From ddc846d860ae483fd088be3c2d98b6642e59526b Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Thu, 11 Jul 2019 09:03:08 +0200 Subject: [PATCH] Setup Infrastructure - Relevant Mod files - Relevant Classes - Resources - Added Symmetry Wand from TMA --- .gitignore | 42 +++ LICENSE | 21 ++ build.gradle | 149 ++++++++++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54708 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 172 ++++++++++++ gradlew.bat | 84 ++++++ .../java/com/simibubi/create/AllBlocks.java | 51 ++++ .../java/com/simibubi/create/AllItems.java | 42 +++ src/main/java/com/simibubi/create/Create.java | 62 +++++ .../com/simibubi/create/CreateItemGroup.java | 16 ++ .../java/com/simibubi/create/ScrollFixer.java | 50 ++++ .../create/block/IJustForRendering.java | 5 + .../create/block/symmetry/BlockSymmetry.java | 13 + .../symmetry/BlockSymmetryCrossPlane.java | 27 ++ .../block/symmetry/BlockSymmetryPlane.java | 26 ++ .../symmetry/BlockSymmetryTriplePlane.java | 12 + .../create/gui/AbstractSimiScreen.java | 101 +++++++ .../com/simibubi/create/gui/GuiOpener.java | 26 ++ .../com/simibubi/create/gui/GuiResources.java | 89 ++++++ .../simibubi/create/gui/GuiWandSymmetry.java | 178 ++++++++++++ .../gui/widgets/AbstractSimiWidget.java | 25 ++ .../create/gui/widgets/DynamicLabel.java | 42 +++ .../create/gui/widgets/GuiIndicator.java | 35 +++ .../create/gui/widgets/OptionScrollArea.java | 47 ++++ .../create/gui/widgets/ScrollArea.java | 239 ++++++++++++++++ .../create/gui/widgets/SimiButton.java | 57 ++++ .../create/item/ItemWandSymmetry.java | 191 +++++++++++++ .../simibubi/create/item/SymmetryHandler.java | 177 ++++++++++++ .../item/symmetry/SymmetryCrossPlane.java | 96 +++++++ .../create/item/symmetry/SymmetryElement.java | 255 ++++++++++++++++++ .../item/symmetry/SymmetryEmptySlot.java | 60 +++++ .../create/item/symmetry/SymmetryPlane.java | 91 +++++++ .../item/symmetry/SymmetryTriplePlane.java | 66 +++++ .../simibubi/create/networking/PacketNbt.java | 36 +++ .../networking/PacketSymmetryEffect.java | 50 ++++ .../simibubi/create/networking/Packets.java | 23 ++ .../com/simibubi/create/utility/Keyboard.java | 30 +++ .../create/utility/TessellatorHelper.java | 216 +++++++++++++++ src/main/resources/META-INF/mods.toml | 56 ++++ .../blockstates/symmetry_crossplane.json | 7 + .../create/blockstates/symmetry_plane.json | 7 + .../blockstates/symmetry_tripleplane.json | 6 + .../resources/assets/create/lang/en_us.json | 4 + .../models/block/symmetry_crossplane.json | 144 ++++++++++ .../block/symmetry_crossplane_diagonal.json | 148 ++++++++++ .../create/models/block/symmetry_plane.json | 99 +++++++ .../models/block/symmetry_tripleplane.json | 172 ++++++++++++ .../create/models/item/symmetry_wand.json | 253 +++++++++++++++++ .../create/textures/block/marker/exporter.png | Bin 0 -> 258 bytes .../create/textures/block/marker/heavy.png | Bin 0 -> 391 bytes .../create/textures/block/marker/inner.png | Bin 0 -> 177 bytes .../textures/block/marker/inner_selected.png | Bin 0 -> 231 bytes .../block/marker/inner_super_selected.png | Bin 0 -> 249 bytes .../block/marker/inner_transparent.png | Bin 0 -> 183 bytes .../create/textures/block/marker/light.png | Bin 0 -> 331 bytes .../create/textures/block/marker/select.png | Bin 0 -> 243 bytes .../create/textures/block/marker/trim.png | Bin 0 -> 215 bytes .../assets/create/textures/gui/background.png | Bin 0 -> 179 bytes .../assets/create/textures/gui/icons.png | Bin 0 -> 2194 bytes .../create/textures/gui/player_inventory.png | Bin 0 -> 2621 bytes .../create/textures/gui/wand_symmetry.png | Bin 0 -> 1854 bytes .../assets/create/textures/gui/widgets.png | Bin 0 -> 4289 bytes .../create/textures/item/blueprint_empty.png | Bin 0 -> 317 bytes .../create/textures/item/blueprint_filled.png | Bin 0 -> 351 bytes src/main/resources/pack.mcmeta | 6 + 66 files changed, 3809 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 src/main/java/com/simibubi/create/AllBlocks.java create mode 100644 src/main/java/com/simibubi/create/AllItems.java create mode 100644 src/main/java/com/simibubi/create/Create.java create mode 100644 src/main/java/com/simibubi/create/CreateItemGroup.java create mode 100644 src/main/java/com/simibubi/create/ScrollFixer.java create mode 100644 src/main/java/com/simibubi/create/block/IJustForRendering.java create mode 100644 src/main/java/com/simibubi/create/block/symmetry/BlockSymmetry.java create mode 100644 src/main/java/com/simibubi/create/block/symmetry/BlockSymmetryCrossPlane.java create mode 100644 src/main/java/com/simibubi/create/block/symmetry/BlockSymmetryPlane.java create mode 100644 src/main/java/com/simibubi/create/block/symmetry/BlockSymmetryTriplePlane.java create mode 100644 src/main/java/com/simibubi/create/gui/AbstractSimiScreen.java create mode 100644 src/main/java/com/simibubi/create/gui/GuiOpener.java create mode 100644 src/main/java/com/simibubi/create/gui/GuiResources.java create mode 100644 src/main/java/com/simibubi/create/gui/GuiWandSymmetry.java create mode 100644 src/main/java/com/simibubi/create/gui/widgets/AbstractSimiWidget.java create mode 100644 src/main/java/com/simibubi/create/gui/widgets/DynamicLabel.java create mode 100644 src/main/java/com/simibubi/create/gui/widgets/GuiIndicator.java create mode 100644 src/main/java/com/simibubi/create/gui/widgets/OptionScrollArea.java create mode 100644 src/main/java/com/simibubi/create/gui/widgets/ScrollArea.java create mode 100644 src/main/java/com/simibubi/create/gui/widgets/SimiButton.java create mode 100644 src/main/java/com/simibubi/create/item/ItemWandSymmetry.java create mode 100644 src/main/java/com/simibubi/create/item/SymmetryHandler.java create mode 100644 src/main/java/com/simibubi/create/item/symmetry/SymmetryCrossPlane.java create mode 100644 src/main/java/com/simibubi/create/item/symmetry/SymmetryElement.java create mode 100644 src/main/java/com/simibubi/create/item/symmetry/SymmetryEmptySlot.java create mode 100644 src/main/java/com/simibubi/create/item/symmetry/SymmetryPlane.java create mode 100644 src/main/java/com/simibubi/create/item/symmetry/SymmetryTriplePlane.java create mode 100644 src/main/java/com/simibubi/create/networking/PacketNbt.java create mode 100644 src/main/java/com/simibubi/create/networking/PacketSymmetryEffect.java create mode 100644 src/main/java/com/simibubi/create/networking/Packets.java create mode 100644 src/main/java/com/simibubi/create/utility/Keyboard.java create mode 100644 src/main/java/com/simibubi/create/utility/TessellatorHelper.java create mode 100644 src/main/resources/META-INF/mods.toml create mode 100644 src/main/resources/assets/create/blockstates/symmetry_crossplane.json create mode 100644 src/main/resources/assets/create/blockstates/symmetry_plane.json create mode 100644 src/main/resources/assets/create/blockstates/symmetry_tripleplane.json create mode 100644 src/main/resources/assets/create/lang/en_us.json create mode 100644 src/main/resources/assets/create/models/block/symmetry_crossplane.json create mode 100644 src/main/resources/assets/create/models/block/symmetry_crossplane_diagonal.json create mode 100644 src/main/resources/assets/create/models/block/symmetry_plane.json create mode 100644 src/main/resources/assets/create/models/block/symmetry_tripleplane.json create mode 100644 src/main/resources/assets/create/models/item/symmetry_wand.json create mode 100644 src/main/resources/assets/create/textures/block/marker/exporter.png create mode 100644 src/main/resources/assets/create/textures/block/marker/heavy.png create mode 100644 src/main/resources/assets/create/textures/block/marker/inner.png create mode 100644 src/main/resources/assets/create/textures/block/marker/inner_selected.png create mode 100644 src/main/resources/assets/create/textures/block/marker/inner_super_selected.png create mode 100644 src/main/resources/assets/create/textures/block/marker/inner_transparent.png create mode 100644 src/main/resources/assets/create/textures/block/marker/light.png create mode 100644 src/main/resources/assets/create/textures/block/marker/select.png create mode 100644 src/main/resources/assets/create/textures/block/marker/trim.png create mode 100644 src/main/resources/assets/create/textures/gui/background.png create mode 100644 src/main/resources/assets/create/textures/gui/icons.png create mode 100644 src/main/resources/assets/create/textures/gui/player_inventory.png create mode 100644 src/main/resources/assets/create/textures/gui/wand_symmetry.png create mode 100644 src/main/resources/assets/create/textures/gui/widgets.png create mode 100644 src/main/resources/assets/create/textures/item/blueprint_empty.png create mode 100644 src/main/resources/assets/create/textures/item/blueprint_filled.png create mode 100644 src/main/resources/pack.mcmeta diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..f8a3cd828 --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +## Based on GitHub's Eclipse .gitignore + +run/ +.gradle/ +build/ +gradle-app.setting + +## IntelliJ IDEA + +.idea/ +*.iml +*.iws +*.ipr + +## Eclipse + +eclipse/ +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..21d4f1bda --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 simibubi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..af8cd416c --- /dev/null +++ b/build.gradle @@ -0,0 +1,149 @@ +buildscript { + repositories { + maven { url = 'https://files.minecraftforge.net/maven' } + jcenter() + mavenCentral() + } + dependencies { + classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true + } +} +apply plugin: 'net.minecraftforge.gradle' +// 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 = '0.0.1' +group = 'com.simibubi.create' // http://maven.apache.org/guides/mini/guide-naming-conventions.html +archivesBaseName = 'create' + +sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly. + +minecraft { + // The mappings can be changed at any time, and must be in the following format. + // snapshot_YYYYMMDD Snapshot are built nightly. + // stable_# Stables are built at the discretion of the MCP team. + // 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. + mappings channel: 'snapshot', version: '20190621-1.14.2' + // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. + + // accessTransformer = file('build/resources/main/META-INF/accesstransformer.cfg') + + // Default run configurations. + // These can be tweaked, removed, or duplicated as needed. + runs { + client { + workingDirectory project.file('run') + + // Recommended logging data for a userdev environment + property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' + + // Recommended logging level for the console + property 'forge.logging.console.level', 'debug' + + mods { + create { + source sourceSets.main + } + } + } + + server { + workingDirectory project.file('run') + + // Recommended logging data for a userdev environment + property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' + + // Recommended logging level for the console + property 'forge.logging.console.level', 'debug' + + mods { + create { + source sourceSets.main + } + } + } + + data { + workingDirectory project.file('run') + + // Recommended logging data for a userdev environment + property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' + + // Recommended logging level for the console + property 'forge.logging.console.level', 'debug' + + args '--mod', 'create', '--all', '--output', file('src/generated/resources/') + + mods { + create { + source sourceSets.main + } + } + } + } +} + +dependencies { + // Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed + // that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied. + // The userdev artifact is a special name and will get all sorts of transformations applied to it. + minecraft 'net.minecraftforge:forge:1.14.3-27.0.43' + + // You may put jars on which you depend on in ./libs or you may define them like so.. + // compile "some.group:artifact:version:classifier" + // compile "some.group:artifact:version" + + // Real examples + // compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env + // 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... + // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html + // http://www.gradle.org/docs/current/userguide/dependency_management.html + +} + +// Example for how to get properties into the manifest for reading by the runtime.. +jar { + manifest { + attributes([ + "Specification-Title": "create", + "Specification-Vendor": "simibubi", + "Specification-Version": "1", // We are version 1 of ourselves + "Implementation-Title": project.name, + "Implementation-Version": "${version}", + "Implementation-Vendor" :"simibubi", + "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") + ]) + } +} + +// Example configuration to allow publishing using the maven-publish task +// we define a custom artifact that is sourced from the reobfJar output task +// and then declare that to be published +// Note you'll need to add a repository here +def reobfFile = file("$buildDir/reobfJar/output.jar") +def reobfArtifact = artifacts.add('default', reobfFile) { + type 'jar' + builtBy 'reobfJar' +} +publishing { + publications { + mavenJava(MavenPublication) { + artifact reobfArtifact + } + } + repositories { + maven { + url "file:///${project.projectDir}/mcmodsrepo" + } + } +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7a3265ee94c0ab25cf079ac8ccdf87f41d455d42 GIT binary patch literal 54708 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

