Compare commits

..
12 Commits
Author SHA1 Message Date
Glease 33d377cea7 pull in buildscript changes 2022-03-02 00:32:50 +08:00
Glease da98b476b0 fix off by one overflow 2022-03-01 23:56:04 +08:00
Martin Robertz 9dd145bc67 Merge pull request #4 from iouter/master
Update zh_CN.lang
2022-02-07 18:13:46 +01:00
iouter 83b7c35ed1 Update zh_CN.lang 2022-02-05 00:06:12 +08:00
Glease bb0bebf3a2 add debug log on multi passing check 2022-01-19 18:47:13 +08:00
Jason Mitchell a49ed1996b maven publish buildscript update 2022-01-17 23:58:46 -08:00
Martin Robertz 6d5d31f5ab Merge pull request #3 from GTNewHorizons/GTNH-Colen-patch-1
QoL fix for item description
2022-01-02 12:32:48 +01:00
GTNH-Colen 3eafe426ba QoL fix for item description
This item will now show in NEI when schematic is searched, in line with old TT schematic. The description is also more grammatically correct (removed extra caps).
2022-01-02 08:58:49 +00:00
Glease eea5227fe3 Pull my onlyIf from GT++ 2021-12-22 21:20:27 +08:00
Glease 1f520cfd73 Add localization stuff I forgot 2021-12-22 21:17:47 +08:00
Martin Robertz 8357fdc826 ignore bat files 2021-12-02 23:44:16 +01:00
Johann Bernhardt 27bb7b2ad9 Update build script and CI 2021-11-30 17:58:54 +08:00
15 changed files with 681 additions and 207 deletions

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
# This is the universal Text Editor Configuration
# for all GTNewHorizons projects
# See: https://editorconfig.org/
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.{bat,ini}]
end_of_line = crlf
[*.{dtd,json,info,mcmeta,md,sh,svg,xml,xsd,xsl,yaml,yml}]
indent_size = 2
-9
View File
@@ -1,9 +0,0 @@
directory="run/crash-reports"
if [ -d $directory ]; then
echo "Crash reports detected:"
cat $directory/*
exit 1
else
echo "No crash reports detected"
exit 0
fi
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
# bashsupport disable=BP5006 # Global environment variables
RUNDIR="run" \
CRASH="crash-reports" \
SERVERLOG="server.log"
# enable nullglob to get 0 results when no match rather than the pattern
shopt -s nullglob
# store matches in array
crash_reports=("$RUNDIR/$CRASH/crash"*.txt)
# if array not empty there are crash_reports
if [ "${#crash_reports[@]}" -gt 0 ]; then
# get the latest crash_report from array
latest_crash_report="${crash_reports[-1]}"
{
printf 'Latest crash report detected %s:\n' "${latest_crash_report##*/}"
cat "$latest_crash_report"
} >&2
exit 1
fi
if grep --quiet --fixed-strings 'Fatal errors were detected' "$SERVERLOG"; then
{
printf 'Fatal errors detected:\n'
cat server.log
} >&2
exit 1
fi
if grep --quiet --fixed-strings 'The state engine was in incorrect state ERRORED and forced into state SERVER_STOPPED' \
"$SERVERLOG"; then
{
printf 'Server force stopped:'
cat server.log
} >&2
exit 1
fi
if ! grep --quiet --perl-regexp --only-matching '.+Done \(.+\)\! For help, type "help" or "\?"' "$SERVERLOG"; then
{
printf 'Server did not finish startup:'
cat server.log
} >&2
exit 1
fi
printf 'No crash reports detected'
exit 0
+10 -10
View File
@@ -14,32 +14,32 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set up JDK 8 - name: Set up JDK 8
uses: actions/setup-java@v2 uses: actions/setup-java@v2
with: with:
java-version: '8' java-version: '8'
distribution: 'adopt' distribution: 'adopt'
cache: gradle cache: gradle
- name: Grant execute permission for gradlew - name: Grant execute permission for gradlew
run: chmod +x gradlew run: chmod +x gradlew
- name: Setup the workspace - name: Setup the workspace
run: ./gradlew setupCIWorkspace run: ./gradlew setupCIWorkspace
- name: Build the mod - name: Build the mod
run: ./gradlew build run: ./gradlew build
- name: Run server for 1 minute - name: Run server for 1.5 minutes
run: | run: |
mkdir run mkdir run
echo "eula=true" > run/eula.txt echo "eula=true" > run/eula.txt
timeout 10 ./gradlew runServer || true timeout 90 ./gradlew runServer 2>&1 | tee -a server.log || true
- name: Test no crashes happend - name: Test no errors reported during server run
run: | run: |
chmod +x .github/scripts/test-no-crash-reports.sh chmod +x .github/scripts/test_no_error_reports
.github/scripts/test-no-crash-reports.sh .github/scripts/test_no_error_reports
-44
View File
@@ -1,44 +0,0 @@
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Release latest build
on:
push:
branches: [ master, main ]
jobs:
build-and-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set release version
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Set up JDK 8
uses: actions/setup-java@v2
with:
java-version: '8'
distribution: 'adopt'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Setup the workspace
run: ./gradlew setupCIWorkspace
- name: Build the mod
run: ./gradlew build
- name: Update latest tag
uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "latest"
prerelease: false
title: "Latest build"
files: build/libs/*.jar
+6
View File
@@ -43,3 +43,9 @@ jobs:
prerelease: false prerelease: false
title: "${{ env.RELEASE_VERSION }}" title: "${{ env.RELEASE_VERSION }}"
files: build/libs/*.jar files: build/libs/*.jar
- name: Publish to Maven
run: ./gradlew publish
env:
MAVEN_USER: ${{ secrets.MAVEN_USER }}
MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
+1
View File
@@ -26,3 +26,4 @@ whitelist.json
*.ipr *.ipr
*.iws *.iws
src/main/resources/mixins.*.json src/main/resources/mixins.*.json
*.bat
+3
View File
@@ -0,0 +1,3 @@
# Any Github changes require admin approval
/.github/** @GTNewHorizons/admin
+356 -131
View File
@@ -1,49 +1,64 @@
//version: 4f3d1b46cf51f9d4ded5379b5d817a2a6f6b302d //version: 1644894948
/* /*
DO NOT CHANGE THIS FILE! DO NOT CHANGE THIS FILE!
Also, you may replace this file at any time if there is an update available. Also, you may replace this file at any time if there is an update available.
Please check https://github.com/SinTh0r4s/ExampleMod1.7.10/blob/main/build.gradle for updates. Please check https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/build.gradle for updates.
*/ */
import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.internal.logging.text.StyledTextOutput.Style
import org.gradle.internal.logging.text.StyledTextOutputFactory
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
buildscript { buildscript {
repositories { repositories {
maven { maven {
name = "forge" name 'forge'
url = "https://maven.minecraftforge.net" url 'https://maven.minecraftforge.net'
} }
maven { maven {
name = "sonatype" name 'sonatype'
url = "https://oss.sonatype.org/content/repositories/snapshots/" url 'https://oss.sonatype.org/content/repositories/snapshots/'
} }
maven { maven {
name = "Scala CI dependencies" name 'Scala CI dependencies'
url = "https://repo1.maven.org/maven2/" url 'https://repo1.maven.org/maven2/'
} }
maven { maven {
name = "jitpack" name 'jitpack'
url = "https://jitpack.io" url 'https://jitpack.io'
} }
} }
dependencies { dependencies {
classpath 'com.github.GTNewHorizons:ForgeGradle:1.2.4' classpath 'com.github.GTNewHorizons:ForgeGradle:1.2.7'
} }
} }
plugins { plugins {
id 'java-library'
id 'idea' id 'idea'
id 'eclipse'
id 'scala' id 'scala'
id("org.ajoberstar.grgit") version("3.1.1") id 'maven-publish'
id("com.github.johnrengelman.shadow") version("4.0.4") id 'org.jetbrains.kotlin.jvm' version '1.5.30' apply false
id("com.palantir.git-version") version("0.12.3") id 'org.jetbrains.kotlin.kapt' version '1.5.30' apply false
id 'org.ajoberstar.grgit' version '4.1.1'
id 'com.github.johnrengelman.shadow' version '4.0.4'
id 'com.palantir.git-version' version '0.13.0' apply false
id 'de.undercouch.download' version '5.0.1'
id 'com.github.gmazzo.buildconfig' version '3.0.3' apply false
} }
if (project.file('.git/HEAD').isFile()) {
apply plugin: 'com.palantir.git-version'
}
def out = services.get(StyledTextOutputFactory).create('an-output')
apply plugin: 'forge' apply plugin: 'forge'
def projectJavaVersion = JavaLanguageVersion.of(8) def projectJavaVersion = JavaLanguageVersion.of(8)
@@ -62,6 +77,10 @@ idea {
} }
} }
if(JavaVersion.current() != JavaVersion.VERSION_1_8) {
throw new GradleException("This project requires Java 8, but it's running on " + JavaVersion.current())
}
checkPropertyExists("modName") checkPropertyExists("modName")
checkPropertyExists("modId") checkPropertyExists("modId")
checkPropertyExists("modGroup") checkPropertyExists("modGroup")
@@ -83,33 +102,31 @@ checkPropertyExists("containsMixinsAndOrCoreModOnly")
checkPropertyExists("usesShadowedDependencies") checkPropertyExists("usesShadowedDependencies")
checkPropertyExists("developmentEnvironmentUserName") checkPropertyExists("developmentEnvironmentUserName")
def checkPropertyExists(String propertyName) { boolean noPublishedSources = project.findProperty("noPublishedSources") ? project.noPublishedSources.toBoolean() : false
if (project.hasProperty(propertyName) == false) {
throw new GradleException("This project requires a property \"" + propertyName + "\"! Please add it your \"gradle.properties\". You can find all properties and their description here: https://github.com/SinTh0r4s/ExampleMod1.7.10/blob/main/gradle.properties")
}
}
String javaSourceDir = "src/main/java/" String javaSourceDir = "src/main/java/"
String scalaSourceDir = "src/main/scala/" String scalaSourceDir = "src/main/scala/"
String kotlinSourceDir = "src/main/kotlin/"
String targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") String targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/")
String targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") String targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/")
if((new File(targetPackageJava).exists() || new File(targetPackageScala).exists()) == false) { String targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/")
throw new GradleException("Could not resolve \"modGroup\"! Could not find " + targetPackageJava + " or " + targetPackageScala) if(!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) {
throw new GradleException("Could not resolve \"modGroup\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin)
} }
if(apiPackage) { if(apiPackage) {
targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/")
targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/")
if((new File(targetPackageJava).exists() || new File(targetPackageScala).exists()) == false) { targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/")
throw new GradleException("Could not resolve \"apiPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala) if(!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) {
throw new GradleException("Could not resolve \"apiPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin)
} }
} }
if(accessTransformersFile) { if(accessTransformersFile) {
String targetFile = "src/main/resources/META-INF/" + accessTransformersFile String targetFile = "src/main/resources/META-INF/" + accessTransformersFile
if(new File(targetFile).exists() == false) { if(!getFile(targetFile).exists()) {
throw new GradleException("Could not resolve \"accessTransformersFile\"! Could not find " + targetFile) throw new GradleException("Could not resolve \"accessTransformersFile\"! Could not find " + targetFile)
} }
} }
@@ -121,15 +138,17 @@ if(usesMixins.toBoolean()) {
targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/") targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/")
targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/") targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/")
if((new File(targetPackageJava).exists() || new File(targetPackageScala).exists()) == false) { targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/")
throw new GradleException("Could not resolve \"mixinsPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala) if(!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) {
throw new GradleException("Could not resolve \"mixinsPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin)
} }
String targetFileJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".java" String targetFileJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".java"
String targetFileScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".scala" String targetFileScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".scala"
String targetFileScalaJava = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".java" String targetFileScalaJava = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".java"
if((new File(targetFileJava).exists() || new File(targetFileScala).exists() || new File(targetFileScalaJava).exists()) == false) { String targetFileKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".kt"
throw new GradleException("Could not resolve \"mixinPlugin\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava) if(!(getFile(targetFileJava).exists() || getFile(targetFileScala).exists() || getFile(targetFileScalaJava).exists() || getFile(targetFileKotlin).exists())) {
throw new GradleException("Could not resolve \"mixinPlugin\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava + " or " + targetFileKotlin)
} }
} }
@@ -137,8 +156,9 @@ if(coreModClass) {
String targetFileJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".java" String targetFileJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".java"
String targetFileScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".scala" String targetFileScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".scala"
String targetFileScalaJava = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".java" String targetFileScalaJava = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".java"
if((new File(targetFileJava).exists() || new File(targetFileScala).exists() || new File(targetFileScalaJava).exists()) == false) { String targetFileKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".kt"
throw new GradleException("Could not resolve \"coreModClass\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava) if(!(getFile(targetFileJava).exists() || getFile(targetFileScala).exists() || getFile(targetFileScalaJava).exists() || getFile(targetFileKotlin).exists())) {
throw new GradleException("Could not resolve \"coreModClass\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava + " or " + targetFileKotlin)
} }
} }
@@ -151,15 +171,64 @@ configurations.all {
} }
// Fix Jenkins' Git: chmod a file should not be detected as a change and append a '.dirty' to the version // Fix Jenkins' Git: chmod a file should not be detected as a change and append a '.dirty' to the version
'git config core.fileMode false'.execute() try {
// Pulls version from git tag 'git config core.fileMode false'.execute()
version = minecraftVersion + "-" + gitVersion() }
catch (Exception ignored) {
out.style(Style.Failure).println("git isn't installed at all")
}
// Pulls version first from the VERSION env and then git tag
String identifiedVersion
String versionOverride = System.getenv("VERSION") ?: null
try {
identifiedVersion = versionOverride == null ? gitVersion() : versionOverride
}
catch (Exception ignored) {
out.style(Style.Failure).text(
'This mod must be version controlled by Git AND the repository must provide at least one tag,\n' +
'or the VERSION override must be set! ').style(Style.SuccessHeader).text('(Do NOT download from GitHub using the ZIP option, instead\n' +
'clone the repository, see ').style(Style.Info).text('https://gtnh.miraheze.org/wiki/Development').style(Style.SuccessHeader).println(' for details.)'
)
versionOverride = 'NO-GIT-TAG-SET'
identifiedVersion = versionOverride
}
version = minecraftVersion + '-' + identifiedVersion
ext {
modVersion = identifiedVersion
}
if(identifiedVersion == versionOverride) {
out.style(Style.Failure).text('Override version to ').style(Style.Identifier).text(modVersion).style(Style.Failure).println('!\7')
}
group = modGroup group = modGroup
archivesBaseName = modId if(project.hasProperty("customArchiveBaseName") && customArchiveBaseName) {
archivesBaseName = customArchiveBaseName
}
else {
archivesBaseName = modId
}
def arguments = []
def jvmArguments = []
if (usesMixins.toBoolean()) {
arguments += [
"--tweakClass org.spongepowered.asm.launch.MixinTweaker"
]
if (!project.hasProperty(usesMixinDebug) || usesMixinDebug.toBoolean()) {
jvmArguments += [
"-Dmixin.debug.countInjections=true",
"-Dmixin.debug.verbose=true",
"-Dmixin.debug.export=true"
]
}
}
minecraft { minecraft {
version = minecraftVersion + "-" + forgeVersion + "-" + minecraftVersion version = minecraftVersion + '-' + forgeVersion + '-' + minecraftVersion
runDir = "run" runDir = 'run'
if (replaceGradleTokenInFile) { if (replaceGradleTokenInFile) {
replaceIn replaceGradleTokenInFile replaceIn replaceGradleTokenInFile
@@ -170,79 +239,99 @@ minecraft {
replace gradleTokenModName, modName replace gradleTokenModName, modName
} }
if(gradleTokenVersion) { if(gradleTokenVersion) {
replace gradleTokenVersion, versionDetails().lastTag replace gradleTokenVersion, modVersion
} }
if(gradleTokenGroupName) { if(gradleTokenGroupName) {
replace gradleTokenGroupName, modGroup replace gradleTokenGroupName, modGroup
} }
} }
clientIntellijRun {
args(arguments)
jvmArgs(jvmArguments)
if(developmentEnvironmentUserName) {
args("--username", developmentEnvironmentUserName)
}
}
serverIntellijRun {
args(arguments)
jvmArgs(jvmArguments)
}
} }
if(file("addon.gradle").exists()) { if(file('addon.gradle').exists()) {
apply from: "addon.gradle" apply from: 'addon.gradle'
} }
apply from: 'repositories.gradle' apply from: 'repositories.gradle'
configurations { configurations {
implementation.extendsFrom(shadowImplementation) implementation.extendsFrom(shadowImplementation) // TODO: remove after all uses are refactored
implementation.extendsFrom(shadowCompile)
implementation.extendsFrom(shadeCompile)
} }
repositories { repositories {
maven { maven {
name = "Overmind forge repo mirror" name 'Overmind forge repo mirror'
url = "https://gregtech.overminddl1.com/" url 'https://gregtech.overminddl1.com/'
} }
if(usesMixins.toBoolean()) { if(usesMixins.toBoolean()) {
maven { maven {
name = "sponge" name 'sponge'
url = "https://repo.spongepowered.org/repository/maven-public" url 'https://repo.spongepowered.org/repository/maven-public'
} }
maven { maven {
url = "https://jitpack.io" url 'https://jitpack.io'
} }
} }
} }
dependencies { dependencies {
if(usesMixins.toBoolean()) { if(usesMixins.toBoolean()) {
annotationProcessor("org.ow2.asm:asm-debug-all:5.0.3") annotationProcessor('org.ow2.asm:asm-debug-all:5.0.3')
annotationProcessor("com.google.guava:guava:24.1.1-jre") annotationProcessor('com.google.guava:guava:24.1.1-jre')
annotationProcessor("com.google.code.gson:gson:2.8.6") annotationProcessor('com.google.code.gson:gson:2.8.6')
annotationProcessor("org.spongepowered:mixin:0.8-SNAPSHOT") annotationProcessor('org.spongepowered:mixin:0.8-SNAPSHOT')
// using 0.8 to workaround a issue in 0.7 which fails mixin application // using 0.8 to workaround a issue in 0.7 which fails mixin application
compile("org.spongepowered:mixin:0.7.11-SNAPSHOT") { compile('com.github.GTNewHorizons:SpongePoweredMixin:0.7.12-GTNH') {
// Mixin includes a lot of dependencies that are too up-to-date // Mixin includes a lot of dependencies that are too up-to-date
exclude module: "launchwrapper" exclude module: 'launchwrapper'
exclude module: "guava" exclude module: 'guava'
exclude module: "gson" exclude module: 'gson'
exclude module: "commons-io" exclude module: 'commons-io'
exclude module: "log4j-core" exclude module: 'log4j-core'
} }
compile("com.github.GTNewHorizons:SpongeMixins:1.3.3:dev") compile('com.github.GTNewHorizons:SpongeMixins:1.5.0')
} }
} }
apply from: 'dependencies.gradle' apply from: 'dependencies.gradle'
def mixinConfigJson = "mixins." + modId + ".json" def mixingConfigRefMap = 'mixins.' + modId + '.refmap.json'
def mixingConfigRefMap = "mixins." + modId + ".refmap.json"
def refMap = "${tasks.compileJava.temporaryDir}" + File.separator + mixingConfigRefMap def refMap = "${tasks.compileJava.temporaryDir}" + File.separator + mixingConfigRefMap
def mixinSrg = "${tasks.reobf.temporaryDir}" + File.separator + "mixins.srg" def mixinSrg = "${tasks.reobf.temporaryDir}" + File.separator + "mixins.srg"
task generateAssets { task generateAssets {
if(usesMixins.toBoolean()) { if (usesMixins.toBoolean()) {
new File(projectDir.toString() + "/src/main/resources/", mixinConfigJson).text = """{ def mixinConfigFile = getFile("/src/main/resources/mixins." + modId + ".json");
if (!mixinConfigFile.exists()) {
mixinConfigFile.text = """{
"required": true, "required": true,
"minVersion": "0.7.11", "minVersion": "0.7.11",
"package": "${modGroup}.${mixinsPackage}", "package": "${modGroup}.${mixinsPackage}",
"plugin": "${modGroup}.${mixinPlugin}", "plugin": "${modGroup}.${mixinPlugin}",
"refmap": "${mixingConfigRefMap}", "refmap": "${mixingConfigRefMap}",
"target": "@env(DEFAULT)", "target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_8" "compatibilityLevel": "JAVA_8",
"mixins": [],
"client": [],
"server": []
} }
""" """
}
} }
} }
@@ -252,16 +341,28 @@ task relocateShadowJar(type: ConfigureShadowRelocation) {
} }
shadowJar { shadowJar {
project.configurations.shadeCompile.each { dep ->
from(project.zipTree(dep)) {
exclude 'META-INF', 'META-INF/**'
}
}
manifest { manifest {
attributes(getManifestAttributes()) attributes(getManifestAttributes())
} }
minimize() // This will only allow shading for actually used classes minimize() // This will only allow shading for actually used classes
configurations = [project.configurations.shadowImplementation] configurations = [project.configurations.shadowImplementation, project.configurations.shadowCompile]
dependsOn(relocateShadowJar) dependsOn(relocateShadowJar)
} }
jar { jar {
project.configurations.shadeCompile.each { dep ->
from(project.zipTree(dep)) {
exclude 'META-INF', 'META-INF/**'
}
}
manifest { manifest {
attributes(getManifestAttributes()) attributes(getManifestAttributes())
} }
@@ -294,15 +395,6 @@ afterEvaluate {
} }
runClient { runClient {
def arguments = []
if(usesMixins.toBoolean()) {
arguments += [
"--mods=../build/libs/$modId-${version}.jar",
"--tweakClass org.spongepowered.asm.launch.MixinTweaker"
]
}
if(developmentEnvironmentUserName) { if(developmentEnvironmentUserName) {
arguments += [ arguments += [
"--username", "--username",
@@ -311,19 +403,12 @@ runClient {
} }
args(arguments) args(arguments)
jvmArgs(jvmArguments)
} }
runServer { runServer {
def arguments = []
if (usesMixins.toBoolean()) {
arguments += [
"--mods=../build/libs/$modId-${version}.jar",
"--tweakClass org.spongepowered.asm.launch.MixinTweaker"
]
}
args(arguments) args(arguments)
jvmArgs(jvmArguments)
} }
tasks.withType(JavaExec).configureEach { tasks.withType(JavaExec).configureEach {
@@ -334,32 +419,35 @@ tasks.withType(JavaExec).configureEach {
) )
} }
processResources processResources {
{ // this will ensure that this task is redone when the versions change.
// this will ensure that this task is redone when the versions change. inputs.property "version", project.version
inputs.property "version", project.version inputs.property "mcversion", project.minecraft.version
inputs.property "mcversion", project.minecraft.version
// replace stuff in mcmod.info, nothing else // replace stuff in mcmod.info, nothing else
from(sourceSets.main.resources.srcDirs) { from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info' include 'mcmod.info'
// replace version and mcversion // replace modVersion and minecraftVersion
expand "minecraftVersion": project.minecraft.version, expand "minecraftVersion": project.minecraft.version,
"modVersion": versionDetails().lastTag, "modVersion": modVersion,
"modId": modId, "modId": modId,
"modName": modName "modName": modName
} }
// copy everything else, thats not the mcmod.info if(usesMixins.toBoolean()) {
from(sourceSets.main.resources.srcDirs) { from refMap
exclude 'mcmod.info' }
}
} // copy everything else that's not the mcmod.info
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
}
}
def getManifestAttributes() { def getManifestAttributes() {
def manifestAttributes = [:] def manifestAttributes = [:]
if(containsMixinsAndOrCoreModOnly.toBoolean() == false && (usesMixins.toBoolean() || coreModClass)) { if(!containsMixinsAndOrCoreModOnly.toBoolean() && (usesMixins.toBoolean() || coreModClass)) {
manifestAttributes += ["FMLCorePluginContainsFMLMod": true] manifestAttributes += ["FMLCorePluginContainsFMLMod": true]
} }
@@ -374,20 +462,26 @@ def getManifestAttributes() {
if(usesMixins.toBoolean()) { if(usesMixins.toBoolean()) {
manifestAttributes += [ manifestAttributes += [
"TweakClass" : "org.spongepowered.asm.launch.MixinTweaker", "TweakClass" : "org.spongepowered.asm.launch.MixinTweaker",
"MixinConfigs" : mixinConfigJson, "MixinConfigs" : "mixins." + modId + ".json",
"ForceLoadAsMod" : containsMixinsAndOrCoreModOnly.toBoolean() == false "ForceLoadAsMod" : !containsMixinsAndOrCoreModOnly.toBoolean()
] ]
} }
return manifestAttributes return manifestAttributes
} }
task sourcesJar(type: Jar) { task sourcesJar(type: Jar) {
from (sourceSets.main.allJava) from (sourceSets.main.allSource)
from (file("$projectDir/LICENSE")) from (file("$projectDir/LICENSE"))
getArchiveClassifier().set('sources') getArchiveClassifier().set('sources')
} }
task shadowDevJar(type: ShadowJar) { task shadowDevJar(type: ShadowJar) {
project.configurations.shadeCompile.each { dep ->
from(project.zipTree(dep)) {
exclude 'META-INF', 'META-INF/**'
}
}
from sourceSets.main.output from sourceSets.main.output
getArchiveClassifier().set("dev") getArchiveClassifier().set("dev")
@@ -396,7 +490,7 @@ task shadowDevJar(type: ShadowJar) {
} }
minimize() // This will only allow shading for actually used classes minimize() // This will only allow shading for actually used classes
configurations = [project.configurations.shadowImplementation] configurations = [project.configurations.shadowImplementation, project.configurations.shadowCompile]
} }
task relocateShadowDevJar(type: ConfigureShadowRelocation) { task relocateShadowDevJar(type: ConfigureShadowRelocation) {
@@ -411,6 +505,12 @@ task circularResolverJar(type: Jar) {
} }
task devJar(type: Jar) { task devJar(type: Jar) {
project.configurations.shadeCompile.each { dep ->
from(project.zipTree(dep)) {
exclude 'META-INF', 'META-INF/**'
}
}
from sourceSets.main.output from sourceSets.main.output
getArchiveClassifier().set("dev") getArchiveClassifier().set("dev")
@@ -425,12 +525,12 @@ task devJar(type: Jar) {
} }
task apiJar(type: Jar) { task apiJar(type: Jar) {
from (sourceSets.main.allJava) { from (sourceSets.main.allSource) {
include modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString() + '/**' include modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + '/**'
} }
from (sourceSets.main.output) { from (sourceSets.main.output) {
include modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString() + '/**' include modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + '/**'
} }
from (sourceSets.main.resources.srcDirs) { from (sourceSets.main.resources.srcDirs) {
@@ -441,24 +541,71 @@ task apiJar(type: Jar) {
} }
artifacts { artifacts {
archives sourcesJar if(!noPublishedSources) {
archives sourcesJar
}
archives devJar archives devJar
if(apiPackage) { if(apiPackage) {
archives apiJar archives apiJar
} }
} }
// Crude handler to append custom maven repositories to maven dependency // The gradle metadata includes all of the additional deps that we disabled from POM generation (including forgeBin with no groupID),
install{ // and isn't strictly needed with the POM so just disable it.
repositories{ tasks.withType(GenerateModuleMetadata) {
mavenInstaller{ enabled = false
}
// workaround variable hiding in pom processing
def projectConfigs = project.configurations
publishing {
publications {
maven(MavenPublication) {
from components.java
if(usesShadowedDependencies.toBoolean()) {
artifact source: shadowJar, classifier: ""
}
if(!noPublishedSources) {
artifact source: sourcesJar, classifier: "src"
}
artifact source: usesShadowedDependencies.toBoolean() ? shadowDevJar : devJar, classifier: "dev"
if (apiPackage) {
artifact source: apiJar, classifier: "api"
}
groupId = System.getenv("ARTIFACT_GROUP_ID") ?: "com.github.GTNewHorizons"
artifactId = System.getenv("ARTIFACT_ID") ?: project.name
// Using the identified version, not project.version as it has the prepended 1.7.10
version = System.getenv("RELEASE_VERSION") ?: identifiedVersion
// remove extra garbage from minecraft and minecraftDeps configuration
pom.withXml { pom.withXml {
def repositoriesNode = asNode().appendNode("repositories") def badArtifacts = [:].withDefault {[] as Set<String>}
project.repositories.each { repository -> for (configuration in [projectConfigs.minecraft, projectConfigs.minecraftDeps]) {
def repositoryNode = repositoriesNode.appendNode("repository") for (dependency in configuration.allDependencies) {
repositoryNode.appendNode("name", repository.name) badArtifacts[dependency.group == null ? "" : dependency.group] += dependency.name
repositoryNode.appendNode("url", repository.properties.get("url")) }
} }
// example for specifying extra stuff to ignore
// badArtifacts["org.example.group"] += "artifactName"
Node pomNode = asNode()
pomNode.dependencies.'*'.findAll() {
badArtifacts[it.groupId.text()].contains(it.artifactId.text())
}.each() {
it.parent().remove(it)
}
}
}
}
repositories {
maven {
url = "http://jenkins.usrv.eu:8081/nexus/content/repositories/releases"
credentials {
username = System.getenv("MAVEN_USER") ?: "NONE"
password = System.getenv("MAVEN_PASSWORD") ?: "NONE"
} }
} }
} }
@@ -467,38 +614,38 @@ install{
// Updating // Updating
task updateBuildScript { task updateBuildScript {
doLast { doLast {
if (updateBuildScript()) return if (performBuildScriptUpdate(projectDir.toString())) return
print("Build script already up-to-date!") print("Build script already up-to-date!")
} }
} }
if (isNewBuildScriptVersionAvailable()) { if (isNewBuildScriptVersionAvailable(projectDir.toString())) {
if (autoUpdateBuildScript.toBoolean()) { if (autoUpdateBuildScript.toBoolean()) {
updateBuildScript() performBuildScriptUpdate(projectDir.toString())
} else { } else {
println("Build script update available! Run 'gradle updateBuildScript'") out.style(Style.SuccessHeader).println("Build script update available! Run 'gradle updateBuildScript'")
} }
} }
static URL availableBuildScriptUrl() { static URL availableBuildScriptUrl() {
new URL("https://raw.githubusercontent.com/SinTh0r4s/ExampleMod1.7.10/main/build.gradle") new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/main/build.gradle")
} }
static boolean updateBuildScript() { boolean performBuildScriptUpdate(String projectDir) {
if (isNewBuildScriptVersionAvailable()) { if (isNewBuildScriptVersionAvailable(projectDir)) {
def buildscriptFile = new File("build.gradle") def buildscriptFile = getFile("build.gradle")
availableBuildScriptUrl().withInputStream { i -> buildscriptFile.withOutputStream { it << i } } availableBuildScriptUrl().withInputStream { i -> buildscriptFile.withOutputStream { it << i } }
print("Build script updated. Please REIMPORT the project or RESTART your IDE!") out.style(Style.Success).print("Build script updated. Please REIMPORT the project or RESTART your IDE!")
return true return true
} }
return false return false
} }
static boolean isNewBuildScriptVersionAvailable() { boolean isNewBuildScriptVersionAvailable(String projectDir) {
Map parameters = ["connectTimeout": 2000, "readTimeout": 2000] Map parameters = ["connectTimeout": 2000, "readTimeout": 2000]
String currentBuildScript = new File("build.gradle").getText() String currentBuildScript = getFile("build.gradle").getText()
String currentBuildScriptHash = getVersionHash(currentBuildScript) String currentBuildScriptHash = getVersionHash(currentBuildScript)
String availableBuildScript = availableBuildScriptUrl().newInputStream(parameters).getText() String availableBuildScript = availableBuildScriptUrl().newInputStream(parameters).getText()
String availableBuildScriptHash = getVersionHash(availableBuildScript) String availableBuildScriptHash = getVersionHash(availableBuildScript)
@@ -519,3 +666,81 @@ configure(updateBuildScript) {
group = 'forgegradle' group = 'forgegradle'
description = 'Updates the build script to the latest version' description = 'Updates the build script to the latest version'
} }
// Deobfuscation
def deobf(String sourceURL) {
try {
URL url = new URL(sourceURL)
String fileName = url.getFile()
//get rid of directories:
int lastSlash = fileName.lastIndexOf("/")
if(lastSlash > 0) {
fileName = fileName.substring(lastSlash + 1)
}
//get rid of extension:
if(fileName.endsWith(".jar")) {
fileName = fileName.substring(0, fileName.lastIndexOf("."))
}
String hostName = url.getHost()
if(hostName.startsWith("www.")) {
hostName = hostName.substring(4)
}
List parts = Arrays.asList(hostName.split("\\."))
Collections.reverse(parts)
hostName = String.join(".", parts)
return deobf(sourceURL, hostName + "/" + fileName)
} catch(Exception e) {
return deobf(sourceURL, "deobf/" + String.valueOf(sourceURL.hashCode()))
}
}
// The method above is to be preferred. Use this method if the filename is not at the end of the URL.
def deobf(String sourceURL, String fileName) {
String cacheDir = System.getProperty("user.home") + "/.gradle/caches/"
String bon2Dir = cacheDir + "forge_gradle/deobf"
String bon2File = bon2Dir + "/BON2-2.5.0.jar"
String obfFile = cacheDir + "modules-2/files-2.1/" + fileName + ".jar"
String deobfFile = cacheDir + "modules-2/files-2.1/" + fileName + "-deobf.jar"
if(file(deobfFile).exists()) {
return files(deobfFile)
}
download.run {
src 'https://github.com/GTNewHorizons/BON2/releases/download/2.5.0/BON2-2.5.0.CUSTOM-all.jar'
dest bon2File
quiet true
overwrite false
}
download.run {
src sourceURL
dest obfFile
quiet true
overwrite false
}
exec {
commandLine 'java', '-jar', bon2File, '--inputJar', obfFile, '--outputJar', deobfFile, '--mcVer', '1.7.10', '--mappingsVer', 'stable_12', '--notch'
workingDir bon2Dir
standardOutput = new ByteArrayOutputStream()
}
return files(deobfFile)
}
// Helper methods
def checkPropertyExists(String propertyName) {
if (!project.hasProperty(propertyName)) {
throw new GradleException("This project requires a property \"" + propertyName + "\"! Please add it your \"gradle.properties\". You can find all properties and their description here: https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/gradle.properties")
}
}
def getFile(String relativePath) {
return new File(projectDir, relativePath)
}
@@ -14,6 +14,10 @@ public interface IAlignment extends IAlignmentLimits,IAlignmentProvider {
ExtendedFacing getExtendedFacing(); ExtendedFacing getExtendedFacing();
/**
* Set the facing without additional checks.
* Tools altering facing should use {@link #toolSetExtendedFacing(ExtendedFacing)} instead.
*/
void setExtendedFacing(ExtendedFacing alignment); void setExtendedFacing(ExtendedFacing alignment);
IAlignmentLimits getAlignmentLimits(); IAlignmentLimits getAlignmentLimits();
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableSet;
import com.gtnewhorizon.structurelib.alignment.IAlignment; import com.gtnewhorizon.structurelib.alignment.IAlignment;
import com.gtnewhorizon.structurelib.alignment.IntegerAxisSwap; import com.gtnewhorizon.structurelib.alignment.IntegerAxisSwap;
import com.gtnewhorizon.structurelib.util.Vec3Impl; import com.gtnewhorizon.structurelib.util.Vec3Impl;
import net.minecraft.util.StatCollector;
import net.minecraft.util.Vec3; import net.minecraft.util.Vec3;
import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.common.util.ForgeDirection;
@@ -276,6 +277,10 @@ public enum ExtendedFacing {
return this.name; return this.name;
} }
public String getLocalizedName() {
return StatCollector.translateToLocal("structurelib.facing." + getIndex());
}
public static ExtendedFacing byName(String name) { public static ExtendedFacing byName(String name) {
return name == null ? null : NAME_LOOKUP.get(name.toLowerCase(Locale.ROOT)); return name == null ? null : NAME_LOOKUP.get(name.toLowerCase(Locale.ROOT));
} }
@@ -128,6 +128,9 @@ public interface IStructureDefinition<T> {
} }
} }
} }
if (DEBUG_MODE) {
StructureLib.LOGGER.info("Multi [" + basePositionX + ", " + basePositionY + ", " + basePositionZ + "] pass");
}
} else { } else {
if (hintsOnly) { if (hintsOnly) {
for (IStructureElement<T> element : elements) { for (IStructureElement<T> element : elements) {
@@ -27,13 +27,7 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.function.BiConsumer; import java.util.function.*;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntBinaryOperator;
import java.util.function.Supplier;
import static java.lang.Integer.MIN_VALUE; import static java.lang.Integer.MIN_VALUE;
@@ -239,7 +233,7 @@ public class StructureUtility {
} }
private Pair<Block, Integer> getHint(ItemStack trigger) { private Pair<Block, Integer> getHint(ItemStack trigger) {
return hints.get(Math.min(Math.max(trigger.stackSize, 1), hints.size())); return hints.get(Math.min(Math.max(trigger.stackSize, 1), hints.size()) - 1);
} }
@Override @Override
@@ -816,6 +810,28 @@ public class StructureUtility {
//endregion //endregion
/**
* Enable this structure element only if given predicate returns true.
*/
public static <T> IStructureElement<T> onlyIf(Predicate<? super T> predicate, IStructureElement<? super T> downstream) {
return new IStructureElement<T>() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
return predicate.test(t) && downstream.check(t, world, x, y, z);
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
return predicate.test(t) && downstream.spawnHint(t, world, x, y, z, trigger);
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
return predicate.test(t) && downstream.placeBlock(t, world, x, y, z, trigger);
}
};
}
/** /**
* Take care while chaining, as it will try to call every structure element until it returns true. * Take care while chaining, as it will try to call every structure element until it returns true.
* If none does it will finally return false. * If none does it will finally return false.
@@ -22,10 +22,10 @@ item.structurelib.frontRotationTool.desc.2=which allows structure rotation.
item.structurelib.constructableTrigger.name=Multiblock Structure Hologram Projector item.structurelib.constructableTrigger.name=Multiblock Structure Hologram Projector
item.structurelib.constructableTrigger.desc.0=Triggers Constructable Interface item.structurelib.constructableTrigger.desc.0=Triggers Constructable Interface
item.structurelib.constructableTrigger.desc.1=Shows multiblock construction details, item.structurelib.constructableTrigger.desc.1=Shows multiblock construction schematic,
item.structurelib.constructableTrigger.desc.2=just Use on a multiblock controller. item.structurelib.constructableTrigger.desc.2=use on the multiblock controller.
item.structurelib.constructableTrigger.desc.3=(Sneak Use in creative to build) item.structurelib.constructableTrigger.desc.3=(Sneak use on controller in creative to build)
item.structurelib.constructableTrigger.desc.4=Quantity affects tier/mode/type item.structurelib.constructableTrigger.desc.4=Quantity of schematics in item stack affects tier/mode/type
structurelib.blockhint.desc.0=Helps while building structurelib.blockhint.desc.0=Helps while building
structurelib.blockhint.0.name=Hint 1 dot structurelib.blockhint.0.name=Hint 1 dot
@@ -51,6 +51,103 @@ structurelib.blockhint.15.name=Hint error
structurelib.blockhint.desc.5=ERROR, what did u expect? structurelib.blockhint.desc.5=ERROR, what did u expect?
itemGroup.structurelib=StructureLib itemGroup.structurelib=StructureLib
structurelib.facing.0=down normal none
structurelib.facing.1=down normal horizontal
structurelib.facing.2=down normal vertical
structurelib.facing.3=down normal both
structurelib.facing.4=down clockwise none
structurelib.facing.5=down clockwise horizontal
structurelib.facing.6=down clockwise vertical
structurelib.facing.7=down clockwise both
structurelib.facing.8=down upside down
structurelib.facing.9=down upside down
structurelib.facing.10=down upside down
structurelib.facing.11=down upside down
structurelib.facing.12=down counter clockwise
structurelib.facing.13=down counter clockwise
structurelib.facing.14=down counter clockwise
structurelib.facing.15=down counter clockwise
structurelib.facing.16=up normal none
structurelib.facing.17=up normal horizontal
structurelib.facing.18=up normal vertical
structurelib.facing.19=up normal both
structurelib.facing.20=up clockwise none
structurelib.facing.21=up clockwise horizontal
structurelib.facing.22=up clockwise vertical
structurelib.facing.23=up clockwise both
structurelib.facing.24=up upside down
structurelib.facing.25=up upside down
structurelib.facing.26=up upside down
structurelib.facing.27=up upside down
structurelib.facing.28=up counter clockwise
structurelib.facing.29=up counter clockwise
structurelib.facing.30=up counter clockwise
structurelib.facing.31=up counter clockwise
structurelib.facing.32=north normal none
structurelib.facing.33=north normal horizontal
structurelib.facing.34=north normal vertical
structurelib.facing.35=north normal both
structurelib.facing.36=north clockwise none
structurelib.facing.37=north clockwise horizontal
structurelib.facing.38=north clockwise vertical
structurelib.facing.39=north clockwise both
structurelib.facing.40=north upside down
structurelib.facing.41=north upside down
structurelib.facing.42=north upside down
structurelib.facing.43=north upside down
structurelib.facing.44=north counter clockwise
structurelib.facing.45=north counter clockwise
structurelib.facing.46=north counter clockwise
structurelib.facing.47=north counter clockwise
structurelib.facing.48=south normal none
structurelib.facing.49=south normal horizontal
structurelib.facing.50=south normal vertical
structurelib.facing.51=south normal both
structurelib.facing.52=south clockwise none
structurelib.facing.53=south clockwise horizontal
structurelib.facing.54=south clockwise vertical
structurelib.facing.55=south clockwise both
structurelib.facing.56=south upside down
structurelib.facing.57=south upside down
structurelib.facing.58=south upside down
structurelib.facing.59=south upside down
structurelib.facing.60=south counter clockwise
structurelib.facing.61=south counter clockwise
structurelib.facing.62=south counter clockwise
structurelib.facing.63=south counter clockwise
structurelib.facing.64=west normal none
structurelib.facing.65=west normal horizontal
structurelib.facing.66=west normal vertical
structurelib.facing.67=west normal both
structurelib.facing.68=west clockwise none
structurelib.facing.69=west clockwise horizontal
structurelib.facing.70=west clockwise vertical
structurelib.facing.71=west clockwise both
structurelib.facing.72=west upside down
structurelib.facing.73=west upside down
structurelib.facing.74=west upside down
structurelib.facing.75=west upside down
structurelib.facing.76=west counter clockwise
structurelib.facing.77=west counter clockwise
structurelib.facing.78=west counter clockwise
structurelib.facing.79=west counter clockwise
structurelib.facing.80=east normal none
structurelib.facing.81=east normal horizontal
structurelib.facing.82=east normal vertical
structurelib.facing.83=east normal both
structurelib.facing.84=east clockwise none
structurelib.facing.85=east clockwise horizontal
structurelib.facing.86=east clockwise vertical
structurelib.facing.87=east clockwise both
structurelib.facing.88=east upside down
structurelib.facing.89=east upside down
structurelib.facing.90=east upside down
structurelib.facing.91=east upside down
structurelib.facing.92=east counter clockwise
structurelib.facing.93=east counter clockwise
structurelib.facing.94=east counter clockwise
structurelib.facing.95=east counter clockwise
structurelib.config.client=Client Side Configurations structurelib.config.client=Client Side Configurations
structurelib.config.client.tooltip=Configurations that only changes how the game looks like, but not how it functions. structurelib.config.client.tooltip=Configurations that only changes how the game looks like, but not how it functions.
structurelib.config.client.hologram=Hologram Configurations structurelib.config.client.hologram=Hologram Configurations
@@ -23,7 +23,7 @@ item.structurelib.frontRotationTool.desc.2=多方块主机一起旋转/翻转。
item.structurelib.constructableTrigger.name=多方块结构全息投影仪 item.structurelib.constructableTrigger.name=多方块结构全息投影仪
item.structurelib.constructableTrigger.desc.0=可以显示多方块机器的结构 item.structurelib.constructableTrigger.desc.0=可以显示多方块机器的结构
item.structurelib.constructableTrigger.desc.1=只能在多方块主机上使用,将会显示机器 item.structurelib.constructableTrigger.desc.1=只能在多方块主机上使用,将会显示机器
item.structurelib.constructableTrigger.desc.2=结构的细节。 (译者注:请搭高使用) item.structurelib.constructableTrigger.desc.2=结构的示意图。 (译者注:请搭高使用)
item.structurelib.constructableTrigger.desc.3= (创造模式下潜行右键可以直接完成搭建) item.structurelib.constructableTrigger.desc.3= (创造模式下潜行右键可以直接完成搭建)
item.structurelib.constructableTrigger.desc.4=此物品堆叠数量会影响显示的机器等级/模式/类型 item.structurelib.constructableTrigger.desc.4=此物品堆叠数量会影响显示的机器等级/模式/类型
@@ -51,6 +51,103 @@ structurelib.blockhint.15.name=提示方块:错误
structurelib.blockhint.desc.5=ERROR,你想要做什么? structurelib.blockhint.desc.5=ERROR,你想要做什么?
itemGroup.structurelib=StructureLib itemGroup.structurelib=StructureLib
structurelib.facing.0=面朝下方
structurelib.facing.1=面朝下方,并水平翻转
structurelib.facing.2=面朝下方,并垂直翻转
structurelib.facing.3=面朝下方,并旋转180度
structurelib.facing.4=面朝下方,并顺时针旋转90度
structurelib.facing.5=面朝下方,顺时针旋转90度并水平翻转
structurelib.facing.6=面朝下方,顺时针旋转90度并垂直翻转
structurelib.facing.7=面朝下方,并逆时针旋转90度
structurelib.facing.8=面朝下方,并旋转180度
structurelib.facing.9=面朝下方,并垂直翻转
structurelib.facing.10=面朝下方,并水平翻转
structurelib.facing.11=面朝下方
structurelib.facing.12=面朝下方,并逆时针旋转90度
structurelib.facing.13=面朝下方,逆时针旋转90度并水平翻转
structurelib.facing.14=面朝下方,逆时针旋转90度并垂直翻转
structurelib.facing.15=面朝下方,并顺时针旋转90度
structurelib.facing.16=面朝上方
structurelib.facing.17=面朝上方,并水平翻转
structurelib.facing.18=面朝上方,并垂直翻转
structurelib.facing.19=面朝上方,并旋转180度
structurelib.facing.20=面朝上方,并顺时针旋转90度
structurelib.facing.21=面朝上方,顺时针旋转90度并水平翻转
structurelib.facing.22=面朝上方,顺时针旋转90度并垂直翻转
structurelib.facing.23=面朝上方,并逆时针旋转90度
structurelib.facing.24=面朝上方,并旋转180度
structurelib.facing.25=面朝上方,并垂直翻转
structurelib.facing.26=面朝上方,并水平翻转
structurelib.facing.27=面朝上方
structurelib.facing.28=面朝上方,并逆时针旋转90度
structurelib.facing.29=面朝上方,逆时针旋转90度并水平翻转
structurelib.facing.30=面朝上方,逆时针旋转90度并垂直翻转
structurelib.facing.31=面朝上方,并顺时针旋转90度
structurelib.facing.32=面朝北方
structurelib.facing.33=面朝北方,并水平翻转
structurelib.facing.34=面朝北方,并垂直翻转
structurelib.facing.35=面朝北方,并旋转180度
structurelib.facing.36=面朝北方,并顺时针旋转90度
structurelib.facing.37=面朝北方,顺时针旋转90度并水平翻转
structurelib.facing.38=面朝北方,顺时针旋转90度并垂直翻转
structurelib.facing.39=面朝北方,并逆时针旋转90度
structurelib.facing.40=面朝北方,并旋转180度
structurelib.facing.41=面朝北方,并垂直翻转
structurelib.facing.42=面朝北方,并水平翻转
structurelib.facing.43=面朝北方
structurelib.facing.44=面朝北方,并逆时针旋转90度
structurelib.facing.45=面朝北方,逆时针旋转90度并水平翻转
structurelib.facing.46=面朝北方,逆时针旋转90度并垂直翻转
structurelib.facing.47=面朝北方,并顺时针旋转90度
structurelib.facing.48=面朝南方
structurelib.facing.49=面朝南方,并水平翻转
structurelib.facing.50=面朝南方,并垂直翻转
structurelib.facing.51=面朝南方,并旋转180度
structurelib.facing.52=面朝南方,并顺时针旋转90度
structurelib.facing.53=面朝南方,顺时针旋转90度并水平翻转
structurelib.facing.54=面朝南方,顺时针旋转90度并垂直翻转
structurelib.facing.55=面朝南方,并逆时针旋转90度
structurelib.facing.56=面朝南方,并旋转180度
structurelib.facing.57=面朝南方,并垂直翻转
structurelib.facing.58=面朝南方,并水平翻转
structurelib.facing.59=面朝南方
structurelib.facing.60=面朝南方,并逆时针旋转90度
structurelib.facing.61=面朝南方,逆时针旋转90度并水平翻转
structurelib.facing.62=面朝南方,逆时针旋转90度并垂直翻转
structurelib.facing.63=面朝南方,并顺时针旋转90度
structurelib.facing.64=面朝西方
structurelib.facing.65=面朝西方,并水平翻转
structurelib.facing.66=面朝西方,并垂直翻转
structurelib.facing.67=面朝西方,并旋转180度
structurelib.facing.68=面朝西方,并顺时针旋转90度
structurelib.facing.69=面朝西方,顺时针旋转90度并水平翻转
structurelib.facing.70=面朝西方,顺时针旋转90度并垂直翻转
structurelib.facing.71=面朝西方,并逆时针旋转90度
structurelib.facing.72=面朝西方,并旋转180度
structurelib.facing.73=面朝西方,并垂直翻转
structurelib.facing.74=面朝西方,并水平翻转
structurelib.facing.75=面朝西方
structurelib.facing.76=面朝西方,并逆时针旋转90度
structurelib.facing.77=面朝西方,逆时针旋转90度并水平翻转
structurelib.facing.78=面朝西方,逆时针旋转90度并垂直翻转
structurelib.facing.79=面朝西方,并顺时针旋转90度
structurelib.facing.80=面朝东方
structurelib.facing.81=面朝东方,并水平翻转
structurelib.facing.82=面朝东方,并垂直翻转
structurelib.facing.83=面朝东方,并旋转180度
structurelib.facing.84=面朝东方,并顺时针旋转90度
structurelib.facing.85=面朝东方,顺时针旋转90度并水平翻转
structurelib.facing.86=面朝东方,顺时针旋转90度并垂直翻转
structurelib.facing.87=面朝东方,并逆时针旋转90度
structurelib.facing.88=面朝东方,并旋转180度
structurelib.facing.89=面朝东方,并垂直翻转
structurelib.facing.90=面朝东方,并水平翻转
structurelib.facing.91=面朝东方
structurelib.facing.92=面朝东方,并逆时针旋转90度
structurelib.facing.93=面朝东方,逆时针旋转90度并水平翻转
structurelib.facing.94=面朝东方,逆时针旋转90度并垂直翻转
structurelib.facing.95=面朝东方,并顺时针旋转90度
structurelib.config.client=客户端-配置 structurelib.config.client=客户端-配置
structurelib.config.client.tooltip=修改此配置只会改变游戏中的显示效果,而不会改变实际工作模式。 structurelib.config.client.tooltip=修改此配置只会改变游戏中的显示效果,而不会改变实际工作模式。
structurelib.config.client.hologram=全息投影仪-配置 structurelib.config.client.hologram=全息投影仪-配置