mirror of
https://github.com/GTNewHorizons/StructureLib.git
synced 2026-11-09 15:04:56 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6d2af2170 | ||
|
|
8309567076 | ||
|
|
23312198a6 | ||
|
|
fa5e2ae4ca | ||
|
|
a8a1547845 | ||
|
|
113e05b7e6 | ||
|
|
080785ad05 | ||
|
|
6c14ca0a1d | ||
|
|
ea38c4e1d6 | ||
|
|
50e8c97aa3 | ||
|
|
9a82239f2c | ||
|
|
8ed2be38eb | ||
|
|
582f59e73d | ||
|
|
464e44de85 | ||
|
|
392d2ace8a | ||
|
|
978938d450 | ||
|
|
7a2328c294 | ||
|
|
d2cd45e07b | ||
|
|
8a24900623 | ||
|
|
15a0034e03 | ||
|
|
7aae6dc31c | ||
|
|
875bc1990e | ||
|
|
74aefd22be | ||
|
|
72ff51d093 | ||
|
|
7d74a65ec0 | ||
|
|
0ac8908b37 | ||
|
|
2dd4349e54 | ||
|
|
f813104ec4 | ||
|
|
4fe9eb6ea5 | ||
|
|
c0814274ec | ||
|
|
23605fc22d | ||
|
|
8ee90a7338 | ||
|
|
9bd19b9254 | ||
|
|
df4c54ea8d | ||
|
|
e71edd50b0 | ||
|
|
1b7cee7c4e |
No files matched your search
@@ -0,0 +1,2 @@
|
||||
# Ignore spotlessApply reformat
|
||||
464e44de8541a46833f50c3bd363d50e1677a685
|
||||
+42
-20
@@ -1,22 +1,44 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
* text eol=lf
|
||||
|
||||
# Custom for Visual Studio
|
||||
*.cs diff=csharp
|
||||
*.sln merge=union
|
||||
*.csproj merge=union
|
||||
*.vbproj merge=union
|
||||
*.fsproj merge=union
|
||||
*.dbproj merge=union
|
||||
*.[jJ][aA][rR] binary
|
||||
|
||||
# Standard to msysgit
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
*.[pP][nN][gG] binary
|
||||
*.[jJ][pP][gG] binary
|
||||
*.[jJ][pP][eE][gG] binary
|
||||
*.[gG][iI][fF] binary
|
||||
*.[tT][iI][fF] binary
|
||||
*.[tT][iI][fF][fF] binary
|
||||
*.[iI][cC][oO] binary
|
||||
*.[sS][vV][gG] text
|
||||
*.[eE][pP][sS] binary
|
||||
*.[xX][cC][fF] binary
|
||||
|
||||
*.[kK][aA][rR] binary
|
||||
*.[mM]4[aA] binary
|
||||
*.[mM][iI][dD] binary
|
||||
*.[mM][iI][dD][iI] binary
|
||||
*.[mM][pP]3 binary
|
||||
*.[oO][gG][gG] binary
|
||||
*.[rR][aA] binary
|
||||
|
||||
*.7[zZ] binary
|
||||
*.[gG][zZ] binary
|
||||
*.[tT][aA][rR] binary
|
||||
*.[tT][gG][zZ] binary
|
||||
*.[zZ][iI][pP] binary
|
||||
|
||||
*.[tT][cC][nN] binary
|
||||
*.[sS][oO] binary
|
||||
*.[dD][lL][lL] binary
|
||||
*.[dD][yY][lL][iI][bB] binary
|
||||
*.[pP][sS][dD] binary
|
||||
*.[tT][tT][fF] binary
|
||||
*.[oO][tT][fF] binary
|
||||
|
||||
*.[pP][aA][tT][cC][hH] -text
|
||||
|
||||
*.[bB][aA][tT] text eol=crlf
|
||||
*.[cC][mM][dD] text eol=crlf
|
||||
*.[pP][sS]1 text eol=crlf
|
||||
|
||||
*[aA][uU][tT][oO][gG][eE][nN][eE][rR][aA][tT][eE][dD]* binary
|
||||
@@ -1,47 +0,0 @@
|
||||
# Simple workflow for deploying static content to GitHub Pages
|
||||
name: Deploy static content to Pages
|
||||
|
||||
on:
|
||||
# Runs on pushes targeting the default branch
|
||||
push:
|
||||
branches: ["gh-pages"]
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
# Allow one concurrent deployment
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Single deploy job since we're just deploying
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v2
|
||||
- name: Generate Index
|
||||
shell: bash
|
||||
run: |
|
||||
find . -name javadoc -type d -print > index.txt
|
||||
echo feature/doc >> index.txt
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v1
|
||||
with:
|
||||
# Upload entire repository
|
||||
path: '.'
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v1
|
||||
@@ -20,13 +20,16 @@ jobs:
|
||||
outputs:
|
||||
result_hash: ${{ steps.deploy.outputs.hash }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-java@v2
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 8
|
||||
java-version: |
|
||||
8
|
||||
11
|
||||
17
|
||||
distribution: 'temurin'
|
||||
cache: gradle
|
||||
|
||||
@@ -51,7 +54,7 @@ jobs:
|
||||
echo Nothing to deploy
|
||||
exit 0
|
||||
fi
|
||||
find . -name javadoc -type d -print | sed 's#^\./\(.*\)/javadoc$#\1#' > index.txt
|
||||
find . -name javadoc -type d -print | sed 's#^\./\(.*\)/javadoc$#\1#' | sort --version-sort --reverse > index.txt
|
||||
git add index.txt
|
||||
git config user.name "${GITHUB_ACTOR}"
|
||||
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
|
||||
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@@ -32,3 +32,5 @@ The project is developed using IDEA. Please manually configure the build to not
|
||||
Due to me adding in ItemStackMap, which was derived from code from CodeChicken's LGPL mod NEI. This mod is effectively considered
|
||||
licensed under LGPL in its entirety since commit ebef584b8c518f8202cfe0984fb28a6d23e52b3d or any squash commit containing it, e.g.
|
||||
609e50428ee4e293f65f67f554a70b9fcfae97c4.
|
||||
|
||||
Note while the LICENSE.txt is added by a much later commit, all code on previous commits are covered by this as well.
|
||||
+20
-2
@@ -1,4 +1,10 @@
|
||||
javadoc {
|
||||
javadocTool = javaToolchains.javadocToolFor {
|
||||
// Last version with frames, but it also has search
|
||||
languageVersion = JavaLanguageVersion.of(11)
|
||||
vendor = JvmVendorSpec.ADOPTIUM
|
||||
}
|
||||
|
||||
inputs.file "src/main/javadoc/overview.html"
|
||||
|
||||
include "com/gtnewhorizon/structurelib/alignment/**"
|
||||
@@ -6,19 +12,31 @@ javadoc {
|
||||
include "com/gtnewhorizon/structurelib/structure/**"
|
||||
include "com/gtnewhorizon/structurelib/util/**"
|
||||
include "com/gtnewhorizon/structurelib/StructureLibAPI.java"
|
||||
include "com/gtnewhorizon/structurelib/StructureEvent.java"
|
||||
|
||||
classpath += sourceSets.patchedMc.output
|
||||
|
||||
options {
|
||||
overview "src/main/javadoc/overview.html"
|
||||
links 'https://docs.oracle.com/javase/8/docs/api/'
|
||||
links 'https://skmedix.github.io/ForgeJavaDocs/javadoc/forge/1.7.10-10.13.4.1614/'
|
||||
addBooleanOption("-frames", true)
|
||||
}
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||
classifier = 'javadoc'
|
||||
tasks.register('javadocJar', Jar) {
|
||||
dependsOn javadoc
|
||||
archiveClassifier = 'javadoc'
|
||||
from javadoc.destinationDir
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives javadocJar
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events "passed", "skipped", "failed"
|
||||
}
|
||||
}
|
||||
+880
-560
File diff suppressed because it is too large.
Load diff
+5
-2
@@ -1,6 +1,9 @@
|
||||
// Add your dependencies here
|
||||
|
||||
dependencies {
|
||||
compile("com.github.GTNewHorizons:GTNHLib:0.0.1:dev")
|
||||
runtime("com.github.GTNewHorizons:NotEnoughItems:2.2.20-GTNH:dev")
|
||||
api("com.github.GTNewHorizons:GTNHLib:0.0.10:dev")
|
||||
runtimeOnly("com.github.GTNewHorizons:NotEnoughItems:2.3.46-GTNH:dev")
|
||||
|
||||
testImplementation(platform('org.junit:junit-bom:5.9.2'))
|
||||
testImplementation('org.junit.jupiter:junit-jupiter')
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
+2
-1
@@ -1,5 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -17,78 +17,113 @@
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# 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"`
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# 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
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | 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"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
@@ -105,84 +140,105 @@ 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 or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; 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" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
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, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
# 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" )
|
||||
|
||||
# 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")"
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
Vendored
+15
-23
@@ -14,7 +14,7 @@
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,10 +25,14 @@
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@@ -37,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -51,7 +55,7 @@ goto fail
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
@@ -61,38 +65,26 @@ 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%
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 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
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
+21
-3
@@ -1,10 +1,28 @@
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
maven {
|
||||
// RetroFuturaGradle
|
||||
name "GTNH Maven"
|
||||
url "http://jenkins.usrv.eu:8081/nexus/content/groups/public/"
|
||||
allowInsecureProtocol = true
|
||||
mavenContent {
|
||||
includeGroup("com.gtnewhorizons.retrofuturagradle")
|
||||
}
|
||||
}
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.diffplug.blowdryerSetup' version '1.6.0'
|
||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.4.0' // Provides java toolchains
|
||||
}
|
||||
|
||||
apply plugin: 'com.diffplug.blowdryerSetup'
|
||||
|
||||
blowdryerSetup {
|
||||
github('GTNewHorizons/ExampleMod1.7.10', 'tag', '0.1.4')
|
||||
repoSubfolder 'gtnhShared'
|
||||
github('GTNewHorizons/ExampleMod1.7.10', 'tag', '0.2.0')
|
||||
//devLocal '.' // Use this when testing config updates locally
|
||||
}
|
||||
@@ -2,21 +2,14 @@ package com.gtnewhorizon.structurelib;
|
||||
|
||||
import static com.gtnewhorizon.structurelib.StructureLib.RANDOM;
|
||||
|
||||
import com.gtnewhorizon.structurelib.entity.fx.WeightlessParticleFX;
|
||||
import com.gtnewhorizon.structurelib.net.SetChannelDataMessage;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.common.gameevent.TickEvent.ClientTickEvent;
|
||||
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
|
||||
import java.util.*;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiNewChat;
|
||||
import net.minecraft.client.particle.EntityFX;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.culling.Frustrum;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
@@ -31,19 +24,28 @@ import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import com.gtnewhorizon.structurelib.entity.fx.WeightlessParticleFX;
|
||||
import com.gtnewhorizon.structurelib.net.SetChannelDataMessage;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.common.gameevent.TickEvent.ClientTickEvent;
|
||||
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
|
||||
|
||||
public class ClientProxy extends CommonProxy {
|
||||
|
||||
private static final short[] RGBA_NO_TINT = {255, 255, 255, 255};
|
||||
private static final short[] RGBA_RED_TINT = {255, 128, 128, 0};
|
||||
private static final short[] RGBA_NO_TINT = { 255, 255, 255, 255 };
|
||||
private static final short[] RGBA_RED_TINT = { 255, 128, 128, 0 };
|
||||
private static final Map<HintParticleInfo, HintGroup> allHints = new HashMap<>();
|
||||
/**
|
||||
* All batches of hints.
|
||||
*/
|
||||
private static final List<HintGroup> allGroups = new ArrayList<>();
|
||||
|
||||
public static int HOLOGRAM_LIFETIME = 200;
|
||||
/**
|
||||
* Current batch of hints. Belongs to the same logical multiblock.
|
||||
*/
|
||||
@@ -55,11 +57,10 @@ public class ClientProxy extends CommonProxy {
|
||||
*/
|
||||
private static final List<HintParticleInfo> allHintsForRender = new ArrayList<>(10000);
|
||||
/**
|
||||
* If the diff to current player position is too great sort the allHints.
|
||||
* Initial value is very far off below y=0 but not huge enough to make a NaN.
|
||||
* If the diff to current player position is too great sort the allHints. Initial value is very far off below y=0
|
||||
* but not huge enough to make a NaN.
|
||||
* <p>
|
||||
* We are using this supposedly immutable object as a mutable object here.
|
||||
* So be aware.
|
||||
* We are using this supposedly immutable object as a mutable object here. So be aware.
|
||||
*/
|
||||
private static final Vec3 lastPlayerPos = Vec3.createVectorHelper(0, -1e30, 0);
|
||||
/**
|
||||
@@ -158,11 +159,7 @@ public class ClientProxy extends CommonProxy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addThrottledChat(
|
||||
Object throttleKey,
|
||||
EntityPlayer player,
|
||||
IChatComponent text,
|
||||
short intervalRequired,
|
||||
public void addThrottledChat(Object throttleKey, EntityPlayer player, IChatComponent text, short intervalRequired,
|
||||
boolean forceUpdateLastSend) {
|
||||
if (player instanceof EntityPlayerMP)
|
||||
super.addThrottledChat(throttleKey, player, text, intervalRequired, forceUpdateLastSend);
|
||||
@@ -250,6 +247,7 @@ public class ClientProxy extends CommonProxy {
|
||||
}
|
||||
|
||||
private static class HintGroup {
|
||||
|
||||
private final List<HintParticleInfo> hints = new LinkedList<>();
|
||||
private int creationTime = -1;
|
||||
|
||||
@@ -267,9 +265,10 @@ public class ClientProxy extends CommonProxy {
|
||||
}
|
||||
|
||||
private static class HintParticleInfo {
|
||||
|
||||
private final World w;
|
||||
// these are the block coordinate for e.g. w.getBlock()
|
||||
private final int x, y, z;
|
||||
private final double X, Y, Z;
|
||||
private final IIcon[] icons;
|
||||
private short[] tint;
|
||||
private boolean renderThrough;
|
||||
@@ -281,9 +280,6 @@ public class ClientProxy extends CommonProxy {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
X = x + 0.25;
|
||||
Y = y + 0.25;
|
||||
Z = z + 0.25;
|
||||
this.icons = icons;
|
||||
this.tint = tint;
|
||||
}
|
||||
@@ -319,10 +315,11 @@ public class ClientProxy extends CommonProxy {
|
||||
}
|
||||
|
||||
public boolean isInFrustrum(Frustrum frustrum) {
|
||||
return frustrum.isBoxInFrustum(x, y, z, X, Y, Z);
|
||||
return frustrum.isBoxInFrustum(x + 0.25, y + 0.25, z + 0.25, x + 0.75, y + 0.75, z + 0.75);
|
||||
}
|
||||
|
||||
public void draw(Tessellator tes) {
|
||||
public void draw(Tessellator tes, double eyeX, double eyeY, double eyeZ, int eyeXint, int eyeYint,
|
||||
int eyeZint) {
|
||||
double size = 0.5;
|
||||
|
||||
int brightness = w.blockExists(x, 0, z) ? w.getLightBrightnessForSkyBlocks(x, y, z, 0) : 0;
|
||||
@@ -334,52 +331,94 @@ public class ClientProxy extends CommonProxy {
|
||||
(int) (tint[2] * 1F),
|
||||
ConfigurationHandler.INSTANCE.getHintTransparency());
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (icons[i] == null) continue;
|
||||
double X = (x - eyeXint) + 0.25;
|
||||
double Y = (y - eyeYint) + 0.25;
|
||||
double Z = (z - eyeZint) + 0.25;
|
||||
double worldX = x + 0.25;
|
||||
double worldY = y + 0.25;
|
||||
double worldZ = z + 0.25;
|
||||
|
||||
markTextureUsed(icons[i]);
|
||||
// this rendering code is independently written by glee8e on July 10th, 2023
|
||||
// and is released as part of StructureLib under LGPL terms, just like everything else in this project
|
||||
// cube is a very special model. its facings can be rendered correctly by viewer distance without using
|
||||
// surface normals and view vector
|
||||
// here we do a 2 pass render.
|
||||
// first pass we draw obstructed faces (i.e. faces that are further away from player)
|
||||
// second pass we draw unobstructed faces
|
||||
for (int j = 0; j < 2; j++) {
|
||||
boolean unobstructedPass = j == 1;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (icons[i] == null) continue;
|
||||
|
||||
double u = icons[i].getMinU();
|
||||
double U = icons[i].getMaxU();
|
||||
double v = icons[i].getMinV();
|
||||
double V = icons[i].getMaxV();
|
||||
switch (i) { // {DOWN, UP, NORTH, SOUTH, WEST, EAST}
|
||||
case 0:
|
||||
tes.addVertexWithUV(X, Y, Z + size, u, V);
|
||||
tes.addVertexWithUV(X, Y, Z, u, v);
|
||||
tes.addVertexWithUV(X + size, Y, Z, U, v);
|
||||
tes.addVertexWithUV(X + size, Y, Z + size, U, V);
|
||||
break;
|
||||
case 1:
|
||||
tes.addVertexWithUV(X, Y + size, Z, u, v);
|
||||
tes.addVertexWithUV(X, Y + size, Z + size, u, V);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z + size, U, V);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z, U, v);
|
||||
break;
|
||||
case 2:
|
||||
tes.addVertexWithUV(X, Y, Z, U, V);
|
||||
tes.addVertexWithUV(X, Y + size, Z, U, v);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z, u, v);
|
||||
tes.addVertexWithUV(X + size, Y, Z, u, V);
|
||||
break;
|
||||
case 3:
|
||||
tes.addVertexWithUV(X + size, Y, Z + size, U, V);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z + size, U, v);
|
||||
tes.addVertexWithUV(X, Y + size, Z + size, u, v);
|
||||
tes.addVertexWithUV(X, Y, Z + size, u, V);
|
||||
break;
|
||||
case 4:
|
||||
tes.addVertexWithUV(X, Y, Z + size, U, V);
|
||||
tes.addVertexWithUV(X, Y + size, Z + size, U, v);
|
||||
tes.addVertexWithUV(X, Y + size, Z, u, v);
|
||||
tes.addVertexWithUV(X, Y, Z, u, V);
|
||||
break;
|
||||
case 5:
|
||||
tes.addVertexWithUV(X + size, Y, Z, U, V);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z, U, v);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z + size, u, v);
|
||||
tes.addVertexWithUV(X + size, Y, Z + size, u, V);
|
||||
break;
|
||||
markTextureUsed(icons[i]);
|
||||
|
||||
double u = icons[i].getMinU();
|
||||
double U = icons[i].getMaxU();
|
||||
double v = icons[i].getMinV();
|
||||
double V = icons[i].getMaxV();
|
||||
switch (i) { // {DOWN, UP, NORTH, SOUTH, WEST, EAST}
|
||||
case 0:
|
||||
// all these ifs is in form if ((is face unobstructed) != (is in unobstructred pass))
|
||||
if ((worldY >= eyeY) != unobstructedPass) continue;
|
||||
tes.setNormal(0, -1, 0);
|
||||
tes.addVertexWithUV(X, Y, Z + size, u, V);
|
||||
tes.addVertexWithUV(X, Y, Z, u, v);
|
||||
tes.addVertexWithUV(X + size, Y, Z, U, v);
|
||||
tes.addVertexWithUV(X + size, Y, Z, U, v);
|
||||
tes.addVertexWithUV(X + size, Y, Z + size, U, V);
|
||||
tes.addVertexWithUV(X, Y, Z + size, u, V);
|
||||
break;
|
||||
case 1:
|
||||
if ((worldY + size <= eyeY) != unobstructedPass) continue;
|
||||
tes.setNormal(0, 1, 0);
|
||||
tes.addVertexWithUV(X, Y + size, Z, u, v);
|
||||
tes.addVertexWithUV(X, Y + size, Z + size, u, V);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z + size, U, V);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z + size, U, V);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z, U, v);
|
||||
tes.addVertexWithUV(X, Y + size, Z, u, v);
|
||||
break;
|
||||
case 2:
|
||||
if ((worldZ >= eyeZ) != unobstructedPass) continue;
|
||||
tes.setNormal(0, 0, -1);
|
||||
tes.addVertexWithUV(X, Y, Z, U, V);
|
||||
tes.addVertexWithUV(X, Y + size, Z, U, v);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z, u, v);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z, u, v);
|
||||
tes.addVertexWithUV(X + size, Y, Z, u, V);
|
||||
tes.addVertexWithUV(X, Y, Z, U, V);
|
||||
break;
|
||||
case 3:
|
||||
if ((worldZ + size <= eyeZ) != unobstructedPass) continue;
|
||||
tes.setNormal(0, 0, 1);
|
||||
tes.addVertexWithUV(X + size, Y, Z + size, U, V);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z + size, U, v);
|
||||
tes.addVertexWithUV(X, Y + size, Z + size, u, v);
|
||||
tes.addVertexWithUV(X, Y + size, Z + size, u, v);
|
||||
tes.addVertexWithUV(X, Y, Z + size, u, V);
|
||||
tes.addVertexWithUV(X + size, Y, Z + size, U, V);
|
||||
break;
|
||||
case 4:
|
||||
if ((worldX >= eyeX) != unobstructedPass) continue;
|
||||
tes.setNormal(-1, 0, 0);
|
||||
tes.addVertexWithUV(X, Y, Z + size, U, V);
|
||||
tes.addVertexWithUV(X, Y + size, Z + size, U, v);
|
||||
tes.addVertexWithUV(X, Y + size, Z, u, v);
|
||||
tes.addVertexWithUV(X, Y + size, Z, u, v);
|
||||
tes.addVertexWithUV(X, Y, Z, u, V);
|
||||
tes.addVertexWithUV(X, Y, Z + size, U, V);
|
||||
break;
|
||||
case 5:
|
||||
if ((worldX + size <= eyeX) != unobstructedPass) continue;
|
||||
tes.setNormal(1, 0, 0);
|
||||
tes.addVertexWithUV(X + size, Y, Z, U, V);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z, U, v);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z + size, u, v);
|
||||
tes.addVertexWithUV(X + size, Y + size, Z + size, u, v);
|
||||
tes.addVertexWithUV(X + size, Y, Z + size, u, V);
|
||||
tes.addVertexWithUV(X + size, Y, Z, U, V);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -389,11 +428,12 @@ public class ClientProxy extends CommonProxy {
|
||||
}
|
||||
|
||||
public double getSquareDistanceTo(Vec3 point) {
|
||||
return point.squareDistanceTo(X, Y, Z);
|
||||
return point.squareDistanceTo(x + 0.5, y + 0.5, z + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FMLEventHandler {
|
||||
|
||||
private void resetPlayerLocation() {
|
||||
lastPlayerPos.xCoord = Minecraft.getMinecraft().thePlayer.posX;
|
||||
lastPlayerPos.yCoord = Minecraft.getMinecraft().thePlayer.posY;
|
||||
@@ -430,12 +470,11 @@ public class ClientProxy extends CommonProxy {
|
||||
for (HintGroup c : allGroups) allHintsForRender.addAll(c.getHints());
|
||||
sortRequired = true;
|
||||
}
|
||||
if (renderThrough > 0 && (sortRequired || playerPos.squareDistanceTo(lastPlayerPos) > 1e-2)) {
|
||||
// only sort if there is anything that need depth test disabled
|
||||
if (sortRequired || playerPos.squareDistanceTo(lastPlayerPos) > 1e-2) {
|
||||
// only redo sort if player moved some distance
|
||||
// default is 0.1 block
|
||||
// if there was a full rebuild, go sort it as well
|
||||
allHintsForRender.sort(Comparator.comparingDouble(info -> info.getSquareDistanceTo(playerPos)));
|
||||
allHintsForRender.sort(Comparator.comparingDouble(info -> -info.getSquareDistanceTo(playerPos)));
|
||||
resetPlayerLocation();
|
||||
}
|
||||
}
|
||||
@@ -443,6 +482,7 @@ public class ClientProxy extends CommonProxy {
|
||||
}
|
||||
|
||||
public static class ForgeEventHandler {
|
||||
|
||||
@SubscribeEvent
|
||||
public void onWorldLoad(WorldEvent.Load e) {
|
||||
if (e.world.isRemote) {
|
||||
@@ -475,35 +515,47 @@ public class ClientProxy extends CommonProxy {
|
||||
+ (entitylivingbase.posY - entitylivingbase.lastTickPosY) * e.partialTicks;
|
||||
double d2 = entitylivingbase.lastTickPosZ
|
||||
+ (entitylivingbase.posZ - entitylivingbase.lastTickPosZ) * e.partialTicks;
|
||||
int i0 = (int) d0, i1 = (int) d1, i2 = (int) d2;
|
||||
frustrum.setPosition(d0, d1, d2);
|
||||
|
||||
GL11.glPushMatrix();
|
||||
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT); // TODO figure out original states
|
||||
// we need the back facing rendered because the thing is transparent
|
||||
GL11.glDisable(GL11.GL_CULL_FACE);
|
||||
GL11.glDisable(GL11.GL_ALPHA_TEST);
|
||||
GL11.glEnable(GL11.GL_BLEND); // enable blend so it is transparent
|
||||
GL11.glBlendFunc(GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_SRC_ALPHA);
|
||||
// depth test begin as enabled
|
||||
boolean renderThrough = false;
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.locationBlocksTexture);
|
||||
GL11.glTranslated(-RenderManager.renderPosX, -RenderManager.renderPosY, -RenderManager.renderPosZ);
|
||||
GL11.glTranslated(-d0 + i0, -d1 + i1, -d2 + i2);
|
||||
Tessellator tes = Tessellator.instance;
|
||||
tes.startDrawingQuads();
|
||||
for (int i = 0, allHintsForRenderSize = allHintsForRender.size(); i < allHintsForRenderSize; i++) {
|
||||
tes.startDrawing(GL11.GL_TRIANGLES);
|
||||
for (int i = 0, allHintsForRenderSize = allHintsForRender.size(), cubeDrawn = 0; i
|
||||
< allHintsForRenderSize; i++, cubeDrawn++) {
|
||||
HintParticleInfo hint = allHintsForRender.get(i);
|
||||
if (!hint.isInFrustrum(frustrum)) continue;
|
||||
if (renderThrough != hint.renderThrough) {
|
||||
if (i > 0) {
|
||||
p.endStartSection("Draw");
|
||||
tes.draw();
|
||||
tes.startDrawingQuads();
|
||||
tes.startDrawing(GL11.GL_TRIANGLES);
|
||||
cubeDrawn = 0;
|
||||
p.endStartSection("Prepare");
|
||||
}
|
||||
if (hint.renderThrough) GL11.glDisable(GL11.GL_DEPTH_TEST);
|
||||
else GL11.glEnable(GL11.GL_DEPTH_TEST);
|
||||
renderThrough = hint.renderThrough;
|
||||
}
|
||||
hint.draw(tes);
|
||||
// Minecraft Tessellator draw in batch of 4096. This plays nicely with quads, but for trigs
|
||||
// it might occasionally end up with one half in first batch and the other half in later batch.
|
||||
// so we manually flush the buffer here if that would happen.
|
||||
// 6 faces per particle, 2 trig per face, 3 vertex per trig
|
||||
if ((cubeDrawn + 1) >= 4096 / (6 * 2 * 3)) {
|
||||
tes.draw();
|
||||
tes.startDrawing(GL11.GL_TRIANGLES);
|
||||
}
|
||||
hint.draw(tes, d0, d1, d2, i0, i1, i2);
|
||||
}
|
||||
p.endStartSection("Draw");
|
||||
tes.draw();
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package com.gtnewhorizon.structurelib;
|
||||
|
||||
import com.gtnewhorizon.structurelib.net.ErrorHintParticleMessage;
|
||||
import com.gtnewhorizon.structurelib.net.UpdateHintParticleMessage;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
@@ -15,7 +13,12 @@ import net.minecraft.util.IChatComponent;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import com.gtnewhorizon.structurelib.net.ErrorHintParticleMessage;
|
||||
import com.gtnewhorizon.structurelib.net.UpdateHintParticleMessage;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
|
||||
public class CommonProxy {
|
||||
|
||||
public void hintParticleTinted(World w, int x, int y, int z, IIcon[] icons, short[] RGBa) {}
|
||||
|
||||
public void hintParticleTinted(World w, int x, int y, int z, Block block, int meta, short[] RGBa) {}
|
||||
@@ -68,11 +71,7 @@ public class CommonProxy {
|
||||
|
||||
private final Map<EntityPlayerMP, Map<Object, Long>> throttleMap = new WeakHashMap<>();
|
||||
|
||||
public void addThrottledChat(
|
||||
Object throttleKey,
|
||||
EntityPlayer player,
|
||||
IChatComponent text,
|
||||
short intervalRequired,
|
||||
public void addThrottledChat(Object throttleKey, EntityPlayer player, IChatComponent text, short intervalRequired,
|
||||
boolean forceUpdateLastSend) {
|
||||
if (player instanceof EntityPlayerMP) {
|
||||
Map<Object, Long> submap = throttleMap.computeIfAbsent((EntityPlayerMP) player, p -> new HashMap<>());
|
||||
@@ -80,13 +79,8 @@ public class CommonProxy {
|
||||
}
|
||||
}
|
||||
|
||||
protected static void addThrottledChat(
|
||||
Object throttleKey,
|
||||
EntityPlayer player,
|
||||
IChatComponent text,
|
||||
short intervalRequired,
|
||||
boolean forceUpdateLastSend,
|
||||
Map<Object, Long> submap) {
|
||||
protected static void addThrottledChat(Object throttleKey, EntityPlayer player, IChatComponent text,
|
||||
short intervalRequired, boolean forceUpdateLastSend, Map<Object, Long> submap) {
|
||||
long now = System.currentTimeMillis();
|
||||
Long old;
|
||||
if (forceUpdateLastSend) {
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
package com.gtnewhorizon.structurelib;
|
||||
|
||||
import cpw.mods.fml.client.event.ConfigChangedEvent;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraftforge.common.config.ConfigCategory;
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
|
||||
import cpw.mods.fml.client.event.ConfigChangedEvent;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
public enum ConfigurationHandler {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
private Configuration config;
|
||||
@@ -54,8 +57,8 @@ public enum ConfigurationHandler {
|
||||
"client.hologram",
|
||||
true,
|
||||
"An attempt will be made to remove an existing hologram if it collides with a new hologram.");
|
||||
hintLifespan =
|
||||
config.getInt("hintLifespan", "client.hologram", 400, 1, 20000, "Ticks before a hologram disappears.");
|
||||
hintLifespan = config
|
||||
.getInt("hintLifespan", "client.hologram", 400, 1, 20000, "Ticks before a hologram disappears.");
|
||||
hintTransparency = config.getInt(
|
||||
"hintTransparency",
|
||||
"client.hologram",
|
||||
@@ -78,7 +81,7 @@ public enum ConfigurationHandler {
|
||||
300,
|
||||
0,
|
||||
20000,
|
||||
"Unit: milisecond. Minimal interval between two auto place round.\n"
|
||||
"Unit: millisecond. Minimal interval between two auto place round.\n"
|
||||
+ "As expected, server side settings will overrides client settings.\n"
|
||||
+ "Note this relates to the wall clock, not in game ticks.\n"
|
||||
+ "Value smaller than default is likely to be perceived as no minimal interval whatsoever.");
|
||||
|
||||
@@ -2,11 +2,15 @@ package com.gtnewhorizon.structurelib;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
|
||||
enum ConfigurationVersion {
|
||||
|
||||
V1 {
|
||||
|
||||
@Override
|
||||
protected void step(Configuration c) {}
|
||||
};
|
||||
@@ -30,10 +34,8 @@ enum ConfigurationVersion {
|
||||
}
|
||||
|
||||
public static ConfigurationVersion identify(Configuration c) {
|
||||
return Arrays.stream(VALUES)
|
||||
.filter(v -> Objects.equals(c.getLoadedConfigVersion(), v.getVersionMarker()))
|
||||
.findFirst()
|
||||
.orElse(V1);
|
||||
return Arrays.stream(VALUES).filter(v -> Objects.equals(c.getLoadedConfigVersion(), v.getVersionMarker()))
|
||||
.findFirst().orElse(V1);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.gtnewhorizon.structurelib;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.lwjgl.opengl.ARBVertexBufferObject;
|
||||
import org.lwjgl.opengl.ContextCapabilities;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GLContext;
|
||||
|
||||
class GLHelper {
|
||||
public static final boolean vboSupported;
|
||||
private static final boolean arbVbo;
|
||||
|
||||
static {
|
||||
ContextCapabilities contextcapabilities = GLContext.getCapabilities();
|
||||
|
||||
arbVbo = !contextcapabilities.OpenGL15 && contextcapabilities.GL_ARB_vertex_buffer_object;
|
||||
vboSupported = contextcapabilities.OpenGL15 || arbVbo;
|
||||
}
|
||||
|
||||
public static int glGenBuffers() {
|
||||
return arbVbo ? ARBVertexBufferObject.glGenBuffersARB() : GL15.glGenBuffers();
|
||||
}
|
||||
|
||||
public static void glBindBuffer(int target, int buffer) {
|
||||
if (arbVbo) {
|
||||
ARBVertexBufferObject.glBindBufferARB(target, buffer);
|
||||
} else {
|
||||
GL15.glBindBuffer(target, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void glBufferData(int target, ByteBuffer data, int usage) {
|
||||
if (arbVbo) {
|
||||
ARBVertexBufferObject.glBufferDataARB(target, data, usage);
|
||||
} else {
|
||||
GL15.glBufferData(target, data, usage);
|
||||
}
|
||||
}
|
||||
|
||||
public static void glDeleteBuffers(int buffer) {
|
||||
if (arbVbo) {
|
||||
ARBVertexBufferObject.glDeleteBuffersARB(buffer);
|
||||
} else {
|
||||
GL15.glDeleteBuffers(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean useVbo() {
|
||||
return vboSupported;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
package com.gtnewhorizon.structurelib;
|
||||
|
||||
import cpw.mods.fml.client.IModGuiFactory;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
|
||||
import cpw.mods.fml.client.IModGuiFactory;
|
||||
|
||||
public class GuiFactory implements IModGuiFactory {
|
||||
|
||||
@Override
|
||||
public void initialize(Minecraft minecraftInstance) {}
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package com.gtnewhorizon.structurelib;
|
||||
|
||||
import com.gtnewhorizon.structurelib.gui.GuiScreenConfigureChannels;
|
||||
import cpw.mods.fml.common.network.IGuiHandler;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import com.gtnewhorizon.structurelib.gui.GuiScreenConfigureChannels;
|
||||
import cpw.mods.fml.common.network.IGuiHandler;
|
||||
|
||||
public class GuiHandler implements IGuiHandler {
|
||||
|
||||
@Override
|
||||
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
|
||||
return null;
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package com.gtnewhorizon.structurelib;
|
||||
|
||||
import cpw.mods.fml.client.config.GuiConfig;
|
||||
import cpw.mods.fml.client.config.IConfigElement;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraftforge.common.config.ConfigElement;
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
|
||||
import cpw.mods.fml.client.config.GuiConfig;
|
||||
import cpw.mods.fml.client.config.IConfigElement;
|
||||
|
||||
public class GuiModConfig extends GuiConfig {
|
||||
|
||||
public GuiModConfig(GuiScreen guiScreen) {
|
||||
super(
|
||||
guiScreen,
|
||||
@@ -16,16 +19,13 @@ public class GuiModConfig extends GuiConfig {
|
||||
StructureLibAPI.MOD_ID,
|
||||
false,
|
||||
false,
|
||||
GuiConfig.getAbridgedConfigPath(
|
||||
ConfigurationHandler.INSTANCE.getConfig().toString()));
|
||||
GuiConfig.getAbridgedConfigPath(ConfigurationHandler.INSTANCE.getConfig().toString()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static List<IConfigElement> getConfigElements() {
|
||||
final Configuration config = ConfigurationHandler.INSTANCE.getConfig();
|
||||
return config.getCategoryNames().stream()
|
||||
.filter(name -> name.indexOf('.') == -1)
|
||||
.map(name -> new ConfigElement(config.getCategory(name)))
|
||||
.collect(Collectors.toList());
|
||||
return config.getCategoryNames().stream().filter(name -> name.indexOf('.') == -1)
|
||||
.map(name -> new ConfigElement(config.getCategory(name))).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -3,5 +3,6 @@ package com.gtnewhorizon.structurelib;
|
||||
import net.minecraft.util.IIcon;
|
||||
|
||||
public interface IStructureCompat {
|
||||
|
||||
void markTextureUsed(IIcon o);
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package com.gtnewhorizon.structurelib;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
import com.gtnewhorizon.structurelib.structure.IStructureElement;
|
||||
import cpw.mods.fml.common.eventhandler.Event;
|
||||
|
||||
/**
|
||||
* Subscribers are <b>required</b> to not keep reference to these events, nor to depend on values of these events after
|
||||
* the method call returns.
|
||||
* <p>
|
||||
* All of these events will be fired on the {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS}, if they are
|
||||
* enabled by {@link StructureLibAPI#enableInstrument(Object)}.
|
||||
* <p>
|
||||
* All public stuff in this class and its enclosed classes are considered part of the public API. Backwards
|
||||
* compatibility is maintained to the maximum extend possible.
|
||||
*/
|
||||
public abstract class StructureEvent extends Event {
|
||||
|
||||
/*
|
||||
* In case the event is passed to another thread for processing.
|
||||
*/
|
||||
private final Object identifier = StructureLibAPI.instrument.get();
|
||||
|
||||
StructureEvent() {}
|
||||
|
||||
/**
|
||||
* The instrument identifier. Subscribers should filter by these identifiers to prevent listening to a structure
|
||||
* event for other people.
|
||||
*/
|
||||
public Object getInstrumentIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired <b>just before</b> any structure element is visited.
|
||||
*/
|
||||
public static final class StructureElementVisitedEvent extends StructureEvent {
|
||||
|
||||
private final World world;
|
||||
private final int x, y, z;
|
||||
private final int a, b, c;
|
||||
private final IStructureElement<?> element;
|
||||
|
||||
/**
|
||||
* Fire this event on {@link MinecraftForge#EVENT_BUS} by populating it with given arguments. Do nothing if
|
||||
* instrumenting isn't enabled for current thread.
|
||||
* <p>
|
||||
* Any {@link Exception} thrown by event listeners will be logged and ignored. {@link Error} will be propagated
|
||||
* as is.
|
||||
*/
|
||||
public static void fireEvent(World world, int x, int y, int z, int a, int b, int c,
|
||||
IStructureElement<?> element) {
|
||||
if (StructureLibAPI.isInstrumentEnabled()) {
|
||||
try {
|
||||
MinecraftForge.EVENT_BUS.post(new StructureElementVisitedEvent(world, x, y, z, a, b, c, element));
|
||||
} catch (Exception e) {
|
||||
// logging is done by event bus, we just ignore the consequence here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StructureElementVisitedEvent(World world, int x, int y, int z, int a, int b, int c,
|
||||
IStructureElement<?> element) {
|
||||
this.world = world;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.c = c;
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
/**
|
||||
* A position in ABC coordinate, relative to (0,0,0) in the piece, i.e. without baseOffset
|
||||
* <p>
|
||||
* Submit a feature request if you need the baseOffset.
|
||||
*/
|
||||
public int getA() {
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* B position in ABC coordinate, relative to (0,0,0) in the piece, i.e. without baseOffset
|
||||
* <p>
|
||||
* Submit a feature request if you need the baseOffset.
|
||||
*/
|
||||
public int getB() {
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* C position in ABC coordinate, relative to (0,0,0) in the piece, i.e. without baseOffset
|
||||
* <p>
|
||||
* Submit a feature request if you need the baseOffset.
|
||||
*/
|
||||
public int getC() {
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Element being visited.
|
||||
*/
|
||||
public IStructureElement<?> getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StructureElementVisitedEvent{" + "a="
|
||||
+ a
|
||||
+ ", b="
|
||||
+ b
|
||||
+ ", c="
|
||||
+ c
|
||||
+ ", element="
|
||||
+ element
|
||||
+ ", world="
|
||||
+ getWorld()
|
||||
+ ", x="
|
||||
+ getX()
|
||||
+ ", y="
|
||||
+ getY()
|
||||
+ ", z="
|
||||
+ getZ()
|
||||
+ '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Location of this event.
|
||||
*/
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Location of this event. Absolute world coordinate.
|
||||
*/
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Location of this event. Absolute world coordinate.
|
||||
*/
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Location of this event. Absolute world coordinate.
|
||||
*/
|
||||
public int getZ() {
|
||||
return z;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,15 @@
|
||||
package com.gtnewhorizon.structurelib;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import com.gtnewhorizon.structurelib.block.BlockHint;
|
||||
import com.gtnewhorizon.structurelib.command.CommandConfigureChannels;
|
||||
import com.gtnewhorizon.structurelib.item.ItemBlockHint;
|
||||
@@ -10,6 +20,7 @@ import com.gtnewhorizon.structurelib.net.ErrorHintParticleMessage;
|
||||
import com.gtnewhorizon.structurelib.net.SetChannelDataMessage;
|
||||
import com.gtnewhorizon.structurelib.net.UpdateHintParticleMessage;
|
||||
import com.gtnewhorizon.structurelib.util.XSTR;
|
||||
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.Mod;
|
||||
import cpw.mods.fml.common.SidedProxy;
|
||||
@@ -20,14 +31,6 @@ import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* This class does not contain a stable API. Refrain from using this class.
|
||||
@@ -39,21 +42,25 @@ import org.apache.logging.log4j.Logger;
|
||||
acceptableRemoteVersions = "*",
|
||||
guiFactory = "com.gtnewhorizon.structurelib.GuiFactory")
|
||||
public class StructureLib {
|
||||
|
||||
private static final String STRUCTURECOMPAT_MODID = "structurecompat";
|
||||
public static boolean DEBUG_MODE;
|
||||
public static boolean PANIC_MODE = Boolean.getBoolean("structurelib.panic");
|
||||
public static Logger LOGGER = LogManager.getLogger("StructureLib");
|
||||
public static final Logger LOGGER = LogManager.getLogger("StructureLib");
|
||||
|
||||
@SidedProxy(
|
||||
serverSide = "com.gtnewhorizon.structurelib.CommonProxy",
|
||||
clientSide = "com.gtnewhorizon.structurelib.ClientProxy")
|
||||
static CommonProxy proxy;
|
||||
|
||||
static SimpleNetworkWrapper net = NetworkRegistry.INSTANCE.newSimpleChannel(StructureLibAPI.MOD_ID);
|
||||
static final SimpleNetworkWrapper net = NetworkRegistry.INSTANCE.newSimpleChannel(StructureLibAPI.MOD_ID);
|
||||
|
||||
static {
|
||||
net.registerMessage(
|
||||
AlignmentMessage.ServerHandler.class, AlignmentMessage.AlignmentQuery.class, 0, Side.SERVER);
|
||||
AlignmentMessage.ServerHandler.class,
|
||||
AlignmentMessage.AlignmentQuery.class,
|
||||
0,
|
||||
Side.SERVER);
|
||||
net.registerMessage(AlignmentMessage.ClientHandler.class, AlignmentMessage.AlignmentData.class, 1, Side.CLIENT);
|
||||
net.registerMessage(UpdateHintParticleMessage.Handler.class, UpdateHintParticleMessage.class, 2, Side.CLIENT);
|
||||
net.registerMessage(SetChannelDataMessage.Handler.class, SetChannelDataMessage.class, 3, Side.SERVER);
|
||||
@@ -80,6 +87,7 @@ public class StructureLib {
|
||||
static Item itemFrontRotationTool;
|
||||
static Item itemConstructableTrigger;
|
||||
public static final CreativeTabs creativeTab = new CreativeTabs("structurelib") {
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public Item getTabIconItem() {
|
||||
@@ -93,7 +101,8 @@ public class StructureLib {
|
||||
GameRegistry.registerBlock(blockHint = new BlockHint(), ItemBlockHint.class, "blockhint");
|
||||
itemBlockHint = ItemBlock.getItemFromBlock(StructureLibAPI.getBlockHint());
|
||||
GameRegistry.registerItem(
|
||||
itemFrontRotationTool = new ItemFrontRotationTool(), itemFrontRotationTool.getUnlocalizedName());
|
||||
itemFrontRotationTool = new ItemFrontRotationTool(),
|
||||
itemFrontRotationTool.getUnlocalizedName());
|
||||
GameRegistry.registerItem(
|
||||
itemConstructableTrigger = new ItemConstructableTrigger(),
|
||||
itemConstructableTrigger.getUnlocalizedName());
|
||||
@@ -101,10 +110,7 @@ public class StructureLib {
|
||||
NetworkRegistry.INSTANCE.registerGuiHandler(instance(), new GuiHandler());
|
||||
|
||||
if (Loader.isModLoaded(STRUCTURECOMPAT_MODID)) {
|
||||
COMPAT = Loader.instance()
|
||||
.getIndexedModList()
|
||||
.get(STRUCTURECOMPAT_MODID)
|
||||
.getMod();
|
||||
COMPAT = Loader.instance().getIndexedModList().get(STRUCTURECOMPAT_MODID).getMod();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,6 @@ package com.gtnewhorizon.structurelib;
|
||||
|
||||
import static com.gtnewhorizon.structurelib.StructureLib.proxy;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.IAlignment;
|
||||
import com.gtnewhorizon.structurelib.alignment.IAlignmentProvider;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.net.AlignmentMessage;
|
||||
import com.gtnewhorizon.structurelib.structure.IItemSource;
|
||||
import cpw.mods.fml.common.network.NetworkRegistry;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
@@ -17,10 +11,20 @@ import net.minecraft.util.IChatComponent;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.IAlignment;
|
||||
import com.gtnewhorizon.structurelib.alignment.IAlignmentProvider;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.net.AlignmentMessage;
|
||||
import com.gtnewhorizon.structurelib.structure.AutoPlaceEnvironment;
|
||||
import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
|
||||
import cpw.mods.fml.common.network.NetworkRegistry;
|
||||
|
||||
/**
|
||||
* A stable interface into the structure lib's internals. Backwards compatibility is maintained to the maximum extend possible.
|
||||
* A stable interface into the structure lib's internals. Backwards compatibility is maintained to the maximum extend
|
||||
* possible.
|
||||
*/
|
||||
public class StructureLibAPI {
|
||||
|
||||
public static final String MOD_ID = "structurelib";
|
||||
public static final int HINT_BLOCK_META_GENERIC_0 = 0;
|
||||
public static final int HINT_BLOCK_META_GENERIC_1 = 1;
|
||||
@@ -38,20 +42,74 @@ public class StructureLibAPI {
|
||||
public static final int HINT_BLOCK_META_AIR = 13;
|
||||
public static final int HINT_BLOCK_META_NOT_AIR = 14;
|
||||
public static final int HINT_BLOCK_META_ERROR = 15;
|
||||
static final ThreadLocal<Object> instrument = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Start a batch of hinting. All hints particles generated during one batch will be considered to belong to one hologram.
|
||||
* Start instrumenting <b>for the current thread only</b>. When instrumentation is enabled,
|
||||
* {@link IStructureDefinition}'s builtin iteration methods will send {@link StructureEvent} and its subclasses when
|
||||
* appropriate. Otherwise, these events will not be sent at all, regardless of whether a listener for these events
|
||||
* are registered.
|
||||
* <p>
|
||||
* You don't need to call this unless your constructable tool didn't call {@link com.gtnewhorizon.structurelib.alignment.constructable.ConstructableUtility#handle(ItemStack, EntityPlayer, World, int, int, int, int)}
|
||||
* Identifiers are required to be value-comparable, i.e. overrides {@link Object#equals(Object)}. Suggested
|
||||
* identifier includes
|
||||
* <ul>
|
||||
* <li>Mod Instance or {@link cpw.mods.fml.common.ModContainer}</li>
|
||||
* <li>{@link com.gtnewhorizon.structurelib.alignment.constructable.IConstructable} and its friends, if you are
|
||||
* triggering structure check via this interface.</li>
|
||||
* <li>{@link net.minecraft.util.ResourceLocation}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* It's an API abuse for normal {@link IStructureDefinition} users to depend on this feature. They have full control
|
||||
* and full knowledge of the {@link IStructureDefinition} they are using. Using events to instrument the structure
|
||||
* check/autoplace is completely unnecessary and does nothing but add overhead.
|
||||
* <p>
|
||||
* Instruments are required to call {@link #disableInstrument()} whenever it is done with its business, as there can
|
||||
* be only one instrument for any given thread.
|
||||
*
|
||||
* @param identifier an identifier sent along the actual event.
|
||||
* @throws IllegalStateException if instrument has already been enabled.
|
||||
*/
|
||||
public static void enableInstrument(Object identifier) {
|
||||
if (isInstrumentEnabled()) throw new IllegalStateException();
|
||||
instrument.set(instrument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop instrumenting.
|
||||
*
|
||||
* @throws IllegalStateException if instrumenting hasn't been enabled.
|
||||
*/
|
||||
public static void disableInstrument() {
|
||||
if (!isInstrumentEnabled()) throw new IllegalStateException();
|
||||
instrument.set(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if instrumenting is enabled.
|
||||
*
|
||||
* @return true if enabled, false otherwise
|
||||
*/
|
||||
public static boolean isInstrumentEnabled() {
|
||||
return instrument.get() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a batch of hinting. All hints particles generated during one batch will be considered to belong to one
|
||||
* hologram.
|
||||
* <p>
|
||||
* You don't need to call this unless your constructable tool didn't call
|
||||
* {@link com.gtnewhorizon.structurelib.alignment.constructable.ConstructableUtility#handle(ItemStack, EntityPlayer, World, int, int, int, int)}
|
||||
*/
|
||||
public static void startHinting(World w) {
|
||||
proxy.startHinting(w);
|
||||
}
|
||||
|
||||
/**
|
||||
* End current batch of hinting. All hints particles generated during one batch will be considered to belong to one hologram.
|
||||
* End current batch of hinting. All hints particles generated during one batch will be considered to belong to one
|
||||
* hologram.
|
||||
* <p>
|
||||
* You don't need to call this unless your constructable tool didn't call {@link com.gtnewhorizon.structurelib.alignment.constructable.ConstructableUtility#handle(ItemStack, EntityPlayer, World, int, int, int, int)}
|
||||
* You don't need to call this unless your constructable tool didn't call
|
||||
* {@link com.gtnewhorizon.structurelib.alignment.constructable.ConstructableUtility#handle(ItemStack, EntityPlayer, World, int, int, int, int)}
|
||||
*/
|
||||
public static void endHinting(World w) {
|
||||
proxy.endHinting(w);
|
||||
@@ -59,12 +117,14 @@ public class StructureLibAPI {
|
||||
|
||||
/**
|
||||
* Generate a new hint particle on client side at given location using given textures with a tint.
|
||||
* @param w World to spawn. Usually the client world.
|
||||
* @param x x coord
|
||||
* @param y y coord
|
||||
* @param z z coord
|
||||
*
|
||||
* @param w World to spawn. Usually the client world.
|
||||
* @param x x coord
|
||||
* @param y y coord
|
||||
* @param z z coord
|
||||
* @param icons 6 texture. in forge direction order.
|
||||
* @param RGBa a 4 short array. tint in rgba form. currently alpha channel is ignored, but we might change this later on.
|
||||
* @param RGBa a 4 short array. tint in rgba form. currently alpha channel is ignored, but we might change this
|
||||
* later on.
|
||||
*/
|
||||
public static void hintParticleTinted(World w, int x, int y, int z, IIcon[] icons, short[] RGBa) {
|
||||
proxy.hintParticleTinted(w, x, y, z, icons, RGBa);
|
||||
@@ -72,13 +132,15 @@ public class StructureLibAPI {
|
||||
|
||||
/**
|
||||
* Generate a new hint particle on client side at given location using textures from given block with a tint.
|
||||
* @param w World to spawn. Usually the client world.
|
||||
* @param x x coord
|
||||
* @param y y coord
|
||||
* @param z z coord
|
||||
*
|
||||
* @param w World to spawn. Usually the client world.
|
||||
* @param x x coord
|
||||
* @param y y coord
|
||||
* @param z z coord
|
||||
* @param block block to take texture from
|
||||
* @param meta the meta of block to take texture from
|
||||
* @param RGBa a 4 short array. tint in rgba form. currently alpha channel is ignored, but we might change this later on.
|
||||
* @param meta the meta of block to take texture from
|
||||
* @param RGBa a 4 short array. tint in rgba form. currently alpha channel is ignored, but we might change this
|
||||
* later on.
|
||||
*/
|
||||
public static void hintParticleTinted(World w, int x, int y, int z, Block block, int meta, short[] RGBa) {
|
||||
proxy.hintParticleTinted(w, x, y, z, block, meta, RGBa);
|
||||
@@ -86,10 +148,11 @@ public class StructureLibAPI {
|
||||
|
||||
/**
|
||||
* Generate a new hint particle on client side at given location using given textures.
|
||||
* @param w World to spawn. Usually the client world.
|
||||
* @param x x coord
|
||||
* @param y y coord
|
||||
* @param z z coord
|
||||
*
|
||||
* @param w World to spawn. Usually the client world.
|
||||
* @param x x coord
|
||||
* @param y y coord
|
||||
* @param z z coord
|
||||
* @param icons 6 texture. in forge direction order.
|
||||
*/
|
||||
public static void hintParticle(World w, int x, int y, int z, IIcon[] icons) {
|
||||
@@ -98,12 +161,13 @@ public class StructureLibAPI {
|
||||
|
||||
/**
|
||||
* Generate a new hint particle on client side at given location using textures from given block.
|
||||
* @param w World to spawn. Usually the client world.
|
||||
* @param x x coord
|
||||
* @param y y coord
|
||||
* @param z z coord
|
||||
*
|
||||
* @param w World to spawn. Usually the client world.
|
||||
* @param x x coord
|
||||
* @param y y coord
|
||||
* @param z z coord
|
||||
* @param block block to take texture from
|
||||
* @param meta the meta of block to take texture from
|
||||
* @param meta the meta of block to take texture from
|
||||
*/
|
||||
public static void hintParticle(World w, int x, int y, int z, Block block, int meta) {
|
||||
proxy.hintParticle(w, x, y, z, block, meta);
|
||||
@@ -111,10 +175,9 @@ public class StructureLibAPI {
|
||||
|
||||
/**
|
||||
* Update the tint of given hint particle. Do nothing if particle not found.
|
||||
*
|
||||
* Can be called on either client side or server side.
|
||||
* Server side will schedule a network message to update it for this player only.
|
||||
* Will do nothing if no hint particle is found at given location.
|
||||
* <p>
|
||||
* Can be called on either client side or server side. Server side will schedule a network message to update it for
|
||||
* this player only. Will do nothing if no hint particle is found at given location.
|
||||
*
|
||||
* @return false if nothing updated. true if updated or update instruction sent.
|
||||
*/
|
||||
@@ -132,11 +195,13 @@ public class StructureLibAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the ExtendedFacing of this tile entity from client side. Can be sent only on client side.
|
||||
* The ExtendedFacing will later be set onto given tile entity via {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)}
|
||||
* upon arrival of server reply.
|
||||
* Query the ExtendedFacing of this tile entity from client side. Can be sent only on client side. The
|
||||
* ExtendedFacing will later be set onto given tile entity via
|
||||
* {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)} upon arrival of
|
||||
* server reply.
|
||||
* <p>
|
||||
* The server side will query the {@link ExtendedFacing} of this provider using {@link IAlignment#getExtendedFacing()}
|
||||
* The server side will query the {@link ExtendedFacing} of this provider using
|
||||
* {@link IAlignment#getExtendedFacing()}
|
||||
*
|
||||
* @throws IllegalArgumentException if is not tile entity or provided a null alignment
|
||||
*/
|
||||
@@ -147,7 +212,8 @@ public class StructureLibAPI {
|
||||
/**
|
||||
* Send the ExtendedFacing of this Tile Entity to all players. Can be called on server side only.
|
||||
* <p>
|
||||
* The receiving tile entity will receive the {@link ExtendedFacing} via its {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)} method.
|
||||
* The receiving tile entity will receive the {@link ExtendedFacing} via its
|
||||
* {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)} method.
|
||||
*
|
||||
* @throws IllegalArgumentException if is not tile entity or provided a null alignment
|
||||
*/
|
||||
@@ -158,7 +224,8 @@ public class StructureLibAPI {
|
||||
/**
|
||||
* Send the ExtendedFacing of this Tile Entity to given player. Can be called on server side only.
|
||||
* <p>
|
||||
* The receiving tile entity will receive the {@link ExtendedFacing} via its {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)} method.
|
||||
* The receiving tile entity will receive the {@link ExtendedFacing} via its
|
||||
* {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)} method.
|
||||
*
|
||||
* @throws IllegalArgumentException if is not tile entity or provided a null alignment
|
||||
*/
|
||||
@@ -167,9 +234,11 @@ public class StructureLibAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the ExtendedFacing of this Tile Entity to all players around target point. Can be called on server side only.
|
||||
* Send the ExtendedFacing of this Tile Entity to all players around target point. Can be called on server side
|
||||
* only.
|
||||
* <p>
|
||||
* The receiving tile entity will receive the {@link ExtendedFacing} via its {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)} method.
|
||||
* The receiving tile entity will receive the {@link ExtendedFacing} via its
|
||||
* {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)} method.
|
||||
*
|
||||
* @throws IllegalArgumentException if is not tile entity or provided a null alignment
|
||||
*/
|
||||
@@ -180,7 +249,8 @@ public class StructureLibAPI {
|
||||
/**
|
||||
* Send the ExtendedFacing of this Tile Entity to all players in that dimension. Can be called on server side only.
|
||||
* <p>
|
||||
* The receiving tile entity will receive the {@link ExtendedFacing} via its {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)} method.
|
||||
* The receiving tile entity will receive the {@link ExtendedFacing} via its
|
||||
* {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)} method.
|
||||
*
|
||||
* @throws IllegalArgumentException if is not tile entity or provided a null alignment
|
||||
*/
|
||||
@@ -202,6 +272,13 @@ public class StructureLibAPI {
|
||||
return StructureLib.itemBlockHint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hologram item.
|
||||
*/
|
||||
public static Item getDefaultHologramItem() {
|
||||
return StructureLib.itemConstructableTrigger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if structure debug mode is on.
|
||||
*
|
||||
@@ -216,12 +293,25 @@ public class StructureLibAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if given block can be replaced without much effort. The exact predicate clauses is not stable and
|
||||
* will be changed, but the general idea will always stay the same.
|
||||
* Determines if given block can be replaced without much effort. The exact predicate clauses is not stable and will
|
||||
* be changed, but the general idea will always stay the same.
|
||||
* <p>
|
||||
* Use this in your {@link com.gtnewhorizon.structurelib.structure.IStructureElement#survivalPlaceBlock(Object, World, int, int, int, ItemStack, IItemSource, EntityPlayerMP, java.util.function.Consumer)}
|
||||
* Use this in your
|
||||
* {@link com.gtnewhorizon.structurelib.structure.IStructureElement#survivalPlaceBlock(Object, World, int, int, int, ItemStack, AutoPlaceEnvironment)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isBlockTriviallyReplaceable(World w, int x, int y, int z, EntityPlayerMP actor) {
|
||||
return isBlockTriviallyReplaceable(w, x, y, z, (EntityPlayer) actor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if given block can be replaced without much effort. The exact predicate clauses is not stable and will
|
||||
* be changed, but the general idea will always stay the same.
|
||||
* <p>
|
||||
* Use this in your
|
||||
* {@link com.gtnewhorizon.structurelib.structure.IStructureElement#survivalPlaceBlock(Object, World, int, int, int, ItemStack, AutoPlaceEnvironment)}
|
||||
*/
|
||||
public static boolean isBlockTriviallyReplaceable(World w, int x, int y, int z, EntityPlayer actor) {
|
||||
// TODO extend this function a bit
|
||||
Block block = w.getBlock(x, y, z);
|
||||
return block.isAir(w, x, y, z) || block.isReplaceable(w, x, y, z);
|
||||
@@ -229,34 +319,34 @@ public class StructureLibAPI {
|
||||
|
||||
/**
|
||||
* Send chat to player, but throttled.
|
||||
* @param throttleKey throttle key. Must properly implement {@link Object#hashCode()} and {@link Object#equals(Object)}
|
||||
* to handle value equality.
|
||||
* @param player player to send chat to
|
||||
* @param text chat to send
|
||||
* @param intervalRequired interval required before last recorded time to actually send the message. unit in millisecond.
|
||||
* we purposefully chose to not use a bigger data type to limit how long this interval can be
|
||||
*
|
||||
* @param throttleKey throttle key. Must properly implement {@link Object#hashCode()} and
|
||||
* {@link Object#equals(Object)} to handle value equality.
|
||||
* @param player player to send chat to
|
||||
* @param text chat to send
|
||||
* @param intervalRequired interval required before last recorded time to actually send the message. unit in
|
||||
* millisecond. we purposefully chose to not use a bigger data type to limit how long this
|
||||
* interval can be
|
||||
*/
|
||||
public static void addThrottledChat(
|
||||
Object throttleKey, EntityPlayer player, IChatComponent text, short intervalRequired) {
|
||||
public static void addThrottledChat(Object throttleKey, EntityPlayer player, IChatComponent text,
|
||||
short intervalRequired) {
|
||||
addThrottledChat(throttleKey, player, text, intervalRequired, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send chat to player, but throttled.
|
||||
* @param throttleKey throttle key. Must properly implement {@link Object#hashCode()} and {@link Object#equals(Object)}
|
||||
* to handle value equality.
|
||||
* @param player player to send chat to
|
||||
* @param text chat to send
|
||||
* @param intervalRequired interval required before last recorded time to actually send the message. unit in millisecond.
|
||||
* we purposefully chose to not use a bigger data type to limit how long this interval can be
|
||||
*
|
||||
* @param throttleKey throttle key. Must properly implement {@link Object#hashCode()} and
|
||||
* {@link Object#equals(Object)} to handle value equality.
|
||||
* @param player player to send chat to
|
||||
* @param text chat to send
|
||||
* @param intervalRequired interval required before last recorded time to actually send the message. unit in
|
||||
* millisecond. we purposefully chose to not use a bigger data type to limit how long
|
||||
* this interval can be
|
||||
* @param forceUpdateLastSend if true, always update the last send time, even if the message isn't actually sent.
|
||||
*/
|
||||
public static void addThrottledChat(
|
||||
Object throttleKey,
|
||||
EntityPlayer player,
|
||||
IChatComponent text,
|
||||
short intervalRequired,
|
||||
boolean forceUpdateLastSend) {
|
||||
public static void addThrottledChat(Object throttleKey, EntityPlayer player, IChatComponent text,
|
||||
short intervalRequired, boolean forceUpdateLastSend) {
|
||||
proxy.addThrottledChat(throttleKey, player, text, intervalRequired, forceUpdateLastSend);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.gtnewhorizon.structurelib.alignment;
|
||||
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.Flip;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.Rotation;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
class AlignmentLimits implements IAlignmentLimits {
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
|
||||
public class AlignmentUtility {
|
||||
|
||||
private AlignmentUtility() {}
|
||||
|
||||
public static boolean handle(EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ) {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package com.gtnewhorizon.structurelib.alignment;
|
||||
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.Direction;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.Flip;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.Rotation;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
public interface IAlignment extends IAlignmentLimits, IAlignmentProvider {
|
||||
|
||||
int DIRECTIONS_COUNT = Direction.VALUES.length;
|
||||
int ROTATIONS_COUNT = Rotation.VALUES.length;
|
||||
int FLIPS_COUNT = Flip.VALUES.length;
|
||||
@@ -15,8 +17,8 @@ public interface IAlignment extends IAlignmentLimits, IAlignmentProvider {
|
||||
ExtendedFacing getExtendedFacing();
|
||||
|
||||
/**
|
||||
* Set the facing without additional checks.
|
||||
* Tools altering facing should use {@link #toolSetExtendedFacing(ExtendedFacing)} instead.
|
||||
* Set the facing without additional checks. Tools altering facing should use
|
||||
* {@link #toolSetExtendedFacing(ExtendedFacing)} instead.
|
||||
*/
|
||||
void setExtendedFacing(ExtendedFacing alignment);
|
||||
|
||||
@@ -57,9 +59,8 @@ public interface IAlignment extends IAlignmentLimits, IAlignmentProvider {
|
||||
|
||||
default boolean toolSetDirection(ForgeDirection direction) {
|
||||
if (direction == null || direction == ForgeDirection.UNKNOWN) {
|
||||
for (int i = 0, j = getDirection().ordinal() + 1, valuesLength = Direction.VALUES.length;
|
||||
i < valuesLength;
|
||||
i++) {
|
||||
for (int i = 0, j = getDirection().ordinal() + 1, valuesLength = Direction.VALUES.length; i
|
||||
< valuesLength; i++) {
|
||||
if (toolSetDirection(Direction.VALUES[(j + i) % valuesLength].getForgeDirection())) {
|
||||
return true;
|
||||
}
|
||||
@@ -97,8 +98,11 @@ public interface IAlignment extends IAlignmentLimits, IAlignmentProvider {
|
||||
int rotations = Rotation.VALUES.length;
|
||||
for (int ii = 0, jj = getFlip().ordinal(); ii < flips; ii++) {
|
||||
for (int i = 1, j = getRotation().ordinal(); i < rotations; i++) {
|
||||
if (checkedSetExtendedFacing(ExtendedFacing.of(
|
||||
getDirection(), Rotation.VALUES[(j + i) % rotations], Flip.VALUES[(jj + ii) % flips]))) {
|
||||
if (checkedSetExtendedFacing(
|
||||
ExtendedFacing.of(
|
||||
getDirection(),
|
||||
Rotation.VALUES[(j + i) % rotations],
|
||||
Flip.VALUES[(jj + ii) % flips]))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -140,9 +144,8 @@ public interface IAlignment extends IAlignmentLimits, IAlignmentProvider {
|
||||
|
||||
default boolean toolSetExtendedFacing(ExtendedFacing extendedFacing) {
|
||||
if (extendedFacing == null) {
|
||||
for (int i = 0, j = getExtendedFacing().ordinal() + 1, valuesLength = ExtendedFacing.VALUES.length;
|
||||
i < valuesLength;
|
||||
i++) {
|
||||
for (int i = 0, j = getExtendedFacing().ordinal() + 1, valuesLength = ExtendedFacing.VALUES.length; i
|
||||
< valuesLength; i++) {
|
||||
if (checkedSetExtendedFacing(ExtendedFacing.VALUES[(j + i) % valuesLength])) {
|
||||
return true;
|
||||
}
|
||||
@@ -187,4 +190,28 @@ public interface IAlignment extends IAlignmentLimits, IAlignmentProvider {
|
||||
return getAlignmentLimits()
|
||||
.isNewExtendedFacingValid(alignment.getDirection(), alignment.getRotation(), alignment.getFlip());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this object support a flip change, assuming both direction and rotation is not changed.
|
||||
*/
|
||||
default boolean isFlipChangeAllowed() {
|
||||
ExtendedFacing facing = getExtendedFacing();
|
||||
for (Flip flip : Flip.VALUES) {
|
||||
if (flip == getFlip()) continue;
|
||||
if (isNewExtendedFacingValid(facing.with(flip))) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this object support a rotation change, assuming both direction and flip is not changed.
|
||||
*/
|
||||
default boolean isRotationChangeAllowed() {
|
||||
ExtendedFacing facing = getExtendedFacing();
|
||||
for (Rotation rotation : Rotation.VALUES) {
|
||||
if (rotation == getRotation()) continue;
|
||||
if (isNewExtendedFacingValid(facing.with(rotation))) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,16 @@ package com.gtnewhorizon.structurelib.alignment;
|
||||
|
||||
import static com.gtnewhorizon.structurelib.alignment.IAlignment.STATES_COUNT;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.Flip;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.Rotation;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.Flip;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.Rotation;
|
||||
|
||||
public interface IAlignmentLimits {
|
||||
|
||||
IAlignmentLimits UNLIMITED = (direction, rotation, flip) -> true;
|
||||
@@ -37,6 +39,7 @@ public interface IAlignmentLimits {
|
||||
}
|
||||
|
||||
class Builder {
|
||||
|
||||
protected final boolean[] validStates = new boolean[STATES_COUNT];
|
||||
|
||||
private Builder() {}
|
||||
@@ -54,15 +57,13 @@ public interface IAlignmentLimits {
|
||||
}
|
||||
|
||||
public Builder deny(ForgeDirection fd) {
|
||||
ExtendedFacing.getAllWith(fd).stream()
|
||||
.mapToInt(ExtendedFacing::getIndex)
|
||||
ExtendedFacing.getAllWith(fd).stream().mapToInt(ExtendedFacing::getIndex)
|
||||
.forEach(v -> validStates[v] = false);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder allow(ForgeDirection fd) {
|
||||
ExtendedFacing.getAllWith(fd).stream()
|
||||
.mapToInt(ExtendedFacing::getIndex)
|
||||
ExtendedFacing.getAllWith(fd).stream().mapToInt(ExtendedFacing::getIndex)
|
||||
.forEach(v -> validStates[v] = true);
|
||||
return this;
|
||||
}
|
||||
@@ -78,29 +79,25 @@ public interface IAlignmentLimits {
|
||||
}
|
||||
|
||||
public Builder deny(Rotation fd) {
|
||||
ExtendedFacing.getAllWith(fd).stream()
|
||||
.mapToInt(ExtendedFacing::getIndex)
|
||||
ExtendedFacing.getAllWith(fd).stream().mapToInt(ExtendedFacing::getIndex)
|
||||
.forEach(v -> validStates[v] = false);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder allow(Rotation fd) {
|
||||
ExtendedFacing.getAllWith(fd).stream()
|
||||
.mapToInt(ExtendedFacing::getIndex)
|
||||
ExtendedFacing.getAllWith(fd).stream().mapToInt(ExtendedFacing::getIndex)
|
||||
.forEach(v -> validStates[v] = true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder deny(Flip fd) {
|
||||
ExtendedFacing.getAllWith(fd).stream()
|
||||
.mapToInt(ExtendedFacing::getIndex)
|
||||
ExtendedFacing.getAllWith(fd).stream().mapToInt(ExtendedFacing::getIndex)
|
||||
.forEach(v -> validStates[v] = false);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder allow(Flip fd) {
|
||||
ExtendedFacing.getAllWith(fd).stream()
|
||||
.mapToInt(ExtendedFacing::getIndex)
|
||||
ExtendedFacing.getAllWith(fd).stream().mapToInt(ExtendedFacing::getIndex)
|
||||
.forEach(v -> validStates[v] = true);
|
||||
return this;
|
||||
}
|
||||
@@ -122,7 +119,7 @@ public interface IAlignmentLimits {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefers rotation over flip, so both flip will get translated to opposite rotation and no flip
|
||||
* Prefers rotation to flip, so both flip will get translated to opposite rotation and no flip
|
||||
*
|
||||
* @param flip the preferred flip to be used Horizontal or vertical
|
||||
* @return this
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.gtnewhorizon.structurelib.alignment;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface IAlignmentProvider {
|
||||
|
||||
@Nullable
|
||||
IAlignment getAlignment();
|
||||
}
|
||||
@@ -2,12 +2,14 @@ package com.gtnewhorizon.structurelib.alignment;
|
||||
|
||||
import static java.lang.Math.abs;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.Direction;
|
||||
import com.gtnewhorizon.structurelib.util.Vec3Impl;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.Direction;
|
||||
import com.gtnewhorizon.structurelib.util.Vec3Impl;
|
||||
|
||||
public class IntegerAxisSwap {
|
||||
|
||||
private final Vec3Impl forFirstAxis;
|
||||
private final Vec3Impl forSecondAxis;
|
||||
private final Vec3Impl forThirdAxis;
|
||||
@@ -20,61 +22,49 @@ public class IntegerAxisSwap {
|
||||
|| abs(this.forFirstAxis.get1()) + abs(this.forSecondAxis.get1()) + abs(this.forThirdAxis.get1()) != 1
|
||||
|| abs(this.forFirstAxis.get2()) + abs(this.forSecondAxis.get2()) + abs(this.forThirdAxis.get2())
|
||||
!= 1) {
|
||||
throw new IllegalArgumentException("Axis are overlapping/missing! " + forFirstAxis.name()
|
||||
+ " " + forSecondAxis.name()
|
||||
+ " " + forThirdAxis.name());
|
||||
throw new IllegalArgumentException(
|
||||
"Axis are overlapping/missing! " + forFirstAxis
|
||||
.name() + " " + forSecondAxis.name() + " " + forThirdAxis.name());
|
||||
}
|
||||
}
|
||||
|
||||
public Vec3Impl translate(Vec3Impl point) {
|
||||
return new Vec3Impl(
|
||||
forFirstAxis.get0() * point.get0()
|
||||
+ forFirstAxis.get1() * point.get1()
|
||||
forFirstAxis.get0() * point.get0() + forFirstAxis.get1() * point.get1()
|
||||
+ forFirstAxis.get2() * point.get2(),
|
||||
forSecondAxis.get0() * point.get0()
|
||||
+ forSecondAxis.get1() * point.get1()
|
||||
forSecondAxis.get0() * point.get0() + forSecondAxis.get1() * point.get1()
|
||||
+ forSecondAxis.get2() * point.get2(),
|
||||
forThirdAxis.get0() * point.get0()
|
||||
+ forThirdAxis.get1() * point.get1()
|
||||
forThirdAxis.get0() * point.get0() + forThirdAxis.get1() * point.get1()
|
||||
+ forThirdAxis.get2() * point.get2());
|
||||
}
|
||||
|
||||
public Vec3Impl inverseTranslate(Vec3Impl point) {
|
||||
return new Vec3Impl(
|
||||
forFirstAxis.get0() * point.get0()
|
||||
+ forSecondAxis.get0() * point.get1()
|
||||
forFirstAxis.get0() * point.get0() + forSecondAxis.get0() * point.get1()
|
||||
+ forThirdAxis.get0() * point.get2(),
|
||||
forFirstAxis.get1() * point.get0()
|
||||
+ forSecondAxis.get1() * point.get1()
|
||||
forFirstAxis.get1() * point.get0() + forSecondAxis.get1() * point.get1()
|
||||
+ forThirdAxis.get1() * point.get2(),
|
||||
forFirstAxis.get2() * point.get0()
|
||||
+ forSecondAxis.get2() * point.get1()
|
||||
forFirstAxis.get2() * point.get0() + forSecondAxis.get2() * point.get1()
|
||||
+ forThirdAxis.get2() * point.get2());
|
||||
}
|
||||
|
||||
public Vec3 translate(Vec3 point) {
|
||||
return Vec3.createVectorHelper(
|
||||
forFirstAxis.get0() * point.xCoord
|
||||
+ forFirstAxis.get1() * point.yCoord
|
||||
forFirstAxis.get0() * point.xCoord + forFirstAxis.get1() * point.yCoord
|
||||
+ forFirstAxis.get2() * point.zCoord,
|
||||
forSecondAxis.get0() * point.xCoord
|
||||
+ forSecondAxis.get1() * point.yCoord
|
||||
forSecondAxis.get0() * point.xCoord + forSecondAxis.get1() * point.yCoord
|
||||
+ forSecondAxis.get2() * point.zCoord,
|
||||
forThirdAxis.get0() * point.xCoord
|
||||
+ forThirdAxis.get1() * point.yCoord
|
||||
forThirdAxis.get0() * point.xCoord + forThirdAxis.get1() * point.yCoord
|
||||
+ forThirdAxis.get2() * point.zCoord);
|
||||
}
|
||||
|
||||
public Vec3 inverseTranslate(Vec3 point) {
|
||||
return Vec3.createVectorHelper(
|
||||
forFirstAxis.get0() * point.xCoord
|
||||
+ forSecondAxis.get0() * point.yCoord
|
||||
forFirstAxis.get0() * point.xCoord + forSecondAxis.get0() * point.yCoord
|
||||
+ forThirdAxis.get0() * point.zCoord,
|
||||
forFirstAxis.get1() * point.xCoord
|
||||
+ forSecondAxis.get1() * point.yCoord
|
||||
forFirstAxis.get1() * point.xCoord + forSecondAxis.get1() * point.yCoord
|
||||
+ forThirdAxis.get1() * point.zCoord,
|
||||
forFirstAxis.get2() * point.xCoord
|
||||
+ forSecondAxis.get2() * point.yCoord
|
||||
forFirstAxis.get2() * point.xCoord + forSecondAxis.get2() * point.yCoord
|
||||
+ forThirdAxis.get2() * point.zCoord);
|
||||
}
|
||||
|
||||
|
||||
+39
-46
@@ -3,23 +3,27 @@ package com.gtnewhorizon.structurelib.alignment.constructable;
|
||||
import static com.gtnewhorizon.structurelib.util.MiscUtils.getTagKeys;
|
||||
import static net.minecraftforge.common.util.Constants.NBT.TAG_COMPOUND;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import java.util.Locale;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
|
||||
/**
|
||||
* Provide accessor methods for channel data from trigger item.
|
||||
*
|
||||
* <a href="{@docRoot}/overview-summary.html#channels">Channels section on overview</a>
|
||||
*/
|
||||
public class ChannelDataAccessor {
|
||||
|
||||
private static final String SECONDARY_HINT_TAG = "channels";
|
||||
|
||||
private ChannelDataAccessor() {}
|
||||
@@ -27,29 +31,25 @@ public class ChannelDataAccessor {
|
||||
/**
|
||||
* Return a trigger item that
|
||||
* <ul>
|
||||
* <li>Still carry all the subchannel in some unspecified ways</li>
|
||||
* <li>Have its master channel data replaced with specified subchannel's data</li>
|
||||
* <li>Still carry all the subchannel in some unspecified ways</li>
|
||||
* <li>Have its master channel data replaced with specified subchannel's data</li>
|
||||
* </ul>
|
||||
*
|
||||
* If given subchannel does not exist, masterStack may or may not be returned to save performance.
|
||||
* Code within StructureLib can depend on this behavior, you cannot.
|
||||
* If given subchannel does not exist, masterStack may or may not be returned to save performance. Code within
|
||||
* StructureLib can depend on this behavior, you cannot.
|
||||
*
|
||||
* @param masterStack trigger item. can be the return value of another {@link #withChannel(ItemStack, String)} call
|
||||
* @param channel subchannel to use. will use current master channel data instead if this channel does not exist
|
||||
* Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
* @param channel subchannel to use. will use current master channel data instead if this channel does not exist
|
||||
* Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
* @return a trigger item with new master channel
|
||||
*/
|
||||
public static ItemStack withChannel(ItemStack masterStack, String channel) {
|
||||
if (StringUtils.isEmpty(channel) || masterStack == null) throw new IllegalArgumentException();
|
||||
if (StructureLibAPI.isDebugEnabled()
|
||||
&& !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
if (StructureLibAPI.isDebugEnabled() && !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
throw new IllegalArgumentException("Channel name can be lower case ONLY");
|
||||
if (!masterStack.hasTagCompound()
|
||||
|| !masterStack.stackTagCompound.hasKey(SECONDARY_HINT_TAG, TAG_COMPOUND)
|
||||
|| !masterStack
|
||||
.stackTagCompound
|
||||
.getCompoundTag(SECONDARY_HINT_TAG)
|
||||
.hasKey(channel, NBT.TAG_INT)) return masterStack;
|
||||
if (!masterStack.hasTagCompound() || !masterStack.stackTagCompound.hasKey(SECONDARY_HINT_TAG, TAG_COMPOUND)
|
||||
|| !masterStack.stackTagCompound.getCompoundTag(SECONDARY_HINT_TAG).hasKey(channel, NBT.TAG_INT))
|
||||
return masterStack;
|
||||
ItemStack ret = new ItemStack(
|
||||
masterStack.getItem(),
|
||||
masterStack.stackTagCompound.getCompoundTag(SECONDARY_HINT_TAG).getInteger(channel),
|
||||
@@ -60,6 +60,7 @@ public class ChannelDataAccessor {
|
||||
|
||||
/**
|
||||
* Check if given trigger item contains any subchannel
|
||||
*
|
||||
* @param masterStack trigger stack to check
|
||||
* @return true if contains any subchannel
|
||||
*/
|
||||
@@ -70,57 +71,47 @@ public class ChannelDataAccessor {
|
||||
|
||||
/**
|
||||
* Check if given trigger item contains specified subchannel
|
||||
*
|
||||
* @param masterStack trigger stack to check
|
||||
* @param channel channel identifier.
|
||||
* Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
* @param channel channel identifier. Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
* @return true if contains specified subchannel
|
||||
*/
|
||||
public static boolean hasSubChannel(ItemStack masterStack, String channel) {
|
||||
if (StringUtils.isEmpty(channel) || masterStack == null) throw new IllegalArgumentException();
|
||||
if (StructureLibAPI.isDebugEnabled()
|
||||
&& !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
if (StructureLibAPI.isDebugEnabled() && !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
throw new IllegalArgumentException("Channel name can be lower case ONLY");
|
||||
return !channel.isEmpty()
|
||||
&& masterStack.hasTagCompound()
|
||||
return !channel.isEmpty() && masterStack.hasTagCompound()
|
||||
&& masterStack.stackTagCompound.hasKey(SECONDARY_HINT_TAG, TAG_COMPOUND)
|
||||
&& masterStack
|
||||
.stackTagCompound
|
||||
.getCompoundTag(SECONDARY_HINT_TAG)
|
||||
.hasKey(channel, NBT.TAG_INT);
|
||||
&& masterStack.stackTagCompound.getCompoundTag(SECONDARY_HINT_TAG).hasKey(channel, NBT.TAG_INT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the subchannel data from given trigger item. Will use master channel instead if not present.
|
||||
*
|
||||
* @param masterStack trigger stack to query from
|
||||
* @param channel channel identifier.
|
||||
* Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
* @param channel channel identifier. Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
* @return channel data
|
||||
*/
|
||||
public static int getChannelData(ItemStack masterStack, String channel) {
|
||||
if (StringUtils.isEmpty(channel) || masterStack == null) throw new IllegalArgumentException();
|
||||
if (StructureLibAPI.isDebugEnabled()
|
||||
&& !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
if (StructureLibAPI.isDebugEnabled() && !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
throw new IllegalArgumentException("Channel name can be lower case ONLY");
|
||||
if (!masterStack.hasTagCompound()
|
||||
|| !masterStack.stackTagCompound.hasKey(SECONDARY_HINT_TAG, TAG_COMPOUND)
|
||||
|| !masterStack
|
||||
.stackTagCompound
|
||||
.getCompoundTag(SECONDARY_HINT_TAG)
|
||||
.hasKey(channel, NBT.TAG_INT)) return masterStack.stackSize;
|
||||
if (!masterStack.hasTagCompound() || !masterStack.stackTagCompound.hasKey(SECONDARY_HINT_TAG, TAG_COMPOUND)
|
||||
|| !masterStack.stackTagCompound.getCompoundTag(SECONDARY_HINT_TAG).hasKey(channel, NBT.TAG_INT))
|
||||
return masterStack.stackSize;
|
||||
return masterStack.stackTagCompound.getCompoundTag(SECONDARY_HINT_TAG).getInteger(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the subchannel data on given trigger item
|
||||
*
|
||||
* @param masterStack trigger stack to check
|
||||
* @param channel channel identifier.
|
||||
* Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
* @param data subchannel data. should always be a positive value
|
||||
* @param channel channel identifier. Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
* @param data subchannel data. should always be a positive value
|
||||
*/
|
||||
public static void setChannelData(ItemStack masterStack, String channel, int data) {
|
||||
if (StringUtils.isEmpty(channel) || masterStack == null) throw new IllegalArgumentException();
|
||||
if (StructureLibAPI.isDebugEnabled()
|
||||
&& !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
if (StructureLibAPI.isDebugEnabled() && !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
throw new IllegalArgumentException("Channel name can be lower case ONLY");
|
||||
if (data <= 0) throw new IllegalArgumentException();
|
||||
if (masterStack.stackTagCompound == null) masterStack.stackTagCompound = new NBTTagCompound();
|
||||
@@ -131,14 +122,13 @@ public class ChannelDataAccessor {
|
||||
|
||||
/**
|
||||
* Clear the given subchannel from given trigger item, if it exists
|
||||
*
|
||||
* @param masterStack trigger stack to unset
|
||||
* @param channel channel identifier.
|
||||
* Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
* @param channel channel identifier. Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
*/
|
||||
public static void unsetChannelData(ItemStack masterStack, String channel) {
|
||||
if (StringUtils.isEmpty(channel) || masterStack == null) throw new IllegalArgumentException();
|
||||
if (StructureLibAPI.isDebugEnabled()
|
||||
&& !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
if (StructureLibAPI.isDebugEnabled() && !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
throw new IllegalArgumentException("Channel name can be lower case ONLY");
|
||||
if (masterStack.stackTagCompound == null) masterStack.stackTagCompound = new NBTTagCompound();
|
||||
NBTTagCompound main = masterStack.stackTagCompound;
|
||||
@@ -151,6 +141,7 @@ public class ChannelDataAccessor {
|
||||
|
||||
/**
|
||||
* Wipe all subchannel data on given trigger item
|
||||
*
|
||||
* @param masterStack trigger stack to wipe
|
||||
*/
|
||||
public static void wipeChannelData(ItemStack masterStack) {
|
||||
@@ -160,10 +151,11 @@ public class ChannelDataAccessor {
|
||||
|
||||
/**
|
||||
* Iterate over all subchannel data on trigger stack. Does not include master channel!!
|
||||
*
|
||||
* @param masterStack trigger stack to check
|
||||
* @return A java8 stream of pairs. Key is channel identifier and value is channel data. Pairs do not support
|
||||
* mutation nor removal. Can still cause {@link java.util.ConcurrentModificationException} if underlying channel
|
||||
* data is modified while stream is working.
|
||||
* mutation nor removal. Can still cause {@link java.util.ConcurrentModificationException} if underlying
|
||||
* channel data is modified while stream is working.
|
||||
*/
|
||||
public static Stream<Entry<String, Integer>> iterateChannelData(ItemStack masterStack) {
|
||||
if (!hasSubChannel(masterStack)) return Stream.empty();
|
||||
@@ -173,6 +165,7 @@ public class ChannelDataAccessor {
|
||||
|
||||
/**
|
||||
* Get the number of subchannels present on given trigger item. Does not include master channel.
|
||||
*
|
||||
* @param masterStack trigger stack to query from
|
||||
* @return subchannel count
|
||||
*/
|
||||
|
||||
+22
-21
@@ -1,12 +1,7 @@
|
||||
package com.gtnewhorizon.structurelib.alignment.constructable;
|
||||
|
||||
import com.gtnewhorizon.structurelib.ConfigurationHandler;
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import com.gtnewhorizon.structurelib.alignment.IAlignment;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.structure.IItemSource;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -16,6 +11,14 @@ import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
import com.gtnewhorizon.structurelib.ConfigurationHandler;
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import com.gtnewhorizon.structurelib.alignment.IAlignment;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.structure.IItemSource;
|
||||
import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
|
||||
|
||||
public class ConstructableUtility {
|
||||
|
||||
private static final WeakHashMap<EntityPlayerMP, Long> lastUse = new WeakHashMap<>();
|
||||
@@ -23,16 +26,16 @@ public class ConstructableUtility {
|
||||
|
||||
private ConstructableUtility() {}
|
||||
|
||||
public static boolean handle(
|
||||
ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ, int aSide) {
|
||||
public static boolean handle(ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ,
|
||||
int aSide) {
|
||||
StructureLibAPI.startHinting(aWorld);
|
||||
boolean ret = handle0(aStack, aPlayer, aWorld, aX, aY, aZ, aSide);
|
||||
StructureLibAPI.endHinting(aWorld);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static boolean handle0(
|
||||
ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ, int aSide) {
|
||||
private static boolean handle0(ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ,
|
||||
int aSide) {
|
||||
TileEntity tTileEntity = aWorld.getTileEntity(aX, aY, aZ);
|
||||
if (tTileEntity == null || aPlayer instanceof FakePlayer) {
|
||||
return aPlayer instanceof EntityPlayerMP;
|
||||
@@ -43,9 +46,10 @@ public class ConstructableUtility {
|
||||
|
||||
long timePast = System.currentTimeMillis() - getLastUseMilis(aPlayer);
|
||||
if (timePast < ConfigurationHandler.INSTANCE.getAutoPlaceInterval()) {
|
||||
aPlayer.addChatComponentMessage(new ChatComponentTranslation(
|
||||
"item.structurelib.constructableTrigger.too_fast",
|
||||
ConfigurationHandler.INSTANCE.getAutoPlaceInterval() - timePast));
|
||||
aPlayer.addChatComponentMessage(
|
||||
new ChatComponentTranslation(
|
||||
"item.structurelib.constructableTrigger.too_fast",
|
||||
ConfigurationHandler.INSTANCE.getAutoPlaceInterval() - timePast));
|
||||
return true;
|
||||
}
|
||||
} else if (!StructureLib.isCurrentPlayer(aPlayer)) {
|
||||
@@ -58,8 +62,7 @@ public class ConstructableUtility {
|
||||
else if (tTileEntity instanceof IConstructable) {
|
||||
constructable = (IConstructable) tTileEntity;
|
||||
} else if (IMultiblockInfoContainer.contains(tTileEntity.getClass())) {
|
||||
ExtendedFacing facing = tTileEntity instanceof IAlignment
|
||||
? ((IAlignment) tTileEntity).getExtendedFacing()
|
||||
ExtendedFacing facing = tTileEntity instanceof IAlignment ? ((IAlignment) tTileEntity).getExtendedFacing()
|
||||
: ExtendedFacing.of(ForgeDirection.getOrientation(aSide));
|
||||
constructable = IMultiblockInfoContainer.<TileEntity>get(tTileEntity.getClass())
|
||||
.toConstructable(tTileEntity, facing);
|
||||
@@ -74,12 +77,10 @@ public class ConstructableUtility {
|
||||
if (aPlayer.capabilities.isCreativeMode) {
|
||||
constructable.construct(aStack, false);
|
||||
} else if (constructable instanceof ISurvivalConstructable) {
|
||||
int built = ((ISurvivalConstructable) constructable)
|
||||
.survivalConstruct(
|
||||
aStack,
|
||||
ConfigurationHandler.INSTANCE.getAutoPlaceBudget(),
|
||||
IItemSource.fromPlayer(playerMP),
|
||||
playerMP);
|
||||
int built = ((ISurvivalConstructable) constructable).survivalConstruct(
|
||||
aStack,
|
||||
ConfigurationHandler.INSTANCE.getAutoPlaceBudget(),
|
||||
ISurvivalBuildEnvironment.create(IItemSource.fromPlayer(playerMP), playerMP));
|
||||
if (built > 0) {
|
||||
playerMP.addChatMessage(new ChatComponentTranslation("structurelib.autoplace.built_stat", built));
|
||||
} else if (built == -1) {
|
||||
|
||||
+12
-1
@@ -1,15 +1,26 @@
|
||||
package com.gtnewhorizon.structurelib.alignment.constructable;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
/**
|
||||
* Created by Tec on 24.03.2017.
|
||||
*/
|
||||
public interface IConstructable {
|
||||
|
||||
void construct(ItemStack stackSize, boolean hintsOnly);
|
||||
|
||||
/**
|
||||
* Get the structure definition used for this constructable. Can be null if this constructable is not backed by one.
|
||||
*/
|
||||
default IStructureDefinition<?> getStructureDefinition() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
String[] getStructureDescription(ItemStack stackSize);
|
||||
}
|
||||
+1
@@ -6,6 +6,7 @@ import javax.annotation.Nullable;
|
||||
* Implement this interface if this tile entity MIGHT be constructable
|
||||
*/
|
||||
public interface IConstructableProvider {
|
||||
|
||||
/**
|
||||
* @return null if not constructable, an instance otherwise.
|
||||
*/
|
||||
|
||||
+35
-41
@@ -1,19 +1,25 @@
|
||||
package com.gtnewhorizon.structurelib.alignment.constructable;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.structure.IItemSource;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import java.util.HashMap;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.structure.AutoPlaceEnvironment;
|
||||
import com.gtnewhorizon.structurelib.structure.IItemSource;
|
||||
import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
/**
|
||||
* To implement IConstructable on not own TileEntities
|
||||
*/
|
||||
public interface IMultiblockInfoContainer<T> {
|
||||
|
||||
HashMap<String, IMultiblockInfoContainer<?>> MULTIBLOCK_MAP = new HashMap<>();
|
||||
|
||||
/**
|
||||
@@ -36,28 +42,37 @@ public interface IMultiblockInfoContainer<T> {
|
||||
void construct(ItemStack stackSize, boolean hintsOnly, T tileEntity, ExtendedFacing aSide);
|
||||
|
||||
/**
|
||||
* Construct the structure using {@link com.gtnewhorizon.structurelib.structure.IStructureElement#survivalPlaceBlock(Object, World, int, int, int, ItemStack, IItemSource, EntityPlayerMP, java.util.function.Consumer)}
|
||||
* Construct the structure using
|
||||
* {@link com.gtnewhorizon.structurelib.structure.IStructureElement#survivalPlaceBlock(Object, World, int, int, int, ItemStack, AutoPlaceEnvironment)}
|
||||
*
|
||||
* @return -1 if done, a helping pointer
|
||||
*/
|
||||
default int survivalConstruct(
|
||||
ItemStack stackSize,
|
||||
int elementBudge,
|
||||
IItemSource source,
|
||||
EntityPlayerMP actorProfile,
|
||||
T tileEntity,
|
||||
ExtendedFacing aSide) {
|
||||
return -1;
|
||||
}
|
||||
int survivalConstruct(ItemStack stackSize, int elementBudge, ISurvivalBuildEnvironment env, T tileEntity,
|
||||
ExtendedFacing aSide);
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
String[] getDescription(ItemStack stackSize);
|
||||
|
||||
/**
|
||||
* Override this and return {@link #toConstructable(IMultiblockInfoContainer, Object, ExtendedFacing)} if
|
||||
* {@link #survivalConstruct(ItemStack, int, IItemSource, EntityPlayerMP, Object, ExtendedFacing)} isn't a stub
|
||||
*/
|
||||
default IConstructable toConstructable(T tileEntity, ExtendedFacing aSide) {
|
||||
return new IConstructable() {
|
||||
default ISurvivalConstructable toConstructable(T tileEntity, ExtendedFacing aSide) {
|
||||
return new ISurvivalConstructable() {
|
||||
|
||||
@Override
|
||||
public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
|
||||
return IMultiblockInfoContainer.this
|
||||
.survivalConstruct(stackSize, elementBudget, env, tileEntity, aSide);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int survivalConstruct(ItemStack stackSize, int elementBudget, IItemSource source,
|
||||
EntityPlayerMP actor) {
|
||||
return IMultiblockInfoContainer.this.survivalConstruct(
|
||||
stackSize,
|
||||
elementBudget,
|
||||
ISurvivalBuildEnvironment.create(source, actor),
|
||||
tileEntity,
|
||||
aSide);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void construct(ItemStack stackSize, boolean hintsOnly) {
|
||||
IMultiblockInfoContainer.this.construct(stackSize, hintsOnly, tileEntity, aSide);
|
||||
@@ -69,25 +84,4 @@ public interface IMultiblockInfoContainer<T> {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static <T> ISurvivalConstructable toConstructable(
|
||||
IMultiblockInfoContainer<T> thiz, T tileEntity, ExtendedFacing aSide) {
|
||||
return new ISurvivalConstructable() {
|
||||
@Override
|
||||
public int survivalConstruct(
|
||||
ItemStack stackSize, int elementBudget, IItemSource source, EntityPlayerMP actor) {
|
||||
return thiz.survivalConstruct(stackSize, elementBudget, source, actor, tileEntity, aSide);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void construct(ItemStack stackSize, boolean hintsOnly) {
|
||||
thiz.construct(stackSize, hintsOnly, tileEntity, aSide);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getStructureDescription(ItemStack stackSize) {
|
||||
return thiz.getDescription(stackSize);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+73
-5
@@ -1,17 +1,85 @@
|
||||
package com.gtnewhorizon.structurelib.alignment.constructable;
|
||||
|
||||
import com.gtnewhorizon.structurelib.structure.IItemSource;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.structure.AutoPlaceEnvironment;
|
||||
import com.gtnewhorizon.structurelib.structure.IItemSource;
|
||||
import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
|
||||
|
||||
/**
|
||||
* An extension to {@link IConstructable}. Tile Entities (or delegates returned by
|
||||
* {@link IConstructableProvider#getConstructable()} should implement this interface to allow third party tools and
|
||||
* StructureLib builtin constructable tools to trigger autoplace in survival mode.
|
||||
* <p>
|
||||
* While not originally planned, a creative player can also use this interface to trigger autoplace by using an
|
||||
* {@link IItemSource} with every possible items in the game.
|
||||
*/
|
||||
public interface ISurvivalConstructable extends IConstructable {
|
||||
|
||||
/**
|
||||
* Construct the structure using {@link com.gtnewhorizon.structurelib.structure.IStructureElement#survivalPlaceBlock(Object, World, int, int, int, ItemStack, IItemSource, EntityPlayerMP, java.util.function.Consumer)}
|
||||
* End player might want to disable this hack if it turns out to be too crashy
|
||||
*/
|
||||
boolean DISABLE_HACKY_MIGRATION_CODE = Boolean.getBoolean("structurelib.disable_isc_migration_hack");
|
||||
|
||||
/**
|
||||
* Construct the structure using
|
||||
* {@link com.gtnewhorizon.structurelib.structure.IStructureElement#survivalPlaceBlock(Object, World, int, int, int, ItemStack, IItemSource, EntityPlayerMP, java.util.function.Consumer)}
|
||||
* or
|
||||
* {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition#survivalBuild(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int, int, IItemSource, EntityPlayerMP, boolean)}
|
||||
*
|
||||
* @param elementBudget The server configured element budget. You can tune this up a bit if the structure is too big, but
|
||||
* generally should not be a 4 digits number to not overwhelm the server
|
||||
* @param elementBudget The server configured element budget. The implementor can choose to tune this up a bit if
|
||||
* the structure is too big, but generally should not be a 4 digits number to not overwhelm the
|
||||
* server
|
||||
* @return -1 if done, otherwise number of elements placed this round
|
||||
*/
|
||||
int survivalConstruct(ItemStack stackSize, int elementBudget, IItemSource source, EntityPlayerMP actor);
|
||||
@Deprecated
|
||||
default int survivalConstruct(ItemStack stackSize, int elementBudget, IItemSource source, EntityPlayerMP actor) {
|
||||
return survivalConstruct(stackSize, elementBudget, ISurvivalBuildEnvironment.create(source, actor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the structure using
|
||||
* {@link com.gtnewhorizon.structurelib.structure.IStructureElement#survivalPlaceBlock(Object, World, int, int, int, ItemStack, AutoPlaceEnvironment)}
|
||||
* or
|
||||
* {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition#survivalBuild(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int, int, ISurvivalBuildEnvironment, boolean)}
|
||||
*
|
||||
* @param elementBudget The server configured element budget. The implementor can choose to tune this up a bit if
|
||||
* the structure is too big, but generally should not be a 4 digits number to not overwhelm the
|
||||
* server
|
||||
* @return -1 if done, -2 if not supported (e.g. due to an incompatible change in the API of env, otherwise number
|
||||
* of elements placed this round
|
||||
*/
|
||||
default int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
|
||||
EntityPlayer actor = env.getActor();
|
||||
if (actor instanceof EntityPlayerMP)
|
||||
return survivalConstruct(stackSize, elementBudget, env.getSource(), (EntityPlayerMP) actor);
|
||||
else if (!DISABLE_HACKY_MIGRATION_CODE && __get_player() == null) {
|
||||
// as far as I know, no implementor would actually do anything to actor beyond passing it down to
|
||||
// IStructureDefinition, so it's probably fine to proceed like this
|
||||
GlobalStates.entityPlayer.set(env.getActor());
|
||||
try {
|
||||
return survivalConstruct(stackSize, elementBudget, env.getSource(), null);
|
||||
} finally {
|
||||
GlobalStates.entityPlayer.remove();
|
||||
}
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal hack. Do not use.
|
||||
*/
|
||||
@Deprecated
|
||||
static EntityPlayer __get_player() {
|
||||
return GlobalStates.entityPlayer.get();
|
||||
}
|
||||
}
|
||||
|
||||
class GlobalStates {
|
||||
|
||||
public static final ThreadLocal<EntityPlayer> entityPlayer = new ThreadLocal<>();
|
||||
}
|
||||
@@ -1,9 +1,16 @@
|
||||
package com.gtnewhorizon.structurelib.alignment.enumerable;
|
||||
|
||||
import com.gtnewhorizon.structurelib.util.Vec3Impl;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
import com.gtnewhorizon.structurelib.util.Vec3Impl;
|
||||
|
||||
public enum Direction {
|
||||
|
||||
DOWN(ForgeDirection.DOWN),
|
||||
UP(ForgeDirection.UP),
|
||||
NORTH(ForgeDirection.NORTH),
|
||||
@@ -14,10 +21,12 @@ public enum Direction {
|
||||
private final ForgeDirection forgeDirection;
|
||||
private final Vec3Impl axisVector;
|
||||
public static final Direction[] VALUES = values();
|
||||
private static final Map<Vec3Impl, Direction> reverseMap = Arrays.stream(VALUES)
|
||||
.collect(Collectors.toMap(d -> d.axisVector, Function.identity()));
|
||||
|
||||
Direction(ForgeDirection forgeDirection) {
|
||||
this.forgeDirection = forgeDirection;
|
||||
axisVector = new Vec3Impl(forgeDirection.offsetX, forgeDirection.offsetY, forgeDirection.offsetZ);
|
||||
axisVector = Vec3Impl.getFromPool(forgeDirection.offsetX, forgeDirection.offsetY, forgeDirection.offsetZ);
|
||||
}
|
||||
|
||||
public ForgeDirection getForgeDirection() {
|
||||
@@ -31,4 +40,8 @@ public enum Direction {
|
||||
public static Vec3Impl getAxisVector(ForgeDirection forgeDirection) {
|
||||
return VALUES[forgeDirection.ordinal()].axisVector;
|
||||
}
|
||||
|
||||
public static Direction getByAxisVector(Vec3Impl vec3) {
|
||||
return reverseMap.get(vec3);
|
||||
}
|
||||
}
|
||||
+51
-26
@@ -6,16 +6,19 @@ import static java.lang.Math.abs;
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.stream.Collectors.*;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.gtnewhorizon.structurelib.alignment.IAlignment;
|
||||
import com.gtnewhorizon.structurelib.alignment.IntegerAxisSwap;
|
||||
import com.gtnewhorizon.structurelib.util.Vec3Impl;
|
||||
import java.util.*;
|
||||
|
||||
import net.minecraft.util.StatCollector;
|
||||
import net.minecraft.util.Vec3;
|
||||
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.util.Vec3Impl;
|
||||
|
||||
public enum ExtendedFacing {
|
||||
|
||||
DOWN_NORMAL_NONE("down normal none"),
|
||||
DOWN_NORMAL_HORIZONTAL("down normal horizontal"),
|
||||
DOWN_NORMAL_VERTICAL("down normal vertical"),
|
||||
@@ -119,31 +122,31 @@ public enum ExtendedFacing {
|
||||
public static final int STATES_COUNT = VALUES.length;
|
||||
|
||||
static {
|
||||
stream(values())
|
||||
.forEach(extendedFacing ->
|
||||
FOR_FACING.compute(extendedFacing.direction, ((forgeDirection, extendedFacings) -> {
|
||||
if (extendedFacings == null) {
|
||||
extendedFacings = new ArrayList<>();
|
||||
}
|
||||
extendedFacings.add(extendedFacing);
|
||||
return extendedFacings;
|
||||
})));
|
||||
stream(values()).forEach(
|
||||
extendedFacing -> FOR_FACING.compute(extendedFacing.direction, ((forgeDirection, extendedFacings) -> {
|
||||
if (extendedFacings == null) {
|
||||
extendedFacings = new ArrayList<>();
|
||||
}
|
||||
extendedFacings.add(extendedFacing);
|
||||
return extendedFacings;
|
||||
})));
|
||||
}
|
||||
|
||||
private static final Map<String, ExtendedFacing> NAME_LOOKUP =
|
||||
stream(VALUES).collect(toMap(ExtendedFacing::getName2, (extendedFacing) -> extendedFacing));
|
||||
private static final Map<String, ExtendedFacing> NAME_LOOKUP = stream(VALUES)
|
||||
.collect(toMap(ExtendedFacing::getName2, (extendedFacing) -> extendedFacing));
|
||||
private static final EnumMap<ForgeDirection, ImmutableSet<ExtendedFacing>> LOOKUP_BY_DIRECTION = stream(VALUES)
|
||||
.collect(groupingBy(
|
||||
ExtendedFacing::getDirection,
|
||||
() -> new EnumMap<>(ForgeDirection.class),
|
||||
collectingAndThen(toSet(), ImmutableSet::copyOf)));
|
||||
private static final EnumMap<Rotation, ImmutableSet<ExtendedFacing>> LOOKUP_BY_ROTATION = stream(VALUES)
|
||||
.collect(groupingBy(
|
||||
.collect(
|
||||
groupingBy(
|
||||
ExtendedFacing::getDirection,
|
||||
() -> new EnumMap<>(ForgeDirection.class),
|
||||
collectingAndThen(toSet(), ImmutableSet::copyOf)));
|
||||
private static final EnumMap<Rotation, ImmutableSet<ExtendedFacing>> LOOKUP_BY_ROTATION = stream(VALUES).collect(
|
||||
groupingBy(
|
||||
ExtendedFacing::getRotation,
|
||||
() -> new EnumMap<>(Rotation.class),
|
||||
collectingAndThen(toSet(), ImmutableSet::copyOf)));
|
||||
private static final EnumMap<Flip, ImmutableSet<ExtendedFacing>> LOOKUP_BY_FLIP = stream(VALUES)
|
||||
.collect(groupingBy(
|
||||
private static final EnumMap<Flip, ImmutableSet<ExtendedFacing>> LOOKUP_BY_FLIP = stream(VALUES).collect(
|
||||
groupingBy(
|
||||
ExtendedFacing::getFlip,
|
||||
() -> new EnumMap<>(Flip.class),
|
||||
collectingAndThen(toSet(), ImmutableSet::copyOf)));
|
||||
@@ -333,7 +336,7 @@ public enum ExtendedFacing {
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates relative to front facing offset to world offset
|
||||
* Translates relative to front facing offset to world offset
|
||||
*
|
||||
* @param abcOffset A,B,C offset (facing relative {@code L-->R,U-->D,F-->B})
|
||||
* @return X, Y, Z offset in world
|
||||
@@ -355,10 +358,32 @@ public enum ExtendedFacing {
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates world offset to relative front facing offset
|
||||
* do note the ABC coordinate system is (X, -Y, Z).
|
||||
*/
|
||||
public ForgeDirection getWorldDirection(ForgeDirection abcDirection) {
|
||||
switch (abcDirection) {
|
||||
case NORTH:
|
||||
return getRelativeForwardInWorld();
|
||||
case SOUTH:
|
||||
return getRelativeBackInWorld();
|
||||
case UP:
|
||||
return getRelativeDownInWorld();
|
||||
case DOWN:
|
||||
return getRelativeUpInWorld();
|
||||
case EAST:
|
||||
return getRelativeLeftInWorld();
|
||||
case WEST:
|
||||
return getRelativeRightInWorld();
|
||||
default:
|
||||
return ForgeDirection.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates world offset to relative front facing offset
|
||||
*
|
||||
* @param xyzOffset X,Y,Z offset in world
|
||||
* @return A, B, C offset (facing relative {@code L-->R,U-->D,F-->B})
|
||||
* @return A, B, C offset (facing relative {@code L-->R,U-->D,F-->B})
|
||||
*/
|
||||
public Vec3 getOffsetABC(Vec3 xyzOffset) {
|
||||
return integerAxisSwap.translate(xyzOffset);
|
||||
|
||||
@@ -7,9 +7,11 @@ import static java.util.stream.Collectors.toMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public enum Flip {
|
||||
|
||||
NONE(3, "none"),
|
||||
HORIZONTAL(2, "horizontal"),
|
||||
VERTICAL(1, "vertical"),
|
||||
|
||||
@@ -7,9 +7,11 @@ import static java.util.stream.Collectors.toMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public enum Rotation {
|
||||
|
||||
NORMAL(2, "normal"),
|
||||
CLOCKWISE(3, "clockwise"),
|
||||
UPSIDE_DOWN(0, "upside down"),
|
||||
@@ -19,8 +21,8 @@ public enum Rotation {
|
||||
private final String name;
|
||||
|
||||
public static final Rotation[] VALUES = values();
|
||||
private static final Map<String, Rotation> NAME_LOOKUP =
|
||||
stream(VALUES).collect(toMap(Rotation::getName2, (rotation) -> rotation));
|
||||
private static final Map<String, Rotation> NAME_LOOKUP = stream(VALUES)
|
||||
.collect(toMap(Rotation::getName2, (rotation) -> rotation));
|
||||
|
||||
Rotation(int oppositeIn, String nameIn) {
|
||||
this.opposite = oppositeIn;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* This package provide a framework for rotating a given block, or a multiblock structure.
|
||||
* <p>
|
||||
* All public stuff in this package and its subpackages are considered part of the public API.
|
||||
* Backwards compatibility is maintained to the maximum extend possible.
|
||||
* All public stuff in this package and its subpackages are considered part of the public API. Backwards compatibility
|
||||
* is maintained to the maximum extend possible.
|
||||
*/
|
||||
package com.gtnewhorizon.structurelib.alignment;
|
||||
@@ -1,10 +1,7 @@
|
||||
package com.gtnewhorizon.structurelib.block;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.client.renderer.texture.IIconRegister;
|
||||
@@ -14,7 +11,14 @@ import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class BlockHint extends Block {
|
||||
|
||||
private static final IIcon[] hint = new IIcon[16];
|
||||
|
||||
public BlockHint() {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package com.gtnewhorizon.structurelib.command;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
|
||||
import com.gtnewhorizon.structurelib.item.ItemConstructableTrigger;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.command.CommandBase;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.command.WrongUsageException;
|
||||
@@ -13,7 +12,11 @@ import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
import net.minecraft.util.ChatComponentTranslation;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
|
||||
import com.gtnewhorizon.structurelib.item.ItemConstructableTrigger;
|
||||
|
||||
public class CommandConfigureChannels extends CommandBase {
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return "sl_channel";
|
||||
@@ -58,13 +61,12 @@ public class CommandConfigureChannels extends CommandBase {
|
||||
if (!ChannelDataAccessor.hasSubChannel(heldItem)) {
|
||||
sender.addChatMessage(new ChatComponentText("No subchannel"));
|
||||
} else {
|
||||
sender.addChatMessage(new ChatComponentTranslation(
|
||||
"item.structurelib.constructableTrigger.desc.lshift.0",
|
||||
ChannelDataAccessor.countChannelData(heldItem)));
|
||||
ChannelDataAccessor.iterateChannelData(heldItem)
|
||||
.map(e -> e.getKey() + ": " + e.getValue())
|
||||
.map(ChatComponentText::new)
|
||||
.forEach(player::addChatMessage);
|
||||
sender.addChatMessage(
|
||||
new ChatComponentTranslation(
|
||||
"item.structurelib.constructableTrigger.desc.lshift.0",
|
||||
ChannelDataAccessor.countChannelData(heldItem)));
|
||||
ChannelDataAccessor.iterateChannelData(heldItem).map(e -> e.getKey() + ": " + e.getValue())
|
||||
.map(ChatComponentText::new).forEach(player::addChatMessage);
|
||||
}
|
||||
return;
|
||||
case "wipe":
|
||||
@@ -73,13 +75,11 @@ public class CommandConfigureChannels extends CommandBase {
|
||||
case "get":
|
||||
case "unset":
|
||||
if (args.length < 2) throw new WrongUsageException(getCommandUsage(sender));
|
||||
channel =
|
||||
args.length == 2 ? args[1] : Arrays.stream(args).skip(1).collect(Collectors.joining());
|
||||
channel = args.length == 2 ? args[1] : Arrays.stream(args).skip(1).collect(Collectors.joining());
|
||||
break;
|
||||
case "set":
|
||||
if (args.length < 3) throw new WrongUsageException(getCommandUsage(sender));
|
||||
channel = args.length == 3
|
||||
? args[1]
|
||||
channel = args.length == 3 ? args[1]
|
||||
: Arrays.stream(args).skip(1).limit(args.length - 2).collect(Collectors.joining());
|
||||
break;
|
||||
default:
|
||||
@@ -88,9 +88,9 @@ public class CommandConfigureChannels extends CommandBase {
|
||||
|
||||
switch (args[0]) {
|
||||
case "get":
|
||||
if (ChannelDataAccessor.hasSubChannel(heldItem, channel))
|
||||
sender.addChatMessage(new ChatComponentText(
|
||||
channel + " value: " + ChannelDataAccessor.getChannelData(heldItem, channel)));
|
||||
if (ChannelDataAccessor.hasSubChannel(heldItem, channel)) sender.addChatMessage(
|
||||
new ChatComponentText(
|
||||
channel + " value: " + ChannelDataAccessor.getChannelData(heldItem, channel)));
|
||||
else sender.addChatMessage(new ChatComponentText(channel + " value: N/A"));
|
||||
break;
|
||||
case "clear":
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
package com.gtnewhorizon.structurelib.entity.fx;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.client.particle.EntityFX;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class WeightlessParticleFX extends EntityFX {
|
||||
public WeightlessParticleFX(
|
||||
World p_i1205_1_,
|
||||
double p_i1205_2_,
|
||||
double p_i1205_4_,
|
||||
double p_i1205_6_,
|
||||
double p_i1205_8_,
|
||||
double p_i1205_10_,
|
||||
double p_i1205_12_) {
|
||||
|
||||
public WeightlessParticleFX(World p_i1205_1_, double p_i1205_2_, double p_i1205_4_, double p_i1205_6_,
|
||||
double p_i1205_8_, double p_i1205_10_, double p_i1205_12_) {
|
||||
super(p_i1205_1_, p_i1205_2_, p_i1205_4_, p_i1205_6_, p_i1205_8_, p_i1205_10_, p_i1205_12_);
|
||||
this.motionX = p_i1205_8_ + (double) ((float) (Math.random() * 2.0D - 1.0D) * 0.05F);
|
||||
this.motionY = p_i1205_10_ + (double) ((float) (Math.random() * 2.0D - 1.0D) * 0.05F);
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.gtnewhorizon.structurelib.gui;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
|
||||
import com.gtnewhorizon.structurelib.gui.GuiScrollableList.IGuiScreen;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.GuiTextField;
|
||||
@@ -15,12 +13,18 @@ import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
|
||||
import com.gtnewhorizon.structurelib.gui.GuiScrollableList.IGuiScreen;
|
||||
|
||||
public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen {
|
||||
|
||||
private static final int KEY_MAX_WIDTH = 50;
|
||||
private final ItemStack trigger;
|
||||
private final GuiChannelsList list;
|
||||
@@ -48,6 +52,7 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen
|
||||
guiTop = (this.height - this.getYSize()) / 2;
|
||||
|
||||
key = new GuiTextField(fontRendererObj, guiLeft + 45, guiTop + 119, 151 + 12 - 45, 12) {
|
||||
|
||||
@Override
|
||||
public void writeText(String text) {
|
||||
// force lower case
|
||||
@@ -58,8 +63,7 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen
|
||||
@Override
|
||||
public void mouseClicked(int p_146192_1_, int p_146192_2_, int p_146192_3_) {
|
||||
super.mouseClicked(p_146192_1_, p_146192_2_, p_146192_3_);
|
||||
boolean flag = p_146192_1_ >= this.xPosition
|
||||
&& p_146192_1_ < this.xPosition + this.width
|
||||
boolean flag = p_146192_1_ >= this.xPosition && p_146192_1_ < this.xPosition + this.width
|
||||
&& p_146192_2_ >= this.yPosition
|
||||
&& p_146192_2_ < this.yPosition + this.height;
|
||||
if (flag && p_146192_3_ == 1) {
|
||||
@@ -75,6 +79,7 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen
|
||||
}
|
||||
};
|
||||
value = new GuiTextField(fontRendererObj, guiLeft + 45, guiTop + 139, 151 + 12 - 45, 12) {
|
||||
|
||||
@Override
|
||||
public void writeText(String text) {
|
||||
// ignore write requests containing non digit characters.
|
||||
@@ -104,8 +109,7 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen
|
||||
@Override
|
||||
public void mouseClicked(int p_146192_1_, int p_146192_2_, int p_146192_3_) {
|
||||
super.mouseClicked(p_146192_1_, p_146192_2_, p_146192_3_);
|
||||
boolean flag = p_146192_1_ >= this.xPosition
|
||||
&& p_146192_1_ < this.xPosition + this.width
|
||||
boolean flag = p_146192_1_ >= this.xPosition && p_146192_1_ < this.xPosition + this.width
|
||||
&& p_146192_2_ >= this.yPosition
|
||||
&& p_146192_2_ < this.yPosition + this.height;
|
||||
if (flag && p_146192_3_ == 1) {
|
||||
@@ -122,22 +126,30 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen
|
||||
|
||||
list.onGuiInit(this);
|
||||
|
||||
addButton(new GuiButton(
|
||||
0, guiLeft + 12, guiTop + 157, 47, 20, I18n.format("item.structurelib.constructableTrigger.gui.add")));
|
||||
addButton(new GuiButton(
|
||||
1,
|
||||
guiLeft + 65,
|
||||
guiTop + 157,
|
||||
47,
|
||||
20,
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.unset")));
|
||||
addButton(new GuiButton(
|
||||
2,
|
||||
guiLeft + 118,
|
||||
guiTop + 157,
|
||||
47,
|
||||
20,
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.wipe")));
|
||||
addButton(
|
||||
new GuiButton(
|
||||
0,
|
||||
guiLeft + 12,
|
||||
guiTop + 157,
|
||||
47,
|
||||
20,
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.add")));
|
||||
addButton(
|
||||
new GuiButton(
|
||||
1,
|
||||
guiLeft + 65,
|
||||
guiTop + 157,
|
||||
47,
|
||||
20,
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.unset")));
|
||||
addButton(
|
||||
new GuiButton(
|
||||
2,
|
||||
guiLeft + 118,
|
||||
guiTop + 157,
|
||||
47,
|
||||
20,
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.wipe")));
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
@@ -236,9 +248,9 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen
|
||||
private void updateButtons() {
|
||||
// this will be called from setText of key and value. NEVER UPDATE THE VALUE OF THESE HERE OR GET A
|
||||
// STACKOVERFLOW!
|
||||
boolean existing = ChannelDataAccessor.hasSubChannel(trigger, key.getText());
|
||||
getButtonList().get(0).displayString = existing
|
||||
? I18n.format("item.structurelib.constructableTrigger.gui.set")
|
||||
String keyText = key.getText();
|
||||
boolean existing = !StringUtils.isEmpty(keyText) && ChannelDataAccessor.hasSubChannel(trigger, keyText);
|
||||
getButtonList().get(0).displayString = existing ? I18n.format("item.structurelib.constructableTrigger.gui.set")
|
||||
: I18n.format("item.structurelib.constructableTrigger.gui.add");
|
||||
getButtonList().get(0).enabled = !StringUtils.isBlank(value.getText());
|
||||
getButtonList().get(1).enabled = existing && !StringUtils.isBlank(value.getText());
|
||||
@@ -299,14 +311,21 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen
|
||||
super.drawScreen(mX, mY, partialTick);
|
||||
list.drawScreen(mX, mY, partialTick);
|
||||
fontRendererObj.drawString(
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.key"), guiLeft + 12, guiTop + 122, 0);
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.key"),
|
||||
guiLeft + 12,
|
||||
guiTop + 122,
|
||||
0);
|
||||
key.drawTextBox();
|
||||
fontRendererObj.drawString(
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.value"), guiLeft + 12, guiTop + 142, 0);
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.value"),
|
||||
guiLeft + 12,
|
||||
guiTop + 142,
|
||||
0);
|
||||
value.drawTextBox();
|
||||
}
|
||||
|
||||
private class GuiChannelsList extends GuiScrollableList<Entry<String, Integer>> {
|
||||
|
||||
private List<Entry<String, Integer>> cache;
|
||||
|
||||
public GuiChannelsList(int width, int height, int originX, int originY, int slotHeight) {
|
||||
@@ -315,11 +334,7 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen
|
||||
|
||||
@Override
|
||||
public Entry<String, Integer> getElementAt(int index) {
|
||||
return ChannelDataAccessor.iterateChannelData(trigger)
|
||||
.sorted()
|
||||
.skip(index)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
return ChannelDataAccessor.iterateChannelData(trigger).sorted().skip(index).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -329,8 +344,7 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen
|
||||
|
||||
@Override
|
||||
protected boolean elementClicked(int elementIndex, boolean doubleClick, int mXRelative, int mYRelative) {
|
||||
if (mXRelative >= margin + 1
|
||||
&& mXRelative <= margin + 5
|
||||
if (mXRelative >= margin + 1 && mXRelative <= margin + 5
|
||||
&& mYRelative >= margin / 2 + 1
|
||||
&& mYRelative <= margin / 2 + 5) {
|
||||
Entry<String, Integer> e = getElementAt(elementIndex);
|
||||
@@ -348,8 +362,8 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawElement(
|
||||
int elementIndex, int x, int y, int height, Tessellator tessellator, boolean isHovering) {
|
||||
protected void drawElement(int elementIndex, int x, int y, int height, Tessellator tessellator,
|
||||
boolean isHovering) {
|
||||
if (elementIndex < 0 || elementIndex >= cache.size()) {
|
||||
return;
|
||||
}
|
||||
@@ -381,8 +395,7 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen
|
||||
// TODO optimize this to not create a billion string, or maybe cache this
|
||||
String s = fontRendererObj.trimStringToWidth(e, keyMaxWidth);
|
||||
if (s.length() != e.length()) {
|
||||
StringBuilder buffer =
|
||||
new StringBuilder(s).deleteCharAt(s.length() - 1).append("...");
|
||||
StringBuilder buffer = new StringBuilder(s).deleteCharAt(s.length() - 1).append("...");
|
||||
while ((s = fontRendererObj.trimStringToWidth(buffer.toString(), keyMaxWidth)).length()
|
||||
!= buffer.length())
|
||||
// drop last original char
|
||||
@@ -390,9 +403,7 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen
|
||||
do {
|
||||
buffer.append('.');
|
||||
} while (fontRendererObj.getStringWidth(buffer.toString()) <= keyMaxWidth);
|
||||
s = buffer.deleteCharAt(s.length() - 1)
|
||||
.insert(s.length() - 3, EnumChatFormatting.GRAY)
|
||||
.toString();
|
||||
s = buffer.deleteCharAt(s.length() - 1).insert(s.length() - 3, EnumChatFormatting.GRAY).toString();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -2,37 +2,40 @@ package com.gtnewhorizon.structurelib.gui;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
/**
|
||||
* Shamelessly stolen from EnderCore, with some amount of edit to fit in one file. Original code from CrazyPants.
|
||||
* <p>
|
||||
* As the code has been released into public domain, it is now LGPL as part of this library as a whole.
|
||||
* You can go to EnderCore's repository to obtain a public domain copy though
|
||||
* As the code has been released into public domain, it is now LGPL as part of this library as a whole. You can go to
|
||||
* EnderCore's repository to obtain a public domain copy though
|
||||
*
|
||||
* Major edits
|
||||
* <ul>
|
||||
* <li>Separate dwheel handling to handleDWheel. The next event calls often cause the mouse click event to
|
||||
* not fire on other widgets</li>
|
||||
* <li>scrollbar are now rendered within width</li>
|
||||
* <li>added prepareDrawElements</li>
|
||||
* <li>Separate dwheel handling to handleDWheel. The next event calls often cause the mouse click event to not fire on
|
||||
* other widgets</li>
|
||||
* <li>scrollbar are now rendered within width</li>
|
||||
* <li>added prepareDrawElements</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author CrazyPants
|
||||
* @author glee8e
|
||||
*/
|
||||
public abstract class GuiScrollableList<T> {
|
||||
|
||||
protected final int slotHeight;
|
||||
private final Minecraft mc = Minecraft.getMinecraft();
|
||||
protected int originX;
|
||||
protected int originY;
|
||||
protected int width;
|
||||
protected int height;
|
||||
protected final int originX;
|
||||
protected final int originY;
|
||||
protected final int width;
|
||||
protected final int height;
|
||||
protected int minY;
|
||||
protected int maxY;
|
||||
protected int minX;
|
||||
@@ -41,7 +44,7 @@ public abstract class GuiScrollableList<T> {
|
||||
protected int mouseY;
|
||||
protected int selectedIndex = -1;
|
||||
protected int margin = 4;
|
||||
protected List<ListSelectionListener<T>> listeners = new CopyOnWriteArrayList<>();
|
||||
protected final List<ListSelectionListener<T>> listeners = new CopyOnWriteArrayList<>();
|
||||
private int scrollUpButtonID;
|
||||
private int scrollDownButtonID;
|
||||
private float initialClickY = -2.0F;
|
||||
@@ -113,8 +116,8 @@ public abstract class GuiScrollableList<T> {
|
||||
|
||||
public abstract int getNumElements();
|
||||
|
||||
protected abstract void drawElement(
|
||||
int elementIndex, int x, int y, int height, Tessellator tessellator, boolean isHovering);
|
||||
protected abstract void drawElement(int elementIndex, int x, int y, int height, Tessellator tessellator,
|
||||
boolean isHovering);
|
||||
|
||||
protected boolean elementClicked(int elementIndex, boolean doubleClick, int mXRelative, int mYRelative) {
|
||||
return true;
|
||||
@@ -153,11 +156,11 @@ public abstract class GuiScrollableList<T> {
|
||||
public void actionPerformed(GuiButton b) {
|
||||
if (b.enabled) {
|
||||
if (b.id == scrollUpButtonID) {
|
||||
amountScrolled -= slotHeight * 2 / 3;
|
||||
amountScrolled -= slotHeight * 2f / 3;
|
||||
initialClickY = -2.0F;
|
||||
clampScrollToBounds();
|
||||
} else if (b.id == scrollDownButtonID) {
|
||||
amountScrolled += slotHeight * 2 / 3;
|
||||
amountScrolled += slotHeight * 2f / 3;
|
||||
initialClickY = -2.0F;
|
||||
clampScrollToBounds();
|
||||
}
|
||||
@@ -165,8 +168,7 @@ public abstract class GuiScrollableList<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* draws the slot to the screen, pass in mouse's current x and y and partial
|
||||
* ticks
|
||||
* draws the slot to the screen, pass in mouse's current x and y and partial ticks
|
||||
*/
|
||||
public void drawScreen(int mX, int mY, float partialTick) {
|
||||
this.mouseX = mX;
|
||||
@@ -325,9 +327,9 @@ public abstract class GuiScrollableList<T> {
|
||||
public void handleDWheel(int mouseWheelDelta) {
|
||||
if (!Mouse.isButtonDown(0)) {
|
||||
if (mouseWheelDelta > 0) {
|
||||
amountScrolled -= slotHeight / 2;
|
||||
amountScrolled -= slotHeight / 2f;
|
||||
} else /* if (mouseWheelDelta < 0) */ {
|
||||
amountScrolled += slotHeight / 2;
|
||||
amountScrolled += slotHeight / 2f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -343,15 +345,17 @@ public abstract class GuiScrollableList<T> {
|
||||
int y = mouseY - minY + (int) amountScrolled - margin;
|
||||
int mouseOverElement = y / slotHeight;
|
||||
|
||||
if (mouseX >= minX
|
||||
&& mouseX <= maxX
|
||||
if (mouseX >= minX && mouseX <= maxX
|
||||
&& mouseOverElement >= 0
|
||||
&& y >= 0
|
||||
&& mouseOverElement < getNumElements()) {
|
||||
boolean doubleClick =
|
||||
mouseOverElement == selectedIndex && Minecraft.getSystemTime() - lastClickedTime < 250L;
|
||||
boolean doubleClick = mouseOverElement == selectedIndex
|
||||
&& Minecraft.getSystemTime() - lastClickedTime < 250L;
|
||||
if (elementClicked(
|
||||
mouseOverElement, doubleClick, mouseX - minX, y - slotHeight * mouseOverElement)) {
|
||||
mouseOverElement,
|
||||
doubleClick,
|
||||
mouseX - minX,
|
||||
y - slotHeight * mouseOverElement)) {
|
||||
setSelection(mouseOverElement);
|
||||
lastClickedTime = Minecraft.getSystemTime();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.gtnewhorizon.structurelib.item;
|
||||
import static net.minecraft.util.StatCollector.translateToLocal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
@@ -11,6 +12,7 @@ import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
public class ItemBlockHint extends ItemBlock {
|
||||
|
||||
public ItemBlockHint(Block p_i45328_1_) {
|
||||
super(p_i45328_1_);
|
||||
setMaxDamage(0);
|
||||
@@ -35,33 +37,35 @@ public class ItemBlockHint extends ItemBlock {
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
aList.add(EnumChatFormatting.AQUA.toString()
|
||||
+ EnumChatFormatting.BOLD
|
||||
+ translateToLocal("structurelib.blockhint.desc.1")); // Placeholder for a certain group.
|
||||
aList.add(
|
||||
EnumChatFormatting.AQUA.toString() + EnumChatFormatting.BOLD
|
||||
+ translateToLocal("structurelib.blockhint.desc.1")); // Placeholder for a certain
|
||||
// group.
|
||||
break;
|
||||
case 12:
|
||||
aList.add(EnumChatFormatting.AQUA.toString()
|
||||
+ EnumChatFormatting.BOLD
|
||||
+ translateToLocal("structurelib.blockhint.desc.2")); // General placeholder.
|
||||
aList.add(
|
||||
EnumChatFormatting.AQUA.toString() + EnumChatFormatting.BOLD
|
||||
+ translateToLocal("structurelib.blockhint.desc.2")); // General placeholder.
|
||||
break;
|
||||
case 13:
|
||||
aList.add(EnumChatFormatting.AQUA.toString()
|
||||
+ EnumChatFormatting.BOLD
|
||||
+ translateToLocal("structurelib.blockhint.desc.3")); // Make sure it contains Air material.
|
||||
aList.add(
|
||||
EnumChatFormatting.AQUA.toString() + EnumChatFormatting.BOLD
|
||||
+ translateToLocal("structurelib.blockhint.desc.3")); // Make sure it contains Air
|
||||
// material.
|
||||
break;
|
||||
case 14:
|
||||
aList.add(EnumChatFormatting.AQUA.toString()
|
||||
+ EnumChatFormatting.BOLD
|
||||
+ translateToLocal(
|
||||
"structurelib.blockhint.desc.4")); // Make sure it does not contain Air material.
|
||||
aList.add(
|
||||
EnumChatFormatting.AQUA.toString() + EnumChatFormatting.BOLD
|
||||
+ translateToLocal("structurelib.blockhint.desc.4")); // Make sure it does not contain
|
||||
// Air material.
|
||||
break;
|
||||
case 15:
|
||||
aList.add(EnumChatFormatting.BLUE.toString()
|
||||
+ translateToLocal("structurelib.blockhint.desc.5")); // ERROR, what did u expect?
|
||||
aList.add(EnumChatFormatting.BLUE + translateToLocal("structurelib.blockhint.desc.5")); // ERROR, what
|
||||
// did u expect?
|
||||
break;
|
||||
default: // WTF?
|
||||
aList.add("Damn son where did you get that!?");
|
||||
aList.add(EnumChatFormatting.BLUE.toString() + "From outer space... I guess...");
|
||||
aList.add(EnumChatFormatting.BLUE + "From outer space... I guess...");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,17 +5,21 @@ import static net.minecraft.util.EnumChatFormatting.BLUE;
|
||||
import static net.minecraft.util.StatCollector.translateToLocal;
|
||||
import static net.minecraft.util.StatCollector.translateToLocalFormatted;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ConstructableUtility;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ConstructableUtility;
|
||||
|
||||
public class ItemConstructableTrigger extends Item {
|
||||
|
||||
public ItemConstructableTrigger() {
|
||||
setUnlocalizedName("structurelib.constructableTrigger");
|
||||
setTextureName(MOD_ID + ":itemConstructableTrigger");
|
||||
@@ -30,17 +34,8 @@ public class ItemConstructableTrigger extends Item {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemUseFirst(
|
||||
ItemStack stack,
|
||||
EntityPlayer player,
|
||||
World world,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
int side,
|
||||
float hitX,
|
||||
float hitY,
|
||||
float hitZ) {
|
||||
public boolean onItemUseFirst(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side,
|
||||
float hitX, float hitY, float hitZ) {
|
||||
return ConstructableUtility.handle(stack, player, world, x, y, z, side);
|
||||
}
|
||||
|
||||
@@ -48,27 +43,25 @@ public class ItemConstructableTrigger extends Item {
|
||||
@Override
|
||||
public void addInformation(ItemStack aStack, EntityPlayer ep, List aList, boolean boo) {
|
||||
if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
|
||||
aList.add(translateToLocalFormatted(
|
||||
"item.structurelib.constructableTrigger.desc.lshift.0",
|
||||
ChannelDataAccessor.countChannelData(aStack)));
|
||||
ChannelDataAccessor.iterateChannelData(aStack)
|
||||
.map(e -> e.getKey() + ": " + e.getValue())
|
||||
aList.add(
|
||||
translateToLocalFormatted(
|
||||
"item.structurelib.constructableTrigger.desc.lshift.0",
|
||||
ChannelDataAccessor.countChannelData(aStack)));
|
||||
ChannelDataAccessor.iterateChannelData(aStack).map(e -> e.getKey() + ": " + e.getValue())
|
||||
.forEach(aList::add);
|
||||
} else {
|
||||
aList.add(translateToLocal(
|
||||
"item.structurelib.constructableTrigger.desc.0")); // Triggers Constructable Interface
|
||||
aList.add(BLUE
|
||||
+ translateToLocal(
|
||||
"item.structurelib.constructableTrigger.desc.1")); // Shows multiblock construction details,
|
||||
aList.add(BLUE
|
||||
+ translateToLocal(
|
||||
"item.structurelib.constructableTrigger.desc.2")); // just Use on a multiblock controller.
|
||||
aList.add(BLUE
|
||||
+ translateToLocal(
|
||||
"item.structurelib.constructableTrigger.desc.3")); // (Sneak Use in creative to build)
|
||||
aList.add(BLUE
|
||||
+ translateToLocal(
|
||||
"item.structurelib.constructableTrigger.desc.4")); // Quantity affects tier/mode/type
|
||||
aList.add(translateToLocal("item.structurelib.constructableTrigger.desc.0")); // Triggers Constructable
|
||||
// Interface
|
||||
aList.add(BLUE + translateToLocal("item.structurelib.constructableTrigger.desc.1")); // Shows multiblock
|
||||
// construction
|
||||
// details,
|
||||
aList.add(BLUE + translateToLocal("item.structurelib.constructableTrigger.desc.2")); // just Use on a
|
||||
// multiblock
|
||||
// controller.
|
||||
aList.add(BLUE + translateToLocal("item.structurelib.constructableTrigger.desc.3")); // (Sneak Use in
|
||||
// creative to build)
|
||||
aList.add(BLUE + translateToLocal("item.structurelib.constructableTrigger.desc.4")); // Quantity affects
|
||||
// tier/mode/type
|
||||
if (ChannelDataAccessor.hasSubChannel(aStack))
|
||||
aList.add(translateToLocal("item.structurelib.constructableTrigger.desc.5"));
|
||||
}
|
||||
|
||||
@@ -3,18 +3,22 @@ package com.gtnewhorizon.structurelib.item;
|
||||
import static com.gtnewhorizon.structurelib.StructureLibAPI.MOD_ID;
|
||||
import static net.minecraft.util.StatCollector.translateToLocal;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.alignment.AlignmentUtility;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.alignment.AlignmentUtility;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class ItemFrontRotationTool extends Item {
|
||||
|
||||
public ItemFrontRotationTool() {
|
||||
setMaxStackSize(1);
|
||||
setUnlocalizedName("structurelib.frontRotationTool");
|
||||
@@ -23,17 +27,8 @@ public class ItemFrontRotationTool extends Item {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemUseFirst(
|
||||
ItemStack stack,
|
||||
EntityPlayer player,
|
||||
World world,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
int side,
|
||||
float hitX,
|
||||
float hitY,
|
||||
float hitZ) {
|
||||
public boolean onItemUseFirst(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side,
|
||||
float hitX, float hitY, float hitZ) {
|
||||
return AlignmentUtility.handle(player, world, x, y, z);
|
||||
}
|
||||
|
||||
@@ -41,9 +36,13 @@ public class ItemFrontRotationTool extends Item {
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void addInformation(ItemStack p_77624_1_, EntityPlayer p_77624_2_, List aList, boolean p_77624_4_) {
|
||||
aList.add(translateToLocal("item.structurelib.frontRotationTool.desc.0")); // Triggers Front Rotation Interface
|
||||
aList.add(EnumChatFormatting.BLUE
|
||||
+ translateToLocal("item.structurelib.frontRotationTool.desc.1")); // Rotates only the front panel,
|
||||
aList.add(EnumChatFormatting.BLUE
|
||||
+ translateToLocal("item.structurelib.frontRotationTool.desc.2")); // which allows structure rotation.
|
||||
aList.add(EnumChatFormatting.BLUE + translateToLocal("item.structurelib.frontRotationTool.desc.1")); // Rotates
|
||||
// only the
|
||||
// front
|
||||
// panel,
|
||||
aList.add(EnumChatFormatting.BLUE + translateToLocal("item.structurelib.frontRotationTool.desc.2")); // which
|
||||
// allows
|
||||
// structure
|
||||
// rotation.
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,23 @@
|
||||
package com.gtnewhorizon.structurelib.net;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.alignment.IAlignment;
|
||||
import com.gtnewhorizon.structurelib.alignment.IAlignmentProvider;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import cpw.mods.fml.common.network.ByteBufUtils;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.alignment.IAlignment;
|
||||
import com.gtnewhorizon.structurelib.alignment.IAlignmentProvider;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
|
||||
import cpw.mods.fml.common.network.ByteBufUtils;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public abstract class AlignmentMessage implements IMessage {
|
||||
|
||||
int mPosX;
|
||||
int mPosY;
|
||||
int mPosZ;
|
||||
@@ -45,10 +48,6 @@ public abstract class AlignmentMessage implements IMessage {
|
||||
ByteBufUtils.writeTag(pBuffer, tFXTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition#check(Object, String, World, ExtendedFacing, int, int, int, int, int, int, boolean)}
|
||||
* @param provider
|
||||
*/
|
||||
private AlignmentMessage(IAlignmentProvider provider) {
|
||||
if (!(provider instanceof TileEntity)) throw new IllegalArgumentException("Provider must be a TileEntity");
|
||||
IAlignment alignment = provider.getAlignment();
|
||||
@@ -70,6 +69,7 @@ public abstract class AlignmentMessage implements IMessage {
|
||||
}
|
||||
|
||||
public static class AlignmentQuery extends AlignmentMessage {
|
||||
|
||||
public AlignmentQuery() {}
|
||||
|
||||
public AlignmentQuery(IAlignmentProvider provider) {
|
||||
@@ -82,6 +82,7 @@ public abstract class AlignmentMessage implements IMessage {
|
||||
}
|
||||
|
||||
public static class AlignmentData extends AlignmentMessage {
|
||||
|
||||
public AlignmentData() {}
|
||||
|
||||
private AlignmentData(AlignmentQuery query) {
|
||||
@@ -102,11 +103,11 @@ public abstract class AlignmentMessage implements IMessage {
|
||||
}
|
||||
|
||||
public static class ClientHandler implements IMessageHandler<AlignmentData, IMessage> {
|
||||
|
||||
@Override
|
||||
public IMessage onMessage(AlignmentData pMessage, MessageContext pCtx) {
|
||||
if (StructureLib.getCurrentPlayer().worldObj.provider.dimensionId == pMessage.mPosD) {
|
||||
TileEntity te = StructureLib.getCurrentPlayer()
|
||||
.worldObj
|
||||
TileEntity te = StructureLib.getCurrentPlayer().worldObj
|
||||
.getTileEntity(pMessage.mPosX, pMessage.mPosY, pMessage.mPosZ);
|
||||
if (te instanceof IAlignmentProvider) {
|
||||
IAlignment alignment = ((IAlignmentProvider) te).getAlignment();
|
||||
@@ -120,6 +121,7 @@ public abstract class AlignmentMessage implements IMessage {
|
||||
}
|
||||
|
||||
public static class ServerHandler implements IMessageHandler<AlignmentQuery, AlignmentData> {
|
||||
|
||||
@Override
|
||||
public AlignmentData onMessage(AlignmentQuery pMessage, MessageContext pCtx) {
|
||||
World world = DimensionManager.getWorld(pMessage.mPosD);
|
||||
|
||||
@@ -4,12 +4,14 @@ import static com.gtnewhorizon.structurelib.StructureLib.LOGGER;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class ErrorHintParticleMessage implements IMessage {
|
||||
|
||||
private int x;
|
||||
private short y;
|
||||
private int z;
|
||||
@@ -37,17 +39,21 @@ public class ErrorHintParticleMessage implements IMessage {
|
||||
}
|
||||
|
||||
public static class Handler implements IMessageHandler<ErrorHintParticleMessage, IMessage> {
|
||||
|
||||
@Override
|
||||
public IMessage onMessage(ErrorHintParticleMessage msg, MessageContext ctx) {
|
||||
boolean updateResult = StructureLibAPI.markHintParticleError(
|
||||
StructureLib.getCurrentPlayer(), StructureLib.getCurrentPlayer().worldObj, msg.x, msg.y, msg.z);
|
||||
if (StructureLibAPI.isDebugEnabled())
|
||||
LOGGER.debug(
|
||||
"Server instructed to mark hint particle at ({}, {}, {}) error, result {}!",
|
||||
msg.x,
|
||||
msg.y,
|
||||
msg.z,
|
||||
updateResult);
|
||||
StructureLib.getCurrentPlayer(),
|
||||
StructureLib.getCurrentPlayer().worldObj,
|
||||
msg.x,
|
||||
msg.y,
|
||||
msg.z);
|
||||
if (StructureLibAPI.isDebugEnabled()) LOGGER.debug(
|
||||
"Server instructed to mark hint particle at ({}, {}, {}) error, result {}!",
|
||||
msg.x,
|
||||
msg.y,
|
||||
msg.z,
|
||||
updateResult);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
package com.gtnewhorizon.structurelib.net;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
|
||||
import com.gtnewhorizon.structurelib.item.ItemConstructableTrigger;
|
||||
|
||||
import cpw.mods.fml.common.network.ByteBufUtils;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
public class SetChannelDataMessage implements IMessage {
|
||||
private List<Map.Entry<String, Integer>> data = new ArrayList<>();
|
||||
|
||||
private final List<Map.Entry<String, Integer>> data = new ArrayList<>();
|
||||
|
||||
public SetChannelDataMessage() {}
|
||||
|
||||
@@ -44,6 +49,7 @@ public class SetChannelDataMessage implements IMessage {
|
||||
}
|
||||
|
||||
public static class Handler implements IMessageHandler<SetChannelDataMessage, IMessage> {
|
||||
|
||||
@Override
|
||||
public IMessage onMessage(SetChannelDataMessage message, MessageContext ctx) {
|
||||
EntityPlayerMP player = ctx.getServerHandler().playerEntity;
|
||||
|
||||
@@ -4,12 +4,14 @@ import static com.gtnewhorizon.structurelib.StructureLib.LOGGER;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class UpdateHintParticleMessage implements IMessage {
|
||||
|
||||
private int x;
|
||||
private short y;
|
||||
private int z;
|
||||
@@ -53,6 +55,7 @@ public class UpdateHintParticleMessage implements IMessage {
|
||||
}
|
||||
|
||||
public static class Handler implements IMessageHandler<UpdateHintParticleMessage, IMessage> {
|
||||
|
||||
@Override
|
||||
public IMessage onMessage(UpdateHintParticleMessage msg, MessageContext ctx) {
|
||||
boolean updateResult = StructureLibAPI.updateHintParticleTint(
|
||||
@@ -61,16 +64,13 @@ public class UpdateHintParticleMessage implements IMessage {
|
||||
msg.x,
|
||||
msg.y,
|
||||
msg.z,
|
||||
new short[] {
|
||||
msg.r, msg.g, msg.b, msg.a,
|
||||
});
|
||||
if (StructureLibAPI.isDebugEnabled())
|
||||
LOGGER.debug(
|
||||
"Server instructed to update hint particle at ({}, {}, {}), result {}!",
|
||||
msg.x,
|
||||
msg.y,
|
||||
msg.z,
|
||||
updateResult);
|
||||
new short[] { msg.r, msg.g, msg.b, msg.a, });
|
||||
if (StructureLibAPI.isDebugEnabled()) LOGGER.debug(
|
||||
"Server instructed to update hint particle at ({}, {}, {}), result {}!",
|
||||
msg.x,
|
||||
msg.y,
|
||||
msg.z,
|
||||
updateResult);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
|
||||
/**
|
||||
* Represent the environment in which autoplace of a single element took place.
|
||||
*/
|
||||
public class AutoPlaceEnvironment {
|
||||
|
||||
private IItemSource source;
|
||||
private final EntityPlayer actor;
|
||||
private final Consumer<IChatComponent> chatter;
|
||||
private final IStructureDefinition<?> definition;
|
||||
private final String piece;
|
||||
private final ExtendedFacing facing;
|
||||
final int[] offsetABC;
|
||||
private final int[] baseOffsetABC;
|
||||
|
||||
public static AutoPlaceEnvironment fromLegacy(IItemSource source, EntityPlayer actor,
|
||||
Consumer<IChatComponent> chatter) {
|
||||
if (source instanceof WrappedIItemSource) {
|
||||
AutoPlaceEnvironment original = ((WrappedIItemSource) source).container;
|
||||
// feels like this is extremely likely to cause issues, but this does allow us to recover lost info.
|
||||
// TODO probably should remove this once all addons migrate over
|
||||
if (actor != original.actor || chatter != original.chatter) {
|
||||
AutoPlaceEnvironment newEnv = original;
|
||||
if (actor != original.actor) newEnv = newEnv.withActor(actor);
|
||||
if (chatter != original.chatter) newEnv = newEnv.withChatter(chatter);
|
||||
return newEnv;
|
||||
}
|
||||
return original;
|
||||
}
|
||||
return new AutoPlaceEnvironment(source, actor, chatter, null, null, null, null, null);
|
||||
}
|
||||
|
||||
AutoPlaceEnvironment(EntityPlayer actor, Consumer<IChatComponent> chatter, IStructureDefinition<?> definition,
|
||||
String piece, ExtendedFacing facing, int[] baseOffsetABC) {
|
||||
this.source = null;
|
||||
this.actor = actor;
|
||||
this.chatter = chatter;
|
||||
this.definition = definition;
|
||||
this.piece = piece;
|
||||
this.facing = facing;
|
||||
this.offsetABC = new int[3];
|
||||
this.baseOffsetABC = baseOffsetABC;
|
||||
}
|
||||
|
||||
AutoPlaceEnvironment(IItemSource source, EntityPlayer actor, Consumer<IChatComponent> chatter,
|
||||
IStructureDefinition<?> definition, String piece, ExtendedFacing facing, int[] offsetABC,
|
||||
int[] baseOffsetABC) {
|
||||
this.source = definition != null && !(source instanceof WrappedIItemSource)
|
||||
? new WrappedIItemSource(this, source)
|
||||
: source;
|
||||
this.actor = actor;
|
||||
this.chatter = chatter;
|
||||
this.definition = definition;
|
||||
this.piece = piece;
|
||||
this.facing = facing;
|
||||
this.offsetABC = offsetABC;
|
||||
this.baseOffsetABC = baseOffsetABC;
|
||||
}
|
||||
|
||||
protected AutoPlaceEnvironment(AutoPlaceEnvironment parent) {
|
||||
this(
|
||||
parent.getSource(),
|
||||
parent.getActor(),
|
||||
parent.getChatter(),
|
||||
parent.definition,
|
||||
parent.piece,
|
||||
parent.facing,
|
||||
parent.offsetABC,
|
||||
parent.baseOffsetABC);
|
||||
}
|
||||
|
||||
void setSource(IItemSource source) {
|
||||
this.source = definition != null && !(source instanceof WrappedIItemSource)
|
||||
? new WrappedIItemSource(this, source)
|
||||
: source;
|
||||
}
|
||||
|
||||
public APILevel getAPILevel() {
|
||||
return definition == null ? actor instanceof EntityPlayerMP ? APILevel.Legacy : APILevel.LegacyRelaxed
|
||||
: APILevel.V2;
|
||||
}
|
||||
|
||||
/**
|
||||
* From where survival autoplace will drain resources.
|
||||
*/
|
||||
public IItemSource getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* The initiator of actions. for very critical errors you can also just send the error messages here, bypassing any
|
||||
* filter that {@link #getChatter()} might have. You might want to use
|
||||
* {@link com.gtnewhorizon.structurelib.StructureLibAPI#addThrottledChat(Object, EntityPlayer, IChatComponent, short)}
|
||||
* to help reduce spam.
|
||||
*/
|
||||
public EntityPlayer getActor() {
|
||||
return actor;
|
||||
}
|
||||
|
||||
/**
|
||||
* send error messages here. Caller will choose an appropriate way to forward it to player if the other fallbacks
|
||||
* also fails.
|
||||
*/
|
||||
public Consumer<IChatComponent> getChatter() {
|
||||
return chatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if given location is contained within the current piece.
|
||||
*
|
||||
* @param offsetA offset in A direction <b>relative to current element</b>
|
||||
* @param offsetB offset in B direction <b>relative to current element</b>
|
||||
* @param offsetC offset in C direction <b>relative to current element</b>
|
||||
* @return true if contained, false otherwise.
|
||||
*/
|
||||
public boolean isContainedInPiece(int offsetA, int offsetB, int offsetC) {
|
||||
if (definition == null) return false;
|
||||
return definition.isContainedInStructure(
|
||||
piece,
|
||||
offsetABC[0] + offsetA + baseOffsetABC[0],
|
||||
offsetABC[1] + offsetB + baseOffsetABC[1],
|
||||
offsetABC[2] + offsetC + baseOffsetABC[2]);
|
||||
}
|
||||
|
||||
public ExtendedFacing getFacing() {
|
||||
return facing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new instance with source modified to given value.
|
||||
*
|
||||
* @param source new source
|
||||
* @return new instance
|
||||
*/
|
||||
public AutoPlaceEnvironment withSource(IItemSource source) {
|
||||
return new AutoPlaceEnvironment(source, actor, chatter, definition, piece, facing, offsetABC, baseOffsetABC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new instance with actor modified to given value.
|
||||
*
|
||||
* @param actor new actor
|
||||
* @return new instance
|
||||
*/
|
||||
public AutoPlaceEnvironment withActor(EntityPlayer actor) {
|
||||
return new AutoPlaceEnvironment(source, actor, chatter, definition, piece, facing, offsetABC, baseOffsetABC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new instance with chatter modified to given value.
|
||||
*
|
||||
* @param chatter new chatter
|
||||
* @return new instance
|
||||
*/
|
||||
public AutoPlaceEnvironment withChatter(Consumer<IChatComponent> chatter) {
|
||||
return new AutoPlaceEnvironment(source, actor, chatter, definition, piece, facing, offsetABC, baseOffsetABC);
|
||||
}
|
||||
|
||||
private static class WrappedIItemSource implements IItemSource {
|
||||
|
||||
final AutoPlaceEnvironment container;
|
||||
final IItemSource delegate;
|
||||
|
||||
public WrappedIItemSource(AutoPlaceEnvironment container, IItemSource delegate) {
|
||||
this.container = container;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public Map<ItemStack, Integer> take(Predicate<ItemStack> predicate, boolean simulate, int count) {
|
||||
return delegate.take(predicate, simulate, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack takeOne(Predicate<ItemStack> predicate, boolean simulate) {
|
||||
return delegate.takeOne(predicate, simulate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean takeAll(Predicate<ItemStack> predicate, boolean simulate, int count) {
|
||||
return delegate.takeAll(predicate, simulate, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean takeOne(ItemStack stack, boolean simulate) {
|
||||
return delegate.takeOne(stack, simulate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean takeAll(ItemStack stack, boolean simulate) {
|
||||
return delegate.takeAll(stack, simulate);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the various API level an {@link AutoPlaceEnvironment} has implemented.
|
||||
* <p>
|
||||
* Enum constants are defined in chronological order.
|
||||
*/
|
||||
public enum APILevel {
|
||||
/**
|
||||
* Implements {@link #getChatter()}, {@link #getActor()} and {@link #getSource()}. {@link #getActor()} is
|
||||
* guaranteed to be an {@link net.minecraft.entity.player.EntityPlayerMP}
|
||||
*/
|
||||
Legacy,
|
||||
/**
|
||||
* Implements {@link #getChatter()}, {@link #getActor()} and {@link #getSource()}. {@link #getActor()} is
|
||||
* <b>NOT</b> guaranteed to be an {@link net.minecraft.entity.player.EntityPlayerMP}
|
||||
*/
|
||||
LegacyRelaxed,
|
||||
/**
|
||||
* Implements everything so far we have defined.
|
||||
*/
|
||||
V2,
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
class ChatThrottleKey {
|
||||
|
||||
static class NoExplicitChannel {
|
||||
|
||||
private static final int hashOffset = NoExplicitChannel.class.hashCode();
|
||||
private final String subchannel;
|
||||
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
|
||||
class DefaultSurvivalBuildEnvironment implements ISurvivalBuildEnvironment {
|
||||
|
||||
private final IItemSource source;
|
||||
private final EntityPlayer actor;
|
||||
|
||||
public DefaultSurvivalBuildEnvironment(IItemSource source, EntityPlayer actor) {
|
||||
this.source = source;
|
||||
this.actor = actor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemSource getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPlayer getActor() {
|
||||
return actor;
|
||||
}
|
||||
}
|
||||
@@ -3,5 +3,6 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface IBlockPosConsumer {
|
||||
|
||||
void consume(World world, int x, int y, int z);
|
||||
}
|
||||
@@ -4,9 +4,10 @@ import net.minecraft.block.Block;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface ICustomBlockSetting {
|
||||
|
||||
/**
|
||||
* Default block setting calls {@link World#setBlock(int x, int y, int z, Block block, int meta, int updateType)} like:
|
||||
* {@code world.setBlock(x,y,z,this/block,meta,2)} where updateType 2 means to update lighting and stuff
|
||||
* Default block setting calls {@link World#setBlock(int x, int y, int z, Block block, int meta, int updateType)}
|
||||
* like: {@code world.setBlock(x,y,z,this/block,meta,2)} where updateType 2 means to update lighting and stuff
|
||||
*
|
||||
* @param world world that should be affected
|
||||
* @param x x position to set
|
||||
|
||||
@@ -1,29 +1,61 @@
|
||||
package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import com.gtnewhorizon.structurelib.util.InventoryIterable;
|
||||
import com.gtnewhorizon.structurelib.util.InventoryUtility;
|
||||
import com.gtnewhorizon.structurelib.util.ItemStackPredicate;
|
||||
import com.gtnewhorizon.structurelib.util.ItemStackPredicate.NBTMode;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import javax.annotation.Nonnull;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
/**
|
||||
* Represent an item source. Take only, cannot be placed back.
|
||||
*/
|
||||
public interface IItemSource {
|
||||
|
||||
/**
|
||||
* We are probably not going to need to get a lot of items from this method
|
||||
* so I don't care about the overhead of storing all fetched items even if downstream code doesn't need it
|
||||
* Retrieve some amount of items from this item source matching given filter.
|
||||
* <p>
|
||||
* We probably don't need to get a lot of items from this method, so I don't care about the overhead of storing all
|
||||
* fetched items even if downstream code doesn't need it
|
||||
*
|
||||
* @param predicate filtering predicate. should return true for ItemStacks that should be added to result collection
|
||||
* @param simulate whether to actually commit the modification. true for dry run, false otherwise.
|
||||
* @param count how many items to extract.
|
||||
* @return A nonnull map reflecting the result of extraction. Note this map is NBT and metadata aware.
|
||||
*/
|
||||
@Nonnull
|
||||
Map<ItemStack, Integer> take(Predicate<ItemStack> predicate, boolean simulate, int count);
|
||||
|
||||
/**
|
||||
* Take exactly one item that matches the predicate.
|
||||
*
|
||||
* @param predicate filtering predicate. should return true for ItemStacks that should be added to result collection
|
||||
* @param simulate whether to actually commit the modification. true for dry run, false otherwise.
|
||||
* @return item stack, or null if none matches
|
||||
* @throws IllegalArgumentException if given predicate is null.
|
||||
*/
|
||||
default ItemStack takeOne(Predicate<ItemStack> predicate, boolean simulate) {
|
||||
if (predicate == null) throw new IllegalArgumentException();
|
||||
Map<ItemStack, Integer> take = take(predicate, simulate, 1);
|
||||
return take.isEmpty() ? null : take.keySet().iterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Take exactly count amount of items matching predicate.
|
||||
*
|
||||
* @param predicate filtering predicate. should return true for ItemStacks that should be added to result collection
|
||||
* @param simulate whether to actually commit the modification. true for dry run, false otherwise.
|
||||
* @param count how many items to extract.
|
||||
* @return true if at least count amount of items can be/is taken.
|
||||
* @throws IllegalArgumentException if given predicate is null
|
||||
*/
|
||||
default boolean takeAll(Predicate<ItemStack> predicate, boolean simulate, int count) {
|
||||
// fast path for 1 item take requests
|
||||
if (count == 1) return takeOne(predicate, simulate) != null;
|
||||
@@ -33,24 +65,56 @@ public interface IItemSource {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take exactly one item. ItemStack given must have a stack size of 1.
|
||||
* <p>
|
||||
* This is meant to be an optimized version of {@link #takeOne(Predicate, boolean)}. Implementations that support
|
||||
* item storage indexed by ItemStack can use this to speed up calculation.
|
||||
*
|
||||
* @param stack what item to extract. The NBT tag of this ItemStack is siginifcant and will be considered during
|
||||
* matching. must have a stack size of 1.
|
||||
* @param simulate whether to actually commit the modification. true for dry run, false otherwise.
|
||||
* @return true if found. false otherwise
|
||||
* @throws IllegalArgumentException if given stack is invalid, or has a stack size other than 1.
|
||||
*/
|
||||
default boolean takeOne(ItemStack stack, boolean simulate) {
|
||||
if (stack == null || stack.getItem() == null || stack.stackSize != 1) throw new IllegalArgumentException();
|
||||
ItemStack took = takeOne(ItemStackPredicate.from(stack, NBTMode.EXACT), simulate);
|
||||
return took == null || took.stackSize <= 0;
|
||||
return took != null && took.stackSize > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take some item. Will not take item if it cannot find enough items to take.
|
||||
* <p>
|
||||
* This is meant to be an optimized version of {@link #takeOne(Predicate, boolean)}. Implementations that support
|
||||
* indexing off ItemStack can use this to speed up calculation.
|
||||
*
|
||||
* @param stack what item and how many to extract. The NBT tag of this ItemStack is siginifcant and will be
|
||||
* considered during matching
|
||||
* @param simulate whether to actually commit the modification. true for dry run, false otherwise.
|
||||
* @return true if enough item can be/has been extracted. false otherwise
|
||||
* @throws IllegalArgumentException if given stack is invalid
|
||||
*/
|
||||
default boolean takeAll(ItemStack stack, boolean simulate) {
|
||||
if (stack == null || stack.getItem() == null) throw new IllegalArgumentException();
|
||||
// fast path for 1 item take requests
|
||||
if (stack.stackSize == 1) return takeOne(stack, simulate);
|
||||
ItemStackPredicate predicate = ItemStackPredicate.from(stack, NBTMode.EXACT);
|
||||
Map<ItemStack, Integer> have = take(predicate, true, stack.stackSize);
|
||||
if (have.values().stream().mapToInt(Integer::intValue).sum() < stack.stackSize) return false;
|
||||
take(predicate, simulate, stack.stackSize);
|
||||
if (simulate) return true;
|
||||
take(predicate, false, stack.stackSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an IItemSource from inventories associated with given player.
|
||||
* <p>
|
||||
* This will be backed by {@link InventoryUtility}
|
||||
*/
|
||||
static IItemSource fromPlayer(EntityPlayerMP player) {
|
||||
return new IItemSource() {
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Map<ItemStack, Integer> take(Predicate<ItemStack> p, boolean s, int c) {
|
||||
@@ -71,6 +135,11 @@ public interface IItemSource {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an IItemSource from given inventory
|
||||
* <p>
|
||||
* This will be backed by {@link InventoryUtility}
|
||||
*/
|
||||
static IItemSource fromInventory(IInventory inv) {
|
||||
return (p, s, c) -> InventoryUtility.takeFromInventory(new InventoryIterable<>(inv), p, s, c, true);
|
||||
}
|
||||
|
||||
@@ -3,5 +3,6 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
import net.minecraft.block.Block;
|
||||
|
||||
public interface ISpecialItemBlock {
|
||||
|
||||
int getItemMetaFromBlockMeta(Block block, int blockMeta);
|
||||
}
|
||||
@@ -3,24 +3,28 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
import static com.gtnewhorizon.structurelib.structure.IStructureWalker.ignoreBlockUnloaded;
|
||||
import static com.gtnewhorizon.structurelib.structure.IStructureWalker.skipBlockUnloaded;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
|
||||
/**
|
||||
* This is the structure definition of your multi. You will have one of these for each multi.
|
||||
*
|
||||
* <h2>Cache the instances of this class</h2>
|
||||
* <p>
|
||||
* You will construct this definition once per multi, either at class load or at first call to your variant of {@code getStructureDefinition()}.
|
||||
* You can use a {@link ClassValue ClassValue<IStructureDefinition<?>>} if you have a template for subclass.
|
||||
* You can also use {@link StructureUtility#defer(Function) defer()} or its overloads for simpler cases, but it is
|
||||
* slightly less performant as it will allocate new objects on each structure check, whereas {@link ClassValue} will
|
||||
* allocate once and cache it onwards.
|
||||
* You will construct this definition once per multi, either at class load or at first call to your variant of
|
||||
* {@code getStructureDefinition()}. You can use a {@link ClassValue ClassValue<IStructureDefinition<?>>} if you
|
||||
* have a template for subclass. You can also use {@link StructureUtility#defer(Function) defer()} or its overloads for
|
||||
* simpler cases, but it is slightly less performant as it will allocate new objects on each structure check, whereas
|
||||
* {@link ClassValue} will allocate once and cache it onwards.
|
||||
* <p>
|
||||
* <h2>Constructing</h2>
|
||||
* <p>
|
||||
@@ -28,59 +32,62 @@ import net.minecraft.world.World;
|
||||
* <p>
|
||||
* Builder has two main methods:
|
||||
* <ul>
|
||||
* <li>{@link com.gtnewhorizon.structurelib.structure.StructureDefinition.Builder#addShape(String, String[][]) addShape()}
|
||||
* is a 2d string array describing the layout of structure. You can optionally use `StructureUtility#transpose()`
|
||||
* to transpose the array to make the structure look nicer in source code.
|
||||
* <li>{@link com.gtnewhorizon.structurelib.structure.StructureDefinition.Builder#addElement(Character, IStructureElement) addElement()}. It takes a char identifier (mapped to a char in any of {@link com.gtnewhorizon.structurelib.structure.StructureDefinition.Builder#addShape(String, String[][]) addShape()} calls) and a {@link IStructureElement}.
|
||||
* <li>{@link com.gtnewhorizon.structurelib.structure.StructureDefinition.Builder#addShape(String, String[][])
|
||||
* addShape()} is a 2d string array describing the layout of structure. You can optionally use
|
||||
* `StructureUtility#transpose()` to transpose the array to make the structure look nicer in source code.
|
||||
* <li>{@link com.gtnewhorizon.structurelib.structure.StructureDefinition.Builder#addElement(Character, IStructureElement)
|
||||
* addElement()}. It takes a char identifier (mapped to a char in any of
|
||||
* {@link com.gtnewhorizon.structurelib.structure.StructureDefinition.Builder#addShape(String, String[][]) addShape()}
|
||||
* calls) and a {@link IStructureElement}.
|
||||
* </ul>
|
||||
* <h2>Position A, B and C</h2>
|
||||
*
|
||||
* Imagine you stand in front of the controller, with controller facing towards you not rotated or flipped.
|
||||
* <ul>
|
||||
* <li>The "A" position would be the number of blocks on the left side of the controller, not counting controller itself.</li>
|
||||
* <li>The "B" position would be the number of blocks on the top side of the controller, not counting controller itself.</li>
|
||||
* <li>The "A" position would be the number of blocks on the left side of the controller, not counting controller
|
||||
* itself.</li>
|
||||
* <li>The "B" position would be the number of blocks on the top side of the controller, not counting controller
|
||||
* itself.</li>
|
||||
* <li>The "C" position would be the number of blocks between you and controller, not counting controller itself.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <T> Type of the context object. Usually this will be the multiblock controller.
|
||||
*/
|
||||
public interface IStructureDefinition<T> {
|
||||
|
||||
/**
|
||||
* Used internally
|
||||
* <p>
|
||||
* Might, but is not required, to throw {@link java.util.NoSuchElementException} if the given structure piece is not found.
|
||||
* Might, but is not required, to throw {@link java.util.NoSuchElementException} if the given structure piece is not
|
||||
* found.
|
||||
*
|
||||
* @param name same name as for other methods here
|
||||
* @return the array of elements to process
|
||||
* @throws java.util.NoSuchElementException if the given structure piece is not found and the moon phase perfectly matches
|
||||
* @throws java.util.NoSuchElementException if the given structure piece is not found and the moon phase perfectly
|
||||
* matches
|
||||
*/
|
||||
IStructureElement<T>[] getStructureFor(String name);
|
||||
|
||||
boolean isContainedInStructure(String name, int offsetA, int offsetB, int offsetC);
|
||||
|
||||
/**
|
||||
* Run a structure check.
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
*
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @param forceCheckAllBlocks check all location even if chunk not currently loaded.
|
||||
* @return true if successful, false otherwise
|
||||
*/
|
||||
default boolean check(
|
||||
T object,
|
||||
String piece,
|
||||
World world,
|
||||
ExtendedFacing extendedFacing,
|
||||
int basePositionX,
|
||||
int basePositionY,
|
||||
int basePositionZ,
|
||||
int basePositionA,
|
||||
int basePositionB,
|
||||
int basePositionC,
|
||||
default boolean check(T object, String piece, World world, ExtendedFacing extendedFacing, int basePositionX,
|
||||
int basePositionY, int basePositionZ, int basePositionA, int basePositionB, int basePositionC,
|
||||
boolean forceCheckAllBlocks) {
|
||||
return iterate(
|
||||
object,
|
||||
@@ -100,29 +107,21 @@ public interface IStructureDefinition<T> {
|
||||
|
||||
/**
|
||||
* Spawn hint particles. Should not be called on server side.
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
*
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @return true if successful, false otherwise
|
||||
*/
|
||||
default boolean hints(
|
||||
T object,
|
||||
ItemStack trigger,
|
||||
String piece,
|
||||
World world,
|
||||
ExtendedFacing extendedFacing,
|
||||
int basePositionX,
|
||||
int basePositionY,
|
||||
int basePositionZ,
|
||||
int basePositionA,
|
||||
int basePositionB,
|
||||
default boolean hints(T object, ItemStack trigger, String piece, World world, ExtendedFacing extendedFacing,
|
||||
int basePositionX, int basePositionY, int basePositionZ, int basePositionA, int basePositionB,
|
||||
int basePositionC) {
|
||||
return iterate(
|
||||
object,
|
||||
@@ -141,33 +140,24 @@ public interface IStructureDefinition<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the multi in creative mode on a best effort basis. Does not guarantee the structure is correct after a
|
||||
* Build the multi in creative mode on a best-effort basis. Does not guarantee the structure is correct after a
|
||||
* successful call.
|
||||
*
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param trigger The trigger item that contains channel data.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param trigger The trigger item that contains channel data.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @return true if sucessful, false otherwise
|
||||
*/
|
||||
default boolean build(
|
||||
T object,
|
||||
ItemStack trigger,
|
||||
String piece,
|
||||
World world,
|
||||
ExtendedFacing extendedFacing,
|
||||
int basePositionX,
|
||||
int basePositionY,
|
||||
int basePositionZ,
|
||||
int basePositionA,
|
||||
int basePositionB,
|
||||
default boolean build(T object, ItemStack trigger, String piece, World world, ExtendedFacing extendedFacing,
|
||||
int basePositionX, int basePositionY, int basePositionZ, int basePositionA, int basePositionB,
|
||||
int basePositionC) {
|
||||
return iterate(
|
||||
object,
|
||||
@@ -186,38 +176,29 @@ public interface IStructureDefinition<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@link #build(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)} if {@code hintsOnly},
|
||||
* call {@link #hints(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)} otherwise.
|
||||
* Call {@link #build(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)} if
|
||||
* {@code hintsOnly}, call
|
||||
* {@link #hints(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)} otherwise.
|
||||
*
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param trigger The trigger item that contains channel data.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param trigger The trigger item that contains channel data.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @param hintsOnly whether to spawn hints or do creative build.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @param hintsOnly whether to spawn hints or do creative build.
|
||||
* @return true if sucessful, false otherwise
|
||||
* @see #hints(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)
|
||||
* @see #build(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)
|
||||
*/
|
||||
default boolean buildOrHints(
|
||||
T object,
|
||||
ItemStack trigger,
|
||||
String piece,
|
||||
World world,
|
||||
ExtendedFacing extendedFacing,
|
||||
int basePositionX,
|
||||
int basePositionY,
|
||||
int basePositionZ,
|
||||
int basePositionA,
|
||||
int basePositionB,
|
||||
int basePositionC,
|
||||
boolean hintsOnly) {
|
||||
default boolean buildOrHints(T object, ItemStack trigger, String piece, World world, ExtendedFacing extendedFacing,
|
||||
int basePositionX, int basePositionY, int basePositionZ, int basePositionA, int basePositionB,
|
||||
int basePositionC, boolean hintsOnly) {
|
||||
return iterate(
|
||||
object,
|
||||
trigger,
|
||||
@@ -237,45 +218,91 @@ public interface IStructureDefinition<T> {
|
||||
/**
|
||||
* Cause a survival build.
|
||||
*
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param trigger The trigger item that contains channel data.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param trigger The trigger item that contains channel data.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @param elementBudget build up to this many elements
|
||||
* @param source from where to drain resource
|
||||
* @param actor source of action
|
||||
* @param check whether {@link IStructureElement#check(Object, World, int, int, int)} should be called if anything
|
||||
* would be placed. use with caution.
|
||||
* if in doubt, call {@link #check(Object, String, World, ExtendedFacing, int, int, int, int, int, int, boolean)}
|
||||
* after this call and set this parameter to false
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @param elementBudget build up to this many elements
|
||||
* @param source from where to drain resource
|
||||
* @param actor source of action
|
||||
* @param check whether {@link IStructureElement#check(Object, World, int, int, int)} should be called if
|
||||
* anything would be placed. use with caution. if in doubt, call
|
||||
* {@link #check(Object, String, World, ExtendedFacing, int, int, int, int, int, int, boolean)}
|
||||
* after this call and set this parameter to false
|
||||
* @return number of elements built, or -1 if structure done
|
||||
* @see #build(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)
|
||||
*/
|
||||
default int survivalBuild(
|
||||
T object,
|
||||
ItemStack trigger,
|
||||
String piece,
|
||||
World world,
|
||||
ExtendedFacing extendedFacing,
|
||||
int basePositionX,
|
||||
int basePositionY,
|
||||
int basePositionZ,
|
||||
int basePositionA,
|
||||
int basePositionB,
|
||||
int basePositionC,
|
||||
int elementBudget,
|
||||
IItemSource source,
|
||||
EntityPlayerMP actor,
|
||||
boolean check) {
|
||||
SurvivalBuildStructureWalker<T> walker =
|
||||
new SurvivalBuildStructureWalker<>(object, trigger, source, actor, elementBudget, check);
|
||||
@Deprecated
|
||||
default int survivalBuild(T object, ItemStack trigger, String piece, World world, ExtendedFacing extendedFacing,
|
||||
int basePositionX, int basePositionY, int basePositionZ, int basePositionA, int basePositionB,
|
||||
int basePositionC, int elementBudget, IItemSource source, EntityPlayerMP actor, boolean check) {
|
||||
EntityPlayer realActor;
|
||||
if (actor == null) {
|
||||
realActor = ISurvivalConstructable.__get_player();
|
||||
if (realActor == null) throw new IllegalArgumentException();
|
||||
} else {
|
||||
realActor = actor;
|
||||
}
|
||||
return survivalBuild(
|
||||
object,
|
||||
trigger,
|
||||
piece,
|
||||
world,
|
||||
extendedFacing,
|
||||
basePositionX,
|
||||
basePositionY,
|
||||
basePositionZ,
|
||||
basePositionA,
|
||||
basePositionB,
|
||||
basePositionC,
|
||||
elementBudget,
|
||||
ISurvivalBuildEnvironment.create(source, realActor),
|
||||
check);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cause a survival build.
|
||||
*
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param trigger The trigger item that contains channel data.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @param elementBudget build up to this many elements
|
||||
* @param env build environment.
|
||||
* @param check whether {@link IStructureElement#check(Object, World, int, int, int)} should be called if
|
||||
* anything would be placed. use with caution. if in doubt, call
|
||||
* {@link IStructureDefinition#check(Object, String, World, ExtendedFacing, int, int, int, int, int, int, boolean)}
|
||||
* after this call and set this parameter to false
|
||||
* @return number of elements built, or -1 if structure done
|
||||
* @see #build(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)
|
||||
*/
|
||||
default int survivalBuild(T object, ItemStack trigger, String piece, World world, ExtendedFacing extendedFacing,
|
||||
int basePositionX, int basePositionY, int basePositionZ, int basePositionA, int basePositionB,
|
||||
int basePositionC, int elementBudget, ISurvivalBuildEnvironment env, boolean check) {
|
||||
SurvivalBuildStructureWalker<T> walker = new SurvivalBuildStructureWalker<>(
|
||||
object,
|
||||
trigger,
|
||||
elementBudget,
|
||||
env,
|
||||
this,
|
||||
piece,
|
||||
extendedFacing,
|
||||
new int[] { basePositionA, basePositionB, basePositionC },
|
||||
check);
|
||||
StructureUtility.iterateV2(
|
||||
getStructureFor(piece),
|
||||
world,
|
||||
@@ -293,38 +320,29 @@ public interface IStructureDefinition<T> {
|
||||
|
||||
/**
|
||||
* Low level utility.
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param trigger The trigger item that contains channel data.
|
||||
* @param elements the structure piece
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @param hintsOnly whether to spawn hints or do creative build. no effect if {@code checkBlocksIfNotNullForceCheckAllIfTrue} is not null.
|
||||
* @param checkBlocksIfNotNullForceCheckAllIfTrue creative build or spawn hints if null. Force check not loaded chunk
|
||||
* if true. Check only loaded chunk is false.
|
||||
*
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param trigger The trigger item that contains channel data.
|
||||
* @param elements the structure piece
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @param hintsOnly whether to spawn hints or do creative build. no effect if
|
||||
* {@code checkBlocksIfNotNullForceCheckAllIfTrue} is not null.
|
||||
* @param checkBlocksIfNotNullForceCheckAllIfTrue creative build or spawn hints if null. Force check not loaded
|
||||
* chunk if true. Check only loaded chunk is false.
|
||||
* @return true if iteration completed successfully.
|
||||
* @param <T> type of context object.
|
||||
*/
|
||||
static <T> boolean iterate(
|
||||
T object,
|
||||
ItemStack trigger,
|
||||
IStructureElement<T>[] elements,
|
||||
World world,
|
||||
ExtendedFacing extendedFacing,
|
||||
int basePositionX,
|
||||
int basePositionY,
|
||||
int basePositionZ,
|
||||
int basePositionA,
|
||||
int basePositionB,
|
||||
int basePositionC,
|
||||
boolean hintsOnly,
|
||||
Boolean checkBlocksIfNotNullForceCheckAllIfTrue) {
|
||||
if (world.isRemote ^ hintsOnly) {
|
||||
static <T> boolean iterate(T object, ItemStack trigger, IStructureElement<T>[] elements, World world,
|
||||
ExtendedFacing extendedFacing, int basePositionX, int basePositionY, int basePositionZ, int basePositionA,
|
||||
int basePositionB, int basePositionC, boolean hintsOnly, Boolean checkBlocksIfNotNullForceCheckAllIfTrue) {
|
||||
if (!world.isRemote && hintsOnly) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -341,7 +359,7 @@ public interface IStructureDefinition<T> {
|
||||
basePositionA,
|
||||
basePositionB,
|
||||
basePositionC,
|
||||
(e, w, x, y, z) -> e.check(object, w, x, y, z),
|
||||
(e, w, x, y, z, a, b, c) -> e.check(object, w, x, y, z),
|
||||
"check");
|
||||
} else {
|
||||
success = StructureUtility.iterateV2(
|
||||
@@ -354,12 +372,12 @@ public interface IStructureDefinition<T> {
|
||||
basePositionA,
|
||||
basePositionB,
|
||||
basePositionC,
|
||||
skipBlockUnloaded((e, w, x, y, z) -> e.check(object, w, x, y, z)),
|
||||
skipBlockUnloaded((e, w, x, y, z, a, b, c) -> e.check(object, w, x, y, z)),
|
||||
"check force");
|
||||
}
|
||||
if (StructureLibAPI.isDebugEnabled() && success) {
|
||||
StructureLib.LOGGER.info(
|
||||
"Multi [" + basePositionX + ", " + basePositionY + ", " + basePositionZ + "] pass");
|
||||
StructureLib.LOGGER
|
||||
.info("Multi [" + basePositionX + ", " + basePositionY + ", " + basePositionZ + "] pass");
|
||||
}
|
||||
return success;
|
||||
} else {
|
||||
@@ -374,7 +392,7 @@ public interface IStructureDefinition<T> {
|
||||
basePositionA,
|
||||
basePositionB,
|
||||
basePositionC,
|
||||
ignoreBlockUnloaded((e, w, x, y, z) -> {
|
||||
ignoreBlockUnloaded((e, w, x, y, z, a, b, c) -> {
|
||||
e.spawnHint(object, world, x, y, z, trigger);
|
||||
return true;
|
||||
}),
|
||||
@@ -390,7 +408,7 @@ public interface IStructureDefinition<T> {
|
||||
basePositionA,
|
||||
basePositionB,
|
||||
basePositionC,
|
||||
ignoreBlockUnloaded((e, w, x, y, z) -> {
|
||||
ignoreBlockUnloaded((e, w, x, y, z, a, b, c) -> {
|
||||
e.placeBlock(object, world, x, y, z, trigger);
|
||||
return true;
|
||||
}),
|
||||
@@ -402,7 +420,7 @@ public interface IStructureDefinition<T> {
|
||||
|
||||
/**
|
||||
* Create a new instance of builder.
|
||||
* @return
|
||||
*
|
||||
* @param <T> type of context object
|
||||
*/
|
||||
static <T> StructureDefinition.Builder<T> builder() {
|
||||
|
||||
@@ -3,18 +3,33 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
import static com.gtnewhorizon.structurelib.StructureLib.LOGGER;
|
||||
import static com.gtnewhorizon.structurelib.StructureLib.PANIC_MODE;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import com.gtnewhorizon.structurelib.util.ItemStackPredicate;
|
||||
import com.gtnewhorizon.structurelib.util.ItemStackPredicate.NBTMode;
|
||||
|
||||
/**
|
||||
* Use StructureUtility to instantiate
|
||||
* Use StructureUtility to instantiate. These are the building blocks for your {@link IStructureDefinition}. It
|
||||
* represents what a particular element can be and how this particular element should be autoplaced.
|
||||
*/
|
||||
public interface IStructureElement<T> {
|
||||
|
||||
boolean check(T t, World world, int x, int y, int z);
|
||||
|
||||
boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger);
|
||||
@@ -24,35 +39,141 @@ public interface IStructureElement<T> {
|
||||
/**
|
||||
* Try place the block by taking resource from given IItemSource.
|
||||
* <p>
|
||||
* You might want to use {@link StructureUtility#survivalPlaceBlock(Block, int, World, int, int, int, IItemSource, EntityPlayerMP)}
|
||||
* You might want to use
|
||||
* {@link StructureUtility#survivalPlaceBlock(Block, int, World, int, int, int, IItemSource, net.minecraft.entity.player.EntityPlayer)}
|
||||
* or its overloads to implement this.
|
||||
*
|
||||
* @param trigger trigger item
|
||||
* @param s drain resources from this place
|
||||
* @param actor source of action. for very critical errors you can also just send the error messages here, bypassing
|
||||
* any filter that chatter might have.
|
||||
* @param actor source of action. for very critical errors you can also just send the error messages here,
|
||||
* bypassing any filter that chatter might have.
|
||||
* @param chatter send error messages here. Caller will choose an appropriate way to forward it to player if the
|
||||
* other fallbacks also fails.
|
||||
* @deprecated caller should call the non deprecated overload. implementor for reusable {@link IStructureElement}
|
||||
* should still implement this. implementor for private implementations can freely ignore this as long
|
||||
* as you know the caller will not call this overload.
|
||||
*/
|
||||
default PlaceResult survivalPlaceBlock(
|
||||
T t,
|
||||
World world,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
ItemStack trigger,
|
||||
IItemSource s,
|
||||
EntityPlayerMP actor,
|
||||
Consumer<IChatComponent> chatter) {
|
||||
@Deprecated
|
||||
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s,
|
||||
EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
|
||||
if (PANIC_MODE) throw new RuntimeException("Panic Tripwire hit");
|
||||
if (StructureLibAPI.isDebugEnabled())
|
||||
LOGGER.error(
|
||||
"Default implementation of survivalPlaceBlock hit! Things aren't going to work well! IStructureElement class: {}",
|
||||
getClass().getName());
|
||||
if (StructureLibAPI.isDebugEnabled()) LOGGER.error(
|
||||
"Default implementation of survivalPlaceBlock hit! Things aren't going to work well! IStructureElement class: {}",
|
||||
getClass().getName());
|
||||
if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor)) return PlaceResult.REJECT;
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simplified version of survivalPlaceBlock. Return null if not implemented.
|
||||
* <p>
|
||||
* <b>BY OVERRIDING THIS TO NULL, YOU ACKNOWLEDGE THAT THE {@link #check(Object, World, int, int, int)} OF THIS
|
||||
* CLASS IS SIDE EFFECT FREE AND CAN HAVE ITS CHECK CALLED WITHOUT BREAKING ANYTHING. OTHERWISE OVERRIDE THE
|
||||
* {@link #survivalPlaceBlock(Object, World, int, int, int, ItemStack, AutoPlaceEnvironment)} TO PROVIDE A
|
||||
* SIDEEFFECT FREE {@link PlaceResult#SKIP}.</b>
|
||||
* <p>
|
||||
* It should be noticed that this filter is only advisory and the actual
|
||||
* {@link #survivalPlaceBlock(Object, World, int, int, int, ItemStack, AutoPlaceEnvironment)} or
|
||||
* {@link #check(Object, World, int, int, int)} are free to reject/accept/place blocks not contained in this list,
|
||||
* e.g. when the element can be placed anywhere in the structure, but no more than 3 overall; when the structure
|
||||
* element cannot know all blocks it will accept at the time of calling; when this is backed by a legacy
|
||||
* {@link IStructureElement} that just didn't implement this API.
|
||||
*
|
||||
* @param trigger trigger item
|
||||
* @param env autoplacing environment
|
||||
* @return null if not implemented, otherwise an instance describing what kind of blocks will be placed by
|
||||
* {@link #survivalPlaceBlock(Object, World, int, int, int, ItemStack, AutoPlaceEnvironment)}
|
||||
*/
|
||||
@Nullable
|
||||
default BlocksToPlace getBlocksToPlace(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try place the block by taking resource from given {@link IItemSource}.
|
||||
* <p>
|
||||
* You might want to use
|
||||
* {@link StructureUtility#survivalPlaceBlock(Block, int, World, int, int, int, IItemSource, net.minecraft.entity.player.EntityPlayer)}
|
||||
* or its overloads to implement this.
|
||||
* <p>
|
||||
* The default implementation provided will
|
||||
* <ol>
|
||||
* <li>Get {@link BlocksToPlace} via
|
||||
* {@link #getBlocksToPlace(Object, World, int, int, int, ItemStack, AutoPlaceEnvironment)}. If not null
|
||||
* <ol>
|
||||
* <li>call {@link #check(Object, World, int, int, int)}. If this returns {@code true}, {@link PlaceResult#SKIP}
|
||||
* will be returned without further action.</li>
|
||||
* <li>Use the {@link BlocksToPlace} retrieved earlier and passed in {@link IItemSource} to determine an item to
|
||||
* place</li>
|
||||
* <li>Hand over control to
|
||||
* {@link StructureUtility#survivalPlaceBlock(ItemStack, NBTMode, NBTTagCompound, boolean, World, int, int, int, IItemSource, EntityPlayer, Consumer)}</li>
|
||||
* </ol>
|
||||
* </li>
|
||||
* <li>Call legacy
|
||||
* {@link #survivalPlaceBlock(Object, World, int, int, int, ItemStack, IItemSource, EntityPlayerMP, Consumer)} if
|
||||
* {@code env.getActor()} contains an {@link EntityPlayerMP}</li>
|
||||
* <li>Emit warning under debug mode (or throw exception under panic mode), then return
|
||||
* {@link PlaceResult#SKIP}</li>
|
||||
* </ol>
|
||||
* It should be noticed that the default implementation is likely to cause unexpected issues if the
|
||||
* {@link #check(Object, World, int, int, int)} is not side effect free, or is not idempotent. E.g. the
|
||||
* {@link #check(Object, World, int, int, int)} will add current coord to a {@link java.util.List}. As this method
|
||||
* might be invoked at a location that is already accepted, this will cause the machine to have multiple of this
|
||||
* coord in its list.
|
||||
*
|
||||
* @param trigger trigger item
|
||||
* @param env autoplacing environment
|
||||
*/
|
||||
default 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 (e != null) {
|
||||
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,
|
||||
true,
|
||||
world,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
source,
|
||||
actor,
|
||||
chatter);
|
||||
}
|
||||
for (ItemStack stack : e.getStacks()) {
|
||||
if (!source.takeOne(stack, true)) continue;
|
||||
return StructureUtility.survivalPlaceBlock(
|
||||
stack,
|
||||
NBTMode.EXACT,
|
||||
stack.stackTagCompound,
|
||||
true,
|
||||
world,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
source,
|
||||
actor,
|
||||
chatter);
|
||||
}
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
if (actor instanceof EntityPlayerMP)
|
||||
return survivalPlaceBlock(t, world, x, y, z, trigger, source, (EntityPlayerMP) actor, chatter);
|
||||
if (PANIC_MODE) throw new RuntimeException("Panic Tripwire hit");
|
||||
if (StructureLibAPI.isDebugEnabled()) LOGGER.info(
|
||||
"Fallback shim code of survivalPlaceBlock hit! Things aren't going to work well! IStructureElement class: {}",
|
||||
getClass().getName());
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forget the messed up class dependency graph for now. this is just so convenient.
|
||||
*/
|
||||
@@ -101,18 +222,19 @@ public interface IStructureElement<T> {
|
||||
|
||||
enum PlaceResult {
|
||||
/**
|
||||
* This element either exists already, or does not yet have an implementation for survivalPlaceBlock, or
|
||||
* some other unforeseen situations.
|
||||
* TODO this definition doesn't seem right. Should we separate SKIP from EXISTS, or SKIP from ERROR?
|
||||
* This element either exists already, or does not yet have an implementation for survivalPlaceBlock, or some
|
||||
* other unforeseen situations. TODO this definition doesn't seem right. Should we separate SKIP from EXISTS, or
|
||||
* SKIP from ERROR?
|
||||
*/
|
||||
SKIP,
|
||||
/**
|
||||
* This element's space is occupied by other stuff and require player attention, or player missing required resource,
|
||||
* or the block cannot be placed due to obscure mechanisms, or some other unforeseen situations.
|
||||
* This element's space is occupied by other stuff and require player attention, or player missing required
|
||||
* resource, or the block cannot be placed due to obscure mechanisms, or some other unforeseen situations.
|
||||
*/
|
||||
REJECT,
|
||||
/**
|
||||
* Autoplace cannot proceed within this tick. To proceed further would require stopping the placement and wait for next round.
|
||||
* Autoplace cannot proceed within this tick. To proceed further would require stopping the placement and wait
|
||||
* for next round.
|
||||
*/
|
||||
STOP,
|
||||
/**
|
||||
@@ -126,4 +248,83 @@ public interface IStructureElement<T> {
|
||||
*/
|
||||
ACCEPT_STOP;
|
||||
}
|
||||
|
||||
final class BlocksToPlace {
|
||||
|
||||
public static final BlocksToPlace errored = createEmpty();
|
||||
private final Predicate<ItemStack> predicate;
|
||||
private final Iterable<ItemStack> stacks;
|
||||
|
||||
public static BlocksToPlace createEmpty() {
|
||||
return new BlocksToPlace(s -> false, Collections.emptyList());
|
||||
}
|
||||
|
||||
public static BlocksToPlace create(ItemStack... stacks) {
|
||||
return create(Arrays.asList(stacks));
|
||||
}
|
||||
|
||||
public static BlocksToPlace create(Iterable<ItemStack> stacks) {
|
||||
Predicate<ItemStack> predicate = null;
|
||||
|
||||
for (ItemStack stack : stacks) {
|
||||
ItemStackPredicate p = ItemStackPredicate.from(stack, NBTMode.EXACT);
|
||||
if (predicate == null) predicate = p;
|
||||
else predicate = predicate.or(p);
|
||||
}
|
||||
|
||||
return new BlocksToPlace(predicate, stacks);
|
||||
}
|
||||
|
||||
public static BlocksToPlace create(Block block, int meta) {
|
||||
Item itemBlock = Item.getItemFromBlock(block);
|
||||
if (itemBlock instanceof ISpecialItemBlock) {
|
||||
meta = ((ISpecialItemBlock) itemBlock).getItemMetaFromBlockMeta(block, meta);
|
||||
}
|
||||
return create(itemBlock, meta);
|
||||
}
|
||||
|
||||
public static BlocksToPlace create(Item item, int meta) {
|
||||
return new BlocksToPlace(
|
||||
ItemStackPredicate.from(item).setMeta(meta),
|
||||
Collections.singletonList(new ItemStack(item, 1, meta)));
|
||||
}
|
||||
|
||||
public static BlocksToPlace create(ItemStack itemStack) {
|
||||
return new BlocksToPlace(ItemStackPredicate.from(itemStack), Collections.singletonList(itemStack));
|
||||
}
|
||||
|
||||
public static BlocksToPlace create(Predicate<ItemStack> predicate) {
|
||||
return new BlocksToPlace(predicate, null);
|
||||
}
|
||||
|
||||
BlocksToPlace(Predicate<ItemStack> predicate, Iterable<ItemStack> stacks) {
|
||||
this.predicate = predicate;
|
||||
this.stacks = stacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the blocks to place filter. This is usually slower as it requires walking through inventories one by one.
|
||||
* <p>
|
||||
* Suitable for use with {@link IItemSource#takeOne(Predicate, boolean)}
|
||||
*
|
||||
* @return a predicate. never null.
|
||||
*/
|
||||
@Nonnull
|
||||
public Predicate<ItemStack> getPredicate() {
|
||||
return predicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ItemStacks that this one is known to accept. Can be null if this info is not available at the time
|
||||
* this instance is constructed.
|
||||
* <p>
|
||||
* Suitable for use with {@link IItemSource#takeOne(ItemStack, boolean)}.
|
||||
* <p>
|
||||
* This should be equivalent to the predicate returned from {@link #getPredicate()}
|
||||
*/
|
||||
@Nullable
|
||||
public Iterable<ItemStack> getStacks() {
|
||||
return stacks;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,15 +3,22 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* Use StructureUtility to instantiate
|
||||
*/
|
||||
public interface IStructureElementChain<T> extends IStructureElement<T> {
|
||||
|
||||
IStructureElement<T>[] fallbacks();
|
||||
|
||||
@Override
|
||||
@@ -44,17 +51,26 @@ public interface IStructureElementChain<T> extends IStructureElement<T> {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
default PlaceResult survivalPlaceBlock(
|
||||
T t,
|
||||
World world,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
ItemStack trigger,
|
||||
IItemSource s,
|
||||
EntityPlayerMP actor,
|
||||
Consumer<IChatComponent> chatter) {
|
||||
default BlocksToPlace getBlocksToPlace(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
Predicate<ItemStack> predicate = null;
|
||||
List<Iterable<ItemStack>> is = new ArrayList<>();
|
||||
for (IStructureElement<T> fallback : fallbacks()) {
|
||||
BlocksToPlace e = fallback.getBlocksToPlace(t, world, x, y, z, trigger, env);
|
||||
if (e == null) continue;
|
||||
if (predicate == null) predicate = e.getPredicate();
|
||||
else predicate = predicate.or(e.getPredicate());
|
||||
is.add(e.getStacks());
|
||||
}
|
||||
if (predicate == null) return null;
|
||||
return new BlocksToPlace(predicate, Iterables.concat(is));
|
||||
}
|
||||
|
||||
@Override
|
||||
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s,
|
||||
EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
|
||||
boolean haveSkip = false;
|
||||
List<IChatComponent> bufferedNoise = new ArrayList<>();
|
||||
for (IStructureElement<T> fallback : fallbacks()) {
|
||||
@@ -74,4 +90,28 @@ public interface IStructureElementChain<T> extends IStructureElement<T> {
|
||||
// TODO need reconsider to ensure this is the right course of action
|
||||
return haveSkip ? PlaceResult.SKIP : PlaceResult.REJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
boolean haveSkip = false;
|
||||
List<IChatComponent> bufferedNoise = new ArrayList<>();
|
||||
for (IStructureElement<T> fallback : fallbacks()) {
|
||||
PlaceResult result = fallback
|
||||
.survivalPlaceBlock(t, world, x, y, z, trigger, env.withChatter(bufferedNoise::add));
|
||||
switch (result) {
|
||||
case REJECT:
|
||||
break;
|
||||
case SKIP:
|
||||
haveSkip = true;
|
||||
break;
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// dump all that noise back into upstream
|
||||
bufferedNoise.forEach(env.getChatter());
|
||||
// TODO need reconsider to ensure this is the right course of action
|
||||
return haveSkip ? PlaceResult.SKIP : PlaceResult.REJECT;
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -1,12 +1,14 @@
|
||||
package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface IStructureElementCheckOnly<T> extends IStructureElement<T> {
|
||||
|
||||
@Override
|
||||
default boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
|
||||
return false;
|
||||
@@ -18,16 +20,14 @@ public interface IStructureElementCheckOnly<T> extends IStructureElement<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
default PlaceResult survivalPlaceBlock(
|
||||
T t,
|
||||
World world,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
ItemStack trigger,
|
||||
IItemSource s,
|
||||
EntityPlayerMP actor,
|
||||
Consumer<IChatComponent> chatter) {
|
||||
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s,
|
||||
EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -3,4 +3,5 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
/**
|
||||
* Use StructureUtility to instantiate
|
||||
*/
|
||||
public interface IStructureElementDeferred<T> extends IStructureElement<T> {}
|
||||
public interface IStructureElementDeferred<T> extends IStructureElement<T> {
|
||||
}
|
||||
+10
-10
@@ -1,28 +1,28 @@
|
||||
package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface IStructureElementNoPlacement<T> extends IStructureElement<T> {
|
||||
|
||||
@Override
|
||||
default boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
default PlaceResult survivalPlaceBlock(
|
||||
T t,
|
||||
World world,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
ItemStack trigger,
|
||||
IItemSource s,
|
||||
EntityPlayerMP actor,
|
||||
Consumer<IChatComponent> chatter) {
|
||||
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s,
|
||||
EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
@@ -10,6 +11,7 @@ import net.minecraft.world.World;
|
||||
* Use StructureUtility to instantiate
|
||||
*/
|
||||
interface IStructureNavigate<T> extends IStructureElement<T> {
|
||||
|
||||
@Override
|
||||
default boolean check(T t, World world, int x, int y, int z) {
|
||||
return true;
|
||||
@@ -26,16 +28,14 @@ interface IStructureNavigate<T> extends IStructureElement<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
default PlaceResult survivalPlaceBlock(
|
||||
T t,
|
||||
World world,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
ItemStack trigger,
|
||||
IItemSource s,
|
||||
EntityPlayerMP actor,
|
||||
Consumer<IChatComponent> chatter) {
|
||||
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s,
|
||||
EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,36 +2,42 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface IStructureWalker<T> {
|
||||
boolean visit(IStructureElement<T> element, World world, int x, int y, int z);
|
||||
interface IStructureWalker<T> {
|
||||
|
||||
default boolean blockNotLoaded(IStructureElement<T> element, World world, int x, int y, int z) {
|
||||
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,
|
||||
int c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static <T> IStructureWalker<T> ignoreBlockUnloaded(IStructureWalker<T> walker) {
|
||||
return new IStructureWalker<T>() {
|
||||
|
||||
@Override
|
||||
public boolean visit(IStructureElement<T> element, World world, int x, int y, int z) {
|
||||
return walker.visit(element, world, x, y, z);
|
||||
public boolean visit(IStructureElement<T> element, World world, int x, int y, int z, int a, int b, int c) {
|
||||
return walker.visit(element, world, x, y, z, a, b, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean blockNotLoaded(IStructureElement<T> element, World world, int x, int y, int z) {
|
||||
return walker.visit(element, world, x, y, z);
|
||||
public boolean blockNotLoaded(IStructureElement<T> element, World world, int x, int y, int z, int a, int b,
|
||||
int c) {
|
||||
return walker.visit(element, world, x, y, z, a, b, c);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static <T> IStructureWalker<T> skipBlockUnloaded(IStructureWalker<T> walker) {
|
||||
return new IStructureWalker<T>() {
|
||||
|
||||
@Override
|
||||
public boolean visit(IStructureElement<T> element, World world, int x, int y, int z) {
|
||||
return walker.visit(element, world, x, y, z);
|
||||
public boolean visit(IStructureElement<T> element, World world, int x, int y, int z, int a, int b, int c) {
|
||||
return walker.visit(element, world, x, y, z, a, b, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean blockNotLoaded(IStructureElement<T> element, World world, int x, int y, int z) {
|
||||
public boolean blockNotLoaded(IStructureElement<T> element, World world, int x, int y, int z, int a, int b,
|
||||
int c) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
|
||||
/*
|
||||
* Architecture notes: this should never get any callback from survival build. All structure significant code belongs
|
||||
* within the IStructureElement. This will make the user easier to maintain the IStructureDefinition. Structure Element
|
||||
* knows the most about what this structure element should do, not the caller.
|
||||
*/
|
||||
public interface ISurvivalBuildEnvironment {
|
||||
|
||||
/**
|
||||
* Get the source of the items. This will be invoked exactly once per structure element build.
|
||||
* <p>
|
||||
* If the call chain ever got into the old API, this will be called at least once per
|
||||
* {@link IStructureDefinition#survivalBuild(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int, int, ISurvivalBuildEnvironment, boolean)}
|
||||
* call.
|
||||
*/
|
||||
IItemSource getSource();
|
||||
|
||||
/**
|
||||
* Get the origin of action. This will be invoked at least once per
|
||||
* {@link IStructureDefinition#survivalBuild(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int, int, ISurvivalBuildEnvironment, boolean)}
|
||||
* call.
|
||||
*/
|
||||
EntityPlayer getActor();
|
||||
|
||||
/**
|
||||
* Create a default implementation with three parameters all being constants.
|
||||
*
|
||||
* @param source from where to drain resource
|
||||
* @param actor source of action
|
||||
*/
|
||||
static ISurvivalBuildEnvironment create(IItemSource source, EntityPlayer actor) {
|
||||
return new DefaultSurvivalBuildEnvironment(source, actor);
|
||||
}
|
||||
}
|
||||
@@ -9,5 +9,6 @@ import net.minecraft.block.Block;
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ITierConverter<TIER> {
|
||||
|
||||
TIER convert(Block block, int meta);
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
/**
|
||||
* Implement this and use {@link StructureUtility#withContext(IStructureElement)} in case you need to record some
|
||||
* temporary states that don't need to live in your main context, which would usually live for the whole lifetime of the
|
||||
* structure than just during structure check. Usually just save some few bytes, but becomes non trivial if you need to
|
||||
* structure than just during structure check. Usually just save some few bytes, but becomes non-trivial if you need to
|
||||
* record too much stuff.
|
||||
* <p>
|
||||
* You will have to reset the context yourself though. The API can't guess when the old context becomes invalid.
|
||||
@@ -11,5 +11,6 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
* @param <CTX> the temporary state context
|
||||
*/
|
||||
public interface IWithExtendedContext<CTX> {
|
||||
|
||||
CTX getCurrentContext();
|
||||
}
|
||||
@@ -2,12 +2,16 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
class LazyStructureElement<T> implements IStructureElementDeferred<T> {
|
||||
|
||||
private Function<T, IStructureElement<T>> to;
|
||||
private IStructureElement<T> elem;
|
||||
|
||||
@@ -38,17 +42,22 @@ class LazyStructureElement<T> implements IStructureElementDeferred<T> {
|
||||
return get(t).spawnHint(t, world, x, y, z, trigger);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PlaceResult survivalPlaceBlock(
|
||||
T t,
|
||||
World world,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
ItemStack trigger,
|
||||
IItemSource s,
|
||||
EntityPlayerMP actor,
|
||||
Consumer<IChatComponent> chatter) {
|
||||
public BlocksToPlace getBlocksToPlace(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
return get(t).getBlocksToPlace(t, world, x, y, z, trigger, env);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s,
|
||||
EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
|
||||
return get(t).survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
return get(t).survivalPlaceBlock(t, world, x, y, z, trigger, env);
|
||||
}
|
||||
}
|
||||
@@ -2,30 +2,32 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import static com.gtnewhorizon.structurelib.structure.StructureUtility.*;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import com.gtnewhorizon.structurelib.util.Vec3Impl;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.gtnewhorizon.structurelib.util.Vec3Impl;
|
||||
|
||||
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;
|
||||
|
||||
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) {
|
||||
private StructureDefinition(Map<Character, IStructureElement<T>> elements, Map<String, String> shapes,
|
||||
Map<String, IStructureElement<T>[]> structures, Map<String, Set<Vec3Impl>> occupiedSpaces) {
|
||||
this.elements = elements;
|
||||
this.shapes = shapes;
|
||||
this.structures = structures;
|
||||
this.occupiedSpaces = occupiedSpaces;
|
||||
}
|
||||
|
||||
public static class Builder<T> {
|
||||
|
||||
private static final char A = '\uA000';
|
||||
private static final char B = '\uB000';
|
||||
private static final char C = '\uC000';
|
||||
@@ -33,11 +35,13 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
private final Map<Vec3Impl, Character> navigates;
|
||||
private final Map<Character, IStructureElement<T>> elements;
|
||||
private final Map<String, String> shapes;
|
||||
private final Map<String, Set<Vec3Impl>> occupiedSpaces;
|
||||
|
||||
private Builder() {
|
||||
navigates = new HashMap<>();
|
||||
elements = new HashMap<>();
|
||||
shapes = new HashMap<>();
|
||||
occupiedSpaces = new HashMap<>();
|
||||
}
|
||||
|
||||
public Map<Character, IStructureElement<T>> getElements() {
|
||||
@@ -49,21 +53,25 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds shape
|
||||
* + is anything but air
|
||||
* - is air checks
|
||||
* space bar is skip
|
||||
* ~ is also skip (but marks controller position, optional and logically it is a space...)
|
||||
* rest needs to be defined
|
||||
* Adds shape. Shape is a two-dimensional string array. Each <b>character</b> inside any of these strings will
|
||||
* be later mapped to a particular type of {@link IStructureElement} as indicated by
|
||||
* {@link #addElement(Character, IStructureElement)}.
|
||||
* <p>
|
||||
* next char is next block(a)
|
||||
* next string is next line(b)
|
||||
* next string[] is next slice(c)
|
||||
* next char is next block(a) next string is next line(b) next string[] is next slice(c)
|
||||
* <p>
|
||||
* There are a few special reserved characters that are pre-mapped to some common structure elements
|
||||
* <ul>
|
||||
* <li>+ is anything but air</li>
|
||||
* <li>- is air checks</li>
|
||||
* <li>space bar is skip</li>
|
||||
* <li>~ is also skip (but marks controller position, not optional)</li>
|
||||
* <li>char {@code A000-FFFF} range is reserved for generated skips</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* char A000-FFFF range is reserved for generated skips
|
||||
*
|
||||
* @param name unlocalized/code name
|
||||
* @param structurePiece generated or written struct - DO NOT STORE IT ANYWHERE, or at least set them to null afterwards
|
||||
* @param structurePiece generated or written struct - DO NOT STORE IT ANYWHERE, or at least set them to null
|
||||
* afterwards
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder<T> addShape(String name, String[][] structurePiece) {
|
||||
@@ -80,22 +88,37 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
}
|
||||
builder.setLength(builder.length() - 1);
|
||||
}
|
||||
Set<Vec3Impl> occupiedSpace = new HashSet<>();
|
||||
// these track the global current location
|
||||
int aa = 0, bb = 0, cc = 0;
|
||||
// these track the vec3 towards next meaningful element
|
||||
int a = 0, b = 0, c = 0;
|
||||
// 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);
|
||||
if (ch == ' ' || ch == '~') {
|
||||
if (ch == ' ') {
|
||||
builder.setCharAt(i, A);
|
||||
ch = A;
|
||||
} else if (ch == '~') {
|
||||
builder.setCharAt(i, A);
|
||||
ch = A;
|
||||
occupiedSpace.add(Vec3Impl.getFromPool(aa, bb, cc));
|
||||
}
|
||||
if (ch == A) {
|
||||
aa++;
|
||||
a++;
|
||||
} else if (ch == B) {
|
||||
aa = 0;
|
||||
a = 0;
|
||||
bb++;
|
||||
b++;
|
||||
} else if (ch == C) {
|
||||
aa = 0;
|
||||
bb = 0;
|
||||
a = 0;
|
||||
b = 0;
|
||||
c++;
|
||||
cc++;
|
||||
} else if (a != 0 || b != 0 || c != 0) {
|
||||
Vec3Impl vec3 = new Vec3Impl(a, b, c);
|
||||
Character navigate = navigates.get(vec3);
|
||||
@@ -105,12 +128,19 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
addElement(navigate, step(vec3));
|
||||
}
|
||||
builder.setCharAt(i - 1, navigate);
|
||||
occupiedSpace.add(Vec3Impl.getFromPool(aa, bb, cc));
|
||||
aa++;
|
||||
a = 0;
|
||||
b = 0;
|
||||
c = 0;
|
||||
} else {
|
||||
occupiedSpace.add(Vec3Impl.getFromPool(aa, bb, cc));
|
||||
aa++;
|
||||
}
|
||||
}
|
||||
|
||||
occupiedSpaces.put(name, occupiedSpace);
|
||||
|
||||
String built = builder.toString().replaceAll("[\\uA000\\uB000\\uC000]", "");
|
||||
|
||||
if (built.contains("+")) {
|
||||
@@ -123,33 +153,42 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
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();
|
||||
if (StructureLibAPI.isDebugEnabled()) {
|
||||
return new StructureDefinition<>(new HashMap<>(elements), new HashMap<>(shapes), structures);
|
||||
} else {
|
||||
return structures::get;
|
||||
}
|
||||
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)));
|
||||
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()));
|
||||
throw new RuntimeException(
|
||||
"Missing Structure Element bindings for (chars as integers): "
|
||||
+ Arrays.toString(missing.toArray()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,22 +196,21 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
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)));
|
||||
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()));
|
||||
throw new RuntimeException(
|
||||
"Missing Structure Element bindings for (chars as integers): "
|
||||
+ Arrays.toString(missing.toArray()));
|
||||
}
|
||||
}
|
||||
|
||||
private Set<Integer> findMissing() {
|
||||
return shapes.values().stream()
|
||||
.flatMapToInt(CharSequence::chars)
|
||||
.filter(i -> !elements.containsKey((char) i))
|
||||
.boxed()
|
||||
.collect(Collectors.toSet());
|
||||
return shapes.values().stream().flatMapToInt(CharSequence::chars)
|
||||
.filter(i -> !elements.containsKey((char) i)).boxed().collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,4 +232,11 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
if (elements == null) throw new NoSuchElementException(name);
|
||||
return elements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContainedInStructure(String name, int offsetA, int offsetB, int offsetC) {
|
||||
Set<Vec3Impl> occupiedSpace = occupiedSpaces.get(name);
|
||||
if (occupiedSpace == null) throw new NoSuchElementException(name);
|
||||
return occupiedSpace.contains(new Vec3Impl(offsetA, offsetB, offsetC));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
* Internal bridge class for easing implementation
|
||||
*/
|
||||
abstract class StructureElement_Bridge<T> implements IStructureElement<T> {
|
||||
|
||||
// seal the deprecated method to prevent accidental overrides
|
||||
@Deprecated
|
||||
@Override
|
||||
public final PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s,
|
||||
EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
|
||||
return survivalPlaceBlock(t, world, x, y, z, trigger, AutoPlaceEnvironment.fromLegacy(s, actor, chatter));
|
||||
}
|
||||
|
||||
// clear the default implementation. we don't need that.
|
||||
public abstract PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
+29
-15
@@ -1,34 +1,48 @@
|
||||
package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import com.gtnewhorizon.structurelib.structure.IStructureElement.PlaceResult;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.structure.IStructureElement.PlaceResult;
|
||||
|
||||
class SurvivalBuildStructureWalker<T> implements IStructureWalker<T> {
|
||||
private final T object;
|
||||
private final ItemStack trigger;
|
||||
private final IItemSource source;
|
||||
private final EntityPlayerMP actor;
|
||||
|
||||
final T object;
|
||||
final ItemStack trigger;
|
||||
private final int elementBudget;
|
||||
private final ISurvivalBuildEnvironment params;
|
||||
private final boolean check;
|
||||
private int built = -1;
|
||||
|
||||
public SurvivalBuildStructureWalker(
|
||||
T object, ItemStack trigger, IItemSource source, EntityPlayerMP actor, int elementBudget, boolean check) {
|
||||
private final AutoPlaceEnvironment env;
|
||||
|
||||
public SurvivalBuildStructureWalker(T object, ItemStack trigger, int elementBudget,
|
||||
ISurvivalBuildEnvironment params, IStructureDefinition<?> definition, String piece, ExtendedFacing facing,
|
||||
int[] baseOffsetABC, boolean check) {
|
||||
this.object = object;
|
||||
this.trigger = trigger;
|
||||
this.source = source;
|
||||
this.actor = actor;
|
||||
this.elementBudget = elementBudget;
|
||||
this.params = params;
|
||||
this.check = check;
|
||||
|
||||
env = new AutoPlaceEnvironment(
|
||||
params.getActor(),
|
||||
params.getActor()::addChatComponentMessage,
|
||||
definition,
|
||||
piece,
|
||||
facing,
|
||||
baseOffsetABC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(IStructureElement<T> element, World world, int x, int y, int z) {
|
||||
PlaceResult placeResult = element.survivalPlaceBlock(
|
||||
object, world, x, y, z, trigger, source, actor, actor::addChatComponentMessage);
|
||||
public boolean visit(IStructureElement<T> element, World world, int x, int y, int z, int a, int b, int c) {
|
||||
env.offsetABC[0] = a;
|
||||
env.offsetABC[1] = b;
|
||||
env.offsetABC[2] = c;
|
||||
env.setSource(params.getSource());
|
||||
PlaceResult placeResult = element.survivalPlaceBlock(object, world, x, y, z, trigger, env);
|
||||
if (placeResult != PlaceResult.SKIP && built == -1) built = 0;
|
||||
switch (placeResult) {
|
||||
case SKIP:
|
||||
@@ -37,7 +51,7 @@ class SurvivalBuildStructureWalker<T> implements IStructureWalker<T> {
|
||||
if (check) element.check(object, world, x, y, z);
|
||||
return ++built < elementBudget;
|
||||
case REJECT:
|
||||
StructureLibAPI.markHintParticleError(actor, world, x, y, z);
|
||||
StructureLibAPI.markHintParticleError(params.getActor(), world, x, y, z);
|
||||
return false;
|
||||
case ACCEPT_STOP:
|
||||
if (check) element.check(object, world, x, y, z);
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.gtnewhorizon.structurelib.structure.adders;
|
||||
import net.minecraft.block.Block;
|
||||
|
||||
public interface IBlockAdder<T> {
|
||||
|
||||
/**
|
||||
* Callback on block added, needs to check if block is valid (and add it)
|
||||
*
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.gtnewhorizon.structurelib.structure.adders;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
||||
public interface ITileAdder<T> {
|
||||
|
||||
/**
|
||||
* Callback to add hatch, needs to check if tile is valid (and add it)
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* This package provide support for multiblock structure checking.
|
||||
* <p>
|
||||
* All public stuff in this package and its subpackages are considered part of the public API.
|
||||
* Backwards compatibility is maintained to the maximum extend possible.
|
||||
* All public stuff in this package and its subpackages are considered part of the public API. Backwards compatibility
|
||||
* is maintained to the maximum extend possible.
|
||||
*/
|
||||
package com.gtnewhorizon.structurelib.structure;
|
||||
@@ -2,10 +2,12 @@ package com.gtnewhorizon.structurelib.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public class InventoryIterable<Inv extends IInventory> implements Iterable<ItemStack> {
|
||||
|
||||
private final Inv inv;
|
||||
private final int maxSlot;
|
||||
|
||||
@@ -25,6 +27,7 @@ public class InventoryIterable<Inv extends IInventory> implements Iterable<ItemS
|
||||
@Override
|
||||
public Iterator<ItemStack> iterator() {
|
||||
return new Iterator<ItemStack>() {
|
||||
|
||||
private int ptr = 0;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,32 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2022, glee8e
|
||||
* This file is part of StructureLib.
|
||||
* Copyright (c) 2022, glee8e This file is part of StructureLib.
|
||||
* <p>
|
||||
* StructureLib is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
* StructureLib is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General
|
||||
* Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any
|
||||
* later version.
|
||||
* <p>
|
||||
* StructureLib is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* StructureLib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
* details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Foobar; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* You should have received a copy of the GNU Lesser General Public License along with Foobar; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.gtnewhorizon.structurelib.util;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap;
|
||||
import com.gtnewhorizon.structurelib.util.InventoryUtility.ItemStackExtractor.APIType;
|
||||
import com.gtnewhorizon.structurelib.util.ItemStackPredicate.NBTMode;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.init.Items;
|
||||
@@ -34,10 +29,15 @@ import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.InventoryEnderChest;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap;
|
||||
import com.gtnewhorizon.structurelib.util.InventoryUtility.ItemStackExtractor.APIType;
|
||||
import com.gtnewhorizon.structurelib.util.ItemStackPredicate.NBTMode;
|
||||
|
||||
/**
|
||||
* This class is part of API, but is not stable. Use at your own risk.
|
||||
*/
|
||||
public class InventoryUtility {
|
||||
|
||||
private static final SortedRegistry<ItemStackExtractor> stackExtractors = new SortedRegistry<>();
|
||||
private static final List<Predicate<? super EntityPlayerMP>> enableEnder = new CopyOnWriteArrayList<>();
|
||||
/**
|
||||
@@ -47,6 +47,7 @@ public class InventoryUtility {
|
||||
|
||||
static {
|
||||
inventoryProviders.register("5000-main-inventory", new InventoryProvider<InventoryIterable<InventoryPlayer>>() {
|
||||
|
||||
@Override
|
||||
public InventoryIterable<InventoryPlayer> getInventory(EntityPlayerMP player) {
|
||||
return new InventoryIterable<>(player.inventory, player.inventory.mainInventory.length);
|
||||
@@ -59,8 +60,9 @@ public class InventoryUtility {
|
||||
inv.getInventory().player.inventoryContainer.detectAndSendChanges();
|
||||
}
|
||||
});
|
||||
inventoryProviders.register(
|
||||
"7000-ender-inventory", new InventoryProvider<InventoryIterable<InventoryEnderChest>>() {
|
||||
inventoryProviders
|
||||
.register("7000-ender-inventory", new InventoryProvider<InventoryIterable<InventoryEnderChest>>() {
|
||||
|
||||
@Override
|
||||
public InventoryIterable<InventoryEnderChest> getInventory(EntityPlayerMP player) {
|
||||
if (enableEnder.stream().anyMatch(p -> p.test(player)))
|
||||
@@ -86,8 +88,8 @@ public class InventoryUtility {
|
||||
stackExtractors.register(key, val);
|
||||
}
|
||||
|
||||
public static <Inv extends IInventory> void registerStackExtractor(
|
||||
String key, Function<ItemStack, ? extends Inv> extractor) {
|
||||
public static <Inv extends IInventory> void registerStackExtractor(String key,
|
||||
Function<ItemStack, ? extends Inv> extractor) {
|
||||
registerStackExtractor(key, newItemStackProvider(extractor));
|
||||
}
|
||||
|
||||
@@ -95,8 +97,8 @@ public class InventoryUtility {
|
||||
inventoryProviders.register(key, val);
|
||||
}
|
||||
|
||||
public static <Inv extends IInventory> void registerInventoryProvider(
|
||||
String key, Function<EntityPlayerMP, ? extends Inv> extractor) {
|
||||
public static <Inv extends IInventory> void registerInventoryProvider(String key,
|
||||
Function<EntityPlayerMP, ? extends Inv> extractor) {
|
||||
registerInventoryProvider(key, newInventoryProvider(extractor));
|
||||
}
|
||||
|
||||
@@ -107,6 +109,7 @@ public class InventoryUtility {
|
||||
public static <Inv extends IInventory> InventoryProvider<InventoryIterable<Inv>> newInventoryProvider(
|
||||
Function<EntityPlayerMP, ? extends Inv> extractor) {
|
||||
return new InventoryProvider<InventoryIterable<Inv>>() {
|
||||
|
||||
@Override
|
||||
public InventoryIterable<Inv> getInventory(EntityPlayerMP player) {
|
||||
Inv inv = extractor.apply(player);
|
||||
@@ -122,24 +125,26 @@ public class InventoryUtility {
|
||||
|
||||
public static ItemStackExtractor newItemStackProvider(Function<ItemStack, ? extends IInventory> extractor) {
|
||||
return new ItemStackExtractor() {
|
||||
|
||||
@Override
|
||||
public boolean isAPIImplemented(APIType type) {
|
||||
return type == APIType.MAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int takeFromStack(
|
||||
Predicate<ItemStack> predicate,
|
||||
boolean simulate,
|
||||
int count,
|
||||
ItemStackCounter store,
|
||||
ItemStack stack,
|
||||
ItemStack filter,
|
||||
EntityPlayerMP player) {
|
||||
public int takeFromStack(Predicate<ItemStack> predicate, boolean simulate, int count,
|
||||
ItemStackCounter store, ItemStack stack, ItemStack filter, EntityPlayerMP player) {
|
||||
IInventory inv = extractor.apply(stack);
|
||||
if (inv == null) return 0;
|
||||
int found = takeFromInventory(
|
||||
new InventoryIterable<>(inv), predicate, simulate, count, store, filter, player, false);
|
||||
new InventoryIterable<>(inv),
|
||||
predicate,
|
||||
simulate,
|
||||
count,
|
||||
store,
|
||||
filter,
|
||||
player,
|
||||
false);
|
||||
if (found > 0) inv.markDirty();
|
||||
return found;
|
||||
}
|
||||
@@ -147,8 +152,8 @@ public class InventoryUtility {
|
||||
}
|
||||
|
||||
/**
|
||||
* take count amount of stacks that matches given filter. might take partial amount of stuff, so simulation is suggested
|
||||
* if you ever need to take more than one.
|
||||
* take count amount of stacks that matches given filter. might take partial amount of stuff, so simulation is
|
||||
* suggested if you ever need to take more than one.
|
||||
*
|
||||
* @param player source of stacks
|
||||
* @param predicate item stack filter
|
||||
@@ -156,8 +161,8 @@ public class InventoryUtility {
|
||||
* @param count let's hope int size is enough...
|
||||
* @return amount taken. never negative nor bigger than count...
|
||||
*/
|
||||
public static Map<ItemStack, Integer> takeFromInventory(
|
||||
EntityPlayerMP player, Predicate<ItemStack> predicate, boolean simulate, int count) {
|
||||
public static Map<ItemStack, Integer> takeFromInventory(EntityPlayerMP player, Predicate<ItemStack> predicate,
|
||||
boolean simulate, int count) {
|
||||
ItemStackCounterImpl store = new ItemStackCounterImpl();
|
||||
int sum = 0;
|
||||
for (InventoryProvider<?> provider : inventoryProviders) {
|
||||
@@ -168,8 +173,8 @@ public class InventoryUtility {
|
||||
}
|
||||
|
||||
/**
|
||||
* take count amount of stacks that matches given filter. might take partial amount of stuff, so simulation is suggested
|
||||
* if you ever need to take more than one.
|
||||
* take count amount of stacks that matches given filter. might take partial amount of stuff, so simulation is
|
||||
* suggested if you ever need to take more than one.
|
||||
*
|
||||
* @param player source of stacks
|
||||
* @param filter the precise type of item to extract. stackSize matters
|
||||
@@ -189,14 +194,9 @@ public class InventoryUtility {
|
||||
}
|
||||
|
||||
// workaround java generics issue
|
||||
private static <R extends Iterable<ItemStack>> int takeFromPlayer(
|
||||
EntityPlayerMP player,
|
||||
Predicate<ItemStack> predicate,
|
||||
boolean simulate,
|
||||
int count,
|
||||
ItemStackCounterImpl store,
|
||||
InventoryProvider<R> provider,
|
||||
ItemStack filter) {
|
||||
private static <R extends Iterable<ItemStack>> int takeFromPlayer(EntityPlayerMP player,
|
||||
Predicate<ItemStack> predicate, boolean simulate, int count, ItemStackCounterImpl store,
|
||||
InventoryProvider<R> provider, ItemStack filter) {
|
||||
R inv = provider.getInventory(player);
|
||||
if (inv == null) return 0;
|
||||
int taken = takeFromInventory(inv, predicate, simulate, count, store, filter, player, true);
|
||||
@@ -215,29 +215,23 @@ public class InventoryUtility {
|
||||
* @param recursive do recursive lookup using {@link #getStackExtractors() stack extractors}
|
||||
* @return amount taken. never negative nor bigger than count...
|
||||
*/
|
||||
public static Map<ItemStack, Integer> takeFromInventory(
|
||||
Iterable<ItemStack> inv, Predicate<ItemStack> predicate, boolean simulate, int count, boolean recursive) {
|
||||
public static Map<ItemStack, Integer> takeFromInventory(Iterable<ItemStack> inv, Predicate<ItemStack> predicate,
|
||||
boolean simulate, int count, boolean recursive) {
|
||||
ItemStackCounterImpl store = new ItemStackCounterImpl();
|
||||
takeFromInventory(inv, predicate, simulate, count, store, null, null, recursive);
|
||||
return store.getStore();
|
||||
}
|
||||
|
||||
private static int takeFromInventory(
|
||||
@Nonnull Iterable<ItemStack> inv,
|
||||
@Nonnull Predicate<ItemStack> predicate,
|
||||
boolean simulate,
|
||||
int count,
|
||||
@Nonnull ItemStackCounter store,
|
||||
@Nullable ItemStack filter,
|
||||
@Nullable EntityPlayerMP player,
|
||||
boolean recursive) {
|
||||
private static int takeFromInventory(@Nonnull Iterable<ItemStack> inv, @Nonnull Predicate<ItemStack> predicate,
|
||||
boolean simulate, int count, @Nonnull ItemStackCounter store, @Nullable ItemStack filter,
|
||||
@Nullable EntityPlayerMP player, boolean recursive) {
|
||||
int found = 0;
|
||||
ItemStack copiedFilter = null;
|
||||
if (filter != null) {
|
||||
copiedFilter = new ItemStack(filter.getItem(), filter.stackSize, Items.feather.getDamage(filter));
|
||||
copiedFilter.setTagCompound(filter.stackTagCompound);
|
||||
}
|
||||
for (Iterator<ItemStack> iterator = inv.iterator(); iterator.hasNext(); ) {
|
||||
for (Iterator<ItemStack> iterator = inv.iterator(); iterator.hasNext();) {
|
||||
ItemStack stack = iterator.next();
|
||||
// invalid stack
|
||||
if (stack == null || stack.getItem() == null || stack.stackSize <= 0) continue;
|
||||
@@ -272,9 +266,10 @@ public class InventoryUtility {
|
||||
}
|
||||
|
||||
public interface OptimizedExtractor {
|
||||
|
||||
/**
|
||||
* Extract a particular type of item. The extractor can choose to not return all items contained within this item
|
||||
* as long as it makes sense, but the author should inform the player of this.
|
||||
* Extract a particular type of item. The extractor can choose to not return all items contained within this
|
||||
* item as long as it makes sense, but the author should inform the player of this.
|
||||
* <p>
|
||||
* Whether optimized extractor do recursive extraction is at the discretion of implementor.
|
||||
*
|
||||
@@ -288,12 +283,14 @@ public class InventoryUtility {
|
||||
}
|
||||
|
||||
public interface InventoryProvider<R extends Iterable<ItemStack>> {
|
||||
|
||||
R getInventory(EntityPlayerMP player);
|
||||
|
||||
void markDirty(R inv);
|
||||
}
|
||||
|
||||
public interface ItemStackExtractor {
|
||||
|
||||
enum APIType {
|
||||
MAIN,
|
||||
EXTRACT_ONE_STACK,
|
||||
@@ -302,13 +299,13 @@ public class InventoryUtility {
|
||||
boolean isAPIImplemented(APIType type);
|
||||
|
||||
/**
|
||||
* Extract a particular type of item. The extractor can choose to not return all items contained within this item
|
||||
* as long as it makes sense, but the author should inform the player of this.
|
||||
* Extract a particular type of item. The extractor can choose to not return all items contained within this
|
||||
* item as long as it makes sense, but the author should inform the player of this.
|
||||
* <p>
|
||||
* Whether this method does recursive extraction is at the discretion of implementor.
|
||||
*
|
||||
* @param predicate the main filtering predicate. never null. It's assumed predicate always returns true on filter,
|
||||
* if that is not null
|
||||
* @param predicate the main filtering predicate. never null. It's assumed predicate always returns true on
|
||||
* filter, if that is not null
|
||||
* @param store where to store extracted items. Should increment the
|
||||
* @param source from where an extraction should be attempted
|
||||
* @param filter stack to extract. should not be mutated! match the NBT tag using EXACT mode. might be null.
|
||||
@@ -316,18 +313,12 @@ public class InventoryUtility {
|
||||
* @param player executor of extraction, or null if from a machine
|
||||
* @return amount extracted, or -1 if this is not implemented
|
||||
*/
|
||||
int takeFromStack(
|
||||
Predicate<ItemStack> predicate,
|
||||
boolean simulate,
|
||||
int count,
|
||||
ItemStackCounter store,
|
||||
ItemStack source,
|
||||
ItemStack filter,
|
||||
EntityPlayerMP player);
|
||||
int takeFromStack(Predicate<ItemStack> predicate, boolean simulate, int count, ItemStackCounter store,
|
||||
ItemStack source, ItemStack filter, EntityPlayerMP player);
|
||||
|
||||
/**
|
||||
* Extract a particular type of item. The extractor can choose to not return all items contained within this item
|
||||
* as long as it makes sense, but the author should inform the player of this.
|
||||
* Extract a particular type of item. The extractor can choose to not return all items contained within this
|
||||
* item as long as it makes sense, but the author should inform the player of this.
|
||||
* <p>
|
||||
* Whether this method does recursive extraction is at the discretion of implementor.
|
||||
*
|
||||
@@ -343,20 +334,15 @@ public class InventoryUtility {
|
||||
|
||||
static ItemStackExtractor createOnlyOptimized(@Nonnull OptimizedExtractor optimizedExtractor) {
|
||||
return new ItemStackExtractor() {
|
||||
|
||||
@Override
|
||||
public boolean isAPIImplemented(APIType type) {
|
||||
return type == APIType.EXTRACT_ONE_STACK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int takeFromStack(
|
||||
Predicate<ItemStack> predicate,
|
||||
boolean simulate,
|
||||
int count,
|
||||
ItemStackCounter store,
|
||||
ItemStack stack,
|
||||
ItemStack filter,
|
||||
EntityPlayerMP player) {
|
||||
public int takeFromStack(Predicate<ItemStack> predicate, boolean simulate, int count,
|
||||
ItemStackCounter store, ItemStack stack, ItemStack filter, EntityPlayerMP player) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -369,6 +355,7 @@ public class InventoryUtility {
|
||||
}
|
||||
|
||||
public interface ItemStackCounter {
|
||||
|
||||
/**
|
||||
* Add some amount of stack. Note stackSize is used instead of stack.stackSize.
|
||||
*/
|
||||
@@ -376,6 +363,7 @@ public class InventoryUtility {
|
||||
}
|
||||
|
||||
private static class ItemStackCounterImpl implements ItemStackCounter {
|
||||
|
||||
private final Map<ItemStack, Integer> store = new ItemStackMap<>(true);
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.gtnewhorizon.structurelib.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public class ItemStackArrayIterable implements Iterable<ItemStack> {
|
||||
|
||||
private final ItemStack[] stacks;
|
||||
|
||||
public ItemStackArrayIterable(ItemStack[] stacks) {
|
||||
@@ -17,6 +19,7 @@ public class ItemStackArrayIterable implements Iterable<ItemStack> {
|
||||
@Override
|
||||
public Iterator<ItemStack> iterator() {
|
||||
return new Iterator<ItemStack>() {
|
||||
|
||||
private int ptr = 0;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.gtnewhorizon.structurelib.util;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.Item;
|
||||
@@ -11,6 +12,7 @@ import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
public final class ItemStackPredicate implements Predicate<ItemStack> {
|
||||
|
||||
public static ItemStackPredicate from(Item item) {
|
||||
return new ItemStackPredicate(item);
|
||||
}
|
||||
@@ -20,8 +22,7 @@ public final class ItemStackPredicate implements Predicate<ItemStack> {
|
||||
}
|
||||
|
||||
public static ItemStackPredicate from(ItemStack itemStack, NBTMode mode) {
|
||||
return new ItemStackPredicate(itemStack.getItem())
|
||||
.setMeta(Items.feather.getDamage(itemStack))
|
||||
return new ItemStackPredicate(itemStack.getItem()).setMeta(Items.feather.getDamage(itemStack))
|
||||
.setTag(mode, itemStack.stackTagCompound);
|
||||
}
|
||||
|
||||
@@ -63,13 +64,16 @@ public final class ItemStackPredicate implements Predicate<ItemStack> {
|
||||
}
|
||||
|
||||
public enum NBTMode implements BiPredicate<NBTTagCompound, NBTTagCompound> {
|
||||
|
||||
IGNORE {
|
||||
|
||||
@Override
|
||||
public boolean test(NBTTagCompound lhs, NBTTagCompound rhs) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
IN {
|
||||
|
||||
@Override
|
||||
public boolean test(NBTTagCompound lhs, NBTTagCompound rhs) {
|
||||
if (lhs == null || lhs.hasNoTags()) return true;
|
||||
@@ -87,6 +91,7 @@ public final class ItemStackPredicate implements Predicate<ItemStack> {
|
||||
}
|
||||
},
|
||||
EXACT {
|
||||
|
||||
@Override
|
||||
public boolean test(NBTTagCompound lhs, NBTTagCompound rhs) {
|
||||
if (lhs != null && lhs.hasNoTags()) lhs = null;
|
||||
@@ -95,6 +100,7 @@ public final class ItemStackPredicate implements Predicate<ItemStack> {
|
||||
}
|
||||
},
|
||||
IGNORE_KNOWN_INSIGNIFICANT_TAGS {
|
||||
|
||||
@Override
|
||||
public boolean test(NBTTagCompound lhs, NBTTagCompound rhs) {
|
||||
// fast path for empty tags
|
||||
@@ -105,8 +111,8 @@ public final class ItemStackPredicate implements Predicate<ItemStack> {
|
||||
return EXACT.test(lhs, rhs);
|
||||
}
|
||||
};
|
||||
private static final String[] KNOWN_INSIGNIFICANT_TAGS = {
|
||||
"display", // TODO expand/refine this
|
||||
|
||||
private static final String[] KNOWN_INSIGNIFICANT_TAGS = { "display", // TODO expand/refine this
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
package com.gtnewhorizon.structurelib.util;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
/**
|
||||
* not related to a certain mod!
|
||||
*/
|
||||
public class MiscUtils {
|
||||
|
||||
private MiscUtils() {}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class SortedRegistry<V> implements Iterable<V> {
|
||||
|
||||
private final NavigableMap<String, V> store = new TreeMap<>();
|
||||
/**
|
||||
* Store stuff in an array for faster iteration access than a red black tree
|
||||
|
||||
@@ -1,14 +1,28 @@
|
||||
package com.gtnewhorizon.structurelib.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.dispenser.IPosition;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
public class Vec3Impl implements Comparable<Vec3Impl> {
|
||||
|
||||
public static final Vec3Impl NULL_VECTOR = new Vec3Impl(0, 0, 0);
|
||||
private static final Map<Vec3Impl, Vec3Impl> pool = new HashMap<>();
|
||||
private final int val0;
|
||||
private final int val1;
|
||||
private final int val2;
|
||||
|
||||
/**
|
||||
* THIS WILL CAUSE THIS VECTOR TO PERMANENTLY RESIDE IN STATIC MEMORY. DO NOT USE THIS UNLESS YOU KNOW WHAT YOU ARE
|
||||
* DOING!!!
|
||||
*/
|
||||
public static Vec3Impl getFromPool(int in0, int in1, int in2) {
|
||||
return pool.computeIfAbsent(new Vec3Impl(in0, in1, in2), Function.identity());
|
||||
}
|
||||
|
||||
public Vec3Impl(int in0, int in1, int in2) {
|
||||
this.val0 = in0;
|
||||
this.val1 = in1;
|
||||
@@ -57,8 +71,7 @@ public class Vec3Impl implements Comparable<Vec3Impl> {
|
||||
}
|
||||
|
||||
public Vec3Impl offset(ForgeDirection facing, int n) {
|
||||
return n == 0
|
||||
? this
|
||||
return n == 0 ? this
|
||||
: new Vec3Impl(val0 + facing.offsetX * n, val1 + facing.offsetY * n, val2 + facing.offsetZ * n);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,37 +1,20 @@
|
||||
package com.gtnewhorizon.structurelib.util;
|
||||
/*
|
||||
A subclass of java.util.random that implements the Xorshift random number
|
||||
generator
|
||||
<p>
|
||||
- it is 30% faster than the generator from Java's library - it produces
|
||||
random sequences of higher quality than java.util.Random - this class also
|
||||
provides a clone() function
|
||||
<p>
|
||||
Usage: XSRandom rand = new XSRandom(); //Instantiation x = rand.nextInt();
|
||||
//pull a random number
|
||||
<p>
|
||||
To use the class in legacy code, you may also instantiate an XSRandom object
|
||||
and assign it to a java.util.Random object: java.util.Random rand = new
|
||||
XSRandom();
|
||||
<p>
|
||||
for an explanation of the algorithm, see
|
||||
http://demesos.blogspot.com/2011/09/pseudo-random-number-generators.html
|
||||
|
||||
@author Wilfried Elmenreich University of Klagenfurt/Lakeside Labs
|
||||
* http://www.elmenreich.tk
|
||||
* <p>
|
||||
* This code is released under the GNU Lesser General Public License Version 3
|
||||
* http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
*/
|
||||
* A subclass of java.util.random that implements the Xorshift random number generator <p> - it is 30% faster than the
|
||||
* generator from Java's library - it produces random sequences of higher quality than java.util.Random - this class
|
||||
* also provides a clone() function <p> Usage: XSRandom rand = new XSRandom(); //Instantiation x = rand.nextInt();
|
||||
* //pull a random number <p> To use the class in legacy code, you may also instantiate an XSRandom object and assign it
|
||||
* to a java.util.Random object: java.util.Random rand = new XSRandom(); <p> for an explanation of the algorithm, see
|
||||
* http://demesos.blogspot.com/2011/09/pseudo-random-number-generators.html
|
||||
* @author Wilfried Elmenreich University of Klagenfurt/Lakeside Labs http://www.elmenreich.tk <p> This code is released
|
||||
* under the GNU Lesser General Public License Version 3 http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
*/
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* XSTR - Xorshift ThermiteRandom
|
||||
* Modified by Bogdan-G
|
||||
* 03.06.2016
|
||||
* version 0.0.4
|
||||
* XSTR - Xorshift ThermiteRandom Modified by Bogdan-G 03.06.2016 version 0.0.4
|
||||
*/
|
||||
public class XSTR extends Random {
|
||||
|
||||
@@ -40,10 +23,11 @@ public class XSTR extends Random {
|
||||
private static final long GAMMA = 0x9e3779b97f4a7c15L;
|
||||
private static final int PROBE_INCREMENT = 0x9e3779b9;
|
||||
private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
|
||||
private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
|
||||
private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
|
||||
private static final float FLOAT_UNIT = 0x1.0p-24f; // 1.0f / (1 << 24)
|
||||
private static final AtomicLong seedUniquifier = new AtomicLong(8682522807148012L);
|
||||
public static final XSTR XSTR_INSTANCE = new XSTR() {
|
||||
|
||||
@Override
|
||||
public synchronized void setSeed(long seed) {
|
||||
if (!Thread.currentThread().getStackTrace()[2].getClassName().equals(Random.class.getName())) {
|
||||
@@ -53,13 +37,11 @@ public class XSTR extends Random {
|
||||
};
|
||||
|
||||
/*
|
||||
MODIFIED BY: Robotia
|
||||
Modification: Implemented Random class seed generator
|
||||
*/
|
||||
* MODIFIED BY: Robotia Modification: Implemented Random class seed generator
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new pseudo random number generator. The seed is initialized to
|
||||
* the current time, as if by
|
||||
* Creates a new pseudo random number generator. The seed is initialized to the current time, as if by
|
||||
* <code>setSeed(System.currentTimeMillis());</code>.
|
||||
*/
|
||||
public XSTR() {
|
||||
@@ -79,8 +61,8 @@ public class XSTR extends Random {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new pseudo random number generator, starting with the specified
|
||||
* seed, using <code>setSeed(seed);</code>.
|
||||
* Creates a new pseudo random number generator, starting with the specified seed, using
|
||||
* <code>setSeed(seed);</code>.
|
||||
*
|
||||
* @param seed the initial seed
|
||||
*/
|
||||
@@ -108,9 +90,8 @@ public class XSTR extends Random {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the seed for this pseudo random number generator. As described
|
||||
* above, two instances of the same random class, starting with the same
|
||||
* seed, produce the same results, if the same methods are called.
|
||||
* Sets the seed for this pseudo random number generator. As described above, two instances of the same random
|
||||
* class, starting with the same seed, produce the same results, if the same methods are called.
|
||||
*
|
||||
* @param seed the new seed
|
||||
*/
|
||||
@@ -128,9 +109,8 @@ public class XSTR extends Random {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of George Marsaglia's elegant Xorshift random generator
|
||||
* 30% faster and better quality than the built-in java.util.random see also
|
||||
* see http://www.javamex.com/tutorials/random_numbers/xorshift.shtml
|
||||
* Implementation of George Marsaglia's elegant Xorshift random generator 30% faster and better quality than the
|
||||
* built-in java.util.random see also see http://www.javamex.com/tutorials/random_numbers/xorshift.shtml
|
||||
*
|
||||
* @param nbits will shift nbits bits
|
||||
* @return next seed
|
||||
@@ -170,15 +150,14 @@ public class XSTR extends Random {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pseudorandom, uniformly distributed {@code int} value between 0
|
||||
* (inclusive) and the specified value (exclusive), drawn from this random
|
||||
* number generator's sequence. The general contract of {@code nextInt} is
|
||||
* that one {@code int} value in the specified range is pseudorandomly
|
||||
* generated and returned. All {@code bound} possible {@code int} values are
|
||||
* produced with (approximately) equal probability. The method
|
||||
* {@code nextInt(int bound)} is implemented by class {@code Random} as if
|
||||
* by:
|
||||
* <pre> {@code
|
||||
* Returns a pseudorandom, uniformly distributed {@code int} value between 0 (inclusive) and the specified value
|
||||
* (exclusive), drawn from this random number generator's sequence. The general contract of {@code nextInt} is that
|
||||
* one {@code int} value in the specified range is pseudorandomly generated and returned. All {@code bound} possible
|
||||
* {@code int} values are produced with (approximately) equal probability. The method {@code nextInt(int bound)} is
|
||||
* implemented by class {@code Random} as if by:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* public int nextInt(int bound) {
|
||||
* if (bound <= 0)
|
||||
* throw new IllegalArgumentException("bound must be positive");
|
||||
@@ -192,35 +171,29 @@ public class XSTR extends Random {
|
||||
* val = bits % bound;
|
||||
* } while (bits - val + (bound-1) < 0);
|
||||
* return val;
|
||||
* }}</pre>
|
||||
* }}
|
||||
* </pre>
|
||||
*
|
||||
* <p>The hedge "approx
|
||||
* imately" is used in the foregoing description only because the next
|
||||
* method is only approximately an unbiased source of independently chosen
|
||||
* bits. If it were a perfect source of randomly chosen bits, then the
|
||||
* algorithm shown would choose {@code int} values from the stated range
|
||||
* with perfect uniformity.
|
||||
* <p>
|
||||
* The algorithm is slightly tricky. It rejects values that would result in
|
||||
* an uneven distribution (due to the fact that 2^31 is not divisible by n).
|
||||
* The probability of a value being rejected depends on n. The worst case is
|
||||
* n=2^30+1, for which the probability of a reject is 1/2, and the expected
|
||||
* number of iterations before the loop terminates is 2.
|
||||
* The hedge "approx imately" is used in the foregoing description only because the next method is only
|
||||
* approximately an unbiased source of independently chosen bits. If it were a perfect source of randomly chosen
|
||||
* bits, then the algorithm shown would choose {@code int} values from the stated range with perfect uniformity.
|
||||
* <p>
|
||||
* The algorithm treats the case where n is a power of two specially: it
|
||||
* returns the correct number of high-order bits from the underlying
|
||||
* pseudo-random number generator. In the absence of special treatment, the
|
||||
* correct number of <i>low-order</i> bits would be returned. Linear
|
||||
* congruential pseudo-random number generators such as the one implemented
|
||||
* by this class are known to have short periods in the sequence of values
|
||||
* of their low-order bits. Thus, this special case greatly increases the
|
||||
* length of the sequence of values returned by successive calls to this
|
||||
* method if n is a small power of two.
|
||||
* The algorithm is slightly tricky. It rejects values that would result in an uneven distribution (due to the fact
|
||||
* that 2^31 is not divisible by n). The probability of a value being rejected depends on n. The worst case is
|
||||
* n=2^30+1, for which the probability of a reject is 1/2, and the expected number of iterations before the loop
|
||||
* terminates is 2.
|
||||
* <p>
|
||||
* The algorithm treats the case where n is a power of two specially: it returns the correct number of high-order
|
||||
* bits from the underlying pseudo-random number generator. In the absence of special treatment, the correct number
|
||||
* of <i>low-order</i> bits would be returned. Linear congruential pseudo-random number generators such as the one
|
||||
* implemented by this class are known to have short periods in the sequence of values of their low-order bits.
|
||||
* Thus, this special case greatly increases the length of the sequence of values returned by successive calls to
|
||||
* this method if n is a small power of two.
|
||||
*
|
||||
* @param bound the upper bound (exclusive). Must be positive.
|
||||
* @return the next pseudorandom, uniformly distributed {@code int} value
|
||||
* between zero (inclusive) and {@code bound} (exclusive) from this random
|
||||
* number generator's sequence
|
||||
* @return the next pseudorandom, uniformly distributed {@code int} value between zero (inclusive) and {@code bound}
|
||||
* (exclusive) from this random number generator's sequence
|
||||
* @throws IllegalArgumentException if bound is not positive
|
||||
* @since 1.2
|
||||
*/
|
||||
@@ -230,18 +203,10 @@ public class XSTR extends Random {
|
||||
// throw new RuntimeException("BadBound");
|
||||
// }
|
||||
|
||||
/*int r = next(31);
|
||||
int m = bound - 1;
|
||||
if ((bound & m) == 0) // i.e., bound is a power of 2
|
||||
{
|
||||
r = (int) ((bound * (long) r) >> 31);
|
||||
} else {
|
||||
for (int u = r;
|
||||
u - (r = u % bound) + m < 0;
|
||||
u = next(31))
|
||||
;
|
||||
}
|
||||
return r;*/
|
||||
/*
|
||||
* int r = next(31); int m = bound - 1; if ((bound & m) == 0) // i.e., bound is a power of 2 { r = (int) ((bound
|
||||
* * (long) r) >> 31); } else { for (int u = r; u - (r = u % bound) + m < 0; u = next(31)) ; } return r;
|
||||
*/
|
||||
// speedup, new nextInt ~+40%
|
||||
long last = seed ^ seed << 21;
|
||||
last ^= last >>> 35;
|
||||
@@ -269,10 +234,9 @@ public class XSTR extends Random {
|
||||
|
||||
@Override
|
||||
public void nextBytes(byte[] bytes_arr) {
|
||||
for (int iba = 0, lenba = bytes_arr.length; iba < lenba; ) {
|
||||
for (int rndba = nextInt(), nba = Math.min(lenba - iba, Integer.SIZE / Byte.SIZE);
|
||||
nba-- > 0;
|
||||
rndba >>= Byte.SIZE) {
|
||||
for (int iba = 0, lenba = bytes_arr.length; iba < lenba;) {
|
||||
for (int rndba = nextInt(), nba = Math.min(lenba - iba, Integer.SIZE / Byte.SIZE); nba--
|
||||
> 0; rndba >>= Byte.SIZE) {
|
||||
bytes_arr[iba++] = (byte) rndba;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
<!DOCTYPE html>
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>API Overview</TITLE>
|
||||
@@ -97,6 +97,18 @@ StructureLib API documentation.
|
||||
breaking client code.
|
||||
</p>
|
||||
|
||||
<h2>{@link com.gtnewhorizon.structurelib.StructureEvent}</h2>
|
||||
<p>
|
||||
This class is the base class of all events that will be posted while a IStructureDefinition are visited.
|
||||
These events are disabled by default, and can be enabled by calling {@link com.gtnewhorizon.structurelib.StructureLibAPI#enableInstrument(Object)}.
|
||||
To receive these events, register an event handler to {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS}.
|
||||
Handlers should filter the events received by {@link com.gtnewhorizon.structurelib.StructureEvent#getInstrumentIdentifier()}.
|
||||
</p>
|
||||
<p>
|
||||
<b>These events are intended for third party tools to inspect structure details.</b> Normal users should not use
|
||||
these at all.
|
||||
</p>
|
||||
|
||||
<h1>Important Concepts</h1>
|
||||
<h2>Context Object</h2>
|
||||
<p>
|
||||
@@ -207,9 +219,9 @@ whereas all these structure elements are designed without considering channels w
|
||||
<pre>
|
||||
import com.gtnewhorizon.structurelib.structure.IStructureElement;
|
||||
|
||||
public class MyHatchElement<T> implements IStructureElement<T> {
|
||||
public class MyHatchElement<T> implements IStructureElement<T> {
|
||||
//...
|
||||
@Override
|
||||
{@literal @}Override
|
||||
public PlaceResult survivalPlaceBlock(
|
||||
Object o,
|
||||
World world,
|
||||
@@ -231,5 +243,13 @@ public class MyHatchElement<T> implements IStructureElement<T> {
|
||||
|
||||
The code for placeBlock() and spawnHint() will be left as an exercise for the reader.
|
||||
|
||||
<h2>Instrumenting StructureLib</h2>
|
||||
<p>
|
||||
StructureLib support third party tools to poke into structure's internals via events. This is done by listening to {@link com.gtnewhorizon.structurelib.StructureEvent}
|
||||
and its subclasses on the {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS forge main event bus}.
|
||||
</p>
|
||||
<p>
|
||||
Please refer to {@link com.gtnewhorizon.structurelib.StructureEvent} to see what events are available.
|
||||
</p>
|
||||
</BODY>
|
||||
</HTML>
|
||||
@@ -28,7 +28,7 @@ item.structurelib.constructableTrigger.desc.3= (潜行右键可以直接完成
|
||||
item.structurelib.constructableTrigger.desc.4=此物品堆叠数量会影响显示的机器等级/模式/类型
|
||||
item.structurelib.constructableTrigger.desc.5=按下 §l[左SHIFT]§r 以显示子信道
|
||||
item.structurelib.constructableTrigger.desc.lshift.0=包含 %d 个子信道
|
||||
item.structurelib.constructableTrigger.too_fast=请在下一次自动搭建前等待%d毫秒...
|
||||
item.structurelib.constructableTrigger.too_fast=请在下一次自动搭建前等待 %d 毫秒...
|
||||
item.structurelib.constructableTrigger.gui.key=信道名:
|
||||
item.structurelib.constructableTrigger.gui.value=值:
|
||||
item.structurelib.constructableTrigger.gui.add=添加
|
||||
@@ -39,8 +39,9 @@ item.structurelib.constructableTrigger.gui.wipe=§4全部清空
|
||||
structurelib.autoplace.built_stat=已放置 %s 个方块
|
||||
structurelib.autoplace.complete=§a这个多方块结构已经完成自动搭建!
|
||||
structurelib.autoplace.error.not_enabled=§c这个多方块结构不支持在生存模式下自动搭建!
|
||||
structurelib.autoplace.error.no_simple_block=§c建议放置§r%s§c,但没有找到它
|
||||
structurelib.autoplace.error.no_item_stack=§c建议使用§r%s§c放置方块,但没有找到它
|
||||
structurelib.autoplace.error.no_simple_block=§c建议放置 §r%s§c ,但没有找到它
|
||||
structurelib.autoplace.error.no_item_stack=§c建议使用 §r%s§c 放置方块,但没有找到它
|
||||
structurelib.autoplace.warning.no_explicit_channel=§6这个结构依赖于不存在的子信道 §r%s§6 。已使用主信道值替代。
|
||||
|
||||
structurelib.blockhint.desc.0=帮助你搭建机器
|
||||
structurelib.blockhint.0.name=提示方块:1号
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.gtnewhorizon.structurelib.alignment.enumerable;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ExtendedFacingTest {
|
||||
|
||||
@Test
|
||||
void ensureGetWorldDirectionDoesNotCrashNorReturnNull() {
|
||||
for (ExtendedFacing ef : ExtendedFacing.VALUES) {
|
||||
for (ForgeDirection src : ForgeDirection.VALID_DIRECTIONS) {
|
||||
assertNotNull(ef.getWorldDirection(src));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void ensureGetWorldDirectionIsCorrect() {
|
||||
assertEquals(ForgeDirection.DOWN, ExtendedFacing.EAST_NORMAL_NONE.getWorldDirection(ForgeDirection.UP));
|
||||
assertEquals(ForgeDirection.DOWN, ExtendedFacing.NORTH_NORMAL_NONE.getWorldDirection(ForgeDirection.UP));
|
||||
assertEquals(ForgeDirection.NORTH, ExtendedFacing.NORTH_NORMAL_NONE.getWorldDirection(ForgeDirection.NORTH));
|
||||
assertEquals(ForgeDirection.NORTH, ExtendedFacing.NORTH_CLOCKWISE_NONE.getWorldDirection(ForgeDirection.NORTH));
|
||||
assertEquals(ForgeDirection.DOWN, ExtendedFacing.NORTH_CLOCKWISE_NONE.getWorldDirection(ForgeDirection.EAST));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user