_x$+l{{cH8$W#CT literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..949819d28 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip diff --git a/gradlew b/gradlew new file mode 100644 index 000000000..cccdd3d51 --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..f9553162f --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java new file mode 100644 index 000000000..86754b354 --- /dev/null +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -0,0 +1,51 @@ +package com.simibubi.create; + +import com.simibubi.create.block.IJustForRendering; +import com.simibubi.create.block.symmetry.BlockSymmetryCrossPlane; +import com.simibubi.create.block.symmetry.BlockSymmetryPlane; +import com.simibubi.create.block.symmetry.BlockSymmetryTriplePlane; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraftforge.registries.IForgeRegistry; + +public enum AllBlocks { + + SYMMETRY_PLANE(new BlockSymmetryPlane()), + SYMMETRY_CROSSPLANE(new BlockSymmetryCrossPlane()), + SYMMETRY_TRIPLEPLANE(new BlockSymmetryTriplePlane()); + + public Block block; + + private AllBlocks(Block block) { + this.block = block; + this.block.setRegistryName(Create.ID, this.name().toLowerCase()); + } + + public static void registerBlocks(IForgeRegistry registry) { + for (AllBlocks block : values()) { + registry.register(block.block); + } + } + + public static void registerItemBlocks(IForgeRegistry registry) { + for (AllBlocks block : values()) { + if (block.get() instanceof IJustForRendering) + continue; + + registry.register(new BlockItem(block.get(), AllItems.standardProperties()) + .setRegistryName(block.get().getRegistryName())); + } + } + + public Block get() { + return block; + } + + public boolean typeOf(BlockState state) { + return state.getBlock() == block; + } + +} diff --git a/src/main/java/com/simibubi/create/AllItems.java b/src/main/java/com/simibubi/create/AllItems.java new file mode 100644 index 000000000..ddca40375 --- /dev/null +++ b/src/main/java/com/simibubi/create/AllItems.java @@ -0,0 +1,42 @@ +package com.simibubi.create; + +import com.simibubi.create.item.ItemWandSymmetry; + +import net.minecraft.item.Item; +import net.minecraft.item.Item.Properties; +import net.minecraft.item.ItemStack; +import net.minecraftforge.registries.IForgeRegistry; + +public enum AllItems { + + SYMMETRY_WAND(new ItemWandSymmetry(standardProperties())); + + public Item item; + + private AllItems(Item item) { + this.item = item; + this.item.setRegistryName(Create.ID, this.name().toLowerCase()); + } + + public static Properties standardProperties() { + return new Properties().group(Create.creativeTab); + } + + public static void registerItems(IForgeRegistry iForgeRegistry) { + for (AllItems item : values()) { + iForgeRegistry.register(item.get()); + } + } + + public Item get() { + return item; + } + + public boolean typeOf(ItemStack stack) { + return stack.getItem() == item; + } + + public static void initColorHandlers() { + } + +} diff --git a/src/main/java/com/simibubi/create/Create.java b/src/main/java/com/simibubi/create/Create.java new file mode 100644 index 000000000..efdbe56e3 --- /dev/null +++ b/src/main/java/com/simibubi/create/Create.java @@ -0,0 +1,62 @@ +package com.simibubi.create; + +import org.apache.logging.log4j.Logger; + +import com.simibubi.create.networking.Packets; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroup; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; + +@EventBusSubscriber(bus = Bus.FORGE) +@Mod(Create.ID) +public class Create { + + public static final String ID = "create"; + public static final String NAME = "Create"; + public static final String VERSION = "0.0.1"; + + public static Logger logger; + + public static ItemGroup creativeTab = new CreateItemGroup(); + + public Create() { + IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + modEventBus.addListener(this::clientInit); + modEventBus.addListener(this::init); + } + + private void clientInit(FMLClientSetupEvent event) { + AllItems.initColorHandlers(); + +// ScrollFixer.init(); + } + + private void init(final FMLCommonSetupEvent event) { + Packets.registerPackets(); + } + + @EventBusSubscriber(bus = Bus.MOD) + public static class RegistryListener { + + @SubscribeEvent + public static void registerItems(RegistryEvent.Register event) { + AllItems.registerItems(event.getRegistry()); + AllBlocks.registerItemBlocks(event.getRegistry()); + } + + @SubscribeEvent + public static void registerBlocks(RegistryEvent.Register event) { + AllBlocks.registerBlocks(event.getRegistry()); + } + } +} diff --git a/src/main/java/com/simibubi/create/CreateItemGroup.java b/src/main/java/com/simibubi/create/CreateItemGroup.java new file mode 100644 index 000000000..381e5ff6c --- /dev/null +++ b/src/main/java/com/simibubi/create/CreateItemGroup.java @@ -0,0 +1,16 @@ +package com.simibubi.create; + +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; + +public final class CreateItemGroup extends ItemGroup { + + public CreateItemGroup() { + super(getGroupCountSafe(), Create.ID); + } + + @Override + public ItemStack createIcon() { + return new ItemStack(AllItems.SYMMETRY_WAND.get()); + } +} diff --git a/src/main/java/com/simibubi/create/ScrollFixer.java b/src/main/java/com/simibubi/create/ScrollFixer.java new file mode 100644 index 000000000..d896a94c3 --- /dev/null +++ b/src/main/java/com/simibubi/create/ScrollFixer.java @@ -0,0 +1,50 @@ +package com.simibubi.create; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; + +import org.lwjgl.glfw.GLFW; +import org.lwjgl.glfw.GLFWScrollCallback; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.MouseHelper; + +public class ScrollFixer { + + private static List> listeners; + + public static void init() { + listeners = new ArrayList<>(); + Method method; + try { + MouseHelper mouseHelper = Minecraft.getInstance().mouseHelper; + method = mouseHelper.getClass().getDeclaredMethod("scrollCallback", Long.TYPE, + Double.TYPE, Double.TYPE); + method.setAccessible(true); + GLFW.glfwSetScrollCallback(Minecraft.getInstance().mainWindow.getHandle(), new GLFWScrollCallback() { + @Override + public void invoke(long win, double dx, double dy) { + for (Predicate consumer : listeners) { + if (consumer.test(dy)) + return; + } + try { + method.invoke(mouseHelper, win, dx, dy); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + e.printStackTrace(); + } + } + }); + } catch (NoSuchMethodException | SecurityException e1) { + e1.printStackTrace(); + } + } + + public static void addMouseWheelListener(Predicate callback) { + listeners.add(callback); + } + +} diff --git a/src/main/java/com/simibubi/create/block/IJustForRendering.java b/src/main/java/com/simibubi/create/block/IJustForRendering.java new file mode 100644 index 000000000..580ab5fde --- /dev/null +++ b/src/main/java/com/simibubi/create/block/IJustForRendering.java @@ -0,0 +1,5 @@ +package com.simibubi.create.block; + +public interface IJustForRendering { + +} diff --git a/src/main/java/com/simibubi/create/block/symmetry/BlockSymmetry.java b/src/main/java/com/simibubi/create/block/symmetry/BlockSymmetry.java new file mode 100644 index 000000000..880782ad6 --- /dev/null +++ b/src/main/java/com/simibubi/create/block/symmetry/BlockSymmetry.java @@ -0,0 +1,13 @@ +package com.simibubi.create.block.symmetry; + +import com.simibubi.create.block.IJustForRendering; + +import net.minecraft.block.Block; + +public class BlockSymmetry extends Block implements IJustForRendering { + + public BlockSymmetry(Properties properties) { + super(properties); + } + +} diff --git a/src/main/java/com/simibubi/create/block/symmetry/BlockSymmetryCrossPlane.java b/src/main/java/com/simibubi/create/block/symmetry/BlockSymmetryCrossPlane.java new file mode 100644 index 000000000..31e471585 --- /dev/null +++ b/src/main/java/com/simibubi/create/block/symmetry/BlockSymmetryCrossPlane.java @@ -0,0 +1,27 @@ +package com.simibubi.create.block.symmetry; + +import com.simibubi.create.item.symmetry.SymmetryCrossPlane; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.material.Material; +import net.minecraft.state.EnumProperty; +import net.minecraft.state.StateContainer.Builder; + +public class BlockSymmetryCrossPlane extends BlockSymmetry { + + public static final EnumProperty align = EnumProperty.create("align", + SymmetryCrossPlane.Align.class); + + public BlockSymmetryCrossPlane() { + super(Properties.create(Material.AIR)); + this.setDefaultState(getDefaultState().with(align, SymmetryCrossPlane.Align.Y)); + } + + @Override + protected void fillStateContainer(Builder builder) { + builder.add(align); + super.fillStateContainer(builder); + } + +} diff --git a/src/main/java/com/simibubi/create/block/symmetry/BlockSymmetryPlane.java b/src/main/java/com/simibubi/create/block/symmetry/BlockSymmetryPlane.java new file mode 100644 index 000000000..3c0fe2f42 --- /dev/null +++ b/src/main/java/com/simibubi/create/block/symmetry/BlockSymmetryPlane.java @@ -0,0 +1,26 @@ +package com.simibubi.create.block.symmetry; + +import com.simibubi.create.item.symmetry.SymmetryPlane; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.material.Material; +import net.minecraft.state.EnumProperty; +import net.minecraft.state.StateContainer.Builder; + +public class BlockSymmetryPlane extends BlockSymmetry { + + public static final EnumProperty align = EnumProperty.create("align", SymmetryPlane.Align.class); + + public BlockSymmetryPlane() { + super(Properties.create(Material.AIR)); + this.setDefaultState(getDefaultState().with(align, SymmetryPlane.Align.XY)); + } + + @Override + protected void fillStateContainer(Builder builder) { + builder.add(align); + super.fillStateContainer(builder); + } + +} diff --git a/src/main/java/com/simibubi/create/block/symmetry/BlockSymmetryTriplePlane.java b/src/main/java/com/simibubi/create/block/symmetry/BlockSymmetryTriplePlane.java new file mode 100644 index 000000000..e63f32f7e --- /dev/null +++ b/src/main/java/com/simibubi/create/block/symmetry/BlockSymmetryTriplePlane.java @@ -0,0 +1,12 @@ +package com.simibubi.create.block.symmetry; + +import net.minecraft.block.material.Material; + +public class BlockSymmetryTriplePlane extends BlockSymmetry { + + public BlockSymmetryTriplePlane() { + super(Properties.create(Material.AIR)); + } + + +} diff --git a/src/main/java/com/simibubi/create/gui/AbstractSimiScreen.java b/src/main/java/com/simibubi/create/gui/AbstractSimiScreen.java new file mode 100644 index 000000000..5f01b4b92 --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/AbstractSimiScreen.java @@ -0,0 +1,101 @@ +package com.simibubi.create.gui; + +import java.util.ArrayList; +import java.util.List; + +import com.simibubi.create.gui.widgets.AbstractSimiWidget; + +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.Widget; +import net.minecraft.util.text.StringTextComponent; + +public abstract class AbstractSimiScreen extends Screen { + + protected int sWidth, sHeight; + protected int topLeftX, topLeftY; + protected List widgets; + + protected AbstractSimiScreen() { + super(new StringTextComponent("")); + widgets = new ArrayList<>(); + } + + protected void setWindowSize(int width, int height) { + sWidth = width; + sHeight = height; + topLeftX = (this.width - sWidth) / 2; + topLeftY = (this.height - sHeight) / 2; + } + + @Override + public void render(int mouseX, int mouseY, float partialTicks) { + renderBackground(); + renderWindow(mouseX, mouseY, partialTicks); + for (Widget widget : widgets) + widget.render(mouseX, mouseY, partialTicks); + renderWindowForeground(mouseX, mouseY, partialTicks); + for (Widget widget : widgets) + widget.renderToolTip(mouseX, mouseY); + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + boolean result = false; + for (Widget widget : widgets) { + if (widget.mouseClicked(x, y, button)) + result = true; + } + return result; + } + + @Override + public boolean keyPressed(int code, int p_keyPressed_2_, int p_keyPressed_3_) { + for (Widget widget : widgets) { + if (widget.keyPressed(code, p_keyPressed_2_, p_keyPressed_3_)) + return true; + } + return super.keyPressed(code, p_keyPressed_2_, p_keyPressed_3_); + } + + @Override + public boolean charTyped(char character, int code) { + for (Widget widget : widgets) { + if (widget.charTyped(character, code)) + return true; + } + return super.charTyped(character, code); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double delta) { + for (Widget widget : widgets) { + if (widget.mouseScrolled(mouseX, mouseY, delta)) + return true; + } + return super.mouseScrolled(mouseX, mouseY, delta); + } + + @Override + public boolean shouldCloseOnEsc() { + return true; + } + + @Override + public boolean isPauseScreen() { + return false; + } + + protected abstract void renderWindow(int mouseX, int mouseY, float partialTicks); + + protected void renderWindowForeground(int mouseX, int mouseY, float partialTicks) { + for (Widget widget : widgets) { + if (!widget.isHovered()) + continue; + + if (widget instanceof AbstractSimiWidget && !((AbstractSimiWidget) widget).getToolTip().isEmpty()) { + renderTooltip(((AbstractSimiWidget) widget).getToolTip(), mouseX, mouseY); + } + } + } + +} diff --git a/src/main/java/com/simibubi/create/gui/GuiOpener.java b/src/main/java/com/simibubi/create/gui/GuiOpener.java new file mode 100644 index 000000000..74112956f --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/GuiOpener.java @@ -0,0 +1,26 @@ +package com.simibubi.create.gui; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.Screen; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent; + +@EventBusSubscriber +public class GuiOpener { + + private static Screen openedGuiNextTick; + + @SubscribeEvent + public static void onClientTick(ClientTickEvent event) { + if (openedGuiNextTick != null) { + Minecraft.getInstance().displayGuiScreen(openedGuiNextTick); + openedGuiNextTick = null; + } + } + + public static void open(Screen gui) { + openedGuiNextTick = gui; + } + +} diff --git a/src/main/java/com/simibubi/create/gui/GuiResources.java b/src/main/java/com/simibubi/create/gui/GuiResources.java new file mode 100644 index 000000000..8941318cc --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/GuiResources.java @@ -0,0 +1,89 @@ +package com.simibubi.create.gui; + +import com.simibubi.create.Create; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.AbstractGui; +import net.minecraft.util.ResourceLocation; + +public enum GuiResources { + + // Inventories + PLAYER_INVENTORY("player_inventory.png", 176, 108), + COMPOSER("composer.png", 256, 58), + PALETTES("palette_picker.png", 256, 236), + EXPORTER("design_exporter.png", 200, 111), + THEME_EDITOR("theme_editor.png", 200, 187), + WAND_SYMMETRY("wand_symmetry.png", 207, 58), + + // Widgets + PALETTE_BUTTON("palette_picker.png", 0, 236, 20, 20), + TEXT_INPUT("widgets.png", 0, 28, 194, 47), + BUTTON("widgets.png", 18, 18), + BUTTON_HOVER("widgets.png", 18, 0, 18, 18), + BUTTON_DOWN("widgets.png", 36, 0, 18, 18), + INDICATOR("widgets.png", 0, 18, 18, 5), + INDICATOR_WHITE("widgets.png", 18, 18, 18, 5), + INDICATOR_GREEN("widgets.png", 0, 23, 18, 5), + INDICATOR_YELLOW("widgets.png", 18, 23, 18, 5), + INDICATOR_RED("widgets.png", 36, 23, 18, 5), + GRAY("background.png", 0, 0, 16, 16), + + SCROLLBAR_AXIS("widgets.png", 224, 0, 32, 256), + SCROLLBAR_CAP("widgets.png", 0, 87, 40, 6), + SCROLLBAR_INDICATOR("widgets.png", 0, 75, 40, 12), + SCROLLBAR_BACKGROUND("widgets.png", 0, 93, 40, 16), + + // Icons + ICON_NONE("icons.png", 16, 16, 16, 16), + ICON_ADD("icons.png", 16, 16), + ICON_TRASH("icons.png", 16, 0, 16, 16), + ICON_3x3("icons.png", 32, 0, 16, 16), + ICON_TARGET("icons.png", 48, 0, 16, 16), + ICON_CONFIRM("icons.png", 0, 16, 16, 16), + + ICON_NORMAL_ROOF("icons.png", 32, 16, 16, 16), + ICON_FLAT_ROOF("icons.png", 48, 16, 16, 16), + ICON_NO_ROOF("icons.png", 0, 32, 16, 16), + + ICON_TOWER_NO_ROOF("icons.png", 16, 32, 16, 16), + ICON_TOWER_ROOF("icons.png", 32, 32, 16, 16), + ICON_TOWER_FLAT_ROOF("icons.png", 48, 32, 16, 16), + + ICON_LAYER_REGULAR("icons.png", 0, 48, 16, 16), + ICON_LAYER_OPEN("icons.png", 16, 48, 16, 16), + ICON_LAYER_FOUNDATION("icons.png", 32, 48, 16, 16), + ICON_LAYER_SPECIAL("icons.png", 48, 48, 16, 16), + + ICON_TOOL_RESHAPE("icons.png", 0, 64, 16, 16), + ICON_TOOL_ROOM("icons.png", 16, 64, 16, 16), + ICON_TOOL_TOWER("icons.png", 32, 64, 16, 16), + ICON_TOOL_STACK("icons.png", 48, 64, 16, 16), + + ICON_TOOL_HEIGHT("icons.png", 0, 80, 16, 16), + ICON_TOOL_REROLL("icons.png", 16, 80, 16, 16), + ICON_TOOL_REROLL_TARGET("icons.png", 32, 80, 16, 16), + ICON_TOOL_PALETTE("icons.png", 48, 80, 16, 16); + + public static final int FONT_COLOR = 0x575F7A; + + public final ResourceLocation location; + public int width, height; + public int startX, startY; + + private GuiResources(String location, int width, int height) { + this(location, 0, 0, width, height); + } + + private GuiResources(String location, int startX, int startY, int width, int height) { + this.location = new ResourceLocation(Create.ID, "textures/gui/" + location); + this.width = width; this.height = height; + this.startX = startX; this.startY = startY; + } + + public void draw(AbstractGui screen, int i, int j) { + Minecraft.getInstance().getTextureManager().bindTexture(location); + screen.blit(i, j, startX, startY, width, height); + } + +} diff --git a/src/main/java/com/simibubi/create/gui/GuiWandSymmetry.java b/src/main/java/com/simibubi/create/gui/GuiWandSymmetry.java new file mode 100644 index 000000000..bf16d9d89 --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/GuiWandSymmetry.java @@ -0,0 +1,178 @@ +package com.simibubi.create.gui; + +import org.lwjgl.opengl.GL11; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.gui.widgets.DynamicLabel; +import com.simibubi.create.gui.widgets.OptionScrollArea; +import com.simibubi.create.gui.widgets.ScrollArea; +import com.simibubi.create.item.ItemWandSymmetry; +import com.simibubi.create.item.symmetry.SymmetryCrossPlane; +import com.simibubi.create.item.symmetry.SymmetryElement; +import com.simibubi.create.item.symmetry.SymmetryEmptySlot; +import com.simibubi.create.item.symmetry.SymmetryPlane; +import com.simibubi.create.item.symmetry.SymmetryTriplePlane; +import com.simibubi.create.networking.PacketNbt; +import com.simibubi.create.networking.Packets; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.AtlasTexture; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.client.model.data.EmptyModelData; +import net.minecraftforge.fml.network.PacketDistributor; + +public class GuiWandSymmetry extends AbstractSimiScreen { + + private ScrollArea areaType; + private DynamicLabel labelType; + private ScrollArea areaAlign; + private DynamicLabel labelAlign; + + private SymmetryElement currentElement; + private float animationProgress; + private ItemStack wand; + + public GuiWandSymmetry(ItemStack wand) { + super(); + + currentElement = ItemWandSymmetry.getMirror(wand); + if (currentElement instanceof SymmetryEmptySlot) { + currentElement = new SymmetryPlane(Vec3d.ZERO); + } + this.wand = wand; + animationProgress = 0; + } + + @Override + public void init() { + super.init(); + this.setWindowSize(GuiResources.WAND_SYMMETRY.width + 50, GuiResources.WAND_SYMMETRY.height + 50); + + labelType = new DynamicLabel(topLeftX + 122, topLeftY + 15, "").colored(0xFFFFFFFF).withShadow(); + labelAlign = new DynamicLabel(topLeftX + 122, topLeftY + 35, "").colored(0xFFFFFFFF).withShadow(); + + int state = currentElement instanceof SymmetryTriplePlane ? 2 + : currentElement instanceof SymmetryCrossPlane ? 1 : 0; + areaType = new OptionScrollArea(topLeftX + 119, topLeftY + 12, 70, 14) + .forOptions(SymmetryElement.TOOLTIP_ELEMENTS).titled("Type of Mirror").writingTo(labelType) + .setState(state); + + areaType.calling(position -> { + switch (position) { + case 0: + currentElement = new SymmetryPlane(currentElement.getPosition()); + break; + case 1: + currentElement = new SymmetryCrossPlane(currentElement.getPosition()); + break; + case 2: + currentElement = new SymmetryTriplePlane(currentElement.getPosition()); + break; + default: + break; + } + initAlign(currentElement); + }); + + widgets.clear(); + + initAlign(currentElement); + + widgets.add(labelAlign); + widgets.add(areaType); + widgets.add(labelType); + + } + + private void initAlign(SymmetryElement element) { + if (areaAlign != null) { + widgets.remove(areaAlign); + } + + areaAlign = new OptionScrollArea(topLeftX + 119, topLeftY + 32, 70, 14).forOptions(element.getAlignToolTips()) + .titled("Direction").writingTo(labelAlign).setState(element.getOrientationIndex()) + .calling(element::setOrientation); + + widgets.add(areaAlign); + } + + @Override + public void tick() { + super.tick(); + animationProgress++; + } + + @Override + protected void renderWindow(int mouseX, int mouseY, float partialTicks) { + GuiResources.WAND_SYMMETRY.draw(this, topLeftX, topLeftY); + + int x = topLeftX + 63; + int y = topLeftY + 15; + + font.drawString("Symmetry", x, y, GuiResources.FONT_COLOR); + font.drawString("Direction", x, y + 20, GuiResources.FONT_COLOR); + + minecraft.getTextureManager().bindTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE); + GlStateManager.enableBlend(); + + renderBlock(); + renderBlock(); + + GlStateManager.pushLightingAttributes(); + GlStateManager.pushMatrix(); + + RenderHelper.enableStandardItemLighting(); + GlStateManager.enableBlend(); + GlStateManager.enableRescaleNormal(); + GlStateManager.enableAlphaTest(); + GlStateManager.alphaFunc(516, 0.1F); + GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); + + GlStateManager.translated((this.width - this.sWidth) / 2 + 250, 250, 100); + GlStateManager.rotatef(-30, .4f, 0, -.2f); + GlStateManager.rotatef(90 + 0.2f * animationProgress, 0, 1, 0); + GlStateManager.scaled(100, -100, 100); + itemRenderer.renderItem(wand, itemRenderer.getModelWithOverrides(wand)); + + GlStateManager.disableAlphaTest(); + GlStateManager.disableRescaleNormal(); + GlStateManager.disableLighting(); + + GlStateManager.popMatrix(); + GlStateManager.popAttributes(); + } + + protected void renderBlock() { + GlStateManager.pushMatrix(); + BufferBuilder buffer = Tessellator.getInstance().getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); + GlStateManager.translated(topLeftX + 15, topLeftY - 117, 20); + GlStateManager.rotatef(-22.5f, .3f, 1f, 0f); + GlStateManager.scaled(32, -32, 32); + minecraft.getBlockRendererDispatcher().renderBlock(currentElement.getModel(), new BlockPos(0, -5, 0), + minecraft.world, buffer, minecraft.world.rand, EmptyModelData.INSTANCE); + + Tessellator.getInstance().draw(); + GlStateManager.popMatrix(); + } + + @Override + public void removed() { + ItemStack heldItemMainhand = minecraft.player.getHeldItemMainhand(); + CompoundNBT compound = heldItemMainhand.getTag(); + compound.put(ItemWandSymmetry.$SYMMETRY, currentElement.writeToNbt()); + heldItemMainhand.setTag(compound); + Packets.channel.send(PacketDistributor.SERVER.noArg(), new PacketNbt(heldItemMainhand)); + minecraft.player.setHeldItem(Hand.MAIN_HAND, heldItemMainhand); + super.removed(); + } + +} diff --git a/src/main/java/com/simibubi/create/gui/widgets/AbstractSimiWidget.java b/src/main/java/com/simibubi/create/gui/widgets/AbstractSimiWidget.java new file mode 100644 index 000000000..48888dd2d --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/widgets/AbstractSimiWidget.java @@ -0,0 +1,25 @@ +package com.simibubi.create.gui.widgets; + +import java.util.LinkedList; +import java.util.List; + +import net.minecraft.client.gui.widget.Widget; + +public abstract class AbstractSimiWidget extends Widget { + + protected List toolTip; + + public AbstractSimiWidget(int xIn, int yIn, int widthIn, int heightIn) { + super(xIn, yIn, widthIn, heightIn, ""); + toolTip = new LinkedList<>(); + } + + public List getToolTip() { + return toolTip; + } + + @Override + public void renderButton(int p_renderButton_1_, int p_renderButton_2_, float p_renderButton_3_) { + } + +} diff --git a/src/main/java/com/simibubi/create/gui/widgets/DynamicLabel.java b/src/main/java/com/simibubi/create/gui/widgets/DynamicLabel.java new file mode 100644 index 000000000..d6bacabaa --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/widgets/DynamicLabel.java @@ -0,0 +1,42 @@ +package com.simibubi.create.gui.widgets; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; + +public class DynamicLabel extends AbstractSimiWidget { + + public String text; + protected boolean hasShadow; + protected int color; + protected FontRenderer font; + + public DynamicLabel(int x, int y, String text) { + super(x, y, Minecraft.getInstance().fontRenderer.getStringWidth(text), 10); + font = Minecraft.getInstance().fontRenderer; + this.text = "Label"; + color = 0xFFFFFF; + hasShadow = false; + } + + public DynamicLabel colored(int color) { + this.color = color; + return this; + } + + public DynamicLabel withShadow() { + this.hasShadow = true; + return this; + } + + @Override + public void render(int mouseX, int mouseY, float partialTicks) { + if (!visible) + return; + + if (hasShadow) + font.drawStringWithShadow(text, x, y, color); + else + font.drawString(text, x, y, color); + } + +} diff --git a/src/main/java/com/simibubi/create/gui/widgets/GuiIndicator.java b/src/main/java/com/simibubi/create/gui/widgets/GuiIndicator.java new file mode 100644 index 000000000..26d44d516 --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/widgets/GuiIndicator.java @@ -0,0 +1,35 @@ +package com.simibubi.create.gui.widgets; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.gui.GuiResources; + +public class GuiIndicator extends AbstractSimiWidget { + + public enum State { + OFF, ON, + RED, YELLOW, GREEN; + } + + public State state; + + public GuiIndicator(int x, int y, String tooltip) { + super(x, y, GuiResources.INDICATOR.width, GuiResources.INDICATOR.height); + this.toolTip = ImmutableList.of(tooltip); + this.state = State.OFF; + } + + @Override + public void render(int mouseX, int mouseY, float partialTicks ) { + GuiResources toDraw; + switch(state) { + case ON: toDraw = GuiResources.INDICATOR_WHITE; break; + case OFF: toDraw = GuiResources.INDICATOR; break; + case RED: toDraw = GuiResources.INDICATOR_RED; break; + case YELLOW: toDraw = GuiResources.INDICATOR_YELLOW; break; + case GREEN: toDraw = GuiResources.INDICATOR_GREEN; break; + default: toDraw = GuiResources.INDICATOR; break; + } + toDraw.draw(this, x, y); + } + +} diff --git a/src/main/java/com/simibubi/create/gui/widgets/OptionScrollArea.java b/src/main/java/com/simibubi/create/gui/widgets/OptionScrollArea.java new file mode 100644 index 000000000..210376ade --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/widgets/OptionScrollArea.java @@ -0,0 +1,47 @@ +package com.simibubi.create.gui.widgets; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.util.text.TextFormatting; + +public class OptionScrollArea extends ScrollArea { + + protected List options; + + public OptionScrollArea(int xIn, int yIn, int widthIn, int heightIn) { + super(xIn, yIn, widthIn, heightIn); + options = new ArrayList<>(); + } + + public ScrollArea forOptions(List options) { + this.options = options; + this.max = options.size(); + updateTooltip(); + return this; + } + + @Override + protected void writeToLabel() { + displayLabel.text = options.get(state); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double delta) { + return super.mouseScrolled(mouseX, mouseY, -delta); + } + + @Override + protected void updateTooltip() { + super.updateTooltip(); + for (int i = min; i < max; i++) { + StringBuilder result = new StringBuilder(); + if (i == state) + result.append(TextFormatting.WHITE).append("-> ").append(options.get(i)); + else + result.append(TextFormatting.GRAY).append("> ").append(options.get(i)); + toolTip.add(result.toString()); + } + } + +} diff --git a/src/main/java/com/simibubi/create/gui/widgets/ScrollArea.java b/src/main/java/com/simibubi/create/gui/widgets/ScrollArea.java new file mode 100644 index 000000000..fed9acd9c --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/widgets/ScrollArea.java @@ -0,0 +1,239 @@ +package com.simibubi.create.gui.widgets; + +import java.util.function.Consumer; + +import com.simibubi.create.utility.Keyboard; + +import net.minecraft.util.text.TextFormatting; + +public class ScrollArea extends AbstractSimiWidget { + + protected Consumer onScroll; + protected int state; + protected String title = "Choose an option"; + protected DynamicLabel displayLabel; + + protected int min, max; + + public ScrollArea(int xIn, int yIn, int widthIn, int heightIn) { + super(xIn, yIn, widthIn, heightIn); + state = 0; + min = 0; + max = 1; + } + + public ScrollArea withRange(int min, int max) { + this.min = min; + this.max = max; + return this; + } + + public ScrollArea calling(Consumer onScroll) { + this.onScroll = onScroll; + return this; + } + + public ScrollArea titled(String title) { + this.title = title; + updateTooltip(); + return this; + } + + public ScrollArea writingTo(DynamicLabel label) { + this.displayLabel = label; + writeToLabel(); + return this; + } + + public int getState() { + return state; + } + + public ScrollArea setState(int state) { + this.state = state; + clampState(); + updateTooltip(); + if (displayLabel != null) + writeToLabel(); + return this; + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double delta) { + if (!isHovered) + return false; + + int priorState = state; + int step = (int) Math.signum(delta) * (Keyboard.isKeyDown(Keyboard.LSHIFT) ? 5 : 1); + + state += step; + clampState(); + + if (priorState != state) + onChanged(); + + return priorState != state; + } + + protected void clampState() { + if (state >= max) + state = max - 1; + if (state < min) + state = min; + } + + protected void onChanged() { + if (displayLabel != null) + writeToLabel(); + if (onScroll != null) + onScroll.accept(state); + updateTooltip(); + } + + protected void writeToLabel() { + displayLabel.text = "" + state; + } + + protected void updateTooltip() { + toolTip.clear(); + toolTip.add(TextFormatting.BLUE + title); + } + +// public interface IScrollAction { +// public void onScroll(int position); +// } +// +// public interface ICancelableScrollAction extends IScrollAction { +// public void onScroll(int position); +// +// public boolean canScroll(int position); +// } +// +// private int x, y, width, height; +// private IScrollAction action; +// public boolean enabled; +// private Optional> tooltipContent; +// private int min, max; +// private boolean limitless; +// private boolean numeric; +// +// public ScrollArea(List options, IScrollAction action) { +// this(0, options.size(), action); +// this.tooltipContent = Optional.of(options); +// updateTooltip(); +// } +// +// public ScrollArea(int min, int max, IScrollAction action) { +// this(action); +// this.limitless = false; +// this.min = min; +// this.max = max; +// } +// +// public ScrollArea(IScrollAction action) { +// this.enabled = true; +// this.action = action; +// this.tooltipContent = Optional.absent(); +// this.limitless = true; +// this.numeric = false; +// } +// +// public void setBounds(int x, int y, int width, int height) { +// this.x = x; +// this.y = y; +// this.width = width; +// this.height = height; +// } +// +// public void setState(int state) { +// currentState = state; +// updateTooltip(); +// } +// +// public int getState() { +// return currentState; +// } +// +// public boolean isHovered(double x, double y) { +// return (x > this.x && x < this.x + this.width && y > this.y && y < this.y + this.height); +// } +// +// public void tryScroll(double mouseX, double mouseY, int amount) { +// if (enabled && isHovered(mouseX, mouseY)) { +// scroll(numeric? -amount : amount); +// } +// } +// +// public void setNumeric(boolean numeric) { +// this.numeric = numeric; +// } +// +// private void scroll(int amount) { +// if (enabled) { +// +// if (limitless) { +// if (!(action instanceof ICancelableScrollAction) +// || ((ICancelableScrollAction) action).canScroll(amount)) +// action.onScroll(amount); +// return; +// } +// +// if (!(action instanceof ICancelableScrollAction) +// || ((ICancelableScrollAction) action).canScroll(currentState + amount)) { +// currentState += amount; +// if (currentState < min) +// currentState = min; +// if (currentState >= max) +// currentState = max - 1; +// updateTooltip(); +// action.onScroll(currentState); +// } +// } +// } +// +// public void draw(Screen screen, int mouseX, int mouseY) { +// GlStateManager.pushLightingAttributes(); +// if (enabled && isHovered(mouseX, mouseY)) { +// GlStateManager.pushMatrix(); +// GlStateManager.translated(mouseX, mouseY,0); +// if (tooltipContent.isPresent()) +// screen.renderTooltip(getToolTip(), 0, 0); +// else +// screen.renderTooltip(TextFormatting.BLUE + title, 0, 0); +// GlStateManager.popMatrix(); +// } +// +// GlStateManager.popAttributes(); +// } +// +// public List getToolTip() { +// return tooltip; +// } +// +// public void setTitle(String title) { +// this.title = title; +// updateTooltip(); +// } +// +// private void updateTooltip() { +// tooltip = new LinkedList<>(); +// tooltip.add(TextFormatting.BLUE + title); +// +// if (tooltipContent.isPresent()) { +// for (int i = min; i < max; i++) { +// StringBuilder result = new StringBuilder(); +// if (i == currentState) +// result.append(TextFormatting.WHITE).append("-> ").append(tooltipContent.get().get(i)); +// else +// result.append(TextFormatting.GRAY).append("> ").append(tooltipContent.get().get(i)); +// tooltip.add(result.toString()); +// } +// +// } +// } +// +// public boolean isNumeric() { +// return numeric; +// } + +} diff --git a/src/main/java/com/simibubi/create/gui/widgets/SimiButton.java b/src/main/java/com/simibubi/create/gui/widgets/SimiButton.java new file mode 100644 index 000000000..33de77bd4 --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/widgets/SimiButton.java @@ -0,0 +1,57 @@ +package com.simibubi.create.gui.widgets; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.gui.GuiResources; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.ResourceLocation; + +public class SimiButton extends AbstractSimiWidget { + + private GuiResources icon; + protected boolean pressed; + + public SimiButton(int x, int y, GuiResources icon) { + super(x, y, 16, 16); + this.icon = icon; + } + + @Override + public void renderButton(int mouseX, int mouseY, float partialTicks) { + if (this.visible) { + ResourceLocation buttonTextures = GuiResources.BUTTON.location; + ResourceLocation iconTexture = icon.location; + this.isHovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height; + + GuiResources button = + (pressed) ? button = GuiResources.BUTTON_DOWN : + (isHovered) ? GuiResources.BUTTON_HOVER : + GuiResources.BUTTON; + + GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); + Minecraft.getInstance().getTextureManager().bindTexture(buttonTextures); + blit(x, y, button.startX, button.startY, button.width, button.height); + Minecraft.getInstance().getTextureManager().bindTexture(iconTexture); + blit(x +1, y +1, icon.startX, icon.startY, icon.width, icon.height); + } + } + + + @Override + public void onClick(double p_onClick_1_, double p_onClick_3_) { + super.onClick(p_onClick_1_, p_onClick_3_); + this.pressed = true; + } + + @Override + public void onRelease(double p_onRelease_1_, double p_onRelease_3_) { + super.onRelease(p_onRelease_1_, p_onRelease_3_); + this.pressed = false; + } + + public void setToolTip(String text) { + toolTip.clear(); + toolTip.add(text); + } + +} diff --git a/src/main/java/com/simibubi/create/item/ItemWandSymmetry.java b/src/main/java/com/simibubi/create/item/ItemWandSymmetry.java new file mode 100644 index 000000000..70332bc05 --- /dev/null +++ b/src/main/java/com/simibubi/create/item/ItemWandSymmetry.java @@ -0,0 +1,191 @@ +package com.simibubi.create.item; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.simibubi.create.gui.GuiOpener; +import com.simibubi.create.gui.GuiWandSymmetry; +import com.simibubi.create.item.symmetry.SymmetryCrossPlane; +import com.simibubi.create.item.symmetry.SymmetryElement; +import com.simibubi.create.item.symmetry.SymmetryEmptySlot; +import com.simibubi.create.item.symmetry.SymmetryPlane; +import com.simibubi.create.networking.PacketSymmetryEffect; +import com.simibubi.create.networking.Packets; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUseContext; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.ActionResult; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.shapes.ISelectionContext; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.world.World; +import net.minecraftforge.fml.network.PacketDistributor; + +public class ItemWandSymmetry extends Item { + + public static final String $SYMMETRY = "symmetry"; + private static final String $ENABLE = "enable"; + + public ItemWandSymmetry(Properties properties) { + super(properties.maxStackSize(1)); + } + + @Override + public ActionResultType onItemUse(ItemUseContext context) { + PlayerEntity player = context.getPlayer(); + BlockPos pos = context.getPos(); + player.getCooldownTracker().setCooldown(this, 5); + + if (context.getWorld().isRemote || context.getHand() != Hand.MAIN_HAND) + return ActionResultType.SUCCESS; + + ItemStack wand = player.getHeldItem(context.getHand()); + checkNBT(wand); + CompoundNBT compound = wand.getTag().getCompound($SYMMETRY); + pos = pos.offset(context.getFace()); + SymmetryElement previousElement = SymmetryElement.fromNBT(compound); + + if (player.isSneaking()) { + if (!(previousElement instanceof SymmetryEmptySlot)) + wand.getTag().putBoolean($ENABLE, !isEnabled(wand)); + return ActionResultType.SUCCESS; + } + + wand.getTag().putBoolean($ENABLE, true); + Vec3d pos3d = new Vec3d(pos.getX(), pos.getY(), pos.getZ()); + SymmetryElement newElement = new SymmetryPlane(pos3d); + + if (previousElement instanceof SymmetryEmptySlot) { + newElement.setOrientation((player.getHorizontalFacing() == Direction.NORTH + || player.getHorizontalFacing() == Direction.SOUTH) ? SymmetryPlane.Align.XY.ordinal() + : SymmetryPlane.Align.YZ.ordinal()); + newElement.enable = true; + player.sendStatusMessage(new StringTextComponent(TextFormatting.GREEN + "New Plane created"), true); + wand.getTag().putBoolean($ENABLE, true); + + } else { + previousElement.setPosition(pos3d); + + if (previousElement instanceof SymmetryPlane) { + previousElement.setOrientation((player.getHorizontalFacing() == Direction.NORTH + || player.getHorizontalFacing() == Direction.SOUTH) ? SymmetryPlane.Align.XY.ordinal() + : SymmetryPlane.Align.YZ.ordinal()); + } + + if (previousElement instanceof SymmetryCrossPlane) { + float rotation = player.getRotationYawHead(); + float abs = Math.abs(rotation % 90); + boolean diagonal = abs > 22 && abs < 45 + 22; + previousElement.setOrientation( + diagonal ? SymmetryCrossPlane.Align.D.ordinal() : SymmetryCrossPlane.Align.Y.ordinal()); + } + + newElement = previousElement; + } + + compound = newElement.writeToNbt(); + wand.getTag().put($SYMMETRY, compound); + + player.setHeldItem(context.getHand(), wand); + return ActionResultType.SUCCESS; + } + + @Override + public ActionResult onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) { + if (worldIn.isRemote) { + GuiOpener.open(new GuiWandSymmetry(playerIn.getHeldItem(handIn))); + playerIn.getCooldownTracker().setCooldown(this, 5); + } + return super.onItemRightClick(worldIn, playerIn, handIn); + } + + private static void checkNBT(ItemStack wand) { + if (!wand.hasTag() || !wand.getTag().contains($SYMMETRY)) { + wand.setTag(new CompoundNBT()); + wand.getTag().put($SYMMETRY, new SymmetryEmptySlot(new Vec3d(0, 0, 0)).writeToNbt()); + wand.getTag().putBoolean($ENABLE, false); + } + } + + public static boolean isEnabled(ItemStack stack) { + checkNBT(stack); + return stack.getTag().getBoolean($ENABLE); + } + + public static SymmetryElement getMirror(ItemStack stack) { + checkNBT(stack); + return SymmetryElement.fromNBT((CompoundNBT) stack.getTag().getCompound($SYMMETRY)); + } + + public static void apply(World world, ItemStack wand, PlayerEntity player, BlockPos pos, BlockState block) { + checkNBT(wand); + if (!isEnabled(wand)) + return; + + Map blockSet = new HashMap<>(); + blockSet.put(pos, block); + SymmetryElement symmetry = SymmetryElement + .fromNBT((CompoundNBT) wand.getTag().getCompound($SYMMETRY)); + + Vec3d mirrorPos = symmetry.getPosition(); + if (mirrorPos.distanceTo(new Vec3d(pos)) > 50) + return; + + symmetry.process(blockSet); + + BlockPos to = new BlockPos(mirrorPos); + List targets = new ArrayList<>(); + + targets.add(pos); + for (BlockPos position : blockSet.keySet()) { + if (world.func_217350_a(block, position, ISelectionContext.forEntity(player))) { + world.setBlockState(position, blockSet.get(position)); + targets.add(position); + } + } + + Packets.channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> player), new PacketSymmetryEffect(to, targets)); + } + + public static void remove(World world, ItemStack wand, PlayerEntity player, BlockPos pos) { + BlockState air = Blocks.AIR.getDefaultState(); + checkNBT(wand); + if (!isEnabled(wand)) + return; + + Map blockSet = new HashMap<>(); + blockSet.put(pos, air); + SymmetryElement symmetry = SymmetryElement + .fromNBT((CompoundNBT) wand.getTag().getCompound($SYMMETRY)); + + Vec3d mirrorPos = symmetry.getPosition(); + if (mirrorPos.distanceTo(new Vec3d(pos)) > 50) + return; + + symmetry.process(blockSet); + + BlockPos to = new BlockPos(mirrorPos); + List targets = new ArrayList<>(); + + targets.add(pos); + for (BlockPos position : blockSet.keySet()) { + targets.add(position); + world.setBlockState(position, air); + } + + Packets.channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> player), new PacketSymmetryEffect(to, targets)); + } + +} diff --git a/src/main/java/com/simibubi/create/item/SymmetryHandler.java b/src/main/java/com/simibubi/create/item/SymmetryHandler.java new file mode 100644 index 000000000..ae9d13064 --- /dev/null +++ b/src/main/java/com/simibubi/create/item/SymmetryHandler.java @@ -0,0 +1,177 @@ +package com.simibubi.create.item; + +import java.util.Random; + +import org.lwjgl.opengl.GL11; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.AllItems; +import com.simibubi.create.item.symmetry.SymmetryElement; +import com.simibubi.create.item.symmetry.SymmetryEmptySlot; +import com.simibubi.create.utility.TessellatorHelper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.client.model.data.EmptyModelData; +import net.minecraftforge.event.world.BlockEvent.BreakEvent; +import net.minecraftforge.event.world.BlockEvent.EntityPlaceEvent; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; +import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent; + +@EventBusSubscriber(bus = Bus.FORGE) +public class SymmetryHandler { + + private static int tickCounter = 0; + + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void onBlockPlaced(EntityPlaceEvent event) { + if (event.getWorld().isRemote()) + return; + if (!(event.getEntity() instanceof PlayerEntity)) + return; + + PlayerEntity player = (PlayerEntity) event.getEntity(); + PlayerInventory inv = player.inventory; + for (int i = 0; i < PlayerInventory.getHotbarSize(); i++) { + if (!inv.getStackInSlot(i).isEmpty() && inv.getStackInSlot(i).getItem() == AllItems.SYMMETRY_WAND.get()) { + ItemWandSymmetry.apply(player.world, inv.getStackInSlot(i), player, event.getPos(), + event.getPlacedBlock()); + } + } + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void onBlockDestroyed(BreakEvent event) { + if (event.getWorld().isRemote()) + return; + + PlayerEntity player = event.getPlayer(); + PlayerInventory inv = player.inventory; + for (int i = 0; i < PlayerInventory.getHotbarSize(); i++) { + if (!inv.getStackInSlot(i).isEmpty() && AllItems.SYMMETRY_WAND.typeOf(inv.getStackInSlot(i))) { + ItemWandSymmetry.remove(player.world, inv.getStackInSlot(i), player, event.getPos()); + } + } + } + + @OnlyIn(Dist.CLIENT) + @SubscribeEvent + public static void render(RenderWorldLastEvent event) { + Minecraft mc = Minecraft.getInstance(); + ClientPlayerEntity player = mc.player; + + GL11.glEnable(GL11.GL_BLEND); + + for (int i = 0; i < PlayerInventory.getHotbarSize(); i++) { + ItemStack stackInSlot = player.inventory.getStackInSlot(i); + if (stackInSlot != null && AllItems.SYMMETRY_WAND.typeOf(stackInSlot) + && ItemWandSymmetry.isEnabled(stackInSlot)) { + SymmetryElement mirror = ItemWandSymmetry.getMirror(stackInSlot); + if (mirror instanceof SymmetryEmptySlot) + continue; + + TessellatorHelper.prepareForDrawing(); + BlockPos pos = new BlockPos(mirror.getPosition()); + + float yShift = 0; + double speed = 1 / 16d; + yShift = MathHelper.sin((float) ((tickCounter + event.getPartialTicks()) * speed)) / 5f; + + BufferBuilder buffer = Tessellator.getInstance().getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); + GlStateManager.pushMatrix(); + GlStateManager.translated(0, yShift + .2f, 0); + mc.getBlockRendererDispatcher().renderBlock(mirror.getModel(), pos, player.world, buffer, player.world.getRandom(), + EmptyModelData.INSTANCE); + Tessellator.getInstance().draw(); + GlStateManager.popMatrix(); + TessellatorHelper.cleanUpAfterDrawing(); + + } + } + + GL11.glDisable(GL11.GL_BLEND); + } + + @OnlyIn(Dist.CLIENT) + @SubscribeEvent + public static void onClientTick(ClientTickEvent event) { + Minecraft mc = Minecraft.getInstance(); + ClientPlayerEntity player = mc.player; + + if (mc.world == null) + return; + if (mc.isGamePaused()) + return; + + tickCounter++; + + if (tickCounter % 10 == 0) { + for (int i = 0; i < PlayerInventory.getHotbarSize(); i++) { + ItemStack stackInSlot = player.inventory.getStackInSlot(i); + + if (stackInSlot != null && AllItems.SYMMETRY_WAND.typeOf(stackInSlot) + && ItemWandSymmetry.isEnabled(stackInSlot)) { + + SymmetryElement mirror = ItemWandSymmetry.getMirror(stackInSlot); + if (mirror instanceof SymmetryEmptySlot) + continue; + + Random r = new Random(); + double offsetX = (r.nextDouble() - 0.5) * 0.3; + double offsetZ = (r.nextDouble() - 0.5) * 0.3; + + Vec3d pos = mirror.getPosition().add(0.5 + offsetX, 1 / 4d, 0.5 + offsetZ); + Vec3d speed = new Vec3d(0, r.nextDouble() * 1 / 8f, 0); + mc.world.addParticle(ParticleTypes.END_ROD, pos.x, pos.y, pos.z, speed.x, speed.y, speed.z); + } + } + } + + } + + public static void drawEffect(BlockPos from, BlockPos to) { + double density = 0.3f; + Vec3d start = new Vec3d(from).add(0.5, 0.5, 0.5); + Vec3d end = new Vec3d(to).add(0.5, 0.5, 0.5); + Vec3d diff = end.subtract(start); + + Vec3d step = diff.normalize().scale(density); + int steps = (int) (diff.length() / step.length()); + + Random r = new Random(); + for (int i = 5; i < steps - 1; i++) { + Vec3d pos = start.add(step.scale(i)); + Vec3d speed = new Vec3d(0, r.nextDouble() * -40f, 0); + Minecraft.getInstance().world.addParticle(ParticleTypes.WITCH, pos.x, pos.y, pos.z, speed.x, + speed.y, speed.z); + } + + Vec3d speed = new Vec3d(0, r.nextDouble() * 1 / 32f, 0); + Vec3d pos = start.add(step.scale(5)); + Minecraft.getInstance().world.addParticle(ParticleTypes.END_ROD, pos.x, pos.y, pos.z, speed.x, speed.y, + speed.z); + + speed = new Vec3d(0, r.nextDouble() * 1 / 32f, 0); + pos = start.add(step.scale(steps)); + Minecraft.getInstance().world.addParticle(ParticleTypes.END_ROD, pos.x, pos.y, pos.z, speed.x, speed.y, + speed.z); + } + +} diff --git a/src/main/java/com/simibubi/create/item/symmetry/SymmetryCrossPlane.java b/src/main/java/com/simibubi/create/item/symmetry/SymmetryCrossPlane.java new file mode 100644 index 000000000..e1579bc6a --- /dev/null +++ b/src/main/java/com/simibubi/create/item/symmetry/SymmetryCrossPlane.java @@ -0,0 +1,96 @@ +package com.simibubi.create.item.symmetry; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.block.symmetry.BlockSymmetryCrossPlane; + +import net.minecraft.block.BlockState; +import net.minecraft.util.IStringSerializable; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +public class SymmetryCrossPlane extends SymmetryElement { + + public static enum Align implements IStringSerializable { + Y("y"), D("d"); + + private final String name; + + private Align(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public String toString() { + return name; + } + } + + public SymmetryCrossPlane(Vec3d pos) { + super(pos); + orientation = Align.Y; + } + + @Override + protected void setOrientation() { + if (orientationIndex < 0) + orientationIndex += Align.values().length; + if (orientationIndex >= Align.values().length) + orientationIndex -= Align.values().length; + orientation = Align.values()[orientationIndex]; + } + + @Override + public void setOrientation(int index) { + this.orientation = Align.values()[index]; + orientationIndex = index; + } + + @Override + public Map process(BlockPos position, BlockState block) { + Map result = new HashMap<>(); + + switch ((Align) orientation) { + case D: + result.put(flipD1(position), flipD1(block)); + result.put(flipD2(position), flipD2(block)); + result.put(flipD1(flipD2(position)), flipD1(flipD2(block))); + break; + case Y: + result.put(flipX(position), flipX(block)); + result.put(flipZ(position), flipZ(block)); + result.put(flipX(flipZ(position)), flipX(flipZ(block))); + break; + default: + break; + } + + return result; + } + + @Override + public String typeName() { + return CROSS_PLANE; + } + + @Override + public BlockState getModel() { + return AllBlocks.SYMMETRY_CROSSPLANE.block.getDefaultState().with(BlockSymmetryCrossPlane.align, + (Align) orientation); + } + + @Override + public List getAlignToolTips() { + return ImmutableList.of("Orthogonal", "Diagonal"); + } + +} diff --git a/src/main/java/com/simibubi/create/item/symmetry/SymmetryElement.java b/src/main/java/com/simibubi/create/item/symmetry/SymmetryElement.java new file mode 100644 index 000000000..9da5f2859 --- /dev/null +++ b/src/main/java/com/simibubi/create/item/symmetry/SymmetryElement.java @@ -0,0 +1,255 @@ +package com.simibubi.create.item.symmetry; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.ImmutableList; + +import net.minecraft.block.BlockState; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.FloatNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.state.DirectionProperty; +import net.minecraft.state.IProperty; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.IStringSerializable; +import net.minecraft.util.Mirror; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +public abstract class SymmetryElement { + + public static final String EMPTY = "empty"; + public static final String PLANE = "plane"; + public static final String CROSS_PLANE = "cross_plane"; + public static final String TRIPLE_PLANE = "triple_plane"; + + public static final List TOOLTIP_ELEMENTS = ImmutableList.of("Mirror once", "Rectanglar", "Octagonal"); + + protected Vec3d position; + protected IStringSerializable orientation; + protected int orientationIndex; + public boolean enable; + + public SymmetryElement(Vec3d pos) { + position = pos; + enable = true; + orientationIndex = 0; + } + + public IStringSerializable getOrientation() { + return orientation; + } + + public Vec3d getPosition() { + return position; + } + + public int getOrientationIndex() { + return orientationIndex; + } + + public void rotate(boolean forward) { + orientationIndex += forward ? 1 : -1; + setOrientation(); + } + + public void process(Map blocks) { + Map result = new HashMap<>(); + for (BlockPos pos : blocks.keySet()) { + result.putAll(process(pos, blocks.get(pos))); + } + blocks.putAll(result); + } + + public abstract Map process(BlockPos position, BlockState block); + + protected abstract void setOrientation(); + + public abstract void setOrientation(int index); + + public abstract String typeName(); + + public abstract BlockState getModel(); + + private static final String $ORIENTATION = "direction"; + private static final String $POSITION = "pos"; + private static final String $TYPE = "type"; + private static final String $ENABLE = "enable"; + + public CompoundNBT writeToNbt() { + CompoundNBT nbt = new CompoundNBT(); + nbt.putInt($ORIENTATION, orientationIndex); + + ListNBT floatList = new ListNBT(); + floatList.add(new FloatNBT((float) position.x)); + floatList.add(new FloatNBT((float) position.y)); + floatList.add(new FloatNBT((float) position.z)); + nbt.put($POSITION, floatList); + nbt.putString($TYPE, typeName()); + nbt.putBoolean($ENABLE, enable); + + return nbt; + } + + public static SymmetryElement fromNBT(CompoundNBT nbt) { + ListNBT floatList = nbt.getList($POSITION, 5); + Vec3d pos = new Vec3d(floatList.getFloat(0), floatList.getFloat(1), floatList.getFloat(2)); + SymmetryElement element; + + switch (nbt.getString($TYPE)) { + case PLANE: + element = new SymmetryPlane(pos); + break; + case CROSS_PLANE: + element = new SymmetryCrossPlane(pos); + break; + case TRIPLE_PLANE: + element = new SymmetryTriplePlane(pos); + break; + default: + element = new SymmetryEmptySlot(pos); + break; + } + + element.setOrientation(nbt.getInt($ORIENTATION)); + element.enable = nbt.getBoolean($ENABLE); + + return element; + } + + protected Vec3d getDiff(BlockPos position) { + return this.position.scale(-1).add(position.getX(), position.getY(), position.getZ()); + } + + protected BlockPos getIDiff(BlockPos position) { + Vec3d diff = getDiff(position); + return new BlockPos((int) diff.x, (int) diff.y, (int) diff.z); + } + + protected BlockState flipX(BlockState in) { + return in.mirror(Mirror.FRONT_BACK); + } + + protected BlockState flipY(BlockState in) { + for (IProperty property : in.getProperties()) { + + if (property == BlockStateProperties.HALF) + return in.cycle(property); + // Directional Blocks + if (property instanceof DirectionProperty) { + if (in.get(property) == Direction.DOWN) { + return in.with((DirectionProperty) property, Direction.UP); + } else if (in.get(property) == Direction.UP) { + return in.with((DirectionProperty) property, Direction.DOWN); + } + } + } + return in; + } + + protected BlockState flipZ(BlockState in) { + return in.mirror(Mirror.LEFT_RIGHT); + } + + protected BlockState flipD1(BlockState in) { + for (IProperty property : in.getProperties()) { + + if (property == BlockStateProperties.AXIS || property == BlockStateProperties.HORIZONTAL_AXIS) { + Axis axis = ((Axis) in.get(property)); + if (axis.isVertical()) + return in; + Axis value = axis == Axis.X ? Axis.Z : Axis.X; + if (property == BlockStateProperties.AXIS) + return in.with(BlockStateProperties.AXIS, value); + return in.with(BlockStateProperties.HORIZONTAL_AXIS, value); + } + + if (property instanceof DirectionProperty) { + switch ((Direction) in.get(property)) { + case EAST: + return in.with((DirectionProperty) property, Direction.NORTH); + case NORTH: + return in.with((DirectionProperty) property, Direction.EAST); + case SOUTH: + return in.with((DirectionProperty) property, Direction.WEST); + case WEST: + return in.with((DirectionProperty) property, Direction.SOUTH); + default: + break; + } + } + + } + return in; + } + + protected BlockState flipD2(BlockState in) { + for (IProperty property : in.getProperties()) { + + if (property == BlockStateProperties.AXIS || property == BlockStateProperties.HORIZONTAL_AXIS) { + Axis axis = ((Axis) in.get(property)); + if (axis.isVertical()) + return in; + Axis value = axis == Axis.X ? Axis.Z : Axis.X; + if (property == BlockStateProperties.AXIS) + return in.with(BlockStateProperties.AXIS, value); + return in.with(BlockStateProperties.HORIZONTAL_AXIS, value); + } + + if (property instanceof DirectionProperty) { + switch ((Direction) in.get(property)) { + case EAST: + return in.with((DirectionProperty) property, Direction.SOUTH); + case NORTH: + return in.with((DirectionProperty) property, Direction.WEST); + case SOUTH: + return in.with((DirectionProperty) property, Direction.EAST); + case WEST: + return in.with((DirectionProperty) property, Direction.NORTH); + default: + break; + } + } + + } + return in; + } + + protected BlockPos flipX(BlockPos position) { + BlockPos diff = getIDiff(position); + return new BlockPos(position.getX() - 2 * diff.getX(), position.getY(), position.getZ()); + } + + protected BlockPos flipY(BlockPos position) { + BlockPos diff = getIDiff(position); + return new BlockPos(position.getX(), position.getY() - 2 * diff.getY(), position.getZ()); + } + + protected BlockPos flipZ(BlockPos position) { + BlockPos diff = getIDiff(position); + return new BlockPos(position.getX(), position.getY(), position.getZ() - 2 * diff.getZ()); + } + + protected BlockPos flipD2(BlockPos position) { + BlockPos diff = getIDiff(position); + return new BlockPos(position.getX() - diff.getX() + diff.getZ(), position.getY(), + position.getZ() - diff.getZ() + diff.getX()); + } + + protected BlockPos flipD1(BlockPos position) { + BlockPos diff = getIDiff(position); + return new BlockPos(position.getX() - diff.getX() - diff.getZ(), position.getY(), + position.getZ() - diff.getZ() - diff.getX()); + } + + public void setPosition(Vec3d pos3d) { + this.position = pos3d; + } + + public abstract List getAlignToolTips(); + +} diff --git a/src/main/java/com/simibubi/create/item/symmetry/SymmetryEmptySlot.java b/src/main/java/com/simibubi/create/item/symmetry/SymmetryEmptySlot.java new file mode 100644 index 000000000..6e3de73cb --- /dev/null +++ b/src/main/java/com/simibubi/create/item/symmetry/SymmetryEmptySlot.java @@ -0,0 +1,60 @@ +package com.simibubi.create.item.symmetry; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.ImmutableList; + +import net.minecraft.block.BlockState; +import net.minecraft.util.IStringSerializable; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +public class SymmetryEmptySlot extends SymmetryElement { + + public static enum Align implements IStringSerializable { + None("none"); + + private final String name; + private Align(String name) { this.name = name; } + @Override public String getName() { return name; } + @Override public String toString() { return name; } + } + + public SymmetryEmptySlot(Vec3d pos) { + super(pos); + orientation = Align.None; + } + + @Override + protected void setOrientation() { + } + + @Override + public void setOrientation(int index) { + this.orientation = Align.values()[index]; + orientationIndex = index; + } + + @Override + public Map process(BlockPos position, BlockState block) { + return new HashMap<>(); + } + + @Override + public String typeName() { + return EMPTY; + } + + @Override + public BlockState getModel() { + return null; + } + + @Override + public List getAlignToolTips() { + return ImmutableList.of(); + } + +} diff --git a/src/main/java/com/simibubi/create/item/symmetry/SymmetryPlane.java b/src/main/java/com/simibubi/create/item/symmetry/SymmetryPlane.java new file mode 100644 index 000000000..cae0b3a64 --- /dev/null +++ b/src/main/java/com/simibubi/create/item/symmetry/SymmetryPlane.java @@ -0,0 +1,91 @@ +package com.simibubi.create.item.symmetry; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.block.symmetry.BlockSymmetryPlane; + +import net.minecraft.block.BlockState; +import net.minecraft.util.IStringSerializable; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +public class SymmetryPlane extends SymmetryElement { + + public static enum Align implements IStringSerializable { + XY("xy"), YZ("yz"); + + private final String name; + + private Align(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public String toString() { + return name; + } + } + + public SymmetryPlane(Vec3d pos) { + super(pos); + orientation = Align.XY; + } + + @Override + protected void setOrientation() { + if (orientationIndex < 0) + orientationIndex += Align.values().length; + if (orientationIndex >= Align.values().length) + orientationIndex -= Align.values().length; + orientation = Align.values()[orientationIndex]; + } + + @Override + public void setOrientation(int index) { + this.orientation = Align.values()[index]; + orientationIndex = index; + } + + @Override + public Map process(BlockPos position, BlockState block) { + Map result = new HashMap<>(); + switch ((Align) orientation) { + + case XY: + result.put(flipZ(position), flipZ(block)); + break; + case YZ: + result.put(flipX(position), flipX(block)); + break; + default: + break; + + } + return result; + } + + @Override + public String typeName() { + return PLANE; + } + + @Override + public BlockState getModel() { + return AllBlocks.SYMMETRY_PLANE.block.getDefaultState().with(BlockSymmetryPlane.align, (Align) orientation); + } + + @Override + public List getAlignToolTips() { + return ImmutableList.of("Mirror Z", "Mirror X"); + } + +} diff --git a/src/main/java/com/simibubi/create/item/symmetry/SymmetryTriplePlane.java b/src/main/java/com/simibubi/create/item/symmetry/SymmetryTriplePlane.java new file mode 100644 index 000000000..b651d2030 --- /dev/null +++ b/src/main/java/com/simibubi/create/item/symmetry/SymmetryTriplePlane.java @@ -0,0 +1,66 @@ +package com.simibubi.create.item.symmetry; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.AllBlocks; + +import net.minecraft.block.BlockState; +import net.minecraft.util.IStringSerializable; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +public class SymmetryTriplePlane extends SymmetryElement { + + public SymmetryTriplePlane(Vec3d pos) { + super(pos); + orientationIndex = 0; + } + + @Override + public Map process(BlockPos position, BlockState block) { + Map result = new HashMap<>(); + + result.put(flipX(position), flipX(block)); + result.put(flipZ(position), flipZ(block)); + result.put(flipX(flipZ(position)), flipX(flipZ(block))); + + result.put(flipD1(position), flipD1(block)); + result.put(flipD1(flipX(position)), flipD1(flipX(block))); + result.put(flipD1(flipZ(position)), flipD1(flipZ(block))); + result.put(flipD1(flipX(flipZ(position))), flipD1(flipX(flipZ(block)))); + + return result; + } + + @Override + public String typeName() { + return TRIPLE_PLANE; + } + + @Override + public BlockState getModel() { + return AllBlocks.SYMMETRY_TRIPLEPLANE.block.getDefaultState(); + } + + @Override + protected void setOrientation() { + } + + @Override + public void setOrientation(int index) { + } + + @Override + public IStringSerializable getOrientation() { + return SymmetryCrossPlane.Align.Y; + } + + @Override + public List getAlignToolTips() { + return ImmutableList.of("Horizontal"); + } + +} diff --git a/src/main/java/com/simibubi/create/networking/PacketNbt.java b/src/main/java/com/simibubi/create/networking/PacketNbt.java new file mode 100644 index 000000000..1b90cc077 --- /dev/null +++ b/src/main/java/com/simibubi/create/networking/PacketNbt.java @@ -0,0 +1,36 @@ +package com.simibubi.create.networking; + +import java.util.function.Supplier; + +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +public class PacketNbt { + + public ItemStack stack; + + public PacketNbt(ItemStack stack) { + this.stack = stack; + } + + public PacketNbt(PacketBuffer buffer) { + stack = buffer.readItemStack(); + } + + public void toBytes(PacketBuffer buffer) { + buffer.writeItemStack(stack); + } + + public void handle(Supplier context) { + context.get().enqueueWork(() -> { + ServerPlayerEntity player = context.get().getSender(); + ItemStack heldItem = player.getHeldItemMainhand(); + if (heldItem.getItem() == stack.getItem()) { + heldItem.setTag(stack.getTag()); + } + }); + } + +} diff --git a/src/main/java/com/simibubi/create/networking/PacketSymmetryEffect.java b/src/main/java/com/simibubi/create/networking/PacketSymmetryEffect.java new file mode 100644 index 000000000..9f75e432d --- /dev/null +++ b/src/main/java/com/simibubi/create/networking/PacketSymmetryEffect.java @@ -0,0 +1,50 @@ +package com.simibubi.create.networking; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +import com.simibubi.create.item.SymmetryHandler; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +public class PacketSymmetryEffect { + + private BlockPos mirror; + private List positions; + + public PacketSymmetryEffect(BlockPos mirror, List positions) { + this.mirror = mirror; + this.positions = positions; + } + + public PacketSymmetryEffect(PacketBuffer buffer) { + mirror = buffer.readBlockPos(); + int amt = buffer.readInt(); + positions = new ArrayList<>(amt); + for (int i = 0; i < amt; i++) { + positions.add(buffer.readBlockPos()); + } + } + + public void toBytes(PacketBuffer buffer) { + buffer.writeBlockPos(mirror); + buffer.writeInt(positions.size()); + for (BlockPos blockPos : positions) { + buffer.writeBlockPos(blockPos); + } + } + + public void handle(Supplier context) { + if (Minecraft.getInstance().player.getPositionVector().distanceTo(new Vec3d(mirror)) > 100) + return; + + for (BlockPos to : positions) + SymmetryHandler.drawEffect(mirror, to); + } + +} diff --git a/src/main/java/com/simibubi/create/networking/Packets.java b/src/main/java/com/simibubi/create/networking/Packets.java new file mode 100644 index 000000000..7ca507cf5 --- /dev/null +++ b/src/main/java/com/simibubi/create/networking/Packets.java @@ -0,0 +1,23 @@ +package com.simibubi.create.networking; + +import com.simibubi.create.Create; + +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.network.NetworkRegistry; +import net.minecraftforge.fml.network.simple.SimpleChannel; + +public class Packets { + + public static final SimpleChannel channel = NetworkRegistry.newSimpleChannel( + new ResourceLocation(Create.ID, "simple_channel"), () -> "1", v -> v.equals("1"), v -> v.equals("1")); + + public static void registerPackets() { + int i = 0; + + channel.registerMessage(i++, PacketNbt.class, PacketNbt::toBytes, PacketNbt::new, + PacketNbt::handle); + channel.registerMessage(i++, PacketSymmetryEffect.class, PacketSymmetryEffect::toBytes, PacketSymmetryEffect::new, + PacketSymmetryEffect::handle); + } + +} diff --git a/src/main/java/com/simibubi/create/utility/Keyboard.java b/src/main/java/com/simibubi/create/utility/Keyboard.java new file mode 100644 index 000000000..088e26633 --- /dev/null +++ b/src/main/java/com/simibubi/create/utility/Keyboard.java @@ -0,0 +1,30 @@ +package com.simibubi.create.utility; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.util.InputMappings; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +@OnlyIn(Dist.CLIENT) +public class Keyboard { + + public static final int PRESS = 1; + public static final int HOLD = 2; + public static final int RELEASE = 0; + + public static final int LSHIFT = 340; + public static final int LALT = 342; + public static final int RETURN = 257; + + public static final int DOWN = 264; + public static final int LEFT = 263; + public static final int RIGHT = 262; + public static final int UP = 265; + + public static final int G = 71; + + public static boolean isKeyDown(int key) { + return InputMappings.isKeyDown(Minecraft.getInstance().mainWindow.getHandle(), key); + } + +} diff --git a/src/main/java/com/simibubi/create/utility/TessellatorHelper.java b/src/main/java/com/simibubi/create/utility/TessellatorHelper.java new file mode 100644 index 000000000..22d3e53bd --- /dev/null +++ b/src/main/java/com/simibubi/create/utility/TessellatorHelper.java @@ -0,0 +1,216 @@ +package com.simibubi.create.utility; + +import org.lwjgl.opengl.GL11; + +import com.mojang.blaze3d.platform.GlStateManager; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +public class TessellatorHelper { + + public static final float fontScale = 1/512f; + + public static void prepareForDrawing() { + Minecraft mc = Minecraft.getInstance(); + GlStateManager.pushMatrix(); + GlStateManager.pushLightingAttributes(); + GlStateManager.enableBlend(); + GlStateManager.enableAlphaTest(); + GlStateManager.color4f(1, 1, 1, 1); + + ActiveRenderInfo renderInfo = mc.gameRenderer.getActiveRenderInfo(); + Vec3d view = renderInfo.getProjectedView(); + GlStateManager.translated(-view.x, -view.y, -view.z); + } + + public static void begin() { + Tessellator.getInstance().getBuffer().begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + } + + public static void draw() { + Tessellator.getInstance().draw(); + } + + public static void cleanUpAfterDrawing() { + GlStateManager.disableAlphaTest(); + GlStateManager.disableBlend(); + GlStateManager.popAttributes(); + GlStateManager.popMatrix(); + } + + public static void drawString(String str, float x, float y, float z, boolean scalesUp, boolean hasDepth) { + Minecraft mc = Minecraft.getInstance(); + float pitch = mc.getRenderManager().playerViewX; + float yaw = mc.getRenderManager().playerViewY; + boolean isThirdPersonFrontal = mc.gameSettings.thirdPersonView == 2; + + GlStateManager.pushMatrix(); + GlStateManager.pushLightingAttributes(); + GlStateManager.translatef(x, y, z); + GlStateManager.normal3f(0.0F, 1.0F, 0.0F); + GlStateManager.rotatef(-yaw, 0.0F, 1.0F, 0.0F); + GlStateManager.rotatef((float) (isThirdPersonFrontal ? -1 : 1) * pitch, 1.0F, 0.0F, 0.0F); + GlStateManager.scalef(-0.025F, -0.025F, 0.025F); + GlStateManager.disableLighting(); + if (!hasDepth) { + GlStateManager.depthMask(false); + GlStateManager.disableDepthTest(); + } + + GlStateManager.enableBlend(); + GlStateManager.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, + GlStateManager.DestFactor.ZERO); + int i = mc.fontRenderer.getStringWidth(str) / 2; + GlStateManager.disableTexture(); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + bufferbuilder.begin(7, DefaultVertexFormats.POSITION_COLOR); + bufferbuilder.pos((double) (-i - 3), (double) (-3), 0.0D).color(1F, 1F, 1F, .5F).endVertex(); + bufferbuilder.pos((double) (-i - 3), (double) (10), 0.0D).color(1F, 1F, 1F, .5F).endVertex(); + bufferbuilder.pos((double) (i + 3), (double) (10), 0.0D).color(1F, 1F, 1F, .5F).endVertex(); + bufferbuilder.pos((double) (i + 3), (double) (-3), 0.0D).color(1F, 1F, 1F, .5F).endVertex(); + + if (scalesUp) { + double distance = mc.player.getEyePosition(mc.getRenderPartialTicks()).squareDistanceTo(x, y, z); + double scale = distance * fontScale; + GlStateManager.scaled(2 + scale, 2 + scale, 2 + scale); + } + tessellator.draw(); + GlStateManager.enableTexture(); + if (hasDepth) { + GlStateManager.translatef(0, 0, -0.125f); + } + + mc.fontRenderer.drawString(str, -mc.fontRenderer.getStringWidth(str) / 2, 0, 0); + GlStateManager.enableDepthTest(); + + GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); + GlStateManager.depthMask(true); + GlStateManager.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.SRC_ALPHA, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + GlStateManager.popMatrix(); + GlStateManager.popAttributes(); + } + + public static void cube(BufferBuilder bufferBuilder, BlockPos pos, BlockPos size, double scale, + boolean scaleVertical, boolean doubleFaces) { + TessellatorHelper.walls(bufferBuilder, pos, size, scale, scaleVertical, doubleFaces); + int w = size.getX(); + int h = size.getY(); + int l = size.getZ(); + + if (doubleFaces) { + TessellatorHelper.doubleFace(bufferBuilder, pos, new BlockPos(w, 0, l), scale, true, scaleVertical, false); + TessellatorHelper.doubleFace(bufferBuilder, pos.east(w).up(h), new BlockPos(-w, 0, l), scale, true, scaleVertical, false); + } else { + TessellatorHelper.face(bufferBuilder, pos, new BlockPos(w, 0, l), scale, true, scaleVertical, false, false); + TessellatorHelper.face(bufferBuilder, pos.east(w).up(h), new BlockPos(-w, 0, l), scale, true, scaleVertical, false, false); + } + } + + public static void walls(BufferBuilder bufferBuilder, BlockPos pos, BlockPos size, double scale, + boolean scaleVertical, boolean doubleFaces) { + int w = size.getX(); + int h = size.getY(); + int l = size.getZ(); + + if (doubleFaces) { + TessellatorHelper.doubleFace(bufferBuilder, pos, new BlockPos(w, h, 0), scale, true, scaleVertical, false); + TessellatorHelper.doubleFace(bufferBuilder, pos.east(w).south(l), new BlockPos(0, h, -l), scale, true, scaleVertical, false); + TessellatorHelper.doubleFace(bufferBuilder, pos.east(w).south(l), new BlockPos(-w, h, 0), scale, true, scaleVertical, false); + TessellatorHelper.doubleFace(bufferBuilder, pos, new BlockPos(0, h, l), scale, true, scaleVertical, false); + } else { + TessellatorHelper.face(bufferBuilder, pos, new BlockPos(w, h, 0), scale, true, scaleVertical, false, false); + TessellatorHelper.face(bufferBuilder, pos.east(w).south(l), new BlockPos(0, h, -l), scale, true, scaleVertical, false, false); + TessellatorHelper.face(bufferBuilder, pos.east(w).south(l), new BlockPos(-w, h, 0), scale, true, scaleVertical, false, false); + TessellatorHelper.face(bufferBuilder, pos, new BlockPos(0, h, l), scale, true, scaleVertical, false, false); + } + } + + public static void doubleFace(BufferBuilder bufferBuilder, BlockPos pos, BlockPos size, double shift, + boolean stretch, boolean shiftVertical, boolean mirrorTexture) { + TessellatorHelper.face(bufferBuilder, pos, size, shift, stretch, shiftVertical, false, mirrorTexture); + TessellatorHelper.face(bufferBuilder, pos.add(size.getX(), 0, (size.getY() == 0) ? 0 : size.getZ()), + new BlockPos(-size.getX(), size.getY(), (size.getY() == 0) ? size.getZ() : -size.getZ()), -shift, + stretch, shiftVertical, true, mirrorTexture); + } + + public static void face(BufferBuilder bufferBuilder, BlockPos pos, BlockPos size, double shift, boolean stretch, + boolean shiftVertical, boolean shiftBackwards, boolean mirrorTexture) { + int w = size.getX(); + int h = size.getY(); + int l = size.getZ(); + if (shiftBackwards) + shift = -shift; + + if (w == 0) { // YZ plane -> H has to be positive + + double xs = (l < 0) ? shift : -shift; + if (shiftBackwards) + xs = -xs; + double ys1 = shiftVertical ? shift : 0; + double zs1 = l < 0 ? -shift : shift; + if (!stretch && (l > 0 ^ mirrorTexture)) + zs1 = -zs1; + double ys2 = stretch ? -ys1 : ys1; + double zs2 = stretch ? -zs1 : zs1; + double u1 = (mirrorTexture) ? l : 0; + double u2 = (mirrorTexture) ? 0 : l; + + TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs, ys2, zs1), pos.south(l), u2, h); + TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs, ys1, zs1), pos.south(l).up(h), u2, 0); + TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs, ys1, zs2), pos.up(h), u1, 0); + TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs, ys2, zs2), pos, u1, h); + + } else if (h == 0) { // XZ plane -> L has to be positive + + double ys = w < 0 ? shift : -shift; + if (shiftBackwards) + ys = -ys; + double xs1 = w < 0 ? -shift : shift; + double zs1 = shift; + double xs2 = stretch ? -xs1 : xs1; + double zs2 = stretch ? -zs1 : zs1; + double u1 = (mirrorTexture) ? w : 0; + double u2 = (mirrorTexture) ? 0 : w; + + TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs2, ys, zs1), pos.south(l), u1, l); + TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs2, ys, zs2), pos, u1, 0); + TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs1, ys, zs2), pos.east(w), u2, 0); + TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs1, ys, zs1), pos.east(w).south(l), u2, l); + + } else if (l == 0) { // XY plane -> H has to be positive + + double zs = w < 0 ? shift : -shift; + if (shiftBackwards) + zs = -zs; + double ys1 = shiftVertical ? shift : 0; + double xs1 = w < 0 ? -shift : shift; + if (!stretch && (w > 0 ^ mirrorTexture)) + xs1 = -xs1; + double ys2 = stretch ? -ys1 : ys1; + double xs2 = stretch ? -xs1 : xs1; + double u1 = (mirrorTexture) ? w : 0; + double u2 = (mirrorTexture) ? 0 : w; + + TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs2, ys2, zs), pos, u1, h); + TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs2, ys1, zs), pos.up(h), u1, 0); + TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs1, ys1, zs), pos.east(w).up(h), u2, 0); + TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs1, ys2, zs), pos.east(w), u2, h); + + } + } + + private static void posTexShift(BufferBuilder bufferBuilder, Vec3d shift, BlockPos pos, double u, double v) { + bufferBuilder.pos(shift.x + pos.getX(), shift.y + pos.getY(), shift.z + pos.getZ()).tex(u, v).endVertex(); + } + +} diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml new file mode 100644 index 000000000..24fd5fc78 --- /dev/null +++ b/src/main/resources/META-INF/mods.toml @@ -0,0 +1,56 @@ +# This is an example mods.toml file. It contains the data relating to the loading mods. +# There are several mandatory fields (#mandatory), and many more that are optional (#optional). +# The overall format is standard TOML format, v0.5.0. +# Note that there are a couple of TOML lists in this file. +# Find more information on toml format here: https://github.com/toml-lang/toml +# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml +modLoader="javafml" #mandatory +# A version range to match for said mod loader - for regular FML @Mod it will be the forge version +loaderVersion="[26,)" #mandatory (26 is current forge version) +# A URL to refer people to when problems occur with this mod +#issueTrackerURL=""#optional +# A list of mods - how many allowed here is determined by the individual mod loader +[[mods]] #mandatory +# The modid of the mod +modId="create" #mandatory +# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it +version="${file.jarVersion}" #mandatory + # A display name for the mod +displayName="Create" #mandatory +# A URL to query for updates for this mod. See the JSON update specification +#updateJSONURL=""#optional +# A URL for the "homepage" for this mod, displayed in the mod UI +displayURL="http://example.com/" #optional +# A file name (in the root of the mod JAR) containing a logo for display +logoFile="examplemod.png" #optional +# A text field displayed in the mod UI +credits="Thanks for this example mod goes to Java" #optional +# A text field displayed in the mod UI +authors="simibubi" #optional +# The description text for the mod (multi line!) (#mandatory) +description=''' +This is a long form description of the mod. You can write whatever you want here + +Have some lorem ipsum. + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis lacinia magna. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed sagittis luctus odio eu tempus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque volutpat ligula eget lacus auctor sagittis. In hac habitasse platea dictumst. Nunc gravida elit vitae sem vehicula efficitur. Donec mattis ipsum et arcu lobortis, eleifend sagittis sem rutrum. Cras pharetra quam eget posuere fermentum. Sed id tincidunt justo. Lorem ipsum dolor sit amet, consectetur adipiscing elit. +''' +# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. +[[dependencies.examplemod]] #optional + # the modid of the dependency + modId="forge" #mandatory + # Does this dependency have to exist - if not, ordering below must be specified + mandatory=true #mandatory + # The version range of the dependency + versionRange="[27,)" #mandatory + # An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory + ordering="NONE" + # Side this dependency is applied on - BOTH, CLIENT or SERVER + side="BOTH" +# Here's another dependency +[[dependencies.examplemod]] + modId="minecraft" + mandatory=true + versionRange="[1.14.3]" + ordering="NONE" + side="BOTH" \ No newline at end of file diff --git a/src/main/resources/assets/create/blockstates/symmetry_crossplane.json b/src/main/resources/assets/create/blockstates/symmetry_crossplane.json new file mode 100644 index 000000000..9e96d8f55 --- /dev/null +++ b/src/main/resources/assets/create/blockstates/symmetry_crossplane.json @@ -0,0 +1,7 @@ +{ + "forgemarker": 1, + "variants": { + "align=y": { "model": "create:block/symmetry_crossplane"}, + "align=d": { "model": "create:block/symmetry_crossplane_diagonal"} + } +} diff --git a/src/main/resources/assets/create/blockstates/symmetry_plane.json b/src/main/resources/assets/create/blockstates/symmetry_plane.json new file mode 100644 index 000000000..48859198d --- /dev/null +++ b/src/main/resources/assets/create/blockstates/symmetry_plane.json @@ -0,0 +1,7 @@ +{ + "forgemarker": 1, + "variants": { + "align=xy": { "model": "create:block/symmetry_plane" }, + "align=yz": { "model": "create:block/symmetry_plane", "y": 90 } + } +} diff --git a/src/main/resources/assets/create/blockstates/symmetry_tripleplane.json b/src/main/resources/assets/create/blockstates/symmetry_tripleplane.json new file mode 100644 index 000000000..2574d1eaf --- /dev/null +++ b/src/main/resources/assets/create/blockstates/symmetry_tripleplane.json @@ -0,0 +1,6 @@ +{ + "forgemarker": 1, + "variants": { + "": { "model": "create:block/symmetry_tripleplane" } + } +} diff --git a/src/main/resources/assets/create/lang/en_us.json b/src/main/resources/assets/create/lang/en_us.json new file mode 100644 index 000000000..248e40894 --- /dev/null +++ b/src/main/resources/assets/create/lang/en_us.json @@ -0,0 +1,4 @@ +{ + "item.create.symmetry_wand": "Staff of Symmetry", + "itemGroup.create": "Create" +} diff --git a/src/main/resources/assets/create/models/block/symmetry_crossplane.json b/src/main/resources/assets/create/models/block/symmetry_crossplane.json new file mode 100644 index 000000000..4e221b354 --- /dev/null +++ b/src/main/resources/assets/create/models/block/symmetry_crossplane.json @@ -0,0 +1,144 @@ +{ + "__comment": "Model generated using MrCrayfish's Model Creator (http://mrcrayfish.com/modelcreator/)", + "textures": { + "0": "block/white_stained_glass", + "1": "block/obsidian", + "2": "block/blue_terracotta" + }, + "elements": [ + { + "name": "Mirror", + "from": [ 4.0, 1.0, 7.500000007450581 ], + "to": [ 7.0, 12.0, 8.50000000745058 ], + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 4.0, 12.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, + "west": { "texture": "#0", "uv": [ 12.0, 1.0, 13.0, 12.0 ] }, + "up": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 2.0 ] }, + "down": { "texture": "#0", "uv": [ 4.0, 14.0, 7.0, 15.0 ] } + } + }, + { + "name": "rod_left_bottom", + "from": [ 1.2000000029802322, 3.0, 7.0 ], + "to": [ 3.2000000029802322, 4.0, 9.0 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -22.5 }, + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "rod_left_top", + "from": [ 1.2000000029802322, 12.0, 7.0 ], + "to": [ 3.2000000029802322, 13.0, 9.0 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -22.5 }, + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "rod_left", + "from": [ 2.0, 4.0, 7.499999992549419 ], + "to": [ 3.0, 12.0, 8.49999999254942 ], + "shade": false, + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -22.5 }, + "faces": { + "north": { "texture": "#2", "uv": [ 3.0, 1.0, 4.0, 9.0 ] }, + "east": { "texture": "#2", "uv": [ 3.0, 0.0, 4.0, 8.0 ] }, + "south": { "texture": "#2", "uv": [ 3.0, 1.0, 4.0, 9.0 ] }, + "west": { "texture": "#2", "uv": [ 5.0, 1.0, 6.0, 9.0 ] } + } + }, + { + "name": "rod_right_bottom", + "from": [ 12.799999997019768, 3.0, 7.0 ], + "to": [ 14.799999997019768, 4.0, 9.0 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -22.5 }, + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "rod_right", + "from": [ 13.0, 4.0, 7.499999992549419 ], + "to": [ 14.0, 12.0, 8.49999999254942 ], + "shade": false, + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -22.5 }, + "faces": { + "north": { "texture": "#2", "uv": [ 3.0, 2.0, 4.0, 10.0 ] }, + "east": { "texture": "#2", "uv": [ 3.0, 3.0, 4.0, 11.0 ] }, + "south": { "texture": "#2", "uv": [ 4.0, 3.0, 5.0, 11.0 ] }, + "west": { "texture": "#2", "uv": [ 5.0, 0.0, 6.0, 8.0 ] } + } + }, + { + "name": "rod_right_top", + "from": [ 12.799999997019768, 12.0, 7.0 ], + "to": [ 14.799999997019768, 13.0, 9.0 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -22.5 }, + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "CrossMirror", + "from": [ 7.499999992549419, 4.0, 9.50000000745058 ], + "to": [ 8.49999999254942, 15.0, 12.50000000745058 ], + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 6.0, 12.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, + "west": { "texture": "#0", "uv": [ 9.0, 1.0, 12.0, 12.0 ] }, + "up": { "texture": "#0", "uv": [ 3.0, 3.0, 4.0, 6.0 ] }, + "down": { "texture": "#0", "uv": [ 5.0, 9.0, 6.0, 12.0 ] } + } + }, + { + "name": "Mirror II", + "from": [ 9.0, 3.0, 7.500000007450581 ], + "to": [ 12.0, 14.0, 8.50000000745058 ], + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 4.0, 12.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, + "west": { "texture": "#0", "uv": [ 12.0, 1.0, 13.0, 12.0 ] }, + "up": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 2.0 ] }, + "down": { "texture": "#0", "uv": [ 4.0, 14.0, 7.0, 15.0 ] } + } + }, + { + "name": "CrossMirror II", + "from": [ 7.499999992549419, 2.0, 3.5000000074505806 ], + "to": [ 8.49999999254942, 13.0, 6.500000007450581 ], + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 6.0, 12.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 14.0 ] }, + "west": { "texture": "#0", "uv": [ 9.0, 2.0, 12.0, 13.0 ] }, + "up": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 6.0 ] }, + "down": { "texture": "#0", "uv": [ 4.0, 8.0, 5.0, 11.0 ] } + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/symmetry_crossplane_diagonal.json b/src/main/resources/assets/create/models/block/symmetry_crossplane_diagonal.json new file mode 100644 index 000000000..431ff819b --- /dev/null +++ b/src/main/resources/assets/create/models/block/symmetry_crossplane_diagonal.json @@ -0,0 +1,148 @@ +{ + "__comment": "Model generated using MrCrayfish's Model Creator (http://mrcrayfish.com/modelcreator/)", + "textures": { + "0": "block/white_stained_glass", + "1": "block/obsidian", + "2": "block/blue_terracotta" + }, + "elements": [ + { + "name": "Mirror", + "from": [ 4.0, 1.0, 7.500000007450581 ], + "to": [ 7.0, 12.0, 8.50000000745058 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": 45.0 }, + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 4.0, 12.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, + "west": { "texture": "#0", "uv": [ 12.0, 1.0, 13.0, 12.0 ] }, + "up": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 2.0 ] }, + "down": { "texture": "#0", "uv": [ 4.0, 14.0, 7.0, 15.0 ] } + } + }, + { + "name": "rod_left_bottom", + "from": [ 1.2000000029802322, 3.0, 7.0 ], + "to": [ 3.2000000029802322, 4.0, 9.0 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": 22.5 }, + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "rod_left_top", + "from": [ 1.2000000029802322, 12.0, 7.0 ], + "to": [ 3.2000000029802322, 13.0, 9.0 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": 22.5 }, + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "rod_left", + "from": [ 2.0, 4.0, 7.499999992549419 ], + "to": [ 3.0, 12.0, 8.49999999254942 ], + "shade": false, + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": 22.5 }, + "faces": { + "north": { "texture": "#2", "uv": [ 3.0, 1.0, 4.0, 9.0 ] }, + "east": { "texture": "#2", "uv": [ 3.0, 0.0, 4.0, 8.0 ] }, + "south": { "texture": "#2", "uv": [ 3.0, 1.0, 4.0, 9.0 ] }, + "west": { "texture": "#2", "uv": [ 5.0, 1.0, 6.0, 9.0 ] } + } + }, + { + "name": "rod_right_bottom", + "from": [ 12.799999997019768, 3.0, 7.0 ], + "to": [ 14.799999997019768, 4.0, 9.0 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": 22.5 }, + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "rod_right", + "from": [ 13.0, 4.0, 7.499999992549419 ], + "to": [ 14.0, 12.0, 8.49999999254942 ], + "shade": false, + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": 22.5 }, + "faces": { + "north": { "texture": "#2", "uv": [ 3.0, 2.0, 4.0, 10.0 ] }, + "east": { "texture": "#2", "uv": [ 3.0, 3.0, 4.0, 11.0 ] }, + "south": { "texture": "#2", "uv": [ 4.0, 3.0, 5.0, 11.0 ] }, + "west": { "texture": "#2", "uv": [ 5.0, 0.0, 6.0, 8.0 ] } + } + }, + { + "name": "rod_right_top", + "from": [ 12.799999997019768, 12.0, 7.0 ], + "to": [ 14.799999997019768, 13.0, 9.0 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": 22.5 }, + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "CrossMirror", + "from": [ 7.499999992549419, 4.0, 9.50000000745058 ], + "to": [ 8.49999999254942, 15.0, 12.50000000745058 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": 45.0 }, + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 6.0, 12.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, + "west": { "texture": "#0", "uv": [ 9.0, 1.0, 12.0, 12.0 ] }, + "up": { "texture": "#0", "uv": [ 3.0, 3.0, 4.0, 6.0 ] }, + "down": { "texture": "#0", "uv": [ 5.0, 9.0, 6.0, 12.0 ] } + } + }, + { + "name": "Mirror II", + "from": [ 9.0, 3.0, 7.500000007450581 ], + "to": [ 12.0, 14.0, 8.50000000745058 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": 45.0 }, + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 4.0, 12.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, + "west": { "texture": "#0", "uv": [ 12.0, 1.0, 13.0, 12.0 ] }, + "up": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 2.0 ] }, + "down": { "texture": "#0", "uv": [ 4.0, 14.0, 7.0, 15.0 ] } + } + }, + { + "name": "CrossMirror II", + "from": [ 7.499999992549419, 2.0, 3.5000000074505806 ], + "to": [ 8.49999999254942, 13.0, 6.500000007450581 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": 45.0 }, + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 6.0, 12.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 14.0 ] }, + "west": { "texture": "#0", "uv": [ 9.0, 2.0, 12.0, 13.0 ] }, + "up": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 6.0 ] }, + "down": { "texture": "#0", "uv": [ 4.0, 8.0, 5.0, 11.0 ] } + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/symmetry_plane.json b/src/main/resources/assets/create/models/block/symmetry_plane.json new file mode 100644 index 000000000..6b4c451ce --- /dev/null +++ b/src/main/resources/assets/create/models/block/symmetry_plane.json @@ -0,0 +1,99 @@ +{ + "__comment": "Model generated using MrCrayfish's Model Creator (http://mrcrayfish.com/modelcreator/)", + "textures": { + "0": "block/white_stained_glass", + "1": "block/obsidian", + "2": "block/blue_terracotta" + }, + "elements": [ + { + "name": "Mirror", + "from": [ 4.0, 1.0, 7.500000007450581 ], + "to": [ 12.0, 15.0, 8.50000000745058 ], + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 12.0, 15.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 4.0, 15.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 1.0, 12.0, 15.0 ] }, + "west": { "texture": "#0", "uv": [ 12.0, 1.0, 13.0, 15.0 ] }, + "up": { "texture": "#0", "uv": [ 4.0, 1.0, 12.0, 2.0 ] }, + "down": { "texture": "#0", "uv": [ 4.0, 14.0, 12.0, 15.0 ] } + } + }, + { + "name": "rod_left_bottom", + "from": [ 1.2000000029802322, 3.0, 7.0 ], + "to": [ 3.2000000029802322, 4.0, 9.0 ], + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "rod_left_top", + "from": [ 1.2000000029802322, 12.0, 7.0 ], + "to": [ 3.2000000029802322, 13.0, 9.0 ], + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "rod_left", + "from": [ 2.0, 4.0, 7.499999992549419 ], + "to": [ 3.0, 12.0, 8.49999999254942 ], + "shade": false, + "faces": { + "north": { "texture": "#2", "uv": [ 3.0, 1.0, 4.0, 9.0 ] }, + "east": { "texture": "#2", "uv": [ 3.0, 0.0, 4.0, 8.0 ] }, + "south": { "texture": "#2", "uv": [ 3.0, 1.0, 4.0, 9.0 ] }, + "west": { "texture": "#2", "uv": [ 5.0, 1.0, 6.0, 9.0 ] } + } + }, + { + "name": "rod_right_bottom", + "from": [ 12.799999997019768, 3.0, 7.0 ], + "to": [ 14.799999997019768, 4.0, 9.0 ], + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "rod_right", + "from": [ 13.0, 4.0, 7.499999992549419 ], + "to": [ 14.0, 12.0, 8.49999999254942 ], + "shade": false, + "faces": { + "north": { "texture": "#2", "uv": [ 3.0, 2.0, 4.0, 10.0 ] }, + "east": { "texture": "#2", "uv": [ 3.0, 3.0, 4.0, 11.0 ] }, + "south": { "texture": "#2", "uv": [ 4.0, 3.0, 5.0, 11.0 ] }, + "west": { "texture": "#2", "uv": [ 5.0, 0.0, 6.0, 8.0 ] } + } + }, + { + "name": "rod_right_top", + "from": [ 12.799999997019768, 12.0, 7.0 ], + "to": [ 14.799999997019768, 13.0, 9.0 ], + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/symmetry_tripleplane.json b/src/main/resources/assets/create/models/block/symmetry_tripleplane.json new file mode 100644 index 000000000..e29c91958 --- /dev/null +++ b/src/main/resources/assets/create/models/block/symmetry_tripleplane.json @@ -0,0 +1,172 @@ +{ + "__comment": "Model generated using MrCrayfish's Model Creator (http://mrcrayfish.com/modelcreator/)", + "textures": { + "0": "block/white_stained_glass", + "1": "block/obsidian", + "2": "block/blue_terracotta" + }, + "elements": [ + { + "name": "Mirror", + "from": [ 6.499999992549419, 1.0, 10.50000000745058 ], + "to": [ 9.49999999254942, 12.0, 11.50000000745058 ], + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 4.0, 12.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, + "west": { "texture": "#0", "uv": [ 12.0, 1.0, 13.0, 12.0 ] }, + "up": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 2.0 ] }, + "down": { "texture": "#0", "uv": [ 4.0, 14.0, 7.0, 15.0 ] } + } + }, + { + "name": "rod_left_bottom", + "from": [ 1.2000000029802322, 3.0, 7.0 ], + "to": [ 3.2000000029802322, 4.0, 9.0 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "rod_left_top", + "from": [ 1.2000000029802322, 12.0, 7.0 ], + "to": [ 3.2000000029802322, 13.0, 9.0 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "rod_left", + "from": [ 2.0, 4.0, 7.499999992549419 ], + "to": [ 3.0, 12.0, 8.49999999254942 ], + "shade": false, + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, + "faces": { + "north": { "texture": "#2", "uv": [ 3.0, 1.0, 4.0, 9.0 ] }, + "east": { "texture": "#2", "uv": [ 3.0, 0.0, 4.0, 8.0 ] }, + "south": { "texture": "#2", "uv": [ 3.0, 1.0, 4.0, 9.0 ] }, + "west": { "texture": "#2", "uv": [ 5.0, 1.0, 6.0, 9.0 ] } + } + }, + { + "name": "rod_right_bottom", + "from": [ 12.799999997019768, 3.0, 7.0 ], + "to": [ 14.799999997019768, 4.0, 9.0 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "rod_right", + "from": [ 13.0, 4.0, 7.499999992549419 ], + "to": [ 14.0, 12.0, 8.49999999254942 ], + "shade": false, + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, + "faces": { + "north": { "texture": "#2", "uv": [ 3.0, 2.0, 4.0, 10.0 ] }, + "east": { "texture": "#2", "uv": [ 3.0, 3.0, 4.0, 11.0 ] }, + "south": { "texture": "#2", "uv": [ 4.0, 3.0, 5.0, 11.0 ] }, + "west": { "texture": "#2", "uv": [ 5.0, 0.0, 6.0, 8.0 ] } + } + }, + { + "name": "rod_right_top", + "from": [ 12.799999997019768, 12.0, 7.0 ], + "to": [ 14.799999997019768, 13.0, 9.0 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }, + "up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "CrossMirror", + "from": [ 4.499999977648258, 2.0, 6.500000007450581 ], + "to": [ 5.499999977648258, 13.0, 9.50000000745058 ], + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 6.0, 12.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, + "west": { "texture": "#0", "uv": [ 9.0, 1.0, 12.0, 12.0 ] }, + "up": { "texture": "#0", "uv": [ 3.0, 3.0, 4.0, 6.0 ] }, + "down": { "texture": "#0", "uv": [ 5.0, 9.0, 6.0, 12.0 ] } + } + }, + { + "name": "Mirror II", + "from": [ 6.499999992549419, 3.0, 4.500000007450581 ], + "to": [ 9.49999999254942, 14.0, 5.500000007450581 ], + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 4.0, 12.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 12.0 ] }, + "west": { "texture": "#0", "uv": [ 12.0, 1.0, 13.0, 12.0 ] }, + "up": { "texture": "#0", "uv": [ 4.0, 1.0, 7.0, 2.0 ] }, + "down": { "texture": "#0", "uv": [ 4.0, 14.0, 7.0, 15.0 ] } + } + }, + { + "name": "CrossMirror II", + "from": [ 10.50000000745058, 4.0, 6.500000007450581 ], + "to": [ 11.50000000745058, 15.0, 9.50000000745058 ], + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 12.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 6.0, 12.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 14.0 ] }, + "west": { "texture": "#0", "uv": [ 9.0, 2.0, 12.0, 13.0 ] }, + "up": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 6.0 ] }, + "down": { "texture": "#0", "uv": [ 4.0, 8.0, 5.0, 11.0 ] } + } + }, + { + "name": "Cube", + "from": [ 7.499999992549419, 6.0, -0.4999999925494194 ], + "to": [ 8.49999999254942, 10.0, 3.5000000074505806 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 5.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 7.0, 5.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 7.0 ] }, + "west": { "texture": "#0", "uv": [ 9.0, 2.0, 13.0, 6.0 ] }, + "up": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 7.0 ] }, + "down": { "texture": "#0", "uv": [ 4.0, 8.0, 5.0, 12.0 ] } + } + }, + { + "name": "Cube", + "from": [ 7.499999992549419, 6.0, 12.50000000745058 ], + "to": [ 8.49999999254942, 10.0, 16.50000000745058 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": -45.0 }, + "faces": { + "north": { "texture": "#0", "uv": [ 4.0, 1.0, 5.0, 5.0 ] }, + "east": { "texture": "#0", "uv": [ 3.0, 1.0, 7.0, 5.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 7.0 ] }, + "west": { "texture": "#0", "uv": [ 9.0, 2.0, 13.0, 6.0 ] }, + "up": { "texture": "#0", "uv": [ 4.0, 3.0, 5.0, 7.0 ] }, + "down": { "texture": "#0", "uv": [ 4.0, 8.0, 5.0, 12.0 ] } + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/symmetry_wand.json b/src/main/resources/assets/create/models/item/symmetry_wand.json new file mode 100644 index 000000000..24cb1cb33 --- /dev/null +++ b/src/main/resources/assets/create/models/item/symmetry_wand.json @@ -0,0 +1,253 @@ +{ + "__comment": "Model generated using MrCrayfish's Model Creator (http://mrcrayfish.com/modelcreator/)", +"ambientocclusion": true, + "display": { + "firstperson_righthand": { + "rotation": [ 15, 0, 0 ], + "translation": [ 0, 0, -2], + "scale":[ 0.6, 0.6, 0.6 ] + }, + "thirdperson_righthand": { + "rotation": [ 15, 0, 0 ], + "translation": [ -1, 1, 1], + "scale":[ 0.5, 0.5, 0.5 ] + }, + "gui": { + "rotation": [ 40, 135, 32 ], + "translation": [ -1.2, -1, 3], + "scale":[ 0.8, 0.8, 0.8 ] + }, + "ground": { + "rotation": [ 0, 0, 0 ], + "translation": [ 0, 4.2, 0], + "scale":[ 0.4, 0.4, 0.4 ] + }, + "fixed": { + "rotation": [ 0, 90, 0 ], + "translation": [ -2, -1, 0 ], + "scale": [ 1, 1, 1 ] + } + }, + "textures": { + "0": "block/obsidian", + "1": "block/purple_concrete_powder", + "2": "block/dark_oak_log", + "3": "block/white_stained_glass", + "4": "block/purple_stained_glass", + "5": "block/white_concrete" + }, + "elements": [ + { + "name": "Grip Core", + "from": [ 6.500000007450581, -5.0, 6.500000007450581 ], + "to": [ 9.50000000745058, 6.0, 9.50000000745058 ], + "faces": { + "north": { "texture": "#0", "uv": [ 5.0, 1.0, 8.0, 12.0 ] }, + "east": { "texture": "#0", "uv": [ 2.0, 3.0, 5.0, 14.0 ] }, + "south": { "texture": "#0", "uv": [ 10.0, 1.0, 13.0, 12.0 ] }, + "west": { "texture": "#0", "uv": [ 7.0, 1.0, 10.0, 12.0 ] }, + "up": { "texture": "#-1", "uv": [ 0.0, 0.0, 3.0, 3.0 ] }, + "down": { "texture": "#0", "uv": [ 5.0, 6.0, 8.0, 9.0 ] } + } + }, + { + "name": "Rod Bottom Core", + "from": [ 6.500000007450581, 8.000000014901161, 6.500000007450581 ], + "to": [ 9.50000000745058, 17.00000001490116, 9.50000000745058 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": 45.0 }, + "faces": { + "north": { "texture": "#1", "uv": [ 5.0, 7.0, 8.0, 16.0 ] }, + "east": { "texture": "#1", "uv": [ 7.0, 7.0, 10.0, 16.0 ] }, + "south": { "texture": "#1", "uv": [ 1.0, 7.0, 4.0, 16.0 ] }, + "west": { "texture": "#1", "uv": [ 3.0, 7.0, 6.0, 16.0 ] }, + "up": { "texture": "#1", "uv": [ 12.0, 1.0, 15.0, 4.0 ] }, + "down": { "texture": "#2", "uv": [ 8.0, 10.0, 11.0, 13.0 ] } + } + }, + { + "name": "Grip Cap", + "from": [ 5.999999985098839, 6.0, 6.0 ], + "to": [ 9.999999985098839, 7.0, 10.0 ], + "faces": { + "north": { "texture": "#2", "uv": [ 2.0, 0.0, 6.0, 1.0 ] }, + "east": { "texture": "#2", "uv": [ 0.0, 0.0, 4.0, 1.0 ] }, + "south": { "texture": "#2", "uv": [ 0.0, 0.0, 4.0, 1.0 ] }, + "west": { "texture": "#2", "uv": [ 0.0, 1.0, 4.0, 2.0 ] }, + "up": { "texture": "#2", "uv": [ 10.0, 15.0, 14.0, 11.0 ] }, + "down": { "texture": "#2", "uv": [ 5.0, 3.0, 9.0, 7.0 ] } + } + }, + { + "name": "Rod Core", + "from": [ 7.0, 18.00000001490116, 7.0 ], + "to": [ 9.0, 26.00000001490116, 9.0 ], + "faces": { + "north": { "texture": "#5", "uv": [ 2.0, 2.0, 4.0, 10.0 ] }, + "east": { "texture": "#5", "uv": [ 4.0, 2.0, 6.0, 10.0 ] }, + "south": { "texture": "#5", "uv": [ 4.0, 2.0, 6.0, 10.0 ] }, + "west": { "texture": "#5", "uv": [ 8.0, 2.0, 10.0, 10.0 ] }, + "up": { "texture": "#5", "uv": [ 2.0, 2.0, 4.0, 4.0 ] }, + "down": { "texture": "#5", "uv": [ 2.0, 2.0, 4.0, 4.0 ] } + } + }, + { + "name": "Rod Top Core", + "from": [ 6.500000007450581, 27.00000001490116, 6.500000007450581 ], + "to": [ 9.50000000745058, 30.00000001490116, 9.50000000745058 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "y", "angle": 45.0 }, + "faces": { + "north": { "texture": "#1", "uv": [ 1.0, 4.0, 4.0, 7.0 ] }, + "east": { "texture": "#1", "uv": [ 1.0, 4.0, 4.0, 7.0 ] }, + "south": { "texture": "#1", "uv": [ 1.0, 4.0, 4.0, 7.0 ] }, + "west": { "texture": "#1", "uv": [ 1.0, 4.0, 4.0, 7.0 ] }, + "up": { "texture": "#1", "uv": [ 12.0, 1.0, 15.0, 4.0 ] }, + "down": { "texture": "#1", "uv": [ 12.0, 1.0, 15.0, 4.0 ] } + } + }, + { + "name": "Cap", + "from": [ 5.999999985098839, 31.0, 6.0 ], + "to": [ 9.999999985098839, 32.0, 10.0 ], + "faces": { + "north": { "texture": "#2", "uv": [ 0.0, 0.0, 4.0, 1.0 ] }, + "east": { "texture": "#2", "uv": [ 0.0, 0.0, 4.0, 1.0 ] }, + "south": { "texture": "#2", "uv": [ 0.0, 0.0, 4.0, 1.0 ] }, + "west": { "texture": "#2", "uv": [ 0.0, 0.0, 4.0, 1.0 ] }, + "up": { "texture": "#2", "uv": [ 7.0, 10.0, 11.0, 14.0 ] }, + "down": { "texture": "#2", "uv": [ 7.0, 10.0, 11.0, 14.0 ] } + } + }, + { + "name": "Grip Deco", + "from": [ 6.3000000193715096, 4.0, 6.3000000193715096 ], + "to": [ 9.700000025331974, 5.0, 9.700000025331974 ], + "faces": { + "north": { "texture": "#2", "uv": [ 2.0, 7.0, 5.4000000059604645, 8.0 ] }, + "east": { "texture": "#2", "uv": [ 4.0, 7.0, 7.4000000059604645, 8.0 ] }, + "south": { "texture": "#2", "uv": [ 6.0, 7.0, 9.400000005960464, 8.0 ] }, + "west": { "texture": "#2", "uv": [ 7.0, 7.0, 10.400000005960464, 8.0 ] } + } + }, + { + "name": "Rod Bottom Cap", + "from": [ 6.000000014901161, 16.0, 6.000000014901161 ], + "to": [ 10.000000014901161, 18.0, 10.000000014901161 ], + "rotation": { "origin": [ 8.0, 6.0, 8.0 ], "axis": "y", "angle": 45.0 }, + "faces": { + "north": { "texture": "#4", "uv": [ 2.0, 2.0, 6.0, 4.0 ] }, + "east": { "texture": "#4", "uv": [ 2.0, 2.0, 6.0, 4.0 ] }, + "south": { "texture": "#4", "uv": [ 2.0, 2.0, 6.0, 4.0 ] }, + "west": { "texture": "#4", "uv": [ 2.0, 2.0, 6.0, 4.0 ] } + } + }, + { + "name": "Rod Top Cap", + "from": [ 6.000000014901161, 26.0, 6.000000014901161 ], + "to": [ 10.000000014901161, 28.0, 10.000000014901161 ], + "rotation": { "origin": [ 8.0, 6.0, 8.0 ], "axis": "y", "angle": 45.0 }, + "faces": { + "north": { "texture": "#4", "uv": [ 2.0, 2.0, 6.0, 4.0 ] }, + "east": { "texture": "#4", "uv": [ 2.0, 2.0, 6.0, 4.0 ] }, + "south": { "texture": "#4", "uv": [ 2.0, 2.0, 6.0, 4.0 ] }, + "west": { "texture": "#4", "uv": [ 2.0, 2.0, 6.0, 4.0 ] } + } + }, + { + "name": "Square North", + "from": [ 7.499999992549419, 21.0, 3.0 ], + "to": [ 8.49999999254942, 23.0, 5.0 ], + "shade": false, + "rotation": { "origin": [ 9.0, 22.0, 5.0 ], "axis": "x", "angle": 45.0 }, + "faces": { + "north": { "texture": "#3", "uv": [ 2.0, 2.0, 3.0, 4.0 ] }, + "east": { "texture": "#3", "uv": [ 6.0, 6.0, 8.0, 8.0 ] }, + "south": { "texture": "#3", "uv": [ 8.0, 6.0, 9.0, 8.0 ] }, + "west": { "texture": "#3", "uv": [ 11.0, 9.0, 13.0, 11.0 ] }, + "up": { "texture": "#3", "uv": [ 9.0, 5.0, 6.0, 8.0 ] }, + "down": { "texture": "#3", "uv": [ 5.0, 7.0, 6.0, 9.0 ] } + } + }, + { + "name": "Square South", + "from": [ 7.499999992549419, 22.0, 10.0 ], + "to": [ 8.49999999254942, 24.0, 12.0 ], + "shade": false, + "rotation": { "origin": [ 13.0, 22.0, 11.0 ], "axis": "x", "angle": 45.0 }, + "faces": { + "north": { "texture": "#3", "uv": [ 2.0, 2.0, 3.0, 4.0 ] }, + "east": { "texture": "#3", "uv": [ 2.0, 2.0, 4.0, 4.0 ] }, + "south": { "texture": "#3", "uv": [ 2.0, 2.0, 3.0, 4.0 ] }, + "west": { "texture": "#3", "uv": [ 2.0, 2.0, 4.0, 4.0 ] }, + "up": { "texture": "#3", "uv": [ 2.0, 2.0, 3.0, 4.0 ] }, + "down": { "texture": "#3", "uv": [ 2.0, 2.0, 3.0, 4.0 ] } + } + }, + { + "name": "Rod Bottom Deco 1", + "from": [ 7.499999992549419, 9.0, 5.500000007450581 ], + "to": [ 8.49999999254942, 10.0, 10.50000000745058 ], + "faces": { + "north": { "texture": "#2", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }, + "east": { "texture": "#2", "uv": [ 0.0, 0.0, 5.0, 1.0 ] }, + "south": { "texture": "#2", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }, + "west": { "texture": "#2", "uv": [ 0.0, 0.0, 5.0, 1.0 ] }, + "up": { "texture": "#2", "uv": [ 0.0, 0.0, 1.0, 5.0 ] }, + "down": { "texture": "#2", "uv": [ 0.0, 0.0, 1.0, 5.0 ] } + } + }, + { + "name": "Rod Bottom Deco 2", + "from": [ 5.499999992549419, 9.0, 7.500000007450581 ], + "to": [ 10.49999999254942, 10.0, 8.50000000745058 ], + "faces": { + "north": { "texture": "#2", "uv": [ 0.0, 0.0, 5.0, 1.0 ] }, + "east": { "texture": "#2", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }, + "south": { "texture": "#2", "uv": [ 0.0, 0.0, 5.0, 1.0 ] }, + "west": { "texture": "#2", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }, + "up": { "texture": "#2", "uv": [ 0.0, 0.0, 5.0, 1.0 ] }, + "down": { "texture": "#2", "uv": [ 0.0, 0.0, 5.0, 1.0 ] } + } + }, + { + "name": "Square West", + "from": [ 11.49999999254942, 22.49999999254942, 7.499999992549419 ], + "to": [ 13.49999999254942, 24.49999999254942, 8.49999999254942 ], + "shade": false, + "rotation": { "origin": [ 13.0, 22.0, 11.0 ], "axis": "z", "angle": 45.0 }, + "faces": { + "north": { "texture": "#3", "uv": [ 2.0, 2.0, 4.0, 4.0 ] }, + "east": { "texture": "#3", "uv": [ 2.0, 2.0, 3.0, 4.0 ] }, + "south": { "texture": "#3", "uv": [ 2.0, 2.0, 4.0, 4.0 ] }, + "west": { "texture": "#3", "uv": [ 2.0, 2.0, 3.0, 4.0 ] }, + "up": { "texture": "#3", "uv": [ 2.0, 2.0, 4.0, 3.0 ] }, + "down": { "texture": "#3", "uv": [ 2.0, 2.0, 4.0, 3.0 ] } + } + }, + { + "name": "Square East", + "from": [ 6.499999992549419, 27.49999999254942, 7.499999992549419 ], + "to": [ 8.49999999254942, 29.49999999254942, 8.49999999254942 ], + "shade": false, + "rotation": { "origin": [ 13.0, 22.0, 11.0 ], "axis": "z", "angle": 45.0 }, + "faces": { + "north": { "texture": "#3", "uv": [ 2.0, 2.0, 4.0, 4.0 ] }, + "east": { "texture": "#3", "uv": [ 2.0, 2.0, 3.0, 4.0 ] }, + "south": { "texture": "#3", "uv": [ 2.0, 2.0, 4.0, 4.0 ] }, + "west": { "texture": "#3", "uv": [ 2.0, 2.0, 3.0, 4.0 ] }, + "up": { "texture": "#3", "uv": [ 2.0, 2.0, 4.0, 3.0 ] }, + "down": { "texture": "#3", "uv": [ 2.0, 2.0, 4.0, 3.0 ] } + } + }, + { + "name": "Cube", + "from": [ 6.3000000193715096, -4.0, 6.3000000193715096 ], + "to": [ 9.700000025331974, -3.0, 9.700000025331974 ], + "faces": { + "north": { "texture": "#2", "uv": [ 5.0, 15.0, 8.400000005960464, 16.0 ] }, + "east": { "texture": "#2", "uv": [ 8.0, 15.0, 11.400000005960464, 16.0 ] }, + "south": { "texture": "#2", "uv": [ 8.0, 15.0, 11.400000005960464, 16.0 ] }, + "west": { "texture": "#2", "uv": [ 7.0, 15.0, 3.4000000059604645, 16.0 ] } + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/block/marker/exporter.png b/src/main/resources/assets/create/textures/block/marker/exporter.png new file mode 100644 index 0000000000000000000000000000000000000000..89cf7a3119356618443bdc8e86e0770d7e78e4b9 GIT binary patch literal 258 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DjSK$uZf!>a)(C{f}XQ4*Y=R#Ki=l*&+$n3-3imzP?iV4`QJXWXmuHyx;^!PCVt z#KJ%M$N&HKt`a^!)V|1m^?Y-m>(IW=$=83W`Np?33NK&NwvutR_X}$#a|V?M^LB0Q z5aGG9xwVR|VNS2FpdHVpW&?&7?m1l_5+}?HWS+pwpe6+7$n9WcoN2bZe?^J zG%hhNGmRwuX8-^J1xZ9fR5(wik|`2{KoCXeKzKX~gW?LD0)s)}F(^C=gU6%roPq;% z_)UJ&)nu#6uX->`uQLssPCJ_9g|HMBtq_n@|IB}tNN1>}`%qG_6*6<9|Y_`U(xIIpVec?QEU$g(UN6{T6Q z2Kv62q9~+k8lA&O1E7pgL{X%F80UGeR|n8P*0q9ng3%$^yd|(F-+R|}n!!7G@KN!g z@Q3Dk)>02$oGgJE0fjN|`Or&8@@RpXA&kqi{H+CMw}H?K0^sDmgD1d{plm!4+%w(< luFX4mg1uJ@%KzSigd31_C09cGB8UJ0002ovPDHLkV1ggkp05A^ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/block/marker/inner.png b/src/main/resources/assets/create/textures/block/marker/inner.png new file mode 100644 index 0000000000000000000000000000000000000000..ae1426441f2bff6ebf53da9ccdaee6bb7c33b9cc GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|Ea{HEjtmSN`?>!lvI6;>1s;*b z3=Dh+L6~vJ#O${~L5ULAh?3y^w370~qEv>0#LT=By}Z;C1rt3(J>y=Lzv)0V`kpS1 zAr}70D^{<*y(yLZqYAUYe?=*VuMIg3pE?*8n+Y(xRb!lvI6;>1s;*b z3=Dh+L6~vJ#O${~L5ULAh?3y^w370~qEv>0#LT=By}Z;C1rt3(J<}BT2$0FCo-U3d z7XC{odGj$SayVD}zuW&oz-_6tvx;$zht~p=^Su_PE-7=HmfyFIW-e-1I-FVdQ&MBb@0Q-SOq5uE@ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/block/marker/inner_super_selected.png b/src/main/resources/assets/create/textures/block/marker/inner_super_selected.png new file mode 100644 index 0000000000000000000000000000000000000000..d7ee1d757ac0561fba6e941894dd3c9124c9e062 GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucL5ULAh?3y^w370~qEv>0#LT=By}Z;C1rt3( zJ>y=Lzv)0VS)MMAAr}5iFWu#05a3~bu=m2ejQ8~q6lR<|~K=?w1;HP;huCKNK`<}Pj#kA?YLbuHH8IJ41 mJCvRoyMg2CM! literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/block/marker/inner_transparent.png b/src/main/resources/assets/create/textures/block/marker/inner_transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..5d52d49a3c60b440d7306599f65061d55ca6e774 GIT binary patch literal 183 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=Dh+L6~vJ#O${~L5ULAh?3y^w370~qEv>0#LT=By}Z;C1rt3(J>y=Lzv)0Vrk*a2 zAr}70D^{=my+8HzwEs^o@hBv{zP6U7wa)R3=~(`$&kWPS#r0Y YAxzQT*#D~dAD{sYp00i_>zopr0De(8ssI20 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/block/marker/light.png b/src/main/resources/assets/create/textures/block/marker/light.png new file mode 100644 index 0000000000000000000000000000000000000000..4f2f340ce6372e086fccd194e2c95a46af7dced2 GIT binary patch literal 331 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=Dh+K$tP>S|=w^P@=>&q9iy!t)x7$D3zfgF*C13FE6!3!9>qc&$w6RZ#q!TNlzEY z5DWjQlXeRpG7xalU&1QHl+hTZuz*2m)dE&=heuW`nx-&mI9KGSwO@_;#&O=}_2b>P zZ%=-#v_EArM{5In-1+LQWqH$`JsBGwysn(DEG+vjc@F26CPtU79M2V4m$9!;*&XTj z*raSL`w9cwjcx{>e?PB?Wm>})C1-oEQ?>ugOHRL1CMN4!+}qtgiQQm!om?_M{8TAd z#)hy9E(;7*SYPbF%Kc9B-`<Sg0_ZR!G(EP|c YId$SI?YSvsKu0#LT=By}Z;C1rt3( zJ<}BT2#_@?o-U3d7XC}mALMK>5OBF@d#kDT=8OdMuxXdoW;efkI6EbvqRHObq4;~e zffgow)LFhg|NbYv{I_~Xn`7VZdiK-qTwYn8_Tq;>FJ+YY{dfKJ?(VGcQ&M|h>TmkF Q8fYJbr>mdKI;Vst0PL|;qyPW_ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/block/marker/trim.png b/src/main/resources/assets/create/textures/block/marker/trim.png new file mode 100644 index 0000000000000000000000000000000000000000..5f98a6f0a7187954d2324ab1516cde9b6afcfe38 GIT binary patch literal 215 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DkxK$!8B)5ZfpL5ULAh?3y^w370~qEv>0#LT=By}Z;C1rt3(J<}BT2$0F4o-U3d z7XC}mZ{%$-5MVjTpV_!Cqo-=cnTwHX2M-FZxp&DTVy@24Nm~+345TD@d)VBV7dKu! zkOAVpUh}(D?*F&D`_`uSlzfq2@!F63Z}*$s`Oz~!xF2DZDqab65d(v#tDnm{r-UW| DoQg@j literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/gui/background.png b/src/main/resources/assets/create/textures/gui/background.png new file mode 100644 index 0000000000000000000000000000000000000000..de5cde99c1d332042bf2e8cd04f2526ee8a06e32 GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DjGK$vmro+3}6phSslL`iUdT1k0gQ7S`0VrE{6US4X6f{C7?o^h|r-*liFLr)jS z5DWigj??k)MQ-`ooNRFC)Ap2?e!!u@;=bbu`%1PBlZj6t0cxJ2Hx49ln-b#F0TWs zQGakD{MqgG2V^dri!n0)ZM?ByZ&DtkR|JD*H|vB=dqh5b@Y6V>@SyC(zo0pn55ygK z+p}@Mu|Vn}x70GGJoZz6b04gj^u~KL=Z?AQ_T^#57g?S}%=ekT-{5S0bM2S-=k|Ox zZ?uKu8+UB4-}`Sf_Y1bF^21-4W;M!{f3aTTSp7V&h9EI+h15#zgg*CwtmaI9 z`a6TIyC-@xTHdKUQuyEn)2&M}+!BilXPDpaWHC5z6%dwv{vw<7PS?meA`?zq1!*TA zh-Q3JRhOE_@<#cF?|lpT^{2HN{cBTo6sFmojC07_^A2dug7+oI-tAoPExw=!=rO4O zN*F(e@&EE`{#F_sU8j(tmqN|LLV^&%zF@ zi@!BB>{&XK-h4*M=7!kY=8v8{{c`Ef9mc@5e;4)|#jcfZm1NOL*(yBYb=9FyEHUO> z#kvU(H|@Ql;UmtlQ`wDU0@Ni(Ar2a)rXYeKu&(YOBlBL*0NbfkJwf${r>mdKI;Vst E04SH~Hvj+t literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/gui/player_inventory.png b/src/main/resources/assets/create/textures/gui/player_inventory.png new file mode 100644 index 0000000000000000000000000000000000000000..0ab18ce9746b1607bfdd6f5e567d7af6110b7bcd GIT binary patch literal 2621 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/item/blueprint_empty.png b/src/main/resources/assets/create/textures/item/blueprint_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..105eeaae35ad6c04e32ef6a3f4b99a9a14e43cc1 GIT binary patch literal 317 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucL5ULAh?3y^w370~qEv>0#LT=By}Z;C1rt3( zJ>y=Lzv)0V>pWc?LoEEyPT0tM$Uwk#FMoH+lrs|rB^pE{6tx{3IaxIqE?l_r%SG#_ z-p4!?*FErF{(0`-e{<*ji~pW3W;i`}m)$15$y@AK-DP2@xZ$-surMz5kg^){)r~ti zCoKOoK_v0{~>&M4R_Da@Ef1hSOmV-Y>o33u3s}H?sSd2T-Lun6QIi(JYD@< J);T3K0RY5{cNzcy literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/item/blueprint_filled.png b/src/main/resources/assets/create/textures/item/blueprint_filled.png new file mode 100644 index 0000000000000000000000000000000000000000..9827887162201b62b54edd5487de7c6737b97184 GIT binary patch literal 351 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucL5ULAh?3y^w370~qEv>0#LT=By}Z;C1rt3( zJ>y=Lzv)0V7d%}YLoED{PB7$RG8Awvme=3pzVS1gQZ-BVN3OVo!W?;t${7onnwgn3 zPBee!EOJI|s=QrJ*|YsKRi>0wx_Hljt5j3(mffbY;ohwF-RsIHh##NgAG@ZEEk$VA zw*67EOXBw}ztq#naDyj|ov|S^rIdl;qejcJn}1#~9QvvDL*2!di@_lK^ZVNj71J;4 z?vg!V!Y9JQxZwMNF9}tA&tH_jVVL6l!*7mfizf22B*f-2?~$06@xZqv{F>?- r-Js~mU3_XsET_J@YVz?s*F)CzXEHNlH(wA0`i;TU)z4*}Q$iB};*fyZ literal 0 HcmV?d00001 diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta new file mode 100644 index 000000000..867ef98d9 --- /dev/null +++ b/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "create resources", + "pack_format": 4 + } +}