48 Commits

Author SHA1 Message Date
Christian Knaapen
5f27eedde2 Keeping outlines until animation is done. Fix itemstack not found error when undoing in creative.
Disabled create test code.
2023-01-17 22:41:38 +01:00
Christian Knaapen
cd3afbbb82 Overhauled block previews to work with ticks. Added place and break animation.
Added DelayedBlockPlacer to play appear animation, then place.
Split BuildConfig into CommonConfig and ClientConfig.
Fixed itemstack not found error in creative.
Added scale and color options to ghost blocks.
2023-01-17 02:30:08 +01:00
Christian Knaapen
fa1aadcd86 Using Create outlines and ghost blocks for block previews.
Fixed item names.
2023-01-16 01:53:09 +01:00
Christian Knaapen
c2d413fad0 Added missing resources.
Modified mods.toml.
Fixed crash and double rendering of modifiers.
2023-01-15 23:16:22 +01:00
Christian Knaapen
064973b07b Added code from Create. Added Flywheel dependency.
Restructured client and mod events to match create.
Copied accesstransformer. Added Create, CreateClient, ClientEvents and CommonEvents proxies.
2023-01-15 22:21:50 +01:00
Christian Knaapen
ea59fef099 Changed reach upgrade recipes. Made radial menu smaller.
Cleaned up radial menu code.
Added russian language.
Tweaked cube icon.
2023-01-14 15:35:43 +01:00
Christian Knaapen
5e6c42d372 Fixed disassembling blocks with the Create Wrench duplicating the item when a build mode other than Normal is used. Disabled break outlines in survival, because breaking multiple blocks in survival is deprecated. 2022-10-25 21:52:14 +02:00
Christian Knaapen
14460c2c01 Fixed keybindings not being registered. 2022-10-24 21:01:19 +02:00
Christian Knaapen
3b31a74780 Merge branch 'master' into 1.19 2022-07-30 10:48:08 +02:00
manapart
911d4b5605 Merged in 1.19 (pull request #4)
1.19

Approved-by: Requios
2022-07-30 08:46:57 +00:00
Christian Knaapen
13ee819439 Merge branch '1.18' 2022-07-30 10:02:13 +02:00
ManApart
319fedc2dd seemingly working with forge .99 2022-07-16 16:14:40 -04:00
ManApart
c7e6230424 seems to be working fine 2022-07-10 08:19:33 -04:00
ManApart
e7ef54bd80 starting game 2022-07-10 08:10:57 -04:00
ManApart
d5af0b097e compiling 2022-07-10 08:05:19 -04:00
ManApart
63b95df0ff upgrade translatable component 2022-07-10 07:59:17 -04:00
ManApart
b3730896e5 upgrade text component 2022-07-10 07:55:10 -04:00
ManApart
675a4930af initial gradle changes 2022-07-10 07:45:49 -04:00
Christian Knaapen
6e22577d61 Updated to work with 1.18.2. 2022-03-19 22:26:59 +01:00
Christian Knaapen
6e7aab673f Fixed crash when previewing lanterns using mirror or radial mirror (blockstate nullpointer). 2022-03-19 21:49:37 +01:00
Christian Knaapen
ad2e81c54e Added build mode categories with colored lines. Hiding pyramid/cone/dome buttons for now. Changed icon of normal mode and renamed to disable. 2022-02-13 16:23:22 +01:00
Christian Knaapen
780d5cc972 Removed reach command and functionality to break multiple blocks in survival. 2022-02-13 01:11:02 +01:00
Christian Knaapen
a1d30fd752 Added descriptions to radial menu. Added pyramid, cone and dome buttons, icons and placeholder classes. Fixed leftclicking to cancel in survival. 2022-02-12 20:55:29 +01:00
Christian Knaapen
96ffc5c1a5 Fixed multiplayer: cache in Mode/ModifierSettingsManager does not work on server, so it's removed. Also changed some packets to use separate classes for clientside handling, as recommended by the Forge Community Wiki. 2022-01-16 15:55:44 +01:00
Christian Knaapen
5ca826362b Update to 1.18 2022-01-03 13:47:18 +01:00
Christian Knaapen
9ae02b16de Tweaks and cleanup 2021-12-05 17:53:47 +01:00
Christian Knaapen
80e355a806 Revamped the radial menu. Removed some old code. 2021-12-05 14:30:57 +01:00
Christian Knaapen
700a3062f7 Hotfix: Fixed crash when rendering overlay: Invalid shaders/core/dissolve.json: Couldn't compile fragment program. 2021-11-02 01:40:17 +01:00
Christian Knaapen
f45d3ffad7 Added golden and diamond randomizer bags (with container, screen, icon and recipe). Updated recipes for reach upgrades. 2021-10-31 16:52:08 +01:00
Christian Knaapen
c8cfa515d0 Fixed icons in radial menu. Cleaned up radial menu code a bit. 2021-10-30 21:34:53 +02:00
Christian Knaapen
6760388bc7 Fixed block preview shader dissolve effect. Fixed reach upgrade item icons. 2021-10-30 20:00:47 +02:00
Christian Knaapen
80c475ff54 Fixed block preview shader being glitchy. Now shows block without effects. 2021-10-30 16:32:23 +02:00
Christian Knaapen
5b8fafd9f7 Fixed randomizer bag inventory not opening. 2021-10-16 13:24:33 +02:00
Christian Knaapen
43d0a02faf Moved dissolve shader to Minecraft's new custom shader rendertype. 2021-09-26 19:38:02 +02:00
Christian Knaapen
4b1997e44f [TASK] Fixed rendering modifier lines and areas. Rendering block previews no longer crashes (renders black). 2021-09-26 12:48:36 +02:00
Christian Knaapen
3930844208 Fixed capabilities and setup events. 2021-09-12 16:58:09 +02:00
Christian Knaapen
d9df8b0d0e Fixed remaining compiler errors. Using deferred registries now, and cleaned up mods.toml file. 2021-09-12 13:54:25 +02:00
Christian Knaapen
178a4ca4e1 Fixed 200+ compiler errors. 23 left. 2021-09-01 17:37:09 +02:00
Christian Knaapen
2297c38574 WIP Update to 1.17 2021-09-01 14:51:44 +02:00
Christian Knaapen
72d1085a54 Updated mapping to 1.16.5 official names. 2021-09-01 14:13:08 +02:00
Christian Knaapen
47f38d0a58 Bumped version number 2021-05-20 21:11:38 +02:00
Alexei Robyn
54d9c3a92f Merged in fakeplayer-fix-1.16 (pull request #3)
Fix FakePlayer-related crashes

Approved-by: Requios
2021-05-20 18:16:16 +00:00
Alexei Robyn
f77a937c6c Fix FakePlayer-related crashes 2021-05-20 14:14:58 +10:00
Christian Knaapen
b41f102f0c Using deferred registry for Randomizer Bag container, which fixes startup crash in 1.16.4 and 1.16.5. 2021-02-03 20:50:09 +01:00
grimm auld
f2fee42c58 Merged in 1.16 (pull request #2)
1.16

Approved-by: Requios
2021-02-02 20:28:16 +00:00
grimmauld
d63786f6e2 merge version bump 2021-02-02 12:52:18 +01:00
grimmauld
5fe5978777 Fix some stuff 2021-01-29 23:43:12 +01:00
grimmauld
7b5f055d22 Get stuff running on 1.16.3 2021-01-29 23:12:11 +01:00
221 changed files with 16586 additions and 8691 deletions

5
.gitattributes vendored Normal file
View File

@@ -0,0 +1,5 @@
# Disable autocrlf on generated files, they always generate with LF
# Add any extra files or paths here to make git stop saying they
# are changed when only line endings change.
src/generated/**/.cache/cache text eol=lf
src/generated/**/*.json text eol=lf

1
.gitignore vendored
View File

@@ -20,6 +20,7 @@ build
# other # other
eclipse eclipse
run run
logs/*
# Files from Forge MDK # Files from Forge MDK
forge*changelog.txt forge*changelog.txt

View File

@@ -1,34 +1,26 @@
buildscript { plugins {
repositories { id 'eclipse'
maven { url = 'https://files.minecraftforge.net/maven' } id 'maven-publish'
jcenter() id 'net.minecraftforge.gradle' version '5.1.+'
mavenCentral()
}
dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true
}
} }
apply plugin: 'net.minecraftforge.gradle'
// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
apply plugin: 'eclipse'
apply plugin: 'maven-publish'
version = '1.15.2-2.21' version = '1.19-2.40'
group = 'nl.requios.effortlessbuilding' // http://maven.apache.org/guides/mini/guide-naming-conventions.html group = 'nl.requios.effortlessbuilding'
archivesBaseName = 'effortlessbuilding' archivesBaseName = 'effortlessbuilding'
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly. // Mojang ships Java 17 to end users in 1.18+, so your mod should target Java 17.
java.toolchain.languageVersion = JavaLanguageVersion.of(17)
println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}"
minecraft { minecraft {
// The mappings can be changed at any time, and must be in the following format. // The mappings can be changed at any time, and must be in the following format.
// snapshot_YYYYMMDD Snapshot are built nightly. // snapshot_YYYYMMDD Snapshot are built nightly.
// stable_# Stables are built at the discretion of the MCP team. // stable_# Stables are built at the discretion of the MCP team.
// Use non-default mappings at your own risk. they may not always work. // Use non-default mappings at your own risk. they may not always work.
// Simply re-run your setup task after changing the mappings to update your workspace. // Simply re-run your setup task after changing the mappings to update your workspace.
mappings channel: 'snapshot', version: '20200514-1.15.1' mappings channel: 'official', version: '1.19.2'
accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
// accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
// Default run configurations. // Default run configurations.
// These can be tweaked, removed, or duplicated as needed. // These can be tweaked, removed, or duplicated as needed.
@@ -42,6 +34,13 @@ minecraft {
// Recommended logging level for the console // Recommended logging level for the console
property 'forge.logging.console.level', 'debug' property 'forge.logging.console.level', 'debug'
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
property 'forge.enabledGameTestNamespaces', 'effortlessbuilding'
// Flywheel
property 'mixin.env.remapRefMap', 'true'
property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"
mods { mods {
effortlessbuilding { effortlessbuilding {
source sourceSets.main source sourceSets.main
@@ -52,12 +51,35 @@ minecraft {
server { server {
workingDirectory project.file('run') workingDirectory project.file('run')
// Recommended logging data for a userdev environment (SCAN,REGISTRIES,REGISTRYDUMP)
property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.markers', 'REGISTRIES'
// Recommended logging level for the console
property 'forge.logging.console.level', 'debug' property 'forge.logging.console.level', 'debug'
property 'forge.enabledGameTestNamespaces', 'effortlessbuilding'
// Flywheel
property 'mixin.env.remapRefMap', 'true'
property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"
mods {
effortlessbuilding {
source sourceSets.main
}
}
}
// This run config launches GameTestServer and runs all registered gametests, then exits.
// By default, the server will crash when no gametests are provided.
// The gametest system is also enabled by default for other run configs under the /test command.
gameTestServer {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
property 'forge.enabledGameTestNamespaces', 'effortlessbuilding'
mods { mods {
effortlessbuilding { effortlessbuilding {
source sourceSets.main source sourceSets.main
@@ -66,15 +88,14 @@ minecraft {
} }
data { data {
workingDirectory project.file('run') workingDirectory project.file('run')
// Recommended logging data for a userdev environment (SCAN,REGISTRIES,REGISTRYDUMP)
property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.markers', 'REGISTRIES'
// Recommended logging level for the console
property 'forge.logging.console.level', 'debug' property 'forge.logging.console.level', 'debug'
args '--mod', 'effortlessbuilding', '--all', '--output', file('src/generated/resources/') // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
args '--mod', 'effortlessbuilding', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
mods { mods {
effortlessbuilding { effortlessbuilding {
@@ -85,30 +106,46 @@ minecraft {
} }
} }
// Include resources generated by data generators.
sourceSets.main.resources { srcDir 'src/generated/resources' }
repositories {
// Put repositories for dependencies here
// ForgeGradle automatically adds the Forge maven and Maven Central for you
// If you have mod jar dependencies in ./libs, you can declare them as a repository like so:
// flatDir {
// dir 'libs'
// }
//Flywheel
maven {
name "tterrag maven"
url "https://maven.tterrag.com/"
}
}
dependencies { dependencies {
// Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed // Specify the version of Minecraft to use. If this is any group other than 'net.minecraft', it is assumed
// that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied. // that the dep is a ForgeGradle 'patcher' dependency, and its patches will be applied.
// The userdev artifact is a special name and will get all sorts of transformations applied to it. // The userdev artifact is a special name and will get all sorts of transformations applied to it.
minecraft 'net.minecraftforge:forge:1.15.2-31.2.0' minecraft 'net.minecraftforge:forge:1.19.2-43.1.47'
// You may put jars on which you depend on in ./libs or you may define them like so.. // Real mod deobf dependency examples - these get remapped to your current mappings
// compile "some.group:artifact:version:classifier" // compileOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}:api") // Adds JEI API as a compile dependency
// compile "some.group:artifact:version" // runtimeOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}") // Adds the full JEI mod as a runtime dependency
// implementation fg.deobf("com.tterrag.registrate:Registrate:MC${mc_version}-${registrate_version}") // Adds registrate as a dependency
// Real examples // Examples using mod jars from ./libs
// compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env // implementation fg.deobf("blank:coolmod-${mc_version}:${coolmod_version}")
// compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
// The 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
// provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
// These dependencies get remapped to your current MCP mappings
// deobf 'com.mod-buildcraft:buildcraft:6.0.8:dev'
// For more info... // For more info...
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
// http://www.gradle.org/docs/current/userguide/dependency_management.html // http://www.gradle.org/docs/current/userguide/dependency_management.html
//Flywheel
//Versions: https://maven.tterrag.com/com/jozufozu/flywheel/flywheel-forge-1.19.2/
implementation fg.deobf("com.jozufozu.flywheel:flywheel-forge-1.19.2:0.6.8-13")
} }
// Example for how to get properties into the manifest for reading by the runtime.. // Example for how to get properties into the manifest for reading by the runtime..
@@ -119,18 +156,18 @@ jar {
"Specification-Vendor": "requios", "Specification-Vendor": "requios",
"Specification-Version": "1", // We are version 1 of ourselves "Specification-Version": "1", // We are version 1 of ourselves
"Implementation-Title": project.name, "Implementation-Title": project.name,
"Implementation-Version": "${version}", "Implementation-Version": project.jar.archiveVersion,
"Implementation-Vendor" :"requios", "Implementation-Vendor" :"requios",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
]) ])
} }
} }
// Example configuration to allow publishing using the maven-publish task // Example configuration to allow publishing using the maven-publish plugin
// This is the preferred method to reobfuscate your jar file // This is the preferred method to reobfuscate your jar file
jar.finalizedBy('reobfJar') jar.finalizedBy('reobfJar')
// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing // However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing
//publish.dependsOn('reobfJar') // publish.dependsOn('reobfJar')
publishing { publishing {
publications { publications {
@@ -140,7 +177,11 @@ publishing {
} }
repositories { repositories {
maven { maven {
url "file:///${project.projectDir}/mcmodsrepo" url "file://${project.projectDir}/mcmodsrepo"
} }
} }
} }
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
}

Binary file not shown.

View File

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

286
gradlew vendored
View File

@@ -1,78 +1,129 @@
#!/usr/bin/env sh #!/bin/sh
#
# Copyright <20> 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
############################################################################## ##############################################################################
## #
## Gradle start up script for UN*X # Gradle start up script for POSIX generated by Gradle.
## #
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions <20>$var<61>, <20>${var}<7D>, <20>${var:-default}<7D>, <20>${var+SET}<7D>,
# <20>${var#prefix}<7D>, <20>${var%suffix}<7D>, and <20>$( cmd )<29>;
# * compound commands having a testable exit status, especially <20>case<73>;
# * various built-in commands including <20>command<6E>, <20>set<65>, and <20>ulimit<69>.
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
############################################################################## ##############################################################################
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" app_path=$0
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do # Need this for daisy-chained symlinks.
ls=`ls -ld "$PRG"` while
link=`expr "$ls" : '.*-> \(.*\)$'` APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
if expr "$link" : '/.*' > /dev/null; then [ -h "$app_path" ]
PRG="$link" do
else ls=$( ls -ld "$app_path" )
PRG=`dirname "$PRG"`"/$link" link=${ls#*' -> '}
fi case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS="" DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD=maximum
warn () { warn () {
echo "$*" echo "$*"
} } >&2
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} } >&2
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "`uname`" in case "$( uname )" in #(
CYGWIN* ) CYGWIN* ) cygwin=true ;; #(
cygwin=true Darwin* ) darwin=true ;; #(
;; MSYS* | MINGW* ) msys=true ;; #(
Darwin* ) NONSTOP* ) nonstop=true ;;
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java" JAVACMD=$JAVA_HOME/jre/sh/java
else else
JAVACMD="$JAVA_HOME/bin/java" JAVACMD=$JAVA_HOME/bin/java
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -81,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi fi
else else
JAVACMD="java" 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. 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 Please set the JAVA_HOME variable in your environment to match the
@@ -89,84 +140,95 @@ location of your Java installation."
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
MAX_FD_LIMIT=`ulimit -H -n` case $MAX_FD in #(
if [ $? -eq 0 ] ; then max*)
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD=$( ulimit -H -n ) ||
MAX_FD="$MAX_FD_LIMIT" warn "Could not query maximum file descriptor limit"
fi esac
ulimit -n $MAX_FD case $MAX_FD in #(
if [ $? -ne 0 ] ; then '' | soft) :;; #(
warn "Could not set maximum file descriptor limit: $MAX_FD" *)
fi ulimit -n "$MAX_FD" ||
else warn "Could not set maximum file descriptor limit to $MAX_FD"
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 esac
fi fi
# Escape application args # Collect all arguments for the java command, stacking in reverse order:
save () { # * args from the command line
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done # * the main class name
echo " " # * -classpath
} # * -D...appname settings
APP_ARGS=$(save "$@") # * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules # For Cygwin or MSYS, switch paths to Windows format before running java
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong JAVACMD=$( cygpath --unix "$JAVACMD" )
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")" # Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

43
gradlew.bat vendored
View File

@@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS= set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,28 +64,14 @@ echo location of your Java installation.
goto fail 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 :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @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% "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell

6
settings.gradle Normal file
View File

@@ -0,0 +1,6 @@
pluginManagement {
repositories {
gradlePluginPortal()
maven { url = 'https://maven.minecraftforge.net/' }
}
}

View File

@@ -1,134 +0,0 @@
package nl.requios.effortlessbuilding;
import net.minecraftforge.common.ForgeConfigSpec;
public class BuildConfig {
private static final ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder();
public static final Reach reach = new Reach(builder);
public static final SurvivalBalancers survivalBalancers = new SurvivalBalancers(builder);
public static final Visuals visuals = new Visuals(builder);
public static final ForgeConfigSpec spec = builder.build();
public static class Reach {
public final ForgeConfigSpec.ConfigValue<Boolean> enableReachUpgrades;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachCreative;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel0;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel1;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel2;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel3;
public Reach(ForgeConfigSpec.Builder builder) {
builder.push("Reach");
enableReachUpgrades = builder
.comment("Reach: how far away the player can place blocks using mirror/array etc.",
"Enable the crafting of reach upgrades to increase reach.",
"If disabled, reach is set to level 3 for survival players.")
.define("enableReachUpgrades", true);
maxReachCreative = builder
.comment("Maximum reach in creative",
"Keep in mind that chunks need to be loaded to be able to place blocks inside.")
.define("maxReachCreative", 200);
maxReachLevel0 = builder
.comment("Maximum reach in survival without upgrades",
"Reach upgrades are craftable consumables that permanently increase reach.",
"Set to 0 to disable Effortless Building until the player has consumed a reach upgrade.")
.define("maxReachLevel0", 20);
maxReachLevel1 = builder
.comment("Maximum reach in survival with one upgrade")
.define("maxReachLevel1", 50);
maxReachLevel2 = builder
.comment("Maximum reach in survival with two upgrades")
.define("maxReachLevel2", 100);
maxReachLevel3 = builder
.comment("Maximum reach in survival with three upgrades")
.define("maxReachLevel3", 200);
builder.pop();
}
}
public static class SurvivalBalancers {
public final ForgeConfigSpec.ConfigValue<Boolean> breakFar;
public final ForgeConfigSpec.ConfigValue<Boolean> increasedMiningTime;
public final ForgeConfigSpec.ConfigValue<Integer> miningTimePercentage;
public final ForgeConfigSpec.ConfigValue<Integer> quickReplaceMiningLevel;
public final ForgeConfigSpec.ConfigValue<Integer> undoStackSize;
public SurvivalBalancers(ForgeConfigSpec.Builder builder) {
builder.push("SurvivalBalancers");
breakFar = builder
.comment("Allows a survival player to break blocks that are far away, in addition to placing blocks.",
"Note: this allows insta-breaking of blocks in survival.")
.define("breakFar", false);
increasedMiningTime = builder
.comment("Increases the time to mine a block when breaking multiple at once.",
"Mining time depends on how many blocks, what type of blocks, and the percentage below.",
"Example: breaking 1 dirt + 1 obsidian takes the time of breaking 1 dirt + 1 obsidian.")
.define("increasedMiningTime", true);
miningTimePercentage = builder
.comment("How much the mining time of each additional block counts towards an increased mining time.",
"A percentage between 0% and 100%, where 0% is the same as disabling it,",
"and 100% takes as much time as breaking each block individually.",
"The block in front of you always counts as 100%.")
.defineInRange("miningTimePercentage", 50, 0, 200);
quickReplaceMiningLevel = builder
.comment("Determines what blocks can be replaced in survival.",
"-1: only blocks that can be harvested by hand (default)",
"0: blocks that can be harvested with wooden or gold tools",
"1: blocks that can be harvested with stone tools",
"2: blocks that can be harvested with iron tools",
"3: blocks that can be harvested with diamond tools")
.defineInRange("quickReplaceMiningLevel", -1, -1, 3);
undoStackSize = builder
.comment("How many placements are remembered for the undo functionality.")
.worldRestart()
.define("undoStackSize", 10);
builder.pop();
}
}
public static class Visuals {
public final ForgeConfigSpec.ConfigValue<Boolean> alwaysShowBlockPreview;
public final ForgeConfigSpec.ConfigValue<Double> dissolveTimeMultiplier;
public final ForgeConfigSpec.ConfigValue<Integer> shaderTreshold;
public final ForgeConfigSpec.ConfigValue<Boolean> useShaders;
public Visuals(ForgeConfigSpec.Builder builder) {
builder.push("Visuals");
alwaysShowBlockPreview = builder
.comment("Show a block preview if you have a block in hand even in the 'Normal' build mode")
.define("alwaysShowBlockPreview", false);
dissolveTimeMultiplier = builder
.comment("How long the dissolve effect takes when placing blocks.",
"Default between 30 and 60 ticks, you can multiply that here.",
"Recommended values:",
"Snappy: 0.7",
"Relaxing: 1.5")
.define("dissolveTimeMultiplier", 1.0);
shaderTreshold = builder
.comment("Switch to using the simple performance shader when placing more than this many blocks.")
.define("shaderTreshold", 1500);
useShaders = builder
.comment("Use fancy shaders while placing blocks")
.define("useShaders", true);
builder.pop();
}
}
}

View File

@@ -0,0 +1,36 @@
package nl.requios.effortlessbuilding;
import net.minecraftforge.common.ForgeConfigSpec;
public class ClientConfig {
private static final ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder();
public static final Visuals visuals = new Visuals(builder);
public static final ForgeConfigSpec spec = builder.build();
public static class Visuals {
public final ForgeConfigSpec.ConfigValue<Boolean> showBlockPreviews;
public final ForgeConfigSpec.ConfigValue<Boolean> alwaysShowBlockPreview;
public final ForgeConfigSpec.ConfigValue<Integer> maxBlockPreviews;
public Visuals(ForgeConfigSpec.Builder builder) {
builder.push("Visuals");
showBlockPreviews = builder
.comment("Show previews of the blocks while placing them")
.define("useShaders", true);
alwaysShowBlockPreview = builder
.comment("Show a block preview if you have a block in hand even in the 'Disabled' build mode")
.define("alwaysShowBlockPreview", false);
maxBlockPreviews = builder
.comment("Don't show block previews when placing more than this many blocks. " +
"The outline will always be rendered.")
.define("shaderTreshold", 500);
builder.pop();
}
}
}

View File

@@ -0,0 +1,337 @@
package nl.requios.effortlessbuilding;
import com.mojang.blaze3d.platform.InputConstants;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import net.minecraft.ChatFormatting;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.InputEvent;
import net.minecraftforge.client.event.RegisterKeyMappingsEvent;
import net.minecraftforge.client.event.RegisterShadersEvent;
import net.minecraftforge.client.event.ScreenEvent;
import net.minecraftforge.client.settings.KeyConflictContext;
import net.minecraftforge.client.settings.KeyModifier;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.gui.buildmode.PlayerSettingsGui;
import nl.requios.effortlessbuilding.gui.buildmode.RadialMenu;
import nl.requios.effortlessbuilding.gui.buildmodifier.ModifierSettingsGui;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.network.*;
import nl.requios.effortlessbuilding.render.BuildRenderTypes;
import org.lwjgl.glfw.GLFW;
import java.io.IOException;
@EventBusSubscriber(Dist.CLIENT)
public class ClientEvents {
public static KeyMapping[] keyBindings;
public static HitResult previousLookAt;
public static HitResult currentLookAt;
public static int ticksInGame = 0;
private static int placeCooldown = 0;
private static int breakCooldown = 0;
//Mod Bus Events
@EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD)
public static class ModBusEvents {
@SubscribeEvent
public static void registerKeyMappings(RegisterKeyMappingsEvent event) {
EffortlessBuilding.log("Registering KeyMappings!");
// register key bindings
keyBindings = new KeyMapping[6];
// instantiate the key bindings
keyBindings[0] = new KeyMapping("key.effortlessbuilding.hud.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_KP_ADD, 0), "key.effortlessbuilding.category");
keyBindings[1] = new KeyMapping("key.effortlessbuilding.replace.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_KP_SUBTRACT, 0), "key.effortlessbuilding.category");
keyBindings[2] = new KeyMapping("key.effortlessbuilding.mode.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_LEFT_ALT, 0), "key.effortlessbuilding.category");
keyBindings[3] = new KeyMapping("key.effortlessbuilding.undo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputConstants.getKey(GLFW.GLFW_KEY_Z, 0), "key.effortlessbuilding.category");
keyBindings[4] = new KeyMapping("key.effortlessbuilding.redo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputConstants.getKey(GLFW.GLFW_KEY_Y, 0), "key.effortlessbuilding.category");
keyBindings[5] = new KeyMapping("key.effortlessbuilding.altplacement.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_LEFT_CONTROL, 0), "key.effortlessbuilding.category");
for (KeyMapping keyBinding : keyBindings) {
event.register(keyBinding);
}
}
@SubscribeEvent
public static void registerShaders(RegisterShadersEvent event) throws IOException {
event.registerShader(new ShaderInstance(event.getResourceManager(),
new ResourceLocation(EffortlessBuilding.MODID, "dissolve"),
DefaultVertexFormat.BLOCK),
shaderInstance -> BuildRenderTypes.dissolveShaderInstance = shaderInstance);
}
}
@SubscribeEvent
public static void onClientTick(TickEvent.ClientTickEvent event) {
if (event.phase == TickEvent.Phase.START) {
onMouseInput();
//Update previousLookAt
HitResult objectMouseOver = Minecraft.getInstance().hitResult;
//Checking for null is necessary! Even in vanilla when looking down ladders it is occasionally null (instead of Type MISS)
if (objectMouseOver == null) return;
if (currentLookAt == null) {
currentLookAt = objectMouseOver;
previousLookAt = objectMouseOver;
return;
}
if (objectMouseOver.getType() == HitResult.Type.BLOCK) {
if (currentLookAt.getType() != HitResult.Type.BLOCK) {
currentLookAt = objectMouseOver;
previousLookAt = objectMouseOver;
} else {
if (((BlockHitResult) currentLookAt).getBlockPos() != ((BlockHitResult) objectMouseOver).getBlockPos()) {
previousLookAt = currentLookAt;
currentLookAt = objectMouseOver;
}
}
}
} else if (event.phase == TickEvent.Phase.END) {
Screen gui = Minecraft.getInstance().screen;
if (gui == null || !gui.isPauseScreen()) {
ticksInGame++;
}
}
}
private static void onMouseInput() {
Minecraft mc = Minecraft.getInstance();
LocalPlayer player = mc.player;
if (player == null) return;
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
if (mc.screen != null ||
buildMode == BuildModes.BuildModeEnum.DISABLED ||
RadialMenu.instance.isVisible()) {
return;
}
if (mc.options.keyUse.isDown()) {
//KeyBinding.setKeyBindState(mc.gameSettings.keyBindUseItem.getKeyCode(), false);
if (placeCooldown <= 0) {
placeCooldown = 4;
ItemStack currentItemStack = player.getItemInHand(InteractionHand.MAIN_HAND);
if (currentItemStack.getItem() instanceof BlockItem ||
(CompatHelper.isItemBlockProxy(currentItemStack) && !player.isShiftKeyDown())) {
ItemStack itemStack = CompatHelper.getItemBlockFromStack(currentItemStack);
//find position in distance
HitResult lookingAt = getLookingAt(player);
if (lookingAt != null && lookingAt.getType() == HitResult.Type.BLOCK) {
BlockHitResult blockLookingAt = (BlockHitResult) lookingAt;
BuildModes.onBlockPlacedMessage(player, new BlockPlacedMessage(blockLookingAt, true));
PacketHandler.INSTANCE.sendToServer(new BlockPlacedMessage(blockLookingAt, true));
//play sound if further than normal
if ((blockLookingAt.getLocation().subtract(player.getEyePosition(1f))).lengthSqr() > 25f &&
itemStack.getItem() instanceof BlockItem) {
BlockState state = ((BlockItem) itemStack.getItem()).getBlock().defaultBlockState();
BlockPos blockPos = blockLookingAt.getBlockPos();
SoundType soundType = state.getBlock().getSoundType(state, player.level, blockPos, player);
player.level.playSound(player, player.blockPosition(), soundType.getPlaceSound(), SoundSource.BLOCKS,
0.4f, soundType.getPitch());
player.swing(InteractionHand.MAIN_HAND);
}
} else {
BuildModes.onBlockPlacedMessage(player, new BlockPlacedMessage());
PacketHandler.INSTANCE.sendToServer(new BlockPlacedMessage());
}
}
} else if (buildMode == BuildModes.BuildModeEnum.SINGLE) {
placeCooldown--;
if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) placeCooldown = 0;
}
} else {
placeCooldown = 0;
}
if (mc.options.keyAttack.isDown()) {
//Break block in distance in creative (or survival if enabled in config)
if (breakCooldown <= 0) {
breakCooldown = 4;
HitResult lookingAt = getLookingAt(player);
if (lookingAt != null && lookingAt.getType() == HitResult.Type.BLOCK) {
BlockHitResult blockLookingAt = (BlockHitResult) lookingAt;
BuildModes.onBlockBrokenMessage(player, new BlockBrokenMessage(blockLookingAt));
PacketHandler.INSTANCE.sendToServer(new BlockBrokenMessage(blockLookingAt));
//play sound if further than normal
if ((blockLookingAt.getLocation().subtract(player.getEyePosition(1f))).lengthSqr() > 25f) {
BlockPos blockPos = blockLookingAt.getBlockPos();
BlockState state = player.level.getBlockState(blockPos);
SoundType soundtype = state.getBlock().getSoundType(state, player.level, blockPos, player);
player.level.playSound(player, player.blockPosition(), soundtype.getBreakSound(), SoundSource.BLOCKS,
0.4f, soundtype.getPitch());
player.swing(InteractionHand.MAIN_HAND);
}
} else {
BuildModes.onBlockBrokenMessage(player, new BlockBrokenMessage());
PacketHandler.INSTANCE.sendToServer(new BlockBrokenMessage());
}
} else if (buildMode == BuildModes.BuildModeEnum.SINGLE) {
breakCooldown--;
if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) breakCooldown = 0;
}
//EffortlessBuilding.packetHandler.sendToServer(new CancelModeMessage());
} else {
breakCooldown = 0;
}
}
@SubscribeEvent(receiveCanceled = true)
public static void onKeyPress(InputEvent.Key event) {
LocalPlayer player = Minecraft.getInstance().player;
if (player == null)
return;
//Remember to send packet to server if necessary
//Show Modifier Settings GUI
if (keyBindings[0].consumeClick()) {
openModifierSettings();
}
//QuickReplace toggle
if (keyBindings[1].consumeClick()) {
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
modifierSettings.setQuickReplace(!modifierSettings.doQuickReplace());
EffortlessBuilding.log(player, "Set " + ChatFormatting.GOLD + "Quick Replace " + ChatFormatting.RESET + (
modifierSettings.doQuickReplace() ? "on" : "off"));
PacketHandler.INSTANCE.sendToServer(new ModifierSettingsMessage(modifierSettings));
}
//Radial menu
if (keyBindings[2].isDown()) {
if (ReachHelper.getMaxReach(player) > 0) {
if (!RadialMenu.instance.isVisible()) {
Minecraft.getInstance().setScreen(RadialMenu.instance);
}
} else {
EffortlessBuilding.log(player, "Build modes are disabled until your reach has increased. Increase your reach with craftable reach upgrades.");
}
}
//Undo (Ctrl+Z)
if (keyBindings[3].consumeClick()) {
ModeOptions.ActionEnum action = ModeOptions.ActionEnum.UNDO;
ModeOptions.performAction(player, action);
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(action));
}
//Redo (Ctrl+Y)
if (keyBindings[4].consumeClick()) {
ModeOptions.ActionEnum action = ModeOptions.ActionEnum.REDO;
ModeOptions.performAction(player, action);
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(action));
}
//Change placement mode
if (keyBindings[5].consumeClick()) {
//Toggle between first two actions of the first option of the current build mode
BuildModes.BuildModeEnum currentBuildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
if (currentBuildMode.options.length > 0) {
ModeOptions.OptionEnum option = currentBuildMode.options[0];
if (option.actions.length >= 2) {
if (ModeOptions.getOptionSetting(option) == option.actions[0]) {
ModeOptions.performAction(player, option.actions[1]);
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(option.actions[1]));
} else {
ModeOptions.performAction(player, option.actions[0]);
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(option.actions[0]));
}
}
}
}
}
public static void openModifierSettings() {
Minecraft mc = Minecraft.getInstance();
LocalPlayer player = mc.player;
if (player == null) return;
//Disabled if max reach is 0, might be set in the config that way.
if (ReachHelper.getMaxReach(player) == 0) {
EffortlessBuilding.log(player, "Build modifiers are disabled until your reach has increased. Increase your reach with craftable reach upgrades.");
} else {
mc.setScreen(new ModifierSettingsGui());
}
}
public static void openPlayerSettings() {
Minecraft mc = Minecraft.getInstance();
mc.setScreen(new PlayerSettingsGui());
}
@SubscribeEvent
public static void onGuiOpen(ScreenEvent event) {
Player player = Minecraft.getInstance().player;
if (player != null) {
BuildModes.initializeMode(player);
}
}
public static boolean isKeybindDown(int keybindIndex) {
return InputConstants.isKeyDown(
Minecraft.getInstance().getWindow().getWindow(),
keyBindings[2].getKey().getValue());
}
public static HitResult getLookingAt(Player player) {
Level world = player.level;
//base distance off of player ability (config)
float raytraceRange = ReachHelper.getPlacementReach(player);
Vec3 look = player.getLookAngle();
Vec3 start = new Vec3(player.getX(), player.getY() + player.getEyeHeight(), player.getZ());
Vec3 end = new Vec3(player.getX() + look.x * raytraceRange, player.getY() + player.getEyeHeight() + look.y * raytraceRange, player.getZ() + look.z * raytraceRange);
// return player.rayTrace(raytraceRange, 1f, RayTraceFluidMode.NEVER);
//TODO 1.14 check if correct
return world.clip(new ClipContext(start, end, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, player));
}
}

View File

@@ -0,0 +1,103 @@
package nl.requios.effortlessbuilding;
import net.minecraftforge.common.ForgeConfigSpec;
import nl.requios.effortlessbuilding.create.foundation.render.SuperByteBufferCache;
public class CommonConfig {
private static final ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder();
public static final Reach reach = new Reach(builder);
public static final SurvivalBalancers survivalBalancers = new SurvivalBalancers(builder);
public static final Visuals visuals = new Visuals(builder);
public static final ForgeConfigSpec spec = builder.build();
public static class Reach {
public final ForgeConfigSpec.ConfigValue<Boolean> enableReachUpgrades;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachCreative;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel0;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel1;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel2;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel3;
public Reach(ForgeConfigSpec.Builder builder) {
builder.push("Reach");
enableReachUpgrades = builder
.comment("Reach: how far away the player can place blocks using mirror/array etc.",
"Enable the crafting of reach upgrades to increase reach.",
"If disabled, reach is set to level 3 for survival players.")
.define("enableReachUpgrades", true);
maxReachCreative = builder
.comment("Maximum reach in creative",
"Keep in mind that chunks need to be loaded to be able to place blocks inside.")
.define("maxReachCreative", 200);
maxReachLevel0 = builder
.comment("Maximum reach in survival without upgrades",
"Reach upgrades are craftable consumables that permanently increase reach.",
"Set to 0 to disable Effortless Building until the player has consumed a reach upgrade.")
.define("maxReachLevel0", 20);
maxReachLevel1 = builder
.comment("Maximum reach in survival with one upgrade")
.define("maxReachLevel1", 50);
maxReachLevel2 = builder
.comment("Maximum reach in survival with two upgrades")
.define("maxReachLevel2", 100);
maxReachLevel3 = builder
.comment("Maximum reach in survival with three upgrades")
.define("maxReachLevel3", 200);
builder.pop();
}
}
public static class SurvivalBalancers {
public final ForgeConfigSpec.ConfigValue<Integer> quickReplaceMiningLevel;
public final ForgeConfigSpec.ConfigValue<Integer> undoStackSize;
public SurvivalBalancers(ForgeConfigSpec.Builder builder) {
builder.push("SurvivalBalancers");
quickReplaceMiningLevel = builder
.comment("Determines what blocks can be replaced in survival.",
"-1: only blocks that can be harvested by hand (default)",
"0: blocks that can be harvested with wooden or gold tools",
"1: blocks that can be harvested with stone tools",
"2: blocks that can be harvested with iron tools",
"3: blocks that can be harvested with diamond tools",
"4: blocks that can be harvested with netherite tools")
.defineInRange("quickReplaceMiningLevel", -1, -1, 3);
undoStackSize = builder
.comment("How many placements are remembered for the undo functionality.")
.worldRestart()
.define("undoStackSize", 10);
builder.pop();
}
}
public static class Visuals {
public final ForgeConfigSpec.ConfigValue<Integer> appearAnimationLength;
public final ForgeConfigSpec.ConfigValue<Integer> breakAnimationLength;
public Visuals(ForgeConfigSpec.Builder builder) {
builder.push("Visuals");
appearAnimationLength = builder
.comment("How long it takes for a block to appear when placed in ticks.",
"Set to 0 to disable animation.")
.define("appearAnimationLength", 5);
breakAnimationLength = builder
.comment("How long the break animation is in ticks.",
"Set to 0 to disable animation.")
.define("breakAnimationLength", 10);
builder.pop();
}
}
}

View File

@@ -0,0 +1,196 @@
package nl.requios.effortlessbuilding;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.level.BlockEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.network.PacketDistributor;
import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
import nl.requios.effortlessbuilding.capability.ModeCapabilityManager;
import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager;
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.network.AddUndoMessage;
import nl.requios.effortlessbuilding.network.ClearUndoMessage;
import nl.requios.effortlessbuilding.network.PacketHandler;
import nl.requios.effortlessbuilding.network.RequestLookAtMessage;
@EventBusSubscriber
public class CommonEvents {
//Mod Bus Events
@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD)
public static class ModBusEvents {
@SubscribeEvent
public void registerCapabilities(RegisterCapabilitiesEvent event){
event.register(ModifierCapabilityManager.IModifierCapability.class);
event.register(ModeCapabilityManager.IModeCapability.class);
}
}
@SubscribeEvent
public static void attachCapabilities(AttachCapabilitiesEvent<Entity> event) {
if (event.getObject() instanceof FakePlayer) return;
if (event.getObject() instanceof Player) {
event.addCapability(new ResourceLocation(EffortlessBuilding.MODID, "build_modifier"), new ModifierCapabilityManager.Provider());
event.addCapability(new ResourceLocation(EffortlessBuilding.MODID, "build_mode"), new ModeCapabilityManager.Provider());
}
}
@SubscribeEvent
public static void onTick(TickEvent.LevelTickEvent event) {
if (event.phase != TickEvent.Phase.START) return;
EffortlessBuilding.DELAYED_BLOCK_PLACER.tick();
}
@SubscribeEvent
public static void onBlockPlaced(BlockEvent.EntityPlaceEvent event) {
if (event.getLevel().isClientSide()) return;
if (!(event.getEntity() instanceof Player)) return;
if (event.getEntity() instanceof FakePlayer) return;
//Cancel event if necessary
ServerPlayer player = ((ServerPlayer) event.getEntity());
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
if (buildMode != BuildModes.BuildModeEnum.DISABLED) {
//Only cancel if itemblock in hand
//Fixed issue with e.g. Create Wrench shift-rightclick disassembling being cancelled.
ItemStack currentItemStack = player.getItemInHand(InteractionHand.MAIN_HAND);
if (currentItemStack.getItem() instanceof BlockItem ||
(CompatHelper.isItemBlockProxy(currentItemStack) && !player.isShiftKeyDown())) {
event.setCanceled(true);
}
} else if (modifierSettings.doQuickReplace()) {
//Cancel event and send message if QuickReplace
event.setCanceled(true);
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new RequestLookAtMessage(true));
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new AddUndoMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()));
} else {
//NORMAL mode, let vanilla handle block placing
//But modifiers should still work
//Send message to client, which sends message back with raytrace info
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new RequestLookAtMessage(false));
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new AddUndoMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()));
}
// Stat<ResourceLocation> blocksPlacedStat = StatList.CUSTOM.get(new ResourceLocation(EffortlessBuilding.MODID, "blocks_placed"));
// player.getStats().increment(player, blocksPlacedStat, 1);
//
// System.out.println(player.getStats().getValue(blocksPlacedStat));
}
@SubscribeEvent
public static void onBlockBroken(BlockEvent.BreakEvent event) {
if (event.getLevel().isClientSide()) return;
if (event.getPlayer() instanceof FakePlayer) return;
//Cancel event if necessary
//If cant break far then dont cancel event ever
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(event.getPlayer()).getBuildMode();
if (buildMode != BuildModes.BuildModeEnum.DISABLED && ReachHelper.canBreakFar(event.getPlayer())) {
event.setCanceled(true);
} else {
//NORMAL mode, let vanilla handle block breaking
//But modifiers and QuickReplace should still work
//Dont break the original block yourself, otherwise Tinkers Hammer and Veinminer won't work
BuildModes.onBlockBroken(event.getPlayer(), event.getPos(), false);
//Add to undo stack in client
if (event.getPlayer() instanceof ServerPlayer && event.getState() != null && event.getPos() != null) {
PacketDistributor.PacketTarget packetTarget = PacketDistributor.PLAYER.with(() -> (ServerPlayer) event.getPlayer());
if (packetTarget != null)
PacketHandler.INSTANCE.send(packetTarget, new AddUndoMessage(event.getPos(), event.getState(), Blocks.AIR.defaultBlockState()));
}
}
}
@SubscribeEvent
public static void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) {
if (event.getEntity() instanceof FakePlayer) return;
Player player = event.getEntity();
ModifierSettingsManager.handleNewPlayer(player);
ModeSettingsManager.handleNewPlayer(player);
}
@SubscribeEvent
public static void onPlayerLoggedOut(PlayerEvent.PlayerLoggedOutEvent event) {
if (event.getEntity() instanceof FakePlayer) return;
Player player = event.getEntity();
if (player.getCommandSenderWorld().isClientSide) return;
UndoRedo.clear(player);
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new ClearUndoMessage());
}
@SubscribeEvent
public static void onPlayerRespawn(PlayerEvent.PlayerRespawnEvent event) {
if (event.getEntity() instanceof FakePlayer) return;
Player player = event.getEntity();
ModifierSettingsManager.handleNewPlayer(player);
ModeSettingsManager.handleNewPlayer(player);
}
@SubscribeEvent
public static void onPlayerChangedDimension(PlayerEvent.PlayerChangedDimensionEvent event) {
if (event.getEntity() instanceof FakePlayer) return;
Player player = event.getEntity();
if (player.getCommandSenderWorld().isClientSide) return;
//Set build mode to normal
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
modeSettings.setBuildMode(BuildModes.BuildModeEnum.DISABLED);
ModeSettingsManager.setModeSettings(player, modeSettings);
//Disable modifiers
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
modifierSettings.getMirrorSettings().enabled = false;
modifierSettings.getRadialMirrorSettings().enabled = false;
modifierSettings.getArraySettings().enabled = false;
ModifierSettingsManager.setModifierSettings(player, modifierSettings);
ModifierSettingsManager.handleNewPlayer(player);
ModeSettingsManager.handleNewPlayer(player);
UndoRedo.clear(player);
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new ClearUndoMessage());
}
@SubscribeEvent
public static void onPlayerClone(PlayerEvent.Clone event) {
if (event.getEntity() instanceof FakePlayer) return;
//Attach capabilities on death, otherwise crash
Player oldPlayer = event.getOriginal();
oldPlayer.revive();
Player newPlayer = event.getEntity();
ModifierSettingsManager.setModifierSettings(newPlayer, ModifierSettingsManager.getModifierSettings(oldPlayer));
ModeSettingsManager.setModeSettings(newPlayer, ModeSettingsManager.getModeSettings(oldPlayer));
}
}

View File

@@ -1,37 +1,29 @@
package nl.requios.effortlessbuilding; package nl.requios.effortlessbuilding;
import net.minecraft.block.Block; import net.minecraft.network.chat.Component;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.inventory.container.Container; import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.inventory.container.ContainerType; import net.minecraft.world.inventory.MenuType;
import net.minecraft.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.util.ResourceLocation; import net.minecraftforge.api.distmarker.Dist;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.text.StringTextComponent;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.ExtensionPoint;
import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import nl.requios.effortlessbuilding.capability.ModeCapabilityManager; import net.minecraftforge.network.IContainerFactory;
import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager; import net.minecraftforge.registries.DeferredRegister;
import nl.requios.effortlessbuilding.command.CommandReach; import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
import nl.requios.effortlessbuilding.compatibility.CompatHelper; import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.gui.DiamondRandomizerBagContainer;
import nl.requios.effortlessbuilding.gui.GoldenRandomizerBagContainer;
import nl.requios.effortlessbuilding.gui.RandomizerBagContainer; import nl.requios.effortlessbuilding.gui.RandomizerBagContainer;
import nl.requios.effortlessbuilding.item.ItemRandomizerBag; import nl.requios.effortlessbuilding.helper.DelayedBlockPlacer;
import nl.requios.effortlessbuilding.item.ItemReachUpgrade1; import nl.requios.effortlessbuilding.item.*;
import nl.requios.effortlessbuilding.item.ItemReachUpgrade2;
import nl.requios.effortlessbuilding.item.ItemReachUpgrade3;
import nl.requios.effortlessbuilding.network.PacketHandler; import nl.requios.effortlessbuilding.network.PacketHandler;
import nl.requios.effortlessbuilding.proxy.ClientProxy; import nl.requios.effortlessbuilding.proxy.ClientProxy;
import nl.requios.effortlessbuilding.proxy.IProxy; import nl.requios.effortlessbuilding.proxy.IProxy;
@@ -39,119 +31,77 @@ import nl.requios.effortlessbuilding.proxy.ServerProxy;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
// The value here should match an entry in the META-INF/mods.toml file
@Mod(EffortlessBuilding.MODID) @Mod(EffortlessBuilding.MODID)
@Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD) public class EffortlessBuilding {
public class EffortlessBuilding
{
public static final String MODID = "effortlessbuilding";
public static final String NAME = "Effortless Building";
public static final String VERSION = "1.15.2-2.21";
public static EffortlessBuilding instance; public static final String MODID = "effortlessbuilding";
public static final Logger logger = LogManager.getLogger();
public static final Logger logger = LogManager.getLogger(); public static EffortlessBuilding instance;
public static IProxy proxy = DistExecutor.safeRunForDist(() -> ClientProxy::new, () -> ServerProxy::new);
public static IProxy proxy = DistExecutor.runForDist(() -> ClientProxy::new, () -> ServerProxy::new); public static final DelayedBlockPlacer DELAYED_BLOCK_PLACER = new DelayedBlockPlacer();
public static final ItemRandomizerBag ITEM_RANDOMIZER_BAG = new ItemRandomizerBag(); //Registration
public static final ItemReachUpgrade1 ITEM_REACH_UPGRADE_1 = new ItemReachUpgrade1(); private static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MODID);
public static final ItemReachUpgrade2 ITEM_REACH_UPGRADE_2 = new ItemReachUpgrade2(); private static final DeferredRegister<MenuType<?>> CONTAINERS = DeferredRegister.create(ForgeRegistries.MENU_TYPES, EffortlessBuilding.MODID);
public static final ItemReachUpgrade3 ITEM_REACH_UPGRADE_3 = new ItemReachUpgrade3();
public static final Block[] BLOCKS = { public static final RegistryObject<Item> RANDOMIZER_BAG_ITEM = ITEMS.register("randomizer_bag", RandomizerBagItem::new);
}; public static final RegistryObject<Item> GOLDEN_RANDOMIZER_BAG_ITEM = ITEMS.register("golden_randomizer_bag", GoldenRandomizerBagItem::new);
public static final RegistryObject<Item> DIAMOND_RANDOMIZER_BAG_ITEM = ITEMS.register("diamond_randomizer_bag", DiamondRandomizerBagItem::new);
public static final RegistryObject<Item> REACH_UPGRADE_1_ITEM = ITEMS.register("reach_upgrade1", ReachUpgrade1Item::new);
public static final RegistryObject<Item> REACH_UPGRADE_2_ITEM = ITEMS.register("reach_upgrade2", ReachUpgrade2Item::new);
public static final RegistryObject<Item> REACH_UPGRADE_3_ITEM = ITEMS.register("reach_upgrade3", ReachUpgrade3Item::new);
public static final Item[] ITEMS = { public static final RegistryObject<MenuType<RandomizerBagContainer>> RANDOMIZER_BAG_CONTAINER = CONTAINERS.register("randomizer_bag", () -> registerContainer(RandomizerBagContainer::new));
ITEM_RANDOMIZER_BAG, public static final RegistryObject<MenuType<GoldenRandomizerBagContainer>> GOLDEN_RANDOMIZER_BAG_CONTAINER = CONTAINERS.register("golden_randomizer_bag", () -> registerContainer(GoldenRandomizerBagContainer::new));
ITEM_REACH_UPGRADE_1, public static final RegistryObject<MenuType<DiamondRandomizerBagContainer>> DIAMOND_RANDOMIZER_BAG_CONTAINER = CONTAINERS.register("diamond_randomizer_bag", () -> registerContainer(DiamondRandomizerBagContainer::new));
ITEM_REACH_UPGRADE_2,
ITEM_REACH_UPGRADE_3
};
public static final ContainerType<RandomizerBagContainer> RANDOMIZER_BAG_CONTAINER = register("randomizer_bag", RandomizerBagContainer::new); public EffortlessBuilding() {
public static final ResourceLocation RANDOMIZER_BAG_GUI = new ResourceLocation(EffortlessBuilding.MODID, "randomizer_bag"); instance = this;
public EffortlessBuilding() { ModLoadingContext modLoadingContext = ModLoadingContext.get();
instance = this; IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
IEventBus forgeEventBus = MinecraftForge.EVENT_BUS;
// Register the setup method for modloading modEventBus.addListener(EffortlessBuilding::setup);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
// Register the enqueueIMC method for modloading
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::enqueueIMC);
// Register the processIMC method for modloading
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::processIMC);
// Register the clientSetup method for modloading
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::clientSetup);
//Register config DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> EffortlessBuildingClient.onConstructorClient(modEventBus, forgeEventBus));
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, BuildConfig.spec);
// Register ourselves for server and other game events we are interested in ITEMS.register(FMLJavaModLoadingContext.get().getModEventBus());
MinecraftForge.EVENT_BUS.register(this); CONTAINERS.register(FMLJavaModLoadingContext.get().getModEventBus());
}
@SubscribeEvent //Register config
public void setup(final FMLCommonSetupEvent event) ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, CommonConfig.spec);
{ ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ClientConfig.spec);
CapabilityManager.INSTANCE.register(ModifierCapabilityManager.IModifierCapability.class, new ModifierCapabilityManager.Storage(), ModifierCapabilityManager.ModifierCapability::new); }
CapabilityManager.INSTANCE.register(ModeCapabilityManager.IModeCapability.class, new ModeCapabilityManager.Storage(), ModeCapabilityManager.ModeCapability::new);
PacketHandler.register(); public static void setup(final FMLCommonSetupEvent event) {
PacketHandler.register();
//TODO 1.13 config CompatHelper.setup();
// ConfigManager.sync(MODID, Config.Type.INSTANCE); }
proxy.setup(event); public static <T extends AbstractContainerMenu> MenuType<T> registerContainer(IContainerFactory<T> fact){
MenuType<T> type = new MenuType<T>(fact);
return type;
}
CompatHelper.setup(); public static void log(String msg) {
} logger.info(msg);
}
@SubscribeEvent public static void log(Player player, String msg) {
public void clientSetup(final FMLClientSetupEvent event) { log(player, msg, false);
}
proxy.clientSetup(event); public static void log(Player player, String msg, boolean actionBar) {
} player.displayClientMessage(Component.literal(msg), actionBar);
}
@SubscribeEvent //Log with translation supported, call either on client or server (which then sends a message)
public void enqueueIMC(final InterModEnqueueEvent event) { public static void logTranslate(Player player, String prefix, String translationKey, String suffix, boolean actionBar) {
proxy.logTranslate(player, prefix, translationKey, suffix, actionBar);
}
// some example code to dispatch IMC to another mod
// InterModComms.sendTo("examplemod", "helloworld", () -> { logger.info("Hello world from the MDK"); return "Hello world";});
}
@SubscribeEvent
public void processIMC(final InterModProcessEvent event) {
// some example code to receive and process InterModComms from other mods
// logger.info("Got IMC {}", event.getIMCStream().
// map(m->m.getMessageSupplier().get()).
// collect(Collectors.toList()));
}
@SubscribeEvent
public void onServerStarting(FMLServerStartingEvent event) {
CommandReach.register(event.getCommandDispatcher());
}
private static <T extends Container> ContainerType<T> register(String key, ContainerType.IFactory<T> factory) {
return Registry.register(Registry.MENU, key, new ContainerType<>(factory));
}
public static void log(String msg){
logger.info(msg);
}
public static void log(PlayerEntity player, String msg){
log(player, msg, false);
}
public static void log(PlayerEntity player, String msg, boolean actionBar){
player.sendStatusMessage(new StringTextComponent(msg), actionBar);
}
//Log with translation supported, call either on client or server (which then sends a message)
public static void logTranslate(PlayerEntity player, String prefix, String translationKey, String suffix, boolean actionBar){
proxy.logTranslate(player, prefix, translationKey, suffix, actionBar);
}
} }

View File

@@ -0,0 +1,21 @@
package nl.requios.effortlessbuilding;
import net.minecraft.client.gui.screens.MenuScreens;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import nl.requios.effortlessbuilding.gui.DiamondRandomizerBagScreen;
import nl.requios.effortlessbuilding.gui.GoldenRandomizerBagScreen;
import nl.requios.effortlessbuilding.gui.RandomizerBagScreen;
public class EffortlessBuildingClient {
public static void onConstructorClient(IEventBus modEventBus, IEventBus forgeEventBus) {
modEventBus.addListener(EffortlessBuildingClient::clientSetup);
}
public static void clientSetup(final FMLClientSetupEvent event) {
MenuScreens.register(EffortlessBuilding.RANDOMIZER_BAG_CONTAINER.get(), RandomizerBagScreen::new);
MenuScreens.register(EffortlessBuilding.GOLDEN_RANDOMIZER_BAG_CONTAINER.get(), GoldenRandomizerBagScreen::new);
MenuScreens.register(EffortlessBuilding.DIAMOND_RANDOMIZER_BAG_CONTAINER.get(), DiamondRandomizerBagScreen::new);
}
}

View File

@@ -1,209 +0,0 @@
package nl.requios.effortlessbuilding;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.network.PacketDistributor;
import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
import nl.requios.effortlessbuilding.capability.ModeCapabilityManager;
import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.network.AddUndoMessage;
import nl.requios.effortlessbuilding.network.ClearUndoMessage;
import nl.requios.effortlessbuilding.network.PacketHandler;
import nl.requios.effortlessbuilding.network.RequestLookAtMessage;
import java.util.List;
@Mod.EventBusSubscriber
public class EventHandler
{
@SubscribeEvent
public static void attachCapabilities(AttachCapabilitiesEvent<Entity> event) {
if (event.getObject() instanceof PlayerEntity) {
event.addCapability(new ResourceLocation(EffortlessBuilding.MODID, "build_modifier"), new ModifierCapabilityManager.Provider());
event.addCapability(new ResourceLocation(EffortlessBuilding.MODID, "build_mode"), new ModeCapabilityManager.Provider());
}
}
//TODO 1.13 config
// @SubscribeEvent
// public static void onConfigChangedEvent(ConfigChangedEvent.OnConfigChangedEvent event)
// {
// if (event.getModID().equals(EffortlessBuilding.MODID))
// {
// ConfigManager.sync(EffortlessBuilding.MODID, Config.Type.INSTANCE);
// }
// }
// @SubscribeEvent
// public static void onServerTick(TickEvent.ServerTickEvent event) {
//
// }
@SubscribeEvent
//Only called serverside (except with lilypads...)
public static void onBlockPlaced(BlockEvent.EntityPlaceEvent event) {
if (event.getWorld().isRemote()) return;
if (!(event.getEntity() instanceof PlayerEntity)) return;
//Cancel event if necessary
ServerPlayerEntity player = ((ServerPlayerEntity) event.getEntity());
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
if (buildMode != BuildModes.BuildModeEnum.NORMAL) {
event.setCanceled(true);
} else if (modifierSettings.doQuickReplace()) {
//Cancel event and send message if QuickReplace
event.setCanceled(true);
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new RequestLookAtMessage(true));
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new AddUndoMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()));
} else {
//NORMAL mode, let vanilla handle block placing
//But modifiers should still work
//Send message to client, which sends message back with raytrace info
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new RequestLookAtMessage(false));
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new AddUndoMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()));
}
// Stat<ResourceLocation> blocksPlacedStat = StatList.CUSTOM.get(new ResourceLocation(EffortlessBuilding.MODID, "blocks_placed"));
// player.getStats().increment(player, blocksPlacedStat, 1);
//
// System.out.println(player.getStats().getValue(blocksPlacedStat));
}
@SubscribeEvent
public static void onBlockBroken(BlockEvent.BreakEvent event) {
if (event.getWorld().isRemote()) return;
//Cancel event if necessary
//If cant break far then dont cancel event ever
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(event.getPlayer()).getBuildMode();
if (buildMode != BuildModes.BuildModeEnum.NORMAL && ReachHelper.canBreakFar(event.getPlayer())) {
event.setCanceled(true);
} else {
//NORMAL mode, let vanilla handle block breaking
//But modifiers and QuickReplace should still work
//Dont break the original block yourself, otherwise Tinkers Hammer and Veinminer won't work
BuildModes.onBlockBroken(event.getPlayer(), event.getPos(), false);
//Add to undo stack in client
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) event.getPlayer()), new AddUndoMessage(event.getPos(), event.getState(), Blocks.AIR.getDefaultState()));
}
}
@SubscribeEvent
public static void breakSpeed(PlayerEvent.BreakSpeed event) {
//Disable if config says so
if (!BuildConfig.survivalBalancers.increasedMiningTime.get()) return;
PlayerEntity player = event.getPlayer();
World world = player.world;
BlockPos pos = event.getPos();
//EffortlessBuilding.log(player, String.valueOf(event.getNewSpeed()));
float originalBlockHardness = event.getState().getBlockHardness(world, pos);
if (originalBlockHardness < 0) return; //Dont break bedrock
float totalBlockHardness = 0;
//get coordinates
List<BlockPos> coordinates = BuildModifiers.findCoordinates(player, pos);
for (int i = 1; i < coordinates.size(); i++) {
BlockPos coordinate = coordinates.get(i);
//get existing blockstates at those coordinates
BlockState blockState = world.getBlockState(coordinate);
//add hardness for each blockstate, if can break
if (SurvivalHelper.canBreak(world, player, coordinate))
totalBlockHardness += blockState.getBlockHardness(world, coordinate);
}
//Grabbing percentage from config
float percentage = (float) BuildConfig.survivalBalancers.miningTimePercentage.get() / 100;
totalBlockHardness *= percentage;
totalBlockHardness += originalBlockHardness;
float newSpeed = event.getOriginalSpeed() / totalBlockHardness * originalBlockHardness;
if (Float.isNaN(newSpeed) || newSpeed == 0f) newSpeed = 1f;
event.setNewSpeed(newSpeed);
//EffortlessBuilding.log(player, String.valueOf(event.getNewSpeed()));
}
@SubscribeEvent
public static void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) {
PlayerEntity player = event.getPlayer();
ModifierSettingsManager.handleNewPlayer(player);
ModeSettingsManager.handleNewPlayer(player);
}
@SubscribeEvent
public static void onPlayerLoggedOut(PlayerEvent.PlayerLoggedOutEvent event) {
PlayerEntity player = event.getPlayer();
if (player.getEntityWorld().isRemote) return;
UndoRedo.clear(player);
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), new ClearUndoMessage());
}
@SubscribeEvent
public static void onPlayerRespawn(PlayerEvent.PlayerRespawnEvent event) {
PlayerEntity player = event.getPlayer();
ModifierSettingsManager.handleNewPlayer(player);
ModeSettingsManager.handleNewPlayer(player);
}
@SubscribeEvent
public static void onPlayerChangedDimension(PlayerEvent.PlayerChangedDimensionEvent event) {
PlayerEntity player = event.getPlayer();
if (player.getEntityWorld().isRemote) return;
//Set build mode to normal
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
modeSettings.setBuildMode(BuildModes.BuildModeEnum.NORMAL);
ModeSettingsManager.setModeSettings(player, modeSettings);
//Disable modifiers
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
modifierSettings.getMirrorSettings().enabled = false;
modifierSettings.getRadialMirrorSettings().enabled = false;
modifierSettings.getArraySettings().enabled = false;
ModifierSettingsManager.setModifierSettings(player, modifierSettings);
ModifierSettingsManager.handleNewPlayer(player);
ModeSettingsManager.handleNewPlayer(player);
UndoRedo.clear(player);
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), new ClearUndoMessage());
}
@SubscribeEvent
public static void onPlayerClone(PlayerEvent.Clone event) {
//Attach capabilities on death, otherwise crash
PlayerEntity oldPlayer = event.getOriginal();
oldPlayer.revive();
PlayerEntity newPlayer = event.getPlayer();
ModifierSettingsManager.setModifierSettings(newPlayer, ModifierSettingsManager.getModifierSettings(oldPlayer));
ModeSettingsManager.setModeSettings(newPlayer, ModeSettingsManager.getModeSettings(oldPlayer));
}
}

View File

@@ -1,48 +0,0 @@
package nl.requios.effortlessbuilding;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import java.util.HashMap;
@Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD, value = {Dist.CLIENT})
public class ModClientEventHandler {
private static final HashMap<BuildModes.BuildModeEnum, ResourceLocation> buildModeIcons = new HashMap<>();
private static final HashMap<ModeOptions.ActionEnum, ResourceLocation> modeOptionIcons = new HashMap<>();
@SubscribeEvent
public static void onTextureStitch(final TextureStitchEvent.Pre event) {
EffortlessBuilding.log("Stitching textures");
//register icon textures
for (final BuildModes.BuildModeEnum mode : BuildModes.BuildModeEnum.values())
{
final ResourceLocation spriteLocation = new ResourceLocation(EffortlessBuilding.MODID, "icons/" + mode.name().toLowerCase());
event.addSprite(spriteLocation);
buildModeIcons.put(mode, spriteLocation);
}
for (final ModeOptions.ActionEnum action : ModeOptions.ActionEnum.values())
{
final ResourceLocation spriteLocation = new ResourceLocation(EffortlessBuilding.MODID, "icons/" + action.name().toLowerCase());
event.addSprite(spriteLocation);
modeOptionIcons.put(action, spriteLocation);
}
}
public static TextureAtlasSprite getBuildModeIcon(BuildModes.BuildModeEnum mode) {
return Minecraft.getInstance().getModelManager().getAtlasTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE).getSprite(buildModeIcons.get(mode));
}
public static TextureAtlasSprite getModeOptionIcon(ModeOptions.ActionEnum action) {
return Minecraft.getInstance().getModelManager().getAtlasTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE).getSprite(modeOptionIcons.get(action));
}
}

View File

@@ -1,45 +0,0 @@
package nl.requios.effortlessbuilding;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import java.util.HashMap;
// You can use EventBusSubscriber to automatically subscribe events on the contained class (this is subscribing to the MOD
// Event bus for receiving Registry Events)
@Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD)
public class ModEventHandler {
@SubscribeEvent
public static void registerBlocks(RegistryEvent.Register<Block> event) {
event.getRegistry().registerAll(EffortlessBuilding.BLOCKS);
}
@SubscribeEvent
public static void registerItems(RegistryEvent.Register<Item> event) {
event.getRegistry().registerAll(EffortlessBuilding.ITEMS);
for (Block block : EffortlessBuilding.BLOCKS)
{
event.getRegistry().register(new BlockItem(block, new Item.Properties()).setRegistryName(block.getRegistryName()));
}
}
// @SubscribeEvent
// public static void registerContainerTypes(RegistryEvent.Register<ContainerType<?>> event) {
// event.getRegistry().register()
// }
}

View File

@@ -1,39 +1,39 @@
package nl.requios.effortlessbuilding.buildmode; package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.Direction; import net.minecraft.core.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
import java.util.Dictionary; import java.util.Dictionary;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.UUID; import java.util.UUID;
public abstract class BaseBuildMode implements IBuildMode { public abstract class BaseBuildMode implements IBuildMode {
//In singleplayer client and server variables are shared //In singleplayer client and server variables are shared
//Split everything that needs separate values and may not be called twice in one click //Split everything that needs separate values and may not be called twice in one click
protected Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>(); protected Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>();
protected Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>(); protected Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>();
protected Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>(); protected Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
protected Dictionary<UUID, Direction> sideHitTable = new Hashtable<>(); protected Dictionary<UUID, Direction> sideHitTable = new Hashtable<>();
protected Dictionary<UUID, Vec3d> hitVecTable = new Hashtable<>(); protected Dictionary<UUID, Vec3> hitVecTable = new Hashtable<>();
@Override @Override
public void initialize(PlayerEntity player) { public void initialize(Player player) {
rightClickClientTable.put(player.getUniqueID(), 0); rightClickClientTable.put(player.getUUID(), 0);
rightClickServerTable.put(player.getUniqueID(), 0); rightClickServerTable.put(player.getUUID(), 0);
firstPosTable.put(player.getUniqueID(), BlockPos.ZERO); firstPosTable.put(player.getUUID(), BlockPos.ZERO);
sideHitTable.put(player.getUniqueID(), Direction.UP); sideHitTable.put(player.getUUID(), Direction.UP);
hitVecTable.put(player.getUniqueID(), Vec3d.ZERO); hitVecTable.put(player.getUUID(), Vec3.ZERO);
} }
@Override @Override
public Direction getSideHit(PlayerEntity player) { public Direction getSideHit(Player player) {
return sideHitTable.get(player.getUniqueID()); return sideHitTable.get(player.getUUID());
} }
@Override @Override
public Vec3d getHitVec(PlayerEntity player) { public Vec3 getHitVec(Player player) {
return hitVecTable.get(player.getUniqueID()); return hitVecTable.get(player.getUUID());
} }
} }

View File

@@ -1,11 +1,12 @@
package nl.requios.effortlessbuilding.buildmode; package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.PlayerEntity; import com.mojang.math.Vector4f;
import net.minecraft.util.Direction; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.Direction;
import net.minecraft.util.math.RayTraceContext; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.level.ClipContext;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.buildmodes.*; import nl.requios.effortlessbuilding.buildmode.buildmodes.*;
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
@@ -20,252 +21,275 @@ import java.util.Dictionary;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List; import java.util.List;
import static nl.requios.effortlessbuilding.buildmode.ModeOptions.*; import static nl.requios.effortlessbuilding.buildmode.ModeOptions.OptionEnum;
public class BuildModes { public class BuildModes {
//Static variables are shared between client and server in singleplayer //Static variables are shared between client and server in singleplayer
//We need them separate //We need them separate
public static Dictionary<PlayerEntity, Boolean> currentlyBreakingClient = new Hashtable<>(); public static Dictionary<Player, Boolean> currentlyBreakingClient = new Hashtable<>();
public static Dictionary<PlayerEntity, Boolean> currentlyBreakingServer = new Hashtable<>(); public static Dictionary<Player, Boolean> currentlyBreakingServer = new Hashtable<>();
public enum BuildModeEnum { //Uses a network message to get the previous raytraceresult from the player
NORMAL("effortlessbuilding.mode.normal", new Normal()), //The server could keep track of all raytraceresults but this might lag with many players
NORMAL_PLUS("effortlessbuilding.mode.normal_plus", new NormalPlus(), OptionEnum.BUILD_SPEED), //Raytraceresult is needed for sideHit and hitVec
LINE("effortlessbuilding.mode.line", new Line() /*, OptionEnum.THICKNESS*/), public static void onBlockPlacedMessage(Player player, BlockPlacedMessage message) {
WALL("effortlessbuilding.mode.wall", new Wall(), OptionEnum.FILL),
FLOOR("effortlessbuilding.mode.floor", new Floor(), OptionEnum.FILL),
DIAGONAL_LINE("effortlessbuilding.mode.diagonal_line", new DiagonalLine() /*, OptionEnum.THICKNESS*/),
DIAGONAL_WALL("effortlessbuilding.mode.diagonal_wall", new DiagonalWall() /*, OptionEnum.FILL*/),
SLOPE_FLOOR("effortlessbuilding.mode.slope_floor", new SlopeFloor(), OptionEnum.RAISED_EDGE),
CIRCLE("effortlessbuilding.mode.circle", new Circle(), OptionEnum.CIRCLE_START, OptionEnum.FILL),
CYLINDER("effortlessbuilding.mode.cylinder", new Cylinder(), OptionEnum.CIRCLE_START, OptionEnum.FILL),
SPHERE("effortlessbuilding.mode.sphere", new Sphere(), OptionEnum.CIRCLE_START, OptionEnum.FILL),
CUBE("effortlessbuilding.mode.cube", new Cube(), OptionEnum.CUBE_FILL);
public String name; //Check if not in the middle of breaking
public IBuildMode instance; Dictionary<Player, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
public OptionEnum[] options; if (currentlyBreaking.get(player) != null && currentlyBreaking.get(player)) {
//Cancel breaking
initializeMode(player);
return;
}
BuildModeEnum(String name, IBuildMode instance, OptionEnum... options) { ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
this.name = name; ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
this.instance = instance; BuildModeEnum buildMode = modeSettings.getBuildMode();
this.options = options;
}
}
//Uses a network message to get the previous raytraceresult from the player BlockPos startPos = null;
//The server could keep track of all raytraceresults but this might lag with many players
//Raytraceresult is needed for sideHit and hitVec
public static void onBlockPlacedMessage(PlayerEntity player, BlockPlacedMessage message) {
//Check if not in the middle of breaking if (message.isBlockHit() && message.getBlockPos() != null) {
Dictionary<PlayerEntity, Boolean> currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer; startPos = message.getBlockPos();
if (currentlyBreaking.get(player) != null && currentlyBreaking.get(player)) {
//Cancel breaking
initializeMode(player);
return;
}
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); //Offset in direction of sidehit if not quickreplace and not replaceable
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); boolean replaceable = player.level.getBlockState(startPos).getMaterial().isReplaceable();
BuildModeEnum buildMode = modeSettings.getBuildMode(); boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos, message.getSideHit());
if (!modifierSettings.doQuickReplace() && !replaceable && !becomesDoubleSlab) {
startPos = startPos.relative(message.getSideHit());
}
BlockPos startPos = null; //Get under tall grass and other replaceable blocks
if (modifierSettings.doQuickReplace() && replaceable) {
startPos = startPos.below();
}
if (message.isBlockHit() && message.getBlockPos() != null) { //Check if player reach does not exceed startpos
startPos = message.getBlockPos(); int maxReach = ReachHelper.getMaxReach(player);
if (buildMode != BuildModeEnum.DISABLED && player.blockPosition().distSqr(startPos) > maxReach * maxReach) {
EffortlessBuilding.log(player, "Placement exceeds your reach.");
return;
}
}
//Offset in direction of sidehit if not quickreplace and not replaceable //Even when no starting block is found, call buildmode instance
//TODO 1.13 replaceable //We might want to place things in the air
boolean replaceable = player.world.getBlockState(startPos).getMaterial().isReplaceable(); List<BlockPos> coordinates = buildMode.instance.onRightClick(player, startPos, message.getSideHit(), message.getHitVec(), modifierSettings.doQuickReplace());
boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos, message.getSideHit());
if (!modifierSettings.doQuickReplace() && !replaceable && !becomesDoubleSlab) {
startPos = startPos.offset(message.getSideHit());
}
//Get under tall grass and other replaceable blocks if (coordinates.isEmpty()) {
if (modifierSettings.doQuickReplace() && replaceable) { currentlyBreaking.put(player, false);
startPos = startPos.down(); return;
} }
//Check if player reach does not exceed startpos //Limit number of blocks you can place
int maxReach = ReachHelper.getMaxReach(player); int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player);
if (buildMode != BuildModeEnum.NORMAL && player.getPosition().distanceSq(startPos) > maxReach * maxReach) { if (coordinates.size() > limit) {
EffortlessBuilding.log(player, "Placement exceeds your reach."); coordinates = coordinates.subList(0, limit);
return; }
}
}
//Even when no starting block is found, call buildmode instance Direction sideHit = buildMode.instance.getSideHit(player);
//We might want to place things in the air if (sideHit == null) sideHit = message.getSideHit();
List<BlockPos> coordinates = buildMode.instance.onRightClick(player, startPos, message.getSideHit(), message.getHitVec(), modifierSettings.doQuickReplace());
if (coordinates.isEmpty()) { Vec3 hitVec = buildMode.instance.getHitVec(player);
currentlyBreaking.put(player, false); if (hitVec == null) hitVec = message.getHitVec();
return;
}
//Limit number of blocks you can place BuildModifiers.onBlockPlaced(player, coordinates, sideHit, hitVec, message.getPlaceStartPos());
int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player);
if (coordinates.size() > limit) {
coordinates = coordinates.subList(0, limit);
}
Direction sideHit = buildMode.instance.getSideHit(player); //Only works when finishing a buildmode is equal to placing some blocks
if (sideHit == null) sideHit = message.getSideHit(); //No intermediate blocks allowed
currentlyBreaking.remove(player);
}
Vec3d hitVec = buildMode.instance.getHitVec(player); //Use a network message to break blocks in the distance using clientside mouse input
if (hitVec == null) hitVec = message.getHitVec(); public static void onBlockBrokenMessage(Player player, BlockBrokenMessage message) {
BlockPos startPos = message.isBlockHit() ? message.getBlockPos() : null;
onBlockBroken(player, startPos, true);
}
BuildModifiers.onBlockPlaced(player, coordinates, sideHit, hitVec, message.getPlaceStartPos()); public static void onBlockBroken(Player player, BlockPos startPos, boolean breakStartPos) {
//Only works when finishing a buildmode is equal to placing some blocks //Check if not in the middle of placing
//No intermediate blocks allowed Dictionary<Player, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
currentlyBreaking.remove(player); if (currentlyBreaking.get(player) != null && !currentlyBreaking.get(player)) {
//Cancel placing
initializeMode(player);
return;
}
} if (!ReachHelper.canBreakFar(player)) return;
//Use a network message to break blocks in the distance using clientside mouse input //If first click
public static void onBlockBrokenMessage(PlayerEntity player, BlockBrokenMessage message) { if (currentlyBreaking.get(player) == null) {
BlockPos startPos = message.isBlockHit() ? message.getBlockPos() : null; //If startpos is null, dont do anything
onBlockBroken(player, startPos, true); if (startPos == null) return;
} }
public static void onBlockBroken(PlayerEntity player, BlockPos startPos, boolean breakStartPos) { ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
//Check if not in the middle of placing //Get coordinates
Dictionary<PlayerEntity, Boolean> currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer; BuildModeEnum buildMode = modeSettings.getBuildMode();
if (currentlyBreaking.get(player) != null && !currentlyBreaking.get(player)) { List<BlockPos> coordinates = buildMode.instance.onRightClick(player, startPos, Direction.UP, Vec3.ZERO, true);
//Cancel placing
initializeMode(player);
return;
}
//If first click if (coordinates.isEmpty()) {
if (currentlyBreaking.get(player) == null) { currentlyBreaking.put(player, true);
//If startpos is null, dont do anything return;
if (startPos == null) return; }
}
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); //Let buildmodifiers break blocks
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); BuildModifiers.onBlockBroken(player, coordinates, breakStartPos);
//Get coordinates //Only works when finishing a buildmode is equal to breaking some blocks
BuildModeEnum buildMode = modeSettings.getBuildMode(); //No intermediate blocks allowed
List<BlockPos> coordinates = buildMode.instance.onRightClick(player, startPos, Direction.UP, Vec3d.ZERO, true); currentlyBreaking.remove(player);
}
if (coordinates.isEmpty()) { public static List<BlockPos> findCoordinates(Player player, BlockPos startPos, boolean skipRaytrace) {
currentlyBreaking.put(player, true); List<BlockPos> coordinates = new ArrayList<>();
return;
}
//Let buildmodifiers break blocks ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
BuildModifiers.onBlockBroken(player, coordinates, breakStartPos); coordinates.addAll(modeSettings.getBuildMode().instance.findCoordinates(player, startPos, skipRaytrace));
//Only works when finishing a buildmode is equal to breaking some blocks return coordinates;
//No intermediate blocks allowed }
currentlyBreaking.remove(player);
}
public static List<BlockPos> findCoordinates(PlayerEntity player, BlockPos startPos, boolean skipRaytrace) { public static void initializeMode(Player player) {
List<BlockPos> coordinates = new ArrayList<>(); //Resetting mode, so not placing or breaking
Dictionary<Player, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
currentlyBreaking.remove(player);
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); ModeSettingsManager.getModeSettings(player).getBuildMode().instance.initialize(player);
coordinates.addAll(modeSettings.getBuildMode().instance.findCoordinates(player, startPos, skipRaytrace)); }
return coordinates; public static boolean isCurrentlyPlacing(Player player) {
} Dictionary<Player, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
return currentlyBreaking.get(player) != null && !currentlyBreaking.get(player);
}
public static void initializeMode(PlayerEntity player) { public static boolean isCurrentlyBreaking(Player player) {
//Resetting mode, so not placing or breaking Dictionary<Player, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
Dictionary<PlayerEntity, Boolean> currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer; return currentlyBreaking.get(player) != null && currentlyBreaking.get(player);
currentlyBreaking.remove(player); }
ModeSettingsManager.getModeSettings(player).getBuildMode().instance.initialize(player); //Either placing or breaking
} public static boolean isActive(Player player) {
Dictionary<Player, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
return currentlyBreaking.get(player) != null;
}
public static boolean isCurrentlyPlacing(PlayerEntity player) { //Find coordinates on a line bound by a plane
Dictionary<PlayerEntity, Boolean> currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer; public static Vec3 findXBound(double x, Vec3 start, Vec3 look) {
return currentlyBreaking.get(player) != null && !currentlyBreaking.get(player); //then y and z are
} double y = (x - start.x) / look.x * look.y + start.y;
double z = (x - start.x) / look.x * look.z + start.z;
public static boolean isCurrentlyBreaking(PlayerEntity player) { return new Vec3(x, y, z);
Dictionary<PlayerEntity, Boolean> currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer; }
return currentlyBreaking.get(player) != null && currentlyBreaking.get(player);
}
//Either placing or breaking public static Vec3 findYBound(double y, Vec3 start, Vec3 look) {
public static boolean isActive(PlayerEntity player) { //then x and z are
Dictionary<PlayerEntity, Boolean> currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer; double x = (y - start.y) / look.y * look.x + start.x;
return currentlyBreaking.get(player) != null; double z = (y - start.y) / look.y * look.z + start.z;
}
return new Vec3(x, y, z);
}
//-- Common build mode functionality --// public static Vec3 findZBound(double z, Vec3 start, Vec3 look) {
//then x and y are
double x = (z - start.z) / look.z * look.x + start.x;
double y = (z - start.z) / look.z * look.y + start.y;
//Find coordinates on a line bound by a plane return new Vec3(x, y, z);
public static Vec3d findXBound(double x, Vec3d start, Vec3d look) { }
//then y and z are
double y = (x - start.x) / look.x * look.y + start.y;
double z = (x - start.x) / look.x * look.z + start.z;
return new Vec3d(x, y, z); //Use this instead of player.getLookVec() in any buildmodes code
} public static Vec3 getPlayerLookVec(Player player) {
Vec3 lookVec = player.getLookAngle();
double x = lookVec.x;
double y = lookVec.y;
double z = lookVec.z;
public static Vec3d findYBound(double y, Vec3d start, Vec3d look) { //Further calculations (findXBound etc) don't like any component being 0 or 1 (e.g. dividing by 0)
//then x and z are //isCriteriaValid below will take up to 2 minutes to raytrace blocks towards infinity if that is the case
double x = (y - start.y) / look.y * look.x + start.x; //So make sure they are close to but never exactly 0 or 1
double z = (y - start.y) / look.y * look.z + start.z; if (Math.abs(x) < 0.0001) x = 0.0001;
if (Math.abs(x - 1.0) < 0.0001) x = 0.9999;
if (Math.abs(x + 1.0) < 0.0001) x = -0.9999;
return new Vec3d(x, y, z); if (Math.abs(y) < 0.0001) y = 0.0001;
} if (Math.abs(y - 1.0) < 0.0001) y = 0.9999;
if (Math.abs(y + 1.0) < 0.0001) y = -0.9999;
public static Vec3d findZBound(double z, Vec3d start, Vec3d look) { if (Math.abs(z) < 0.0001) z = 0.0001;
//then x and y are if (Math.abs(z - 1.0) < 0.0001) z = 0.9999;
double x = (z - start.z) / look.z * look.x + start.x; if (Math.abs(z + 1.0) < 0.0001) z = -0.9999;
double y = (z - start.z) / look.z * look.y + start.y;
return new Vec3d(x, y, z); return new Vec3(x, y, z);
} }
//Use this instead of player.getLookVec() in any buildmodes code public static boolean isCriteriaValid(Vec3 start, Vec3 look, int reach, Player player, boolean skipRaytrace, Vec3 lineBound, Vec3 planeBound, double distToPlayerSq) {
public static Vec3d getPlayerLookVec(PlayerEntity player){ boolean intersects = false;
Vec3d lookVec = player.getLookVec(); if (!skipRaytrace) {
double x = lookVec.x; //collision within a 1 block radius to selected is fine
double y = lookVec.y; ClipContext rayTraceContext = new ClipContext(start, lineBound, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, player);
double z = lookVec.z; HitResult rayTraceResult = player.level.clip(rayTraceContext);
intersects = rayTraceResult != null && rayTraceResult.getType() == HitResult.Type.BLOCK &&
planeBound.subtract(rayTraceResult.getLocation()).lengthSqr() > 4;
}
//Further calculations (findXBound etc) don't like any component being 0 or 1 (e.g. dividing by 0) return planeBound.subtract(start).dot(look) > 0 &&
//isCriteriaValid below will take up to 2 minutes to raytrace blocks towards infinity if that is the case distToPlayerSq > 2 && distToPlayerSq < reach * reach &&
//So make sure they are close to but never exactly 0 or 1 !intersects;
if (Math.abs(x) < 0.0001) x = 0.0001; }
if (Math.abs(x - 1.0) < 0.0001) x = 0.9999;
if (Math.abs(x + 1.0) < 0.0001) x = -0.9999;
if (Math.abs(y) < 0.0001) y = 0.0001; public enum BuildModeEnum {
if (Math.abs(y - 1.0) < 0.0001) y = 0.9999; DISABLED("normal", new Disabled(), BuildModeCategoryEnum.BASIC),
if (Math.abs(y + 1.0) < 0.0001) y = -0.9999; SINGLE("normal_plus", new Single(), BuildModeCategoryEnum.BASIC, OptionEnum.BUILD_SPEED),
LINE("line", new Line(), BuildModeCategoryEnum.BASIC /*, OptionEnum.THICKNESS*/),
WALL("wall", new Wall(), BuildModeCategoryEnum.BASIC, OptionEnum.FILL),
FLOOR("floor", new Floor(), BuildModeCategoryEnum.BASIC, OptionEnum.FILL),
CUBE("cube", new Cube(), BuildModeCategoryEnum.BASIC, OptionEnum.CUBE_FILL),
DIAGONAL_LINE("diagonal_line", new DiagonalLine(), BuildModeCategoryEnum.DIAGONAL /*, OptionEnum.THICKNESS*/),
DIAGONAL_WALL("diagonal_wall", new DiagonalWall(), BuildModeCategoryEnum.DIAGONAL /*, OptionEnum.FILL*/),
SLOPE_FLOOR("slope_floor", new SlopeFloor(), BuildModeCategoryEnum.DIAGONAL, OptionEnum.RAISED_EDGE),
CIRCLE("circle", new Circle(), BuildModeCategoryEnum.CIRCULAR, OptionEnum.CIRCLE_START, OptionEnum.FILL),
CYLINDER("cylinder", new Cylinder(), BuildModeCategoryEnum.CIRCULAR, OptionEnum.CIRCLE_START, OptionEnum.FILL),
SPHERE("sphere", new Sphere(), BuildModeCategoryEnum.CIRCULAR, OptionEnum.CIRCLE_START, OptionEnum.FILL);
// PYRAMID("pyramid", new Pyramid(), BuildModeCategoryEnum.ROOF),
// CONE("cone", new Cone(), BuildModeCategoryEnum.ROOF),
// DOME("dome", new Dome(), BuildModeCategoryEnum.ROOF);
if (Math.abs(z) < 0.0001) z = 0.0001; private final String name;
if (Math.abs(z - 1.0) < 0.0001) z = 0.9999; public final IBuildMode instance;
if (Math.abs(z + 1.0) < 0.0001) z = -0.9999; public final BuildModeCategoryEnum category;
public final OptionEnum[] options;
return new Vec3d(x, y, z); BuildModeEnum(String name, IBuildMode instance, BuildModeCategoryEnum category, OptionEnum... options) {
} this.name = name;
this.instance = instance;
this.category = category;
this.options = options;
}
public static boolean isCriteriaValid(Vec3d start, Vec3d look, int reach, PlayerEntity player, boolean skipRaytrace, Vec3d lineBound, Vec3d planeBound, double distToPlayerSq) { public String getNameKey() {
boolean intersects = false; return "effortlessbuilding.mode." + name;
if (!skipRaytrace) { }
//collision within a 1 block radius to selected is fine
RayTraceContext rayTraceContext = new RayTraceContext(start, lineBound, RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.NONE, player);
RayTraceResult rayTraceResult = player.world.rayTraceBlocks(rayTraceContext);
intersects = rayTraceResult != null && rayTraceResult.getType() == RayTraceResult.Type.BLOCK &&
planeBound.subtract(rayTraceResult.getHitVec()).lengthSquared() > 4;
}
return planeBound.subtract(start).dotProduct(look) > 0 && public String getDescriptionKey() {
distToPlayerSq > 2 && distToPlayerSq < reach * reach && return "effortlessbuilding.modedescription." + name;
!intersects; }
} }
public enum BuildModeCategoryEnum {
BASIC(new Vector4f(0f, .5f, 1f, .8f)),
DIAGONAL(new Vector4f(0.56f, 0.28f, 0.87f, .8f)),
CIRCULAR(new Vector4f(0.29f, 0.76f, 0.3f, 1f)),
ROOF(new Vector4f(0.83f, 0.87f, 0.23f, .8f));
public final Vector4f color;
BuildModeCategoryEnum(Vector4f color) {
this.color = color;
}
}
} }

View File

@@ -1,25 +1,25 @@
package nl.requios.effortlessbuilding.buildmode; package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.Direction; import net.minecraft.core.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
import java.util.List; import java.util.List;
public interface IBuildMode { public interface IBuildMode {
//Fired when a player selects a buildmode and when it needs to initializeMode //Fired when a player selects a buildmode and when it needs to initializeMode
void initialize(PlayerEntity player); void initialize(Player player);
//Fired when a block would be placed //Fired when a block would be placed
//Return a list of coordinates where you want to place blocks //Return a list of coordinates where you want to place blocks
List<BlockPos> onRightClick(PlayerEntity player, BlockPos blockPos, Direction sideHit, Vec3d hitVec, boolean skipRaytrace); List<BlockPos> onRightClick(Player player, BlockPos blockPos, Direction sideHit, Vec3 hitVec, boolean skipRaytrace);
//Fired continuously for visualization purposes //Fired continuously for visualization purposes
List<BlockPos> findCoordinates(PlayerEntity player, BlockPos blockPos, boolean skipRaytrace); List<BlockPos> findCoordinates(Player player, BlockPos blockPos, boolean skipRaytrace);
Direction getSideHit(PlayerEntity player); Direction getSideHit(Player player);
Vec3d getHitVec(PlayerEntity player); Vec3 getHitVec(Player player);
} }

View File

@@ -1,7 +1,8 @@
package nl.requios.effortlessbuilding.buildmode; package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.text.TextFormatting; import net.minecraft.ChatFormatting;
import nl.requios.effortlessbuilding.ClientEvents;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo; import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
@@ -9,183 +10,183 @@ import nl.requios.effortlessbuilding.proxy.ClientProxy;
public class ModeOptions { public class ModeOptions {
public enum ActionEnum { private static ActionEnum buildSpeed = ActionEnum.NORMAL_SPEED;
UNDO("effortlessbuilding.action.undo"), private static ActionEnum fill = ActionEnum.FULL;
REDO("effortlessbuilding.action.redo"), private static ActionEnum cubeFill = ActionEnum.CUBE_FULL;
REPLACE("effortlessbuilding.action.replace"), private static ActionEnum raisedEdge = ActionEnum.SHORT_EDGE;
OPEN_MODIFIER_SETTINGS("effortlessbuilding.action.open_modifier_settings"), private static ActionEnum lineThickness = ActionEnum.THICKNESS_1;
OPEN_PLAYER_SETTINGS("effortlessbuilding.action.open_player_settings"), private static ActionEnum circleStart = ActionEnum.CIRCLE_START_CORNER;
NORMAL_SPEED("effortlessbuilding.action.normal_speed"), public static ActionEnum getOptionSetting(OptionEnum option) {
FAST_SPEED("effortlessbuilding.action.fast_speed"), switch (option) {
case BUILD_SPEED:
return getBuildSpeed();
case FILL:
return getFill();
case CUBE_FILL:
return getCubeFill();
case RAISED_EDGE:
return getRaisedEdge();
case LINE_THICKNESS:
return getLineThickness();
case CIRCLE_START:
return getCircleStart();
default:
return null;
}
}
FULL("effortlessbuilding.action.full"), public static ActionEnum getBuildSpeed() {
HOLLOW("effortlessbuilding.action.hollow"), return buildSpeed;
}
CUBE_FULL("effortlessbuilding.action.full"), public static ActionEnum getFill() {
CUBE_HOLLOW("effortlessbuilding.action.hollow"), return fill;
CUBE_SKELETON("effortlessbuilding.action.skeleton"), }
SHORT_EDGE("effortlessbuilding.action.short_edge"), public static ActionEnum getCubeFill() {
LONG_EDGE("effortlessbuilding.action.long_edge"), return cubeFill;
}
THICKNESS_1("effortlessbuilding.action.thickness_1"), public static ActionEnum getRaisedEdge() {
THICKNESS_3("effortlessbuilding.action.thickness_3"), return raisedEdge;
THICKNESS_5("effortlessbuilding.action.thickness_5"), }
CIRCLE_START_CORNER("effortlessbuilding.action.start_corner"), public static ActionEnum getLineThickness() {
CIRCLE_START_CENTER("effortlessbuilding.action.start_center"); return lineThickness;
}
public String name; public static ActionEnum getCircleStart() {
return circleStart;
}
ActionEnum(String name) { //Called on both client and server
this.name = name; public static void performAction(Player player, ActionEnum action) {
} if (action == null) return;
}
public enum OptionEnum { switch (action) {
BUILD_SPEED("effortlessbuilding.action.build_speed", ActionEnum.NORMAL_SPEED, ActionEnum.FAST_SPEED), case UNDO:
FILL("effortlessbuilding.action.filling", ActionEnum.FULL, ActionEnum.HOLLOW), UndoRedo.undo(player);
CUBE_FILL("effortlessbuilding.action.filling", ActionEnum.CUBE_FULL, ActionEnum.CUBE_HOLLOW, ActionEnum.CUBE_SKELETON), break;
RAISED_EDGE("effortlessbuilding.action.raised_edge", ActionEnum.SHORT_EDGE, ActionEnum.LONG_EDGE), case REDO:
LINE_THICKNESS("effortlessbuilding.action.thickness", ActionEnum.THICKNESS_1, ActionEnum.THICKNESS_3, ActionEnum.THICKNESS_5), UndoRedo.redo(player);
CIRCLE_START("effortlessbuilding.action.circle_start", ActionEnum.CIRCLE_START_CORNER, ActionEnum.CIRCLE_START_CENTER); break;
case REPLACE:
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
modifierSettings.setQuickReplace(!modifierSettings.doQuickReplace());
EffortlessBuilding.log(player, "Set " + ChatFormatting.GOLD + "Quick Replace " + ChatFormatting.RESET + (
modifierSettings.doQuickReplace() ? "on" : "off"), true);
break;
case OPEN_MODIFIER_SETTINGS:
if (player.level.isClientSide)
ClientEvents.openModifierSettings();
break;
case OPEN_PLAYER_SETTINGS:
if (player.level.isClientSide)
ClientEvents.openPlayerSettings();
break;
public String name; case NORMAL_SPEED:
public ActionEnum[] actions; buildSpeed = ActionEnum.NORMAL_SPEED;
break;
case FAST_SPEED:
buildSpeed = ActionEnum.FAST_SPEED;
break;
case FULL:
fill = ActionEnum.FULL;
break;
case HOLLOW:
fill = ActionEnum.HOLLOW;
break;
case CUBE_FULL:
cubeFill = ActionEnum.CUBE_FULL;
break;
case CUBE_HOLLOW:
cubeFill = ActionEnum.CUBE_HOLLOW;
break;
case CUBE_SKELETON:
cubeFill = ActionEnum.CUBE_SKELETON;
break;
case SHORT_EDGE:
raisedEdge = ActionEnum.SHORT_EDGE;
break;
case LONG_EDGE:
raisedEdge = ActionEnum.LONG_EDGE;
break;
case THICKNESS_1:
lineThickness = ActionEnum.THICKNESS_1;
break;
case THICKNESS_3:
lineThickness = ActionEnum.THICKNESS_3;
break;
case THICKNESS_5:
lineThickness = ActionEnum.THICKNESS_5;
break;
case CIRCLE_START_CENTER:
circleStart = ActionEnum.CIRCLE_START_CENTER;
break;
case CIRCLE_START_CORNER:
circleStart = ActionEnum.CIRCLE_START_CORNER;
break;
}
OptionEnum(String name, ActionEnum... actions){ if (player.level.isClientSide &&
this.name = name; action != ActionEnum.REPLACE &&
this.actions = actions; action != ActionEnum.OPEN_MODIFIER_SETTINGS &&
} action != ActionEnum.OPEN_PLAYER_SETTINGS) {
}
private static ActionEnum buildSpeed = ActionEnum.NORMAL_SPEED; EffortlessBuilding.logTranslate(player, "", action.name, "", true);
private static ActionEnum fill = ActionEnum.FULL; }
private static ActionEnum cubeFill = ActionEnum.CUBE_FULL; }
private static ActionEnum raisedEdge = ActionEnum.SHORT_EDGE;
private static ActionEnum lineThickness = ActionEnum.THICKNESS_1;
private static ActionEnum circleStart = ActionEnum.CIRCLE_START_CORNER;
public static ActionEnum getOptionSetting(OptionEnum option) { public enum ActionEnum {
switch (option) { UNDO("effortlessbuilding.action.undo"),
case BUILD_SPEED: REDO("effortlessbuilding.action.redo"),
return getBuildSpeed(); REPLACE("effortlessbuilding.action.replace"),
case FILL: OPEN_MODIFIER_SETTINGS("effortlessbuilding.action.open_modifier_settings"),
return getFill(); OPEN_PLAYER_SETTINGS("effortlessbuilding.action.open_player_settings"),
case CUBE_FILL:
return getCubeFill();
case RAISED_EDGE:
return getRaisedEdge();
case LINE_THICKNESS:
return getLineThickness();
case CIRCLE_START:
return getCircleStart();
default:
return null;
}
}
public static ActionEnum getBuildSpeed() { NORMAL_SPEED("effortlessbuilding.action.normal_speed"),
return buildSpeed; FAST_SPEED("effortlessbuilding.action.fast_speed"),
}
public static ActionEnum getFill() { FULL("effortlessbuilding.action.full"),
return fill; HOLLOW("effortlessbuilding.action.hollow"),
}
public static ActionEnum getCubeFill() { CUBE_FULL("effortlessbuilding.action.full"),
return cubeFill; CUBE_HOLLOW("effortlessbuilding.action.hollow"),
} CUBE_SKELETON("effortlessbuilding.action.skeleton"),
public static ActionEnum getRaisedEdge() { SHORT_EDGE("effortlessbuilding.action.short_edge"),
return raisedEdge; LONG_EDGE("effortlessbuilding.action.long_edge"),
}
public static ActionEnum getLineThickness() { THICKNESS_1("effortlessbuilding.action.thickness_1"),
return lineThickness; THICKNESS_3("effortlessbuilding.action.thickness_3"),
} THICKNESS_5("effortlessbuilding.action.thickness_5"),
public static ActionEnum getCircleStart() { CIRCLE_START_CORNER("effortlessbuilding.action.start_corner"),
return circleStart; CIRCLE_START_CENTER("effortlessbuilding.action.start_center");
}
//Called on both client and server public String name;
public static void performAction(PlayerEntity player, ActionEnum action) {
if (action == null) return;
switch (action) { ActionEnum(String name) {
case UNDO: this.name = name;
UndoRedo.undo(player); }
break; }
case REDO:
UndoRedo.redo(player);
break;
case REPLACE:
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
modifierSettings.setQuickReplace(!modifierSettings.doQuickReplace());
EffortlessBuilding.log(player, "Set " + TextFormatting.GOLD + "Quick Replace " + TextFormatting.RESET + (
modifierSettings.doQuickReplace() ? "on" : "off"), true);
break;
case OPEN_MODIFIER_SETTINGS:
if (player.world.isRemote)
ClientProxy.openModifierSettings();
break;
case OPEN_PLAYER_SETTINGS:
if (player.world.isRemote)
ClientProxy.openPlayerSettings();
break;
case NORMAL_SPEED: public enum OptionEnum {
buildSpeed = ActionEnum.NORMAL_SPEED; BUILD_SPEED("effortlessbuilding.action.build_speed", ActionEnum.NORMAL_SPEED, ActionEnum.FAST_SPEED),
break; FILL("effortlessbuilding.action.filling", ActionEnum.FULL, ActionEnum.HOLLOW),
case FAST_SPEED: CUBE_FILL("effortlessbuilding.action.filling", ActionEnum.CUBE_FULL, ActionEnum.CUBE_HOLLOW, ActionEnum.CUBE_SKELETON),
buildSpeed = ActionEnum.FAST_SPEED; RAISED_EDGE("effortlessbuilding.action.raised_edge", ActionEnum.SHORT_EDGE, ActionEnum.LONG_EDGE),
break; LINE_THICKNESS("effortlessbuilding.action.thickness", ActionEnum.THICKNESS_1, ActionEnum.THICKNESS_3, ActionEnum.THICKNESS_5),
case FULL: CIRCLE_START("effortlessbuilding.action.circle_start", ActionEnum.CIRCLE_START_CORNER, ActionEnum.CIRCLE_START_CENTER);
fill = ActionEnum.FULL;
break;
case HOLLOW:
fill = ActionEnum.HOLLOW;
break;
case CUBE_FULL:
cubeFill = ActionEnum.CUBE_FULL;
break;
case CUBE_HOLLOW:
cubeFill = ActionEnum.CUBE_HOLLOW;
break;
case CUBE_SKELETON:
cubeFill = ActionEnum.CUBE_SKELETON;
break;
case SHORT_EDGE:
raisedEdge = ActionEnum.SHORT_EDGE;
break;
case LONG_EDGE:
raisedEdge = ActionEnum.LONG_EDGE;
break;
case THICKNESS_1:
lineThickness = ActionEnum.THICKNESS_1;
break;
case THICKNESS_3:
lineThickness = ActionEnum.THICKNESS_3;
break;
case THICKNESS_5:
lineThickness = ActionEnum.THICKNESS_5;
break;
case CIRCLE_START_CENTER:
circleStart = ActionEnum.CIRCLE_START_CENTER;
break;
case CIRCLE_START_CORNER:
circleStart = ActionEnum.CIRCLE_START_CORNER;
break;
}
if (player.world.isRemote && public String name;
action != ActionEnum.REPLACE && public ActionEnum[] actions;
action != ActionEnum.OPEN_MODIFIER_SETTINGS &&
action != ActionEnum.OPEN_PLAYER_SETTINGS) {
EffortlessBuilding.logTranslate(player, "", action.name, "", true); OptionEnum(String name, ActionEnum... actions) {
} this.name = name;
} this.actions = actions;
}
}
} }

View File

@@ -1,10 +1,10 @@
package nl.requios.effortlessbuilding.buildmode; package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.network.PacketDistributor; import net.minecraftforge.network.PacketDistributor;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.capability.ModeCapabilityManager; import nl.requios.effortlessbuilding.capability.ModeCapabilityManager;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
@@ -16,83 +16,82 @@ import javax.annotation.Nonnull;
@Mod.EventBusSubscriber @Mod.EventBusSubscriber
public class ModeSettingsManager { public class ModeSettingsManager {
//Retrieves the buildsettings of a player through the modifierCapability capability //Retrieves the buildsettings of a player through the modeCapability capability
//Never returns null //Never returns null
@Nonnull @Nonnull
public static ModeSettings getModeSettings(PlayerEntity player) { public static ModeSettings getModeSettings(Player player) {
LazyOptional<ModeCapabilityManager.IModeCapability> modeCapability = LazyOptional<ModeCapabilityManager.IModeCapability> modeCapability =
player.getCapability(ModeCapabilityManager.modeCapability, null); player.getCapability(ModeCapabilityManager.MODE_CAPABILITY, null);
if (modeCapability.isPresent()) { if (modeCapability.isPresent()) {
ModeCapabilityManager.IModeCapability capability = modeCapability.orElse(null); ModeCapabilityManager.IModeCapability capability = modeCapability.orElse(null);
if (capability.getModeData() == null) { if (capability.getModeData() == null){
capability.setModeData(new ModeSettings()); capability.setModeData(new ModeSettings());
} }
return capability.getModeData(); return capability.getModeData();
} }
//Player does not have modeCapability capability EffortlessBuilding.logger.warn("Player does not have modeCapability: " + player);
//Return dummy settings //Return dummy settings
return new ModeSettings(); return new ModeSettings();
// throw new IllegalArgumentException("Player does not have modeCapability capability"); }
}
public static void setModeSettings(PlayerEntity player, ModeSettings modeSettings) { public static void setModeSettings(Player player, ModeSettings modeSettings) {
if (player == null) { if (player == null) {
EffortlessBuilding.log("Cannot set buildmode settings, player is null"); EffortlessBuilding.log("Cannot set buildmode settings, player is null");
return; return;
} }
LazyOptional<ModeCapabilityManager.IModeCapability> modeCapability = LazyOptional<ModeCapabilityManager.IModeCapability> modeCapability =
player.getCapability(ModeCapabilityManager.modeCapability, null); player.getCapability(ModeCapabilityManager.MODE_CAPABILITY, null);
modeCapability.ifPresent((capability) -> { modeCapability.ifPresent((capability) -> {
capability.setModeData(modeSettings); capability.setModeData(modeSettings);
BuildModes.initializeMode(player); BuildModes.initializeMode(player);
}); });
if (!modeCapability.isPresent()) { if (!modeCapability.isPresent()) {
EffortlessBuilding.log(player, "Saving buildmode settings failed."); EffortlessBuilding.log(player, "Saving buildmode settings failed.");
} }
} }
public static String sanitize(ModeSettings modeSettings, PlayerEntity player) { public static String sanitize(ModeSettings modeSettings, Player player) {
int maxReach = ReachHelper.getMaxReach(player); int maxReach = ReachHelper.getMaxReach(player);
String error = ""; String error = "";
//TODO sanitize //TODO sanitize
return error; return error;
} }
public static class ModeSettings { public static void handleNewPlayer(Player player) {
private BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.NORMAL; //Makes sure player has mode settings (if it doesnt it will create it)
getModeSettings(player);
public ModeSettings() { //Only on server
} if (!player.level.isClientSide) {
//Send to client
ModeSettingsMessage msg = new ModeSettingsMessage(getModeSettings(player));
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), msg);
}
}
public ModeSettings(BuildModes.BuildModeEnum buildMode) { public static class ModeSettings {
this.buildMode = buildMode; private BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.DISABLED;
}
public BuildModes.BuildModeEnum getBuildMode() { public ModeSettings() {
return this.buildMode; }
}
public void setBuildMode(BuildModes.BuildModeEnum buildMode) { public ModeSettings(BuildModes.BuildModeEnum buildMode) {
this.buildMode = buildMode; this.buildMode = buildMode;
} }
}
public static void handleNewPlayer(PlayerEntity player){ public BuildModes.BuildModeEnum getBuildMode() {
//Makes sure player has mode settings (if it doesnt it will create it) return this.buildMode;
getModeSettings(player); }
//Only on server public void setBuildMode(BuildModes.BuildModeEnum buildMode) {
if (!player.world.isRemote) { this.buildMode = buildMode;
//Send to client }
ModeSettingsMessage msg = new ModeSettingsMessage(getModeSettings(player)); }
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), msg);
}
}
} }

View File

@@ -1,213 +1,213 @@
package nl.requios.effortlessbuilding.buildmode; package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.Direction; import net.minecraft.core.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.*; import java.util.*;
public abstract class ThreeClicksBuildMode extends BaseBuildMode { public abstract class ThreeClicksBuildMode extends BaseBuildMode {
protected Dictionary<UUID, BlockPos> secondPosTable = new Hashtable<>(); protected Dictionary<UUID, BlockPos> secondPosTable = new Hashtable<>();
static class HeightCriteria { //Finds height after floor has been chosen in buildmodes with 3 clicks
Vec3d planeBound; public static BlockPos findHeight(Player player, BlockPos secondPos, boolean skipRaytrace) {
Vec3d lineBound; Vec3 look = BuildModes.getPlayerLookVec(player);
double distToLineSq; Vec3 start = new Vec3(player.getX(), player.getY() + player.getEyeHeight(), player.getZ());
double distToPlayerSq;
HeightCriteria(Vec3d planeBound, BlockPos secondPos, Vec3d start) { List<HeightCriteria> criteriaList = new ArrayList<>(3);
this.planeBound = planeBound;
this.lineBound = toLongestLine(this.planeBound, secondPos);
this.distToLineSq = this.lineBound.subtract(this.planeBound).lengthSquared();
this.distToPlayerSq = this.planeBound.subtract(start).lengthSquared();
}
//Make it from a plane into a line, on y axis only //X
private Vec3d toLongestLine(Vec3d boundVec, BlockPos secondPos) { Vec3 xBound = BuildModes.findXBound(secondPos.getX(), start, look);
BlockPos bound = new BlockPos(boundVec); criteriaList.add(new HeightCriteria(xBound, secondPos, start));
return new Vec3d(secondPos.getX(), bound.getY(), secondPos.getZ());
}
//check if its not behind the player and its not too close and not too far //Z
//also check if raytrace from player to block does not intersect blocks Vec3 zBound = BuildModes.findZBound(secondPos.getZ(), start, look);
public boolean isValid(Vec3d start, Vec3d look, int reach, PlayerEntity player, boolean skipRaytrace) { criteriaList.add(new HeightCriteria(zBound, secondPos, start));
return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, lineBound, planeBound, distToPlayerSq); //Remove invalid criteria
} int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
} criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
@Override //If none are valid, return empty list of blocks
public void initialize(PlayerEntity player) { if (criteriaList.isEmpty()) return null;
super.initialize(player);
secondPosTable.put(player.getUniqueID(), BlockPos.ZERO);
}
@Override //If only 1 is valid, choose that one
public List<BlockPos> onRightClick(PlayerEntity player, BlockPos blockPos, Direction sideHit, Vec3d hitVec, boolean skipRaytrace) { HeightCriteria selected = criteriaList.get(0);
List<BlockPos> list = new ArrayList<>();
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable; //If multiple are valid, choose based on criteria
int rightClickNr = rightClickTable.get(player.getUniqueID()); if (criteriaList.size() > 1) {
rightClickNr++; //Select the one that is closest (from wall position to its line counterpart)
rightClickTable.put(player.getUniqueID(), rightClickNr); for (int i = 1; i < criteriaList.size(); i++) {
HeightCriteria criteria = criteriaList.get(i);
if (criteria.distToLineSq < 2.0 && selected.distToLineSq < 2.0) {
//Both very close to line, choose closest to player
if (criteria.distToPlayerSq < selected.distToPlayerSq)
selected = criteria;
} else {
//Pick closest to line
if (criteria.distToLineSq < selected.distToLineSq)
selected = criteria;
}
}
}
return new BlockPos(selected.lineBound);
}
if (rightClickNr == 1) { @Override
//If clicking in air, reset and try again public void initialize(Player player) {
if (blockPos == null) { super.initialize(player);
rightClickTable.put(player.getUniqueID(), 0); secondPosTable.put(player.getUUID(), BlockPos.ZERO);
return list; }
}
//First click, remember starting position @Override
firstPosTable.put(player.getUniqueID(), blockPos); public List<BlockPos> onRightClick(Player player, BlockPos blockPos, Direction sideHit, Vec3 hitVec, boolean skipRaytrace) {
sideHitTable.put(player.getUniqueID(), sideHit); List<BlockPos> list = new ArrayList<>();
hitVecTable.put(player.getUniqueID(), hitVec);
//Keep list empty, dont place any blocks yet
} else if (rightClickNr == 2) {
//Second click, find other floor point
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
BlockPos secondPos = findSecondPos(player, firstPos, true);
if (secondPos == null) { Dictionary<UUID, Integer> rightClickTable = player.level.isClientSide ? rightClickClientTable : rightClickServerTable;
rightClickTable.put(player.getUniqueID(), 1); int rightClickNr = rightClickTable.get(player.getUUID());
return list; rightClickNr++;
} rightClickTable.put(player.getUUID(), rightClickNr);
secondPosTable.put(player.getUniqueID(), secondPos); if (rightClickNr == 1) {
//If clicking in air, reset and try again
if (blockPos == null) {
rightClickTable.put(player.getUUID(), 0);
return list;
}
} else { //First click, remember starting position
//Third click, place diagonal wall with height firstPosTable.put(player.getUUID(), blockPos);
list = findCoordinates(player, blockPos, skipRaytrace); sideHitTable.put(player.getUUID(), sideHit);
rightClickTable.put(player.getUniqueID(), 0); hitVecTable.put(player.getUUID(), hitVec);
} //Keep list empty, dont place any blocks yet
} else if (rightClickNr == 2) {
//Second click, find other floor point
BlockPos firstPos = firstPosTable.get(player.getUUID());
BlockPos secondPos = findSecondPos(player, firstPos, true);
return list; if (secondPos == null) {
} rightClickTable.put(player.getUUID(), 1);
return list;
}
@Override secondPosTable.put(player.getUUID(), secondPos);
public List<BlockPos> findCoordinates(PlayerEntity player, BlockPos blockPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>();
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
int rightClickNr = rightClickTable.get(player.getUniqueID());
if (rightClickNr == 0) { } else {
if (blockPos != null) //Third click, place diagonal wall with height
list.add(blockPos); list = findCoordinates(player, blockPos, skipRaytrace);
} else if (rightClickNr == 1) { rightClickTable.put(player.getUUID(), 0);
BlockPos firstPos = firstPosTable.get(player.getUniqueID()); }
BlockPos secondPos = findSecondPos(player, firstPos, true); return list;
if (secondPos == null) return list; }
//Limit amount of blocks you can place per row @Override
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player); public List<BlockPos> findCoordinates(Player player, BlockPos blockPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>();
Dictionary<UUID, Integer> rightClickTable = player.level.isClientSide ? rightClickClientTable : rightClickServerTable;
int rightClickNr = rightClickTable.get(player.getUUID());
int x1 = firstPos.getX(), x2 = secondPos.getX(); if (rightClickNr == 0) {
int y1 = firstPos.getY(), y2 = secondPos.getY(); if (blockPos != null)
int z1 = firstPos.getZ(), z2 = secondPos.getZ(); list.add(blockPos);
} else if (rightClickNr == 1) {
BlockPos firstPos = firstPosTable.get(player.getUUID());
//limit axis BlockPos secondPos = findSecondPos(player, firstPos, true);
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1; if (secondPos == null) return list;
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
//Add diagonal line from first to second //Limit amount of blocks you can place per row
list.addAll(getIntermediateBlocks(player, x1, y1, z1, x2, y2, z2)); int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
} else { int x1 = firstPos.getX(), x2 = secondPos.getX();
BlockPos firstPos = firstPosTable.get(player.getUniqueID()); int y1 = firstPos.getY(), y2 = secondPos.getY();
BlockPos secondPos = secondPosTable.get(player.getUniqueID()); int z1 = firstPos.getZ(), z2 = secondPos.getZ();
BlockPos thirdPos = findThirdPos(player, firstPos, secondPos, skipRaytrace); //limit axis
if (thirdPos == null) return list; if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
//Limit amount of blocks you can place per row //Add diagonal line from first to second
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player); list.addAll(getIntermediateBlocks(player, x1, y1, z1, x2, y2, z2));
int x1 = firstPos.getX(), x2 = secondPos.getX(), x3 = thirdPos.getX(); } else {
int y1 = firstPos.getY(), y2 = secondPos.getY(), y3 = thirdPos.getY(); BlockPos firstPos = firstPosTable.get(player.getUUID());
int z1 = firstPos.getZ(), z2 = secondPos.getZ(), z3 = thirdPos.getZ(); BlockPos secondPos = secondPosTable.get(player.getUUID());
//limit axis BlockPos thirdPos = findThirdPos(player, firstPos, secondPos, skipRaytrace);
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1; if (thirdPos == null) return list;
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
if (x3 - x1 >= axisLimit) x3 = x1 + axisLimit - 1; //Limit amount of blocks you can place per row
if (x1 - x3 >= axisLimit) x3 = x1 - axisLimit + 1; int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
if (y3 - y1 >= axisLimit) y3 = y1 + axisLimit - 1;
if (y1 - y3 >= axisLimit) y3 = y1 - axisLimit + 1;
if (z3 - z1 >= axisLimit) z3 = z1 + axisLimit - 1;
if (z1 - z3 >= axisLimit) z3 = z1 - axisLimit + 1;
//Add diagonal line from first to third int x1 = firstPos.getX(), x2 = secondPos.getX(), x3 = thirdPos.getX();
list.addAll(getFinalBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3)); int y1 = firstPos.getY(), y2 = secondPos.getY(), y3 = thirdPos.getY();
} int z1 = firstPos.getZ(), z2 = secondPos.getZ(), z3 = thirdPos.getZ();
return list; //limit axis
} if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
//Finds the place of the second block pos if (x3 - x1 >= axisLimit) x3 = x1 + axisLimit - 1;
protected abstract BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace); if (x1 - x3 >= axisLimit) x3 = x1 - axisLimit + 1;
if (y3 - y1 >= axisLimit) y3 = y1 + axisLimit - 1;
if (y1 - y3 >= axisLimit) y3 = y1 - axisLimit + 1;
if (z3 - z1 >= axisLimit) z3 = z1 + axisLimit - 1;
if (z1 - z3 >= axisLimit) z3 = z1 - axisLimit + 1;
//Finds the place of the third block pos //Add diagonal line from first to third
protected abstract BlockPos findThirdPos(PlayerEntity player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace); list.addAll(getFinalBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3));
}
//After first and second pos are known, we want to visualize the blocks in a way (like floor for cube) return list;
protected abstract List<BlockPos> getIntermediateBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2); }
//After first, second and third pos are known, we want all the blocks //Finds the place of the second block pos
protected abstract List<BlockPos> getFinalBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3); protected abstract BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace);
//Finds height after floor has been chosen in buildmodes with 3 clicks //Finds the place of the third block pos
public static BlockPos findHeight(PlayerEntity player, BlockPos secondPos, boolean skipRaytrace) { protected abstract BlockPos findThirdPos(Player player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace);
Vec3d look = BuildModes.getPlayerLookVec(player);
Vec3d start = new Vec3d(player.getPosX(), player.getPosY() + player.getEyeHeight(), player.getPosZ());
List<HeightCriteria> criteriaList = new ArrayList<>(3); //After first and second pos are known, we want to visualize the blocks in a way (like floor for cube)
protected abstract List<BlockPos> getIntermediateBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2);
//X //After first, second and third pos are known, we want all the blocks
Vec3d xBound = BuildModes.findXBound(secondPos.getX(), start, look); protected abstract List<BlockPos> getFinalBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3);
criteriaList.add(new HeightCriteria(xBound, secondPos, start));
//Z static class HeightCriteria {
Vec3d zBound = BuildModes.findZBound(secondPos.getZ(), start, look); Vec3 planeBound;
criteriaList.add(new HeightCriteria(zBound, secondPos, start)); Vec3 lineBound;
double distToLineSq;
double distToPlayerSq;
//Remove invalid criteria HeightCriteria(Vec3 planeBound, BlockPos secondPos, Vec3 start) {
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach this.planeBound = planeBound;
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace)); this.lineBound = toLongestLine(this.planeBound, secondPos);
this.distToLineSq = this.lineBound.subtract(this.planeBound).lengthSqr();
this.distToPlayerSq = this.planeBound.subtract(start).lengthSqr();
}
//If none are valid, return empty list of blocks //Make it from a plane into a line, on y axis only
if (criteriaList.isEmpty()) return null; private Vec3 toLongestLine(Vec3 boundVec, BlockPos secondPos) {
BlockPos bound = new BlockPos(boundVec);
return new Vec3(secondPos.getX(), bound.getY(), secondPos.getZ());
}
//If only 1 is valid, choose that one //check if its not behind the player and its not too close and not too far
HeightCriteria selected = criteriaList.get(0); //also check if raytrace from player to block does not intersect blocks
public boolean isValid(Vec3 start, Vec3 look, int reach, Player player, boolean skipRaytrace) {
//If multiple are valid, choose based on criteria return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, lineBound, planeBound, distToPlayerSq);
if (criteriaList.size() > 1) { }
//Select the one that is closest (from wall position to its line counterpart) }
for (int i = 1; i < criteriaList.size(); i++) {
HeightCriteria criteria = criteriaList.get(i);
if (criteria.distToLineSq < 2.0 && selected.distToLineSq < 2.0) {
//Both very close to line, choose closest to player
if (criteria.distToPlayerSq < selected.distToPlayerSq)
selected = criteria;
} else {
//Pick closest to line
if (criteria.distToLineSq < selected.distToLineSq)
selected = criteria;
}
}
}
return new BlockPos(selected.lineBound);
}
} }

View File

@@ -1,10 +1,9 @@
package nl.requios.effortlessbuilding.buildmode; package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.Direction; import net.minecraft.core.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.ArrayList; import java.util.ArrayList;
@@ -14,74 +13,74 @@ import java.util.UUID;
public abstract class TwoClicksBuildMode extends BaseBuildMode { public abstract class TwoClicksBuildMode extends BaseBuildMode {
@Override @Override
public List<BlockPos> onRightClick(PlayerEntity player, BlockPos blockPos, Direction sideHit, Vec3d hitVec, boolean skipRaytrace) { public List<BlockPos> onRightClick(Player player, BlockPos blockPos, Direction sideHit, Vec3 hitVec, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>(); List<BlockPos> list = new ArrayList<>();
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable; Dictionary<UUID, Integer> rightClickTable = player.level.isClientSide ? rightClickClientTable : rightClickServerTable;
int rightClickNr = rightClickTable.get(player.getUniqueID()); int rightClickNr = rightClickTable.get(player.getUUID());
rightClickNr++; rightClickNr++;
rightClickTable.put(player.getUniqueID(), rightClickNr); rightClickTable.put(player.getUUID(), rightClickNr);
if (rightClickNr == 1) { if (rightClickNr == 1) {
//If clicking in air, reset and try again //If clicking in air, reset and try again
if (blockPos == null) { if (blockPos == null) {
rightClickTable.put(player.getUniqueID(), 0); rightClickTable.put(player.getUUID(), 0);
return list; return list;
} }
//First click, remember starting position //First click, remember starting position
firstPosTable.put(player.getUniqueID(), blockPos); firstPosTable.put(player.getUUID(), blockPos);
sideHitTable.put(player.getUniqueID(), sideHit); sideHitTable.put(player.getUUID(), sideHit);
hitVecTable.put(player.getUniqueID(), hitVec); hitVecTable.put(player.getUUID(), hitVec);
//Keep list empty, dont place any blocks yet //Keep list empty, dont place any blocks yet
} else { } else {
//Second click, place blocks //Second click, place blocks
list = findCoordinates(player, blockPos, skipRaytrace); list = findCoordinates(player, blockPos, skipRaytrace);
rightClickTable.put(player.getUniqueID(), 0); rightClickTable.put(player.getUUID(), 0);
} }
return list; return list;
} }
@Override @Override
public List<BlockPos> findCoordinates(PlayerEntity player, BlockPos blockPos, boolean skipRaytrace) { public List<BlockPos> findCoordinates(Player player, BlockPos blockPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>(); List<BlockPos> list = new ArrayList<>();
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable; Dictionary<UUID, Integer> rightClickTable = player.level.isClientSide ? rightClickClientTable : rightClickServerTable;
int rightClickNr = rightClickTable.get(player.getUniqueID()); int rightClickNr = rightClickTable.get(player.getUUID());
BlockPos firstPos = firstPosTable.get(player.getUniqueID()); BlockPos firstPos = firstPosTable.get(player.getUUID());
if (rightClickNr == 0) { if (rightClickNr == 0) {
if (blockPos != null) if (blockPos != null)
list.add(blockPos); list.add(blockPos);
} else { } else {
BlockPos secondPos = findSecondPos(player, firstPos, skipRaytrace); BlockPos secondPos = findSecondPos(player, firstPos, skipRaytrace);
if (secondPos == null) return list; if (secondPos == null) return list;
//Limit amount of blocks we can place per row //Limit amount of blocks we can place per row
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player); int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
int x1 = firstPos.getX(), x2 = secondPos.getX(); int x1 = firstPos.getX(), x2 = secondPos.getX();
int y1 = firstPos.getY(), y2 = secondPos.getY(); int y1 = firstPos.getY(), y2 = secondPos.getY();
int z1 = firstPos.getZ(), z2 = secondPos.getZ(); int z1 = firstPos.getZ(), z2 = secondPos.getZ();
//limit axis //limit axis
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1; if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1; if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1; if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1; if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1; if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1; if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
list.addAll(getAllBlocks(player, x1, y1, z1, x2, y2, z2)); list.addAll(getAllBlocks(player, x1, y1, z1, x2, y2, z2));
} }
return list; return list;
} }
//Finds the place of the second block pos based on criteria (floor must be on same height as first click, wall on same plane etc) //Finds the place of the second block pos based on criteria (floor must be on same height as first click, wall on same plane etc)
protected abstract BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace); protected abstract BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace);
//After first and second pos are known, we want all the blocks //After first and second pos are known, we want all the blocks
protected abstract List<BlockPos> getAllBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2); protected abstract List<BlockPos> getAllBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2);
} }

View File

@@ -1,88 +1,89 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.Mth;
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
import nl.requios.effortlessbuilding.buildmode.ModeOptions; import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
import java.util.*; import java.util.ArrayList;
import java.util.List;
public class Circle extends TwoClicksBuildMode { public class Circle extends TwoClicksBuildMode {
@Override public static List<BlockPos> getCircleBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { List<BlockPos> list = new ArrayList<>();
return Floor.findFloor(player, firstPos, skipRaytrace);
}
@Override float centerX = x1;
protected List<BlockPos> getAllBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { float centerZ = z1;
return getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
}
public static List<BlockPos> getCircleBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { //Adjust for CIRCLE_START
List<BlockPos> list = new ArrayList<>(); if (ModeOptions.getCircleStart() == ModeOptions.ActionEnum.CIRCLE_START_CORNER) {
centerX = x1 + (x2 - x1) / 2f;
centerZ = z1 + (z2 - z1) / 2f;
} else {
x1 = (int) (centerX - (x2 - centerX));
z1 = (int) (centerZ - (z2 - centerZ));
}
float centerX = x1; float radiusX = Mth.abs(x2 - centerX);
float centerZ = z1; float radiusZ = Mth.abs(z2 - centerZ);
//Adjust for CIRCLE_START if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
if (ModeOptions.getCircleStart() == ModeOptions.ActionEnum.CIRCLE_START_CORNER) { addCircleBlocks(list, x1, y1, z1, x2, y2, z2, centerX, centerZ, radiusX, radiusZ);
centerX = x1 + (x2 - x1) / 2f; else
centerZ = z1 + (z2 - z1) / 2f; addHollowCircleBlocks(list, x1, y1, z1, x2, y2, z2, centerX, centerZ, radiusX, radiusZ);
} else {
x1 = (int) (centerX - (x2 - centerX));
z1 = (int) (centerZ - (z2 - centerZ));
}
float radiusX = MathHelper.abs(x2 - centerX); return list;
float radiusZ = MathHelper.abs(z2 - centerZ); }
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL) public static void addCircleBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2, float centerX, float centerZ, float radiusX, float radiusZ) {
addCircleBlocks(list, x1, y1, z1, x2, y2, z2, centerX, centerZ, radiusX, radiusZ);
else
addHollowCircleBlocks(list, x1, y1, z1, x2, y2, z2, centerX, centerZ, radiusX, radiusZ);
return list; for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) {
}
public static void addCircleBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2, float centerX, float centerZ, float radiusX, float radiusZ) { for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) {
for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) { float distance = distance(l, n, centerX, centerZ);
float radius = calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, l, n);
if (distance < radius + 0.4f)
list.add(new BlockPos(l, y1, n));
}
}
}
for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) { public static void addHollowCircleBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2, float centerX, float centerZ, float radiusX, float radiusZ) {
float distance = distance(l, n, centerX, centerZ); for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) {
float radius = calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, l, n);
if (distance < radius + 0.4f)
list.add(new BlockPos(l, y1, n));
}
}
}
public static void addHollowCircleBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2, float centerX, float centerZ, float radiusX, float radiusZ) { for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) {
for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) { float distance = distance(l, n, centerX, centerZ);
float radius = calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, l, n);
if (distance < radius + 0.4f && distance > radius - 0.6f)
list.add(new BlockPos(l, y1, n));
}
}
}
for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) { private static float distance(float x1, float z1, float x2, float z2) {
return Mth.sqrt((x2 - x1) * (x2 - x1) + (z2 - z1) * (z2 - z1));
}
float distance = distance(l, n, centerX, centerZ); public static float calculateEllipseRadius(float centerX, float centerZ, float radiusX, float radiusZ, int x, int z) {
float radius = calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, l, n); //https://math.stackexchange.com/questions/432902/how-to-get-the-radius-of-an-ellipse-at-a-specific-angle-by-knowing-its-semi-majo
if (distance < radius + 0.4f && distance > radius - 0.6f) float theta = (float) Mth.atan2(z - centerZ, x - centerX);
list.add(new BlockPos(l, y1, n)); float part1 = radiusX * radiusX * Mth.sin(theta) * Mth.sin(theta);
} float part2 = radiusZ * radiusZ * Mth.cos(theta) * Mth.cos(theta);
} return radiusX * radiusZ / Mth.sqrt(part1 + part2);
} }
private static float distance(float x1, float z1, float x2, float z2) { @Override
return MathHelper.sqrt((x2 - x1) * (x2 - x1) + (z2 - z1) * (z2 - z1)); protected BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace) {
} return Floor.findFloor(player, firstPos, skipRaytrace);
}
public static float calculateEllipseRadius(float centerX, float centerZ, float radiusX, float radiusZ, int x, int z) { @Override
//https://math.stackexchange.com/questions/432902/how-to-get-the-radius-of-an-ellipse-at-a-specific-angle-by-knowing-its-semi-majo protected List<BlockPos> getAllBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
float theta = (float) MathHelper.atan2(z - centerZ, x - centerX); return getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
float part1 = radiusX * radiusX * MathHelper.sin(theta) * MathHelper.sin(theta); }
float part2 = radiusZ * radiusZ * MathHelper.cos(theta) * MathHelper.cos(theta);
return radiusX * radiusZ / MathHelper.sqrt(part1 + part2);
}
} }

View File

@@ -0,0 +1,31 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.player.Player;
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
import java.util.List;
public class Cone extends ThreeClicksBuildMode {
@Override
protected BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace) {
return Floor.findFloor(player, firstPos, skipRaytrace);
}
@Override
protected BlockPos findThirdPos(Player player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
return findHeight(player, secondPos, skipRaytrace);
}
@Override
protected List<BlockPos> getIntermediateBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
return Floor.getFloorBlocks(player, x1, y1, z1, x2, y2, z2);
}
@Override
protected List<BlockPos> getFinalBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
//TODO
return SlopeFloor.getSlopeFloorBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
}
}

View File

@@ -1,100 +1,101 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import nl.requios.effortlessbuilding.buildmode.ModeOptions; import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
import java.util.*; import java.util.ArrayList;
import java.util.List;
public class Cube extends ThreeClicksBuildMode { public class Cube extends ThreeClicksBuildMode {
@Override public static List<BlockPos> getFloorBlocksUsingCubeFill(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { List<BlockPos> list = new ArrayList<>();
return Floor.findFloor(player, firstPos, skipRaytrace);
}
@Override if (ModeOptions.getCubeFill() == ModeOptions.ActionEnum.CUBE_SKELETON)
protected BlockPos findThirdPos(PlayerEntity player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) { Floor.addHollowFloorBlocks(list, x1, x2, y1, z1, z2);
return findHeight(player, secondPos, skipRaytrace); else
} Floor.addFloorBlocks(list, x1, x2, y1, z1, z2);
@Override return list;
protected List<BlockPos> getIntermediateBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { }
return getFloorBlocksUsingCubeFill(player, x1, y1, z1, x2, y2, z2);
}
@Override public static List<BlockPos> getCubeBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
protected List<BlockPos> getFinalBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { List<BlockPos> list = new ArrayList<>();
return getCubeBlocks(player, x1, y1, z1, x3, y3, z3);
}
public static List<BlockPos> getFloorBlocksUsingCubeFill(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { switch (ModeOptions.getCubeFill()) {
List<BlockPos> list = new ArrayList<>(); case CUBE_FULL:
addCubeBlocks(list, x1, x2, y1, y2, z1, z2);
break;
case CUBE_HOLLOW:
addHollowCubeBlocks(list, x1, x2, y1, y2, z1, z2);
break;
case CUBE_SKELETON:
addSkeletonCubeBlocks(list, x1, x2, y1, y2, z1, z2);
break;
}
if (ModeOptions.getCubeFill() == ModeOptions.ActionEnum.CUBE_SKELETON) return list;
Floor.addHollowFloorBlocks(list, x1, x2, y1, z1, z2); }
else
Floor.addFloorBlocks(list, x1, x2, y1, z1, z2);
return list; public static void addCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) {
} for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) {
public static List<BlockPos> getCubeBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) {
List<BlockPos> list = new ArrayList<>();
switch (ModeOptions.getCubeFill()) { for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) {
case CUBE_FULL: list.add(new BlockPos(l, m, n));
addCubeBlocks(list, x1, x2, y1, y2, z1, z2); }
break; }
case CUBE_HOLLOW: }
addHollowCubeBlocks(list, x1, x2, y1, y2, z1, z2); }
break;
case CUBE_SKELETON:
addSkeletonCubeBlocks(list, x1, x2, y1, y2, z1, z2);
break;
}
return list; public static void addHollowCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) {
} Wall.addXWallBlocks(list, x1, y1, y2, z1, z2);
Wall.addXWallBlocks(list, x2, y1, y2, z1, z2);
public static void addCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) { Wall.addZWallBlocks(list, x1, x2, y1, y2, z1);
for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) { Wall.addZWallBlocks(list, x1, x2, y1, y2, z2);
for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) { Floor.addFloorBlocks(list, x1, x2, y1, z1, z2);
Floor.addFloorBlocks(list, x1, x2, y2, z1, z2);
}
for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) { public static void addSkeletonCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) {
list.add(new BlockPos(l, m, n)); Line.addXLineBlocks(list, x1, x2, y1, z1);
} Line.addXLineBlocks(list, x1, x2, y1, z2);
} Line.addXLineBlocks(list, x1, x2, y2, z1);
} Line.addXLineBlocks(list, x1, x2, y2, z2);
}
public static void addHollowCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) { Line.addYLineBlocks(list, y1, y2, x1, z1);
Wall.addXWallBlocks(list, x1, y1, y2, z1, z2); Line.addYLineBlocks(list, y1, y2, x1, z2);
Wall.addXWallBlocks(list, x2, y1, y2, z1, z2); Line.addYLineBlocks(list, y1, y2, x2, z1);
Line.addYLineBlocks(list, y1, y2, x2, z2);
Wall.addZWallBlocks(list, x1, x2, y1, y2, z1); Line.addZLineBlocks(list, z1, z2, x1, y1);
Wall.addZWallBlocks(list, x1, x2, y1, y2, z2); Line.addZLineBlocks(list, z1, z2, x1, y2);
Line.addZLineBlocks(list, z1, z2, x2, y1);
Line.addZLineBlocks(list, z1, z2, x2, y2);
}
Floor.addFloorBlocks(list, x1, x2, y1, z1, z2); @Override
Floor.addFloorBlocks(list, x1, x2, y2, z1, z2); protected BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace) {
} return Floor.findFloor(player, firstPos, skipRaytrace);
}
public static void addSkeletonCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) { @Override
Line.addXLineBlocks(list, x1, x2, y1, z1); protected BlockPos findThirdPos(Player player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
Line.addXLineBlocks(list, x1, x2, y1, z2); return findHeight(player, secondPos, skipRaytrace);
Line.addXLineBlocks(list, x1, x2, y2, z1); }
Line.addXLineBlocks(list, x1, x2, y2, z2);
Line.addYLineBlocks(list, y1, y2, x1, z1); @Override
Line.addYLineBlocks(list, y1, y2, x1, z2); protected List<BlockPos> getIntermediateBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
Line.addYLineBlocks(list, y1, y2, x2, z1); return getFloorBlocksUsingCubeFill(player, x1, y1, z1, x2, y2, z2);
Line.addYLineBlocks(list, y1, y2, x2, z2); }
Line.addZLineBlocks(list, z1, z2, x1, y1); @Override
Line.addZLineBlocks(list, z1, z2, x1, y2); protected List<BlockPos> getFinalBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
Line.addZLineBlocks(list, z1, z2, x2, y1); return getCubeBlocks(player, x1, y1, z1, x3, y3, z3);
Line.addZLineBlocks(list, z1, z2, x2, y2); }
}
} }

View File

@@ -1,7 +1,7 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
import java.util.ArrayList; import java.util.ArrayList;
@@ -9,42 +9,42 @@ import java.util.List;
public class Cylinder extends ThreeClicksBuildMode { public class Cylinder extends ThreeClicksBuildMode {
@Override public static List<BlockPos> getCylinderBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
public BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { List<BlockPos> list = new ArrayList<>();
return Floor.findFloor(player, firstPos, skipRaytrace);
}
@Override //Get circle blocks (using CIRCLE_START and FILL options built-in)
public BlockPos findThirdPos(PlayerEntity player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) { List<BlockPos> circleBlocks = Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
return findHeight(player, secondPos, skipRaytrace);
}
@Override int lowest = Math.min(y1, y3);
public List<BlockPos> getIntermediateBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { int highest = Math.max(y1, y3);
return Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
}
@Override //Copy circle on y axis
public List<BlockPos> getFinalBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { for (int y = lowest; y <= highest; y++) {
return getCylinderBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3); for (BlockPos blockPos : circleBlocks) {
} list.add(new BlockPos(blockPos.getX(), y, blockPos.getZ()));
}
}
public static List<BlockPos> getCylinderBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { return list;
List<BlockPos> list = new ArrayList<>(); }
//Get circle blocks (using CIRCLE_START and FILL options built-in) @Override
List<BlockPos> circleBlocks = Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2); public BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace) {
return Floor.findFloor(player, firstPos, skipRaytrace);
}
int lowest = Math.min(y1, y3); @Override
int highest = Math.max(y1, y3); public BlockPos findThirdPos(Player player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
return findHeight(player, secondPos, skipRaytrace);
}
//Copy circle on y axis @Override
for (int y = lowest; y <= highest; y++) { public List<BlockPos> getIntermediateBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
for (BlockPos blockPos : circleBlocks) { return Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
list.add(new BlockPos(blockPos.getX(), y, blockPos.getZ())); }
}
}
return list; @Override
} public List<BlockPos> getFinalBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
return getCylinderBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
}
} }

View File

@@ -1,8 +1,8 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
import java.util.ArrayList; import java.util.ArrayList;
@@ -10,44 +10,44 @@ import java.util.List;
public class DiagonalLine extends ThreeClicksBuildMode { public class DiagonalLine extends ThreeClicksBuildMode {
@Override //Add diagonal line from first to second
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { public static List<BlockPos> getDiagonalLineBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, float sampleMultiplier) {
return Floor.findFloor(player, firstPos, skipRaytrace); List<BlockPos> list = new ArrayList<>();
}
@Override Vec3 first = new Vec3(x1, y1, z1).add(0.5, 0.5, 0.5);
protected BlockPos findThirdPos(PlayerEntity player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) { Vec3 second = new Vec3(x2, y2, z2).add(0.5, 0.5, 0.5);
return findHeight(player, secondPos, skipRaytrace);
}
@Override int iterations = (int) Math.ceil(first.distanceTo(second) * sampleMultiplier);
protected List<BlockPos> getIntermediateBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { for (double t = 0; t <= 1.0; t += 1.0 / iterations) {
//Add diagonal line from first to second Vec3 lerp = first.add(second.subtract(first).scale(t));
return getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 10); BlockPos candidate = new BlockPos(lerp);
} //Only add if not equal to the last in the list
if (list.isEmpty() || !list.get(list.size() - 1).equals(candidate))
list.add(candidate);
}
@Override return list;
protected List<BlockPos> getFinalBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { }
//Add diagonal line from first to third
return getDiagonalLineBlocks(player, x1, y1, z1, x3, y3, z3, 10);
}
//Add diagonal line from first to second @Override
public static List<BlockPos> getDiagonalLineBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, float sampleMultiplier) { protected BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>(); return Floor.findFloor(player, firstPos, skipRaytrace);
}
Vec3d first = new Vec3d(x1, y1, z1).add(0.5, 0.5, 0.5); @Override
Vec3d second = new Vec3d(x2, y2, z2).add(0.5, 0.5, 0.5); protected BlockPos findThirdPos(Player player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
return findHeight(player, secondPos, skipRaytrace);
}
int iterations = (int) Math.ceil(first.distanceTo(second) * sampleMultiplier); @Override
for (double t = 0; t <= 1.0; t += 1.0/iterations) { protected List<BlockPos> getIntermediateBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
Vec3d lerp = first.add(second.subtract(first).scale(t)); //Add diagonal line from first to second
BlockPos candidate = new BlockPos(lerp); return getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 10);
//Only add if not equal to the last in the list }
if (list.isEmpty() || !list.get(list.size() - 1).equals(candidate))
list.add(candidate);
}
return list; @Override
} protected List<BlockPos> getFinalBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
//Add diagonal line from first to third
return getDiagonalLineBlocks(player, x1, y1, z1, x3, y3, z3, 10);
}
} }

View File

@@ -1,7 +1,7 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
import java.util.ArrayList; import java.util.ArrayList;
@@ -9,43 +9,43 @@ import java.util.List;
public class DiagonalWall extends ThreeClicksBuildMode { public class DiagonalWall extends ThreeClicksBuildMode {
@Override //Add diagonal wall from first to second
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { public static List<BlockPos> getDiagonalWallBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
return Floor.findFloor(player, firstPos, skipRaytrace); List<BlockPos> list = new ArrayList<>();
}
@Override //Get diagonal line blocks
protected BlockPos findThirdPos(PlayerEntity player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) { List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 1);
return findHeight(player, secondPos, skipRaytrace);
}
@Override int lowest = Math.min(y1, y3);
protected List<BlockPos> getIntermediateBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { int highest = Math.max(y1, y3);
return DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 1);
}
@Override //Copy diagonal line on y axis
protected List<BlockPos> getFinalBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { for (int y = lowest; y <= highest; y++) {
return getDiagonalWallBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3); for (BlockPos blockPos : diagonalLineBlocks) {
} list.add(new BlockPos(blockPos.getX(), y, blockPos.getZ()));
}
}
//Add diagonal wall from first to second return list;
public static List<BlockPos> getDiagonalWallBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { }
List<BlockPos> list = new ArrayList<>();
//Get diagonal line blocks @Override
List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 1); protected BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace) {
return Floor.findFloor(player, firstPos, skipRaytrace);
}
int lowest = Math.min(y1, y3); @Override
int highest = Math.max(y1, y3); protected BlockPos findThirdPos(Player player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
return findHeight(player, secondPos, skipRaytrace);
}
//Copy diagonal line on y axis @Override
for (int y = lowest; y <= highest; y++) { protected List<BlockPos> getIntermediateBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
for (BlockPos blockPos : diagonalLineBlocks) { return DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 1);
list.add(new BlockPos(blockPos.getX(), y, blockPos.getZ())); }
}
}
return list; @Override
} protected List<BlockPos> getFinalBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
return getDiagonalWallBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
}
} }

View File

@@ -0,0 +1,41 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.world.entity.player.Player;
import net.minecraft.core.Direction;
import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.Vec3;
import nl.requios.effortlessbuilding.buildmode.IBuildMode;
import java.util.ArrayList;
import java.util.List;
public class Disabled implements IBuildMode {
@Override
public void initialize(Player player) {
}
@Override
public List<BlockPos> onRightClick(Player player, BlockPos blockPos, Direction sideHit, Vec3 hitVec, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>();
if (blockPos != null) list.add(blockPos);
return list;
}
@Override
public List<BlockPos> findCoordinates(Player player, BlockPos blockPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>();
if (blockPos != null) list.add(blockPos);
return list;
}
@Override
public Direction getSideHit(Player player) {
return null;
}
@Override
public Vec3 getHitVec(Player player) {
return null;
}
}

View File

@@ -0,0 +1,31 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.player.Player;
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
import java.util.List;
public class Dome extends ThreeClicksBuildMode {
@Override
protected BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace) {
return Floor.findFloor(player, firstPos, skipRaytrace);
}
@Override
protected BlockPos findThirdPos(Player player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
return findHeight(player, secondPos, skipRaytrace);
}
@Override
protected List<BlockPos> getIntermediateBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
return Floor.getFloorBlocks(player, x1, y1, z1, x2, y2, z2);
}
@Override
protected List<BlockPos> getFinalBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
//TODO
return SlopeFloor.getSlopeFloorBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
}
}

View File

@@ -1,93 +1,94 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
import nl.requios.effortlessbuilding.buildmode.ModeOptions; import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.*; import java.util.ArrayList;
import java.util.List;
public class Floor extends TwoClicksBuildMode { public class Floor extends TwoClicksBuildMode {
static class Criteria { public static BlockPos findFloor(Player player, BlockPos firstPos, boolean skipRaytrace) {
Vec3d planeBound; Vec3 look = BuildModes.getPlayerLookVec(player);
double distToPlayerSq; Vec3 start = new Vec3(player.getX(), player.getY() + player.getEyeHeight(), player.getZ());
Criteria(Vec3d planeBound, Vec3d start) { List<Criteria> criteriaList = new ArrayList<>(3);
this.planeBound = planeBound;
this.distToPlayerSq = this.planeBound.subtract(start).lengthSquared();
}
//check if its not behind the player and its not too close and not too far //Y
//also check if raytrace from player to block does not intersect blocks Vec3 yBound = BuildModes.findYBound(firstPos.getY(), start, look);
public boolean isValid(Vec3d start, Vec3d look, int reach, PlayerEntity player, boolean skipRaytrace) { criteriaList.add(new Criteria(yBound, start));
return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, planeBound, planeBound, distToPlayerSq); //Remove invalid criteria
} int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
} criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
@Override //If none are valid, return empty list of blocks
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { if (criteriaList.isEmpty()) return null;
return findFloor(player, firstPos, skipRaytrace);
}
public static BlockPos findFloor(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { //Then only 1 can be valid, return that one
Vec3d look = BuildModes.getPlayerLookVec(player); Criteria selected = criteriaList.get(0);
Vec3d start = new Vec3d(player.getPosX(), player.getPosY() + player.getEyeHeight(), player.getPosZ());
List<Criteria> criteriaList = new ArrayList<>(3); return new BlockPos(selected.planeBound);
}
//Y public static List<BlockPos> getFloorBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
Vec3d yBound = BuildModes.findYBound(firstPos.getY(), start, look); List<BlockPos> list = new ArrayList<>();
criteriaList.add(new Criteria(yBound, start));
//Remove invalid criteria if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach addFloorBlocks(list, x1, x2, y1, z1, z2);
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace)); else
addHollowFloorBlocks(list, x1, x2, y1, z1, z2);
//If none are valid, return empty list of blocks return list;
if (criteriaList.isEmpty()) return null; }
//Then only 1 can be valid, return that one public static void addFloorBlocks(List<BlockPos> list, int x1, int x2, int y, int z1, int z2) {
Criteria selected = criteriaList.get(0);
return new BlockPos(selected.planeBound); for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) {
}
@Override for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) {
protected List<BlockPos> getAllBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) {
return getFloorBlocks(player, x1, y1, z1, x2, y2, z2);
}
public static List<BlockPos> getFloorBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { list.add(new BlockPos(l, y, n));
List<BlockPos> list = new ArrayList<>(); }
}
}
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL) public static void addHollowFloorBlocks(List<BlockPos> list, int x1, int x2, int y, int z1, int z2) {
addFloorBlocks(list, x1, x2, y1, z1, z2); Line.addXLineBlocks(list, x1, x2, y, z1);
else Line.addXLineBlocks(list, x1, x2, y, z2);
addHollowFloorBlocks(list, x1, x2, y1, z1, z2); Line.addZLineBlocks(list, z1, z2, x1, y);
Line.addZLineBlocks(list, z1, z2, x2, y);
}
return list; @Override
} protected BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace) {
return findFloor(player, firstPos, skipRaytrace);
}
public static void addFloorBlocks(List<BlockPos> list, int x1, int x2, int y, int z1, int z2) { @Override
protected List<BlockPos> getAllBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
return getFloorBlocks(player, x1, y1, z1, x2, y2, z2);
}
for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) { static class Criteria {
Vec3 planeBound;
double distToPlayerSq;
for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) { Criteria(Vec3 planeBound, Vec3 start) {
this.planeBound = planeBound;
this.distToPlayerSq = this.planeBound.subtract(start).lengthSqr();
}
list.add(new BlockPos(l, y, n)); //check if its not behind the player and its not too close and not too far
} //also check if raytrace from player to block does not intersect blocks
} public boolean isValid(Vec3 start, Vec3 look, int reach, Player player, boolean skipRaytrace) {
}
public static void addHollowFloorBlocks(List<BlockPos> list, int x1, int x2, int y, int z1, int z2) { return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, planeBound, planeBound, distToPlayerSq);
Line.addXLineBlocks(list, x1, x2, y, z1); }
Line.addXLineBlocks(list, x1, x2, y, z2); }
Line.addZLineBlocks(list, z1, z2, x1, y);
Line.addZLineBlocks(list, z1, z2, x2, y);
}
} }

View File

@@ -1,9 +1,8 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
@@ -13,136 +12,136 @@ import java.util.List;
public class Line extends TwoClicksBuildMode { public class Line extends TwoClicksBuildMode {
static class Criteria { public static BlockPos findLine(Player player, BlockPos firstPos, boolean skipRaytrace) {
Vec3d planeBound; Vec3 look = BuildModes.getPlayerLookVec(player);
Vec3d lineBound; Vec3 start = new Vec3(player.getX(), player.getY() + player.getEyeHeight(), player.getZ());
double distToLineSq;
double distToPlayerSq;
Criteria(Vec3d planeBound, BlockPos firstPos, Vec3d start) { List<Criteria> criteriaList = new ArrayList<>(3);
this.planeBound = planeBound;
this.lineBound = toLongestLine(this.planeBound, firstPos);
this.distToLineSq = this.lineBound.subtract(this.planeBound).lengthSquared();
this.distToPlayerSq = this.planeBound.subtract(start).lengthSquared();
}
//Make it from a plane into a line //X
//Select the axis that is longest Vec3 xBound = BuildModes.findXBound(firstPos.getX(), start, look);
private Vec3d toLongestLine(Vec3d boundVec, BlockPos firstPos) { criteriaList.add(new Criteria(xBound, firstPos, start));
BlockPos bound = new BlockPos(boundVec);
BlockPos firstToSecond = bound.subtract(firstPos); //Y
firstToSecond = new BlockPos(Math.abs(firstToSecond.getX()), Math.abs(firstToSecond.getY()), Math.abs(firstToSecond.getZ())); Vec3 yBound = BuildModes.findYBound(firstPos.getY(), start, look);
int longest = Math.max(firstToSecond.getX(), Math.max(firstToSecond.getY(), firstToSecond.getZ())); criteriaList.add(new Criteria(yBound, firstPos, start));
if (longest == firstToSecond.getX()) {
return new Vec3d(bound.getX(), firstPos.getY(), firstPos.getZ());
}
if (longest == firstToSecond.getY()) {
return new Vec3d(firstPos.getX(), bound.getY(), firstPos.getZ());
}
if (longest == firstToSecond.getZ()) {
return new Vec3d(firstPos.getX(), firstPos.getY(), bound.getZ());
}
return null;
}
//check if its not behind the player and its not too close and not too far //Z
//also check if raytrace from player to block does not intersect blocks Vec3 zBound = BuildModes.findZBound(firstPos.getZ(), start, look);
public boolean isValid(Vec3d start, Vec3d look, int reach, PlayerEntity player, boolean skipRaytrace) { criteriaList.add(new Criteria(zBound, firstPos, start));
return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, lineBound, planeBound, distToPlayerSq); //Remove invalid criteria
} int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
} //If none are valid, return empty list of blocks
if (criteriaList.isEmpty()) return null;
@Override //If only 1 is valid, choose that one
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { Criteria selected = criteriaList.get(0);
return findLine(player, firstPos, skipRaytrace);
}
public static BlockPos findLine(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { //If multiple are valid, choose based on criteria
Vec3d look = BuildModes.getPlayerLookVec(player); if (criteriaList.size() > 1) {
Vec3d start = new Vec3d(player.getPosX(), player.getPosY() + player.getEyeHeight(), player.getPosZ()); //Select the one that is closest (from wall position to its line counterpart)
for (int i = 1; i < criteriaList.size(); i++) {
Criteria criteria = criteriaList.get(i);
if (criteria.distToLineSq < 2.0 && selected.distToLineSq < 2.0) {
//Both very close to line, choose closest to player
if (criteria.distToPlayerSq < selected.distToPlayerSq)
selected = criteria;
} else {
//Pick closest to line
if (criteria.distToLineSq < selected.distToLineSq)
selected = criteria;
}
}
List<Criteria> criteriaList = new ArrayList<>(3); }
//X return new BlockPos(selected.lineBound);
Vec3d xBound = BuildModes.findXBound(firstPos.getX(), start, look); }
criteriaList.add(new Criteria(xBound, firstPos, start));
//Y public static List<BlockPos> getLineBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
Vec3d yBound = BuildModes.findYBound(firstPos.getY(), start, look); List<BlockPos> list = new ArrayList<>();
criteriaList.add(new Criteria(yBound, firstPos, start));
//Z if (x1 != x2) {
Vec3d zBound = BuildModes.findZBound(firstPos.getZ(), start, look); addXLineBlocks(list, x1, x2, y1, z1);
criteriaList.add(new Criteria(zBound, firstPos, start)); } else if (y1 != y2) {
addYLineBlocks(list, y1, y2, x1, z1);
} else {
addZLineBlocks(list, z1, z2, x1, y1);
}
//Remove invalid criteria return list;
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach }
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
//If none are valid, return empty list of blocks public static void addXLineBlocks(List<BlockPos> list, int x1, int x2, int y, int z) {
if (criteriaList.isEmpty()) return null; for (int x = x1; x1 < x2 ? x <= x2 : x >= x2; x += x1 < x2 ? 1 : -1) {
list.add(new BlockPos(x, y, z));
}
}
//If only 1 is valid, choose that one public static void addYLineBlocks(List<BlockPos> list, int y1, int y2, int x, int z) {
Criteria selected = criteriaList.get(0); for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) {
list.add(new BlockPos(x, y, z));
}
}
//If multiple are valid, choose based on criteria public static void addZLineBlocks(List<BlockPos> list, int z1, int z2, int x, int y) {
if (criteriaList.size() > 1) { for (int z = z1; z1 < z2 ? z <= z2 : z >= z2; z += z1 < z2 ? 1 : -1) {
//Select the one that is closest (from wall position to its line counterpart) list.add(new BlockPos(x, y, z));
for (int i = 1; i < criteriaList.size(); i++) { }
Criteria criteria = criteriaList.get(i); }
if (criteria.distToLineSq < 2.0 && selected.distToLineSq < 2.0) {
//Both very close to line, choose closest to player
if (criteria.distToPlayerSq < selected.distToPlayerSq)
selected = criteria;
} else {
//Pick closest to line
if (criteria.distToLineSq < selected.distToLineSq)
selected = criteria;
}
}
} @Override
protected BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace) {
return findLine(player, firstPos, skipRaytrace);
}
return new BlockPos(selected.lineBound); @Override
} protected List<BlockPos> getAllBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
return getLineBlocks(player, x1, y1, z1, x2, y2, z2);
}
@Override static class Criteria {
protected List<BlockPos> getAllBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { Vec3 planeBound;
return getLineBlocks(player, x1, y1, z1, x2, y2, z2); Vec3 lineBound;
} double distToLineSq;
double distToPlayerSq;
public static List<BlockPos> getLineBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { Criteria(Vec3 planeBound, BlockPos firstPos, Vec3 start) {
List<BlockPos> list = new ArrayList<>(); this.planeBound = planeBound;
this.lineBound = toLongestLine(this.planeBound, firstPos);
this.distToLineSq = this.lineBound.subtract(this.planeBound).lengthSqr();
this.distToPlayerSq = this.planeBound.subtract(start).lengthSqr();
}
if (x1 != x2) { //Make it from a plane into a line
addXLineBlocks(list, x1, x2, y1, z1); //Select the axis that is longest
} else if (y1 != y2) { private Vec3 toLongestLine(Vec3 boundVec, BlockPos firstPos) {
addYLineBlocks(list, y1, y2, x1, z1); BlockPos bound = new BlockPos(boundVec);
} else {
addZLineBlocks(list, z1, z2, x1, y1);
}
return list; BlockPos firstToSecond = bound.subtract(firstPos);
} firstToSecond = new BlockPos(Math.abs(firstToSecond.getX()), Math.abs(firstToSecond.getY()), Math.abs(firstToSecond.getZ()));
int longest = Math.max(firstToSecond.getX(), Math.max(firstToSecond.getY(), firstToSecond.getZ()));
if (longest == firstToSecond.getX()) {
return new Vec3(bound.getX(), firstPos.getY(), firstPos.getZ());
}
if (longest == firstToSecond.getY()) {
return new Vec3(firstPos.getX(), bound.getY(), firstPos.getZ());
}
if (longest == firstToSecond.getZ()) {
return new Vec3(firstPos.getX(), firstPos.getY(), bound.getZ());
}
return null;
}
public static void addXLineBlocks(List<BlockPos> list, int x1, int x2, int y, int z) { //check if its not behind the player and its not too close and not too far
for (int x = x1; x1 < x2 ? x <= x2 : x >= x2; x += x1 < x2 ? 1 : -1) { //also check if raytrace from player to block does not intersect blocks
list.add(new BlockPos(x, y, z)); public boolean isValid(Vec3 start, Vec3 look, int reach, Player player, boolean skipRaytrace) {
}
}
public static void addYLineBlocks(List<BlockPos> list, int y1, int y2, int x, int z) { return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, lineBound, planeBound, distToPlayerSq);
for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) { }
list.add(new BlockPos(x, y, z));
}
}
public static void addZLineBlocks(List<BlockPos> list, int z1, int z2, int x, int y) { }
for (int z = z1; z1 < z2 ? z <= z2 : z >= z2; z += z1 < z2 ? 1 : -1) {
list.add(new BlockPos(x, y, z));
}
}
} }

View File

@@ -1,41 +0,0 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import nl.requios.effortlessbuilding.buildmode.IBuildMode;
import java.util.ArrayList;
import java.util.List;
public class Normal implements IBuildMode {
@Override
public void initialize(PlayerEntity player) {
}
@Override
public List<BlockPos> onRightClick(PlayerEntity player, BlockPos blockPos, Direction sideHit, Vec3d hitVec, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>();
if (blockPos != null) list.add(blockPos);
return list;
}
@Override
public List<BlockPos> findCoordinates(PlayerEntity player, BlockPos blockPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>();
if (blockPos != null) list.add(blockPos);
return list;
}
@Override
public Direction getSideHit(PlayerEntity player) {
return null;
}
@Override
public Vec3d getHitVec(PlayerEntity player) {
return null;
}
}

View File

@@ -1,41 +0,0 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import nl.requios.effortlessbuilding.buildmode.IBuildMode;
import java.util.ArrayList;
import java.util.List;
public class NormalPlus implements IBuildMode {
@Override
public void initialize(PlayerEntity player) {
}
@Override
public List<BlockPos> onRightClick(PlayerEntity player, BlockPos blockPos, Direction sideHit, Vec3d hitVec, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>();
if (blockPos != null) list.add(blockPos);
return list;
}
@Override
public List<BlockPos> findCoordinates(PlayerEntity player, BlockPos blockPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>();
if (blockPos != null) list.add(blockPos);
return list;
}
@Override
public Direction getSideHit(PlayerEntity player) {
return null;
}
@Override
public Vec3d getHitVec(PlayerEntity player) {
return null;
}
}

View File

@@ -0,0 +1,34 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.player.Player;
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.ArrayList;
import java.util.List;
public class Pyramid extends ThreeClicksBuildMode {
@Override
protected BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace) {
return Floor.findFloor(player, firstPos, skipRaytrace);
}
@Override
protected BlockPos findThirdPos(Player player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
return findHeight(player, secondPos, skipRaytrace);
}
@Override
protected List<BlockPos> getIntermediateBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
return Floor.getFloorBlocks(player, x1, y1, z1, x2, y2, z2);
}
@Override
protected List<BlockPos> getFinalBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
//TODO
return SlopeFloor.getSlopeFloorBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
}
}

View File

@@ -0,0 +1,41 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.world.entity.player.Player;
import net.minecraft.core.Direction;
import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.Vec3;
import nl.requios.effortlessbuilding.buildmode.IBuildMode;
import java.util.ArrayList;
import java.util.List;
public class Single implements IBuildMode {
@Override
public void initialize(Player player) {
}
@Override
public List<BlockPos> onRightClick(Player player, BlockPos blockPos, Direction sideHit, Vec3 hitVec, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>();
if (blockPos != null) list.add(blockPos);
return list;
}
@Override
public List<BlockPos> findCoordinates(Player player, BlockPos blockPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>();
if (blockPos != null) list.add(blockPos);
return list;
}
@Override
public Direction getSideHit(Player player) {
return null;
}
@Override
public Vec3 getHitVec(Player player) {
return null;
}
}

View File

@@ -1,7 +1,7 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import nl.requios.effortlessbuilding.buildmode.ModeOptions; import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
@@ -11,85 +11,85 @@ import java.util.List;
public class SlopeFloor extends ThreeClicksBuildMode { public class SlopeFloor extends ThreeClicksBuildMode {
@Override //Add slope floor from first to second
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { public static List<BlockPos> getSlopeFloorBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
return Floor.findFloor(player, firstPos, skipRaytrace); List<BlockPos> list = new ArrayList<>();
}
@Override int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
protected BlockPos findThirdPos(PlayerEntity player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
return findHeight(player, secondPos, skipRaytrace);
}
@Override //Determine whether to use x or z axis to slope up
protected List<BlockPos> getIntermediateBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { boolean onXAxis = true;
return Floor.getFloorBlocks(player, x1, y1, z1, x2, y2, z2);
}
@Override int xLength = Math.abs(x2 - x1);
protected List<BlockPos> getFinalBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { int zLength = Math.abs(z2 - z1);
return getSlopeFloorBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
}
//Add slope floor from first to second if (ModeOptions.getRaisedEdge() == ModeOptions.ActionEnum.SHORT_EDGE) {
public static List<BlockPos> getSlopeFloorBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { //Slope along short edge
List<BlockPos> list = new ArrayList<>(); if (zLength > xLength) onXAxis = false;
} else {
//Slope along long edge
if (zLength <= xLength) onXAxis = false;
}
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player); if (onXAxis) {
//Along X goes up
//Determine whether to use x or z axis to slope up //Get diagonal line blocks
boolean onXAxis = true; List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y3, z1, 1f);
int xLength = Math.abs(x2 - x1); //Limit amount of blocks we can place
int zLength = Math.abs(z2 - z1); int lowest = Math.min(z1, z2);
int highest = Math.max(z1, z2);
if (ModeOptions.getRaisedEdge() == ModeOptions.ActionEnum.SHORT_EDGE) { if (highest - lowest >= axisLimit) highest = lowest + axisLimit - 1;
//Slope along short edge
if (zLength > xLength) onXAxis = false;
} else {
//Slope along long edge
if (zLength <= xLength) onXAxis = false;
}
if (onXAxis) { //Copy diagonal line on x axis
//Along X goes up for (int z = lowest; z <= highest; z++) {
for (BlockPos blockPos : diagonalLineBlocks) {
list.add(new BlockPos(blockPos.getX(), blockPos.getY(), z));
}
}
//Get diagonal line blocks } else {
List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y3, z1, 1f); //Along Z goes up
//Limit amount of blocks we can place //Get diagonal line blocks
int lowest = Math.min(z1, z2); List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x1, y3, z2, 1f);
int highest = Math.max(z1, z2);
if (highest - lowest >= axisLimit) highest = lowest + axisLimit - 1; //Limit amount of blocks we can place
int lowest = Math.min(x1, x2);
int highest = Math.max(x1, x2);
//Copy diagonal line on x axis if (highest - lowest >= axisLimit) highest = lowest + axisLimit - 1;
for (int z = lowest; z <= highest; z++) {
for (BlockPos blockPos : diagonalLineBlocks) {
list.add(new BlockPos(blockPos.getX(), blockPos.getY(), z));
}
}
} else { //Copy diagonal line on x axis
//Along Z goes up for (int x = lowest; x <= highest; x++) {
for (BlockPos blockPos : diagonalLineBlocks) {
list.add(new BlockPos(x, blockPos.getY(), blockPos.getZ()));
}
}
}
//Get diagonal line blocks return list;
List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x1, y3, z2, 1f); }
//Limit amount of blocks we can place @Override
int lowest = Math.min(x1, x2); protected BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace) {
int highest = Math.max(x1, x2); return Floor.findFloor(player, firstPos, skipRaytrace);
}
if (highest - lowest >= axisLimit) highest = lowest + axisLimit - 1; @Override
protected BlockPos findThirdPos(Player player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
return findHeight(player, secondPos, skipRaytrace);
}
//Copy diagonal line on x axis @Override
for (int x = lowest; x <= highest; x++) { protected List<BlockPos> getIntermediateBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
for (BlockPos blockPos : diagonalLineBlocks) { return Floor.getFloorBlocks(player, x1, y1, z1, x2, y2, z2);
list.add(new BlockPos(x, blockPos.getY(), blockPos.getZ())); }
}
}
}
return list; @Override
} protected List<BlockPos> getFinalBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
return getSlopeFloorBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
}
} }

View File

@@ -1,8 +1,8 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.Mth;
import nl.requios.effortlessbuilding.buildmode.ModeOptions; import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
@@ -11,100 +11,100 @@ import java.util.List;
public class Sphere extends ThreeClicksBuildMode { public class Sphere extends ThreeClicksBuildMode {
@Override public static List<BlockPos> getSphereBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
public BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { List<BlockPos> list = new ArrayList<>();
return Floor.findFloor(player, firstPos, skipRaytrace);
}
@Override float centerX = x1;
public BlockPos findThirdPos(PlayerEntity player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) { float centerY = y1;
return findHeight(player, secondPos, skipRaytrace); float centerZ = z1;
}
@Override //Adjust for CIRCLE_START
public List<BlockPos> getIntermediateBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { if (ModeOptions.getCircleStart() == ModeOptions.ActionEnum.CIRCLE_START_CORNER) {
return Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2); centerX = x1 + (x2 - x1) / 2f;
} centerY = y1 + (y3 - y1) / 2f;
centerZ = z1 + (z2 - z1) / 2f;
} else {
x1 = (int) (centerX - (x2 - centerX));
y1 = (int) (centerY - (y3 - centerY));
z1 = (int) (centerZ - (z2 - centerZ));
}
@Override float radiusX = Mth.abs(x2 - centerX);
public List<BlockPos> getFinalBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { float radiusY = Mth.abs(y3 - centerY);
return getSphereBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3); float radiusZ = Mth.abs(z2 - centerZ);
}
public static List<BlockPos> getSphereBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
List<BlockPos> list = new ArrayList<>(); addSphereBlocks(list, x1, y1, z1, x3, y3, z3, centerX, centerY, centerZ, radiusX, radiusY, radiusZ);
else
addHollowSphereBlocks(list, x1, y1, z1, x3, y3, z3, centerX, centerY, centerZ, radiusX, radiusY, radiusZ);
float centerX = x1; return list;
float centerY = y1; }
float centerZ = z1;
//Adjust for CIRCLE_START public static void addSphereBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2,
if (ModeOptions.getCircleStart() == ModeOptions.ActionEnum.CIRCLE_START_CORNER) { float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ) {
centerX = x1 + (x2 - x1) / 2f; for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) {
centerY = y1 + (y3 - y1) / 2f;
centerZ = z1 + (z2 - z1) / 2f;
} else {
x1 = (int) (centerX - (x2 - centerX));
y1 = (int) (centerY - (y3 - centerY));
z1 = (int) (centerZ - (z2 - centerZ));
}
float radiusX = MathHelper.abs(x2 - centerX); for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) {
float radiusY = MathHelper.abs(y3 - centerY);
float radiusZ = MathHelper.abs(z2 - centerZ);
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL) for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) {
addSphereBlocks(list, x1, y1, z1, x3, y3, z3, centerX, centerY, centerZ, radiusX, radiusY, radiusZ);
else
addHollowSphereBlocks(list, x1, y1, z1, x3, y3, z3, centerX, centerY, centerZ, radiusX, radiusY, radiusZ);
return list; float distance = distance(l, m, n, centerX, centerY, centerZ);
} float radius = calculateSpheroidRadius(centerX, centerY, centerZ, radiusX, radiusY, radiusZ, l, m, n);
if (distance < radius + 0.4f)
list.add(new BlockPos(l, m, n));
}
}
}
}
public static void addSphereBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2, public static void addHollowSphereBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2,
float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ) { float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ) {
for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) { for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) {
for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) { for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) {
for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) { for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) {
float distance = distance(l, m, n, centerX, centerY, centerZ); float distance = distance(l, m, n, centerX, centerY, centerZ);
float radius = calculateSpheroidRadius(centerX, centerY, centerZ, radiusX, radiusY, radiusZ, l, m, n); float radius = calculateSpheroidRadius(centerX, centerY, centerZ, radiusX, radiusY, radiusZ, l, m, n);
if (distance < radius + 0.4f) if (distance < radius + 0.4f && distance > radius - 0.6f)
list.add(new BlockPos(l, m, n)); list.add(new BlockPos(l, m, n));
} }
} }
} }
} }
public static void addHollowSphereBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2, private static float distance(float x1, float y1, float z1, float x2, float y2, float z2) {
float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ) { return Mth.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1));
for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) { }
for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) { public static float calculateSpheroidRadius(float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ, int x, int y, int z) {
//Twice ellipse radius
float radiusXZ = Circle.calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, x, z);
for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) { //TODO project x to plane
float distance = distance(l, m, n, centerX, centerY, centerZ); return Circle.calculateEllipseRadius(centerX, centerY, radiusXZ, radiusY, x, y);
float radius = calculateSpheroidRadius(centerX, centerY, centerZ, radiusX, radiusY, radiusZ, l, m, n); }
if (distance < radius + 0.4f && distance > radius - 0.6f)
list.add(new BlockPos(l, m, n));
}
}
}
}
private static float distance(float x1, float y1, float z1, float x2, float y2, float z2) { @Override
return MathHelper.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1)); public BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace) {
} return Floor.findFloor(player, firstPos, skipRaytrace);
}
public static float calculateSpheroidRadius(float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ, int x, int y, int z) { @Override
//Twice ellipse radius public BlockPos findThirdPos(Player player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
float radiusXZ = Circle.calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, x, z); return findHeight(player, secondPos, skipRaytrace);
}
//TODO project x to plane @Override
public List<BlockPos> getIntermediateBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
return Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
}
return Circle.calculateEllipseRadius(centerX, centerY, radiusXZ, radiusY, x, y); @Override
} public List<BlockPos> getFinalBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
return getSphereBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
}
} }

View File

@@ -1,134 +1,135 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
import nl.requios.effortlessbuilding.buildmode.ModeOptions; import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.*; import java.util.ArrayList;
import java.util.List;
public class Wall extends TwoClicksBuildMode { public class Wall extends TwoClicksBuildMode {
static class Criteria { public static BlockPos findWall(Player player, BlockPos firstPos, boolean skipRaytrace) {
Vec3d planeBound; Vec3 look = BuildModes.getPlayerLookVec(player);
double distToPlayerSq; Vec3 start = new Vec3(player.getX(), player.getY() + player.getEyeHeight(), player.getZ());
double angle;
Criteria(Vec3d planeBound, BlockPos firstPos, Vec3d start, Vec3d look) { List<Criteria> criteriaList = new ArrayList<>(3);
this.planeBound = planeBound;
this.distToPlayerSq = this.planeBound.subtract(start).lengthSquared();
Vec3d wall = this.planeBound.subtract(new Vec3d(firstPos));
this.angle = wall.x * look.x + wall.z * look.z; //dot product ignoring y (looking up/down should not affect this angle)
}
//check if its not behind the player and its not too close and not too far //X
//also check if raytrace from player to block does not intersect blocks Vec3 xBound = BuildModes.findXBound(firstPos.getX(), start, look);
public boolean isValid(Vec3d start, Vec3d look, int reach, PlayerEntity player, boolean skipRaytrace) { criteriaList.add(new Criteria(xBound, firstPos, start, look));
return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, planeBound, planeBound, distToPlayerSq); //Z
} Vec3 zBound = BuildModes.findZBound(firstPos.getZ(), start, look);
} criteriaList.add(new Criteria(zBound, firstPos, start, look));
@Override //Remove invalid criteria
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
return findWall(player, firstPos, skipRaytrace); criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
}
public static BlockPos findWall(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { //If none are valid, return empty list of blocks
Vec3d look = BuildModes.getPlayerLookVec(player); if (criteriaList.isEmpty()) return null;
Vec3d start = new Vec3d(player.getPosX(), player.getPosY() + player.getEyeHeight(), player.getPosZ());
List<Criteria> criteriaList = new ArrayList<>(3); //If only 1 is valid, choose that one
Criteria selected = criteriaList.get(0);
//X //If multiple are valid, choose based on criteria
Vec3d xBound = BuildModes.findXBound(firstPos.getX(), start, look); if (criteriaList.size() > 1) {
criteriaList.add(new Criteria(xBound, firstPos, start, look)); //Select the one that is closest
//Limit the angle to not be too extreme
for (int i = 1; i < criteriaList.size(); i++) {
Criteria criteria = criteriaList.get(i);
if (criteria.distToPlayerSq < selected.distToPlayerSq && Math.abs(criteria.angle) - Math.abs(selected.angle) < 3)
selected = criteria;
}
}
//Z return new BlockPos(selected.planeBound);
Vec3d zBound = BuildModes.findZBound(firstPos.getZ(), start, look); }
criteriaList.add(new Criteria(zBound, firstPos, start, look));
//Remove invalid criteria public static List<BlockPos> getWallBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach List<BlockPos> list = new ArrayList<>();
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
//If none are valid, return empty list of blocks if (x1 == x2) {
if (criteriaList.isEmpty()) return null; if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
addXWallBlocks(list, x1, y1, y2, z1, z2);
else
addXHollowWallBlocks(list, x1, y1, y2, z1, z2);
} else {
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
addZWallBlocks(list, x1, x2, y1, y2, z1);
else
addZHollowWallBlocks(list, x1, x2, y1, y2, z1);
}
//If only 1 is valid, choose that one return list;
Criteria selected = criteriaList.get(0); }
//If multiple are valid, choose based on criteria public static void addXWallBlocks(List<BlockPos> list, int x, int y1, int y2, int z1, int z2) {
if (criteriaList.size() > 1) {
//Select the one that is closest
//Limit the angle to not be too extreme
for (int i = 1; i < criteriaList.size(); i++) {
Criteria criteria = criteriaList.get(i);
if (criteria.distToPlayerSq < selected.distToPlayerSq && Math.abs(criteria.angle) - Math.abs(selected.angle) < 3)
selected = criteria;
}
}
return new BlockPos(selected.planeBound); for (int z = z1; z1 < z2 ? z <= z2 : z >= z2; z += z1 < z2 ? 1 : -1) {
}
@Override for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) {
protected List<BlockPos> getAllBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { list.add(new BlockPos(x, y, z));
return getWallBlocks(player, x1, y1, z1, x2, y2, z2); }
} }
}
public static List<BlockPos> getWallBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { public static void addZWallBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z) {
List<BlockPos> list = new ArrayList<>();
if (x1 == x2) { for (int x = x1; x1 < x2 ? x <= x2 : x >= x2; x += x1 < x2 ? 1 : -1) {
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
addXWallBlocks(list, x1, y1, y2, z1, z2);
else
addXHollowWallBlocks(list, x1, y1, y2, z1, z2);
} else {
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
addZWallBlocks(list, x1, x2, y1, y2, z1);
else
addZHollowWallBlocks(list, x1, x2, y1, y2, z1);
}
return list; for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) {
} list.add(new BlockPos(x, y, z));
}
}
}
public static void addXWallBlocks(List<BlockPos> list, int x, int y1, int y2, int z1, int z2) { public static void addXHollowWallBlocks(List<BlockPos> list, int x, int y1, int y2, int z1, int z2) {
Line.addZLineBlocks(list, z1, z2, x, y1);
Line.addZLineBlocks(list, z1, z2, x, y2);
Line.addYLineBlocks(list, y1, y2, x, z1);
Line.addYLineBlocks(list, y1, y2, x, z2);
}
for (int z = z1; z1 < z2 ? z <= z2 : z >= z2; z += z1 < z2 ? 1 : -1) { public static void addZHollowWallBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z) {
Line.addXLineBlocks(list, x1, x2, y1, z);
Line.addXLineBlocks(list, x1, x2, y2, z);
Line.addYLineBlocks(list, y1, y2, x1, z);
Line.addYLineBlocks(list, y1, y2, x2, z);
}
for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) { @Override
list.add(new BlockPos(x, y, z)); protected BlockPos findSecondPos(Player player, BlockPos firstPos, boolean skipRaytrace) {
} return findWall(player, firstPos, skipRaytrace);
} }
}
public static void addZWallBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z) { @Override
protected List<BlockPos> getAllBlocks(Player player, int x1, int y1, int z1, int x2, int y2, int z2) {
return getWallBlocks(player, x1, y1, z1, x2, y2, z2);
}
for (int x = x1; x1 < x2 ? x <= x2 : x >= x2; x += x1 < x2 ? 1 : -1) { static class Criteria {
Vec3 planeBound;
double distToPlayerSq;
double angle;
for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) { Criteria(Vec3 planeBound, BlockPos firstPos, Vec3 start, Vec3 look) {
list.add(new BlockPos(x, y, z)); this.planeBound = planeBound;
} this.distToPlayerSq = this.planeBound.subtract(start).lengthSqr();
} Vec3 wall = this.planeBound.subtract(Vec3.atLowerCornerOf(firstPos));
} this.angle = wall.x * look.x + wall.z * look.z; //dot product ignoring y (looking up/down should not affect this angle)
}
public static void addXHollowWallBlocks(List<BlockPos> list, int x, int y1, int y2, int z1, int z2) { //check if its not behind the player and its not too close and not too far
Line.addZLineBlocks(list, z1, z2, x, y1); //also check if raytrace from player to block does not intersect blocks
Line.addZLineBlocks(list, z1, z2, x, y2); public boolean isValid(Vec3 start, Vec3 look, int reach, Player player, boolean skipRaytrace) {
Line.addYLineBlocks(list, y1, y2, x, z1);
Line.addYLineBlocks(list, y1, y2, x, z2);
}
public static void addZHollowWallBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z) { return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, planeBound, planeBound, distToPlayerSq);
Line.addXLineBlocks(list, x1, x2, y1, z); }
Line.addXLineBlocks(list, x1, x2, y2, z); }
Line.addYLineBlocks(list, y1, y2, x1, z);
Line.addYLineBlocks(list, y1, y2, x2, z);
}
} }

View File

@@ -1,104 +1,104 @@
package nl.requios.effortlessbuilding.buildmodifier; package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.util.Direction; import net.minecraft.core.Direction;
import net.minecraft.util.Hand; import net.minecraft.world.InteractionHand;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
import net.minecraft.util.math.Vec3i; import net.minecraft.core.Vec3i;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import nl.requios.effortlessbuilding.item.ItemRandomizerBag; import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Array { public class Array {
public static class ArraySettings{ public static List<BlockPos> findCoordinates(Player player, BlockPos startPos) {
public boolean enabled = false; List<BlockPos> coordinates = new ArrayList<>();
public BlockPos offset = BlockPos.ZERO;
public int count = 5;
public ArraySettings() { //find arraysettings for the player
} ArraySettings a = ModifierSettingsManager.getModifierSettings(player).getArraySettings();
if (!isEnabled(a)) return coordinates;
public ArraySettings(boolean enabled, BlockPos offset, int count) { BlockPos pos = startPos;
this.enabled = enabled; Vec3i offset = new Vec3i(a.offset.getX(), a.offset.getY(), a.offset.getZ());
this.offset = offset;
this.count = count;
}
public int getReach() { for (int i = 0; i < a.count; i++) {
//find largest offset pos = pos.offset(offset);
int x = Math.abs(offset.getX()); coordinates.add(pos);
int y = Math.abs(offset.getY()); }
int z = Math.abs(offset.getZ());
int largestOffset = Math.max(Math.max(x, y), z);
return largestOffset * count; return coordinates;
} }
}
public static List<BlockPos> findCoordinates(PlayerEntity player, BlockPos startPos) { public static List<BlockState> findBlockStates(Player player, BlockPos startPos, BlockState blockState, ItemStack itemStack, List<ItemStack> itemStacks) {
List<BlockPos> coordinates = new ArrayList<>(); List<BlockState> blockStates = new ArrayList<>();
//find arraysettings for the player //find arraysettings for the player that placed the block
ArraySettings a = ModifierSettingsManager.getModifierSettings(player).getArraySettings(); ArraySettings a = ModifierSettingsManager.getModifierSettings(player).getArraySettings();
if (!isEnabled(a)) return coordinates; if (!isEnabled(a)) return blockStates;
BlockPos pos = startPos; BlockPos pos = startPos;
Vec3i offset = new Vec3i(a.offset.getX(), a.offset.getY(), a.offset.getZ()); Vec3i offset = new Vec3i(a.offset.getX(), a.offset.getY(), a.offset.getZ());
for (int i = 0; i < a.count; i++) { //Randomizer bag synergy
pos = pos.add(offset); AbstractRandomizerBagItem randomizerBagItem = null;
coordinates.add(pos); IItemHandler bagInventory = null;
} if (!itemStack.isEmpty() && itemStack.getItem() instanceof AbstractRandomizerBagItem) {
randomizerBagItem = (AbstractRandomizerBagItem) itemStack.getItem() ;
bagInventory = randomizerBagItem.getBagInventory(itemStack);
}
return coordinates; for (int i = 0; i < a.count; i++) {
} pos = pos.offset(offset);
public static List<BlockState> findBlockStates(PlayerEntity player, BlockPos startPos, BlockState blockState, ItemStack itemStack, List<ItemStack> itemStacks) { //Randomizer bag synergy
List<BlockState> blockStates = new ArrayList<>(); if (randomizerBagItem != null) {
itemStack = randomizerBagItem.pickRandomStack(bagInventory);
blockState = BuildModifiers
.getBlockStateFromItem(itemStack, player, startPos, Direction.UP, new Vec3(0, 0, 0), InteractionHand.MAIN_HAND);
}
//find arraysettings for the player that placed the block //blockState = blockState.getBlock().getStateForPlacement(player.world, pos, )
ArraySettings a = ModifierSettingsManager.getModifierSettings(player).getArraySettings(); blockStates.add(blockState);
if (!isEnabled(a)) return blockStates; itemStacks.add(itemStack);
}
BlockPos pos = startPos; return blockStates;
Vec3i offset = new Vec3i(a.offset.getX(), a.offset.getY(), a.offset.getZ()); }
//Randomizer bag synergy public static boolean isEnabled(ArraySettings a) {
IItemHandler bagInventory = null; if (a == null || !a.enabled) return false;
if (!itemStack.isEmpty() && itemStack.getItem() instanceof ItemRandomizerBag) {
bagInventory = ItemRandomizerBag.getBagInventory(itemStack);
}
for (int i = 0; i < a.count; i++) { return a.offset.getX() != 0 || a.offset.getY() != 0 || a.offset.getZ() != 0;
pos = pos.add(offset); }
//Randomizer bag synergy public static class ArraySettings {
if (bagInventory != null) { public boolean enabled = false;
itemStack = ItemRandomizerBag.pickRandomStack(bagInventory); public BlockPos offset = BlockPos.ZERO;
blockState = BuildModifiers public int count = 5;
.getBlockStateFromItem(itemStack, player, startPos, Direction.UP, new Vec3d(0, 0, 0), Hand.MAIN_HAND);
}
//blockState = blockState.getBlock().getStateForPlacement(player.world, pos, ) public ArraySettings() {
blockStates.add(blockState); }
itemStacks.add(itemStack);
}
return blockStates; public ArraySettings(boolean enabled, BlockPos offset, int count) {
} this.enabled = enabled;
this.offset = offset;
this.count = count;
}
public static boolean isEnabled(ArraySettings a) { public int getReach() {
if (a == null || !a.enabled) return false; //find largest offset
int x = Math.abs(offset.getX());
int y = Math.abs(offset.getY());
int z = Math.abs(offset.getZ());
int largestOffset = Math.max(Math.max(x, y), z);
if (a.offset.getX() == 0 && a.offset.getY() == 0 && a.offset.getZ() == 0) return false; return largestOffset * count;
}
return true; }
}
} }

View File

@@ -1,50 +1,50 @@
package nl.requios.effortlessbuilding.buildmodifier; package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
import java.util.List; import java.util.List;
public class BlockSet { public class BlockSet {
private List<BlockPos> coordinates; private final List<BlockPos> coordinates;
private List<BlockState> previousBlockStates; private final List<BlockState> previousBlockStates;
private List<BlockState> newBlockStates; private final List<BlockState> newBlockStates;
private Vec3d hitVec; private final Vec3 hitVec;
private BlockPos firstPos; private final BlockPos firstPos;
private BlockPos secondPos; private final BlockPos secondPos;
public BlockSet(List<BlockPos> coordinates, List<BlockState> previousBlockStates, List<BlockState> newBlockStates, Vec3d hitVec, public BlockSet(List<BlockPos> coordinates, List<BlockState> previousBlockStates, List<BlockState> newBlockStates, Vec3 hitVec,
BlockPos firstPos, BlockPos secondPos) { BlockPos firstPos, BlockPos secondPos) {
this.coordinates = coordinates; this.coordinates = coordinates;
this.previousBlockStates = previousBlockStates; this.previousBlockStates = previousBlockStates;
this.newBlockStates = newBlockStates; this.newBlockStates = newBlockStates;
this.hitVec = hitVec; this.hitVec = hitVec;
this.firstPos = firstPos; this.firstPos = firstPos;
this.secondPos = secondPos; this.secondPos = secondPos;
} }
public List<BlockPos> getCoordinates() { public List<BlockPos> getCoordinates() {
return coordinates; return coordinates;
} }
public List<BlockState> getPreviousBlockStates() { public List<BlockState> getPreviousBlockStates() {
return previousBlockStates; return previousBlockStates;
} }
public List<BlockState> getNewBlockStates() { public List<BlockState> getNewBlockStates() {
return newBlockStates; return newBlockStates;
} }
public Vec3d getHitVec() { public Vec3 getHitVec() {
return hitVec; return hitVec;
} }
public BlockPos getFirstPos() { public BlockPos getFirstPos() {
return firstPos; return firstPos;
} }
public BlockPos getSecondPos() { public BlockPos getSecondPos() {
return secondPos; return secondPos;
} }
} }

View File

@@ -1,260 +1,232 @@
package nl.requios.effortlessbuilding.buildmodifier; package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.level.block.Blocks;
import net.minecraft.block.Blocks; import net.minecraft.world.entity.player.Player;
import net.minecraft.item.BlockItem; import net.minecraft.world.item.BlockItem;
import net.minecraft.item.BlockItemUseContext; import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.item.ItemUseContext; import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.util.Direction; import net.minecraft.core.Direction;
import net.minecraft.util.Hand; import net.minecraft.world.InteractionHand;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
import net.minecraft.world.World; import net.minecraft.world.level.Level;
import nl.requios.effortlessbuilding.CommonConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.compatibility.CompatHelper; import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.helper.InventoryHelper; import nl.requios.effortlessbuilding.helper.DelayedBlockPlacer;
import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.item.ItemRandomizerBag; import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem;
import nl.requios.effortlessbuilding.render.BlockPreviewRenderer; import nl.requios.effortlessbuilding.render.BlockPreviews;
import java.util.*; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BuildModifiers { public class BuildModifiers {
//Called from BuildModes //Called from BuildModes
public static void onBlockPlaced(PlayerEntity player, List<BlockPos> startCoordinates, Direction sideHit, Vec3d hitVec, boolean placeStartPos) { public static void onBlockPlaced(Player player, List<BlockPos> startCoordinates, Direction sideHit, Vec3 hitVec, boolean placeStartPos) {
World world = player.world; Level world = player.level;
ItemRandomizerBag.renewRandomness(); AbstractRandomizerBagItem.renewRandomness();
//Format hitvec to 0.x //Format hitvec to 0.x
hitVec = new Vec3d(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)), Math.abs(hitVec.z - ((int) hitVec.z))); hitVec = new Vec3(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)), Math.abs(hitVec.z - ((int) hitVec.z)));
//find coordinates and blockstates //find coordinates and blockstates
List<BlockPos> coordinates = findCoordinates(player, startCoordinates); List<BlockPos> coordinates = findCoordinates(player, startCoordinates);
List<ItemStack> itemStacks = new ArrayList<>(); List<ItemStack> itemStacks = new ArrayList<>();
List<BlockState> blockStates = findBlockStates(player, startCoordinates, hitVec, sideHit, itemStacks); List<BlockState> blockStates = findBlockStates(player, startCoordinates, hitVec, sideHit, itemStacks);
//check if valid blockstates //check if valid blockstates
if (blockStates.size() == 0 || coordinates.size() != blockStates.size()) return; if (blockStates.size() == 0 || coordinates.size() != blockStates.size()) return;
//remember previous blockstates for undo if (world.isClientSide) {
List<BlockState> previousBlockStates = new ArrayList<>(coordinates.size());
List<BlockState> newBlockStates = new ArrayList<>(coordinates.size());
for (BlockPos coordinate : coordinates) {
previousBlockStates.add(world.getBlockState(coordinate));
}
if (world.isRemote) { BlockPreviews.onBlocksPlaced();
BlockPreviewRenderer.onBlocksPlaced(); } else {
newBlockStates = blockStates; int delay = CommonConfig.visuals.appearAnimationLength.get() * 3 - 3; //DelayedBlockPlacer is called 3 times per tick?
} else { //place blocks after delay
EffortlessBuilding.DELAYED_BLOCK_PLACER.placeBlocksDelayed(new DelayedBlockPlacer.Entry(world, player, coordinates,
blockStates, itemStacks, hitVec, placeStartPos, delay));
}
}
//place blocks public static void onBlockBroken(Player player, List<BlockPos> startCoordinates, boolean breakStartPos) {
for (int i = placeStartPos ? 0 : 1; i < coordinates.size(); i++) { Level world = player.level;
BlockPos blockPos = coordinates.get(i);
BlockState blockState = blockStates.get(i);
ItemStack itemStack = itemStacks.get(i);
if (world.isBlockPresent(blockPos)) { List<BlockPos> coordinates = findCoordinates(player, startCoordinates);
//check itemstack empty
if (itemStack.isEmpty()) {
//try to find new stack, otherwise continue
itemStack = InventoryHelper.findItemStackInInventory(player, blockState.getBlock());
if (itemStack.isEmpty()) continue;
}
SurvivalHelper.placeBlock(world, player, blockPos, blockState, itemStack, Direction.UP, hitVec, false, false, false);
}
}
//find actual new blockstates for undo if (coordinates.isEmpty()) return;
for (BlockPos coordinate : coordinates) {
newBlockStates.add(world.getBlockState(coordinate));
}
}
//Set first previousBlockState to empty if in NORMAL mode, to make undo/redo work //remember previous blockstates for undo
//(Block is placed by the time it gets here, and unplaced after this) List<BlockState> previousBlockStates = new ArrayList<>(coordinates.size());
if (!placeStartPos) previousBlockStates.set(0, Blocks.AIR.getDefaultState()); List<BlockState> newBlockStates = new ArrayList<>(coordinates.size());
for (BlockPos coordinate : coordinates) {
previousBlockStates.add(world.getBlockState(coordinate));
}
//If all new blockstates are air then no use in adding it, no block was actually placed if (world.isClientSide) {
//Can happen when e.g. placing one block in yourself BlockPreviews.onBlocksBroken();
if (Collections.frequency(newBlockStates, Blocks.AIR.getDefaultState()) != newBlockStates.size()) {
//add to undo stack
BlockPos firstPos = startCoordinates.get(0);
BlockPos secondPos = startCoordinates.get(startCoordinates.size() - 1);
UndoRedo.addUndo(player, new BlockSet(coordinates, previousBlockStates, newBlockStates, hitVec, firstPos, secondPos));
}
}
public static void onBlockBroken(PlayerEntity player, List<BlockPos> startCoordinates, boolean breakStartPos) { //list of air blockstates
World world = player.world; for (int i = 0; i < coordinates.size(); i++) {
newBlockStates.add(Blocks.AIR.defaultBlockState());
}
List<BlockPos> coordinates = findCoordinates(player, startCoordinates); } else {
if (coordinates.isEmpty()) return; //If the player is going to instabreak grass or a plant, only break other instabreaking things
boolean onlyInstaBreaking = !player.isCreative() &&
world.getBlockState(startCoordinates.get(0)).getDestroySpeed(world, startCoordinates.get(0)) == 0f;
//remember previous blockstates for undo //break all those blocks
List<BlockState> previousBlockStates = new ArrayList<>(coordinates.size()); for (int i = breakStartPos ? 0 : 1; i < coordinates.size(); i++) {
List<BlockState> newBlockStates = new ArrayList<>(coordinates.size()); BlockPos coordinate = coordinates.get(i);
for (BlockPos coordinate : coordinates) { if (world.isLoaded(coordinate) && !world.isEmptyBlock(coordinate)) {
previousBlockStates.add(world.getBlockState(coordinate)); if (!onlyInstaBreaking || world.getBlockState(coordinate).getDestroySpeed(world, coordinate) == 0f) {
} SurvivalHelper.breakBlock(world, player, coordinate, false);
}
}
}
if (world.isRemote) { //find actual new blockstates for undo
BlockPreviewRenderer.onBlocksBroken(); for (BlockPos coordinate : coordinates) {
newBlockStates.add(world.getBlockState(coordinate));
}
}
//list of air blockstates //Set first newBlockState to empty if in NORMAL mode, to make undo/redo work
for (int i = 0; i < coordinates.size(); i++) { //(Block isn't broken yet by the time it gets here, and broken after this)
newBlockStates.add(Blocks.AIR.getDefaultState()); if (!breakStartPos) newBlockStates.set(0, Blocks.AIR.defaultBlockState());
}
} else { //add to undo stack
BlockPos firstPos = startCoordinates.get(0);
BlockPos secondPos = startCoordinates.get(startCoordinates.size() - 1);
Vec3 hitVec = new Vec3(0.5, 0.5, 0.5);
UndoRedo.addUndo(player, new BlockSet(coordinates, previousBlockStates, newBlockStates, hitVec, firstPos, secondPos));
//If the player is going to instabreak grass or a plant, only break other instabreaking things }
boolean onlyInstaBreaking = !player.isCreative() &&
world.getBlockState(startCoordinates.get(0)).getBlockHardness(world, startCoordinates.get(0)) == 0f;
//break all those blocks public static List<BlockPos> findCoordinates(Player player, List<BlockPos> posList) {
for (int i = breakStartPos ? 0 : 1; i < coordinates.size(); i++) { List<BlockPos> coordinates = new ArrayList<>();
BlockPos coordinate = coordinates.get(i); //Add current blocks being placed too
if (world.isBlockPresent(coordinate) && !world.isAirBlock(coordinate)) { coordinates.addAll(posList);
if (!onlyInstaBreaking || world.getBlockState(coordinate).getBlockHardness(world, coordinate) == 0f) {
SurvivalHelper.breakBlock(world, player, coordinate, false);
}
}
}
//find actual new blockstates for undo //Find mirror/array/radial mirror coordinates for each blockpos
for (BlockPos coordinate : coordinates) { for (BlockPos blockPos : posList) {
newBlockStates.add(world.getBlockState(coordinate)); List<BlockPos> arrayCoordinates = Array.findCoordinates(player, blockPos);
} coordinates.addAll(arrayCoordinates);
} coordinates.addAll(Mirror.findCoordinates(player, blockPos));
coordinates.addAll(RadialMirror.findCoordinates(player, blockPos));
//get mirror for each array coordinate
for (BlockPos coordinate : arrayCoordinates) {
coordinates.addAll(Mirror.findCoordinates(player, coordinate));
coordinates.addAll(RadialMirror.findCoordinates(player, coordinate));
}
}
//Set first newBlockState to empty if in NORMAL mode, to make undo/redo work return coordinates;
//(Block isn't broken yet by the time it gets here, and broken after this) }
if (!breakStartPos) newBlockStates.set(0, Blocks.AIR.getDefaultState());
//add to undo stack public static List<BlockPos> findCoordinates(Player player, BlockPos blockPos) {
BlockPos firstPos = startCoordinates.get(0); return findCoordinates(player, new ArrayList<>(Collections.singletonList(blockPos)));
BlockPos secondPos = startCoordinates.get(startCoordinates.size() - 1); }
Vec3d hitVec = new Vec3d(0.5, 0.5, 0.5);
UndoRedo.addUndo(player, new BlockSet(coordinates, previousBlockStates, newBlockStates, hitVec, firstPos, secondPos));
} public static List<BlockState> findBlockStates(Player player, List<BlockPos> posList, Vec3 hitVec, Direction facing, List<ItemStack> itemStacks) {
List<BlockState> blockStates = new ArrayList<>();
itemStacks.clear();
public static List<BlockPos> findCoordinates(PlayerEntity player, List<BlockPos> posList) { //Get itemstack
List<BlockPos> coordinates = new ArrayList<>(); ItemStack itemStack = player.getItemInHand(InteractionHand.MAIN_HAND);
//Add current blocks being placed too if (itemStack.isEmpty() || !CompatHelper.isItemBlockProxy(itemStack)) {
coordinates.addAll(posList); itemStack = player.getItemInHand(InteractionHand.OFF_HAND);
}
if (itemStack.isEmpty() || !CompatHelper.isItemBlockProxy(itemStack)) {
return blockStates;
}
//Find mirror/array/radial mirror coordinates for each blockpos //Get ItemBlock stack
for (BlockPos blockPos : posList) { ItemStack itemBlock = ItemStack.EMPTY;
List<BlockPos> arrayCoordinates = Array.findCoordinates(player, blockPos); if (itemStack.getItem() instanceof BlockItem) itemBlock = itemStack;
coordinates.addAll(arrayCoordinates); else itemBlock = CompatHelper.getItemBlockFromStack(itemStack);
coordinates.addAll(Mirror.findCoordinates(player, blockPos)); AbstractRandomizerBagItem.resetRandomness();
coordinates.addAll(RadialMirror.findCoordinates(player, blockPos));
//get mirror for each array coordinate
for (BlockPos coordinate : arrayCoordinates) {
coordinates.addAll(Mirror.findCoordinates(player, coordinate));
coordinates.addAll(RadialMirror.findCoordinates(player, coordinate));
}
}
return coordinates; //Add blocks in posList first
} for (BlockPos blockPos : posList) {
if (!(itemStack.getItem() instanceof BlockItem)) itemBlock = CompatHelper.getItemBlockFromStack(itemStack);
BlockState blockState = getBlockStateFromItem(itemBlock, player, blockPos, facing, hitVec, InteractionHand.MAIN_HAND);
if (blockState == null) continue;
public static List<BlockPos> findCoordinates(PlayerEntity player, BlockPos blockPos) { blockStates.add(blockState);
return findCoordinates(player, new ArrayList<>(Arrays.asList(blockPos))); itemStacks.add(itemBlock);
} }
public static List<BlockState> findBlockStates(PlayerEntity player, List<BlockPos> posList, Vec3d hitVec, Direction facing, List<ItemStack> itemStacks) { for (BlockPos blockPos : posList) {
List<BlockState> blockStates = new ArrayList<>(); BlockState blockState = getBlockStateFromItem(itemBlock, player, blockPos, facing, hitVec, InteractionHand.MAIN_HAND);
itemStacks.clear(); if (blockState == null) continue;
//Get itemstack List<BlockState> arrayBlockStates = Array.findBlockStates(player, blockPos, blockState, itemStack, itemStacks);
ItemStack itemStack = player.getHeldItem(Hand.MAIN_HAND); blockStates.addAll(arrayBlockStates);
if (itemStack.isEmpty() || !CompatHelper.isItemBlockProxy(itemStack)) { blockStates.addAll(Mirror.findBlockStates(player, blockPos, blockState, itemStack, itemStacks));
itemStack = player.getHeldItem(Hand.OFF_HAND); blockStates.addAll(RadialMirror.findBlockStates(player, blockPos, blockState, itemStack, itemStacks));
} //add mirror for each array coordinate
if (itemStack.isEmpty() || !CompatHelper.isItemBlockProxy(itemStack)) { List<BlockPos> arrayCoordinates = Array.findCoordinates(player, blockPos);
return blockStates; for (int i = 0; i < arrayCoordinates.size(); i++) {
} BlockPos coordinate = arrayCoordinates.get(i);
BlockState blockState1 = arrayBlockStates.get(i);
if (blockState1 == null) continue;
//Get ItemBlock stack blockStates.addAll(Mirror.findBlockStates(player, coordinate, blockState1, itemStack, itemStacks));
ItemStack itemBlock = ItemStack.EMPTY; blockStates.addAll(RadialMirror.findBlockStates(player, coordinate, blockState1, itemStack, itemStacks));
if (itemStack.getItem() instanceof BlockItem) itemBlock = itemStack; }
else itemBlock = CompatHelper.getItemBlockFromStack(itemStack);
ItemRandomizerBag.resetRandomness();
//Add blocks in posList first //Adjust blockstates for torches and ladders etc to place on a valid side
for (BlockPos blockPos : posList) { //TODO optimize findCoordinates (done twice now)
if (!(itemStack.getItem() instanceof BlockItem)) itemBlock = CompatHelper.getItemBlockFromStack(itemStack); //TODO fix mirror
BlockState blockState = getBlockStateFromItem(itemBlock, player, blockPos, facing, hitVec, Hand.MAIN_HAND);
blockStates.add(blockState);
itemStacks.add(itemBlock);
}
for (BlockPos blockPos : posList) {
BlockState blockState = getBlockStateFromItem(itemBlock, player, blockPos, facing, hitVec, Hand.MAIN_HAND);
List<BlockState> arrayBlockStates = Array.findBlockStates(player, blockPos, blockState, itemStack, itemStacks);
blockStates.addAll(arrayBlockStates);
blockStates.addAll(Mirror.findBlockStates(player, blockPos, blockState, itemStack, itemStacks));
blockStates.addAll(RadialMirror.findBlockStates(player, blockPos, blockState, itemStack, itemStacks));
//add mirror for each array coordinate
List<BlockPos> arrayCoordinates = Array.findCoordinates(player, blockPos);
for (int i = 0; i < arrayCoordinates.size(); i++) {
BlockPos coordinate = arrayCoordinates.get(i);
BlockState blockState1 = arrayBlockStates.get(i);
blockStates.addAll(Mirror.findBlockStates(player, coordinate, blockState1, itemStack, itemStacks));
blockStates.addAll(RadialMirror.findBlockStates(player, coordinate, blockState1, itemStack, itemStacks));
}
//Adjust blockstates for torches and ladders etc to place on a valid side
//TODO optimize findCoordinates (done twice now)
//TODO fix mirror
// List<BlockPos> coordinates = findCoordinates(player, startPos); // List<BlockPos> coordinates = findCoordinates(player, startPos);
// for (int i = 0; i < blockStates.size(); i++) { // for (int i = 0; i < blockStates.size(); i++) {
// blockStates.set(i, blockStates.get(i).getBlock().getStateForPlacement(player.world, coordinates.get(i), facing, // blockStates.set(i, blockStates.get(i).getBlock().getStateForPlacement(player.world, coordinates.get(i), facing,
// (float) hitVec.x, (float) hitVec.y, (float) hitVec.z, itemStacks.get(i).getMetadata(), player, EnumHand.MAIN_HAND)); // (float) hitVec.x, (float) hitVec.y, (float) hitVec.z, itemStacks.get(i).getMetadata(), player, EnumHand.MAIN_HAND));
// } // }
} }
return blockStates; return blockStates;
} }
public static boolean isEnabled(ModifierSettingsManager.ModifierSettings modifierSettings, BlockPos startPos) { public static boolean isEnabled(ModifierSettingsManager.ModifierSettings modifierSettings, BlockPos startPos) {
return Mirror.isEnabled(modifierSettings.getMirrorSettings(), startPos) || //startPos can be null
Array.isEnabled(modifierSettings.getArraySettings()) || return Mirror.isEnabled(modifierSettings.getMirrorSettings(), startPos) ||
RadialMirror.isEnabled(modifierSettings.getRadialMirrorSettings(), startPos) || Array.isEnabled(modifierSettings.getArraySettings()) ||
modifierSettings.doQuickReplace(); RadialMirror.isEnabled(modifierSettings.getRadialMirrorSettings(), startPos) ||
} modifierSettings.doQuickReplace();
}
public static BlockState getBlockStateFromItem(ItemStack itemStack, PlayerEntity player, BlockPos blockPos, Direction facing, Vec3d hitVec, Hand hand) { public static BlockState getBlockStateFromItem(ItemStack itemStack, Player player, BlockPos blockPos, Direction facing, Vec3 hitVec, InteractionHand hand) {
return Block.getBlockFromItem(itemStack.getItem()).getStateForPlacement(new BlockItemUseContext(new ItemUseContext(player, hand, new BlockRayTraceResult(hitVec, facing, blockPos, false)))); return Block.byItem(itemStack.getItem()).getStateForPlacement(new BlockPlaceContext(new UseOnContext(player, hand, new BlockHitResult(hitVec, facing, blockPos, false))));
} }
//Returns true if equal (or both null) //Returns true if equal (or both null)
public static boolean compareCoordinates(List<BlockPos> coordinates1, List<BlockPos> coordinates2) { public static boolean compareCoordinates(List<BlockPos> coordinates1, List<BlockPos> coordinates2) {
if (coordinates1 == null && coordinates2 == null) return true; if (coordinates1 == null && coordinates2 == null) return true;
if (coordinates1 == null || coordinates2 == null) return false; if (coordinates1 == null || coordinates2 == null) return false;
//Check count, not actual values //Check count, not actual values
if (coordinates1.size() == coordinates2.size()){ if (coordinates1.size() == coordinates2.size()) {
if (coordinates1.size() == 1){ if (coordinates1.size() == 1) {
return coordinates1.get(0).equals(coordinates2.get(0)); return coordinates1.get(0).equals(coordinates2.get(0));
} }
return true; return true;
} else { } else {
return false; return false;
} }
// return coordinates1.equals(coordinates2); // return coordinates1.equals(coordinates2);
} }
} }

View File

@@ -1,228 +1,234 @@
package nl.requios.effortlessbuilding.buildmodifier; package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.*; import net.minecraft.world.entity.player.Player;
import net.minecraft.block.StairsBlock; import net.minecraft.world.item.ItemStack;
import net.minecraft.block.DirectionalBlock; import net.minecraft.world.level.block.state.properties.Half;
import net.minecraft.block.SlabBlock; import net.minecraft.world.level.block.state.properties.SlabType;
import net.minecraft.block.BlockState; import net.minecraft.core.Direction;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.InteractionHand;
import net.minecraft.item.ItemStack; import net.minecraft.core.BlockPos;
import net.minecraft.state.properties.Half; import net.minecraft.world.phys.Vec3;
import net.minecraft.state.properties.SlabType;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import nl.requios.effortlessbuilding.item.ItemRandomizerBag; import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import net.minecraft.world.level.block.DirectionalBlock;
import net.minecraft.world.level.block.DispenserBlock;
import net.minecraft.world.level.block.SlabBlock;
import net.minecraft.world.level.block.StairBlock;
import net.minecraft.world.level.block.state.BlockState;
public class Mirror { public class Mirror {
public static class MirrorSettings { public static List<BlockPos> findCoordinates(Player player, BlockPos startPos) {
public boolean enabled = false; List<BlockPos> coordinates = new ArrayList<>();
public Vec3d position = new Vec3d(0.5, 64.5, 0.5);
public boolean mirrorX = true, mirrorY = false, mirrorZ = false;
public int radius = 10;
public boolean drawLines = true, drawPlanes = true;
public MirrorSettings() { //find mirrorsettings for the player
} MirrorSettings m = ModifierSettingsManager.getModifierSettings(player).getMirrorSettings();
if (!isEnabled(m, startPos)) return coordinates;
public MirrorSettings(boolean mirrorEnabled, Vec3d position, boolean mirrorX, boolean mirrorY, boolean mirrorZ, int radius, boolean drawLines, boolean drawPlanes) { if (m.mirrorX) coordinateMirrorX(m, startPos, coordinates);
this.enabled = mirrorEnabled; if (m.mirrorY) coordinateMirrorY(m, startPos, coordinates);
this.position = position; if (m.mirrorZ) coordinateMirrorZ(m, startPos, coordinates);
this.mirrorX = mirrorX;
this.mirrorY = mirrorY;
this.mirrorZ = mirrorZ;
this.radius = radius;
this.drawLines = drawLines;
this.drawPlanes = drawPlanes;
}
public int getReach() { return coordinates;
return radius * 2; //Change ModifierSettings#setReachUpgrade too }
}
}
public static List<BlockPos> findCoordinates(PlayerEntity player, BlockPos startPos) {
List<BlockPos> coordinates = new ArrayList<>();
//find mirrorsettings for the player private static void coordinateMirrorX(MirrorSettings m, BlockPos oldBlockPos, List<BlockPos> coordinates) {
MirrorSettings m = ModifierSettingsManager.getModifierSettings(player).getMirrorSettings(); //find mirror position
if (!isEnabled(m, startPos)) return coordinates; double x = m.position.x + (m.position.x - oldBlockPos.getX() - 0.5);
BlockPos newBlockPos = new BlockPos(x, oldBlockPos.getY(), oldBlockPos.getZ());
coordinates.add(newBlockPos);
if (m.mirrorX) coordinateMirrorX(m, startPos, coordinates); if (m.mirrorY) coordinateMirrorY(m, newBlockPos, coordinates);
if (m.mirrorY) coordinateMirrorY(m, startPos, coordinates); if (m.mirrorZ) coordinateMirrorZ(m, newBlockPos, coordinates);
if (m.mirrorZ) coordinateMirrorZ(m, startPos, coordinates); }
return coordinates; private static void coordinateMirrorY(MirrorSettings m, BlockPos oldBlockPos, List<BlockPos> coordinates) {
} //find mirror position
double y = m.position.y + (m.position.y - oldBlockPos.getY() - 0.5);
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), y, oldBlockPos.getZ());
coordinates.add(newBlockPos);
private static void coordinateMirrorX(MirrorSettings m, BlockPos oldBlockPos, List<BlockPos> coordinates) { if (m.mirrorZ) coordinateMirrorZ(m, newBlockPos, coordinates);
//find mirror position }
double x = m.position.x + (m.position.x - oldBlockPos.getX() - 0.5);
BlockPos newBlockPos = new BlockPos(x, oldBlockPos.getY(), oldBlockPos.getZ());
coordinates.add(newBlockPos);
if (m.mirrorY) coordinateMirrorY(m, newBlockPos, coordinates); private static void coordinateMirrorZ(MirrorSettings m, BlockPos oldBlockPos, List<BlockPos> coordinates) {
if (m.mirrorZ) coordinateMirrorZ(m, newBlockPos, coordinates); //find mirror position
} double z = m.position.z + (m.position.z - oldBlockPos.getZ() - 0.5);
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), oldBlockPos.getY(), z);
coordinates.add(newBlockPos);
}
private static void coordinateMirrorY(MirrorSettings m, BlockPos oldBlockPos, List<BlockPos> coordinates) { public static List<BlockState> findBlockStates(Player player, BlockPos startPos, BlockState blockState, ItemStack itemStack, List<ItemStack> itemStacks) {
//find mirror position List<BlockState> blockStates = new ArrayList<>();
double y = m.position.y + (m.position.y - oldBlockPos.getY() - 0.5);
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), y, oldBlockPos.getZ());
coordinates.add(newBlockPos);
if (m.mirrorZ) coordinateMirrorZ(m, newBlockPos, coordinates); //find mirrorsettings for the player
} MirrorSettings m = ModifierSettingsManager.getModifierSettings(player).getMirrorSettings();
if (!isEnabled(m, startPos)) return blockStates;
private static void coordinateMirrorZ(MirrorSettings m, BlockPos oldBlockPos, List<BlockPos> coordinates) { //Randomizer bag synergy
//find mirror position AbstractRandomizerBagItem randomizerBagItem = null;
double z = m.position.z + (m.position.z - oldBlockPos.getZ() - 0.5); IItemHandler bagInventory = null;
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), oldBlockPos.getY(), z); if (!itemStack.isEmpty() && itemStack.getItem() instanceof AbstractRandomizerBagItem) {
coordinates.add(newBlockPos); randomizerBagItem = (AbstractRandomizerBagItem) itemStack.getItem() ;
} bagInventory = randomizerBagItem.getBagInventory(itemStack);
}
public static List<BlockState> findBlockStates(PlayerEntity player, BlockPos startPos, BlockState blockState, ItemStack itemStack, List<ItemStack> itemStacks) { if (m.mirrorX)
List<BlockState> blockStates = new ArrayList<>(); blockStateMirrorX(player, m, startPos, blockState, bagInventory, itemStack, InteractionHand.MAIN_HAND, blockStates, itemStacks);
if (m.mirrorY)
blockStateMirrorY(player, m, startPos, blockState, bagInventory, itemStack, InteractionHand.MAIN_HAND, blockStates, itemStacks);
if (m.mirrorZ)
blockStateMirrorZ(player, m, startPos, blockState, bagInventory, itemStack, InteractionHand.MAIN_HAND, blockStates, itemStacks);
//find mirrorsettings for the player return blockStates;
MirrorSettings m = ModifierSettingsManager.getModifierSettings(player).getMirrorSettings(); }
if (!isEnabled(m, startPos)) return blockStates;
//Randomizer bag synergy private static void blockStateMirrorX(Player player, MirrorSettings m, BlockPos oldBlockPos, BlockState oldBlockState,
IItemHandler bagInventory = null; IItemHandler bagInventory, ItemStack itemStack, InteractionHand hand, List<BlockState> blockStates, List<ItemStack> itemStacks) {
if (!itemStack.isEmpty() && itemStack.getItem() instanceof ItemRandomizerBag) { //find mirror position
bagInventory = ItemRandomizerBag.getBagInventory(itemStack); double x = m.position.x + (m.position.x - oldBlockPos.getX() - 0.5);
} BlockPos newBlockPos = new BlockPos(x, oldBlockPos.getY(), oldBlockPos.getZ());
if (m.mirrorX) blockStateMirrorX(player, m, startPos, blockState, bagInventory, itemStack, Hand.MAIN_HAND, blockStates, itemStacks); //Randomizer bag synergy
if (m.mirrorY) blockStateMirrorY(player, m, startPos, blockState, bagInventory, itemStack, Hand.MAIN_HAND, blockStates, itemStacks); if (bagInventory != null) {
if (m.mirrorZ) blockStateMirrorZ(player, m, startPos, blockState, bagInventory, itemStack, Hand.MAIN_HAND, blockStates, itemStacks); itemStack = ((AbstractRandomizerBagItem)itemStack.getItem()).pickRandomStack(bagInventory);
oldBlockState = BuildModifiers.getBlockStateFromItem(itemStack, player, oldBlockPos, Direction.UP, new Vec3(0, 0, 0), hand);
}
return blockStates; //Find blockstate
} BlockState newBlockState = oldBlockState == null ? null : oldBlockState.mirror(net.minecraft.world.level.block.Mirror.FRONT_BACK);
private static void blockStateMirrorX(PlayerEntity player, MirrorSettings m, BlockPos oldBlockPos, BlockState oldBlockState, //Store blockstate and itemstack
IItemHandler bagInventory, ItemStack itemStack, Hand hand, List<BlockState> blockStates, List<ItemStack> itemStacks) { blockStates.add(newBlockState);
//find mirror position itemStacks.add(itemStack);
double x = m.position.x + (m.position.x - oldBlockPos.getX() - 0.5);
BlockPos newBlockPos = new BlockPos(x, oldBlockPos.getY(), oldBlockPos.getZ());
//Randomizer bag synergy if (m.mirrorY)
if (bagInventory != null) { blockStateMirrorY(player, m, newBlockPos, newBlockState, bagInventory, itemStack, hand, blockStates, itemStacks);
itemStack = ItemRandomizerBag.pickRandomStack(bagInventory); if (m.mirrorZ)
oldBlockState = BuildModifiers.getBlockStateFromItem(itemStack, player, oldBlockPos, Direction.UP, new Vec3d(0, 0, 0), hand); blockStateMirrorZ(player, m, newBlockPos, newBlockState, bagInventory, itemStack, hand, blockStates, itemStacks);
} }
//Find blockstate private static void blockStateMirrorY(Player player, MirrorSettings m, BlockPos oldBlockPos, BlockState oldBlockState,
BlockState newBlockState = oldBlockState == null ? null : oldBlockState.mirror(net.minecraft.util.Mirror.FRONT_BACK); IItemHandler bagInventory, ItemStack itemStack, InteractionHand hand, List<BlockState> blockStates, List<ItemStack> itemStacks) {
//find mirror position
double y = m.position.y + (m.position.y - oldBlockPos.getY() - 0.5);
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), y, oldBlockPos.getZ());
//Store blockstate and itemstack //Randomizer bag synergy
blockStates.add(newBlockState); if (bagInventory != null) {
itemStacks.add(itemStack); itemStack = ((AbstractRandomizerBagItem)itemStack.getItem()).pickRandomStack(bagInventory);
oldBlockState = BuildModifiers.getBlockStateFromItem(itemStack, player, oldBlockPos, Direction.UP, new Vec3(0, 0, 0), hand);
}
if (m.mirrorY) blockStateMirrorY(player, m, newBlockPos, newBlockState, bagInventory, itemStack, hand, blockStates, itemStacks); //Find blockstate
if (m.mirrorZ) blockStateMirrorZ(player, m, newBlockPos, newBlockState, bagInventory, itemStack, hand, blockStates, itemStacks); BlockState newBlockState = oldBlockState == null ? null : getVerticalMirror(oldBlockState);
}
private static void blockStateMirrorY(PlayerEntity player, MirrorSettings m, BlockPos oldBlockPos, BlockState oldBlockState, //Store blockstate and itemstack
IItemHandler bagInventory, ItemStack itemStack, Hand hand, List<BlockState> blockStates, List<ItemStack> itemStacks) { blockStates.add(newBlockState);
//find mirror position itemStacks.add(itemStack);
double y = m.position.y + (m.position.y - oldBlockPos.getY() - 0.5);
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), y, oldBlockPos.getZ());
//Randomizer bag synergy if (m.mirrorZ)
if (bagInventory != null) { blockStateMirrorZ(player, m, newBlockPos, newBlockState, bagInventory, itemStack, hand, blockStates, itemStacks);
itemStack = ItemRandomizerBag.pickRandomStack(bagInventory); }
oldBlockState = BuildModifiers.getBlockStateFromItem(itemStack, player, oldBlockPos, Direction.UP, new Vec3d(0, 0, 0), hand);
}
//Find blockstate private static void blockStateMirrorZ(Player player, MirrorSettings m, BlockPos oldBlockPos, BlockState oldBlockState,
BlockState newBlockState = oldBlockState == null ? null : getVerticalMirror(oldBlockState); IItemHandler bagInventory, ItemStack itemStack, InteractionHand hand, List<BlockState> blockStates, List<ItemStack> itemStacks) {
//find mirror position
double z = m.position.z + (m.position.z - oldBlockPos.getZ() - 0.5);
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), oldBlockPos.getY(), z);
//Store blockstate and itemstack //Randomizer bag synergy
blockStates.add(newBlockState); if (bagInventory != null) {
itemStacks.add(itemStack); itemStack = ((AbstractRandomizerBagItem)itemStack.getItem()).pickRandomStack(bagInventory);
oldBlockState = BuildModifiers.getBlockStateFromItem(itemStack, player, oldBlockPos, Direction.UP, new Vec3(0, 0, 0), hand);
}
if (m.mirrorZ) blockStateMirrorZ(player, m, newBlockPos, newBlockState, bagInventory, itemStack, hand, blockStates, itemStacks); //Find blockstate
} BlockState newBlockState = oldBlockState == null ? null : oldBlockState.mirror(net.minecraft.world.level.block.Mirror.LEFT_RIGHT);
private static void blockStateMirrorZ(PlayerEntity player, MirrorSettings m, BlockPos oldBlockPos, BlockState oldBlockState, //Store blockstate and itemstack
IItemHandler bagInventory, ItemStack itemStack, Hand hand, List<BlockState> blockStates, List<ItemStack> itemStacks) { blockStates.add(newBlockState);
//find mirror position itemStacks.add(itemStack);
double z = m.position.z + (m.position.z - oldBlockPos.getZ() - 0.5); }
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), oldBlockPos.getY(), z);
//Randomizer bag synergy public static boolean isEnabled(MirrorSettings m, BlockPos startPos) {
if (bagInventory != null) { if (m == null || !m.enabled || (!m.mirrorX && !m.mirrorY && !m.mirrorZ)) return false;
itemStack = ItemRandomizerBag.pickRandomStack(bagInventory);
oldBlockState = BuildModifiers.getBlockStateFromItem(itemStack, player, oldBlockPos, Direction.UP, new Vec3d(0, 0, 0), hand);
}
//Find blockstate //within mirror distance
BlockState newBlockState = oldBlockState == null ? null : oldBlockState.mirror(net.minecraft.util.Mirror.LEFT_RIGHT); return !(startPos.getX() + 0.5 < m.position.x - m.radius) && !(startPos.getX() + 0.5 > m.position.x + m.radius) &&
!(startPos.getY() + 0.5 < m.position.y - m.radius) && !(startPos.getY() + 0.5 > m.position.y + m.radius) &&
!(startPos.getZ() + 0.5 < m.position.z - m.radius) && !(startPos.getZ() + 0.5 > m.position.z + m.radius);
}
//Store blockstate and itemstack private static BlockState getVerticalMirror(BlockState blockState) {
blockStates.add(newBlockState); //Stairs
itemStacks.add(itemStack); if (blockState.getBlock() instanceof StairBlock) {
} if (blockState.getValue(StairBlock.HALF) == Half.BOTTOM) {
return blockState.setValue(StairBlock.HALF, Half.TOP);
} else {
return blockState.setValue(StairBlock.HALF, Half.BOTTOM);
}
}
public static boolean isEnabled(MirrorSettings m, BlockPos startPos) { //Slabs
if (m == null || !m.enabled || (!m.mirrorX && !m.mirrorY && !m.mirrorZ)) return false; if (blockState.getBlock() instanceof SlabBlock) {
if (blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE) {
return blockState;
} else if (blockState.getValue(SlabBlock.TYPE) == SlabType.BOTTOM) {
return blockState.setValue(SlabBlock.TYPE, SlabType.TOP);
} else {
return blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM);
}
}
//within mirror distance //Buttons, endrod, observer, piston
if (startPos.getX() + 0.5 < m.position.x - m.radius || startPos.getX() + 0.5 > m.position.x + m.radius || if (blockState.getBlock() instanceof DirectionalBlock) {
startPos.getY() + 0.5 < m.position.y - m.radius || startPos.getY() + 0.5 > m.position.y + m.radius || if (blockState.getValue(DirectionalBlock.FACING) == Direction.DOWN) {
startPos.getZ() + 0.5 < m.position.z - m.radius || startPos.getZ() + 0.5 > m.position.z + m.radius) return blockState.setValue(DirectionalBlock.FACING, Direction.UP);
return false; } else if (blockState.getValue(DirectionalBlock.FACING) == Direction.UP) {
return blockState.setValue(DirectionalBlock.FACING, Direction.DOWN);
}
}
return true; //Dispenser, dropper
} if (blockState.getBlock() instanceof DispenserBlock) {
if (blockState.getValue(DispenserBlock.FACING) == Direction.DOWN) {
return blockState.setValue(DispenserBlock.FACING, Direction.UP);
} else if (blockState.getValue(DispenserBlock.FACING) == Direction.UP) {
return blockState.setValue(DispenserBlock.FACING, Direction.DOWN);
}
}
private static BlockState getVerticalMirror(BlockState blockState) { return blockState;
//Stairs }
if (blockState.getBlock() instanceof StairsBlock) {
if (blockState.get(StairsBlock.HALF) == Half.BOTTOM) {
return blockState.with(StairsBlock.HALF, Half.TOP);
} else {
return blockState.with(StairsBlock.HALF, Half.BOTTOM);
}
}
//Slabs public static class MirrorSettings {
if (blockState.getBlock() instanceof SlabBlock) { public boolean enabled = false;
if (blockState.get(SlabBlock.TYPE) == SlabType.DOUBLE) { public Vec3 position = new Vec3(0.5, 64.5, 0.5);
return blockState; public boolean mirrorX = true, mirrorY = false, mirrorZ = false;
} else if (blockState.get(SlabBlock.TYPE) == SlabType.BOTTOM) { public int radius = 10;
return blockState.with(SlabBlock.TYPE, SlabType.TOP); public boolean drawLines = true, drawPlanes = true;
} else {
return blockState.with(SlabBlock.TYPE, SlabType.BOTTOM);
}
}
//Buttons, endrod, observer, piston public MirrorSettings() {
if (blockState.getBlock() instanceof DirectionalBlock) { }
if (blockState.get(DirectionalBlock.FACING) == Direction.DOWN) {
return blockState.with(DirectionalBlock.FACING, Direction.UP);
} else if (blockState.get(DirectionalBlock.FACING) == Direction.UP) {
return blockState.with(DirectionalBlock.FACING, Direction.DOWN);
}
}
//Dispenser, dropper public MirrorSettings(boolean mirrorEnabled, Vec3 position, boolean mirrorX, boolean mirrorY, boolean mirrorZ, int radius, boolean drawLines, boolean drawPlanes) {
if (blockState.getBlock() instanceof DispenserBlock) { this.enabled = mirrorEnabled;
if (blockState.get(DispenserBlock.FACING) == Direction.DOWN) { this.position = position;
return blockState.with(DispenserBlock.FACING, Direction.UP); this.mirrorX = mirrorX;
} else if (blockState.get(DispenserBlock.FACING) == Direction.UP) { this.mirrorY = mirrorY;
return blockState.with(DispenserBlock.FACING, Direction.DOWN); this.mirrorZ = mirrorZ;
} this.radius = radius;
} this.drawLines = drawLines;
this.drawPlanes = drawPlanes;
}
return blockState; public int getReach() {
} return radius * 2; //Change ModifierSettings#setReachUpgrade too
}
}
} }

View File

@@ -1,11 +1,11 @@
package nl.requios.effortlessbuilding.buildmodifier; package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.network.PacketDistributor; import net.minecraftforge.network.PacketDistributor;
import nl.requios.effortlessbuilding.BuildConfig; import nl.requios.effortlessbuilding.CommonConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager; import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
@@ -17,191 +17,199 @@ import javax.annotation.Nonnull;
@Mod.EventBusSubscriber @Mod.EventBusSubscriber
public class ModifierSettingsManager { public class ModifierSettingsManager {
//Retrieves the buildsettings of a player through the modifierCapability capability //Retrieves the buildsettings of a player through the modifierCapability capability
//Never returns null //Never returns null
@Nonnull @Nonnull
public static ModifierSettings getModifierSettings(PlayerEntity player){ public static ModifierSettings getModifierSettings(Player player) {
LazyOptional<ModifierCapabilityManager.IModifierCapability> modifierCapability =
player.getCapability(ModifierCapabilityManager.modifierCapability, null);
if (modifierCapability.isPresent()) { LazyOptional<ModifierCapabilityManager.IModifierCapability> modifierCapability =
ModifierCapabilityManager.IModifierCapability capability = modifierCapability.orElse(null); player.getCapability(ModifierCapabilityManager.MODIFIER_CAPABILITY, null);
if (capability.getModifierData() == null) {
capability.setModifierData(new ModifierSettings());
}
return capability.getModifierData();
}
//Player does not have modifierCapability capability if (modifierCapability.isPresent()) {
//Return dummy settings ModifierCapabilityManager.IModifierCapability capability = modifierCapability.orElse(null);
return new ModifierSettings(); if (capability.getModifierData() == null){
// throw new IllegalArgumentException("Player does not have modifierCapability capability"); capability.setModifierData(new ModifierSettings());
} }
return capability.getModifierData();
}
public static void setModifierSettings(PlayerEntity player, ModifierSettings modifierSettings) { EffortlessBuilding.logger.warn("Player does not have modifierCapability: " + player);
if (player == null) { //Return dummy settings
EffortlessBuilding.log("Cannot set buildsettings, player is null"); return new ModifierSettings();
return; }
}
LazyOptional<ModifierCapabilityManager.IModifierCapability> modifierCapability = public static void setModifierSettings(Player player, ModifierSettings modifierSettings) {
player.getCapability(ModifierCapabilityManager.modifierCapability, null); if (player == null) {
EffortlessBuilding.log("Cannot set buildsettings, player is null");
return;
}
modifierCapability.ifPresent((capability) -> { LazyOptional<ModifierCapabilityManager.IModifierCapability> modifierCapability =
capability.setModifierData(modifierSettings); player.getCapability(ModifierCapabilityManager.MODIFIER_CAPABILITY, null);
});
if (!modifierCapability.isPresent()) { modifierCapability.ifPresent((capability) -> {
EffortlessBuilding.log(player, "Saving buildsettings failed."); capability.setModifierData(modifierSettings);
} });
}
public static String sanitize(ModifierSettings modifierSettings, PlayerEntity player) { if (!modifierCapability.isPresent()) {
int maxReach = ReachHelper.getMaxReach(player); EffortlessBuilding.log(player, "Saving buildsettings failed.");
String error = ""; }
}
//Mirror settings public static String sanitize(ModifierSettings modifierSettings, Player player) {
Mirror.MirrorSettings m = modifierSettings.getMirrorSettings(); int maxReach = ReachHelper.getMaxReach(player);
if (m.radius < 1) { String error = "";
m.radius = 1;
error += "Mirror size has to be at least 1. This has been corrected. ";
}
if (m.getReach() > maxReach) {
m.radius = maxReach / 2;
error += "Mirror exceeds your maximum reach of " + (maxReach / 2) + ". Radius has been set to "+ (maxReach / 2) + ". ";
}
//Array settings //Mirror settings
Array.ArraySettings a = modifierSettings.getArraySettings(); Mirror.MirrorSettings m = modifierSettings.getMirrorSettings();
if (a.count < 0) { if (m.radius < 1) {
a.count = 0; m.radius = 1;
error += "Array count may not be negative. It has been reset to 0."; error += "Mirror size has to be at least 1. This has been corrected. ";
} }
if (m.getReach() > maxReach) {
m.radius = maxReach / 2;
error += "Mirror exceeds your maximum reach of " + (maxReach / 2) + ". Radius has been set to " + (maxReach / 2) + ". ";
}
if (a.getReach() > maxReach) { //Array settings
a.count = 0; Array.ArraySettings a = modifierSettings.getArraySettings();
error += "Array exceeds your maximum reach of " + maxReach + ". Array count has been reset to 0. "; if (a.count < 0) {
} a.count = 0;
error += "Array count may not be negative. It has been reset to 0.";
}
//Radial mirror settings if (a.getReach() > maxReach) {
RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings(); a.count = 0;
if (r.slices < 2) { error += "Array exceeds your maximum reach of " + maxReach + ". Array count has been reset to 0. ";
r.slices = 2; }
error += "Radial mirror needs to have at least 2 slices. Slices has been set to 2.";
}
if (r.radius < 1) { //Radial mirror settings
r.radius = 1; RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings();
error += "Radial mirror radius has to be at least 1. This has been corrected. "; if (r.slices < 2) {
} r.slices = 2;
if (r.getReach() > maxReach) { error += "Radial mirror needs to have at least 2 slices. Slices has been set to 2.";
r.radius = maxReach / 2; }
error += "Radial mirror exceeds your maximum reach of " + (maxReach / 2) + ". Radius has been set to "+ (maxReach / 2) + ". ";
}
//Other if (r.radius < 1) {
if (modifierSettings.reachUpgrade < 0) { r.radius = 1;
modifierSettings.reachUpgrade = 0; error += "Radial mirror radius has to be at least 1. This has been corrected. ";
} }
if (modifierSettings.reachUpgrade > 3) { if (r.getReach() > maxReach) {
modifierSettings.reachUpgrade = 3; r.radius = maxReach / 2;
} error += "Radial mirror exceeds your maximum reach of " + (maxReach / 2) + ". Radius has been set to " + (maxReach / 2) + ". ";
}
return error; //Other
} if (modifierSettings.reachUpgrade < 0) {
modifierSettings.reachUpgrade = 0;
}
if (modifierSettings.reachUpgrade > 3) {
modifierSettings.reachUpgrade = 3;
}
public static class ModifierSettings { return error;
private Mirror.MirrorSettings mirrorSettings; }
private Array.ArraySettings arraySettings;
private RadialMirror.RadialMirrorSettings radialMirrorSettings;
private boolean quickReplace = false;
private int reachUpgrade = 0;
public ModifierSettings() { public static void handleNewPlayer(Player player) {
mirrorSettings = new Mirror.MirrorSettings(); //Makes sure player has modifier settings (if it doesnt it will create it)
arraySettings = new Array.ArraySettings(); getModifierSettings(player);
radialMirrorSettings = new RadialMirror.RadialMirrorSettings();
}
public ModifierSettings(Mirror.MirrorSettings mirrorSettings, Array.ArraySettings arraySettings, //Only on server
RadialMirror.RadialMirrorSettings radialMirrorSettings, boolean quickReplace, int reachUpgrade) { if (!player.level.isClientSide) {
this.mirrorSettings = mirrorSettings; //Send to client
this.arraySettings = arraySettings; ModifierSettingsMessage msg = new ModifierSettingsMessage(getModifierSettings(player));
this.radialMirrorSettings = radialMirrorSettings; PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), msg);
this.quickReplace = quickReplace; }
this.reachUpgrade = reachUpgrade; }
}
public Mirror.MirrorSettings getMirrorSettings() { public static class ModifierSettings {
if (this.mirrorSettings == null) this.mirrorSettings = new Mirror.MirrorSettings(); private Mirror.MirrorSettings mirrorSettings;
return this.mirrorSettings; private Array.ArraySettings arraySettings;
} private RadialMirror.RadialMirrorSettings radialMirrorSettings;
private boolean quickReplace = false;
private int reachUpgrade = 0;
public void setMirrorSettings(Mirror.MirrorSettings mirrorSettings) { public ModifierSettings() {
if (mirrorSettings == null) return; mirrorSettings = new Mirror.MirrorSettings();
this.mirrorSettings = mirrorSettings; arraySettings = new Array.ArraySettings();
} radialMirrorSettings = new RadialMirror.RadialMirrorSettings();
}
public Array.ArraySettings getArraySettings() { public ModifierSettings(Mirror.MirrorSettings mirrorSettings, Array.ArraySettings arraySettings,
if (this.arraySettings == null) this.arraySettings = new Array.ArraySettings(); RadialMirror.RadialMirrorSettings radialMirrorSettings, boolean quickReplace, int reachUpgrade) {
return this.arraySettings; this.mirrorSettings = mirrorSettings;
} this.arraySettings = arraySettings;
this.radialMirrorSettings = radialMirrorSettings;
this.quickReplace = quickReplace;
this.reachUpgrade = reachUpgrade;
}
public void setArraySettings(Array.ArraySettings arraySettings) { public Mirror.MirrorSettings getMirrorSettings() {
if (arraySettings == null) return; if (this.mirrorSettings == null) this.mirrorSettings = new Mirror.MirrorSettings();
this.arraySettings = arraySettings; return this.mirrorSettings;
} }
public RadialMirror.RadialMirrorSettings getRadialMirrorSettings() { public void setMirrorSettings(Mirror.MirrorSettings mirrorSettings) {
if (this.radialMirrorSettings == null) this.radialMirrorSettings = new RadialMirror.RadialMirrorSettings(); if (mirrorSettings == null) return;
return this.radialMirrorSettings; this.mirrorSettings = mirrorSettings;
} }
public void setRadialMirrorSettings(RadialMirror.RadialMirrorSettings radialMirrorSettings) { public Array.ArraySettings getArraySettings() {
if (radialMirrorSettings == null) return; if (this.arraySettings == null) this.arraySettings = new Array.ArraySettings();
this.radialMirrorSettings = radialMirrorSettings; return this.arraySettings;
} }
public boolean doQuickReplace() { public void setArraySettings(Array.ArraySettings arraySettings) {
return quickReplace; if (arraySettings == null) return;
} this.arraySettings = arraySettings;
}
public void setQuickReplace(boolean quickReplace) { public RadialMirror.RadialMirrorSettings getRadialMirrorSettings() {
this.quickReplace = quickReplace; if (this.radialMirrorSettings == null) this.radialMirrorSettings = new RadialMirror.RadialMirrorSettings();
} return this.radialMirrorSettings;
}
public int getReachUpgrade() { public void setRadialMirrorSettings(RadialMirror.RadialMirrorSettings radialMirrorSettings) {
return reachUpgrade; if (radialMirrorSettings == null) return;
} this.radialMirrorSettings = radialMirrorSettings;
}
public void setReachUpgrade(int reachUpgrade) { public boolean doQuickReplace() {
this.reachUpgrade = reachUpgrade; return quickReplace;
//Set mirror radius to max }
int reach = 10;
switch (reachUpgrade) {
case 0: reach = BuildConfig.reach.maxReachLevel0.get(); break;
case 1: reach = BuildConfig.reach.maxReachLevel1.get(); break;
case 2: reach = BuildConfig.reach.maxReachLevel2.get(); break;
case 3: reach = BuildConfig.reach.maxReachLevel3.get(); break;
}
if (this.mirrorSettings != null) public void setQuickReplace(boolean quickReplace) {
this.mirrorSettings.radius = reach / 2; this.quickReplace = quickReplace;
if (this.radialMirrorSettings != null) }
this.radialMirrorSettings.radius = reach / 2;
}
}
public static void handleNewPlayer(PlayerEntity player){ public int getReachUpgrade() {
//Makes sure player has modifier settings (if it doesnt it will create it) return reachUpgrade;
getModifierSettings(player); }
//Only on server public void setReachUpgrade(int reachUpgrade) {
if (!player.world.isRemote) { this.reachUpgrade = reachUpgrade;
//Send to client //Set mirror radius to max
ModifierSettingsMessage msg = new ModifierSettingsMessage(getModifierSettings(player)); int reach = 10;
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), msg); switch (reachUpgrade) {
} case 0:
} reach = CommonConfig.reach.maxReachLevel0.get();
break;
case 1:
reach = CommonConfig.reach.maxReachLevel1.get();
break;
case 2:
reach = CommonConfig.reach.maxReachLevel2.get();
break;
case 3:
reach = CommonConfig.reach.maxReachLevel3.get();
break;
}
if (this.mirrorSettings != null)
this.mirrorSettings.radius = reach / 2;
if (this.radialMirrorSettings != null)
this.radialMirrorSettings.radius = reach / 2;
}
}
} }

View File

@@ -1,195 +1,194 @@
package nl.requios.effortlessbuilding.buildmodifier; package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.util.Direction; import net.minecraft.core.Direction;
import net.minecraft.util.Hand; import net.minecraft.world.InteractionHand;
import net.minecraft.util.Mirror; import net.minecraft.world.level.block.Mirror;
import net.minecraft.util.Rotation; import net.minecraft.world.level.block.Rotation;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.Mth;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import nl.requios.effortlessbuilding.item.ItemRandomizerBag; import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class RadialMirror { public class RadialMirror {
public static class RadialMirrorSettings { public static List<BlockPos> findCoordinates(Player player, BlockPos startPos) {
public boolean enabled = false; List<BlockPos> coordinates = new ArrayList<>();
public Vec3d position = new Vec3d(0.5, 64.5, 0.5);
public int slices = 4;
public boolean alternate = false;
public int radius = 20;
public boolean drawLines = true, drawPlanes = false;
public RadialMirrorSettings() { //find radial mirror settings for the player
} RadialMirrorSettings r = ModifierSettingsManager.getModifierSettings(player).getRadialMirrorSettings();
if (!isEnabled(r, startPos)) return coordinates;
public RadialMirrorSettings(boolean enabled, Vec3d position, int slices, boolean alternate, int radius, boolean drawLines, boolean drawPlanes) { //get angle between slices
this.enabled = enabled; double sliceAngle = 2 * Math.PI / r.slices;
this.position = position;
this.slices = slices;
this.alternate = alternate;
this.radius = radius;
this.drawLines = drawLines;
this.drawPlanes = drawPlanes;
}
public int getReach() { Vec3 startVec = new Vec3(startPos.getX() + 0.5f, startPos.getY() + 0.5f, startPos.getZ() + 0.5f);
return radius * 2; Vec3 relStartVec = startVec.subtract(r.position);
}
}
public static List<BlockPos> findCoordinates(PlayerEntity player, BlockPos startPos) { double startAngleToCenter = Mth.atan2(relStartVec.x, relStartVec.z);
List<BlockPos> coordinates = new ArrayList<>(); if (startAngleToCenter < 0) startAngleToCenter += Math.PI;
double startAngleInSlice = startAngleToCenter % sliceAngle;
//find radial mirror settings for the player for (int i = 1; i < r.slices; i++) {
RadialMirrorSettings r = ModifierSettingsManager.getModifierSettings(player).getRadialMirrorSettings(); double curAngle = sliceAngle * i;
if (!isEnabled(r, startPos)) return coordinates;
//get angle between slices //alternate mirroring of slices
double sliceAngle = 2 * Math.PI / r.slices; if (r.alternate && i % 2 == 1) {
curAngle = curAngle - startAngleInSlice + (sliceAngle - startAngleInSlice);
}
Vec3d startVec = new Vec3d(startPos.getX() + 0.5f, startPos.getY() + 0.5f, startPos.getZ() + 0.5f); Vec3 relNewVec = relStartVec.yRot((float) curAngle);
Vec3d relStartVec = startVec.subtract(r.position); BlockPos newBlockPos = new BlockPos(r.position.add(relNewVec));
if (!coordinates.contains(newBlockPos) && !newBlockPos.equals(startPos)) coordinates.add(newBlockPos);
}
double startAngleToCenter = MathHelper.atan2(relStartVec.x, relStartVec.z); return coordinates;
if (startAngleToCenter < 0) startAngleToCenter += Math.PI; }
double startAngleInSlice = startAngleToCenter % sliceAngle;
for (int i = 1; i < r.slices; i++) { public static List<BlockState> findBlockStates(Player player, BlockPos startPos, BlockState blockState, ItemStack itemStack, List<ItemStack> itemStacks) {
double curAngle = sliceAngle * i; List<BlockState> blockStates = new ArrayList<>();
List<BlockPos> coordinates = new ArrayList<>(); //to keep track of duplicates
//alternate mirroring of slices //find radial mirror settings for the player that placed the block
if (r.alternate && i%2 == 1) { RadialMirrorSettings r = ModifierSettingsManager.getModifierSettings(player).getRadialMirrorSettings();
curAngle = curAngle - startAngleInSlice + (sliceAngle - startAngleInSlice); if (!isEnabled(r, startPos)) return blockStates;
}
Vec3d relNewVec = relStartVec.rotateYaw((float) curAngle);
BlockPos newBlockPos = new BlockPos(r.position.add(relNewVec));
if (!coordinates.contains(newBlockPos) && !newBlockPos.equals(startPos)) coordinates.add(newBlockPos);
}
return coordinates;
}
public static List<BlockState> findBlockStates(PlayerEntity player, BlockPos startPos, BlockState blockState, ItemStack itemStack, List<ItemStack> itemStacks) {
List<BlockState> blockStates = new ArrayList<>();
List<BlockPos> coordinates = new ArrayList<>(); //to keep track of duplicates
//find radial mirror settings for the player that placed the block
RadialMirrorSettings r = ModifierSettingsManager.getModifierSettings(player).getRadialMirrorSettings();
if (!isEnabled(r, startPos)) return blockStates;
//get angle between slices //get angle between slices
double sliceAngle = 2 * Math.PI / r.slices; double sliceAngle = 2 * Math.PI / r.slices;
Vec3d startVec = new Vec3d(startPos.getX() + 0.5f, startPos.getY() + 0.5f, startPos.getZ() + 0.5f); Vec3 startVec = new Vec3(startPos.getX() + 0.5f, startPos.getY() + 0.5f, startPos.getZ() + 0.5f);
Vec3d relStartVec = startVec.subtract(r.position); Vec3 relStartVec = startVec.subtract(r.position);
double startAngleToCenter = MathHelper.atan2(relStartVec.x, relStartVec.z); double startAngleToCenter = Mth.atan2(relStartVec.x, relStartVec.z);
double startAngleToCenterMod = startAngleToCenter < 0 ? startAngleToCenter + Math.PI : startAngleToCenter; double startAngleToCenterMod = startAngleToCenter < 0 ? startAngleToCenter + Math.PI : startAngleToCenter;
double startAngleInSlice = startAngleToCenterMod % sliceAngle; double startAngleInSlice = startAngleToCenterMod % sliceAngle;
//Rotate the original blockstate //Rotate the original blockstate
blockState = rotateOriginalBlockState(startAngleToCenter, blockState); blockState = rotateOriginalBlockState(player, startPos, startAngleToCenter, blockState);
//Randomizer bag synergy //Randomizer bag synergy
IItemHandler bagInventory = null; AbstractRandomizerBagItem randomizerBagItem = null;
if (!itemStack.isEmpty() && itemStack.getItem() instanceof ItemRandomizerBag) { IItemHandler bagInventory = null;
bagInventory = ItemRandomizerBag.getBagInventory(itemStack); if (!itemStack.isEmpty() && itemStack.getItem() instanceof AbstractRandomizerBagItem) {
} randomizerBagItem = (AbstractRandomizerBagItem) itemStack.getItem() ;
bagInventory = randomizerBagItem.getBagInventory(itemStack);
}
BlockState newBlockState; BlockState newBlockState;
for (int i = 1; i < r.slices; i++) { for (int i = 1; i < r.slices; i++) {
newBlockState = blockState; newBlockState = blockState;
double curAngle = sliceAngle * i; double curAngle = sliceAngle * i;
//alternate mirroring of slices //alternate mirroring of slices
if (r.alternate && i%2 == 1) { if (r.alternate && i % 2 == 1) {
curAngle = curAngle - startAngleInSlice + (sliceAngle - startAngleInSlice); curAngle = curAngle - startAngleInSlice + (sliceAngle - startAngleInSlice);
} }
Vec3d relNewVec = relStartVec.rotateYaw((float) curAngle); Vec3 relNewVec = relStartVec.yRot((float) curAngle);
BlockPos newBlockPos = new BlockPos(r.position.add(relNewVec)); BlockPos newBlockPos = new BlockPos(r.position.add(relNewVec));
if (coordinates.contains(newBlockPos) || newBlockPos.equals(startPos)) continue; //filter out duplicates if (coordinates.contains(newBlockPos) || newBlockPos.equals(startPos)) continue; //filter out duplicates
coordinates.add(newBlockPos); coordinates.add(newBlockPos);
//Randomizer bag synergy //Randomizer bag synergy
if (bagInventory != null) { if (randomizerBagItem != null) {
itemStack = ItemRandomizerBag.pickRandomStack(bagInventory); itemStack = randomizerBagItem.pickRandomStack(bagInventory);
newBlockState = BuildModifiers newBlockState = BuildModifiers
.getBlockStateFromItem(itemStack, player, startPos, Direction.UP, new Vec3d(0, 0, 0), Hand.MAIN_HAND); .getBlockStateFromItem(itemStack, player, startPos, Direction.UP, new Vec3(0, 0, 0), InteractionHand.MAIN_HAND);
newBlockState = rotateOriginalBlockState(startAngleToCenter, newBlockState); newBlockState = rotateOriginalBlockState(player, startPos, startAngleToCenter, newBlockState);
} }
//rotate //rotate
newBlockState = rotateBlockState(relNewVec, newBlockState, r.alternate && i%2 == 1); newBlockState = rotateBlockState(player, startPos, relNewVec, newBlockState, r.alternate && i % 2 == 1);
blockStates.add(newBlockState); blockStates.add(newBlockState);
itemStacks.add(itemStack); itemStacks.add(itemStack);
} }
return blockStates; return blockStates;
} }
private static BlockState rotateOriginalBlockState(double startAngleToCenter, BlockState blockState) { private static BlockState rotateOriginalBlockState(Player player, BlockPos startPos, double startAngleToCenter, BlockState blockState) {
BlockState newBlockState = blockState; BlockState newBlockState = blockState;
if (startAngleToCenter < -0.751 * Math.PI || startAngleToCenter > 0.749 * Math.PI) { if (startAngleToCenter < -0.751 * Math.PI || startAngleToCenter > 0.749 * Math.PI) {
newBlockState = blockState.rotate(Rotation.CLOCKWISE_180); newBlockState = blockState.rotate(player.level, startPos, Rotation.CLOCKWISE_180);
} else if (startAngleToCenter < -0.251 * Math.PI) { } else if (startAngleToCenter < -0.251 * Math.PI) {
newBlockState = blockState.rotate(Rotation.COUNTERCLOCKWISE_90); newBlockState = blockState.rotate(player.level, startPos, Rotation.COUNTERCLOCKWISE_90);
} else if (startAngleToCenter > 0.249 * Math.PI) { } else if (startAngleToCenter > 0.249 * Math.PI) {
newBlockState = blockState.rotate(Rotation.CLOCKWISE_90); newBlockState = blockState.rotate(player.level, startPos, Rotation.CLOCKWISE_90);
} }
return newBlockState; return newBlockState;
} }
private static BlockState rotateBlockState(Vec3d relVec, BlockState blockState, boolean alternate) { private static BlockState rotateBlockState(Player player, BlockPos startPos, Vec3 relVec, BlockState blockState, boolean alternate) {
BlockState newBlockState; BlockState newBlockState;
double angleToCenter = MathHelper.atan2(relVec.x, relVec.z); //between -PI and PI double angleToCenter = Mth.atan2(relVec.x, relVec.z); //between -PI and PI
if (angleToCenter < -0.751 * Math.PI || angleToCenter > 0.749 * Math.PI) { if (angleToCenter < -0.751 * Math.PI || angleToCenter > 0.749 * Math.PI) {
newBlockState = blockState.rotate(Rotation.CLOCKWISE_180); newBlockState = blockState.rotate(player.level, startPos, Rotation.CLOCKWISE_180);
if (alternate) { if (alternate) {
newBlockState = newBlockState.mirror(Mirror.FRONT_BACK); newBlockState = newBlockState.mirror(Mirror.FRONT_BACK);
} }
} else if (angleToCenter < -0.251 * Math.PI) { } else if (angleToCenter < -0.251 * Math.PI) {
newBlockState = blockState.rotate(Rotation.CLOCKWISE_90); newBlockState = blockState.rotate(player.level, startPos, Rotation.CLOCKWISE_90);
if (alternate) { if (alternate) {
newBlockState = newBlockState.mirror(Mirror.LEFT_RIGHT); newBlockState = newBlockState.mirror(Mirror.LEFT_RIGHT);
} }
} else if (angleToCenter > 0.249 * Math.PI) { } else if (angleToCenter > 0.249 * Math.PI) {
newBlockState = blockState.rotate(Rotation.COUNTERCLOCKWISE_90); newBlockState = blockState.rotate(player.level, startPos, Rotation.COUNTERCLOCKWISE_90);
if (alternate) { if (alternate) {
newBlockState = newBlockState.mirror(Mirror.LEFT_RIGHT); newBlockState = newBlockState.mirror(Mirror.LEFT_RIGHT);
} }
} else { } else {
newBlockState = blockState; newBlockState = blockState;
if (alternate) { if (alternate) {
newBlockState = newBlockState.mirror(Mirror.FRONT_BACK); newBlockState = newBlockState.mirror(Mirror.FRONT_BACK);
} }
} }
return newBlockState; return newBlockState;
} }
public static boolean isEnabled(RadialMirrorSettings r, BlockPos startPos) { public static boolean isEnabled(RadialMirrorSettings r, BlockPos startPos) {
if (r == null || !r.enabled) return false; if (r == null || !r.enabled) return false;
if (new Vec3d(startPos.getX() + 0.5, startPos.getY() + 0.5, startPos.getZ() + 0.5).subtract(r.position).lengthSquared() > return !(new Vec3(startPos.getX() + 0.5, startPos.getY() + 0.5, startPos.getZ() + 0.5).subtract(r.position).lengthSqr() >
r.radius * r.radius) r.radius * r.radius);
return false; }
return true; public static class RadialMirrorSettings {
} public boolean enabled = false;
public Vec3 position = new Vec3(0.5, 64.5, 0.5);
public int slices = 4;
public boolean alternate = false;
public int radius = 20;
public boolean drawLines = true, drawPlanes = false;
public RadialMirrorSettings() {
}
public RadialMirrorSettings(boolean enabled, Vec3 position, int slices, boolean alternate, int radius, boolean drawLines, boolean drawPlanes) {
this.enabled = enabled;
this.position = position;
this.slices = slices;
this.alternate = alternate;
this.radius = radius;
this.drawLines = drawLines;
this.drawPlanes = drawPlanes;
}
public int getReach() {
return radius * 2;
}
}
} }

View File

@@ -1,49 +1,46 @@
package nl.requios.effortlessbuilding.buildmodifier; package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.entity.player.Player;
import net.minecraft.item.BlockItem; import net.minecraft.world.item.BlockItem;
import net.minecraft.item.Item; import net.minecraft.world.item.ItemStack;
import net.minecraft.item.ItemStack; import net.minecraft.core.Direction;
import net.minecraft.util.Direction; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.BlockPos; import net.minecraft.world.phys.Vec3;
import net.minecraft.util.math.Vec3d; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.server.ServerWorld; import nl.requios.effortlessbuilding.CommonConfig;
import net.minecraft.world.storage.loot.LootContext;
import net.minecraft.world.storage.loot.LootParameterSet;
import nl.requios.effortlessbuilding.BuildConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.helper.FixedStack; import nl.requios.effortlessbuilding.helper.FixedStack;
import nl.requios.effortlessbuilding.helper.InventoryHelper; import nl.requios.effortlessbuilding.helper.InventoryHelper;
import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.render.BlockPreviewRenderer; import nl.requios.effortlessbuilding.render.BlockPreviews;
import java.util.*; import java.util.*;
public class UndoRedo { public class UndoRedo {
//Undo and redo stacks per player //Undo and redo stacks per player
//Gets added to twice in singleplayer (server and client) if not careful. So separate stacks. //Gets added to twice in singleplayer (server and client) if not careful. So separate stacks.
private static Map<UUID, FixedStack<BlockSet>> undoStacksClient = new HashMap<>(); private static final Map<UUID, FixedStack<BlockSet>> undoStacksClient = new HashMap<>();
private static Map<UUID, FixedStack<BlockSet>> undoStacksServer = new HashMap<>(); private static final Map<UUID, FixedStack<BlockSet>> undoStacksServer = new HashMap<>();
private static Map<UUID, FixedStack<BlockSet>> redoStacksClient = new HashMap<>(); private static final Map<UUID, FixedStack<BlockSet>> redoStacksClient = new HashMap<>();
private static Map<UUID, FixedStack<BlockSet>> redoStacksServer = new HashMap<>(); private static final Map<UUID, FixedStack<BlockSet>> redoStacksServer = new HashMap<>();
//add to undo stack //add to undo stack
public static void addUndo(PlayerEntity player, BlockSet blockSet) { public static void addUndo(Player player, BlockSet blockSet) {
Map<UUID, FixedStack<BlockSet>> undoStacks = player.world.isRemote ? undoStacksClient : undoStacksServer; Map<UUID, FixedStack<BlockSet>> undoStacks = player.level.isClientSide ? undoStacksClient : undoStacksServer;
//Assert coordinates is as long as previous and new blockstate lists //Assert coordinates is as long as previous and new blockstate lists
if (blockSet.getCoordinates().size() != blockSet.getPreviousBlockStates().size() || if (blockSet.getCoordinates().size() != blockSet.getPreviousBlockStates().size() ||
blockSet.getCoordinates().size() != blockSet.getNewBlockStates().size()) { blockSet.getCoordinates().size() != blockSet.getNewBlockStates().size()) {
EffortlessBuilding.logger.error("Coordinates and blockstate lists are not equal length. Coordinates: {}. Previous blockstates: {}. New blockstates: {}.", EffortlessBuilding.logger.error("Coordinates and blockstate lists are not equal length. Coordinates: {}. Previous blockstates: {}. New blockstates: {}.",
blockSet.getCoordinates().size(), blockSet.getPreviousBlockStates().size(), blockSet.getNewBlockStates().size()); blockSet.getCoordinates().size(), blockSet.getPreviousBlockStates().size(), blockSet.getNewBlockStates().size());
} }
//Warn if previous and new blockstate are equal //Warn if previous and new blockstate are equal
//Can happen in a lot of valid cases //Can happen in a lot of valid cases
// for (int i = 0; i < blockSet.getCoordinates().size(); i++) { // for (int i = 0; i < blockSet.getCoordinates().size(); i++) {
// if (blockSet.getPreviousBlockStates().get(i).equals(blockSet.getNewBlockStates().get(i))) { // if (blockSet.getPreviousBlockStates().get(i).equals(blockSet.getNewBlockStates().get(i))) {
// EffortlessBuilding.logger.warn("Previous and new blockstates are equal at index {}. Blockstate: {}.", // EffortlessBuilding.logger.warn("Previous and new blockstates are equal at index {}. Blockstate: {}.",
@@ -51,193 +48,192 @@ public class UndoRedo {
// } // }
// } // }
//If no stack exists, make one //If no stack exists, make one
if (!undoStacks.containsKey(player.getUniqueID())) { if (!undoStacks.containsKey(player.getUUID())) {
undoStacks.put(player.getUniqueID(), new FixedStack<>(new BlockSet[BuildConfig.survivalBalancers.undoStackSize.get()])); undoStacks.put(player.getUUID(), new FixedStack<>(new BlockSet[CommonConfig.survivalBalancers.undoStackSize.get()]));
} }
undoStacks.get(player.getUniqueID()).push(blockSet); undoStacks.get(player.getUUID()).push(blockSet);
} }
private static void addRedo(PlayerEntity player, BlockSet blockSet) { private static void addRedo(Player player, BlockSet blockSet) {
Map<UUID, FixedStack<BlockSet>> redoStacks = player.world.isRemote ? redoStacksClient : redoStacksServer; Map<UUID, FixedStack<BlockSet>> redoStacks = player.level.isClientSide ? redoStacksClient : redoStacksServer;
//(No asserts necessary, it's private) //(No asserts necessary, it's private)
//If no stack exists, make one //If no stack exists, make one
if (!redoStacks.containsKey(player.getUniqueID())) { if (!redoStacks.containsKey(player.getUUID())) {
redoStacks.put(player.getUniqueID(), new FixedStack<>(new BlockSet[BuildConfig.survivalBalancers.undoStackSize.get()])); redoStacks.put(player.getUUID(), new FixedStack<>(new BlockSet[CommonConfig.survivalBalancers.undoStackSize.get()]));
} }
redoStacks.get(player.getUniqueID()).push(blockSet); redoStacks.get(player.getUUID()).push(blockSet);
} }
public static boolean undo(PlayerEntity player) { public static boolean undo(Player player) {
Map<UUID, FixedStack<BlockSet>> undoStacks = player.world.isRemote ? undoStacksClient : undoStacksServer; Map<UUID, FixedStack<BlockSet>> undoStacks = player.level.isClientSide ? undoStacksClient : undoStacksServer;
if (!undoStacks.containsKey(player.getUniqueID())) return false; if (!undoStacks.containsKey(player.getUUID())) return false;
FixedStack<BlockSet> undoStack = undoStacks.get(player.getUniqueID()); FixedStack<BlockSet> undoStack = undoStacks.get(player.getUUID());
if (undoStack.isEmpty()) return false; if (undoStack.isEmpty()) return false;
BlockSet blockSet = undoStack.pop(); BlockSet blockSet = undoStack.pop();
List<BlockPos> coordinates = blockSet.getCoordinates(); List<BlockPos> coordinates = blockSet.getCoordinates();
List<BlockState> previousBlockStates = blockSet.getPreviousBlockStates(); List<BlockState> previousBlockStates = blockSet.getPreviousBlockStates();
List<BlockState> newBlockStates = blockSet.getNewBlockStates(); List<BlockState> newBlockStates = blockSet.getNewBlockStates();
Vec3d hitVec = blockSet.getHitVec(); Vec3 hitVec = blockSet.getHitVec();
//Find up to date itemstacks in player inventory //Find up to date itemstacks in player inventory
List<ItemStack> itemStacks = findItemStacksInInventory(player, previousBlockStates); List<ItemStack> itemStacks = findItemStacksInInventory(player, previousBlockStates);
if (player.world.isRemote) { if (player.level.isClientSide) {
BlockPreviewRenderer.onBlocksBroken(coordinates, itemStacks, newBlockStates, blockSet.getSecondPos(), blockSet.getFirstPos()); BlockPreviews.onBlocksBroken(coordinates, itemStacks, newBlockStates, blockSet.getSecondPos(), blockSet.getFirstPos());
} else { } else {
//break all those blocks, reset to what they were //break all those blocks, reset to what they were
for (int i = 0; i < coordinates.size(); i++) { for (int i = 0; i < coordinates.size(); i++) {
BlockPos coordinate = coordinates.get(i); BlockPos coordinate = coordinates.get(i);
ItemStack itemStack = itemStacks.get(i); ItemStack itemStack = itemStacks.get(i);
if (previousBlockStates.get(i).equals(newBlockStates.get(i))) continue; if (previousBlockStates.get(i).equals(newBlockStates.get(i))) continue;
//get blockstate from itemstack //get blockstate from itemstack
BlockState previousBlockState = Blocks.AIR.getDefaultState(); BlockState previousBlockState = previousBlockStates.get(i);
if (itemStack.getItem() instanceof BlockItem) { if (itemStack.getItem() instanceof BlockItem) {
previousBlockState = ((BlockItem) itemStack.getItem()).getBlock().getDefaultState(); previousBlockState = ((BlockItem) itemStack.getItem()).getBlock().defaultBlockState();
} }
if (player.world.isBlockPresent(coordinate)) { if (player.level.isLoaded(coordinate)) {
//check itemstack empty //check itemstack empty
if (itemStack.isEmpty()) { if (itemStack.isEmpty() && !player.isCreative()) {
itemStack = findItemStackInInventory(player, previousBlockStates.get(i)); itemStack = findItemStackInInventory(player, previousBlockStates.get(i));
//get blockstate from new itemstack //get blockstate from new itemstack
if (!itemStack.isEmpty() && itemStack.getItem() instanceof BlockItem) { if (!itemStack.isEmpty() && itemStack.getItem() instanceof BlockItem) {
previousBlockState = ((BlockItem) itemStack.getItem()).getBlock().getDefaultState(); previousBlockState = ((BlockItem) itemStack.getItem()).getBlock().defaultBlockState();
} else { } else {
if (previousBlockStates.get(i).getBlock() != Blocks.AIR) if (previousBlockStates.get(i).getBlock() != Blocks.AIR)
EffortlessBuilding.logTranslate(player, "", previousBlockStates.get(i).getBlock().getTranslationKey(), " not found in inventory", true); EffortlessBuilding.logTranslate(player, "", previousBlockStates.get(i).getBlock().getDescriptionId(), " not found in inventory", true);
previousBlockState = Blocks.AIR.getDefaultState(); previousBlockState = Blocks.AIR.defaultBlockState();
} }
} }
if (itemStack.isEmpty()) SurvivalHelper.breakBlock(player.world, player, coordinate, true); if (itemStack.isEmpty()) SurvivalHelper.breakBlock(player.level, player, coordinate, true);
//if previousBlockState is air, placeBlock will set it to air //if previousBlockState is air, placeBlock will set it to air
SurvivalHelper.placeBlock(player.world, player, coordinate, previousBlockState, itemStack, Direction.UP, hitVec, true, false, false); SurvivalHelper.placeBlock(player.level, player, coordinate, previousBlockState, itemStack, Direction.UP, hitVec, true, false, false);
} }
} }
} }
//add to redo //add to redo
addRedo(player, blockSet); addRedo(player, blockSet);
return true; return true;
} }
public static boolean redo(PlayerEntity player) { public static boolean redo(Player player) {
Map<UUID, FixedStack<BlockSet>> redoStacks = player.world.isRemote ? redoStacksClient : redoStacksServer; Map<UUID, FixedStack<BlockSet>> redoStacks = player.level.isClientSide ? redoStacksClient : redoStacksServer;
if (!redoStacks.containsKey(player.getUniqueID())) return false; if (!redoStacks.containsKey(player.getUUID())) return false;
FixedStack<BlockSet> redoStack = redoStacks.get(player.getUniqueID()); FixedStack<BlockSet> redoStack = redoStacks.get(player.getUUID());
if (redoStack.isEmpty()) return false; if (redoStack.isEmpty()) return false;
BlockSet blockSet = redoStack.pop(); BlockSet blockSet = redoStack.pop();
List<BlockPos> coordinates = blockSet.getCoordinates(); List<BlockPos> coordinates = blockSet.getCoordinates();
List<BlockState> previousBlockStates = blockSet.getPreviousBlockStates(); List<BlockState> previousBlockStates = blockSet.getPreviousBlockStates();
List<BlockState> newBlockStates = blockSet.getNewBlockStates(); List<BlockState> newBlockStates = blockSet.getNewBlockStates();
Vec3d hitVec = blockSet.getHitVec(); Vec3 hitVec = blockSet.getHitVec();
//Find up to date itemstacks in player inventory //Find up to date itemstacks in player inventory
List<ItemStack> itemStacks = findItemStacksInInventory(player, newBlockStates); List<ItemStack> itemStacks = findItemStacksInInventory(player, newBlockStates);
if (player.world.isRemote) { if (player.level.isClientSide) {
BlockPreviewRenderer.onBlocksPlaced(coordinates, itemStacks, newBlockStates, blockSet.getFirstPos(), blockSet.getSecondPos()); BlockPreviews.onBlocksPlaced(coordinates, itemStacks, newBlockStates, blockSet.getFirstPos(), blockSet.getSecondPos());
} else { } else {
//place blocks //place blocks
for (int i = 0; i < coordinates.size(); i++) { for (int i = 0; i < coordinates.size(); i++) {
BlockPos coordinate = coordinates.get(i); BlockPos coordinate = coordinates.get(i);
ItemStack itemStack = itemStacks.get(i); ItemStack itemStack = itemStacks.get(i);
if (previousBlockStates.get(i).equals(newBlockStates.get(i))) continue; if (previousBlockStates.get(i).equals(newBlockStates.get(i))) continue;
//get blockstate from itemstack //get blockstate from itemstack
BlockState newBlockState = Blocks.AIR.getDefaultState(); BlockState newBlockState = newBlockStates.get(i);
if (itemStack.getItem() instanceof BlockItem) { if (itemStack.getItem() instanceof BlockItem) {
newBlockState = ((BlockItem) itemStack.getItem()).getBlock().getDefaultState(); newBlockState = ((BlockItem) itemStack.getItem()).getBlock().defaultBlockState();
} }
if (player.world.isBlockPresent(coordinate)) { if (player.level.isLoaded(coordinate)) {
//check itemstack empty //check itemstack empty
if (itemStack.isEmpty()) { if (itemStack.isEmpty() && !player.isCreative()) {
itemStack = findItemStackInInventory(player, newBlockStates.get(i)); itemStack = findItemStackInInventory(player, newBlockStates.get(i));
//get blockstate from new itemstack //get blockstate from new itemstack
if (!itemStack.isEmpty() && itemStack.getItem() instanceof BlockItem) { if (!itemStack.isEmpty() && itemStack.getItem() instanceof BlockItem) {
newBlockState = ((BlockItem) itemStack.getItem()).getBlock().getDefaultState(); newBlockState = ((BlockItem) itemStack.getItem()).getBlock().defaultBlockState();
} else { } else {
if (newBlockStates.get(i).getBlock() != Blocks.AIR) if (newBlockStates.get(i).getBlock() != Blocks.AIR)
EffortlessBuilding.logTranslate(player, "", newBlockStates.get(i).getBlock().getTranslationKey(), " not found in inventory", true); EffortlessBuilding.logTranslate(player, "", newBlockStates.get(i).getBlock().getDescriptionId(), " not found in inventory", true);
newBlockState = Blocks.AIR.getDefaultState(); newBlockState = Blocks.AIR.defaultBlockState();
} }
} }
if (itemStack.isEmpty()) SurvivalHelper.breakBlock(player.world, player, coordinate, true); if (itemStack.isEmpty()) SurvivalHelper.breakBlock(player.level, player, coordinate, true);
SurvivalHelper.placeBlock(player.world, player, coordinate, newBlockState, itemStack, Direction.UP, hitVec, true, false, false); SurvivalHelper.placeBlock(player.level, player, coordinate, newBlockState, itemStack, Direction.UP, hitVec, true, false, false);
} }
} }
} }
//add to undo //add to undo
addUndo(player, blockSet); addUndo(player, blockSet);
return true; return true;
} }
public static void clear(PlayerEntity player) { public static void clear(Player player) {
Map<UUID, FixedStack<BlockSet>> undoStacks = player.world.isRemote ? undoStacksClient : undoStacksServer; Map<UUID, FixedStack<BlockSet>> undoStacks = player.level.isClientSide ? undoStacksClient : undoStacksServer;
Map<UUID, FixedStack<BlockSet>> redoStacks = player.world.isRemote ? redoStacksClient : redoStacksServer; Map<UUID, FixedStack<BlockSet>> redoStacks = player.level.isClientSide ? redoStacksClient : redoStacksServer;
if (undoStacks.containsKey(player.getUniqueID())) { if (undoStacks.containsKey(player.getUUID())) {
undoStacks.get(player.getUniqueID()).clear(); undoStacks.get(player.getUUID()).clear();
} }
if (redoStacks.containsKey(player.getUniqueID())) { if (redoStacks.containsKey(player.getUUID())) {
redoStacks.get(player.getUniqueID()).clear(); redoStacks.get(player.getUUID()).clear();
} }
} }
private static List<ItemStack> findItemStacksInInventory(PlayerEntity player, List<BlockState> blockStates) { private static List<ItemStack> findItemStacksInInventory(Player player, List<BlockState> blockStates) {
List<ItemStack> itemStacks = new ArrayList<>(blockStates.size()); List<ItemStack> itemStacks = new ArrayList<>(blockStates.size());
for (BlockState blockState : blockStates) { for (BlockState blockState : blockStates) {
itemStacks.add(findItemStackInInventory(player, blockState)); itemStacks.add(findItemStackInInventory(player, blockState));
} }
return itemStacks; return itemStacks;
} }
private static ItemStack findItemStackInInventory(PlayerEntity player, BlockState blockState) { private static ItemStack findItemStackInInventory(Player player, BlockState blockState) {
ItemStack itemStack = ItemStack.EMPTY; ItemStack itemStack = ItemStack.EMPTY;
if (blockState == null) return itemStack; if (blockState == null) return itemStack;
//First try previousBlockStates //First try previousBlockStates
//TODO try to find itemstack with right blockstate first //TODO try to find itemstack with right blockstate first
// then change line 103 back (get state from item) // then change line 103 back (get state from item)
itemStack = InventoryHelper.findItemStackInInventory(player, blockState.getBlock()); itemStack = InventoryHelper.findItemStackInInventory(player, blockState.getBlock());
//then anything it drops //then anything it drops
if (itemStack.isEmpty()) { if (itemStack.isEmpty()) {
//Cannot check drops on clientside because loot tables are server only //Cannot check drops on clientside because loot tables are server only
if (!player.world.isRemote) if (!player.level.isClientSide) {
{ List<ItemStack> itemsDropped = Block.getDrops(blockState, (ServerLevel) player.level, BlockPos.ZERO, null);
List<ItemStack> itemsDropped = Block.getDrops(blockState, (ServerWorld) player.world, BlockPos.ZERO, null); for (ItemStack itemStackDropped : itemsDropped) {
for (ItemStack itemStackDropped : itemsDropped) { if (itemStackDropped.getItem() instanceof BlockItem) {
if (itemStackDropped.getItem() instanceof BlockItem) { Block block = ((BlockItem) itemStackDropped.getItem()).getBlock();
Block block = ((BlockItem) itemStackDropped.getItem()).getBlock(); itemStack = InventoryHelper.findItemStackInInventory(player, block);
itemStack = InventoryHelper.findItemStackInInventory(player, block); }
} }
} }
} }
}
//then air //then air
//(already empty) //(already empty)
return itemStack; return itemStack;
} }
} }

View File

@@ -1,34 +1,37 @@
package nl.requios.effortlessbuilding.capability; package nl.requios.effortlessbuilding.capability;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Direction; import net.minecraft.core.Direction;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilitySerializable; import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.ItemStackHandler;
import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class ItemHandlerCapabilityProvider implements ICapabilitySerializable<CompoundNBT> { public class ItemHandlerCapabilityProvider implements ICapabilitySerializable<CompoundTag> {
IItemHandler itemHandler = new ItemStackHandler(ItemRandomizerBag.INV_SIZE); IItemHandler itemHandler;
@Nonnull public ItemHandlerCapabilityProvider(int size) {
@Override itemHandler = new ItemStackHandler(size);
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { }
return CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.orEmpty(cap, LazyOptional.of(() -> itemHandler));
}
@Override @Nonnull
public CompoundNBT serializeNBT() { @Override
return ((ItemStackHandler) itemHandler).serializeNBT(); public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
} return CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.orEmpty(cap, LazyOptional.of(() -> itemHandler));
}
@Override @Override
public void deserializeNBT(CompoundNBT nbt) { public CompoundTag serializeNBT() {
((ItemStackHandler) itemHandler).deserializeNBT(nbt); return ((ItemStackHandler) itemHandler).serializeNBT();
} }
@Override
public void deserializeNBT(CompoundTag nbt) {
((ItemStackHandler) itemHandler).deserializeNBT(nbt);
}
} }

View File

@@ -1,11 +1,9 @@
package nl.requios.effortlessbuilding.capability; package nl.requios.effortlessbuilding.capability;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.INBT; import net.minecraft.nbt.Tag;
import net.minecraft.util.Direction; import net.minecraft.core.Direction;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.*;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
@@ -15,89 +13,96 @@ import nl.requios.effortlessbuilding.buildmode.BuildModes;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings; import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings;
@Mod.EventBusSubscriber @Mod.EventBusSubscriber
public class ModeCapabilityManager { public class ModeCapabilityManager {
@CapabilityInject(IModeCapability.class) public static Capability<IModeCapability> MODE_CAPABILITY = CapabilityManager.get(new CapabilityToken<>(){});
public final static Capability<IModeCapability> modeCapability = null;
public interface IModeCapability { // Allows for the capability to persist after death.
ModeSettings getModeData(); @SubscribeEvent
public static void clonePlayer(PlayerEvent.Clone event) {
LazyOptional<IModeCapability> original = event.getOriginal().getCapability(MODE_CAPABILITY, null);
LazyOptional<IModeCapability> clone = event.getEntity().getCapability(MODE_CAPABILITY, null);
clone.ifPresent(cloneModeCapability ->
original.ifPresent(originalModeCapability ->
cloneModeCapability.setModeData(originalModeCapability.getModeData())));
}
void setModeData(ModeSettings modeSettings); public interface IModeCapability {
} ModeSettings getModeData();
public static class ModeCapability implements IModeCapability { void setModeData(ModeSettings modeSettings);
private ModeSettings modeSettings; }
@Override public static class ModeCapability implements IModeCapability {
public ModeSettings getModeData() { private ModeSettings modeSettings;
return modeSettings;
}
@Override @Override
public void setModeData(ModeSettings modeSettings) { public ModeSettings getModeData() {
this.modeSettings = modeSettings; return modeSettings;
} }
}
public static class Storage implements Capability.IStorage<IModeCapability> { @Override
@Override public void setModeData(ModeSettings modeSettings) {
public INBT writeNBT(Capability<IModeCapability> capability, IModeCapability instance, Direction side) { this.modeSettings = modeSettings;
CompoundNBT compound = new CompoundNBT(); }
ModeSettings modeSettings = instance.getModeData(); }
if (modeSettings == null) modeSettings = new ModeSettings();
//compound.putInteger("buildMode", modeSettings.getBuildMode().ordinal()); public static class Provider extends CapabilityProvider<Provider> implements ICapabilitySerializable<Tag> {
//TODO add mode settings private IModeCapability instance = new ModeCapability();
private LazyOptional<IModeCapability> modeCapabilityOptional = LazyOptional.of(() -> instance);
return compound; public Provider() {
} super(Provider.class);
gatherCapabilities();
}
@Override @Nonnull
public void readNBT(Capability<IModeCapability> capability, IModeCapability instance, Direction side, INBT nbt) { @Override
CompoundNBT compound = (CompoundNBT) nbt; public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
if (cap == MODE_CAPABILITY) return modeCapabilityOptional.cast();
return LazyOptional.empty();
}
//BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.values()[compound.getInteger("buildMode")]; @Override
public void invalidateCaps() {
super.invalidateCaps();
modeCapabilityOptional.invalidate();
}
//TODO add mode settings @Override
public void reviveCaps() {
super.reviveCaps();
modeCapabilityOptional = LazyOptional.of(() -> instance);
}
ModeSettings modeSettings = new ModeSettings(BuildModes.BuildModeEnum.NORMAL); @Override
instance.setModeData(modeSettings); public Tag serializeNBT() {
} CompoundTag compound = new CompoundTag();
} ModeSettings modeSettings = instance.getModeData();
if (modeSettings == null) modeSettings = new ModeSettings();
public static class Provider implements ICapabilitySerializable<INBT> { //compound.putInteger("buildMode", modeSettings.getBuildMode().ordinal());
IModeCapability inst = modeCapability.getDefaultInstance();
@Nonnull //TODO add mode settings
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
return modeCapability.orEmpty(cap, LazyOptional.of(() -> inst));
}
@Override return compound;
public INBT serializeNBT() { }
return modeCapability.getStorage().writeNBT(modeCapability, inst, null);
}
@Override @Override
public void deserializeNBT(INBT nbt) { public void deserializeNBT(Tag nbt) {
modeCapability.getStorage().readNBT(modeCapability, inst, null, nbt); CompoundTag compound = (CompoundTag) nbt;
}
} //BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.values()[compound.getInteger("buildMode")];
// Allows for the capability to persist after death. //TODO add mode settings
@SubscribeEvent
public static void clonePlayer(PlayerEvent.Clone event) { ModeSettings modeSettings = new ModeSettings(BuildModes.BuildModeEnum.DISABLED);
LazyOptional<IModeCapability> original = event.getOriginal().getCapability(modeCapability, null); instance.setModeData(modeSettings);
LazyOptional<IModeCapability> clone = event.getEntity().getCapability(modeCapability, null); }
clone.ifPresent(cloneModeCapability ->
original.ifPresent(originalModeCapability -> }
cloneModeCapability.setModeData(originalModeCapability.getModeData())));
}
} }

View File

@@ -1,13 +1,12 @@
package nl.requios.effortlessbuilding.capability; package nl.requios.effortlessbuilding.capability;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.INBT; import net.minecraft.nbt.Tag;
import net.minecraft.util.Direction; import net.minecraft.core.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.*;
import net.minecraftforge.common.capabilities.CapabilityInject; import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
@@ -19,164 +18,169 @@ import nl.requios.effortlessbuilding.buildmodifier.RadialMirror;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.*; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.ModifierSettings;
@Mod.EventBusSubscriber @Mod.EventBusSubscriber
public class ModifierCapabilityManager { public class ModifierCapabilityManager {
@CapabilityInject(IModifierCapability.class) public final static Capability<IModifierCapability> MODIFIER_CAPABILITY = CapabilityManager.get(new CapabilityToken<>(){});
public final static Capability<IModifierCapability> modifierCapability = null;
public interface IModifierCapability { // Allows for the capability to persist after death.
ModifierSettings getModifierData(); @SubscribeEvent
public static void clonePlayer(PlayerEvent.Clone event) {
LazyOptional<IModifierCapability> original = event.getOriginal().getCapability(MODIFIER_CAPABILITY, null);
LazyOptional<IModifierCapability> clone = event.getEntity().getCapability(MODIFIER_CAPABILITY, null);
clone.ifPresent(cloneModifierCapability ->
original.ifPresent(originalModifierCapability ->
cloneModifierCapability.setModifierData(originalModifierCapability.getModifierData())));
}
void setModifierData(ModifierSettings modifierSettings); public interface IModifierCapability {
} ModifierSettings getModifierData();
public static class ModifierCapability implements IModifierCapability { void setModifierData(ModifierSettings modifierSettings);
private ModifierSettings modifierSettings; }
@Override public static class ModifierCapability implements IModifierCapability {
public ModifierSettings getModifierData() { private ModifierSettings modifierSettings;
return modifierSettings;
}
@Override @Override
public void setModifierData(ModifierSettings modifierSettings) { public ModifierSettings getModifierData() {
this.modifierSettings = modifierSettings; return modifierSettings;
} }
}
public static class Storage implements Capability.IStorage<IModifierCapability> { @Override
@Override public void setModifierData(ModifierSettings modifierSettings) {
public INBT writeNBT(Capability<IModifierCapability> capability, IModifierCapability instance, Direction side) { this.modifierSettings = modifierSettings;
CompoundNBT compound = new CompoundNBT(); }
ModifierSettings modifierSettings = instance.getModifierData(); }
if (modifierSettings == null) modifierSettings = new ModifierSettings();
//MIRROR public static class Provider extends CapabilityProvider<Provider> implements INBTSerializable<Tag> {
Mirror.MirrorSettings m = modifierSettings.getMirrorSettings();
if (m == null) m = new Mirror.MirrorSettings();
compound.putBoolean("mirrorEnabled", m.enabled);
compound.putDouble("mirrorPosX", m.position.x);
compound.putDouble("mirrorPosY", m.position.y);
compound.putDouble("mirrorPosZ", m.position.z);
compound.putBoolean("mirrorX", m.mirrorX);
compound.putBoolean("mirrorY", m.mirrorY);
compound.putBoolean("mirrorZ", m.mirrorZ);
compound.putInt("mirrorRadius", m.radius);
compound.putBoolean("mirrorDrawLines", m.drawLines);
compound.putBoolean("mirrorDrawPlanes", m.drawPlanes);
//ARRAY private final IModifierCapability instance = new ModifierCapability();
Array.ArraySettings a = modifierSettings.getArraySettings(); private LazyOptional<IModifierCapability> modifierCapabilityOptional = LazyOptional.of(() -> instance);
if (a == null) a = new Array.ArraySettings();
compound.putBoolean("arrayEnabled", a.enabled);
compound.putInt("arrayOffsetX", a.offset.getX());
compound.putInt("arrayOffsetY", a.offset.getY());
compound.putInt("arrayOffsetZ", a.offset.getZ());
compound.putInt("arrayCount", a.count);
compound.putInt("reachUpgrade", modifierSettings.getReachUpgrade()); public Provider() {
super(Provider.class);
gatherCapabilities();
}
//compound.putBoolean("quickReplace", buildSettings.doQuickReplace()); dont save quickreplace @Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
if (cap == MODIFIER_CAPABILITY) return modifierCapabilityOptional.cast();
return LazyOptional.empty();
}
//RADIAL MIRROR @Override
RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings(); public void invalidateCaps() {
if (r == null) r = new RadialMirror.RadialMirrorSettings(); super.invalidateCaps();
compound.putBoolean("radialMirrorEnabled", r.enabled); modifierCapabilityOptional.invalidate();
compound.putDouble("radialMirrorPosX", r.position.x); }
compound.putDouble("radialMirrorPosY", r.position.y);
compound.putDouble("radialMirrorPosZ", r.position.z);
compound.putInt("radialMirrorSlices", r.slices);
compound.putBoolean("radialMirrorAlternate", r.alternate);
compound.putInt("radialMirrorRadius", r.radius);
compound.putBoolean("radialMirrorDrawLines", r.drawLines);
compound.putBoolean("radialMirrorDrawPlanes", r.drawPlanes);
return compound; @Override
} public void reviveCaps() {
super.reviveCaps();
modifierCapabilityOptional = LazyOptional.of(() -> instance);
}
@Override @Override
public void readNBT(Capability<IModifierCapability> capability, IModifierCapability instance, Direction side, INBT nbt) { public Tag serializeNBT() {
CompoundNBT compound = (CompoundNBT) nbt; CompoundTag compound = new CompoundTag();
ModifierSettings modifierSettings = instance.getModifierData();
if (modifierSettings == null) modifierSettings = new ModifierSettings();
//MIRROR //MIRROR
boolean mirrorEnabled = compound.getBoolean("mirrorEnabled"); Mirror.MirrorSettings m = modifierSettings.getMirrorSettings();
Vec3d mirrorPosition = new Vec3d( if (m == null) m = new Mirror.MirrorSettings();
compound.getDouble("mirrorPosX"), compound.putBoolean("mirrorEnabled", m.enabled);
compound.getDouble("mirrorPosY"), compound.putDouble("mirrorPosX", m.position.x);
compound.getDouble("mirrorPosZ")); compound.putDouble("mirrorPosY", m.position.y);
boolean mirrorX = compound.getBoolean("mirrorX"); compound.putDouble("mirrorPosZ", m.position.z);
boolean mirrorY = compound.getBoolean("mirrorY"); compound.putBoolean("mirrorX", m.mirrorX);
boolean mirrorZ = compound.getBoolean("mirrorZ"); compound.putBoolean("mirrorY", m.mirrorY);
int mirrorRadius = compound.getInt("mirrorRadius"); compound.putBoolean("mirrorZ", m.mirrorZ);
boolean mirrorDrawLines = compound.getBoolean("mirrorDrawLines"); compound.putInt("mirrorRadius", m.radius);
boolean mirrorDrawPlanes = compound.getBoolean("mirrorDrawPlanes"); compound.putBoolean("mirrorDrawLines", m.drawLines);
Mirror.MirrorSettings mirrorSettings = new Mirror.MirrorSettings(mirrorEnabled, mirrorPosition, mirrorX, mirrorY, mirrorZ, mirrorRadius, mirrorDrawLines, mirrorDrawPlanes); compound.putBoolean("mirrorDrawPlanes", m.drawPlanes);
//ARRAY //ARRAY
boolean arrayEnabled = compound.getBoolean("arrayEnabled"); Array.ArraySettings a = modifierSettings.getArraySettings();
BlockPos arrayOffset = new BlockPos( if (a == null) a = new Array.ArraySettings();
compound.getInt("arrayOffsetX"), compound.putBoolean("arrayEnabled", a.enabled);
compound.getInt("arrayOffsetY"), compound.putInt("arrayOffsetX", a.offset.getX());
compound.getInt("arrayOffsetZ")); compound.putInt("arrayOffsetY", a.offset.getY());
int arrayCount = compound.getInt("arrayCount"); compound.putInt("arrayOffsetZ", a.offset.getZ());
Array.ArraySettings arraySettings = new Array.ArraySettings(arrayEnabled, arrayOffset, arrayCount); compound.putInt("arrayCount", a.count);
int reachUpgrade = compound.getInt("reachUpgrade"); compound.putInt("reachUpgrade", modifierSettings.getReachUpgrade());
//boolean quickReplace = compound.getBoolean("quickReplace"); //dont load quickreplace //compound.putBoolean("quickReplace", buildSettings.doQuickReplace()); dont save quickreplace
//RADIAL MIRROR //RADIAL MIRROR
boolean radialMirrorEnabled = compound.getBoolean("radialMirrorEnabled"); RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings();
Vec3d radialMirrorPosition = new Vec3d( if (r == null) r = new RadialMirror.RadialMirrorSettings();
compound.getDouble("radialMirrorPosX"), compound.putBoolean("radialMirrorEnabled", r.enabled);
compound.getDouble("radialMirrorPosY"), compound.putDouble("radialMirrorPosX", r.position.x);
compound.getDouble("radialMirrorPosZ")); compound.putDouble("radialMirrorPosY", r.position.y);
int radialMirrorSlices = compound.getInt("radialMirrorSlices"); compound.putDouble("radialMirrorPosZ", r.position.z);
boolean radialMirrorAlternate = compound.getBoolean("radialMirrorAlternate"); compound.putInt("radialMirrorSlices", r.slices);
int radialMirrorRadius = compound.getInt("radialMirrorRadius"); compound.putBoolean("radialMirrorAlternate", r.alternate);
boolean radialMirrorDrawLines = compound.getBoolean("radialMirrorDrawLines"); compound.putInt("radialMirrorRadius", r.radius);
boolean radialMirrorDrawPlanes = compound.getBoolean("radialMirrorDrawPlanes"); compound.putBoolean("radialMirrorDrawLines", r.drawLines);
RadialMirror.RadialMirrorSettings radialMirrorSettings = new RadialMirror.RadialMirrorSettings(radialMirrorEnabled, radialMirrorPosition, compound.putBoolean("radialMirrorDrawPlanes", r.drawPlanes);
radialMirrorSlices, radialMirrorAlternate, radialMirrorRadius, radialMirrorDrawLines, radialMirrorDrawPlanes);
ModifierSettings modifierSettings = new ModifierSettings(mirrorSettings, arraySettings, radialMirrorSettings, false, reachUpgrade); return compound;
instance.setModifierData(modifierSettings); }
}
}
public static class Provider implements ICapabilitySerializable<INBT> { @Override
public void deserializeNBT(Tag nbt) {
CompoundTag compound = (CompoundTag) nbt;
IModifierCapability inst = modifierCapability.getDefaultInstance(); //MIRROR
boolean mirrorEnabled = compound.getBoolean("mirrorEnabled");
Vec3 mirrorPosition = new Vec3(
compound.getDouble("mirrorPosX"),
compound.getDouble("mirrorPosY"),
compound.getDouble("mirrorPosZ"));
boolean mirrorX = compound.getBoolean("mirrorX");
boolean mirrorY = compound.getBoolean("mirrorY");
boolean mirrorZ = compound.getBoolean("mirrorZ");
int mirrorRadius = compound.getInt("mirrorRadius");
boolean mirrorDrawLines = compound.getBoolean("mirrorDrawLines");
boolean mirrorDrawPlanes = compound.getBoolean("mirrorDrawPlanes");
Mirror.MirrorSettings mirrorSettings = new Mirror.MirrorSettings(mirrorEnabled, mirrorPosition, mirrorX, mirrorY, mirrorZ, mirrorRadius, mirrorDrawLines, mirrorDrawPlanes);
@Nonnull //ARRAY
@Override boolean arrayEnabled = compound.getBoolean("arrayEnabled");
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { BlockPos arrayOffset = new BlockPos(
return modifierCapability.orEmpty(cap, LazyOptional.of(() -> inst)); compound.getInt("arrayOffsetX"),
} compound.getInt("arrayOffsetY"),
compound.getInt("arrayOffsetZ"));
int arrayCount = compound.getInt("arrayCount");
Array.ArraySettings arraySettings = new Array.ArraySettings(arrayEnabled, arrayOffset, arrayCount);
@Override int reachUpgrade = compound.getInt("reachUpgrade");
public INBT serializeNBT() {
return modifierCapability.getStorage().writeNBT(modifierCapability, inst, null);
}
@Override //boolean quickReplace = compound.getBoolean("quickReplace"); //dont load quickreplace
public void deserializeNBT(INBT nbt) {
modifierCapability.getStorage().readNBT(modifierCapability, inst, null, nbt);
}
} //RADIAL MIRROR
boolean radialMirrorEnabled = compound.getBoolean("radialMirrorEnabled");
Vec3 radialMirrorPosition = new Vec3(
compound.getDouble("radialMirrorPosX"),
compound.getDouble("radialMirrorPosY"),
compound.getDouble("radialMirrorPosZ"));
int radialMirrorSlices = compound.getInt("radialMirrorSlices");
boolean radialMirrorAlternate = compound.getBoolean("radialMirrorAlternate");
int radialMirrorRadius = compound.getInt("radialMirrorRadius");
boolean radialMirrorDrawLines = compound.getBoolean("radialMirrorDrawLines");
boolean radialMirrorDrawPlanes = compound.getBoolean("radialMirrorDrawPlanes");
RadialMirror.RadialMirrorSettings radialMirrorSettings = new RadialMirror.RadialMirrorSettings(radialMirrorEnabled, radialMirrorPosition,
radialMirrorSlices, radialMirrorAlternate, radialMirrorRadius, radialMirrorDrawLines, radialMirrorDrawPlanes);
ModifierSettings modifierSettings = new ModifierSettings(mirrorSettings, arraySettings, radialMirrorSettings, false, reachUpgrade);
instance.setModifierData(modifierSettings);
}
// Allows for the capability to persist after death. }
@SubscribeEvent
public static void clonePlayer(PlayerEvent.Clone event) {
LazyOptional<IModifierCapability> original = event.getOriginal().getCapability(modifierCapability, null);
LazyOptional<IModifierCapability> clone = event.getEntity().getCapability(modifierCapability, null);
clone.ifPresent(cloneModifierCapability ->
original.ifPresent(originalModifierCapability ->
cloneModifierCapability.setModifierData(originalModifierCapability.getModifierData())));
}
} }

View File

@@ -1,43 +0,0 @@
package nl.requios.effortlessbuilding.command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import net.minecraft.command.CommandSource;
import net.minecraft.command.Commands;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.util.text.StringTextComponent;
import net.minecraftforge.fml.network.PacketDistributor;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.network.ModifierSettingsMessage;
import nl.requios.effortlessbuilding.network.PacketHandler;
public class CommandReach {
public static void register(CommandDispatcher<CommandSource> dispatcher) {
dispatcher.register(Commands.literal("reach").then(Commands.literal("set").then(Commands.argument("level", IntegerArgumentType.integer(0, 3)).executes((context) -> {
return setReachLevel(context.getSource().asPlayer(), IntegerArgumentType.getInteger(context, "level"));
}))).then(Commands.literal("get").executes((context -> {
return getReachLevel(context.getSource().asPlayer());
}))));
}
private static int setReachLevel(ServerPlayerEntity player, int level){
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
modifierSettings.setReachUpgrade(level);
ModifierSettingsManager.setModifierSettings(player, modifierSettings);
//Send to client
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new ModifierSettingsMessage(modifierSettings));
player.sendMessage(new StringTextComponent("Reach level of " + player.getName().getString() + " set to " + modifierSettings.getReachUpgrade()));
return 1;
}
private static int getReachLevel(ServerPlayerEntity player){
int reachUpgrade = ModifierSettingsManager.getModifierSettings(player).getReachUpgrade();
EffortlessBuilding.log(player, "Current reach: level "+reachUpgrade);
return 1;
}
}

View File

@@ -1,132 +1,63 @@
package nl.requios.effortlessbuilding.compatibility; package nl.requios.effortlessbuilding.compatibility;
import net.minecraft.block.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.item.BlockItem;
import net.minecraft.item.BlockItem; import net.minecraft.world.item.Item;
import net.minecraft.item.Item; import net.minecraft.world.item.ItemStack;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem;
import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
public class CompatHelper { public class CompatHelper {
//TODO 1.13 compatibility
// // Get a handle to the dank null item instance. This will remain null if the mod doesn't load
// // and all checks will fail, so it works.
// @GameRegistry.ObjectHolder("danknull:dank_null")
// public static final Item dankNullItem = null;
//
// public static IChiselsAndBitsProxy chiselsAndBitsProxy;
//
public static void setup() {
//TODO 1.13 compatibility
// if (Loader.isModLoaded("chiselsandbits")) {
// // reflection to avoid hard dependency
// try {
// chiselsAndBitsProxy = Class.forName("nl.requios.effortlessbuilding.compatibility.ActiveChiselsAndBitsProxy").asSubclass(ActiveChiselsAndBitsProxy.class).newInstance();
// } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// e.printStackTrace();
// }
// } else {
// chiselsAndBitsProxy = new DummyChiselsAndBitsProxy();
// }
}
// Check if the item given is a proxy for blocks. For now, we check for the randomizer bag, public static void setup() {
// /dank/null, or plain old blocks.
public static boolean isItemBlockProxy(ItemStack stack) {
Item item = stack.getItem();
if (item instanceof BlockItem)
return true;
if ((item instanceof ItemRandomizerBag))
return true;
//TODO 1.13 compatibility
// if (item == dankNullItem)
// return true;
return false;
}
// Get the block to be placed by this proxy. For the /dank/null, it's the slot stack }
// pointed to by nbt integer selectedIndex.
public static ItemStack getItemBlockFromStack(ItemStack proxy) {
Item proxyItem = proxy.getItem();
if (proxyItem instanceof BlockItem) // Check if the item given is a proxy for blocks. For now, we check for the randomizer bag,
return proxy; // /dank/null, or plain old blocks.
public static boolean isItemBlockProxy(ItemStack stack) {
Item item = stack.getItem();
if (item instanceof BlockItem)
return true;
return item instanceof AbstractRandomizerBagItem;
}
//Randomizer Bag // Get the block to be placed by this proxy. For the /dank/null, it's the slot stack
if (proxyItem instanceof ItemRandomizerBag) { // pointed to by nbt integer selectedIndex.
ItemStack itemStack = proxy; public static ItemStack getItemBlockFromStack(ItemStack proxy) {
while (!(itemStack.getItem() instanceof BlockItem || itemStack.isEmpty())) { Item proxyItem = proxy.getItem();
if (itemStack.getItem() instanceof ItemRandomizerBag)
itemStack = ItemRandomizerBag.pickRandomStack(ItemRandomizerBag.getBagInventory(itemStack));
}
return itemStack;
}
//TODO 1.13 compatibility if (proxyItem instanceof BlockItem)
//Dank Null return proxy;
// if (proxyItem == dankNullItem) {
// int index = 0;
// if (proxy.hasTagCompound() && proxy.getTagCompound().hasKey("selectedIndex"))
// index = proxy.getTagCompound().getInteger("selectedIndex");
// return proxy.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null).getStackInSlot(index);
// }
return ItemStack.EMPTY; //Randomizer Bag
} if (proxyItem instanceof AbstractRandomizerBagItem) {
ItemStack itemStack = proxy;
while (!(itemStack.getItem() instanceof BlockItem || itemStack.isEmpty())) {
if (itemStack.getItem() instanceof AbstractRandomizerBagItem) {
AbstractRandomizerBagItem randomizerBagItem = (AbstractRandomizerBagItem) itemStack.getItem();
itemStack = randomizerBagItem.pickRandomStack(randomizerBagItem.getBagInventory(itemStack));
}
}
return itemStack;
}
public static ItemStack getItemBlockByState(ItemStack stack, BlockState state) { return ItemStack.EMPTY;
if (state == null) return ItemStack.EMPTY; }
Item blockItem = Item.getItemFromBlock(state.getBlock()); public static ItemStack getItemBlockByState(ItemStack stack, BlockState state) {
if (stack.getItem() instanceof BlockItem) if (state == null) return ItemStack.EMPTY;
return stack;
else if (stack.getItem() instanceof ItemRandomizerBag) {
IItemHandler bagInventory = ItemRandomizerBag.getBagInventory(stack);
return ItemRandomizerBag.findStack(bagInventory, blockItem);
}
//TODO 1.13 compatibility
// else if (stack.getItem() == dankNullItem) {
// int index = itemHandlerSlotForItem(stack, blockItem);
// if (index >= 0)
// return stack.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null).getStackInSlot(index);
// }
return ItemStack.EMPTY;
}
// Handle IItemHandler slot stacks not being modifiable. We must call IItemHandler#extractItem, Item blockItem = Item.byBlock(state.getBlock());
// because the ItemStack returned by IItemHandler#getStackInSlot isn't modifiable. if (stack.getItem() instanceof BlockItem)
public static void shrinkStack(ItemStack origStack, ItemStack curStack, PlayerEntity player) { return stack;
//TODO 1.13 compatibility, offhand support else if (stack.getItem() instanceof AbstractRandomizerBagItem) {
//Hacky way to get the origstack, because given origStack is itemblock stack and never proxy AbstractRandomizerBagItem randomizerBagItem = (AbstractRandomizerBagItem) stack.getItem();
// origStack = player.getHeldItem(EnumHand.MAIN_HAND); IItemHandler bagInventory = randomizerBagItem.getBagInventory(stack);
return randomizerBagItem.findStack(bagInventory, blockItem);
}
// if (origStack.getItem() == dankNullItem) { return ItemStack.EMPTY;
// int index = itemHandlerSlotForItem(origStack, curStack.getItem()); }
// origStack.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null).extractItem(index, 1, false);
// } else
curStack.shrink(1);
}
private static int itemHandlerSlotForItem(ItemStack stack, Item blockItem) {
LazyOptional<IItemHandler> itemHandlerLazyOptional = stack.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
IItemHandler handler = itemHandlerLazyOptional.orElse(null);
if (handler == null) {
EffortlessBuilding.logger.warn("Itemblock proxy has no item handler capability!");
return -1;
}
for (int i = 0; i < handler.getSlots(); i++) {
ItemStack ref = handler.getStackInSlot(i);
if (ref.getItem() instanceof BlockItem)
if (ref.getItem() == blockItem)
return i;
}
return -1;
}
} }

View File

@@ -0,0 +1,33 @@
package nl.requios.effortlessbuilding.create;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.resources.ResourceLocation;
public enum AllSpecialTextures {
BLANK("blank.png"),
CHECKERED("checkerboard.png"),
THIN_CHECKERED("thin_checkerboard.png"),
CUTOUT_CHECKERED("cutout_checkerboard.png"),
HIGHLIGHT_CHECKERED("highlighted_checkerboard.png"),
SELECTION("selection.png"),
GLUE("glue.png"),
;
public static final String ASSET_PATH = "textures/special/";
private ResourceLocation location;
private AllSpecialTextures(String filename) {
location = Create.asResource(ASSET_PATH + filename);
}
public void bind() {
RenderSystem.setShaderTexture(0, location);
}
public ResourceLocation getLocation() {
return location;
}
}

View File

@@ -0,0 +1,16 @@
package nl.requios.effortlessbuilding.create;
import com.mojang.logging.LogUtils;
import net.minecraft.resources.ResourceLocation;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import org.slf4j.Logger;
public class Create {
public static final String ID = EffortlessBuilding.MODID;
public static final Logger LOGGER = LogUtils.getLogger();
public static ResourceLocation asResource(String path) {
return new ResourceLocation(EffortlessBuilding.MODID, path);
}
}

View File

@@ -0,0 +1,15 @@
package nl.requios.effortlessbuilding.create;
import nl.requios.effortlessbuilding.create.foundation.render.SuperByteBufferCache;
import nl.requios.effortlessbuilding.create.foundation.utility.ghost.GhostBlocks;
import nl.requios.effortlessbuilding.create.foundation.utility.outliner.Outliner;
public class CreateClient {
public static final SuperByteBufferCache BUFFER_CACHE = new SuperByteBufferCache();
public static final Outliner OUTLINER = new Outliner();
public static final GhostBlocks GHOST_BLOCKS = new GhostBlocks();
public static void invalidateRenderers() {
CreateClient.BUFFER_CACHE.invalidate();
}
}

View File

@@ -0,0 +1,31 @@
package nl.requios.effortlessbuilding.create;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.phys.AABB;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import nl.requios.effortlessbuilding.create.foundation.utility.Color;
@Mod.EventBusSubscriber(Dist.CLIENT)
public class CreateClientTest {
// @SubscribeEvent
// public static void onTick(TickEvent.ClientTickEvent event) {
// CreateClient.GHOST_BLOCKS.showGhostState(1, Blocks.SPRUCE_LOG.defaultBlockState())
// .at(0, 120, 0)
// .breathingAlpha();
// CreateClient.GHOST_BLOCKS.showGhostState(2, Blocks.SPRUCE_LOG.defaultBlockState())
// .at(1, 120, 0)
// .breathingAlpha();
//
// CreateClient.OUTLINER.showAABB(1, new AABB(0, 0, 0, 10, 2, 6)
// .move(10, 120, 0))
// .withFaceTexture(AllSpecialTextures.CHECKERED)
// .colored(new Color(0.11f, 0.49f, 0.7f, 1f))
//// .colored(0xbfbfbf)
// .disableNormals()
// .lineWidth(1 / 32f);
// }
}

View File

@@ -0,0 +1,96 @@
package nl.requios.effortlessbuilding.create.events;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RenderLevelLastEvent;
import net.minecraftforge.client.event.ViewportEvent;
import net.minecraftforge.event.TickEvent.ClientTickEvent;
import net.minecraftforge.event.level.LevelEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import nl.requios.effortlessbuilding.create.Create;
import nl.requios.effortlessbuilding.create.CreateClient;
import nl.requios.effortlessbuilding.create.foundation.render.SuperRenderTypeBuffer;
import nl.requios.effortlessbuilding.create.foundation.utility.AnimationTickHolder;
import nl.requios.effortlessbuilding.create.foundation.utility.CameraAngleAnimationService;
import nl.requios.effortlessbuilding.create.foundation.utility.worldWrappers.WrappedClientWorld;
@EventBusSubscriber(Dist.CLIENT)
public class ClientEvents {
private static final String ITEM_PREFIX = "item." + Create.ID;
private static final String BLOCK_PREFIX = "block." + Create.ID;
@SubscribeEvent
public static void onTick(ClientTickEvent event) {
if (!isGameActive())
return;
Level world = Minecraft.getInstance().level;
AnimationTickHolder.tick();
CreateClient.GHOST_BLOCKS.tickGhosts();
CreateClient.OUTLINER.tickOutlines();
CameraAngleAnimationService.tick();
}
@SubscribeEvent
public static void onLoadWorld(LevelEvent.Load event) {
LevelAccessor world = event.getLevel();
if (world.isClientSide() && world instanceof ClientLevel && !(world instanceof WrappedClientWorld)) {
CreateClient.invalidateRenderers();
AnimationTickHolder.reset();
}
}
@SubscribeEvent
public static void onUnloadWorld(LevelEvent.Unload event) {
if (!event.getLevel()
.isClientSide())
return;
CreateClient.invalidateRenderers();
AnimationTickHolder.reset();
}
@SubscribeEvent
public static void onRenderWorld(RenderLevelLastEvent event) {
Vec3 cameraPos = Minecraft.getInstance().gameRenderer.getMainCamera()
.getPosition();
float pt = AnimationTickHolder.getPartialTicks();
PoseStack ms = event.getPoseStack();
ms.pushPose();
ms.translate(-cameraPos.x(), -cameraPos.y(), -cameraPos.z());
SuperRenderTypeBuffer buffer = SuperRenderTypeBuffer.getInstance();
CreateClient.GHOST_BLOCKS.renderAll(ms, buffer);
CreateClient.OUTLINER.renderOutlines(ms, buffer, pt);
buffer.draw();
RenderSystem.enableCull();
ms.popPose();
}
@SubscribeEvent
public static void onCameraSetup(ViewportEvent.ComputeCameraAngles event) {
float partialTicks = AnimationTickHolder.getPartialTicks();
if (CameraAngleAnimationService.isYawAnimating())
event.setYaw(CameraAngleAnimationService.getYaw(partialTicks));
if (CameraAngleAnimationService.isPitchAnimating())
event.setPitch(CameraAngleAnimationService.getPitch(partialTicks));
}
public static boolean isGameActive() {
return !(Minecraft.getInstance().level == null || Minecraft.getInstance().player == null);
}
}

View File

@@ -0,0 +1,39 @@
package nl.requios.effortlessbuilding.create.events;
import net.minecraft.world.level.LevelAccessor;
import net.minecraftforge.event.level.LevelEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import nl.requios.effortlessbuilding.create.foundation.utility.WorldAttached;
@EventBusSubscriber
public class CommonEvents {
@SubscribeEvent
public static void onUnloadWorld(LevelEvent.Unload event) {
LevelAccessor world = event.getLevel();
WorldAttached.invalidateWorld(world);
}
@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD)
public static class ModBusEvents {
// @SubscribeEvent
// public static void addPackFinders(AddPackFindersEvent event) {
// if (event.getPackType() == PackType.CLIENT_RESOURCES) {
// IModFileInfo modFileInfo = ModList.get().getModFileById(Create.ID);
// if (modFileInfo == null) {
// Create.LOGGER.error("Could not find Create mod file info; built-in resource packs will be missing!");
// return;
// }
// IModFile modFile = modFileInfo.getFile();
// event.addRepositorySource((consumer, constructor) -> {
// consumer.accept(Pack.create(Create.asResource("legacy_copper").toString(), false, () -> new ModFilePackResources("Create Legacy Copper", modFile, "resourcepacks/legacy_copper"), constructor, Pack.Position.TOP, PackSource.DEFAULT));
// });
// }
// }
}
}

View File

@@ -0,0 +1,16 @@
package nl.requios.effortlessbuilding.create.foundation;
import nl.requios.effortlessbuilding.create.foundation.utility.LangNumberFormat;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
public class ClientResourceReloadListener implements ResourceManagerReloadListener {
@Override
public void onResourceManagerReload(ResourceManager resourceManager) {
// CreateClient.invalidateRenderers();
// SoundScapes.invalidateAll();
LangNumberFormat.numberFormat.update();
}
}

View File

@@ -0,0 +1,25 @@
package nl.requios.effortlessbuilding.create.foundation;
import net.minecraftforge.forgespi.locating.IModFile;
import net.minecraftforge.resource.PathPackResources;
import java.nio.file.Path;
public class ModFilePackResources extends PathPackResources {
protected final IModFile modFile;
protected final String sourcePath;
public ModFilePackResources(String name, IModFile modFile, String sourcePath) {
super(name, modFile.findResource(sourcePath));
this.modFile = modFile;
this.sourcePath = sourcePath;
}
@Override
protected Path resolve(String... paths) {
String[] allPaths = new String[paths.length + 1];
allPaths[0] = sourcePath;
System.arraycopy(paths, 0, allPaths, 1, paths.length);
return modFile.findResource(allPaths);
}
}

View File

@@ -0,0 +1,49 @@
package nl.requios.effortlessbuilding.create.foundation.block.render;
import com.jozufozu.flywheel.core.StitchedSprite;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.resources.ResourceLocation;
public class SpriteShiftEntry {
protected StitchedSprite original;
protected StitchedSprite target;
public void set(ResourceLocation originalTextureLocation, ResourceLocation targetTextureLocation) {
original = new StitchedSprite(originalTextureLocation);
target = new StitchedSprite(targetTextureLocation);
}
public ResourceLocation getOriginalResourceLocation() {
return original.getLocation();
}
public ResourceLocation getTargetResourceLocation() {
return target.getLocation();
}
public TextureAtlasSprite getOriginal() {
return original.get();
}
public TextureAtlasSprite getTarget() {
return target.get();
}
public float getTargetU(float localU) {
return getTarget().getU(getUnInterpolatedU(getOriginal(), localU));
}
public float getTargetV(float localV) {
return getTarget().getV(getUnInterpolatedV(getOriginal(), localV));
}
public static float getUnInterpolatedU(TextureAtlasSprite sprite, float u) {
float f = sprite.getU1() - sprite.getU0();
return (u - sprite.getU0()) / f * 16.0F;
}
public static float getUnInterpolatedV(TextureAtlasSprite sprite, float v) {
float f = sprite.getV1() - sprite.getV0();
return (v - sprite.getV0()) / f * 16.0F;
}
}

View File

@@ -0,0 +1,29 @@
package nl.requios.effortlessbuilding.create.foundation.render;
import com.jozufozu.flywheel.core.model.ModelUtil;
import com.jozufozu.flywheel.util.Pair;
import com.mojang.blaze3d.vertex.BufferBuilder.RenderedBuffer;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.world.level.block.state.BlockState;
public class BakedModelRenderHelper {
public static SuperByteBuffer standardBlockRender(BlockState renderedState) {
BlockRenderDispatcher dispatcher = Minecraft.getInstance()
.getBlockRenderer();
return standardModelRender(dispatcher.getBlockModel(renderedState), renderedState);
}
public static SuperByteBuffer standardModelRender(BakedModel model, BlockState referenceState) {
return standardModelRender(model, referenceState, new PoseStack());
}
public static SuperByteBuffer standardModelRender(BakedModel model, BlockState referenceState, PoseStack ms) {
Pair<RenderedBuffer, Integer> pair = ModelUtil.getBufferBuilder(model, referenceState, ms);
return new SuperByteBuffer(pair.first(), pair.second());
}
}

View File

@@ -0,0 +1,88 @@
package nl.requios.effortlessbuilding.create.foundation.render;
import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
import nl.requios.effortlessbuilding.create.CreateClient;
import nl.requios.effortlessbuilding.create.foundation.render.SuperByteBufferCache.Compartment;
import nl.requios.effortlessbuilding.create.foundation.utility.AngleHelper;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockState;
import org.apache.commons.lang3.tuple.Pair;
import java.util.function.Supplier;
import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING;
public class CachedBufferer {
public static final Compartment<BlockState> GENERIC_TILE = new Compartment<>();
public static final Compartment<PartialModel> PARTIAL = new Compartment<>();
public static final Compartment<Pair<Direction, PartialModel>> DIRECTIONAL_PARTIAL = new Compartment<>();
public static SuperByteBuffer block(BlockState toRender) {
return block(GENERIC_TILE, toRender);
}
public static SuperByteBuffer block(Compartment<BlockState> compartment, BlockState toRender) {
return CreateClient.BUFFER_CACHE.get(compartment, toRender, () -> BakedModelRenderHelper.standardBlockRender(toRender));
}
public static SuperByteBuffer partial(PartialModel partial, BlockState referenceState) {
return CreateClient.BUFFER_CACHE.get(PARTIAL, partial,
() -> BakedModelRenderHelper.standardModelRender(partial.get(), referenceState));
}
public static SuperByteBuffer partial(PartialModel partial, BlockState referenceState,
Supplier<PoseStack> modelTransform) {
return CreateClient.BUFFER_CACHE.get(PARTIAL, partial,
() -> BakedModelRenderHelper.standardModelRender(partial.get(), referenceState, modelTransform.get()));
}
public static SuperByteBuffer partialFacing(PartialModel partial, BlockState referenceState) {
Direction facing = referenceState.getValue(FACING);
return partialFacing(partial, referenceState, facing);
}
public static SuperByteBuffer partialFacing(PartialModel partial, BlockState referenceState, Direction facing) {
return partialDirectional(partial, referenceState, facing,
rotateToFace(facing));
}
public static SuperByteBuffer partialFacingVertical(PartialModel partial, BlockState referenceState, Direction facing) {
return partialDirectional(partial, referenceState, facing,
rotateToFaceVertical(facing));
}
public static SuperByteBuffer partialDirectional(PartialModel partial, BlockState referenceState, Direction dir,
Supplier<PoseStack> modelTransform) {
return CreateClient.BUFFER_CACHE.get(DIRECTIONAL_PARTIAL, Pair.of(dir, partial),
() -> BakedModelRenderHelper.standardModelRender(partial.get(), referenceState, modelTransform.get()));
}
public static Supplier<PoseStack> rotateToFace(Direction facing) {
return () -> {
PoseStack stack = new PoseStack();
TransformStack.cast(stack)
.centre()
.rotateY(AngleHelper.horizontalAngle(facing))
.rotateX(AngleHelper.verticalAngle(facing))
.unCentre();
return stack;
};
}
public static Supplier<PoseStack> rotateToFaceVertical(Direction facing) {
return () -> {
PoseStack stack = new PoseStack();
TransformStack.cast(stack)
.centre()
.rotateY(AngleHelper.horizontalAngle(facing))
.rotateX(AngleHelper.verticalAngle(facing) + 90)
.unCentre();
return stack;
};
}
}

View File

@@ -0,0 +1,30 @@
package nl.requios.effortlessbuilding.create.foundation.render;
import com.jozufozu.flywheel.util.DiffuseLightCalculator;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import javax.annotation.Nullable;
public final class ForcedDiffuseState {
private static final ThreadLocal<ObjectArrayList<DiffuseLightCalculator>> FORCED_DIFFUSE = ThreadLocal.withInitial(ObjectArrayList::new);
private ForcedDiffuseState() {
}
public static void pushCalculator(DiffuseLightCalculator calculator) {
FORCED_DIFFUSE.get().push(calculator);
}
public static void popCalculator() {
FORCED_DIFFUSE.get().pop();
}
@Nullable
public static DiffuseLightCalculator getForcedCalculator() {
ObjectArrayList<DiffuseLightCalculator> stack = FORCED_DIFFUSE.get();
if (stack.isEmpty()) {
return null;
}
return stack.top();
}
}

View File

@@ -0,0 +1,160 @@
package nl.requios.effortlessbuilding.create.foundation.render;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat;
import nl.requios.effortlessbuilding.create.AllSpecialTextures;
import nl.requios.effortlessbuilding.create.Create;
import net.minecraft.client.renderer.RenderStateShard;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RegisterShadersEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import java.io.IOException;
// TODO 1.17: use custom shaders instead of vanilla ones
public class RenderTypes extends RenderStateShard {
public static final ShaderStateShard GLOWING_SHADER = new ShaderStateShard(() -> Shaders.glowingShader);
private static final RenderType OUTLINE_SOLID =
RenderType.create(createLayerName("outline_solid"), DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, false,
false, RenderType.CompositeState.builder()
.setShaderState(RENDERTYPE_ENTITY_SOLID_SHADER)
.setTextureState(new TextureStateShard(AllSpecialTextures.BLANK.getLocation(), false, false))
.setCullState(CULL)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(false));
public static RenderType getOutlineSolid() {
return OUTLINE_SOLID;
}
public static RenderType getOutlineTranslucent(ResourceLocation texture, boolean cull) {
return RenderType.create(createLayerName("outline_translucent" + (cull ? "_cull" : "")),
DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, false, true, RenderType.CompositeState.builder()
.setShaderState(cull ? RENDERTYPE_ENTITY_TRANSLUCENT_CULL_SHADER : RENDERTYPE_ENTITY_TRANSLUCENT_SHADER)
.setTextureState(new TextureStateShard(texture, false, false))
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setCullState(cull ? CULL : NO_CULL)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.setWriteMaskState(COLOR_WRITE)
.createCompositeState(false));
}
public static RenderType getGlowingSolid(ResourceLocation texture) {
return RenderType.create(createLayerName("glowing_solid"), DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256,
true, false, RenderType.CompositeState.builder()
.setShaderState(GLOWING_SHADER)
.setTextureState(new TextureStateShard(texture, false, false))
.setCullState(CULL)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
}
private static final RenderType GLOWING_SOLID_DEFAULT = getGlowingSolid(InventoryMenu.BLOCK_ATLAS);
public static RenderType getGlowingSolid() {
return GLOWING_SOLID_DEFAULT;
}
public static RenderType getGlowingTranslucent(ResourceLocation texture) {
return RenderType.create(createLayerName("glowing_translucent"), DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS,
256, true, true, RenderType.CompositeState.builder()
.setShaderState(GLOWING_SHADER)
.setTextureState(new TextureStateShard(texture, false, false))
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
}
private static final RenderType ADDITIVE = RenderType.create(createLayerName("additive"), DefaultVertexFormat.BLOCK,
VertexFormat.Mode.QUADS, 256, true, true, RenderType.CompositeState.builder()
.setShaderState(BLOCK_SHADER)
.setTextureState(new TextureStateShard(InventoryMenu.BLOCK_ATLAS, false, false))
.setTransparencyState(ADDITIVE_TRANSPARENCY)
.setCullState(NO_CULL)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
public static RenderType getAdditive() {
return ADDITIVE;
}
private static final RenderType GLOWING_TRANSLUCENT_DEFAULT = getGlowingTranslucent(InventoryMenu.BLOCK_ATLAS);
public static RenderType getGlowingTranslucent() {
return GLOWING_TRANSLUCENT_DEFAULT;
}
private static final RenderType ITEM_PARTIAL_SOLID =
RenderType.create(createLayerName("item_partial_solid"), DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, true,
false, RenderType.CompositeState.builder()
.setShaderState(RENDERTYPE_ENTITY_SOLID_SHADER)
.setTextureState(BLOCK_SHEET)
.setCullState(CULL)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
public static RenderType getItemPartialSolid() {
return ITEM_PARTIAL_SOLID;
}
private static final RenderType ITEM_PARTIAL_TRANSLUCENT = RenderType.create(createLayerName("item_partial_translucent"),
DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, true, true, RenderType.CompositeState.builder()
.setShaderState(RENDERTYPE_ENTITY_TRANSLUCENT_CULL_SHADER)
.setTextureState(BLOCK_SHEET)
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
public static RenderType getItemPartialTranslucent() {
return ITEM_PARTIAL_TRANSLUCENT;
}
private static final RenderType FLUID = RenderType.create(createLayerName("fluid"),
DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, false, true, RenderType.CompositeState.builder()
.setShaderState(RENDERTYPE_ENTITY_TRANSLUCENT_CULL_SHADER)
.setTextureState(BLOCK_SHEET_MIPPED)
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
public static RenderType getFluid() {
return FLUID;
}
private static String createLayerName(String name) {
return Create.ID + ":" + name;
}
// Mmm gimme those protected fields
private RenderTypes() {
super(null, null, null);
}
@EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD)
private static class Shaders {
private static ShaderInstance glowingShader;
@SubscribeEvent
public static void onRegisterShaders(RegisterShadersEvent event) throws IOException {
ResourceManager resourceManager = event.getResourceManager();
event.registerShader(new ShaderInstance(resourceManager, Create.asResource("glowing_shader"), DefaultVertexFormat.NEW_ENTITY), shader -> glowingShader = shader);
}
}
}

View File

@@ -0,0 +1,112 @@
package nl.requios.effortlessbuilding.create.foundation.render;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape;
/**
* Taken from EntityRendererManager
*/
public class ShadowRenderHelper {
private static final RenderType SHADOW_LAYER =
RenderType.entityNoOutline(new ResourceLocation("textures/misc/shadow.png"));
public static void renderShadow(PoseStack matrixStack, MultiBufferSource buffer, float opacity, float radius) {
PoseStack.Pose entry = matrixStack.last();
VertexConsumer builder = buffer.getBuffer(SHADOW_LAYER);
opacity /= 2;
shadowVertex(entry, builder, opacity, -1 * radius, 0, -1 * radius, 0, 0);
shadowVertex(entry, builder, opacity, -1 * radius, 0, 1 * radius, 0, 1);
shadowVertex(entry, builder, opacity, 1 * radius, 0, 1 * radius, 1, 1);
shadowVertex(entry, builder, opacity, 1 * radius, 0, -1 * radius, 1, 0);
}
public static void renderShadow(PoseStack matrixStack, MultiBufferSource buffer, LevelReader world,
Vec3 pos, float opacity, float radius) {
float f = radius;
double d2 = pos.x();
double d0 = pos.y();
double d1 = pos.z();
int i = Mth.floor(d2 - (double) f);
int j = Mth.floor(d2 + (double) f);
int k = Mth.floor(d0 - (double) f);
int l = Mth.floor(d0);
int i1 = Mth.floor(d1 - (double) f);
int j1 = Mth.floor(d1 + (double) f);
PoseStack.Pose entry = matrixStack.last();
VertexConsumer builder = buffer.getBuffer(SHADOW_LAYER);
for (BlockPos blockpos : BlockPos.betweenClosed(new BlockPos(i, k, i1), new BlockPos(j, l, j1))) {
renderBlockShadow(entry, builder, world, blockpos, d2, d0, d1, f,
opacity);
}
}
private static void renderBlockShadow(PoseStack.Pose entry, VertexConsumer builder,
LevelReader world, BlockPos pos, double x, double y, double z,
float radius, float opacity) {
BlockPos blockpos = pos.below();
BlockState blockstate = world.getBlockState(blockpos);
if (blockstate.getRenderShape() != RenderShape.INVISIBLE && world.getMaxLocalRawBrightness(pos) > 3) {
if (blockstate.isCollisionShapeFullBlock(world, blockpos)) {
VoxelShape voxelshape = blockstate.getShape(world, pos.below());
if (!voxelshape.isEmpty()) {
float brightness = LightTexture.getBrightness(world.dimensionType(), world.getMaxLocalRawBrightness(pos));
float f = (float) ((opacity - (y - pos.getY()) / 2.0D) * 0.5D * brightness);
if (f >= 0.0F) {
if (f > 1.0F) {
f = 1.0F;
}
AABB AABB = voxelshape.bounds();
double d0 = (double) pos.getX() + AABB.minX;
double d1 = (double) pos.getX() + AABB.maxX;
double d2 = (double) pos.getY() + AABB.minY;
double d3 = (double) pos.getZ() + AABB.minZ;
double d4 = (double) pos.getZ() + AABB.maxZ;
float f1 = (float) (d0 - x);
float f2 = (float) (d1 - x);
float f3 = (float) (d2 - y + 0.015625D);
float f4 = (float) (d3 - z);
float f5 = (float) (d4 - z);
float f6 = -f1 / 2.0F / radius + 0.5F;
float f7 = -f2 / 2.0F / radius + 0.5F;
float f8 = -f4 / 2.0F / radius + 0.5F;
float f9 = -f5 / 2.0F / radius + 0.5F;
shadowVertex(entry, builder, f, f1, f3, f4, f6, f8);
shadowVertex(entry, builder, f, f1, f3, f5, f6, f9);
shadowVertex(entry, builder, f, f2, f3, f5, f7, f9);
shadowVertex(entry, builder, f, f2, f3, f4, f7, f8);
}
}
}
}
}
private static void shadowVertex(PoseStack.Pose entry, VertexConsumer builder, float alpha,
float x, float y, float z, float u, float v) {
builder.vertex(entry.pose(), x, y, z)
.color(1.0F, 1.0F, 1.0F, alpha)
.uv(u, v)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(LightTexture.FULL_BRIGHT)
.normal(entry.normal(), 0.0F, 1.0F, 0.0F)
.endVertex();
}
}

View File

@@ -0,0 +1,464 @@
package nl.requios.effortlessbuilding.create.foundation.render;
import com.jozufozu.flywheel.api.vertex.ShadedVertexList;
import com.jozufozu.flywheel.backend.ShadersModHandler;
import com.jozufozu.flywheel.core.vertex.BlockVertexList;
import com.jozufozu.flywheel.util.DiffuseLightCalculator;
import com.jozufozu.flywheel.util.transform.TStack;
import com.jozufozu.flywheel.util.transform.Transform;
import com.mojang.blaze3d.vertex.BufferBuilder.DrawState;
import com.mojang.blaze3d.vertex.BufferBuilder.RenderedBuffer;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.*;
import nl.requios.effortlessbuilding.create.foundation.block.render.SpriteShiftEntry;
import nl.requios.effortlessbuilding.create.foundation.utility.Color;
import it.unimi.dsi.fastutil.longs.Long2IntMap;
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
import net.minecraft.world.level.Level;
public class SuperByteBuffer implements Transform<SuperByteBuffer>, TStack<SuperByteBuffer> {
private final ShadedVertexList template;
// Vertex Position
private final PoseStack transforms;
// Vertex Coloring
private boolean shouldColor;
private int r, g, b, a;
private boolean disableDiffuseMult;
private DiffuseLightCalculator diffuseCalculator;
// Vertex Texture Coords
private SpriteShiftFunc spriteShiftFunc;
// Vertex Overlay Color
private boolean hasOverlay;
private int overlay = OverlayTexture.NO_OVERLAY;
// Vertex Lighting
private boolean useWorldLight;
private Matrix4f lightTransform;
private boolean hasCustomLight;
private int packedLightCoords;
private boolean hybridLight;
// Vertex Normals
private boolean fullNormalTransform;
// Temporary
private static final Long2IntMap WORLD_LIGHT_CACHE = new Long2IntOpenHashMap();
public SuperByteBuffer(RenderedBuffer buf, int unshadedStartVertex) {
DrawState drawState = buf.drawState();
template = new BlockVertexList.Shaded(buf.vertexBuffer(), drawState.vertexCount(), drawState.format().getVertexSize(), unshadedStartVertex);
transforms = new PoseStack();
transforms.pushPose();
}
public void renderInto(PoseStack input, VertexConsumer builder) {
if (isEmpty())
return;
Matrix4f modelMat = input.last()
.pose()
.copy();
Matrix4f localTransforms = transforms.last()
.pose();
modelMat.multiply(localTransforms);
Matrix3f normalMat;
if (fullNormalTransform) {
normalMat = input.last()
.normal()
.copy();
Matrix3f localNormalTransforms = transforms.last()
.normal();
normalMat.mul(localNormalTransforms);
} else {
normalMat = transforms.last()
.normal()
.copy();
}
if (useWorldLight) {
WORLD_LIGHT_CACHE.clear();
}
final Vector4f pos = new Vector4f();
final Vector3f normal = new Vector3f();
final Vector4f lightPos = new Vector4f();
DiffuseLightCalculator diffuseCalculator = ForcedDiffuseState.getForcedCalculator();
final boolean disableDiffuseMult =
this.disableDiffuseMult || (ShadersModHandler.isShaderPackInUse() && diffuseCalculator == null);
if (diffuseCalculator == null) {
diffuseCalculator = this.diffuseCalculator;
if (diffuseCalculator == null) {
diffuseCalculator = DiffuseLightCalculator.forCurrentLevel();
}
}
final int vertexCount = template.getVertexCount();
for (int i = 0; i < vertexCount; i++) {
float x = template.getX(i);
float y = template.getY(i);
float z = template.getZ(i);
pos.set(x, y, z, 1F);
pos.transform(modelMat);
builder.vertex(pos.x(), pos.y(), pos.z());
float normalX = template.getNX(i);
float normalY = template.getNY(i);
float normalZ = template.getNZ(i);
normal.set(normalX, normalY, normalZ);
normal.transform(normalMat);
float nx = normal.x();
float ny = normal.y();
float nz = normal.z();
byte r, g, b, a;
if (shouldColor) {
r = (byte) this.r;
g = (byte) this.g;
b = (byte) this.b;
a = (byte) this.a;
} else {
r = template.getR(i);
g = template.getG(i);
b = template.getB(i);
a = template.getA(i);
}
if (disableDiffuseMult) {
builder.color(r, g, b, a);
} else {
float instanceDiffuse = diffuseCalculator.getDiffuse(nx, ny, nz, template.isShaded(i));
int colorR = transformColor(r, instanceDiffuse);
int colorG = transformColor(g, instanceDiffuse);
int colorB = transformColor(b, instanceDiffuse);
builder.color(colorR, colorG, colorB, a);
}
float u = template.getU(i);
float v = template.getV(i);
if (spriteShiftFunc != null) {
spriteShiftFunc.shift(builder, u, v);
} else {
builder.uv(u, v);
}
if (hasOverlay) {
builder.overlayCoords(overlay);
}
int light;
if (useWorldLight) {
lightPos.set(((x - .5f) * 15 / 16f) + .5f, (y - .5f) * 15 / 16f + .5f, (z - .5f) * 15 / 16f + .5f, 1f);
lightPos.transform(localTransforms);
if (lightTransform != null) {
lightPos.transform(lightTransform);
}
light = getLight(Minecraft.getInstance().level, lightPos);
if (hasCustomLight) {
light = maxLight(light, packedLightCoords);
}
} else if (hasCustomLight) {
light = packedLightCoords;
} else {
light = template.getLight(i);
}
if (hybridLight) {
builder.uv2(maxLight(light, template.getLight(i)));
} else {
builder.uv2(light);
}
builder.normal(nx, ny, nz);
builder.endVertex();
}
reset();
}
public SuperByteBuffer reset() {
while (!transforms.clear())
transforms.popPose();
transforms.pushPose();
shouldColor = false;
r = 0;
g = 0;
b = 0;
a = 0;
disableDiffuseMult = false;
diffuseCalculator = null;
spriteShiftFunc = null;
hasOverlay = false;
overlay = OverlayTexture.NO_OVERLAY;
useWorldLight = false;
lightTransform = null;
hasCustomLight = false;
packedLightCoords = 0;
hybridLight = false;
fullNormalTransform = false;
return this;
}
public boolean isEmpty() {
return template.isEmpty();
}
public PoseStack getTransforms() {
return transforms;
}
@Override
public SuperByteBuffer translate(double x, double y, double z) {
transforms.translate(x, y, z);
return this;
}
@Override
public SuperByteBuffer multiply(Quaternion quaternion) {
transforms.mulPose(quaternion);
return this;
}
@Override
public SuperByteBuffer scale(float factorX, float factorY, float factorZ) {
transforms.scale(factorX, factorY, factorZ);
return this;
}
@Override
public SuperByteBuffer pushPose() {
transforms.pushPose();
return this;
}
@Override
public SuperByteBuffer popPose() {
transforms.popPose();
return this;
}
@Override
public SuperByteBuffer mulPose(Matrix4f pose) {
transforms.last()
.pose()
.multiply(pose);
return this;
}
@Override
public SuperByteBuffer mulNormal(Matrix3f normal) {
transforms.last()
.normal()
.mul(normal);
return this;
}
public SuperByteBuffer transform(PoseStack stack) {
transforms.last()
.pose()
.multiply(stack.last()
.pose());
transforms.last()
.normal()
.mul(stack.last()
.normal());
return this;
}
public SuperByteBuffer rotateCentered(Direction axis, float radians) {
translate(.5f, .5f, .5f).rotate(axis, radians)
.translate(-.5f, -.5f, -.5f);
return this;
}
public SuperByteBuffer rotateCentered(Quaternion q) {
translate(.5f, .5f, .5f).multiply(q)
.translate(-.5f, -.5f, -.5f);
return this;
}
public SuperByteBuffer color(int r, int g, int b, int a) {
shouldColor = true;
this.r = r;
this.g = g;
this.b = b;
this.a = a;
return this;
}
public SuperByteBuffer color(int color) {
shouldColor = true;
r = ((color >> 16) & 0xFF);
g = ((color >> 8) & 0xFF);
b = (color & 0xFF);
a = 255;
return this;
}
public SuperByteBuffer color(Color c) {
return color(c.getRGB());
}
/**
* Prevents vertex colors from being multiplied by the diffuse value calculated
* from the final transformed normal vector. Useful for entity rendering, when
* diffuse is applied automatically later.
*/
public SuperByteBuffer disableDiffuse() {
disableDiffuseMult = true;
return this;
}
public SuperByteBuffer diffuseCalculator(DiffuseLightCalculator diffuseCalculator) {
this.diffuseCalculator = diffuseCalculator;
return this;
}
public SuperByteBuffer shiftUV(SpriteShiftEntry entry) {
this.spriteShiftFunc = (builder, u, v) -> {
builder.uv(entry.getTargetU(u), entry.getTargetV(v));
};
return this;
}
public SuperByteBuffer shiftUVScrolling(SpriteShiftEntry entry, float scrollV) {
return this.shiftUVScrolling(entry, 0, scrollV);
}
public SuperByteBuffer shiftUVScrolling(SpriteShiftEntry entry, float scrollU, float scrollV) {
this.spriteShiftFunc = (builder, u, v) -> {
float targetU = u - entry.getOriginal()
.getU0() + entry.getTarget()
.getU0()
+ scrollU;
float targetV = v - entry.getOriginal()
.getV0() + entry.getTarget()
.getV0()
+ scrollV;
builder.uv(targetU, targetV);
};
return this;
}
public SuperByteBuffer shiftUVtoSheet(SpriteShiftEntry entry, float uTarget, float vTarget, int sheetSize) {
this.spriteShiftFunc = (builder, u, v) -> {
float targetU = entry.getTarget()
.getU((SpriteShiftEntry.getUnInterpolatedU(entry.getOriginal(), u) / sheetSize) + uTarget * 16);
float targetV = entry.getTarget()
.getV((SpriteShiftEntry.getUnInterpolatedV(entry.getOriginal(), v) / sheetSize) + vTarget * 16);
builder.uv(targetU, targetV);
};
return this;
}
public SuperByteBuffer overlay() {
hasOverlay = true;
return this;
}
public SuperByteBuffer overlay(int overlay) {
hasOverlay = true;
this.overlay = overlay;
return this;
}
public SuperByteBuffer light() {
useWorldLight = true;
return this;
}
public SuperByteBuffer light(Matrix4f lightTransform) {
useWorldLight = true;
this.lightTransform = lightTransform;
return this;
}
public SuperByteBuffer light(int packedLightCoords) {
hasCustomLight = true;
this.packedLightCoords = packedLightCoords;
return this;
}
public SuperByteBuffer light(Matrix4f lightTransform, int packedLightCoords) {
light(lightTransform);
light(packedLightCoords);
return this;
}
/**
* Uses max light from calculated light (world light or custom light) and vertex
* light for the final light value. Ineffective if any other light method was
* not called.
*/
public SuperByteBuffer hybridLight() {
hybridLight = true;
return this;
}
/**
* Transforms normals not only by the local matrix stack, but also by the passed
* matrix stack.
*/
public SuperByteBuffer fullNormalTransform() {
fullNormalTransform = true;
return this;
}
public SuperByteBuffer forEntityRender() {
disableDiffuse();
overlay();
fullNormalTransform();
return this;
}
public static int transformColor(byte component, float scale) {
return Mth.clamp((int) (Byte.toUnsignedInt(component) * scale), 0, 255);
}
public static int transformColor(int component, float scale) {
return Mth.clamp((int) (component * scale), 0, 255);
}
public static int maxLight(int packedLight1, int packedLight2) {
int blockLight1 = LightTexture.block(packedLight1);
int skyLight1 = LightTexture.sky(packedLight1);
int blockLight2 = LightTexture.block(packedLight2);
int skyLight2 = LightTexture.sky(packedLight2);
return LightTexture.pack(Math.max(blockLight1, blockLight2), Math.max(skyLight1, skyLight2));
}
private static int getLight(Level world, Vector4f lightPos) {
BlockPos pos = new BlockPos(lightPos.x(), lightPos.y(), lightPos.z());
return WORLD_LIGHT_CACHE.computeIfAbsent(pos.asLong(), $ -> LevelRenderer.getLightColor(world, pos));
}
@FunctionalInterface
public interface SpriteShiftFunc {
void shift(VertexConsumer builder, float u, float v);
}
@FunctionalInterface
public interface VertexLighter {
int getPackedLight(float x, float y, float z);
}
}

View File

@@ -0,0 +1,54 @@
package nl.requios.effortlessbuilding.create.foundation.render;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class SuperByteBufferCache {
protected final Map<Compartment<?>, Cache<Object, SuperByteBuffer>> caches = new HashMap<>();
public synchronized void registerCompartment(Compartment<?> compartment) {
caches.put(compartment, CacheBuilder.newBuilder()
.build());
}
public synchronized void registerCompartment(Compartment<?> compartment, long ticksUntilExpired) {
caches.put(compartment, CacheBuilder.newBuilder()
.expireAfterAccess(ticksUntilExpired * 50, TimeUnit.MILLISECONDS)
.build());
}
public <T> SuperByteBuffer get(Compartment<T> compartment, T key, Callable<SuperByteBuffer> callable) {
Cache<Object, SuperByteBuffer> cache = caches.get(compartment);
if (cache != null) {
try {
return cache.get(key, callable);
} catch (ExecutionException e) {
e.printStackTrace();
}
}
return null;
}
public <T> void invalidate(Compartment<T> compartment, T key) {
caches.get(compartment).invalidate(key);
}
public <T> void invalidate(Compartment<?> compartment) {
caches.get(compartment).invalidateAll();
}
public void invalidate() {
caches.forEach((compartment, cache) -> cache.invalidateAll());
}
public static class Compartment<T> {
}
}

View File

@@ -0,0 +1,94 @@
package nl.requios.effortlessbuilding.create.foundation.render;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.VertexConsumer;
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
import net.minecraft.Util;
import net.minecraft.client.renderer.ChunkBufferBuilderPack;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.Sheets;
import net.minecraft.client.resources.model.ModelBakery;
import java.util.SortedMap;
public class SuperRenderTypeBuffer implements MultiBufferSource {
private static final SuperRenderTypeBuffer INSTANCE = new SuperRenderTypeBuffer();
public static SuperRenderTypeBuffer getInstance() {
return INSTANCE;
}
private SuperRenderTypeBufferPhase earlyBuffer;
private SuperRenderTypeBufferPhase defaultBuffer;
private SuperRenderTypeBufferPhase lateBuffer;
public SuperRenderTypeBuffer() {
earlyBuffer = new SuperRenderTypeBufferPhase();
defaultBuffer = new SuperRenderTypeBufferPhase();
lateBuffer = new SuperRenderTypeBufferPhase();
}
public VertexConsumer getEarlyBuffer(RenderType type) {
return earlyBuffer.bufferSource.getBuffer(type);
}
@Override
public VertexConsumer getBuffer(RenderType type) {
return defaultBuffer.bufferSource.getBuffer(type);
}
public VertexConsumer getLateBuffer(RenderType type) {
return lateBuffer.bufferSource.getBuffer(type);
}
public void draw() {
earlyBuffer.bufferSource.endBatch();
defaultBuffer.bufferSource.endBatch();
lateBuffer.bufferSource.endBatch();
}
public void draw(RenderType type) {
earlyBuffer.bufferSource.endBatch(type);
defaultBuffer.bufferSource.endBatch(type);
lateBuffer.bufferSource.endBatch(type);
}
private static class SuperRenderTypeBufferPhase {
// Visible clones from RenderBuffers
private final ChunkBufferBuilderPack fixedBufferPack = new ChunkBufferBuilderPack();
private final SortedMap<RenderType, BufferBuilder> fixedBuffers = Util.make(new Object2ObjectLinkedOpenHashMap<>(), map -> {
map.put(Sheets.solidBlockSheet(), fixedBufferPack.builder(RenderType.solid()));
map.put(Sheets.cutoutBlockSheet(), fixedBufferPack.builder(RenderType.cutout()));
map.put(Sheets.bannerSheet(), fixedBufferPack.builder(RenderType.cutoutMipped()));
map.put(Sheets.translucentCullBlockSheet(), fixedBufferPack.builder(RenderType.translucent()));
put(map, Sheets.shieldSheet());
put(map, Sheets.bedSheet());
put(map, Sheets.shulkerBoxSheet());
put(map, Sheets.signSheet());
put(map, Sheets.chestSheet());
put(map, RenderType.translucentNoCrumbling());
put(map, RenderType.armorGlint());
put(map, RenderType.armorEntityGlint());
put(map, RenderType.glint());
put(map, RenderType.glintDirect());
put(map, RenderType.glintTranslucent());
put(map, RenderType.entityGlint());
put(map, RenderType.entityGlintDirect());
put(map, RenderType.waterMask());
put(map, RenderTypes.getOutlineSolid());
ModelBakery.DESTROY_TYPES.forEach((p_173062_) -> {
put(map, p_173062_);
});
});
private final BufferSource bufferSource = MultiBufferSource.immediateWithBuffers(fixedBuffers, new BufferBuilder(256));
private static void put(Object2ObjectLinkedOpenHashMap<RenderType, BufferBuilder> map, RenderType type) {
map.put(type, new BufferBuilder(type.bufferSize()));
}
}
}

View File

@@ -0,0 +1,113 @@
package nl.requios.effortlessbuilding.create.foundation.render;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
import com.jozufozu.flywheel.config.BackendType;
import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector4f;
import nl.requios.effortlessbuilding.create.Create;
import nl.requios.effortlessbuilding.create.foundation.utility.AnimationTickHolder;
import nl.requios.effortlessbuilding.create.foundation.utility.RegisteredObjects;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import javax.annotation.Nullable;
import java.util.Iterator;
public class TileEntityRenderHelper {
public static void renderTileEntities(Level world, Iterable<BlockEntity> customRenderTEs, PoseStack ms,
MultiBufferSource buffer) {
renderTileEntities(world, null, customRenderTEs, ms, null, buffer);
}
public static void renderTileEntities(Level world, Iterable<BlockEntity> customRenderTEs, PoseStack ms,
MultiBufferSource buffer, float pt) {
renderTileEntities(world, null, customRenderTEs, ms, null, buffer, pt);
}
public static void renderTileEntities(Level world, @Nullable VirtualRenderWorld renderWorld,
Iterable<BlockEntity> customRenderTEs, PoseStack ms, @Nullable Matrix4f lightTransform, MultiBufferSource buffer) {
renderTileEntities(world, renderWorld, customRenderTEs, ms, lightTransform, buffer,
AnimationTickHolder.getPartialTicks());
}
public static void renderTileEntities(Level world, @Nullable VirtualRenderWorld renderWorld,
Iterable<BlockEntity> customRenderTEs, PoseStack ms, @Nullable Matrix4f lightTransform, MultiBufferSource buffer,
float pt) {
Iterator<BlockEntity> iterator = customRenderTEs.iterator();
while (iterator.hasNext()) {
BlockEntity tileEntity = iterator.next();
if (Backend.getBackendType() == BackendType.INSTANCING && Backend.isFlywheelWorld(renderWorld) && InstancedRenderRegistry.shouldSkipRender(tileEntity))
continue;
BlockEntityRenderer<BlockEntity> renderer = Minecraft.getInstance().getBlockEntityRenderDispatcher().getRenderer(tileEntity);
if (renderer == null) {
iterator.remove();
continue;
}
BlockPos pos = tileEntity.getBlockPos();
ms.pushPose();
TransformStack.cast(ms)
.translate(pos);
try {
int worldLight = getCombinedLight(world, getLightPos(lightTransform, pos), renderWorld, pos);
if (renderWorld != null) {
// Swap the real world for the render world so that the renderer gets contraption-local information
tileEntity.setLevel(renderWorld);
renderer.render(tileEntity, pt, ms, buffer, worldLight, OverlayTexture.NO_OVERLAY);
tileEntity.setLevel(world);
} else {
renderer.render(tileEntity, pt, ms, buffer, worldLight, OverlayTexture.NO_OVERLAY);
}
} catch (Exception e) {
iterator.remove();
String message = "BlockEntity " + RegisteredObjects.getKeyOrThrow(tileEntity.getType())
.toString() + " could not be rendered virtually.";
// if (AllConfigs.CLIENT.explainRenderErrors.get())
Create.LOGGER.error(message, e);
// else
// Create.LOGGER.error(message);
}
ms.popPose();
}
}
private static BlockPos getLightPos(@Nullable Matrix4f lightTransform, BlockPos contraptionPos) {
if (lightTransform != null) {
Vector4f lightVec = new Vector4f(contraptionPos.getX() + .5f, contraptionPos.getY() + .5f, contraptionPos.getZ() + .5f, 1);
lightVec.transform(lightTransform);
return new BlockPos(lightVec.x(), lightVec.y(), lightVec.z());
} else {
return contraptionPos;
}
}
public static int getCombinedLight(Level world, BlockPos worldPos, @Nullable VirtualRenderWorld renderWorld,
BlockPos renderWorldPos) {
int worldLight = LevelRenderer.getLightColor(world, worldPos);
if (renderWorld != null) {
int renderWorldLight = LevelRenderer.getLightColor(renderWorld, renderWorldPos);
return SuperByteBuffer.maxLight(worldLight, renderWorldLight);
}
return worldLight;
}
}

View File

@@ -0,0 +1,36 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraftforge.event.ForgeEventFactory;
import javax.annotation.Nullable;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public abstract class AbstractBlockBreakQueue {
protected Consumer<BlockPos> makeCallbackFor(Level world, float effectChance, ItemStack toDamage,
@Nullable Player playerEntity, BiConsumer<BlockPos, ItemStack> drop) {
return pos -> {
ItemStack usedTool = toDamage.copy();
BlockHelper.destroyBlockAs(world, pos, playerEntity, toDamage, effectChance,
stack -> drop.accept(pos, stack));
if (toDamage.isEmpty() && !usedTool.isEmpty())
ForgeEventFactory.onPlayerDestroyItem(playerEntity, usedTool, InteractionHand.MAIN_HAND);
};
}
public void destroyBlocks(Level world, @Nullable LivingEntity entity, BiConsumer<BlockPos, ItemStack> drop) {
Player playerEntity = entity instanceof Player ? ((Player) entity) : null;
ItemStack toDamage =
playerEntity != null && !playerEntity.isCreative() ? playerEntity.getMainHandItem() : ItemStack.EMPTY;
destroyBlocks(world, toDamage, playerEntity, drop);
}
public abstract void destroyBlocks(Level world, ItemStack toDamage, @Nullable Player playerEntity,
BiConsumer<BlockPos, ItemStack> drop);
}

View File

@@ -0,0 +1,52 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.util.Mth;
public class AngleHelper {
public static float horizontalAngle(Direction facing) {
if (facing.getAxis().isVertical())
return 0;
float angle = facing.toYRot();
if (facing.getAxis() == Axis.X)
angle = -angle;
return angle;
}
public static float verticalAngle(Direction facing) {
return facing == Direction.UP ? -90 : facing == Direction.DOWN ? 90 : 0;
}
public static float rad(double angle) {
if (angle == 0)
return 0;
return (float) (angle / 180 * Math.PI);
}
public static float deg(double angle) {
if (angle == 0)
return 0;
return (float) (angle * 180 / Math.PI);
}
public static float angleLerp(double pct, double current, double target) {
return (float) (current + getShortestAngleDiff(current, target) * pct);
}
public static float getShortestAngleDiff(double current, double target) {
current = current % 360;
target = target % 360;
return (float) (((((target - current) % 360) + 540) % 360) - 180);
}
public static float getShortestAngleDiff(double current, double target, float hint) {
float diff = getShortestAngleDiff(current, target);
if (Mth.equal(Math.abs(diff), 180) && Math.signum(diff) != Math.signum(hint)) {
return diff + 360*Math.signum(hint);
}
return diff;
}
}

View File

@@ -0,0 +1,56 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import nl.requios.effortlessbuilding.create.foundation.utility.worldWrappers.WrappedClientWorld;
import net.minecraft.client.Minecraft;
import net.minecraft.world.level.LevelAccessor;
public class AnimationTickHolder {
private static int ticks;
private static int pausedTicks;
public static void reset() {
ticks = 0;
pausedTicks = 0;
}
public static void tick() {
if (!Minecraft.getInstance()
.isPaused()) {
ticks = (ticks + 1) % 1_728_000; // wrap around every 24 hours so we maintain enough floating point precision
} else {
pausedTicks = (pausedTicks + 1) % 1_728_000;
}
}
public static int getTicks() {
return getTicks(false);
}
public static int getTicks(boolean includePaused) {
return includePaused ? ticks + pausedTicks : ticks;
}
public static float getRenderTime() {
return getTicks() + getPartialTicks();
}
public static float getPartialTicks() {
Minecraft mc = Minecraft.getInstance();
return (mc.isPaused() ? mc.pausePartialTick : mc.getFrameTime());
}
public static int getTicks(LevelAccessor world) {
if (world instanceof WrappedClientWorld)
return getTicks(((WrappedClientWorld) world).getWrappedWorld());
return getTicks();
}
public static float getRenderTime(LevelAccessor world) {
return getTicks(world) + getPartialTicks(world);
}
public static float getPartialTicks(LevelAccessor world) {
return getPartialTicks();
}
}

View File

@@ -0,0 +1,20 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
public class BBHelper {
public static BoundingBox encapsulate(BoundingBox bb, BlockPos pos) {
return new BoundingBox(Math.min(bb.minX(), pos.getX()), Math.min(bb.minY(), pos.getY()),
Math.min(bb.minZ(), pos.getZ()), Math.max(bb.maxX(), pos.getX()), Math.max(bb.maxY(), pos.getY()),
Math.max(bb.maxZ(), pos.getZ()));
}
public static BoundingBox encapsulate(BoundingBox bb, BoundingBox bb2) {
return new BoundingBox(Math.min(bb.minX(), bb2.minX()), Math.min(bb.minY(), bb2.minY()),
Math.min(bb.minZ(), bb2.minZ()), Math.max(bb.maxX(), bb2.maxX()), Math.max(bb.maxY(), bb2.maxY()),
Math.max(bb.maxZ(), bb2.maxZ()));
}
}

View File

@@ -0,0 +1,52 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
public class BlockFace extends Pair<BlockPos, Direction> {
public BlockFace(BlockPos first, Direction second) {
super(first, second);
}
public boolean isEquivalent(BlockFace other) {
if (equals(other))
return true;
return getConnectedPos().equals(other.getPos()) && getPos().equals(other.getConnectedPos());
}
public BlockPos getPos() {
return getFirst();
}
public Direction getFace() {
return getSecond();
}
public Direction getOppositeFace() {
return getSecond().getOpposite();
}
public BlockFace getOpposite() {
return new BlockFace(getConnectedPos(), getOppositeFace());
}
public BlockPos getConnectedPos() {
return getPos().relative(getFace());
}
public CompoundTag serializeNBT() {
CompoundTag compoundNBT = new CompoundTag();
compoundNBT.put("Pos", NbtUtils.writeBlockPos(getPos()));
NBTHelper.writeEnum(compoundNBT, "Face", getFace());
return compoundNBT;
}
public static BlockFace fromNBT(CompoundTag compound) {
return new BlockFace(NbtUtils.readBlockPos(compound.getCompound("Pos")),
NBTHelper.readEnum(compound, "Face", Direction.class));
}
}

View File

@@ -0,0 +1,337 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.stats.Stats;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.FluidTags;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.block.state.properties.SlabType;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Material;
import net.minecraftforge.common.IPlantable;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.level.BlockEvent;
import javax.annotation.Nullable;
import java.util.function.Consumer;
public class BlockHelper {
public static BlockState setZeroAge(BlockState blockState) {
if (blockState.hasProperty(BlockStateProperties.AGE_1))
return blockState.setValue(BlockStateProperties.AGE_1, 0);
if (blockState.hasProperty(BlockStateProperties.AGE_2))
return blockState.setValue(BlockStateProperties.AGE_2, 0);
if (blockState.hasProperty(BlockStateProperties.AGE_3))
return blockState.setValue(BlockStateProperties.AGE_3, 0);
if (blockState.hasProperty(BlockStateProperties.AGE_5))
return blockState.setValue(BlockStateProperties.AGE_5, 0);
if (blockState.hasProperty(BlockStateProperties.AGE_7))
return blockState.setValue(BlockStateProperties.AGE_7, 0);
if (blockState.hasProperty(BlockStateProperties.AGE_15))
return blockState.setValue(BlockStateProperties.AGE_15, 0);
if (blockState.hasProperty(BlockStateProperties.AGE_25))
return blockState.setValue(BlockStateProperties.AGE_25, 0);
if (blockState.hasProperty(BlockStateProperties.LEVEL_HONEY))
return blockState.setValue(BlockStateProperties.LEVEL_HONEY, 0);
if (blockState.hasProperty(BlockStateProperties.HATCH))
return blockState.setValue(BlockStateProperties.HATCH, 0);
if (blockState.hasProperty(BlockStateProperties.STAGE))
return blockState.setValue(BlockStateProperties.STAGE, 0);
if (blockState.is(BlockTags.CAULDRONS))
return Blocks.CAULDRON.defaultBlockState();
if (blockState.hasProperty(BlockStateProperties.LEVEL_COMPOSTER))
return blockState.setValue(BlockStateProperties.LEVEL_COMPOSTER, 0);
if (blockState.hasProperty(BlockStateProperties.EXTENDED))
return blockState.setValue(BlockStateProperties.EXTENDED, false);
return blockState;
}
public static int findAndRemoveInInventory(BlockState block, Player player, int amount) {
int amountFound = 0;
Item required = getRequiredItem(block).getItem();
boolean needsTwo = block.hasProperty(BlockStateProperties.SLAB_TYPE)
&& block.getValue(BlockStateProperties.SLAB_TYPE) == SlabType.DOUBLE;
if (needsTwo)
amount *= 2;
if (block.hasProperty(BlockStateProperties.EGGS))
amount *= block.getValue(BlockStateProperties.EGGS);
if (block.hasProperty(BlockStateProperties.PICKLES))
amount *= block.getValue(BlockStateProperties.PICKLES);
{
// Try held Item first
int preferredSlot = player.getInventory().selected;
ItemStack itemstack = player.getInventory()
.getItem(preferredSlot);
int count = itemstack.getCount();
if (itemstack.getItem() == required && count > 0) {
int taken = Math.min(count, amount - amountFound);
player.getInventory()
.setItem(preferredSlot, new ItemStack(itemstack.getItem(), count - taken));
amountFound += taken;
}
}
// Search inventory
for (int i = 0; i < player.getInventory()
.getContainerSize(); ++i) {
if (amountFound == amount)
break;
ItemStack itemstack = player.getInventory()
.getItem(i);
int count = itemstack.getCount();
if (itemstack.getItem() == required && count > 0) {
int taken = Math.min(count, amount - amountFound);
player.getInventory()
.setItem(i, new ItemStack(itemstack.getItem(), count - taken));
amountFound += taken;
}
}
if (needsTwo) {
// Give back 1 if uneven amount was removed
if (amountFound % 2 != 0)
player.getInventory()
.add(new ItemStack(required));
amountFound /= 2;
}
return amountFound;
}
public static ItemStack getRequiredItem(BlockState state) {
ItemStack itemStack = new ItemStack(state.getBlock());
Item item = itemStack.getItem();
if (item == Items.FARMLAND || item == Items.DIRT_PATH)
itemStack = new ItemStack(Items.DIRT);
return itemStack;
}
public static void destroyBlock(Level world, BlockPos pos, float effectChance) {
destroyBlock(world, pos, effectChance, stack -> Block.popResource(world, pos, stack));
}
public static void destroyBlock(Level world, BlockPos pos, float effectChance,
Consumer<ItemStack> droppedItemCallback) {
destroyBlockAs(world, pos, null, ItemStack.EMPTY, effectChance, droppedItemCallback);
}
public static void destroyBlockAs(Level world, BlockPos pos, @Nullable Player player, ItemStack usedTool,
float effectChance, Consumer<ItemStack> droppedItemCallback) {
FluidState fluidState = world.getFluidState(pos);
BlockState state = world.getBlockState(pos);
if (world.random.nextFloat() < effectChance)
world.levelEvent(2001, pos, Block.getId(state));
BlockEntity tileentity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null;
if (player != null) {
BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(world, pos, state, player);
MinecraftForge.EVENT_BUS.post(event);
if (event.isCanceled())
return;
if (event.getExpToDrop() > 0 && world instanceof ServerLevel)
state.getBlock()
.popExperience((ServerLevel) world, pos, event.getExpToDrop());
usedTool.mineBlock(world, state, pos, player);
player.awardStat(Stats.BLOCK_MINED.get(state.getBlock()));
}
if (world instanceof ServerLevel && world.getGameRules()
.getBoolean(GameRules.RULE_DOBLOCKDROPS) && !world.restoringBlockSnapshots
&& (player == null || !player.isCreative())) {
for (ItemStack itemStack : Block.getDrops(state, (ServerLevel) world, pos, tileentity, player, usedTool))
droppedItemCallback.accept(itemStack);
// Simulating IceBlock#playerDestroy. Not calling method directly as it would drop item
// entities as a side-effect
if (state.getBlock() instanceof IceBlock && usedTool.getEnchantmentLevel(Enchantments.SILK_TOUCH) == 0) {
if (world.dimensionType()
.ultraWarm())
return;
Material material = world.getBlockState(pos.below())
.getMaterial();
if (material.blocksMotion() || material.isLiquid())
world.setBlockAndUpdate(pos, Blocks.WATER.defaultBlockState());
return;
}
state.spawnAfterBreak((ServerLevel) world, pos, ItemStack.EMPTY, true);
}
world.setBlockAndUpdate(pos, fluidState.createLegacyBlock());
}
public static boolean isSolidWall(BlockGetter reader, BlockPos fromPos, Direction toDirection) {
return hasBlockSolidSide(reader.getBlockState(fromPos.relative(toDirection)), reader,
fromPos.relative(toDirection), toDirection.getOpposite());
}
public static boolean noCollisionInSpace(BlockGetter reader, BlockPos pos) {
return reader.getBlockState(pos)
.getCollisionShape(reader, pos)
.isEmpty();
}
private static void placeRailWithoutUpdate(Level world, BlockState state, BlockPos target) {
LevelChunk chunk = world.getChunkAt(target);
int idx = chunk.getSectionIndex(target.getY());
LevelChunkSection chunksection = chunk.getSection(idx);
if (chunksection == null) {
chunksection = new LevelChunkSection(chunk.getSectionYFromSectionIndex(idx), world.registryAccess()
.registryOrThrow(Registry.BIOME_REGISTRY));
chunk.getSections()[idx] = chunksection;
}
BlockState old = chunksection.setBlockState(SectionPos.sectionRelative(target.getX()),
SectionPos.sectionRelative(target.getY()), SectionPos.sectionRelative(target.getZ()), state);
chunk.setUnsaved(true);
world.markAndNotifyBlock(target, chunk, old, state, 82, 512);
world.setBlock(target, state, 82);
world.neighborChanged(target, world.getBlockState(target.below())
.getBlock(), target.below());
}
public static void placeSchematicBlock(Level world, BlockState state, BlockPos target, ItemStack stack,
@Nullable CompoundTag data) {
BlockEntity existingTile = world.getBlockEntity(target);
// Piston
if (state.hasProperty(BlockStateProperties.EXTENDED))
state = state.setValue(BlockStateProperties.EXTENDED, Boolean.FALSE);
if (state.hasProperty(BlockStateProperties.WATERLOGGED))
state = state.setValue(BlockStateProperties.WATERLOGGED, Boolean.FALSE);
// if (AllBlocks.BELT.has(state)) {
// world.setBlock(target, state, 2);
// return;
// } else if (state.getBlock() == Blocks.COMPOSTER)
// state = Blocks.COMPOSTER.defaultBlockState();
// else if (state.getBlock() != Blocks.SEA_PICKLE && state.getBlock() instanceof IPlantable)
// state = ((IPlantable) state.getBlock()).getPlant(world, target);
// else if (state.is(BlockTags.CAULDRONS))
// state = Blocks.CAULDRON.defaultBlockState();
if (world.dimensionType()
.ultraWarm() && state.getFluidState().is(FluidTags.WATER)) {
int i = target.getX();
int j = target.getY();
int k = target.getZ();
world.playSound(null, target, SoundEvents.FIRE_EXTINGUISH, SoundSource.BLOCKS, 0.5F,
2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F);
for (int l = 0; l < 8; ++l) {
world.addParticle(ParticleTypes.LARGE_SMOKE, i + Math.random(), j + Math.random(), k + Math.random(),
0.0D, 0.0D, 0.0D);
}
Block.dropResources(state, world, target);
return;
}
if (state.getBlock() instanceof BaseRailBlock) {
placeRailWithoutUpdate(world, state, target);
} else {
world.setBlock(target, state, 18);
}
if (data != null) {
// if (existingTile instanceof IMergeableTE mergeable) {
// BlockEntity loaded = BlockEntity.loadStatic(target, state, data);
// if (existingTile.getType()
// .equals(loaded.getType())) {
// mergeable.accept(loaded);
// return;
// }
// }
BlockEntity tile = world.getBlockEntity(target);
if (tile != null) {
data.putInt("x", target.getX());
data.putInt("y", target.getY());
data.putInt("z", target.getZ());
// if (tile instanceof KineticTileEntity)
// ((KineticTileEntity) tile).warnOfMovement();
tile.load(data);
}
}
try {
state.getBlock()
.setPlacedBy(world, target, state, null, stack);
} catch (Exception e) {
}
}
public static double getBounceMultiplier(Block block) {
if (block instanceof SlimeBlock)
return 0.8D;
if (block instanceof BedBlock)
return 0.66 * 0.8D;
return 0;
}
public static boolean hasBlockSolidSide(BlockState p_220056_0_, BlockGetter p_220056_1_, BlockPos p_220056_2_,
Direction p_220056_3_) {
return !p_220056_0_.is(BlockTags.LEAVES)
&& Block.isFaceFull(p_220056_0_.getCollisionShape(p_220056_1_, p_220056_2_), p_220056_3_);
}
public static boolean extinguishFire(Level world, @Nullable Player p_175719_1_, BlockPos p_175719_2_,
Direction p_175719_3_) {
p_175719_2_ = p_175719_2_.relative(p_175719_3_);
if (world.getBlockState(p_175719_2_)
.getBlock() == Blocks.FIRE) {
world.levelEvent(p_175719_1_, 1009, p_175719_2_, 0);
world.removeBlock(p_175719_2_, false);
return true;
} else {
return false;
}
}
public static BlockState copyProperties(BlockState fromState, BlockState toState) {
for (Property<?> property : fromState.getProperties()) {
toState = copyProperty(property, fromState, toState);
}
return toState;
}
public static <T extends Comparable<T>> BlockState copyProperty(Property<T> property, BlockState fromState,
BlockState toState) {
if (fromState.hasProperty(property) && toState.hasProperty(property)) {
return toState.setValue(property, fromState.getValue(property));
}
return toState;
}
}

View File

@@ -0,0 +1,90 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import nl.requios.effortlessbuilding.create.foundation.utility.animation.LerpedFloat;
import net.minecraft.client.Minecraft;
import net.minecraft.util.Mth;
public class CameraAngleAnimationService {
private static final LerpedFloat yRotation = LerpedFloat.angular().startWithValue(0);
private static final LerpedFloat xRotation = LerpedFloat.angular().startWithValue(0);
private static Mode animationMode = Mode.LINEAR;
private static float animationSpeed = -1;
public static void tick() {
yRotation.tickChaser();
xRotation.tickChaser();
if (Minecraft.getInstance().player != null) {
if (!yRotation.settled())
Minecraft.getInstance().player.setYRot(yRotation.getValue(1));
if (!xRotation.settled())
Minecraft.getInstance().player.setXRot(xRotation.getValue(1));
}
}
public static boolean isYawAnimating() {
return !yRotation.settled();
}
public static boolean isPitchAnimating() {
return !xRotation.settled();
}
public static float getYaw(float partialTicks) {
return yRotation.getValue(partialTicks);
}
public static float getPitch(float partialTicks) {
return xRotation.getValue(partialTicks);
}
public static void setAnimationMode(Mode mode) {
animationMode = mode;
}
public static void setAnimationSpeed(float speed) {
animationSpeed = speed;
}
public static void setYawTarget(float yaw) {
float currentYaw = getCurrentYaw();
yRotation.startWithValue(currentYaw);
setupChaser(yRotation, currentYaw + AngleHelper.getShortestAngleDiff(currentYaw, Mth.wrapDegrees(yaw)));
}
public static void setPitchTarget(float pitch) {
float currentPitch = getCurrentPitch();
xRotation.startWithValue(currentPitch);
setupChaser(xRotation, currentPitch + AngleHelper.getShortestAngleDiff(currentPitch, Mth.wrapDegrees(pitch)));
}
private static float getCurrentYaw() {
if (Minecraft.getInstance().player == null)
return 0;
return Mth.wrapDegrees(Minecraft.getInstance().player.getYRot());
}
private static float getCurrentPitch() {
if (Minecraft.getInstance().player == null)
return 0;
return Mth.wrapDegrees(Minecraft.getInstance().player.getXRot());
}
private static void setupChaser(LerpedFloat rotation, float target) {
if (animationMode == Mode.LINEAR) {
rotation.chase(target, animationSpeed > 0 ? animationSpeed : 2, LerpedFloat.Chaser.LINEAR);
} else if (animationMode == Mode.EXPONENTIAL) {
rotation.chase(target, animationSpeed > 0 ? animationSpeed : 0.25, LerpedFloat.Chaser.EXP);
}
}
public enum Mode {
LINEAR,
EXPONENTIAL
}
}

View File

@@ -0,0 +1,310 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import com.google.common.hash.Hashing;
import com.mojang.math.Vector3f;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec3;
import javax.annotation.Nonnull;
import java.util.function.UnaryOperator;
public class Color {
public final static Color TRANSPARENT_BLACK = new Color(0, 0, 0, 0).setImmutable();
public final static Color BLACK = new Color(0, 0, 0).setImmutable();
public final static Color WHITE = new Color(255, 255, 255).setImmutable();
public final static Color RED = new Color(255, 0, 0).setImmutable();
public final static Color GREEN = new Color(0, 255, 0).setImmutable();
public final static Color SPRING_GREEN = new Color(0, 255, 187).setImmutable();
protected boolean mutable = true;
protected int value;
public Color(int r, int g, int b) {
this(r, g, b, 0xff);
}
public Color(int r, int g, int b, int a) {
value = ((a & 0xff) << 24) |
((r & 0xff) << 16) |
((g & 0xff) << 8) |
((b & 0xff) << 0);
}
public Color(float r, float g, float b, float a) {
this(
(int) (0.5 + 0xff * Mth.clamp(r, 0, 1)),
(int) (0.5 + 0xff * Mth.clamp(g, 0, 1)),
(int) (0.5 + 0xff * Mth.clamp(b, 0, 1)),
(int) (0.5 + 0xff * Mth.clamp(a, 0, 1))
);
}
public Color(int rgba) {
value = rgba;
}
public Color(int rgb, boolean hasAlpha) {
if (hasAlpha) {
value = rgb;
} else {
value = rgb | 0xff_000000;
}
}
public Color copy() {
return copy(true);
}
public Color copy(boolean mutable) {
if (mutable)
return new Color(value);
else
return new Color(value).setImmutable();
}
/**
* Mark this color as immutable. Attempting to mutate this color in the future
* will instead cause a copy to be created that can me modified.
*/
public Color setImmutable() {
this.mutable = false;
return this;
}
/**
* @return the red component in the range 0-255.
* @see #getRGB
*/
public int getRed() {
return (getRGB() >> 16) & 0xff;
}
/**
* @return the green component in the range 0-255.
* @see #getRGB
*/
public int getGreen() {
return (getRGB() >> 8) & 0xff;
}
/**
* @return the blue component in the range 0-255.
* @see #getRGB
*/
public int getBlue() {
return (getRGB() >> 0) & 0xff;
}
/**
* @return the alpha component in the range 0-255.
* @see #getRGB
*/
public int getAlpha() {
return (getRGB() >> 24) & 0xff;
}
/**
* @return the red component in the range 0-1f.
*/
public float getRedAsFloat() {
return getRed() / 255f;
}
/**
* @return the green component in the range 0-1f.
*/
public float getGreenAsFloat() {
return getGreen() / 255f;
}
/**
* @return the blue component in the range 0-1f.
*/
public float getBlueAsFloat() {
return getBlue() / 255f;
}
/**
* @return the alpha component in the range 0-1f.
*/
public float getAlphaAsFloat() {
return getAlpha() / 255f;
}
/**
* Returns the RGB value representing this color
* (Bits 24-31 are alpha, 16-23 are red, 8-15 are green, 0-7 are blue).
* @return the RGB value of the color
*/
public int getRGB() {
return value;
}
public Vec3 asVector() {
return new Vec3(getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat());
}
public Vector3f asVectorF() {
return new Vector3f(getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat());
}
public Color setRed(int r) {
return ensureMutable().setRedUnchecked(r);
}
public Color setGreen(int g) {
return ensureMutable().setGreenUnchecked(g);
}
public Color setBlue(int b) {
return ensureMutable().setBlueUnchecked(b);
}
public Color setAlpha(int a) {
return ensureMutable().setAlphaUnchecked(a);
}
public Color setRed(float r) {
return ensureMutable().setRedUnchecked((int) (0xff * Mth.clamp(r, 0, 1)));
}
public Color setGreen(float g) {
return ensureMutable().setGreenUnchecked((int) (0xff * Mth.clamp(g, 0, 1)));
}
public Color setBlue(float b) {
return ensureMutable().setBlueUnchecked((int) (0xff * Mth.clamp(b, 0, 1)));
}
public Color setAlpha(float a) {
return ensureMutable().setAlphaUnchecked((int) (0xff * Mth.clamp(a, 0, 1)));
}
public Color scaleAlpha(float factor) {
return ensureMutable().setAlphaUnchecked((int) (getAlpha() * Mth.clamp(factor, 0, 1)));
}
public Color mixWith(Color other, float weight) {
return ensureMutable()
.setRedUnchecked((int) (getRed() + (other.getRed() - getRed()) * weight))
.setGreenUnchecked((int) (getGreen() + (other.getGreen() - getGreen()) * weight))
.setBlueUnchecked((int) (getBlue() + (other.getBlue() - getBlue()) * weight))
.setAlphaUnchecked((int) (getAlpha() + (other.getAlpha() - getAlpha()) * weight));
}
public Color darker() {
int a = getAlpha();
return ensureMutable().mixWith(BLACK, .25f).setAlphaUnchecked(a);
}
public Color brighter() {
int a = getAlpha();
return ensureMutable().mixWith(WHITE, .25f).setAlphaUnchecked(a);
}
public Color setValue(int value) {
return ensureMutable().setValueUnchecked(value);
}
public Color modifyValue(UnaryOperator<Integer> function) {
int newValue = function.apply(value);
if (newValue == value)
return this;
return ensureMutable().setValueUnchecked(newValue);
}
// ********* //
protected Color ensureMutable() {
if (this.mutable)
return this;
return new Color(this.value);
}
protected Color setRedUnchecked(int r) {
this.value = (this.value & 0xff_00ffff) | ((r & 0xff) << 16);
return this;
}
protected Color setGreenUnchecked(int g) {
this.value = (this.value & 0xff_ff00ff) | ((g & 0xff) << 8);
return this;
}
protected Color setBlueUnchecked(int b) {
this.value = (this.value & 0xff_ffff00) | ((b & 0xff) << 0);
return this;
}
protected Color setAlphaUnchecked(int a) {
this.value = (this.value & 0x00_ffffff) | ((a & 0xff) << 24);
return this;
}
protected Color setValueUnchecked(int value) {
this.value = value;
return this;
}
// ********* //
public static Color mixColors(@Nonnull Color c1, @Nonnull Color c2, float w) {
return new Color(
(int) (c1.getRed() + (c2.getRed() - c1.getRed()) * w),
(int) (c1.getGreen() + (c2.getGreen() - c1.getGreen()) * w),
(int) (c1.getBlue() + (c2.getBlue() - c1.getBlue()) * w),
(int) (c1.getAlpha() + (c2.getAlpha() - c1.getAlpha()) * w)
);
}
public static Color mixColors(@Nonnull Couple<Color> colors, float w) {
return mixColors(colors.getFirst(), colors.getSecond(), w);
}
public static int mixColors(int color1, int color2, float w) {
int a1 = (color1 >> 24);
int r1 = (color1 >> 16) & 0xFF;
int g1 = (color1 >> 8) & 0xFF;
int b1 = color1 & 0xFF;
int a2 = (color2 >> 24);
int r2 = (color2 >> 16) & 0xFF;
int g2 = (color2 >> 8) & 0xFF;
int b2 = color2 & 0xFF;
return
((int) (a1 + (a2 - a1) * w) << 24) +
((int) (r1 + (r2 - r1) * w) << 16) +
((int) (g1 + (g2 - g1) * w) << 8) +
((int) (b1 + (b2 - b1) * w) << 0);
}
public static Color rainbowColor(int timeStep) {
int localTimeStep = Math.abs(timeStep) % 1536;
int timeStepInPhase = localTimeStep % 256;
int phaseBlue = localTimeStep / 256;
int red = colorInPhase(phaseBlue + 4, timeStepInPhase);
int green = colorInPhase(phaseBlue + 2, timeStepInPhase);
int blue = colorInPhase(phaseBlue, timeStepInPhase);
return new Color(red, green, blue);
}
private static int colorInPhase(int phase, int progress) {
phase = phase % 6;
if (phase <= 1)
return 0;
if (phase == 2)
return progress;
if (phase <= 4)
return 255;
else
return 255 - progress;
}
public static Color generateFromLong(long l) {
return rainbowColor(Hashing.crc32().hashLong(l).asInt())
.mixWith(WHITE, 0.5f);
}
}

View File

@@ -0,0 +1,26 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.client.color.block.BlockColor;
import net.minecraft.client.color.item.ItemColor;
import net.minecraft.client.renderer.BiomeColors;
import net.minecraft.world.level.GrassColor;
import net.minecraft.world.level.block.RedStoneWireBlock;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
public class ColorHandlers {
public static BlockColor getGrassyBlock() {
return (state, world, pos, layer) -> pos != null && world != null ? BiomeColors.getAverageGrassColor(world, pos)
: GrassColor.get(0.5D, 1.0D);
}
public static ItemColor getGrassyItem() {
return (stack, layer) -> GrassColor.get(0.5D, 1.0D);
}
public static BlockColor getRedstonePower() {
return (state, world, pos, layer) -> RedStoneWireBlock
.getColorForPower(pos != null && world != null ? state.getValue(BlockStateProperties.POWER) : 0);
}
}

View File

@@ -0,0 +1,33 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
public final class Components {
private static final Component IMMUTABLE_EMPTY = Component.empty();
public static Component immutableEmpty() {
return IMMUTABLE_EMPTY;
}
/** Use {@link #immutableEmpty()} when possible to prevent creating an extra object. */
public static MutableComponent empty() {
return Component.empty();
}
public static MutableComponent literal(String str) {
return Component.literal(str);
}
public static MutableComponent translatable(String key) {
return Component.translatable(key);
}
public static MutableComponent translatable(String key, Object... args) {
return Component.translatable(key, args);
}
public static MutableComponent keybind(String name) {
return Component.keybind(name);
}
}

View File

@@ -0,0 +1,151 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import com.google.common.collect.ImmutableList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import java.util.Iterator;
import java.util.List;
import java.util.function.*;
import java.util.stream.Stream;
public class Couple<T> extends Pair<T, T> implements Iterable<T> {
private static final Couple<Boolean> TRUE_AND_FALSE = Couple.create(true, false);
protected Couple(T first, T second) {
super(first, second);
}
public static <T> Couple<T> create(T first, T second) {
return new Couple<>(first, second);
}
public static <T> Couple<T> create(Supplier<T> factory) {
return new Couple<>(factory.get(), factory.get());
}
public static <T> Couple<T> createWithContext(Function<Boolean, T> factory) {
return new Couple<>(factory.apply(true), factory.apply(false));
}
public T get(boolean first) {
return first ? getFirst() : getSecond();
}
public void set(boolean first, T value) {
if (first)
setFirst(value);
else
setSecond(value);
}
@Override
public Couple<T> copy() {
return create(first, second);
}
public <S> Couple<S> map(Function<T, S> function) {
return Couple.create(function.apply(first), function.apply(second));
}
public <S> Couple<S> mapWithContext(BiFunction<T, Boolean, S> function) {
return Couple.create(function.apply(first, true), function.apply(second, false));
}
public <S, R> Couple<S> mapWithParams(BiFunction<T, R, S> function, Couple<R> values) {
return Couple.create(function.apply(first, values.first), function.apply(second, values.second));
}
public <S, R> Couple<S> mapNotNullWithParam(BiFunction<T, R, S> function, R value) {
return Couple.create(first != null ? function.apply(first, value) : null,
second != null ? function.apply(second, value) : null);
}
public boolean both(Predicate<T> test) {
return test.test(getFirst()) && test.test(getSecond());
}
public boolean either(Predicate<T> test) {
return test.test(getFirst()) || test.test(getSecond());
}
public void replace(Function<T, T> function) {
setFirst(function.apply(getFirst()));
setSecond(function.apply(getSecond()));
}
public void replaceWithContext(BiFunction<T, Boolean, T> function) {
replaceWithParams(function, TRUE_AND_FALSE);
}
public <S> void replaceWithParams(BiFunction<T, S, T> function, Couple<S> values) {
setFirst(function.apply(getFirst(), values.getFirst()));
setSecond(function.apply(getSecond(), values.getSecond()));
}
@Override
public void forEach(Consumer<? super T> consumer) {
consumer.accept(getFirst());
consumer.accept(getSecond());
}
public void forEachWithContext(BiConsumer<T, Boolean> consumer) {
forEachWithParams(consumer, TRUE_AND_FALSE);
}
public <S> void forEachWithParams(BiConsumer<T, S> function, Couple<S> values) {
function.accept(getFirst(), values.getFirst());
function.accept(getSecond(), values.getSecond());
}
public Couple<T> swap() {
return Couple.create(second, first);
}
public ListTag serializeEach(Function<T, CompoundTag> serializer) {
return NBTHelper.writeCompoundList(ImmutableList.of(first, second), serializer);
}
public static <S> Couple<S> deserializeEach(ListTag list, Function<CompoundTag, S> deserializer) {
List<S> readCompoundList = NBTHelper.readCompoundList(list, deserializer);
return new Couple<>(readCompoundList.get(0), readCompoundList.get(1));
}
@Override
public Iterator<T> iterator() {
return new Couplerator<>(this);
}
public Stream<T> stream() {
return Stream.of(first, second);
}
private static class Couplerator<T> implements Iterator<T> {
int state;
private final Couple<T> couple;
public Couplerator(Couple<T> couple) {
this.couple = couple;
state = 0;
}
@Override
public boolean hasNext() {
return state != 2;
}
@Override
public T next() {
state++;
if (state == 1)
return couple.first;
if (state == 2)
return couple.second;
return null;
}
}
}

View File

@@ -0,0 +1,102 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.registries.IForgeRegistry;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.create.Create;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class CreateRegistry<K, V> {
private static final List<CreateRegistry<?, ?>> ALL = new ArrayList<>();
protected final IForgeRegistry<K> objectRegistry;
protected final Map<ResourceLocation, V> locationMap = new HashMap<>();
protected final Map<K, V> objectMap = new IdentityHashMap<>();
protected boolean unwrapped = false;
public CreateRegistry(IForgeRegistry<K> objectRegistry) {
this.objectRegistry = objectRegistry;
ALL.add(this);
}
public void register(ResourceLocation location, V value) {
if (!unwrapped) {
locationMap.put(location, value);
} else {
K object = objectRegistry.getValue(location);
if (object != null) {
objectMap.put(object, value);
} else {
Create.LOGGER.warn("Could not get object for location '" + location + "' in CreateRegistry after unwrapping!");
}
}
}
public void register(K object, V value) {
if (unwrapped) {
objectMap.put(object, value);
} else {
ResourceLocation location = objectRegistry.getKey(object);
if (location != null) {
locationMap.put(location, value);
} else {
Create.LOGGER.warn("Could not get location of object '" + object + "' in CreateRegistry before unwrapping!");
}
}
}
@Nullable
public V get(ResourceLocation location) {
if (!unwrapped) {
return locationMap.get(location);
} else {
K object = objectRegistry.getValue(location);
if (object != null) {
return objectMap.get(object);
} else {
Create.LOGGER.warn("Could not get object for location '" + location + "' in CreateRegistry after unwrapping!");
return null;
}
}
}
@Nullable
public V get(K object) {
if (unwrapped) {
return objectMap.get(object);
} else {
ResourceLocation location = objectRegistry.getKey(object);
if (location != null) {
return locationMap.get(location);
} else {
Create.LOGGER.warn("Could not get location of object '" + object + "' in CreateRegistry before unwrapping!");
return null;
}
}
}
public boolean isUnwrapped() {
return unwrapped;
}
protected void unwrap() {
for (Map.Entry<ResourceLocation, V> entry : locationMap.entrySet()) {
ResourceLocation location = entry.getKey();
K object = objectRegistry.getValue(location);
if (object != null) {
objectMap.put(object, entry.getValue());
} else {
Create.LOGGER.warn("Could not get object for location '" + location + "' in CreateRegistry during unwrapping!");
}
}
unwrapped = true;
}
public static void unwrapAll() {
for (CreateRegistry<?, ?> registry : ALL) {
registry.unwrap();
}
}
}

View File

@@ -0,0 +1,67 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import nl.requios.effortlessbuilding.create.Create;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.util.thread.EffectiveSide;
/** Deprecated so simi doensn't forget to remove debug calls **/
@OnlyIn(value = Dist.CLIENT)
public class Debug {
@Deprecated
public static void debugChat(String message) {
if (Minecraft.getInstance().player != null)
Minecraft.getInstance().player.displayClientMessage(Components.literal(message), false);
}
@Deprecated
public static void debugChatAndShowStack(String message, int depth) {
if (Minecraft.getInstance().player != null)
Minecraft.getInstance().player.displayClientMessage(Components.literal(message).append("@")
.append(debugStack(depth)), false);
}
@Deprecated
public static void debugMessage(String message) {
if (Minecraft.getInstance().player != null)
Minecraft.getInstance().player.displayClientMessage(Components.literal(message), true);
}
@Deprecated
public static void log(String message) {
Create.LOGGER.info(message);
}
@Deprecated
public static String getLogicalSide() {
return EffectiveSide.get()
.isClient() ? "CL" : "SV";
}
@Deprecated
public static Component debugStack(int depth) {
StackTraceElement[] stackTraceElements = Thread.currentThread()
.getStackTrace();
MutableComponent text = Components.literal("[")
.append(Components.literal(getLogicalSide()).withStyle(ChatFormatting.GOLD))
.append("] ");
for (int i = 1; i < depth + 2 && i < stackTraceElements.length; i++) {
StackTraceElement e = stackTraceElements[i];
if (e.getClassName()
.equals(Debug.class.getName()))
continue;
text.append(Components.literal(e.getMethodName()).withStyle(ChatFormatting.YELLOW))
.append(", ");
}
return text.append(Components.literal(" ...").withStyle(ChatFormatting.GRAY));
}
@Deprecated
public static void markTemporary() {}
}

View File

@@ -0,0 +1,75 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import com.google.common.collect.ImmutableMap;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.Blocks;
import java.util.Map;
public class DyeHelper {
public static ItemLike getWoolOfDye(DyeColor color) {
switch (color) {
case BLACK:
return Blocks.BLACK_WOOL;
case BLUE:
return Blocks.BLUE_WOOL;
case BROWN:
return Blocks.BROWN_WOOL;
case CYAN:
return Blocks.CYAN_WOOL;
case GRAY:
return Blocks.GRAY_WOOL;
case GREEN:
return Blocks.GREEN_WOOL;
case LIGHT_BLUE:
return Blocks.LIGHT_BLUE_WOOL;
case LIGHT_GRAY:
return Blocks.LIGHT_GRAY_WOOL;
case LIME:
return Blocks.LIME_WOOL;
case MAGENTA:
return Blocks.MAGENTA_WOOL;
case ORANGE:
return Blocks.ORANGE_WOOL;
case PINK:
return Blocks.PINK_WOOL;
case PURPLE:
return Blocks.PURPLE_WOOL;
case RED:
return Blocks.RED_WOOL;
case YELLOW:
return Blocks.YELLOW_WOOL;
case WHITE:
default:
return Blocks.WHITE_WOOL;
}
}
public static final Map<DyeColor, Couple<Integer>> DYE_TABLE = new ImmutableMap.Builder<DyeColor, Couple<Integer>>()
// DyeColor, ( Front RGB, Back RGB )
.put(DyeColor.BLACK, Couple.create(0x45403B, 0x21201F))
.put(DyeColor.RED, Couple.create(0xB13937, 0x632737))
.put(DyeColor.GREEN, Couple.create(0x208A46, 0x1D6045))
.put(DyeColor.BROWN, Couple.create(0xAC855C, 0x68533E))
.put(DyeColor.BLUE, Couple.create(0x5391E1, 0x504B90))
.put(DyeColor.GRAY, Couple.create(0x5D666F, 0x313538))
.put(DyeColor.LIGHT_GRAY, Couple.create(0x95969B, 0x707070))
.put(DyeColor.PURPLE, Couple.create(0x9F54AE, 0x63366C))
.put(DyeColor.CYAN, Couple.create(0x3EABB4, 0x3C7872))
.put(DyeColor.PINK, Couple.create(0xD5A8CB, 0xB86B95))
.put(DyeColor.LIME, Couple.create(0xA3DF55, 0x4FB16F))
.put(DyeColor.YELLOW, Couple.create(0xE6D756, 0xE9AC29))
.put(DyeColor.LIGHT_BLUE, Couple.create(0x69CED2, 0x508AA5))
.put(DyeColor.ORANGE, Couple.create(0xEE9246, 0xD94927))
.put(DyeColor.MAGENTA, Couple.create(0xF062B0, 0xC04488))
.put(DyeColor.WHITE, Couple.create(0xEDEAE5, 0xBBB6B0))
.build();
}

View File

@@ -0,0 +1,94 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import nl.requios.effortlessbuilding.create.Create;
import net.minecraft.commands.CommandSource;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.ComponentUtils;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
public class DynamicComponent {
private JsonElement rawCustomText;
private Component parsedCustomText;
public DynamicComponent() {}
public void displayCustomText(Level level, BlockPos pos, String tagElement) {
if (tagElement == null)
return;
rawCustomText = getJsonFromString(tagElement);
parsedCustomText = parseCustomText(level, pos, rawCustomText);
}
public boolean sameAs(String tagElement) {
return isValid() && rawCustomText.equals(getJsonFromString(tagElement));
}
public boolean isValid() {
return parsedCustomText != null && rawCustomText != null;
}
public String resolve() {
return parsedCustomText.getString();
}
public MutableComponent get() {
return parsedCustomText == null ? Components.empty() : parsedCustomText.copy();
}
public void read(Level level, BlockPos pos, CompoundTag nbt) {
rawCustomText = getJsonFromString(nbt.getString("RawCustomText"));
try {
parsedCustomText = Component.Serializer.fromJson(nbt.getString("CustomText"));
} catch (JsonParseException e) {
parsedCustomText = null;
}
}
public void write(CompoundTag nbt) {
if (!isValid())
return;
nbt.putString("RawCustomText", rawCustomText.toString());
nbt.putString("CustomText", Component.Serializer.toJson(parsedCustomText));
}
public static JsonElement getJsonFromString(String string) {
try {
return JsonParser.parseString(string);
} catch (JsonParseException e) {
return null;
}
}
public static Component parseCustomText(Level level, BlockPos pos, JsonElement customText) {
if (!(level instanceof ServerLevel serverLevel))
return null;
try {
return ComponentUtils.updateForEntity(getCommandSource(serverLevel, pos),
Component.Serializer.fromJson(customText), null, 0);
} catch (JsonParseException e) {
return null;
} catch (CommandSyntaxException e) {
return null;
}
}
public static CommandSourceStack getCommandSource(ServerLevel level, BlockPos pos) {
return new CommandSourceStack(CommandSource.NULL, Vec3.atCenterOf(pos), Vec2.ZERO, level, 2, Create.ID,
Components.literal(Create.ID), level.getServer(), null);
}
}

View File

@@ -0,0 +1,101 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.internal.Streams;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import nl.requios.effortlessbuilding.create.Create;
import net.minecraft.nbt.CompoundTag;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class FilesHelper {
public static void createFolderIfMissing(String name) {
try {
Files.createDirectories(Paths.get(name));
} catch (IOException e) {
Create.LOGGER.warn("Could not create Folder: {}", name);
}
}
public static String findFirstValidFilename(String name, String folderPath, String extension) {
int index = 0;
String filename;
String filepath;
do {
filename = slug(name) + ((index == 0) ? "" : "_" + index) + "." + extension;
index++;
filepath = folderPath + "/" + filename;
} while (Files.exists(Paths.get(filepath)));
return filename;
}
public static String slug(String name) {
return Lang.asId(name)
.replaceAll("\\W+", "_");
}
public static boolean saveTagCompoundAsJson(CompoundTag compound, String path) {
try {
Files.deleteIfExists(Paths.get(path));
JsonWriter writer = new JsonWriter(Files.newBufferedWriter(Paths.get(path), StandardOpenOption.CREATE));
writer.setIndent(" ");
Streams.write(JsonParser.parseString(compound.toString()), writer);
writer.close();
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
public static boolean saveTagCompoundAsJsonCompact(CompoundTag compound, String path) {
try {
Files.deleteIfExists(Paths.get(path));
JsonWriter writer = new JsonWriter(Files.newBufferedWriter(Paths.get(path), StandardOpenOption.CREATE));
Streams.write(JsonParser.parseString(compound.toString()), writer);
writer.close();
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private static JsonElement loadJson(InputStream inputStream) {
try {
JsonReader reader = new JsonReader(new BufferedReader(new InputStreamReader(inputStream)));
reader.setLenient(true);
JsonElement element = Streams.parse(reader);
reader.close();
inputStream.close();
return element;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static JsonElement loadJsonResource(String filepath) {
return loadJson(ClassLoader.getSystemResourceAsStream(filepath));
}
public static JsonElement loadJson(String filepath) {
try {
return loadJson(Files.newInputStream(Paths.get(filepath), StandardOpenOption.READ));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

View File

@@ -0,0 +1,26 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.network.chat.MutableComponent;
public class FluidFormatter {
public static String asString(long amount, boolean shorten) {
Couple<MutableComponent> couple = asComponents(amount, shorten);
return couple.getFirst().getString() + " " + couple.getSecond().getString();
}
public static Couple<MutableComponent> asComponents(long amount, boolean shorten) {
if (shorten && amount >= 1000) {
return Couple.create(
Components.literal(String.format("%.1f" , amount / 1000d)),
Lang.translateDirect("generic.unit.buckets")
);
}
return Couple.create(
Components.literal(String.valueOf(amount)),
Lang.translateDirect("generic.unit.millibuckets")
);
}
}

View File

@@ -0,0 +1,87 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.math.Matrix4f;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import java.text.BreakIterator;
import java.util.LinkedList;
import java.util.List;
public final class FontHelper {
private FontHelper() {}
public static List<String> cutString(Font font, String text, int maxWidthPerLine) {
// Split words
List<String> words = new LinkedList<>();
BreakIterator iterator = BreakIterator.getLineInstance(Minecraft.getInstance().getLocale());
iterator.setText(text);
int start = iterator.first();
for (int end = iterator.next(); end != BreakIterator.DONE; start = end, end = iterator.next()) {
String word = text.substring(start, end);
words.add(word);
}
// Apply hard wrap
List<String> lines = new LinkedList<>();
StringBuilder currentLine = new StringBuilder();
int width = 0;
for (String word : words) {
int newWidth = font.width(word);
if (width + newWidth > maxWidthPerLine) {
if (width > 0) {
String line = currentLine.toString();
lines.add(line);
currentLine = new StringBuilder();
width = 0;
} else {
lines.add(word);
continue;
}
}
currentLine.append(word);
width += newWidth;
}
if (width > 0) {
lines.add(currentLine.toString());
}
return lines;
}
public static void drawSplitString(PoseStack ms, Font font, String text, int x, int y, int width,
int color) {
List<String> list = cutString(font, text, width);
Matrix4f matrix4f = ms.last()
.pose();
for (String s : list) {
float f = (float) x;
if (font.isBidirectional()) {
int i = font.width(font.bidirectionalShaping(s));
f += (float) (width - i);
}
draw(font, s, f, (float) y, color, matrix4f, false);
y += 9;
}
}
private static int draw(Font font, String p_228078_1_, float p_228078_2_, float p_228078_3_,
int p_228078_4_, Matrix4f p_228078_5_, boolean p_228078_6_) {
if (p_228078_1_ == null) {
return 0;
} else {
MultiBufferSource.BufferSource irendertypebuffer$impl = MultiBufferSource.immediate(Tesselator.getInstance()
.getBuilder());
int i = font.drawInBatch(p_228078_1_, p_228078_2_, p_228078_3_, p_228078_4_, p_228078_6_, p_228078_5_,
irendertypebuffer$impl, false, 0, LightTexture.FULL_BRIGHT);
irendertypebuffer$impl.endBatch();
return i;
}
}
}

View File

@@ -0,0 +1,8 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.core.BlockPos;
@FunctionalInterface
public interface ICoordinate {
float get(BlockPos from);
}

View File

@@ -0,0 +1,7 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.world.entity.player.Player;
public interface IInteractionChecker {
boolean canPlayerUse(Player player);
}

View File

@@ -0,0 +1,8 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.nbt.CompoundTag;
public interface IPartialSafeNBT {
/** This method always runs on the logical server. */
public void writeSafe(CompoundTag compound);
}

View File

@@ -0,0 +1,61 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.nbt.CompoundTag;
import java.util.Comparator;
import java.util.function.Function;
public class IntAttached<V> extends Pair<Integer, V> {
protected IntAttached(Integer first, V second) {
super(first, second);
}
public static <V> IntAttached<V> with(int number, V value) {
return new IntAttached<>(number, value);
}
public static <V> IntAttached<V> withZero(V value) {
return new IntAttached<>(0, value);
}
public boolean isZero() {
return first.intValue() == 0;
}
public boolean exceeds(int value) {
return first.intValue() > value;
}
public boolean isOrBelowZero() {
return first.intValue() <= 0;
}
public void increment() {
first++;
}
public void decrement() {
first--;
}
public V getValue() {
return getSecond();
}
public CompoundTag serializeNBT(Function<V, CompoundTag> serializer) {
CompoundTag nbt = new CompoundTag();
nbt.put("Item", serializer.apply(getValue()));
nbt.putInt("Location", getFirst());
return nbt;
}
public static Comparator<? super IntAttached<?>> comparator() {
return (i1, i2) -> Integer.compare(i2.getFirst(), i1.getFirst());
}
public static <T> IntAttached<T> read(CompoundTag nbt, Function<CompoundTag, T> deserializer) {
return IntAttached.with(nbt.getInt("Location"), deserializer.apply(nbt.getCompound("Item")));
}
}

View File

@@ -0,0 +1,48 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
public class Iterate {
public static final boolean[] trueAndFalse = { true, false };
public static final boolean[] falseAndTrue = { false, true };
public static final int[] zeroAndOne = { 0, 1 };
public static final int[] positiveAndNegative = { 1, -1 };
public static final Direction[] directions = Direction.values();
public static final Direction[] horizontalDirections = getHorizontals();
public static final Axis[] axes = Axis.values();
public static final EnumSet<Axis> axisSet = EnumSet.allOf(Axis.class);
private static Direction[] getHorizontals() {
Direction[] directions = new Direction[4];
for (int i = 0; i < 4; i++)
directions[i] = Direction.from2DDataValue(i);
return directions;
}
public static Direction[] directionsInAxis(Axis axis) {
switch (axis) {
case X:
return new Direction[] { Direction.EAST, Direction.WEST };
case Y:
return new Direction[] { Direction.UP, Direction.DOWN };
default:
case Z:
return new Direction[] { Direction.SOUTH, Direction.NORTH };
}
}
public static List<BlockPos> hereAndBelow(BlockPos pos) {
return Arrays.asList(pos, pos.below());
}
public static List<BlockPos> hereBelowAndAbove(BlockPos pos) {
return Arrays.asList(pos, pos.below(), pos.above());
}
}

View File

@@ -0,0 +1,91 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import nl.requios.effortlessbuilding.create.Create;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.fluids.FluidStack;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class Lang {
/**
* legacy-ish. Use Lang.translate and other builder methods where possible
*
* @param key
* @param args
* @return
*/
public static MutableComponent translateDirect(String key, Object... args) {
return Components.translatable(Create.ID + "." + key, resolveBuilders(args));
}
public static String asId(String name) {
return name.toLowerCase(Locale.ROOT);
}
public static String nonPluralId(String name) {
String asId = asId(name);
return asId.endsWith("s") ? asId.substring(0, asId.length() - 1) : asId;
}
public static List<Component> translatedOptions(String prefix, String... keys) {
List<Component> result = new ArrayList<>(keys.length);
for (String key : keys)
result.add(translate((prefix != null ? prefix + "." : "") + key).component());
return result;
}
//
public static LangBuilder builder() {
return new LangBuilder(Create.ID);
}
public static LangBuilder builder(String namespace) {
return new LangBuilder(namespace);
}
//
public static LangBuilder blockName(BlockState state) {
return builder().add(state.getBlock()
.getName());
}
public static LangBuilder itemName(ItemStack stack) {
return builder().add(stack.getHoverName()
.copy());
}
public static LangBuilder fluidName(FluidStack stack) {
return builder().add(stack.getDisplayName()
.copy());
}
public static LangBuilder number(double d) {
return builder().text(LangNumberFormat.format(d));
}
public static LangBuilder translate(String langKey, Object... args) {
return builder().translate(langKey, args);
}
public static LangBuilder text(String text) {
return builder().text(text);
}
//
public static Object[] resolveBuilders(Object[] args) {
for (int i = 0; i < args.length; i++)
if (args[i]instanceof LangBuilder cb)
args[i] = cb.component();
return args;
}
}

View File

@@ -0,0 +1,165 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import joptsimple.internal.Strings;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.entity.player.Player;
import java.util.List;
public class LangBuilder {
String namespace;
MutableComponent component;
public LangBuilder(String namespace) {
this.namespace = namespace;
}
public LangBuilder space() {
return text(" ");
}
public LangBuilder newLine() {
return text("\n");
}
/**
* Appends a localised component<br>
* To add an independently formatted localised component, use add() and a nested
* builder
*
* @param langKey
* @param args
* @return
*/
public LangBuilder translate(String langKey, Object... args) {
return add(Components.translatable(namespace + "." + langKey, Lang.resolveBuilders(args)));
}
/**
* Appends a text component
*
* @param literalText
* @return
*/
public LangBuilder text(String literalText) {
return add(Components.literal(literalText));
}
/**
* Appends a colored text component
*
* @param format
* @param literalText
* @return
*/
public LangBuilder text(ChatFormatting format, String literalText) {
return add(Components.literal(literalText).withStyle(format));
}
/**
* Appends a colored text component
*
* @param color
* @param literalText
* @return
*/
public LangBuilder text(int color, String literalText) {
return add(Components.literal(literalText).withStyle(s -> s.withColor(color)));
}
/**
* Appends the contents of another builder
*
* @param otherBuilder
* @return
*/
public LangBuilder add(LangBuilder otherBuilder) {
return add(otherBuilder.component());
}
/**
* Appends a component
*
* @param customComponent
* @return
*/
public LangBuilder add(MutableComponent customComponent) {
component = component == null ? customComponent : component.append(customComponent);
return this;
}
//
/**
* Applies the format to all added components
*
* @param format
* @return
*/
public LangBuilder style(ChatFormatting format) {
assertComponent();
component = component.withStyle(format);
return this;
}
/**
* Applies the color to all added components
*
* @param color
* @return
*/
public LangBuilder color(int color) {
assertComponent();
component = component.withStyle(s -> s.withColor(color));
return this;
}
//
public MutableComponent component() {
assertComponent();
return component;
}
public String string() {
return component().getString();
}
public String json() {
return Component.Serializer.toJson(component());
}
public void sendStatus(Player player) {
player.displayClientMessage(component(), true);
}
public void sendChat(Player player) {
player.displayClientMessage(component(), false);
}
public void addTo(List<? super MutableComponent> tooltip) {
tooltip.add(component());
}
public void forGoggles(List<? super MutableComponent> tooltip) {
forGoggles(tooltip, 0);
}
public void forGoggles(List<? super MutableComponent> tooltip, int indents) {
tooltip.add(Lang.builder()
.text(Strings.repeat(' ', 4 + indents))
.add(this)
.component());
}
//
private void assertComponent() {
if (component == null)
throw new IllegalStateException("No components were added to builder");
}
}

View File

@@ -0,0 +1,33 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.client.Minecraft;
import java.text.NumberFormat;
import java.util.Locale;
public class LangNumberFormat {
private NumberFormat format = NumberFormat.getNumberInstance(Locale.ROOT);
public static LangNumberFormat numberFormat = new LangNumberFormat();
public NumberFormat get() {
return format;
}
public void update() {
format = NumberFormat.getInstance(Minecraft.getInstance()
.getLanguageManager()
.getSelected()
.getJavaLocale());
format.setMaximumFractionDigits(2);
format.setMinimumFractionDigits(0);
format.setGroupingUsed(true);
}
public static String format(double d) {
return numberFormat.get()
.format(d)
.replace("\u00A0", " ");
}
}

View File

@@ -0,0 +1,106 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.core.Vec3i;
import net.minecraft.nbt.*;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.AABB;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
public class NBTHelper {
public static void putMarker(CompoundTag nbt, String marker) {
nbt.putBoolean(marker, true);
}
public static <T extends Enum<?>> T readEnum(CompoundTag nbt, String key, Class<T> enumClass) {
T[] enumConstants = enumClass.getEnumConstants();
if (enumConstants == null)
throw new IllegalArgumentException("Non-Enum class passed to readEnum: " + enumClass.getName());
if (nbt.contains(key, Tag.TAG_STRING)) {
String name = nbt.getString(key);
for (T t : enumConstants) {
if (t.name()
.equals(name))
return t;
}
}
return enumConstants[0];
}
public static <T extends Enum<?>> void writeEnum(CompoundTag nbt, String key, T enumConstant) {
nbt.putString(key, enumConstant.name());
}
public static <T> ListTag writeCompoundList(Iterable<T> list, Function<T, CompoundTag> serializer) {
ListTag listNBT = new ListTag();
list.forEach(t -> {
CompoundTag apply = serializer.apply(t);
if (apply == null)
return;
listNBT.add(apply);
});
return listNBT;
}
public static <T> List<T> readCompoundList(ListTag listNBT, Function<CompoundTag, T> deserializer) {
List<T> list = new ArrayList<>(listNBT.size());
listNBT.forEach(inbt -> list.add(deserializer.apply((CompoundTag) inbt)));
return list;
}
public static <T> void iterateCompoundList(ListTag listNBT, Consumer<CompoundTag> consumer) {
listNBT.forEach(inbt -> consumer.accept((CompoundTag) inbt));
}
public static ListTag writeItemList(Iterable<ItemStack> stacks) {
return writeCompoundList(stacks, ItemStack::serializeNBT);
}
public static List<ItemStack> readItemList(ListTag stacks) {
return readCompoundList(stacks, ItemStack::of);
}
public static ListTag writeAABB(AABB bb) {
ListTag bbtag = new ListTag();
bbtag.add(FloatTag.valueOf((float) bb.minX));
bbtag.add(FloatTag.valueOf((float) bb.minY));
bbtag.add(FloatTag.valueOf((float) bb.minZ));
bbtag.add(FloatTag.valueOf((float) bb.maxX));
bbtag.add(FloatTag.valueOf((float) bb.maxY));
bbtag.add(FloatTag.valueOf((float) bb.maxZ));
return bbtag;
}
public static AABB readAABB(ListTag bbtag) {
if (bbtag == null || bbtag.isEmpty())
return null;
return new AABB(bbtag.getFloat(0), bbtag.getFloat(1), bbtag.getFloat(2), bbtag.getFloat(3),
bbtag.getFloat(4), bbtag.getFloat(5));
}
public static ListTag writeVec3i(Vec3i vec) {
ListTag tag = new ListTag();
tag.add(IntTag.valueOf(vec.getX()));
tag.add(IntTag.valueOf(vec.getY()));
tag.add(IntTag.valueOf(vec.getZ()));
return tag;
}
public static Vec3i readVec3i(ListTag tag) {
return new Vec3i(tag.getInt(0), tag.getInt(1), tag.getInt(2));
}
@Nonnull
public static Tag getINBT(CompoundTag nbt, String id) {
Tag inbt = nbt.get(id);
if (inbt != null)
return inbt;
return new CompoundTag();
}
}

View File

@@ -0,0 +1,84 @@
package nl.requios.effortlessbuilding.create.foundation.utility;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.entity.SpawnerBlockEntity;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.function.UnaryOperator;
public final class NBTProcessors {
private static final Map<BlockEntityType<?>, UnaryOperator<CompoundTag>> processors = new HashMap<>();
private static final Map<BlockEntityType<?>, UnaryOperator<CompoundTag>> survivalProcessors = new HashMap<>();
public static synchronized void addProcessor(BlockEntityType<?> type, UnaryOperator<CompoundTag> processor) {
processors.put(type, processor);
}
public static synchronized void addSurvivalProcessor(BlockEntityType<?> type, UnaryOperator<CompoundTag> processor) {
survivalProcessors.put(type, processor);
}
static {
addProcessor(BlockEntityType.SIGN, data -> {
for (int i = 0; i < 4; ++i) {
if (textComponentHasClickEvent(data.getString("Text" + (i + 1))))
return null;
}
return data;
});
addProcessor(BlockEntityType.LECTERN, data -> {
if (!data.contains("Book", Tag.TAG_COMPOUND))
return data;
CompoundTag book = data.getCompound("Book");
if (!book.contains("tag", Tag.TAG_COMPOUND))
return data;
CompoundTag tag = book.getCompound("tag");
if (!tag.contains("pages", Tag.TAG_LIST))
return data;
ListTag pages = tag.getList("pages", Tag.TAG_STRING);
for (Tag inbt : pages) {
if (textComponentHasClickEvent(inbt.getAsString()))
return null;
}
return data;
});
}
public static boolean textComponentHasClickEvent(String json) {
Component component = Component.Serializer.fromJson(json.isEmpty() ? "\"\"" : json);
return component != null && component.getStyle() != null && component.getStyle().getClickEvent() != null;
}
private NBTProcessors() {
}
@Nullable
public static CompoundTag process(BlockEntity tileEntity, CompoundTag compound, boolean survival) {
if (compound == null)
return null;
BlockEntityType<?> type = tileEntity.getType();
if (survival && survivalProcessors.containsKey(type))
compound = survivalProcessors.get(type)
.apply(compound);
if (compound != null && processors.containsKey(type))
return processors.get(type)
.apply(compound);
if (tileEntity instanceof SpawnerBlockEntity)
return compound;
if (tileEntity.onlyOpCanSetNbt())
return null;
return compound;
}
}

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