Setup Infrastructure

- Relevant Mod files
- Relevant Classes
- Resources
- Added Symmetry Wand from TMA
This commit is contained in:
simibubi 2019-07-11 09:03:08 +02:00
parent bed75516df
commit ddc846d860
66 changed files with 3809 additions and 0 deletions

42
.gitignore vendored Normal file
View file

@ -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

21
LICENSE Normal file
View file

@ -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.

149
build.gradle Normal file
View file

@ -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"
}
}
}

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

Binary file not shown.

View file

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

172
gradlew vendored Normal file
View file

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

84
gradlew.bat vendored Normal file
View file

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

View file

@ -0,0 +1,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<Block> registry) {
for (AllBlocks block : values()) {
registry.register(block.block);
}
}
public static void registerItemBlocks(IForgeRegistry<Item> 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;
}
}

View file

@ -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<Item> 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() {
}
}

View file

@ -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<Item> event) {
AllItems.registerItems(event.getRegistry());
AllBlocks.registerItemBlocks(event.getRegistry());
}
@SubscribeEvent
public static void registerBlocks(RegistryEvent.Register<Block> event) {
AllBlocks.registerBlocks(event.getRegistry());
}
}
}

View file

@ -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());
}
}

View file

@ -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<Predicate<Double>> 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<Double> 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<Double> callback) {
listeners.add(callback);
}
}

View file

@ -0,0 +1,5 @@
package com.simibubi.create.block;
public interface IJustForRendering {
}

View file

@ -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);
}
}

View file

@ -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<SymmetryCrossPlane.Align> 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<Block, BlockState> builder) {
builder.add(align);
super.fillStateContainer(builder);
}
}

View file

@ -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<SymmetryPlane.Align> 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<Block, BlockState> builder) {
builder.add(align);
super.fillStateContainer(builder);
}
}

View file

@ -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));
}
}

View file

@ -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<Widget> 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);
}
}
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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();
}
}

View file

@ -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<String> toolTip;
public AbstractSimiWidget(int xIn, int yIn, int widthIn, int heightIn) {
super(xIn, yIn, widthIn, heightIn, "");
toolTip = new LinkedList<>();
}
public List<String> getToolTip() {
return toolTip;
}
@Override
public void renderButton(int p_renderButton_1_, int p_renderButton_2_, float p_renderButton_3_) {
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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<String> options;
public OptionScrollArea(int xIn, int yIn, int widthIn, int heightIn) {
super(xIn, yIn, widthIn, heightIn);
options = new ArrayList<>();
}
public ScrollArea forOptions(List<String> 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());
}
}
}

View file

@ -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<Integer> 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<Integer> 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<List<String>> tooltipContent;
// private int min, max;
// private boolean limitless;
// private boolean numeric;
//
// public ScrollArea(List<String> 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<String> 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;
// }
}

View file

@ -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);
}
}

View file

@ -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<ItemStack> 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<BlockPos, BlockState> 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<BlockPos> 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<BlockPos, BlockState> 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<BlockPos> 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));
}
}

View file

@ -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);
}
}

View file

@ -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<BlockPos, BlockState> process(BlockPos position, BlockState block) {
Map<BlockPos, BlockState> 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<String> getAlignToolTips() {
return ImmutableList.of("Orthogonal", "Diagonal");
}
}

View file

@ -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<String> 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<BlockPos, BlockState> blocks) {
Map<BlockPos, BlockState> result = new HashMap<>();
for (BlockPos pos : blocks.keySet()) {
result.putAll(process(pos, blocks.get(pos)));
}
blocks.putAll(result);
}
public abstract Map<BlockPos, BlockState> 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<String> getAlignToolTips();
}

View file

@ -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<BlockPos, BlockState> process(BlockPos position, BlockState block) {
return new HashMap<>();
}
@Override
public String typeName() {
return EMPTY;
}
@Override
public BlockState getModel() {
return null;
}
@Override
public List<String> getAlignToolTips() {
return ImmutableList.of();
}
}

View file

@ -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<BlockPos, BlockState> process(BlockPos position, BlockState block) {
Map<BlockPos, BlockState> 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<String> getAlignToolTips() {
return ImmutableList.of("Mirror Z", "Mirror X");
}
}

View file

@ -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<BlockPos, BlockState> process(BlockPos position, BlockState block) {
Map<BlockPos, BlockState> 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<String> getAlignToolTips() {
return ImmutableList.of("Horizontal");
}
}

View file

@ -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) {
context.get().enqueueWork(() -> {
ServerPlayerEntity player = context.get().getSender();
ItemStack heldItem = player.getHeldItemMainhand();
if (heldItem.getItem() == stack.getItem()) {
heldItem.setTag(stack.getTag());
}
});
}
}

View file

@ -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<BlockPos> positions;
public PacketSymmetryEffect(BlockPos mirror, List<BlockPos> 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> context) {
if (Minecraft.getInstance().player.getPositionVector().distanceTo(new Vec3d(mirror)) > 100)
return;
for (BlockPos to : positions)
SymmetryHandler.drawEffect(mirror, to);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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();
}
}

View file

@ -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 <here>
#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"

View file

@ -0,0 +1,7 @@
{
"forgemarker": 1,
"variants": {
"align=y": { "model": "create:block/symmetry_crossplane"},
"align=d": { "model": "create:block/symmetry_crossplane_diagonal"}
}
}

View file

@ -0,0 +1,7 @@
{
"forgemarker": 1,
"variants": {
"align=xy": { "model": "create:block/symmetry_plane" },
"align=yz": { "model": "create:block/symmetry_plane", "y": 90 }
}
}

View file

@ -0,0 +1,6 @@
{
"forgemarker": 1,
"variants": {
"": { "model": "create:block/symmetry_tripleplane" }
}
}

View file

@ -0,0 +1,4 @@
{
"item.create.symmetry_wand": "Staff of Symmetry",
"itemGroup.create": "Create"
}

View file

@ -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 ] }
}
}
]
}

View file

@ -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 ] }
}
}
]
}

View file

@ -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 ] }
}
}
]
}

View file

@ -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 ] }
}
}
]
}

View file

@ -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 ] }
}
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

View file

@ -0,0 +1,6 @@
{
"pack": {
"description": "create resources",
"pack_format": 4
}
}