Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
517aabf219 | ||
|
|
40edf05109 | ||
|
|
4e5a92aff7 | ||
|
|
afc90899f9 | ||
|
|
a09e6058a9 | ||
|
|
f4546ac4f8 | ||
|
|
15e9be364a | ||
|
|
e774dd5e10 | ||
|
|
e864b9b292 | ||
|
|
0866dbee98 | ||
|
|
208f7ffc41 | ||
|
|
4f1edf1319 | ||
|
|
88a6021546 | ||
|
|
a05267a566 | ||
|
|
dd3413dcaa | ||
|
|
26b88a5f27 | ||
|
|
87903fead7 | ||
|
|
1166c651d2 | ||
|
|
7f42cc1de8 | ||
|
|
34394ef8a5 | ||
|
|
ff3904ec1a | ||
|
|
c3671609d3 | ||
|
|
7c0d3f4bd6 |
No files matched your search
@@ -0,0 +1,17 @@
|
||||
name: Optimize images
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master, main, release/** ]
|
||||
paths:
|
||||
- "**/*.png"
|
||||
|
||||
push:
|
||||
branches: [ master, main, release/** ]
|
||||
paths:
|
||||
- "**/*.png"
|
||||
|
||||
jobs:
|
||||
optimize-images:
|
||||
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/optimize-images.yml@master
|
||||
secrets: inherit
|
||||
@@ -1,9 +1,10 @@
|
||||
// Add your dependencies here
|
||||
|
||||
dependencies {
|
||||
api("com.github.GTNewHorizons:GTNHLib:0.6.39:dev")
|
||||
implementation("com.github.GTNewHorizons:NotEnoughItems:2.7.86-GTNH:dev")
|
||||
api("com.github.GTNewHorizons:GTNHLib:0.9.47:dev")
|
||||
implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.84-GTNH:dev")
|
||||
|
||||
testImplementation(platform('org.junit:junit-bom:5.9.2'))
|
||||
testImplementation('org.junit.jupiter:junit-jupiter')
|
||||
testRuntimeOnly ('org.junit.platform:junit-platform-launcher')
|
||||
}
|
||||
@@ -39,9 +39,33 @@ remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/co
|
||||
# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE.
|
||||
developmentEnvironmentUserName = Developer
|
||||
|
||||
# Enables using modern Java syntax (up to version 17) via Jabel, while still targeting JVM 8.
|
||||
# See https://github.com/bsideup/jabel for details on how this works.
|
||||
enableModernJavaSyntax = true
|
||||
# Enables modern Java syntax support. Valid values:
|
||||
# - false: No modern syntax, Java 8 only
|
||||
# - jabel: Jabel syntax-only support, compiles to J8 bytecode
|
||||
# - jvmDowngrader: Full modern Java via JVM Downgrader (syntax + stdlib APIs)
|
||||
# - modern: Native modern Java bytecode, no downgrading
|
||||
enableModernJavaSyntax = jabel
|
||||
|
||||
# If set, ignores the above setting and compiles with the given toolchain. This may cause unexpected issues,
|
||||
# and should *not* be used in most situations. -1 disables this.
|
||||
# forceToolchainVersion = -1
|
||||
|
||||
# Target JVM version for JVM Downgrader bytecode downgrading.
|
||||
# Only used when enableModernJavaSyntax = jvmDowngrader
|
||||
# downgradeTargetVersion = 8
|
||||
|
||||
# Comma-separated list of Java versions for multi-release jar support (JVM Downgrader only).
|
||||
# Classes will be available in META-INF/versions/N/ for each version N in this list.
|
||||
# Default: "21,25" (J25+ gets native classes, J21-24 gets partial downgrade, J8-20 gets full downgrade).
|
||||
# jvmDowngraderMultiReleaseVersions = 21,25
|
||||
|
||||
# Specifies how JVM Downgrader API stubs are provided. Options:
|
||||
# - shade: Shade minimized stubs into the jar
|
||||
# - gtnhlib: GTNHLib provides stubs at runtime (adds version constraint)
|
||||
# - external: Another dependency provides stubs (no constraint, no warning)
|
||||
# - (empty): Warning reminding you to configure stubs
|
||||
# Note: 'shade' option requires you to verify license compliance, see: https://github.com/unimined/JvmDowngrader/blob/main/LICENSE.md
|
||||
# jvmDowngraderStubsProvider =
|
||||
|
||||
# Enables injecting missing generics into the decompiled source code for a better coding experience.
|
||||
# Turns most publicly visible List, Map, etc. into proper List<E>, Map<K, V> types.
|
||||
@@ -96,7 +120,9 @@ usesMixinDebug = false
|
||||
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
|
||||
mixinPlugin =
|
||||
|
||||
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
|
||||
# Specify the package that contains all of your Mixins. The package must exist or
|
||||
# the build will fail. If you have a package property defined in your mixins.<modid>.json,
|
||||
# it must match with this or the build will fail.
|
||||
mixinsPackage = mixins
|
||||
|
||||
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
|
||||
@@ -172,6 +198,12 @@ curseForgeRelations =
|
||||
# projects. New projects should not use this parameter.
|
||||
# customArchiveBaseName =
|
||||
|
||||
# Optional parameter to customize the default working directory used by the runClient* tasks. Relative to the project directory.
|
||||
# runClientWorkingDirectory = run/client
|
||||
|
||||
# Optional parameter to customize the default working directory used by the runServer* tasks. Relative to the project directory.
|
||||
# runServerWorkingDirectory = run/server
|
||||
|
||||
# Optional parameter to have the build automatically fail if an illegal version is used.
|
||||
# This can be useful if you e.g. only want to allow versions in the form of '1.1.xxx'.
|
||||
# The check is ONLY performed if the version is a git tag.
|
||||
@@ -201,3 +233,6 @@ curseForgeRelations =
|
||||
# This is meant to be set in $HOME/.gradle/gradle.properties.
|
||||
# ideaCheckSpotlessOnBuild = true
|
||||
|
||||
# Non-GTNH properties
|
||||
org.gradle.configuration-cache = true
|
||||
org.gradle.parallel = true
|
||||
@@ -0,0 +1,12 @@
|
||||
#This file is generated by updateDaemonJvm
|
||||
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/1630f7ebef05444cb27a2709ea0249b3/redirect
|
||||
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/cd495626d2ee49a75447e3fdc6afb287/redirect
|
||||
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/1630f7ebef05444cb27a2709ea0249b3/redirect
|
||||
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/cd495626d2ee49a75447e3fdc6afb287/redirect
|
||||
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/d4fd992c9557644e637ebe98263e0ae7/redirect
|
||||
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/faa12903720d410b387cc69ccafb1a74/redirect
|
||||
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/1630f7ebef05444cb27a2709ea0249b3/redirect
|
||||
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/cd495626d2ee49a75447e3fdc6afb287/redirect
|
||||
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/a4c09dd2e2d7079373d30e524bbc2829/redirect
|
||||
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/8e1d9ee5d0f13e442218f6884a306da1/redirect
|
||||
toolchainVersion=25
|
||||
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
# Copyright © 2015 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -57,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -114,7 +114,6 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -172,7 +171,6 @@ fi
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
@@ -212,8 +210,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
||||
@@ -70,11 +70,10 @@ goto fail
|
||||
: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 %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
||||
@@ -17,7 +17,7 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.42'
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.24'
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,11 @@ import static java.lang.Math.abs;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
import org.joml.Vector3i;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.Direction;
|
||||
import com.gtnewhorizon.structurelib.coords.CoordinateSystem;
|
||||
import com.gtnewhorizon.structurelib.coords.Position;
|
||||
import com.gtnewhorizon.structurelib.util.Vec3Impl;
|
||||
|
||||
public class IntegerAxisSwap {
|
||||
@@ -91,4 +95,32 @@ public class IntegerAxisSwap {
|
||||
out[1] = forFirstAxis.get1() * point[0] + forSecondAxis.get1() * point[1] + forThirdAxis.get1() * point[2];
|
||||
out[2] = forFirstAxis.get2() * point[0] + forSecondAxis.get2() * point[1] + forThirdAxis.get2() * point[2];
|
||||
}
|
||||
|
||||
public Vector3i translate(Vector3i point) {
|
||||
return new Vector3i(
|
||||
forFirstAxis.get0() * point.x() + forFirstAxis.get1() * point.y() + forFirstAxis.get2() * point.z(),
|
||||
forSecondAxis.get0() * point.x() + forSecondAxis.get1() * point.y() + forSecondAxis.get2() * point.z(),
|
||||
forThirdAxis.get0() * point.x() + forThirdAxis.get1() * point.y() + forThirdAxis.get2() * point.z());
|
||||
}
|
||||
|
||||
public Vector3i inverseTranslate(Vector3i point) {
|
||||
return new Vector3i(
|
||||
forFirstAxis.get0() * point.x() + forSecondAxis.get0() * point.y() + forThirdAxis.get0() * point.z(),
|
||||
forFirstAxis.get1() * point.x() + forSecondAxis.get1() * point.y() + forThirdAxis.get1() * point.z(),
|
||||
forFirstAxis.get2() * point.x() + forSecondAxis.get2() * point.y() + forThirdAxis.get2() * point.z());
|
||||
}
|
||||
|
||||
public <C extends CoordinateSystem<C, ?>> Position<C> translate(Position<?> point) {
|
||||
return new Position<>(
|
||||
forFirstAxis.get0() * point.x() + forFirstAxis.get1() * point.y() + forFirstAxis.get2() * point.z(),
|
||||
forSecondAxis.get0() * point.x() + forSecondAxis.get1() * point.y() + forSecondAxis.get2() * point.z(),
|
||||
forThirdAxis.get0() * point.x() + forThirdAxis.get1() * point.y() + forThirdAxis.get2() * point.z());
|
||||
}
|
||||
|
||||
public <C extends CoordinateSystem<C, ?>> Position<C> inverseTranslate(Position<?> point) {
|
||||
return new Position<>(
|
||||
forFirstAxis.get0() * point.x() + forSecondAxis.get0() * point.y() + forThirdAxis.get0() * point.z(),
|
||||
forFirstAxis.get1() * point.x() + forSecondAxis.get1() * point.y() + forThirdAxis.get1() * point.z(),
|
||||
forFirstAxis.get2() * point.x() + forSecondAxis.get2() * point.y() + forThirdAxis.get2() * point.z());
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import net.minecraftforge.common.util.ForgeDirection;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.gtnewhorizon.structurelib.alignment.IAlignment;
|
||||
import com.gtnewhorizon.structurelib.alignment.IntegerAxisSwap;
|
||||
import com.gtnewhorizon.structurelib.coords.StructureRelativeCoords;
|
||||
import com.gtnewhorizon.structurelib.util.Vec3Impl;
|
||||
|
||||
public enum ExtendedFacing {
|
||||
@@ -166,6 +167,7 @@ public enum ExtendedFacing {
|
||||
|
||||
private final String name;
|
||||
private final IntegerAxisSwap integerAxisSwap;
|
||||
private final StructureRelativeCoords coordinateSystem;
|
||||
|
||||
ExtendedFacing(String name) {
|
||||
this.name = name;
|
||||
@@ -247,6 +249,7 @@ public enum ExtendedFacing {
|
||||
this.b = b;
|
||||
this.c = c;
|
||||
integerAxisSwap = new IntegerAxisSwap(a, b, c);
|
||||
coordinateSystem = new StructureRelativeCoords(integerAxisSwap);
|
||||
}
|
||||
|
||||
public static ExtendedFacing of(ForgeDirection direction, Rotation rotation, Flip flip) {
|
||||
@@ -437,4 +440,8 @@ public enum ExtendedFacing {
|
||||
public ForgeDirection getRelativeForwardInWorld() {
|
||||
return c.getOpposite();
|
||||
}
|
||||
|
||||
public StructureRelativeCoords asCoordinateSystem() {
|
||||
return coordinateSystem;
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,10 @@ public class BlockHint extends Block {
|
||||
|
||||
@Override
|
||||
public IIcon getIcon(int aSide, int aMeta) {
|
||||
// For numbered hints, top and bottom are blank
|
||||
if (aSide <= 1 && aMeta <= 11) {
|
||||
return hint[13];
|
||||
}
|
||||
return hint[aMeta];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.gtnewhorizon.structurelib.coords;
|
||||
|
||||
/**
|
||||
* Controller-relative coordinates. The controller is at 0,0,0. No axis swapping takes place, each axis points in the
|
||||
* same directions as the matching world axis.
|
||||
*/
|
||||
public class ControllerRelativeCoords implements CoordinateSystem<ControllerRelativeCoords, WorldCoords> {
|
||||
|
||||
public final int controllerX, controllerY, controllerZ;
|
||||
|
||||
public ControllerRelativeCoords(int controllerX, int controllerY, int controllerZ) {
|
||||
this.controllerX = controllerX;
|
||||
this.controllerY = controllerY;
|
||||
this.controllerZ = controllerZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position<ControllerRelativeCoords> translate(Position<WorldCoords> position) {
|
||||
return translate(position, controllerX, controllerY, controllerZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position<WorldCoords> translateInverse(Position<ControllerRelativeCoords> position) {
|
||||
return translateInverse(position, controllerX, controllerY, controllerZ);
|
||||
}
|
||||
|
||||
public static Position<ControllerRelativeCoords> translate(Position<WorldCoords> position, int controllerX,
|
||||
int controllerY, int controllerZ) {
|
||||
position.sub(controllerX, controllerY, controllerZ);
|
||||
|
||||
return CoordinateSystem.transmute(position);
|
||||
}
|
||||
|
||||
public static Position<WorldCoords> translateInverse(Position<ControllerRelativeCoords> position, int controllerX,
|
||||
int controllerY, int controllerZ) {
|
||||
position.add(controllerX, controllerY, controllerZ);
|
||||
|
||||
return CoordinateSystem.transmute(position);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.gtnewhorizon.structurelib.coords;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
|
||||
/**
|
||||
* A coordinate system is a statically-checked helper for determining which coordinates a {@link Position} has.
|
||||
* Translation methods never copy a {@link Position} - if a position must remain unchanged, it must be copied
|
||||
* separately. Most coordinate systems will have static methods that allow you to avoid allocations, though some (such
|
||||
* as the ones provided by {@link ExtendedFacing#asCoordinateSystem()}) have no reason to be static.
|
||||
*
|
||||
* @param <Self>
|
||||
* @param <Parent>
|
||||
*/
|
||||
public interface CoordinateSystem<Self extends CoordinateSystem<Self, Parent>, Parent extends CoordinateSystem<Parent, ?>> {
|
||||
|
||||
/**
|
||||
* Translates a position from the parent coordinate system into this one.
|
||||
*/
|
||||
Position<Self> translate(Position<Parent> position);
|
||||
|
||||
/**
|
||||
* Translates a position from this coordinate system into the parent.
|
||||
*/
|
||||
Position<Parent> translateInverse(Position<Self> position);
|
||||
|
||||
/**
|
||||
* Helper method that converts a position's coordinate system. Should not be used unless you know it's correct.
|
||||
*/
|
||||
static <P1 extends CoordinateSystem<P1, ?>, P2 extends CoordinateSystem<P2, ?>> Position<P1> transmute(
|
||||
Position<P2> pos) {
|
||||
// noinspection unchecked
|
||||
return (Position<P1>) pos;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.gtnewhorizon.structurelib.coords;
|
||||
|
||||
import net.minecraft.util.MathHelper;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.ChunkPosition;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector3i;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.blockpos.BlockPos;
|
||||
import com.gtnewhorizon.structurelib.util.Vec3Impl;
|
||||
|
||||
/**
|
||||
* A {@link BlockPos} with a statically-checked coordinate system.
|
||||
*/
|
||||
public class Position<C extends CoordinateSystem<C, ?>> extends BlockPos {
|
||||
|
||||
public Position() {
|
||||
|
||||
}
|
||||
|
||||
public Position(int x, int y, int z) {
|
||||
super(x, y, z);
|
||||
}
|
||||
|
||||
public Position(float x, float y, float z) {
|
||||
super(MathHelper.floor_float(x), MathHelper.floor_float(y), MathHelper.floor_float(z));
|
||||
}
|
||||
|
||||
public Position(double x, double y, double z) {
|
||||
super(MathHelper.floor_double(x), MathHelper.floor_double(y), MathHelper.floor_double(z));
|
||||
}
|
||||
|
||||
public Position(ChunkPosition chunkPosition) {
|
||||
super(chunkPosition);
|
||||
}
|
||||
|
||||
public Position(Vector3i v) {
|
||||
super(v.x, v.y, v.z);
|
||||
}
|
||||
|
||||
public Position(Vector3f v) {
|
||||
this(v.x, v.y, v.z);
|
||||
}
|
||||
|
||||
public Position(Vec3 v) {
|
||||
this(v.xCoord, v.yCoord, v.zCoord);
|
||||
}
|
||||
|
||||
public Position(Vec3Impl v) {
|
||||
this(v.get0(), v.get1(), v.get2());
|
||||
}
|
||||
|
||||
public Position<C> copy() {
|
||||
return new Position<>(x, y, z);
|
||||
}
|
||||
|
||||
public Vector3i toVector3i() {
|
||||
return new Vector3i(x, y, z);
|
||||
}
|
||||
|
||||
public Vector3f toVector3f() {
|
||||
return new Vector3f(x, y, z);
|
||||
}
|
||||
|
||||
public Vec3 toVec3() {
|
||||
return Vec3.createVectorHelper(x, y, z);
|
||||
}
|
||||
|
||||
public Vec3Impl toVec3Impl() {
|
||||
return new Vec3Impl(x, y, z);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.gtnewhorizon.structurelib.coords;
|
||||
|
||||
/// The structure definition-local coords. 0,0,0 is the front-most left-most top-most element. Coordinates increase as
|
||||
/// you go down, right, or back.
|
||||
public class StructureDefinitionCoords implements CoordinateSystem<StructureDefinitionCoords, StructureRelativeCoords> {
|
||||
|
||||
public final int offsetX, offsetY, offsetZ;
|
||||
|
||||
public StructureDefinitionCoords(int offsetX, int offsetY, int offsetZ) {
|
||||
this.offsetX = offsetX;
|
||||
this.offsetY = offsetY;
|
||||
this.offsetZ = offsetZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position<StructureDefinitionCoords> translate(Position<StructureRelativeCoords> position) {
|
||||
return translate(position, offsetX, offsetY, offsetZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position<StructureRelativeCoords> translateInverse(Position<StructureDefinitionCoords> position) {
|
||||
return translateInverse(position, offsetX, offsetY, offsetZ);
|
||||
}
|
||||
|
||||
public static Position<StructureDefinitionCoords> translate(Position<StructureRelativeCoords> position, int offsetX,
|
||||
int offsetY, int offsetZ) {
|
||||
position.add(offsetX, offsetY, offsetZ);
|
||||
|
||||
return CoordinateSystem.transmute(position);
|
||||
}
|
||||
|
||||
public static Position<StructureRelativeCoords> translateInverse(Position<StructureDefinitionCoords> position,
|
||||
int offsetX, int offsetY, int offsetZ) {
|
||||
position.sub(offsetX, offsetY, offsetZ);
|
||||
|
||||
return CoordinateSystem.transmute(position);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.gtnewhorizon.structurelib.coords;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.IntegerAxisSwap;
|
||||
|
||||
/**
|
||||
* Coordinates relative to the structure. 0,0,0 is the controller. 0,0,1 is the block immediately behind the controller
|
||||
* (looking at it from its face). 1,0,0 is the block to the right of the controller. 0,1,0 is the block below the
|
||||
* controller.
|
||||
*/
|
||||
public class StructureRelativeCoords implements CoordinateSystem<StructureRelativeCoords, ControllerRelativeCoords> {
|
||||
|
||||
public final IntegerAxisSwap axisSwap;
|
||||
|
||||
public StructureRelativeCoords(IntegerAxisSwap axisSwap) {
|
||||
this.axisSwap = axisSwap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position<StructureRelativeCoords> translate(Position<ControllerRelativeCoords> position) {
|
||||
position.set(axisSwap.translate(position));
|
||||
|
||||
return CoordinateSystem.transmute(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position<ControllerRelativeCoords> translateInverse(Position<StructureRelativeCoords> position) {
|
||||
position.set(axisSwap.inverseTranslate(position));
|
||||
|
||||
return CoordinateSystem.transmute(position);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.gtnewhorizon.structurelib.coords;
|
||||
|
||||
/**
|
||||
* World block coordinates
|
||||
*/
|
||||
public class WorldCoords implements CoordinateSystem<WorldCoords, WorldCoords> {
|
||||
|
||||
public static final WorldCoords INSTANCE = new WorldCoords();
|
||||
|
||||
private WorldCoords() {}
|
||||
|
||||
@Override
|
||||
public Position<WorldCoords> translate(Position<WorldCoords> position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position<WorldCoords> translateInverse(Position<WorldCoords> position) {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
@@ -261,6 +261,11 @@ public class GuiScreenConfigureChannels extends GuiContainer implements IGuiScre
|
||||
switch (aKey) {
|
||||
case Keyboard.KEY_TAB:
|
||||
if (key.isFocused()) {
|
||||
if (autoCompleteList.getSelectedElement() != null) {
|
||||
key.setText(autoCompleteList.getSelectedElement());
|
||||
return;
|
||||
}
|
||||
|
||||
key.setFocused(false);
|
||||
value.setFocused(true);
|
||||
} else {
|
||||
@@ -298,11 +303,10 @@ public class GuiScreenConfigureChannels extends GuiContainer implements IGuiScre
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (key.textboxKeyTyped(aChar, aKey)) {
|
||||
if (key.textboxKeyTyped(aChar, aKey) || value.textboxKeyTyped(aChar, aKey)) {
|
||||
updateButtons();
|
||||
return;
|
||||
}
|
||||
if (value.textboxKeyTyped(aChar, aKey)) return;
|
||||
super.keyTyped(aChar, aKey);
|
||||
}
|
||||
|
||||
@@ -313,7 +317,8 @@ public class GuiScreenConfigureChannels extends GuiContainer implements IGuiScre
|
||||
boolean existing = !StringUtils.isEmpty(keyText) && ChannelDataAccessor.hasSubChannel(trigger, keyText);
|
||||
getButtonList().get(ADD_BTN).displayString = existing ? I18n.format(I18N_PREFIX + "set")
|
||||
: I18n.format(I18N_PREFIX + "add");
|
||||
getButtonList().get(ADD_BTN).enabled = !StringUtils.isBlank(value.getText())
|
||||
getButtonList().get(ADD_BTN).enabled = !StringUtils.isBlank(key.getText())
|
||||
&& !StringUtils.isBlank(value.getText())
|
||||
&& Integer.parseInt(value.getText()) > 0;
|
||||
getButtonList().get(UNSET_BTN).enabled = existing && !StringUtils.isBlank(value.getText());
|
||||
|
||||
|
||||
@@ -3,8 +3,11 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
import static com.gtnewhorizon.structurelib.structure.IStructureWalker.ignoreBlockUnloaded;
|
||||
import static com.gtnewhorizon.structurelib.structure.IStructureWalker.skipBlockUnloaded;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -15,6 +18,8 @@ import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.coords.Position;
|
||||
import com.gtnewhorizon.structurelib.coords.StructureDefinitionCoords;
|
||||
|
||||
/**
|
||||
* This is the structure definition of your multi. You will have one of these for each multi.
|
||||
@@ -319,6 +324,65 @@ public interface IStructureDefinition<T> {
|
||||
return walker.getBuilt();
|
||||
}
|
||||
|
||||
default void iterate(String piece, World world, ExtendedFacing extendedFacing, int basePositionX, int basePositionY,
|
||||
int basePositionZ, int basePositionA, int basePositionB, int basePositionC, IStructureWalker<T> predicate) {
|
||||
StructureUtility.iterateV2(
|
||||
getStructureFor(piece),
|
||||
world,
|
||||
extendedFacing,
|
||||
basePositionX,
|
||||
basePositionY,
|
||||
basePositionZ,
|
||||
basePositionA,
|
||||
basePositionB,
|
||||
basePositionC,
|
||||
predicate,
|
||||
"customIterate");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controller position for a piece. Controller positions are denoted by a tilde.
|
||||
*
|
||||
* @param piece The piece name
|
||||
* @return The controller position, or null if it doesn't exist for the given piece
|
||||
*/
|
||||
Position<StructureDefinitionCoords> getControllerPosition(String piece);
|
||||
|
||||
/**
|
||||
* Gets the coordinate system for a piece. This is used to translate structure definition coordinates into structure
|
||||
* relative coordinates.
|
||||
*
|
||||
* @param piece The piece
|
||||
* @return The coordinate system
|
||||
* @throws IllegalArgumentException When the piece does not exist
|
||||
*/
|
||||
StructureDefinitionCoords getCoordinateSystem(String piece);
|
||||
|
||||
/**
|
||||
* Gets a socket from a piece.
|
||||
*
|
||||
* @param piece The piece name
|
||||
* @param socket The socket character
|
||||
* @return The socket's position
|
||||
* @throws IllegalArgumentException When the piece does not exist
|
||||
* @throws IllegalArgumentException When the socket does not exist
|
||||
* @throws IllegalStateException When more than one socket exists with this character
|
||||
* @see StructureDefinition.Builder#addSocket(char, char)
|
||||
*/
|
||||
Position<StructureDefinitionCoords> getSocket(String piece, char socket);
|
||||
|
||||
/**
|
||||
* Gets all sockets with a given character for a piece.
|
||||
*
|
||||
* @param piece The piece name
|
||||
* @param socket The socket character
|
||||
* @return The list of socket positions, or an empty list if the socket is not present
|
||||
* @throws IllegalArgumentException When the piece does not exist
|
||||
* @see StructureDefinition.Builder#addSocket(char, char)
|
||||
*/
|
||||
@Nonnull
|
||||
List<Position<StructureDefinitionCoords>> getAllSockets(String piece, char socket);
|
||||
|
||||
/**
|
||||
* Low level utility.
|
||||
*
|
||||
|
||||
@@ -2,8 +2,25 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
|
||||
interface IStructureWalker<T> {
|
||||
/**
|
||||
* A functional interface that is used to iterate over an arbitrary structure.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface IStructureWalker<T> {
|
||||
|
||||
/**
|
||||
* Called once per structure element.
|
||||
*
|
||||
* @param element The current element
|
||||
* @param world The current world
|
||||
* @param x The absolute X position of the element in world coordinates
|
||||
* @param y The absolute Y position of the element in world coordinates
|
||||
* @param z The absolute Z position of the element in world coordinates
|
||||
* @param a The relative A position of the element in structure-local coordinates (pre transform)
|
||||
* @param b The relative B position of the element in structure-local coordinates (pre transform)
|
||||
* @param c The relative C position of the element in structure-local coordinates (pre transform)
|
||||
* @return False to stop iterating, true to continue.
|
||||
*/
|
||||
boolean visit(IStructureElement<T> element, World world, int x, int y, int z, int a, int b, int c);
|
||||
|
||||
default boolean blockNotLoaded(IStructureElement<T> element, World world, int x, int y, int z, int a, int b,
|
||||
|
||||
@@ -4,33 +4,49 @@ import static com.gtnewhorizon.structurelib.structure.StructureUtility.isAir;
|
||||
import static com.gtnewhorizon.structurelib.structure.StructureUtility.notAir;
|
||||
import static com.gtnewhorizon.structurelib.structure.StructureUtility.step;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.MultimapBuilder;
|
||||
import com.gtnewhorizon.structurelib.coords.Position;
|
||||
import com.gtnewhorizon.structurelib.coords.StructureDefinitionCoords;
|
||||
import com.gtnewhorizon.structurelib.util.Vec3Impl;
|
||||
|
||||
import it.unimi.dsi.fastutil.chars.Char2CharOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.chars.CharOpenHashSet;
|
||||
|
||||
public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
|
||||
private final Map<Character, IStructureElement<T>> elements;
|
||||
private final Map<String, String> shapes;
|
||||
private final Map<String, IStructureElement<T>[]> structures;
|
||||
private final Map<String, Set<Vec3Impl>> occupiedSpaces;
|
||||
private final Map<String, Position<StructureDefinitionCoords>> controllers;
|
||||
private final Map<String, ListMultimap<Character, Position<StructureDefinitionCoords>>> socketLocations;
|
||||
|
||||
public static <B> Builder<B> builder() {
|
||||
return new Builder<>();
|
||||
}
|
||||
|
||||
private StructureDefinition(Map<Character, IStructureElement<T>> elements, Map<String, String> shapes,
|
||||
Map<String, IStructureElement<T>[]> structures, Map<String, Set<Vec3Impl>> occupiedSpaces) {
|
||||
Map<String, IStructureElement<T>[]> structures, Map<String, Set<Vec3Impl>> occupiedSpaces,
|
||||
Map<String, Position<StructureDefinitionCoords>> controllers,
|
||||
Map<String, ListMultimap<Character, Position<StructureDefinitionCoords>>> socketLocations) {
|
||||
this.elements = elements;
|
||||
this.shapes = shapes;
|
||||
this.structures = structures;
|
||||
this.occupiedSpaces = occupiedSpaces;
|
||||
this.controllers = controllers;
|
||||
this.socketLocations = socketLocations;
|
||||
}
|
||||
|
||||
public static class Builder<T> {
|
||||
@@ -41,12 +57,18 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
private char d = '\uD000';
|
||||
private final Map<Vec3Impl, Character> navigates;
|
||||
private final Map<Character, IStructureElement<T>> elements;
|
||||
private final Map<String, String[][]> uncompiledShapes;
|
||||
private final Map<String, String> shapes;
|
||||
private final Map<String, Set<Vec3Impl>> occupiedSpaces;
|
||||
|
||||
private final Map<String, Position<StructureDefinitionCoords>> controllers = new HashMap<>();
|
||||
private final Char2CharOpenHashMap socketTranslations = new Char2CharOpenHashMap();
|
||||
private final Map<String, ListMultimap<Character, Position<StructureDefinitionCoords>>> socketLocations = new HashMap<>();
|
||||
|
||||
private Builder() {
|
||||
navigates = new HashMap<>();
|
||||
elements = new HashMap<>();
|
||||
uncompiledShapes = new HashMap<>();
|
||||
shapes = new HashMap<>();
|
||||
occupiedSpaces = new HashMap<>();
|
||||
}
|
||||
@@ -82,7 +104,69 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder<T> addShape(String name, String[][] structurePiece) {
|
||||
uncompiledShapes.put(name, structurePiece);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use the unboxed version
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder<T> addElement(Character name, IStructureElement<T> structurePiece) {
|
||||
elements.putIfAbsent(name, structurePiece);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> addElement(char name, IStructureElement<T> structurePiece) {
|
||||
elements.putIfAbsent(name, structurePiece);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Denotes {@code name} as a socket. Sockets are virtual structure elements that record their position in the
|
||||
* structure for future retrieval. They are transformed into real structure elements and do not need their own
|
||||
* element (see {@code replacement}).
|
||||
*
|
||||
* @param name The socket name character
|
||||
* @param replacement The replacement character
|
||||
* @see IStructureDefinition#getSocket(String, char)
|
||||
* @see IStructureDefinition#getAllSockets(String, char)
|
||||
*/
|
||||
public Builder<T> addSocket(char name, char replacement) {
|
||||
socketTranslations.put(name, replacement);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #addSocket(char, char)} but without the replacement. The structure must have a structure element
|
||||
* with the given character.
|
||||
*
|
||||
* @param name The socket name character
|
||||
*/
|
||||
public Builder<T> addSocket(char name) {
|
||||
// Adding a name -> name entry like this isn't ideal but this is the cleanest solution
|
||||
socketTranslations.put(name, name);
|
||||
return this;
|
||||
}
|
||||
|
||||
public IStructureDefinition<T> build() {
|
||||
uncompiledShapes.forEach(this::compileShape);
|
||||
|
||||
Map<String, IStructureElement<T>[]> structures = compileStructureMap();
|
||||
|
||||
return new StructureDefinition<>(
|
||||
new HashMap<>(elements),
|
||||
new HashMap<>(shapes),
|
||||
structures,
|
||||
occupiedSpaces,
|
||||
controllers,
|
||||
socketLocations);
|
||||
}
|
||||
|
||||
private Builder<T> compileShape(String name, String[][] structurePiece) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (structurePiece.length > 0) {
|
||||
for (String[] strings : structurePiece) {
|
||||
if (strings.length > 0) {
|
||||
@@ -95,6 +179,11 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
}
|
||||
builder.setLength(builder.length() - 1);
|
||||
}
|
||||
|
||||
// Always create a map for this piece, even if it doesn't have any sockets
|
||||
// noinspection UnstableApiUsage
|
||||
socketLocations.put(name, MultimapBuilder.hashKeys().arrayListValues().build());
|
||||
|
||||
Set<Vec3Impl> occupiedSpace = new HashSet<>();
|
||||
// these track the global current location
|
||||
int aa = 0, bb = 0, cc = 0;
|
||||
@@ -103,6 +192,15 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
// I do know these are pretty bad variable naming, but I have no better idea
|
||||
for (int i = 0; i < builder.length(); i++) {
|
||||
char ch = builder.charAt(i);
|
||||
|
||||
// Translate the element char if it's a socket, and record the socket position
|
||||
if (socketTranslations.containsKey(ch)) {
|
||||
socketLocations.get(name).put(ch, new Position<>(aa, bb, cc));
|
||||
|
||||
ch = socketTranslations.get(ch);
|
||||
builder.setCharAt(i, ch);
|
||||
}
|
||||
|
||||
if (ch == ' ') {
|
||||
builder.setCharAt(i, A);
|
||||
ch = A;
|
||||
@@ -110,6 +208,7 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
builder.setCharAt(i, A);
|
||||
ch = A;
|
||||
occupiedSpace.add(Vec3Impl.getFromPool(aa, bb, cc));
|
||||
controllers.put(name, new Position<>(aa, bb, cc));
|
||||
}
|
||||
if (ch == A) {
|
||||
aa++;
|
||||
@@ -148,76 +247,87 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
|
||||
occupiedSpaces.put(name, occupiedSpace);
|
||||
|
||||
String built = builder.toString().replaceAll("[\\uA000\\uB000\\uC000]", "");
|
||||
boolean hasPlus = false;
|
||||
boolean hasMinus = false;
|
||||
|
||||
if (built.contains("+")) {
|
||||
int write = 0;
|
||||
for (int read = 0; read < builder.length(); read++) {
|
||||
char ch = builder.charAt(read);
|
||||
if (ch == A || ch == B || ch == C) {
|
||||
continue;
|
||||
}
|
||||
if (ch == '+') {
|
||||
hasPlus = true;
|
||||
} else if (ch == '-') {
|
||||
hasMinus = true;
|
||||
}
|
||||
if (read != write) builder.setCharAt(write, ch);
|
||||
write++;
|
||||
}
|
||||
builder.setLength(write);
|
||||
|
||||
if (hasPlus) {
|
||||
addElement('+', notAir());
|
||||
}
|
||||
if (built.contains("-")) {
|
||||
if (hasMinus) {
|
||||
addElement('-', isAir());
|
||||
}
|
||||
shapes.put(name, built);
|
||||
shapes.put(name, builder.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use the unboxed version
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder<T> addElement(Character name, IStructureElement<T> structurePiece) {
|
||||
elements.putIfAbsent(name, structurePiece);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> addElement(char name, IStructureElement<T> structurePiece) {
|
||||
elements.putIfAbsent(name, structurePiece);
|
||||
return this;
|
||||
}
|
||||
|
||||
public IStructureDefinition<T> build() {
|
||||
Map<String, IStructureElement<T>[]> structures = compileStructureMap();
|
||||
return new StructureDefinition<>(
|
||||
new HashMap<>(elements),
|
||||
new HashMap<>(shapes),
|
||||
structures,
|
||||
occupiedSpaces);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, IStructureElement<T>[]> compileElementSetMap() {
|
||||
Set<Integer> missing = findMissing();
|
||||
if (missing.isEmpty()) {
|
||||
return shapes.entrySet().stream().collect(
|
||||
Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
e -> e.getValue().chars().mapToObj(c -> (char) c).distinct().map(elements::get)
|
||||
.toArray(IStructureElement[]::new)));
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Missing Structure Element bindings for (chars as integers): "
|
||||
+ Arrays.toString(missing.toArray()));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, IStructureElement<T>[]> compileStructureMap() {
|
||||
Set<Integer> missing = findMissing();
|
||||
if (missing.isEmpty()) {
|
||||
return shapes.entrySet().stream().collect(
|
||||
Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
e -> e.getValue().chars().mapToObj(c -> elements.get((char) c))
|
||||
.toArray(IStructureElement[]::new)));
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Missing Structure Element bindings for (chars as integers): "
|
||||
+ Arrays.toString(missing.toArray()));
|
||||
CharOpenHashSet missing = findMissing();
|
||||
|
||||
if (!missing.isEmpty()) {
|
||||
throw new RuntimeException("Missing Structure Element bindings for: " + missing);
|
||||
}
|
||||
|
||||
Map<String, IStructureElement<T>[]> map = new HashMap<>();
|
||||
|
||||
for (Entry<String, String> e : shapes.entrySet()) {
|
||||
char[] chars = e.getValue().toCharArray();
|
||||
IStructureElement<T>[] compiled = new IStructureElement[chars.length];
|
||||
|
||||
int a = 0, b = 0, c = 0;
|
||||
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char ch = chars[i];
|
||||
|
||||
IStructureElement<T> element = this.elements.get(ch);
|
||||
|
||||
compiled[i] = element;
|
||||
|
||||
if (element.isNavigating()) {
|
||||
a = (element.resetA() ? 0 : a) + element.getStepA();
|
||||
b = (element.resetB() ? 0 : b) + element.getStepB();
|
||||
c = (element.resetC() ? 0 : c) + element.getStepC();
|
||||
} else {
|
||||
a++;
|
||||
}
|
||||
}
|
||||
|
||||
if (map.put(e.getKey(), compiled) != null) {
|
||||
throw new IllegalStateException("Duplicate shape: " + e.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private Set<Integer> findMissing() {
|
||||
return shapes.values().stream().flatMapToInt(CharSequence::chars)
|
||||
.filter(i -> !elements.containsKey((char) i)).boxed().collect(Collectors.toSet());
|
||||
private CharOpenHashSet findMissing() {
|
||||
CharOpenHashSet missing = new CharOpenHashSet();
|
||||
|
||||
for (String shape : shapes.values()) {
|
||||
for (char c : shape.toCharArray()) {
|
||||
if (!elements.containsKey(c)) {
|
||||
missing.add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return missing;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,4 +356,61 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
if (occupiedSpace == null) throw new NoSuchElementException(name);
|
||||
return occupiedSpace.contains(new Vec3Impl(offsetA, offsetB, offsetC));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position<StructureDefinitionCoords> getControllerPosition(String piece) {
|
||||
return controllers.get(piece);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinitionCoords getCoordinateSystem(String piece) {
|
||||
var controller = controllers.get(piece);
|
||||
|
||||
if (controller == null) {
|
||||
throw new IllegalArgumentException("Invalid piece: " + piece);
|
||||
}
|
||||
|
||||
return new StructureDefinitionCoords(controller.x, controller.y, controller.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position<StructureDefinitionCoords> getSocket(String piece, char socket) {
|
||||
var piecePositions = socketLocations.get(piece);
|
||||
|
||||
if (piecePositions == null) {
|
||||
throw new IllegalArgumentException("Invalid piece: " + piece);
|
||||
}
|
||||
|
||||
var positions = piecePositions.get(socket);
|
||||
|
||||
if (positions.isEmpty()) {
|
||||
throw new IllegalArgumentException("Socket " + socket + " for piece " + piece + " does not exist");
|
||||
}
|
||||
|
||||
if (positions.size() > 1) {
|
||||
throw new IllegalStateException(
|
||||
"Socket " + socket
|
||||
+ " for piece "
|
||||
+ piece
|
||||
+ " has several positions, but expected one and only one");
|
||||
}
|
||||
|
||||
return positions.get(0).copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public List<Position<StructureDefinitionCoords>> getAllSockets(String piece, char socket) {
|
||||
var piecePositions = socketLocations.get(piece);
|
||||
|
||||
if (piecePositions == null) {
|
||||
throw new IllegalArgumentException("Invalid piece: " + piece);
|
||||
}
|
||||
|
||||
var list = new ArrayList<>(piecePositions.get(socket));
|
||||
|
||||
list.replaceAll(Position::copy);
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,10 @@ import net.minecraft.item.ItemBlock;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
import net.minecraft.util.ChatComponentTranslation;
|
||||
import net.minecraft.util.ChatStyle;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.World;
|
||||
@@ -338,9 +341,7 @@ public class StructureUtility {
|
||||
ItemStack stack = new ItemStack(itemBlock, 1, itemMeta);
|
||||
if (!s.takeOne(stack, true)) {
|
||||
if (chatter != null) chatter.accept(
|
||||
new ChatComponentTranslation(
|
||||
"structurelib.autoplace.error.no_simple_block",
|
||||
stack.func_151000_E()));
|
||||
new ChatComponentTranslation("structurelib.autoplace.missing_block", stack.func_151000_E()));
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
if (block instanceof ICustomBlockSetting) {
|
||||
@@ -447,7 +448,7 @@ public class StructureUtility {
|
||||
if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor)) return PlaceResult.REJECT;
|
||||
if (!assumeStackPresent && !s.takeOne(stack, true)) {
|
||||
if (chatter != null) chatter.accept(
|
||||
new ChatComponentTranslation("structurelib.autoplace.error.no_item_stack", stack.func_151000_E()));
|
||||
new ChatComponentTranslation("structurelib.autoplace.missing_block", stack.func_151000_E()));
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
if (!stack.copy().tryPlaceItemIntoWorld(actor, world, x, y, z, ForgeDirection.UP.ordinal(), 0.5f, 0.5f, 0.5f))
|
||||
@@ -1411,6 +1412,53 @@ public class StructureUtility {
|
||||
} else {
|
||||
return new IStructureElement<T>() {
|
||||
|
||||
@Override
|
||||
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
BlocksToPlace e = getBlocksToPlace(t, world, x, y, z, trigger, env);
|
||||
IItemSource source = env.getSource();
|
||||
EntityPlayer actor = env.getActor();
|
||||
Consumer<IChatComponent> chatter = env.getChatter();
|
||||
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
|
||||
if (e.getStacks() == null) {
|
||||
ItemStack taken = source.takeOne(e.getPredicate(), true);
|
||||
return StructureUtility.survivalPlaceBlock(
|
||||
taken,
|
||||
NBTMode.EXACT,
|
||||
taken.stackTagCompound,
|
||||
false,
|
||||
world,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
source,
|
||||
actor,
|
||||
chatter);
|
||||
}
|
||||
for (ItemStack stack : e.getStacks()) {
|
||||
if (!source.takeOne(stack, true)) {
|
||||
IChatComponent name = new ChatComponentText(stack.getDisplayName());
|
||||
name.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.YELLOW));
|
||||
env.getChatter()
|
||||
.accept(new ChatComponentTranslation("structurelib.autoplace.missing_block", name));
|
||||
continue;
|
||||
}
|
||||
return StructureUtility.survivalPlaceBlock(
|
||||
stack,
|
||||
NBTMode.EXACT,
|
||||
stack.stackTagCompound,
|
||||
false,
|
||||
world,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
source,
|
||||
actor,
|
||||
chatter);
|
||||
}
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check(T t, World world, int x, int y, int z) {
|
||||
Block worldBlock = world.getBlock(x, y, z);
|
||||
|
||||
@@ -51,6 +51,7 @@ structurelib.autoplace.error.not_enabled=§cThis multiblock does not support aut
|
||||
structurelib.autoplace.error.no_simple_block=§cSuggested to place §r%s§c but none was found
|
||||
structurelib.autoplace.error.no_item_stack=§cSuggested to place block by using §r%s§c but none was found
|
||||
structurelib.autoplace.warning.no_explicit_channel=§6This structure depends on nonexistent sub channel §r%s§6. Using master channel instead.
|
||||
structurelib.autoplace.missing_block=§cMissing block: %s
|
||||
|
||||
structurelib.blockhint.desc.0=Helps while building
|
||||
structurelib.blockhint.0.name=Hint 1 dot
|
||||
|
||||
|
Before Width: | Height: | Size: 273 B After Width: | Height: | Size: 126 B |
|
Before Width: | Height: | Size: 279 B After Width: | Height: | Size: 154 B |
|
Before Width: | Height: | Size: 296 B After Width: | Height: | Size: 138 B |
|
Before Width: | Height: | Size: 301 B After Width: | Height: | Size: 160 B |
|
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 137 B |
|
Before Width: | Height: | Size: 281 B After Width: | Height: | Size: 138 B |
|
Before Width: | Height: | Size: 285 B After Width: | Height: | Size: 131 B |
|
Before Width: | Height: | Size: 289 B After Width: | Height: | Size: 141 B |
|
Before Width: | Height: | Size: 293 B After Width: | Height: | Size: 132 B |
|
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 138 B |
|
Before Width: | Height: | Size: 296 B After Width: | Height: | Size: 139 B |
|
Before Width: | Height: | Size: 297 B After Width: | Height: | Size: 143 B |
|
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 99 B |
|
Before Width: | Height: | Size: 301 B After Width: | Height: | Size: 132 B |
|
Before Width: | Height: | Size: 306 B After Width: | Height: | Size: 146 B |
|
Before Width: | Height: | Size: 281 B After Width: | Height: | Size: 115 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 367 B After Width: | Height: | Size: 276 B |
|
Before Width: | Height: | Size: 667 B After Width: | Height: | Size: 606 B |
|
Before Width: | Height: | Size: 439 B After Width: | Height: | Size: 361 B |
@@ -0,0 +1,102 @@
|
||||
package com.gtnewhorizon.structurelib.coords;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
|
||||
import com.gtnewhorizon.structurelib.structure.StructureUtility;
|
||||
|
||||
// spotless:off
|
||||
class CoordinateTests {
|
||||
|
||||
private IStructureDefinition<?> getDefinition() {
|
||||
String[][] main = {
|
||||
{ " ", " ", " ", " ", " " },
|
||||
{ " ", " ", " ", " ", " " },
|
||||
{ " ", " ", " X ", " ", " " },
|
||||
{ " ", " ", " YY ", " ", " " },
|
||||
{ " ~ ", " ", " ", " ", " " }
|
||||
};
|
||||
|
||||
return IStructureDefinition.builder()
|
||||
.addShape("main", StructureUtility.transpose(main))
|
||||
.addSocket('X', ' ')
|
||||
.addSocket('Y', ' ')
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSocketAndCoordSystemTranslationToWorld() {
|
||||
IStructureDefinition<?> def = getDefinition();
|
||||
|
||||
// Note: the position is the same object between all of these transforms, it is never copied, its generic just
|
||||
// changes
|
||||
|
||||
var p = def.getSocket("main", 'X');
|
||||
Assertions.assertEquals(new Position<>(2, 2, 2), p);
|
||||
|
||||
var p2 = def.getCoordinateSystem("main").translateInverse(p);
|
||||
Assertions.assertEquals(new Position<>(0, -2, 2), p2);
|
||||
|
||||
var p3 = ExtendedFacing.NORTH_NORMAL_NONE.asCoordinateSystem().translateInverse(p2);
|
||||
Assertions.assertEquals(new Position<>(0, 2, 2), p3);
|
||||
|
||||
var p4 = ControllerRelativeCoords.translateInverse(p3, 5, 5, 5);
|
||||
Assertions.assertEquals(new Position<>(5, 7, 7), p4);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSocketAndCoordSystemTranslationToStructureDef() {
|
||||
IStructureDefinition<?> def = getDefinition();
|
||||
|
||||
// Note: the position is the same object between all of these transforms, it is never copied, its generic just
|
||||
// changes
|
||||
|
||||
var p = new Position<WorldCoords>(5, 7, 7);
|
||||
|
||||
var p2 = ControllerRelativeCoords.translate(p, 5, 5, 5);
|
||||
Assertions.assertEquals(new Position<>(0, 2, 2), p2);
|
||||
|
||||
var p3 = ExtendedFacing.NORTH_NORMAL_NONE.asCoordinateSystem().translate(p2);
|
||||
Assertions.assertEquals(new Position<>(0, -2, 2), p3);
|
||||
|
||||
var p4 = def.getCoordinateSystem("main").translate(p3);
|
||||
Assertions.assertEquals(new Position<>(2, 2, 2), p4);
|
||||
|
||||
Assertions.assertEquals(def.getSocket("main", 'X'), p4);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSocketGetters() {
|
||||
IStructureDefinition<?> def = getDefinition();
|
||||
|
||||
Assertions.assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> def.getSocket("invalid", 'X'));
|
||||
Assertions.assertThrows(
|
||||
IllegalStateException.class,
|
||||
() -> def.getSocket("main", 'Y'));
|
||||
Assertions.assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> def.getSocket("main", 'Z'));
|
||||
|
||||
Assertions.assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> def.getAllSockets("invalid", 'X'));
|
||||
|
||||
Assertions.assertEquals(
|
||||
Collections.emptyList(),
|
||||
def.getAllSockets("main", 'Z'));
|
||||
Assertions.assertEquals(
|
||||
Arrays.asList(new Position<>(2, 2, 2)),
|
||||
def.getAllSockets("main", 'X'));
|
||||
Assertions.assertEquals(
|
||||
Arrays.asList(new Position<>(2, 3, 2), new Position<>(3, 3, 2)),
|
||||
def.getAllSockets("main", 'Y'));
|
||||
}
|
||||
}
|
||||
// spotless:on
|
||||