diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c49cdaaca..afa6f8601 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,27 @@ +7.0.1 Release Candidate 1 +- Improve //naturalize over large areas +- Fixed //restore with 1.14 worlds +- Added item brush support to WorldEdit for Bukkit (Formerly just Forge) +- Create an internal state ID mapping for performance +- Improve rotation for some blocks +- Added .self permission node to undo/redo to only allow undoing and redoing own history +- Improve sponge schematic implementation +- Re-add the delchunks command +- Added 1.14 blocks, items, tags, etc to the API (Remains compatible with 1.13) +- Made the navigation and selection wands normal tools that can be rebound per-user with //selwand and //navwand +- Added //wand -n to get the navigation wand +- Improved movement of paintings +- Allow command suggestions for selectors +- Allow block replacer to work with tile entities +- Fixed pasting leashed entities +- Fixed setting player heads with names +- Added a mask flag to //count +- Setup pagination for //distr +- Fixed an entity-related error being caused by plugins improperly using Spigot. +- Fixed gravity brush +- Modify chunk batching for performance +- Further legacy schematic loading improvements + 7.0.0 See https://matthewmiller.dev/blog/introducing-worldedit-7/ for a friendlier explanation of some new features diff --git a/build.gradle b/build.gradle deleted file mode 100644 index dddd5470e..000000000 --- a/build.gradle +++ /dev/null @@ -1,159 +0,0 @@ -buildscript { - repositories { - mavenCentral() - maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" } - jcenter() - } - - configurations.all { - resolutionStrategy { - force 'commons-io:commons-io:2.4' - } - } - - dependencies { - classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4' - classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.8.1' - } -} - -plugins { - id 'net.minecrell.licenser' version '0.4.1' apply false - id "org.ajoberstar.grgit" version "2.3.0" -} - -println """ -******************************************* - You are building WorldEdit! - - If you encounter trouble: - 1) Read COMPILING.md if you haven't yet - 2) Try running 'build' in a separate Gradle run - 3) Use gradlew and not gradle - 4) If you still need help, ask on Discord! https://discord.gg/enginehub - - Output files will be in [subproject]/build/libs -******************************************* -""" - -allprojects { - group = 'com.sk89q.worldedit' - version = '7.0.1-SNAPSHOT' -} - -if (!project.hasProperty("artifactory_contextUrl")) ext.artifactory_contextUrl = "http://localhost" -if (!project.hasProperty("artifactory_user")) ext.artifactory_user = "guest" -if (!project.hasProperty("artifactory_password")) ext.artifactory_password = "" - -if (!project.hasProperty("gitCommitHash") && !JavaVersion.current().isJava6()) { - try { - def repo = grgit.open() - ext.gitCommitHash = repo.head().abbreviatedId - } catch (Exception e) { - println "Error getting commit hash: " + e.getMessage() - } -} -if (!project.hasProperty("gitCommitHash")) { - ext.gitCommitHash = "no_git_id" -} - -apply plugin: 'com.jfrog.artifactory' -artifactory { - contextUrl = "${artifactory_contextUrl}" - publish { - repository { - repoKey = project.version.contains("SNAPSHOT") ? 'libs-snapshot-local' : 'libs-release-local' - username = "${artifactory_user}" - password = "${artifactory_password}" - maven = true - ivy = false - } - } -} -artifactoryPublish.skip = true - -subprojects { - repositories { - mavenCentral() - maven { url "http://maven.sk89q.com/repo/" } - maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } - } - configurations.all { - resolutionStrategy { - cacheChangingModulesFor 5, 'minutes' - } - } -} - -configure(['core', 'bukkit', 'forge', 'sponge', 'fabric'].collect { project(":worldedit-$it") }) { - apply plugin: 'java' - apply plugin: 'maven' - apply plugin: 'checkstyle' - apply plugin: 'com.github.johnrengelman.shadow' - apply plugin: 'com.jfrog.artifactory' - apply plugin: 'net.minecrell.licenser' - - ext.internalVersion = version + ";" + gitCommitHash - - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - - checkstyle.configFile = new File(rootProject.projectDir, "config/checkstyle/checkstyle.xml") - checkstyle.toolVersion = '7.6.1' - - if (JavaVersion.current().isJava8Compatible()) { - // Java 8 turns on doclint which we fail - tasks.withType(Javadoc) { - options.addStringOption('Xdoclint:none', '-quiet') - } - } - - task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' - from javadoc.destinationDir - } - - artifacts { - archives jar - archives javadocJar - } - - if (name == "worldedit-core" || name == "worldedit-bukkit") { - task sourcesJar(type: Jar, dependsOn: classes) { - classifier = 'sources' - from sourceSets.main.allSource - } - - artifacts { - archives sourcesJar - } - build.dependsOn(sourcesJar) - } - - build.dependsOn(checkstyleMain) - build.dependsOn(checkstyleTest) - build.dependsOn(javadocJar) - - artifactoryPublish { - publishConfigs('archives') - } - - license { - header = rootProject.file("HEADER.txt") - include '**/*.java' - } -} - -configure(['bukkit', 'forge', 'sponge', 'fabric'].collect { project(":worldedit-$it") }) { - shadowJar { - classifier 'dist' - dependencies { - include(project(":worldedit-libs:core")) - include(project(":worldedit-libs:${project.name.replace("worldedit-", "")}")) - include(project(":worldedit-core")) - } - exclude 'GradleStart**' - exclude '.cache' - exclude 'LICENSE*' - } -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 000000000..07b943531 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,28 @@ +import org.ajoberstar.grgit.Grgit + +logger.lifecycle(""" +******************************************* + You are building WorldEdit! + + If you encounter trouble: + 1) Read COMPILING.md if you haven't yet + 2) Try running 'build' in a separate Gradle run + 3) Use gradlew and not gradle + 4) If you still need help, ask on Discord! https://discord.gg/enginehub + + Output files will be in [subproject]/build/libs +******************************************* +""") + +applyRootArtifactoryConfig() + +if (!project.hasProperty("gitCommitHash")) { + apply(plugin = "org.ajoberstar.grgit") + ext["gitCommitHash"] = try { + (ext["grgit"] as Grgit?)?.head()?.abbreviatedId + } catch (e: Exception) { + logger.warn("Error getting commit hash", e) + + "no_git_id" + } +} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 000000000..1d1da51c1 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,36 @@ +plugins { + `kotlin-dsl` + kotlin("jvm") version embeddedKotlinVersion +} + +repositories { + jcenter() + gradlePluginPortal() + maven { + name = "Forge Maven" + url = uri("https://files.minecraftforge.net/maven") + } +} + +configurations.all { + resolutionStrategy { + // Fabric needs this. + force( + "commons-io:commons-io:2.5", + "org.ow2.asm:asm:7.1", + "org.ow2.asm:asm-commons:7.1" + ) + } +} + +dependencies { + implementation(gradleApi()) + implementation("gradle.plugin.net.minecrell:licenser:0.4.1") + implementation("org.ajoberstar.grgit:grgit-gradle:3.1.1") + implementation("com.github.jengelman.gradle.plugins:shadow:5.1.0") + implementation("net.ltgt.apt-eclipse:net.ltgt.apt-eclipse.gradle.plugin:0.21") + implementation("net.ltgt.apt-idea:net.ltgt.apt-idea.gradle.plugin:0.21") + implementation("org.jfrog.buildinfo:build-info-extractor-gradle:4.9.7") + implementation("gradle.plugin.org.spongepowered:spongegradle:0.9.0") + implementation("net.minecraftforge.gradle:ForgeGradle:3.0.130") +} diff --git a/buildSrc/src/main/kotlin/ArtifactoryConfig.kt b/buildSrc/src/main/kotlin/ArtifactoryConfig.kt new file mode 100644 index 000000000..d19f35238 --- /dev/null +++ b/buildSrc/src/main/kotlin/ArtifactoryConfig.kt @@ -0,0 +1,40 @@ +import org.gradle.api.Project +import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.named +import org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention +import org.jfrog.gradle.plugin.artifactory.task.ArtifactoryTask + +private const val ARTIFACTORY_CONTEXT_URL = "artifactory_contextUrl" +private const val ARTIFACTORY_USER = "artifactory_user" +private const val ARTIFACTORY_PASSWORD = "artifactory_password" + +fun Project.applyRootArtifactoryConfig() { + if (!project.hasProperty(ARTIFACTORY_CONTEXT_URL)) ext[ARTIFACTORY_CONTEXT_URL] = "http://localhost" + if (!project.hasProperty(ARTIFACTORY_USER)) ext[ARTIFACTORY_USER] = "guest" + if (!project.hasProperty(ARTIFACTORY_PASSWORD)) ext[ARTIFACTORY_PASSWORD] = "" + + apply(plugin = "com.jfrog.artifactory") + configure { + setContextUrl("${project.property(ARTIFACTORY_CONTEXT_URL)}") + clientConfig.publisher.run { + repoKey = when { + "${project.version}".contains("SNAPSHOT") -> "libs-snapshot-local" + else -> "libs-release-local" + } + username = "${project.property(ARTIFACTORY_USER)}" + password = "${project.property(ARTIFACTORY_PASSWORD)}" + isMaven = true + isIvy = false + } + } + tasks.named("artifactoryPublish") { + isSkip = true + } +} + +fun Project.applyCommonArtifactoryConfig() { + tasks.named("artifactoryPublish") { + publishConfigs("archives") + } +} diff --git a/buildSrc/src/main/kotlin/CommonConfig.kt b/buildSrc/src/main/kotlin/CommonConfig.kt new file mode 100644 index 000000000..e93f4a2dd --- /dev/null +++ b/buildSrc/src/main/kotlin/CommonConfig.kt @@ -0,0 +1,18 @@ +import org.gradle.api.Project +import org.gradle.kotlin.dsl.repositories + +fun Project.applyCommonConfiguration() { + group = rootProject.group + version = rootProject.version + + repositories { + mavenCentral() + maven { url = uri("https://maven.sk89q.com/repo/") } + maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") } + } + configurations.all { + resolutionStrategy { + cacheChangingModulesFor(5, "minutes") + } + } +} diff --git a/buildSrc/src/main/kotlin/GradleExtras.kt b/buildSrc/src/main/kotlin/GradleExtras.kt new file mode 100644 index 000000000..e7d1e0ede --- /dev/null +++ b/buildSrc/src/main/kotlin/GradleExtras.kt @@ -0,0 +1,12 @@ +import org.gradle.api.Project +import org.gradle.api.plugins.ExtraPropertiesExtension +import org.gradle.api.plugins.JavaPluginConvention +import org.gradle.api.tasks.SourceSetContainer +import org.gradle.kotlin.dsl.getByType +import org.gradle.kotlin.dsl.the + +val Project.ext: ExtraPropertiesExtension + get() = extensions.getByType() + +val Project.sourceSets: SourceSetContainer + get() = the().sourceSets diff --git a/buildSrc/src/main/kotlin/LibsConfig.kt b/buildSrc/src/main/kotlin/LibsConfig.kt new file mode 100644 index 000000000..c2754d487 --- /dev/null +++ b/buildSrc/src/main/kotlin/LibsConfig.kt @@ -0,0 +1,98 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import org.gradle.api.Project +import org.gradle.api.artifacts.ModuleDependency +import org.gradle.api.internal.HasConvention +import org.gradle.api.plugins.MavenRepositoryHandlerConvention +import org.gradle.api.tasks.Upload +import org.gradle.api.tasks.bundling.Jar +import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.get +import org.gradle.kotlin.dsl.getPlugin +import org.gradle.kotlin.dsl.invoke +import org.gradle.kotlin.dsl.register + +fun Project.applyLibrariesConfiguration() { + applyCommonConfiguration() + apply(plugin = "java-base") + apply(plugin = "maven") + apply(plugin = "com.github.johnrengelman.shadow") + apply(plugin = "com.jfrog.artifactory") + + configurations { + create("shade") + getByName("archives").extendsFrom(getByName("default")) + } + + group = "${rootProject.group}.worldedit-libs" + + tasks.register("jar") { + configurations = listOf(project.configurations["shade"]) + archiveClassifier.set("") + + dependencies { + exclude(dependency("com.google.guava:guava")) + exclude(dependency("com.google.code.gson:gson")) + exclude(dependency("org.checkerframework:checker-qual")) + } + + relocate("net.kyori.text", "com.sk89q.worldedit.util.formatting.text") + } + val altConfigFiles = { artifactType: String -> + val deps = configurations["shade"].incoming.dependencies + .filterIsInstance() + .map { it.copy() } + .map { dependency -> + dependency.artifact { + name = dependency.name + type = artifactType + extension = "jar" + classifier = artifactType + } + dependency + } + + files(configurations.detachedConfiguration(*deps.toTypedArray()) + .resolvedConfiguration.lenientConfiguration.artifacts + .filter { it.classifier == artifactType } + .map { zipTree(it.file) }) + } + tasks.register("sourcesJar") { + from({ + altConfigFiles("sources") + }) + val filePattern = Regex("(.*)net/kyori/text((?:/|$).*)") + val textPattern = Regex("net\\.kyori\\.text") + eachFile { + filter { + it.replaceFirst(textPattern, "com.sk89q.worldedit.util.formatting.text") + } + path = path.replaceFirst(filePattern, "$1com/sk89q/worldedit/util/formatting/text$2") + } + archiveClassifier.set("sources") + } + + tasks.named("assemble").configure { + dependsOn("jar", "sourcesJar") + } + + artifacts { + val jar = tasks.named("jar") + add("default", jar) { + builtBy(jar) + } + val sourcesJar = tasks.named("sourcesJar") + add("archives", sourcesJar) { + builtBy(sourcesJar) + } + } + + tasks.register("install") { + configuration = configurations["archives"] + (repositories as HasConvention).convention.getPlugin().mavenInstaller { + pom.version = project.version.toString() + pom.artifactId = project.name + } + } + + applyCommonArtifactoryConfig() +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt new file mode 100644 index 000000000..c5deea857 --- /dev/null +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -0,0 +1,112 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import net.minecrell.gradle.licenser.LicenseExtension +import org.gradle.api.JavaVersion +import org.gradle.api.Project +import org.gradle.api.plugins.JavaPluginConvention +import org.gradle.api.plugins.quality.CheckstyleExtension +import org.gradle.api.tasks.bundling.Jar +import org.gradle.api.tasks.javadoc.Javadoc +import org.gradle.api.tasks.testing.Test +import org.gradle.external.javadoc.CoreJavadocOptions +import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.dependencies +import org.gradle.kotlin.dsl.get +import org.gradle.kotlin.dsl.getByName +import org.gradle.kotlin.dsl.named +import org.gradle.kotlin.dsl.register +import org.gradle.kotlin.dsl.withType + +fun Project.applyPlatformAndCoreConfiguration() { + applyCommonConfiguration() + apply(plugin = "java") + apply(plugin = "eclipse") + apply(plugin = "idea") + apply(plugin = "maven") + apply(plugin = "checkstyle") + apply(plugin = "com.github.johnrengelman.shadow") + apply(plugin = "com.jfrog.artifactory") + apply(plugin = "net.minecrell.licenser") + + ext["internalVersion"] = "$version;${rootProject.ext["gitCommitHash"]}" + + configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + configure { + configFile = rootProject.file("config/checkstyle/checkstyle.xml") + toolVersion = "7.6.1" + } + + tasks.withType().configureEach { + useJUnitPlatform() + } + + dependencies { + "testImplementation"("org.junit.jupiter:junit-jupiter-api:${Versions.JUNIT}") + "testRuntime"("org.junit.jupiter:junit-jupiter-engine:${Versions.JUNIT}") + } + + // Java 8 turns on doclint which we fail + tasks.withType().configureEach { + (options as CoreJavadocOptions).addStringOption("Xdoclint:none", "-quiet") + } + + tasks.register("javadocJar") { + dependsOn("javadoc") + archiveClassifier.set("javadoc") + from(tasks.getByName("javadoc").destinationDir) + } + + tasks.named("assemble").configure { + dependsOn("javadocJar") + } + + artifacts { + add("archives", tasks.named("jar")) + add("archives", tasks.named("javadocJar")) + } + + if (name == "worldedit-core" || name == "worldedit-bukkit") { + tasks.register("sourcesJar") { + dependsOn("classes") + archiveClassifier.set("sources") + from(sourceSets["main"].allSource) + } + + artifacts { + add("archives", tasks.named("sourcesJar")) + } + tasks.named("assemble").configure { + dependsOn("sourcesJar") + } + } + + tasks.named("check").configure { + dependsOn("checkstyleMain", "checkstyleTest") + } + + applyCommonArtifactoryConfig() + + configure { + header = rootProject.file("HEADER.txt") + include("**/*.java") + } +} + +fun Project.applyShadowConfiguration() { + tasks.named("shadowJar") { + archiveClassifier.set("dist") + dependencies { + include(project(":worldedit-libs:core")) + include(project(":worldedit-libs:${project.name.replace("worldedit-", "")}")) + include(project(":worldedit-core")) + } + exclude("GradleStart**") + exclude(".cache") + exclude("LICENSE*") + minimize() + } +} diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt new file mode 100644 index 000000000..e0c2b4763 --- /dev/null +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -0,0 +1,7 @@ +object Versions { + const val TEXT = "3.0.1" + const val TEXT_EXTRAS = "3.0.2" + const val PISTON = "0.4.3" + const val AUTO_VALUE = "1.6.5" + const val JUNIT = "5.5.0" +} diff --git a/gradle.properties b/gradle.properties index bca9aaf56..a2cc53d8e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -# Sets default memory used for gradle commands. Can be overridden by user or command line properties. -# This is required to provide enough memory for the Minecraft decompilation process. -#org.gradle.jvmargs=-Xmx3G -org.gradle.daemon=false \ No newline at end of file +group=com.sk89q.worldedit +version=7.0.1-SNAPSHOT + +org.gradle.jvmargs=-Xmx1G diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 0d4a95168..5c2d1cf01 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a9534e761..430dfabc5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Thu Mar 14 00:19:48 PDT 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip diff --git a/gradlew b/gradlew index cccdd3d51..8e25e6c19 100755 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/gradlew.bat b/gradlew.bat index e95643d6a..24467a141 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index a7c14e8ee..000000000 --- a/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -rootProject.name = 'worldedit' - -include 'worldedit-libs' - -['bukkit', 'core', 'forge', 'sponge', 'fabric'].forEach { - include "worldedit-libs:$it" - include "worldedit-$it" -} -include "worldedit-libs:core:ap" - -include "worldedit-core:doctools" diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 000000000..6da7bedcc --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,11 @@ +rootProject.name = "worldedit" + +include("worldedit-libs") + +listOf("bukkit", "core", "forge", "sponge", "fabric").forEach { + include("worldedit-libs:$it") + include("worldedit-$it") +} +include("worldedit-libs:core:ap") + +include("worldedit-core:doctools") diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle deleted file mode 100644 index ba7a34f31..000000000 --- a/worldedit-bukkit/build.gradle +++ /dev/null @@ -1,63 +0,0 @@ -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: 'maven' -apply plugin: 'java-library' - -repositories { - maven { url "https://hub.spigotmc.org/nexus/content/groups/public" } - maven { url "https://repo.codemc.org/repository/maven-public" } - maven { url "https://papermc.io/repo/repository/maven-public/" } -} - -configurations.all { Configuration it -> - it.resolutionStrategy { ResolutionStrategy rs -> - rs.force("com.google.guava:guava:21.0") - } -} - -dependencies { - api project(':worldedit-core') - api project(':worldedit-libs:bukkit') - api 'org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT' // zzz - compileOnly 'com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT' - implementation 'io.papermc:paperlib:1.0.2' - compileOnly 'com.sk89q:dummypermscompat:1.10' - implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' - implementation 'org.bstats:bstats-bukkit:1.5' - testCompile 'org.mockito:mockito-core:1.9.0-rc1' -} - -processResources { - filesMatching('plugin.yml') { - expand 'internalVersion': project.internalVersion - } - from (zipTree('src/main/resources/worldedit-adapters.jar').matching { - exclude 'META-INF/' - }) - exclude '**/worldedit-adapters.jar' -} - -jar { - manifest { - attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", - "WorldEdit-Version": version) - } -} - -shadowJar { - dependencies { - relocate "org.slf4j", "com.sk89q.worldedit.slf4j" - relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge" - include(dependency(':worldedit-core')) - include(dependency('org.slf4j:slf4j-api')) - include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) - relocate ("org.bstats", "com.sk89q.worldedit.bukkit.bstats") { - include(dependency("org.bstats:bstats-bukkit:1.5")) - } - relocate ("io.papermc.lib", "com.sk89q.worldedit.bukkit.paperlib") { - include(dependency("io.papermc:paperlib:1.0.2")) - } - } -} - -build.dependsOn(shadowJar) diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts new file mode 100644 index 000000000..1343ff2be --- /dev/null +++ b/worldedit-bukkit/build.gradle.kts @@ -0,0 +1,71 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +plugins { + `java-library` +} + +applyPlatformAndCoreConfiguration() +applyShadowConfiguration() + +repositories { + maven { url = uri("https://hub.spigotmc.org/nexus/content/groups/public") } + maven { url = uri("https://repo.codemc.org/repository/maven-public") } + maven { url = uri("https://papermc.io/repo/repository/maven-public/") } +} + +configurations.all { + resolutionStrategy { + force("com.google.guava:guava:21.0") + } +} + +dependencies { + "api"(project(":worldedit-core")) + "api"(project(":worldedit-libs:bukkit")) + "api"("org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT") { + exclude("junit", "junit") + } + "compileOnly"("com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT") + "implementation"("io.papermc:paperlib:1.0.2") + "compileOnly"("com.sk89q:dummypermscompat:1.10") + "implementation"("org.apache.logging.log4j:log4j-slf4j-impl:2.8.1") + "implementation"("org.bstats:bstats-bukkit:1.5") + "testCompile"("org.mockito:mockito-core:1.9.0-rc1") +} + +tasks.named("processResources") { + filesMatching("plugin.yml") { + expand("internalVersion" to project.ext["internalVersion"]) + } + from(zipTree("src/main/resources/worldedit-adapters.jar").matching { + exclude("META-INF/") + }) + exclude("**/worldedit-adapters.jar") +} + +tasks.named("jar") { + manifest { + attributes("Class-Path" to "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", + "WorldEdit-Version" to project.version) + } +} + +tasks.named("shadowJar") { + dependencies { + relocate("org.slf4j", "com.sk89q.worldedit.slf4j") + relocate("org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge") + include(dependency(":worldedit-core")) + include(dependency("org.slf4j:slf4j-api")) + include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) + relocate("org.bstats", "com.sk89q.worldedit.bukkit.bstats") { + include(dependency("org.bstats:bstats-bukkit:1.5")) + } + relocate("io.papermc.lib", "com.sk89q.worldedit.bukkit.paperlib") { + include(dependency("io.papermc:paperlib:1.0.2")) + } + } +} + +tasks.named("assemble").configure { + dependsOn("shadowJar") +} diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index f311a9e1b..79526882f 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -335,7 +335,11 @@ public class BukkitAdapter { * @return WorldEdit EntityType */ public static EntityType adapt(org.bukkit.entity.EntityType entityType) { - return EntityTypes.get(entityType.getName().toLowerCase(Locale.ROOT)); + final String name = entityType.getName(); + if (name == null) { + return null; + } + return EntityTypes.get(name.toLowerCase(Locale.ROOT)); } public static org.bukkit.entity.EntityType adapt(EntityType entityType) { diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index b5cd6bd37..3e12279ea 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -185,14 +185,13 @@ public class BukkitPlayer extends AbstractPlayerActor { } @Override - public void floatAt(int x, int y, int z, boolean alwaysGlass) { - if (alwaysGlass || !player.getAllowFlight()) { - super.floatAt(x, y, z, alwaysGlass); - return; - } + public boolean isAllowedToFly() { + return player.getAllowFlight(); + } - setPosition(Vector3.at(x + 0.5, y, z + 0.5)); - player.setFlying(true); + @Override + public void setFlying(boolean flying) { + player.setFlying(flying); } @Override diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index 977985df7..438c43cbd 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -316,15 +316,16 @@ public class BukkitWorld extends AbstractWorld { @Override public boolean equals(Object other) { - if (worldRef.get() == null) { + final World ref = worldRef.get(); + if (ref == null) { return false; } else if (other == null) { return false; } else if ((other instanceof BukkitWorld)) { World otherWorld = ((BukkitWorld) other).worldRef.get(); - return otherWorld != null && otherWorld.equals(getWorld()); + return ref.equals(otherWorld); } else if (other instanceof com.sk89q.worldedit.world.World) { - return ((com.sk89q.worldedit.world.World) other).getName().equals(getName()); + return ((com.sk89q.worldedit.world.World) other).getName().equals(ref.getName()); } else { return false; } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index a81aab7c5..e4fb3ea8c 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -96,7 +96,6 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { private static final Logger log = LoggerFactory.getLogger(WorldEditPlugin.class); public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui"; private static WorldEditPlugin INSTANCE; - private static WorldInitListener worldInitListener = null; private BukkitImplAdapter bukkitAdapter; private BukkitServerInterface server; @@ -139,22 +138,19 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { getServer().getPluginManager().registerEvents(new AsyncTabCompleteListener(), this); } - // register this so we can load world-dependent data right as the first world is loading - if (worldInitListener != null) { + initializeRegistries(); // this creates the objects matching Bukkit's enums - but doesn't fill them with data yet + if (Bukkit.getWorlds().isEmpty()) { + setupPreWorldData(); + // register this so we can load world-dependent data right as the first world is loading + getServer().getPluginManager().registerEvents(new WorldInitListener(), this); + } else { getLogger().warning("Server reload detected. This may cause various issues with WorldEdit and dependent plugins."); try { - // these don't stick around between reload - loadAdapter(); - loadConfig(); - WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); + setupPreWorldData(); + // since worlds are loaded already, we can do this now + setupWorldData(); } catch (Throwable ignored) { } - } else { - getServer().getPluginManager().registerEvents((worldInitListener = new WorldInitListener()), this); - loadAdapter(); // Need an adapter to work with special blocks with NBT data - setupRegistries(); - WorldEdit.getInstance().loadMappings(); - loadConfig(); // Load configuration } // Enable metrics @@ -162,12 +158,19 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { PaperLib.suggestPaper(this); } + private void setupPreWorldData() { + loadAdapter(); + loadConfig(); + WorldEdit.getInstance().loadMappings(); + } + private void setupWorldData() { - setupTags(); + setupTags(); // datapacks aren't loaded until just before the world is, and bukkit has no event for this + // so the earliest we can do this is in WorldInit WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); } - private void setupRegistries() { + private void initializeRegistries() { // Biome for (Biome biome : Biome.values()) { String lowerCaseBiomeName = biome.name().toLowerCase(Locale.ROOT); @@ -487,9 +490,9 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { if (!event.isCommand()) return; String buffer = event.getBuffer(); - final String[] parts = buffer.split(" "); - if (parts.length < 1) return; - final String label = parts[0]; + int firstSpace = buffer.indexOf(' '); + if (firstSpace < 0) return; + final String label = buffer.substring(0, firstSpace); final Optional command = WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getCommandManager().getCommand(label); if (!command.isPresent()) return; diff --git a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar index b940ae841..d1659adf2 100644 Binary files a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar and b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar differ diff --git a/worldedit-bukkit/src/test/java/com/sk89q/wepif/DinnerPermsResolverTest.java b/worldedit-bukkit/src/test/java/com/sk89q/wepif/DinnerPermsResolverTest.java index e207e7b8d..37deab330 100644 --- a/worldedit-bukkit/src/test/java/com/sk89q/wepif/DinnerPermsResolverTest.java +++ b/worldedit-bukkit/src/test/java/com/sk89q/wepif/DinnerPermsResolverTest.java @@ -19,26 +19,26 @@ package com.sk89q.wepif; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - import org.bukkit.Server; import org.bukkit.plugin.PluginManager; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class DinnerPermsResolverTest { private DinnerPermsResolver resolver; - @Before + @BeforeEach public void setUp() { Server server = mock(Server.class); when(server.getPluginManager()).thenReturn(mock(PluginManager.class)); resolver = new DinnerPermsResolver(server); } - + @Test public void testBasicResolving() { final TestOfflinePermissible permissible = new TestOfflinePermissible(); @@ -49,7 +49,7 @@ public class DinnerPermsResolverTest { assertFalse(resolver.hasPermission(permissible, "completely.unrelated")); permissible.clearPermissions(); } - + @Test public void testBasicWildcardResolution() { final TestOfflinePermissible permissible = new TestOfflinePermissible(); @@ -59,7 +59,7 @@ public class DinnerPermsResolverTest { assertTrue(resolver.hasPermission(permissible, "commandbook.spawnmob.spider.skeleton")); permissible.clearPermissions(); } - + @Test public void testNegatingNodes() { final TestOfflinePermissible permissible = new TestOfflinePermissible(); @@ -67,16 +67,16 @@ public class DinnerPermsResolverTest { permissible.setPermission("commandbook.cuteasianboys", false); permissible.setPermission("commandbook.warp.*", false); permissible.setPermission("commandbook.warp.create", true); - + assertTrue(resolver.hasPermission(permissible, "commandbook.motd")); assertFalse(resolver.hasPermission(permissible, "commandbook.cuteasianboys")); assertFalse(resolver.hasPermission(permissible, "commandbook.warp.remove")); assertTrue(resolver.hasPermission(permissible, "commandbook.warp.create")); - + permissible.clearPermissions(); } - - + + @Test public void testInGroup() { final TestOfflinePermissible permissible = new TestOfflinePermissible(); diff --git a/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitWorldTest.java b/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitWorldTest.java index e6776cf8c..8851fb926 100644 --- a/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitWorldTest.java +++ b/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitWorldTest.java @@ -20,15 +20,16 @@ package com.sk89q.worldedit.bukkit; import com.sk89q.worldedit.util.TreeGenerator; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; public class BukkitWorldTest { @Test public void testTreeTypeMapping() { for (TreeGenerator.TreeType type : TreeGenerator.TreeType.values()) { - Assert.assertNotNull("No mapping for: " + type, BukkitWorld.toBukkitTreeType(type)); + assertNotNull(BukkitWorld.toBukkitTreeType(type), "No mapping for: " + type); } } diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle deleted file mode 100644 index 9ed0f8b2a..000000000 --- a/worldedit-core/build.gradle +++ /dev/null @@ -1,52 +0,0 @@ -plugins { - id("net.ltgt.apt") version "0.21" -} - -apply plugin: 'java-library' -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: 'net.ltgt.apt-eclipse' -apply plugin: 'net.ltgt.apt-idea' - -configurations.all { Configuration it -> - it.resolutionStrategy { ResolutionStrategy rs -> - rs.force("com.google.guava:guava:21.0") - } -} - -dependencies { - compile project(':worldedit-libs:core') - compile 'de.schlichtherle:truezip:6.8.3' - compile 'rhino:js:1.7R2' - compile 'org.yaml:snakeyaml:1.9' - compile 'com.google.guava:guava:21.0' - compile 'com.google.code.findbugs:jsr305:1.3.9' - compile 'com.google.code.gson:gson:2.8.0' - compile 'com.googlecode.json-simple:json-simple:1.1.1' - compile 'org.slf4j:slf4j-api:1.7.26' - - compileOnly project(':worldedit-libs:core:ap') - annotationProcessor project(':worldedit-libs:core:ap') - annotationProcessor "com.google.guava:guava:21.0" - def avVersion = "1.6.5" - compileOnly "com.google.auto.value:auto-value-annotations:$avVersion" - annotationProcessor "com.google.auto.value:auto-value:$avVersion" - //compile 'net.sf.trove4j:trove4j:3.0.3' - testCompile 'org.mockito:mockito-core:1.9.0-rc1' -} - -tasks.withType(JavaCompile).configureEach { - it.options.compilerArgs.add("-Aarg.name.key.prefix=") -} - -sourceSets { - main { - java { - srcDir 'src/main/java' - srcDir 'src/legacy/java' - } - resources { - srcDir 'src/main/resources' - } - } -} diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts new file mode 100644 index 000000000..274cf2e06 --- /dev/null +++ b/worldedit-core/build.gradle.kts @@ -0,0 +1,49 @@ +plugins { + id("java-library") + id("net.ltgt.apt-eclipse") + id("net.ltgt.apt-idea") +} + +applyPlatformAndCoreConfiguration() + +configurations.all { + resolutionStrategy { + force("com.google.guava:guava:21.0") + } +} + +dependencies { + "compile"(project(":worldedit-libs:core")) + "compile"("de.schlichtherle:truezip:6.8.3") + "compile"("org.mozilla:rhino:1.7.11") + "compile"("org.yaml:snakeyaml:1.9") + "compile"("com.google.guava:guava:21.0") + "compile"("com.google.code.findbugs:jsr305:1.3.9") + "compile"("com.google.code.gson:gson:2.8.0") + "compile"("org.slf4j:slf4j-api:1.7.26") + + "compileOnly"(project(":worldedit-libs:core:ap")) + "annotationProcessor"(project(":worldedit-libs:core:ap")) + // ensure this is on the classpath for the AP + "annotationProcessor"("com.google.guava:guava:21.0") + "compileOnly"("com.google.auto.value:auto-value-annotations:${Versions.AUTO_VALUE}") + "annotationProcessor"("com.google.auto.value:auto-value:${Versions.AUTO_VALUE}") + "testCompile"("org.mockito:mockito-core:1.9.0-rc1") +} + +tasks.withType().configureEach { + dependsOn(":worldedit-libs:build") + options.compilerArgs.add("-Aarg.name.key.prefix=") +} + +sourceSets { + main { + java { + srcDir("src/main/java") + srcDir("src/legacy/java") + } + resources { + srcDir("src/main/resources") + } + } +} diff --git a/worldedit-core/doctools/build.gradle.kts b/worldedit-core/doctools/build.gradle.kts index 002f367bd..803e1078e 100644 --- a/worldedit-core/doctools/build.gradle.kts +++ b/worldedit-core/doctools/build.gradle.kts @@ -1,17 +1,15 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") version "1.3.31" + kotlin("jvm") version "1.3.41" } +applyCommonConfiguration() + tasks.withType { kotlinOptions.jvmTarget = "1.8" } -repositories { - jcenter() -} - dependencies { "implementation"(project(":worldedit-libs:core:ap")) "implementation"(project(":worldedit-core")) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index 4e2b714e2..29747852e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -180,7 +180,8 @@ public class BiomeCommands { Mask2D mask2d = mask != null ? mask.toMask2D() : null; if (atPosition) { - region = new CuboidRegion(player.getLocation().toVector().toBlockPoint(), player.getLocation().toVector().toBlockPoint()); + final BlockVector3 pos = player.getLocation().toVector().toBlockPoint(); + region = new CuboidRegion(pos, pos); } else { region = session.getSelection(world); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java index e9a9e231d..5d5d245d1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.internal.anvil.ChunkDeleter; import com.sk89q.worldedit.internal.anvil.ChunkDeletionInfo; @@ -34,6 +35,7 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; @@ -50,8 +52,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.time.ZonedDateTime; import java.util.ArrayList; +import java.util.List; import java.util.Set; -import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; @@ -93,11 +95,11 @@ public class ChunkCommands { @CommandPermissions("worldedit.listchunks") public void listChunks(Player player, LocalSession session, @ArgFlag(name = 'p', desc = "Page number.", def = "1") int page) throws WorldEditException { - Set chunks = session.getSelection(player.getWorld()).getChunks(); + final Region region = session.getSelection(player.getWorld()); - PaginationBox paginationBox = PaginationBox.fromStrings("Selected Chunks", "/listchunks -p %page%", - chunks.stream().map(BlockVector2::toString).collect(Collectors.toList())); - player.print(paginationBox.create(page)); + WorldEditAsyncCommandBuilder.createAndSendMessage(player, + () -> new ChunkListPaginationBox(region).create(page), + "Listing chunks for " + player.getName()); } @Command( @@ -134,8 +136,8 @@ public class ChunkCommands { newBatch.backup = true; final Region selection = session.getSelection(player.getWorld()); if (selection instanceof CuboidRegion) { - newBatch.minChunk = BlockVector2.at(selection.getMinimumPoint().getBlockX() >> 4, selection.getMinimumPoint().getBlockZ() >> 4); - newBatch.maxChunk = BlockVector2.at(selection.getMaximumPoint().getBlockX() >> 4, selection.getMaximumPoint().getBlockZ() >> 4); + newBatch.minChunk = selection.getMinimumPoint().shr(4).toBlockVector2(); + newBatch.maxChunk = selection.getMaximumPoint().shr(4).toBlockVector2(); } else { // this has a possibility to OOM for very large selections still Set chunks = selection.getChunks(); @@ -168,4 +170,27 @@ public class ChunkCommands { .clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop")))); } + private static class ChunkListPaginationBox extends PaginationBox { + //private final Region region; + private final List chunks; + + ChunkListPaginationBox(Region region) { + super("Selected Chunks", "/listchunks -p %page%"); + // TODO make efficient/streamable/calculable implementations of this + // for most region types, so we can just store the region and random-access get one page of chunks + // (this is non-trivial for some types of selections...) + //this.region = region.clone(); + this.chunks = new ArrayList<>(region.getChunks()); + } + + @Override + public Component getComponent(int number) { + return TextComponent.of(chunks.get(number).toString()); + } + + @Override + public int getComponentsSize() { + return chunks.size(); + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index 4ae72b9d7..9fcfd2c37 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -162,13 +162,13 @@ public class GenerationCommands { final double radiusX, radiusY, radiusZ; switch (radii.size()) { case 1: - radiusX = radiusY = radiusZ = Math.max(1, radii.get(0)); + radiusX = radiusY = radiusZ = Math.max(0, radii.get(0)); break; case 3: - radiusX = Math.max(1, radii.get(0)); - radiusY = Math.max(1, radii.get(1)); - radiusZ = Math.max(1, radii.get(2)); + radiusX = Math.max(0, radii.get(0)); + radiusY = Math.max(0, radii.get(1)); + radiusZ = Math.max(0, radii.get(2)); break; default: @@ -205,7 +205,7 @@ public class GenerationCommands { @Arg(desc = "The density of the forest, between 0 and 100", def = "5") double density) throws WorldEditException { checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100"); - density = density / 100; + density /= 100; int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type); player.print(affected + " trees created."); return affected; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 47f3daf9e..a2b59ffbd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.command; +import com.google.common.collect.Multimap; +import com.google.common.io.Files; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -42,10 +44,10 @@ import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.formatting.component.CodeFormat; import com.sk89q.worldedit.util.formatting.component.ErrorFormat; import com.sk89q.worldedit.util.formatting.component.PaginationBox; -import com.sk89q.worldedit.util.formatting.component.SchematicPaginationBox; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.io.Closer; import com.sk89q.worldedit.util.io.file.FilenameException; @@ -68,7 +70,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.Callable; +import java.util.regex.Pattern; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; /** @@ -404,4 +408,44 @@ public class SchematicCommands { } return fileList; } + + private static class SchematicPaginationBox extends PaginationBox { + private final String prefix; + private final File[] files; + + SchematicPaginationBox(String rootDir, File[] files, String pageCommand) { + super("Available schematics", pageCommand); + this.prefix = rootDir == null ? "" : rootDir; + this.files = files; + } + + @Override + public Component getComponent(int number) { + checkArgument(number < files.length && number >= 0); + File file = files[number]; + Multimap exts = ClipboardFormats.getFileExtensionMap(); + String format = exts.get(Files.getFileExtension(file.getName())) + .stream().findFirst().map(ClipboardFormat::getName).orElse("Unknown"); + boolean inRoot = file.getParentFile().getName().equals(prefix); + + String path = inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1]; + + return TextComponent.builder() + .content("") + .append(TextComponent.of("[L]") + .color(TextColor.GOLD) + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/schem load " + path)) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to load")))) + .append(TextComponent.space()) + .append(TextComponent.of(path) + .color(TextColor.DARK_GREEN) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of(format)))) + .build(); + } + + @Override + public int getComponentsSize() { + return files.length; + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index d0dd6ef5a..88285e475 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.command; +import com.google.common.base.Strings; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -56,16 +57,19 @@ import com.sk89q.worldedit.regions.selector.SphereRegionSelector; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.formatting.component.BlockDistributionResult; import com.sk89q.worldedit.util.formatting.component.CommandListBox; +import com.sk89q.worldedit.util.formatting.component.InvalidComponentException; import com.sk89q.worldedit.util.formatting.component.PaginationBox; import com.sk89q.worldedit.util.formatting.component.SubtleFormat; import com.sk89q.worldedit.util.formatting.component.TextComponentProducer; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.storage.ChunkStore; @@ -570,7 +574,7 @@ public class SelectionCommands { } case LIST: default: - CommandListBox box = new CommandListBox("Selection modes", null); + CommandListBox box = new CommandListBox("Selection modes", null, null); box.setHidingHelp(true); TextComponentProducer contents = box.getContents(); contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline(); @@ -608,4 +612,62 @@ public class SelectionCommands { session.dispatchCUISelection(player); } + private static class BlockDistributionResult extends PaginationBox { + + private final List> distribution; + private final int totalBlocks; + private final boolean separateStates; + + BlockDistributionResult(List> distribution, boolean separateStates) { + super("Block Distribution", "//distr -p %page%" + (separateStates ? " -d" : "")); + this.distribution = distribution; + // note: doing things like region.getArea is inaccurate for non-cuboids. + this.totalBlocks = distribution.stream().mapToInt(Countable::getAmount).sum(); + this.separateStates = separateStates; + setComponentsPerPage(7); + } + + @Override + public Component getComponent(int number) { + Countable c = distribution.get(number); + TextComponent.Builder line = TextComponent.builder(); + + final int count = c.getAmount(); + + final double perc = count / (double) totalBlocks * 100; + final int maxDigits = (int) (Math.log10(totalBlocks) + 1); + final int curDigits = (int) (Math.log10(count) + 1); + line.append(String.format("%s%.3f%% ", perc < 10 ? " " : "", perc), TextColor.GOLD); + final int space = maxDigits - curDigits; + String pad = Strings.repeat(" ", space == 0 ? 2 : 2 * space + 1); + line.append(String.format("%s%s", count, pad), TextColor.YELLOW); + + final BlockState state = c.getID(); + final BlockType blockType = state.getBlockType(); + TextComponent blockName = TextComponent.of(blockType.getName(), TextColor.LIGHT_PURPLE); + TextComponent toolTip; + if (separateStates && state != blockType.getDefaultState()) { + toolTip = TextComponent.of(state.getAsString(), TextColor.GRAY); + blockName = blockName.append(TextComponent.of("*", TextColor.LIGHT_PURPLE)); + } else { + toolTip = TextComponent.of(blockType.getId(), TextColor.GRAY); + } + blockName = blockName.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, toolTip)); + line.append(blockName); + + return line.build(); + } + + @Override + public int getComponentsSize() { + return distribution.size(); + } + + @Override + public Component create(int page) throws InvalidComponentException { + super.getContents().append(TextComponent.of("Total Block Count: " + totalBlocks, TextColor.GRAY)) + .append(TextComponent.newline()); + return super.create(page); + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 76e5d441e..9d3765943 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -523,7 +523,8 @@ public class UtilityCommands { int page, @Arg(desc = "The command to retrieve help for", def = "", variable = true) List command) throws WorldEditException { - PrintCommandHelp.help(command, page, listSubCommands, we, actor); + PrintCommandHelp.help(command, page, listSubCommands, + we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "//help"); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java index 02ab382a4..25329885a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java @@ -164,6 +164,7 @@ public class WorldEditCommands { int page, @Arg(desc = "The command to retrieve help for", def = "", variable = true) List command) throws WorldEditException { - PrintCommandHelp.help(command, page, listSubCommands, we, actor); + PrintCommandHelp.help(command, page, listSubCommands, + we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "/worldedit help"); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java index 2e324f9ee..e8724208b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java @@ -92,7 +92,7 @@ public class BrushTool implements TraceTool { * @return the mask used to stop block traces */ public @Nullable Mask getTraceMask() { - return mask; + return this.traceMask; } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java index aedcb578c..08288636e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java @@ -23,44 +23,78 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.util.LocatedBlock; +import com.sk89q.worldedit.util.collection.LocatedBlockList; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.LinkedHashSet; +import java.util.Set; public class GravityBrush implements Brush { private final boolean fullHeight; - + public GravityBrush(boolean fullHeight) { this.fullHeight = fullHeight; } @Override public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { - final double startY = fullHeight ? editSession.getWorld().getMaxY() : position.getBlockY() + size; - for (double x = position.getBlockX() + size; x > position.getBlockX() - size; --x) { - for (double z = position.getBlockZ() + size; z > position.getBlockZ() - size; --z) { - double y = startY; - final List blockTypes = new ArrayList<>(); - for (; y > position.getBlockY() - size; --y) { - final BlockVector3 pt = BlockVector3.at(x, y, z); - final BlockState block = editSession.getBlock(pt); - if (!block.getBlockType().getMaterial().isAir()) { - blockTypes.add(block); - editSession.setBlock(pt, BlockTypes.AIR.getDefaultState()); + double yMax = fullHeight ? editSession.getWorld().getMaxY() : position.getY() + size; + double yMin = Math.max(position.getY() - size, 0); + LocatedBlockList column = new LocatedBlockList(); + Set removedBlocks = new LinkedHashSet<>(); + for (double x = position.getX() - size; x <= position.getX() + size; x++) { + for (double z = position.getZ() - size; z <= position.getZ() + size; z++) { + /* + * Algorithm: + * 1. Find lowest air block in the selection -> $lowestAir = position + * 2. Move the first non-air block above it down to $lowestAir + * 3. Add 1 to $lowestAir's y-coord. + * 4. If more blocks above current position, repeat from 2 + */ + + BlockVector3 lowestAir = null; + for (double y = yMin; y <= yMax; y++) { + BlockVector3 pt = BlockVector3.at(x, y, z); + + BaseBlock block = editSession.getFullBlock(pt); + + if (block.getBlockType().getMaterial().isAir()) { + if (lowestAir == null) { + // we found the lowest air block + lowestAir = pt; + } + continue; } - } - BlockVector3 pt = BlockVector3.at(x, y, z); - Collections.reverse(blockTypes); - for (int i = 0; i < blockTypes.size();) { - if (editSession.getBlock(pt).getBlockType().getMaterial().isAir()) { - editSession.setBlock(pt, blockTypes.get(i++)); + + if (lowestAir == null) { + // no place to move the block to + continue; } - pt = pt.add(0, 1, 0); + + BlockVector3 newPos = lowestAir; + // we know the block above must be air, + // since either this block is being moved into it, + // or there has been more air before this block + lowestAir = lowestAir.add(0, 1, 0); + + removedBlocks.remove(newPos); + column.add(newPos, block); + removedBlocks.add(pt); } + + for (LocatedBlock block : column) { + editSession.setBlock(block.getLocation(), block.getBlock()); + } + + for (BlockVector3 removedBlock : removedBlocks) { + editSession.setBlock(removedBlock, BlockTypes.AIR.getDefaultState()); + } + + column.clear(); + removedBlocks.clear(); } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java index ad7dad226..dc3e97865 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java @@ -67,11 +67,11 @@ public class PrintCommandHelp { return mapping.orElse(null); } - public static void help(List commandPath, int page, boolean listSubCommands, WorldEdit we, Actor actor) throws InvalidComponentException { - CommandManager manager = we.getPlatformManager().getPlatformCommandManager().getCommandManager(); + public static void help(List commandPath, int page, boolean listSubCommands, + CommandManager manager, Actor actor, String helpRootCommand) throws InvalidComponentException { if (commandPath.isEmpty()) { - printCommands(page, manager.getAllCommands(), actor, ImmutableList.of()); + printCommands(page, manager.getAllCommands(), actor, ImmutableList.of(), helpRootCommand); return; } @@ -93,7 +93,7 @@ public class PrintCommandHelp { toCommandString(visited), subCommand)); // full help for single command CommandUsageBox box = new CommandUsageBox(visited, visited.stream() - .map(Command::getName).collect(Collectors.joining(" "))); + .map(Command::getName).collect(Collectors.joining(" ")), helpRootCommand); actor.print(box.create()); return; } @@ -105,7 +105,7 @@ public class PrintCommandHelp { actor.printError(String.format("The sub-command '%s' under '%s' could not be found.", subCommand, toCommandString(visited))); // list subcommands for currentCommand - printCommands(page, getSubCommands(Iterables.getLast(visited)).values().stream(), actor, visited); + printCommands(page, getSubCommands(Iterables.getLast(visited)).values().stream(), actor, visited, helpRootCommand); return; } } @@ -114,10 +114,10 @@ public class PrintCommandHelp { if (subCommands.isEmpty() || !listSubCommands) { // Create the message - CommandUsageBox box = new CommandUsageBox(visited, toCommandString(visited)); + CommandUsageBox box = new CommandUsageBox(visited, toCommandString(visited), helpRootCommand); actor.print(box.create()); } else { - printCommands(page, subCommands.values().stream(), actor, visited); + printCommands(page, subCommands.values().stream(), actor, visited, helpRootCommand); } } @@ -126,7 +126,7 @@ public class PrintCommandHelp { } private static void printCommands(int page, Stream commandStream, Actor actor, - List commandList) throws InvalidComponentException { + List commandList, String helpRootCommand) throws InvalidComponentException { // Get a list of aliases List commands = commandStream .sorted(byCleanName()) @@ -135,7 +135,8 @@ public class PrintCommandHelp { String used = commandList.isEmpty() ? null : toCommandString(commandList); CommandListBox box = new CommandListBox( (used == null ? "Help" : "Subcommands: " + used), - "//help -s -p %page%" + (used == null ? "" : " " + used)); + helpRootCommand + " -s -p %page%" + (used == null ? "" : " " + used), + helpRootCommand); if (!actor.isPlayer()) { box.formatForConsole(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java index f51f992ac..2054dc603 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -19,7 +19,10 @@ package com.sk89q.worldedit.extension.platform; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.NotABlockException; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extent.Extent; @@ -32,6 +35,7 @@ import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TargetBlock; import com.sk89q.worldedit.util.auth.AuthorizationException; +import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -173,7 +177,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { if (spots == 2) { final BlockVector3 platform = BlockVector3.at(x, y - 2, z); final BlockState block = world.getBlock(platform); - final com.sk89q.worldedit.world.block.BlockType type = block.getBlockType(); + final BlockType type = block.getBlockType(); // Don't get put in lava! if (type == BlockTypes.LAVA) { @@ -259,6 +263,13 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { // Found a ceiling! if (world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) { int platformY = Math.max(initialY, y - 3 - clearance); + if (platformY < initialY) { // if ==, they already have the given clearance, if <, clearance is too large + printError("Not enough space above you!"); + return false; + } else if (platformY == initialY) { + printError("You're already at the ceiling."); + return false; + } floatAt(x, platformY + 1, z, alwaysGlass); return true; } @@ -302,25 +313,49 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public void floatAt(int x, int y, int z, boolean alwaysGlass) { - try { + if (alwaysGlass || !isAllowedToFly()) { BlockVector3 spot = BlockVector3.at(x, y - 1, z); - if (!getLocation().getExtent().getBlock(spot).getBlockType().getMaterial().isMovementBlocker()) { - getLocation().getExtent().setBlock(spot, BlockTypes.GLASS.getDefaultState()); + final World world = getWorld(); + if (!world.getBlock(spot).getBlockType().getMaterial().isMovementBlocker()) { + try (EditSession session = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, 1, this)) { + session.setBlock(spot, BlockTypes.GLASS.getDefaultState()); + } catch (MaxChangedBlocksException ignored) { + } } - } catch (WorldEditException e) { - e.printStackTrace(); + } else { + setFlying(true); } setPosition(Vector3.at(x + 0.5, y, z + 0.5)); } + /** + * Check whether the player is allowed to fly. + * + * @return true if allowed flight + */ + protected boolean isAllowedToFly() { + return false; + } + + /** + * Set whether the player is currently flying. + * + * @param flying true to fly + */ + protected void setFlying(boolean flying) { + } + + @Override public Location getBlockIn() { - return getLocation().setPosition(getLocation().toVector().floor()); + final Location location = getLocation(); + return location.setPosition(location.toVector().floor()); } @Override public Location getBlockOn() { - return getLocation().setPosition(getLocation().setY(getLocation().getY() - 1).toVector().floor()); + final Location location = getLocation(); + return location.setPosition(location.setY(location.getY() - 1).toVector().floor()); } @Override @@ -369,15 +404,16 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public Direction getCardinalDirection(int yawOffset) { - if (getLocation().getPitch() > 67.5) { + final Location location = getLocation(); + if (location.getPitch() > 67.5) { return Direction.DOWN; } - if (getLocation().getPitch() < -67.5) { + if (location.getPitch() < -67.5) { return Direction.UP; } // From hey0's code - double rot = (getLocation().getYaw() + yawOffset) % 360; //let's use real yaw now + double rot = (location.getYaw() + yawOffset) % 360; //let's use real yaw now if (rot < 0) { rot += 360.0; } @@ -394,51 +430,62 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { } } + private boolean canPassThroughBlock(Location curBlock) { + BlockVector3 blockPos = curBlock.toVector().toBlockPoint(); + BlockState block = curBlock.getExtent().getBlock(blockPos); + return !block.getBlockType().getMaterial().isMovementBlocker(); + } + /** - * Get the player's view yaw. - * - * @return yaw + * Advances the block target block until the current block is a wall + * @return true if a wall is found */ - - @Override - public boolean passThroughForwardWall(int range) { - int searchDist = 0; - TargetBlock hitBlox = new TargetBlock(this, range, 0.2); - Extent world = getLocation().getExtent(); - Location block; - boolean firstBlock = true; - int freeToFind = 2; - boolean inFree = false; - - while ((block = hitBlox.getNextBlock()) != null) { - boolean free = !world.getBlock(block.toVector().toBlockPoint()).getBlockType().getMaterial().isMovementBlocker(); - - if (firstBlock) { - firstBlock = false; - - if (!free) { - --freeToFind; - continue; - } - } - - ++searchDist; - if (searchDist > 20) { - return false; - } - - if (inFree != free) { - if (free) { - --freeToFind; - } - } - - if (freeToFind == 0) { - setOnGround(block); + private boolean advanceToWall(TargetBlock hitBlox) { + Location curBlock; + while ((curBlock = hitBlox.getCurrentBlock()) != null) { + if (!canPassThroughBlock(curBlock)) { return true; } - inFree = free; + hitBlox.getNextBlock(); + } + + return false; + } + + /** + * Advances the block target block until the current block is a free + * @return true if a free spot is found + */ + private boolean advanceToFree(TargetBlock hitBlox) { + Location curBlock; + while ((curBlock = hitBlox.getCurrentBlock()) != null) { + if (canPassThroughBlock(curBlock)) { + return true; + } + + hitBlox.getNextBlock(); + } + + return false; + } + + @Override + public boolean passThroughForwardWall(int range) { + TargetBlock hitBlox = new TargetBlock(this, range, 0.2); + + if (!advanceToWall(hitBlox)) { + return false; + } + + if (!advanceToFree(hitBlox)) { + return false; + } + + Location foundBlock = hitBlox.getCurrentBlock(); + if (foundBlock != null) { + setOnGround(foundBlock); + return true; } return false; @@ -446,7 +493,8 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public void setPosition(Vector3 pos) { - setPosition(pos, getLocation().getPitch(), getLocation().getYaw()); + final Location location = getLocation(); + setPosition(pos, location.getPitch(), location.getYaw()); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java index 8ecf3cc10..120dd47ac 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java @@ -178,4 +178,9 @@ class PlayerProxy extends AbstractPlayerActor { public > void sendFakeBlock(BlockVector3 pos, B block) { basePlayer.sendFakeBlock(pos, block); } + + @Override + public void floatAt(int x, int y, int z, boolean alwaysGlass) { + basePlayer.floatAt(x, y, z, alwaysGlass); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java new file mode 100644 index 000000000..7e1b6466a --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java @@ -0,0 +1,67 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.Optional; + +/** + * Base extent class for buffering changes between {@link #setBlock(BlockVector3, BlockStateHolder)} + * and the delegate extent. This class ensures that {@link #getBlock(BlockVector3)} is properly + * handled, by returning buffered blocks. + */ +public abstract class AbstractBufferingExtent extends AbstractDelegateExtent { + /** + * Create a new instance. + * + * @param extent the extent + */ + protected AbstractBufferingExtent(Extent extent) { + super(extent); + } + + @Override + public abstract > boolean setBlock(BlockVector3 location, T block) throws WorldEditException; + + protected final > boolean setDelegateBlock(BlockVector3 location, T block) throws WorldEditException { + return super.setBlock(location, block); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + return getBufferedBlock(position) + .map(BaseBlock::toImmutableState) + .orElseGet(() -> super.getBlock(position)); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + return getBufferedBlock(position) + .orElseGet(() -> super.getFullBlock(position)); + } + + protected abstract Optional getBufferedBlock(BlockVector3 position); + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ExtentBuffer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ExtentBuffer.java index 562f094e5..8a974c6a6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ExtentBuffer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ExtentBuffer.java @@ -21,16 +21,16 @@ package com.sk89q.worldedit.extent.buffer; import com.google.common.collect.Maps; import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.AbstractBufferingExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import java.util.Map; +import java.util.Optional; import static com.google.common.base.Preconditions.checkNotNull; @@ -38,7 +38,7 @@ import static com.google.common.base.Preconditions.checkNotNull; * Buffers changes to an {@link Extent} and allows retrieval of the changed blocks, * without modifying the underlying extent. */ -public class ExtentBuffer extends AbstractDelegateExtent { +public class ExtentBuffer extends AbstractBufferingExtent { private final Map buffer = Maps.newHashMap(); private final Mask mask; @@ -67,23 +67,11 @@ public class ExtentBuffer extends AbstractDelegateExtent { } @Override - public BlockState getBlock(BlockVector3 position) { + protected Optional getBufferedBlock(BlockVector3 position) { if (mask.test(position)) { - return getOrDefault(position).toImmutableState(); + return Optional.of(buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos)))); } - return super.getBlock(position); - } - - @Override - public BaseBlock getFullBlock(BlockVector3 position) { - if (mask.test(position)) { - return getOrDefault(position); - } - return super.getFullBlock(position); - } - - private BaseBlock getOrDefault(BlockVector3 position) { - return buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos))); + return Optional.empty(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java index bcba783a4..61110ea09 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java @@ -206,6 +206,8 @@ public class MCEditSchematicReader extends NBTSchematicReader { } if (values.isEmpty()) { t = null; + } else { + t = new CompoundTag(values); } if (fixer != null && t != null) { @@ -378,6 +380,24 @@ public class MCEditSchematicReader extends NBTSchematicReader { return "note_block"; case "Structure": return "structure_block"; + case "Chest": + return "chest"; + case "Sign": + return "sign"; + case "Banner": + return "banner"; + case "Beacon": + return "beacon"; + case "Comparator": + return "comparator"; + case "Dropper": + return "dropper"; + case "Furnace": + return "furnace"; + case "Hopper": + return "hopper"; + case "Skull": + return "skull"; default: return id; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java index 865dae6fd..b2deb51f0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java @@ -111,7 +111,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { } else if (dataVersion < liveDataVersion) { fixer = platform.getDataFixer(); if (fixer != null) { - log.info("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.", + log.debug("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.", dataVersion, liveDataVersion); } else { log.info("Schematic was made in an older Minecraft version ({} < {}), but DFU is not available. Data may be incompatible.", diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java index 2ed06cc03..fcc8c8e93 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java @@ -260,8 +260,9 @@ public class SpongeSchematicWriter implements ClipboardWriter { } values.remove("id"); values.put("Id", new StringTag(state.getType().getId())); - values.put("Pos", writeVector(e.getLocation().toVector())); - values.put("Rotation", writeRotation(e.getLocation())); + final Location location = e.getLocation(); + values.put("Pos", writeVector(location.toVector())); + values.put("Rotation", writeRotation(location)); return new CompoundTag(values); }).filter(Objects::nonNull).collect(Collectors.toList()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java index b8f6082c4..a44017fd1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java @@ -19,22 +19,25 @@ package com.sk89q.worldedit.extent.reorder; +import com.google.common.collect.Table; +import com.google.common.collect.TreeBasedTable; import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.AbstractBufferingExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.RunContext; -import com.sk89q.worldedit.function.operation.SetLocatedBlocks; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.collection.LocatedBlockList; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; import java.util.Comparator; +import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.SortedMap; -import java.util.TreeMap; +import java.util.Map; +import java.util.Optional; +import java.util.Set; /** * A special extent that batches changes into Minecraft chunks. This helps @@ -42,17 +45,19 @@ import java.util.TreeMap; * loaded repeatedly, however it does take more memory due to caching the * blocks. */ -public class ChunkBatchingExtent extends AbstractDelegateExtent { +public class ChunkBatchingExtent extends AbstractBufferingExtent { /** * Comparator optimized for sorting chunks by the region file they reside * in. This allows for file caches to be used while loading the chunk. */ private static final Comparator REGION_OPTIMIZED_SORT = - Comparator.comparing((BlockVector2 vec) -> vec.divide(32), BlockVector2.COMPARING_GRID_ARRANGEMENT) + Comparator.comparing((BlockVector2 vec) -> vec.shr(5), BlockVector2.COMPARING_GRID_ARRANGEMENT) .thenComparing(BlockVector2.COMPARING_GRID_ARRANGEMENT); - private final SortedMap batches = new TreeMap<>(REGION_OPTIMIZED_SORT); + private final Table batches = + TreeBasedTable.create(REGION_OPTIMIZED_SORT, BlockVector3.sortByCoordsYzx()); + private final Set containedBlocks = new HashSet<>(); private boolean enabled; public ChunkBatchingExtent(Extent extent) { @@ -76,16 +81,34 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent { return enabled; } + private BlockVector2 getChunkPos(BlockVector3 location) { + return location.shr(4).toBlockVector2(); + } + + private BlockVector3 getInChunkPos(BlockVector3 location) { + return BlockVector3.at(location.getX() & 15, location.getY(), location.getZ() & 15); + } + @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { if (!enabled) { - return getExtent().setBlock(location, block); + return setDelegateBlock(location, block); } - BlockVector2 chunkPos = BlockVector2.at(location.getBlockX() >> 4, location.getBlockZ() >> 4); - batches.computeIfAbsent(chunkPos, k -> new LocatedBlockList()).add(location, block); + BlockVector2 chunkPos = getChunkPos(location); + BlockVector3 inChunkPos = getInChunkPos(location); + batches.put(chunkPos, inChunkPos, block.toBaseBlock()); + containedBlocks.add(location); return true; } + @Override + protected Optional getBufferedBlock(BlockVector3 position) { + if (!containedBlocks.contains(position)) { + return Optional.empty(); + } + return Optional.of(batches.get(getChunkPos(position), getInChunkPos(position))); + } + @Override protected Operation commitBefore() { if (!commitRequired()) { @@ -94,17 +117,22 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent { return new Operation() { // we get modified between create/resume -- only create this on resume to prevent CME - private Iterator batchIterator; + private Iterator>> batchIterator; @Override public Operation resume(RunContext run) throws WorldEditException { if (batchIterator == null) { - batchIterator = batches.values().iterator(); + batchIterator = batches.rowMap().entrySet().iterator(); } if (!batchIterator.hasNext()) { return null; } - new SetLocatedBlocks(getExtent(), batchIterator.next()).resume(run); + Map.Entry> next = batchIterator.next(); + BlockVector3 chunkOffset = next.getKey().toBlockVector3().shl(4); + for (Map.Entry block : next.getValue().entrySet()) { + getExtent().setBlock(block.getKey().add(chunkOffset), block.getValue()); + containedBlocks.remove(block.getKey()); + } batchIterator.remove(); return this; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java index 55ddbcb73..011640709 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java @@ -20,7 +20,7 @@ package com.sk89q.worldedit.extent.reorder; import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.AbstractBufferingExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.OperationQueue; @@ -36,13 +36,17 @@ import com.sk89q.worldedit.world.block.BlockTypes; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; /** * Re-orders blocks into several stages. */ -public class MultiStageReorder extends AbstractDelegateExtent implements ReorderingExtent { +public class MultiStageReorder extends AbstractBufferingExtent implements ReorderingExtent { private static final Map priorityMap = new HashMap<>(); @@ -139,6 +143,7 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder priorityMap.put(BlockTypes.MOVING_PISTON, PlacementPriority.FINAL); } + private final Set containedBlocks = new HashSet<>(); private Map stages = new HashMap<>(); private boolean enabled; @@ -212,7 +217,7 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { if (!enabled) { - return super.setBlock(location, block); + return setDelegateBlock(location, block); } BlockState existing = getBlock(location); @@ -240,9 +245,21 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder } stages.get(priority).add(location, block); + containedBlocks.add(location); return !existing.equalsFuzzy(block); } + @Override + protected Optional getBufferedBlock(BlockVector3 position) { + if (!containedBlocks.contains(position)) { + return Optional.empty(); + } + return stages.values().stream() + .map(blocks -> blocks.get(position)) + .filter(Objects::nonNull) + .findAny(); + } + @Override public Operation commitBefore() { if (!commitRequired()) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java index 9c9ad2a85..05ac90c78 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java @@ -55,7 +55,9 @@ public class BlockOptimizedHistory extends ArrayListHistory { if (change instanceof BlockChange) { BlockChange blockChange = (BlockChange) change; BlockVector3 position = blockChange.getPosition(); - previous.add(position, blockChange.getPrevious()); + if (!previous.containsLocation(position)) { + previous.add(position, blockChange.getPrevious()); + } current.add(position, blockChange.getCurrent()); } else { super.add(change); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java index 5a13140db..2ca8f3bd3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java @@ -32,6 +32,7 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; @@ -114,11 +115,12 @@ public class ServerCUIHandler { } // Borrowed this math from FAWE - double rotX = player.getLocation().getYaw(); - double rotY = player.getLocation().getPitch(); + final Location location = player.getLocation(); + double rotX = location.getYaw(); + double rotY = location.getPitch(); double xz = Math.cos(Math.toRadians(rotY)); - int x = (int) (player.getLocation().getX() - (-xz * Math.sin(Math.toRadians(rotX))) * 12); - int z = (int) (player.getLocation().getZ() - (xz * Math.cos(Math.toRadians(rotX))) * 12); + int x = (int) (location.getX() - (-xz * Math.sin(Math.toRadians(rotX))) * 12); + int z = (int) (location.getZ() - (xz * Math.cos(Math.toRadians(rotX))) * 12); int y = Math.max(0, Math.min(Math.min(255, posY + 32), posY + 3)); Map structureTag = new HashMap<>(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java index 92548fc99..6e2dd17e1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.math; -import com.google.common.collect.ComparisonChain; import com.sk89q.worldedit.math.transform.AffineTransform; import java.util.Comparator; @@ -28,7 +27,7 @@ import java.util.Comparator; * An immutable 2-dimensional vector. */ public final class BlockVector2 { - + public static final BlockVector2 ZERO = new BlockVector2(0, 0); public static final BlockVector2 UNIT_X = new BlockVector2(1, 0); public static final BlockVector2 UNIT_Z = new BlockVector2(0, 1); @@ -48,12 +47,8 @@ public final class BlockVector2 { * cdef * */ - public static final Comparator COMPARING_GRID_ARRANGEMENT = (a, b) -> { - return ComparisonChain.start() - .compare(a.getBlockZ(), b.getBlockZ()) - .compare(a.getBlockX(), b.getBlockX()) - .result(); - }; + public static final Comparator COMPARING_GRID_ARRANGEMENT = + Comparator.comparingInt(BlockVector2::getZ).thenComparingInt(BlockVector2::getX); public static BlockVector2 at(double x, double z) { return at((int) Math.floor(x), (int) Math.floor(z)); @@ -303,6 +298,27 @@ public final class BlockVector2 { return divide(n, n); } + /** + * Shift all components right. + * + * @param x the value to shift x by + * @param z the value to shift z by + * @return a new vector + */ + public BlockVector2 shr(int x, int z) { + return at(this.x >> x, this.z >> z); + } + + /** + * Shift all components right by {@code n}. + * + * @param n the value to shift by + * @return a new vector + */ + public BlockVector2 shr(int n) { + return shr(n, n); + } + /** * Get the length of the vector. * @@ -532,5 +548,4 @@ public final class BlockVector2 { public String toString() { return "(" + x + ", " + z + ")"; } - } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java index ffb6f6347..e8192a128 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java @@ -19,13 +19,12 @@ package com.sk89q.worldedit.math; -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.collect.ComparisonChain; import com.sk89q.worldedit.math.transform.AffineTransform; import java.util.Comparator; +import static com.google.common.base.Preconditions.checkArgument; + /** * An immutable 3-dimensional vector. */ @@ -64,18 +63,15 @@ public final class BlockVector3 { // thread-safe initialization idiom private static final class YzxOrderComparator { - private static final Comparator YZX_ORDER = (a, b) -> { - return ComparisonChain.start() - .compare(a.y, b.y) - .compare(a.z, b.z) - .compare(a.x, b.x) - .result(); - }; + private static final Comparator YZX_ORDER = + Comparator.comparingInt(BlockVector3::getY) + .thenComparingInt(BlockVector3::getZ) + .thenComparingInt(BlockVector3::getX); } /** * Returns a comparator that sorts vectors first by Y, then Z, then X. - * + * *

* Useful for sorting by chunk block storage order. */ @@ -348,6 +344,50 @@ public final class BlockVector3 { return divide(n, n, n); } + /** + * Shift all components right. + * + * @param x the value to shift x by + * @param y the value to shift y by + * @param z the value to shift z by + * @return a new vector + */ + public BlockVector3 shr(int x, int y, int z) { + return at(this.x >> x, this.y >> y, this.z >> z); + } + + /** + * Shift all components right by {@code n}. + * + * @param n the value to shift by + * @return a new vector + */ + public BlockVector3 shr(int n) { + return shr(n, n, n); + } + + /** + * Shift all components left. + * + * @param x the value to shift x by + * @param y the value to shift y by + * @param z the value to shift z by + * @return a new vector + */ + public BlockVector3 shl(int x, int y, int z) { + return at(this.x << x, this.y << y, this.z << z); + } + + /** + * Shift all components left by {@code n}. + * + * @param n the value to shift by + * @return a new vector + */ + public BlockVector3 shl(int n) { + return shl(n, n, n); + } + /** * Get the length of the vector. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/MinecraftHidingClassShutter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/MinecraftHidingClassShutter.java new file mode 100644 index 000000000..20324ed59 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/MinecraftHidingClassShutter.java @@ -0,0 +1,41 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.scripting; + +import org.mozilla.javascript.ClassShutter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Hides Minecraft's obfuscated & de-obfuscated names from scripts. + */ +class MinecraftHidingClassShutter implements ClassShutter { + + private static final Logger LOGGER = LoggerFactory.getLogger(MinecraftHidingClassShutter.class); + + @Override + public boolean visibleToScripts(String fullClassName) { + if (!fullClassName.contains(".")) { + // Default package -- probably Minecraft + return false; + } + return !fullClassName.startsWith("net.minecraft"); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java index 79d51cefb..8cad2670b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java @@ -50,6 +50,7 @@ public class RhinoCraftScriptEngine implements CraftScriptEngine { throws ScriptException, Throwable { RhinoContextFactory factory = new RhinoContextFactory(timeLimit); Context cx = factory.enterContext(); + cx.setClassShutter(new MinecraftHidingClassShutter()); ScriptableObject scriptable = new ImporterTopLevel(cx); Scriptable scope = cx.initStandardObjects(scriptable); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/java/RhinoScriptEngine.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/java/RhinoScriptEngine.java deleted file mode 100644 index afab20c3a..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/java/RhinoScriptEngine.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program 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 3 of the License, or - * (at your option) any later version. - * - * This program 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. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.scripting.java; - -import com.sk89q.worldedit.scripting.RhinoContextFactory; -import org.mozilla.javascript.Context; -import org.mozilla.javascript.ImporterTopLevel; -import org.mozilla.javascript.JavaScriptException; -import org.mozilla.javascript.RhinoException; -import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.ScriptableObject; - -import java.io.IOException; -import java.io.Reader; - -import javax.script.AbstractScriptEngine; -import javax.script.Bindings; -import javax.script.ScriptContext; -import javax.script.ScriptEngine; -import javax.script.ScriptEngineFactory; -import javax.script.ScriptException; -import javax.script.SimpleBindings; - -public class RhinoScriptEngine extends AbstractScriptEngine { - private ScriptEngineFactory factory; - private Context cx; - - public RhinoScriptEngine() { - RhinoContextFactory factory = new RhinoContextFactory(3000); - factory.enterContext(); - } - - @Override - public Bindings createBindings() { - return new SimpleBindings(); - } - - @Override - public Object eval(String script, ScriptContext context) - throws ScriptException { - - Scriptable scope = setupScope(cx, context); - - String filename = (filename = (String) get(ScriptEngine.FILENAME)) == null - ? "" : filename; - - try { - return cx.evaluateString(scope, script, filename, 1, null); - } catch (RhinoException e) { - String msg; - int line = (line = e.lineNumber()) == 0 ? -1 : line; - - if (e instanceof JavaScriptException) { - msg = String.valueOf(((JavaScriptException) e).getValue()); - } else { - msg = e.getMessage(); - } - - ScriptException scriptException = - new ScriptException(msg, e.sourceName(), line); - scriptException.initCause(e); - - throw scriptException; - } finally { - Context.exit(); - } - } - - @Override - public Object eval(Reader reader, ScriptContext context) - throws ScriptException { - - Scriptable scope = setupScope(cx, context); - - String filename = (filename = (String) get(ScriptEngine.FILENAME)) == null - ? "" : filename; - - try { - return cx.evaluateReader(scope, reader, filename, 1, null); - } catch (RhinoException e) { - String msg; - int line = (line = e.lineNumber()) == 0 ? -1 : line; - - if (e instanceof JavaScriptException) { - msg = String.valueOf(((JavaScriptException) e).getValue()); - } else { - msg = e.getMessage(); - } - - ScriptException scriptException = - new ScriptException(msg, e.sourceName(), line); - scriptException.initCause(e); - - throw scriptException; - } catch (IOException e) { - throw new ScriptException(e); - } finally { - Context.exit(); - } - } - - @Override - public ScriptEngineFactory getFactory() { - if (factory != null) { - return factory; - } else { - return new RhinoScriptEngineFactory(); - } - } - - private Scriptable setupScope(Context cx, ScriptContext context) { - ScriptableObject scriptable = new ImporterTopLevel(cx); - Scriptable scope = cx.initStandardObjects(scriptable); - //ScriptableObject.putProperty(scope, "argv", Context.javaToJS(args, scope)); - return scope; - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/java/RhinoScriptEngineFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/java/RhinoScriptEngineFactory.java deleted file mode 100644 index ee312229c..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/java/RhinoScriptEngineFactory.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program 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 3 of the License, or - * (at your option) any later version. - * - * This program 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. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.scripting.java; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.script.ScriptEngine; -import javax.script.ScriptEngineFactory; - -public class RhinoScriptEngineFactory implements ScriptEngineFactory { - private static List names; - private static List mimeTypes; - private static List extensions; - - static { - names = new ArrayList<>(5); - names.add("ECMAScript"); - names.add("ecmascript"); - names.add("JavaScript"); - names.add("javascript"); - names.add("js"); - names = Collections.unmodifiableList(names); - - mimeTypes = new ArrayList<>(4); - mimeTypes.add("application/ecmascript"); - mimeTypes.add("text/ecmascript"); - mimeTypes.add("application/javascript"); - mimeTypes.add("text/javascript"); - mimeTypes = Collections.unmodifiableList(mimeTypes); - - extensions = new ArrayList<>(2); - extensions.add("emcascript"); - extensions.add("js"); - extensions = Collections.unmodifiableList(extensions); - } - - @Override - public String getEngineName() { - return "Rhino JavaScript Engine (SK)"; - } - - @Override - public String getEngineVersion() { - return "unknown"; - } - - @Override - public List getExtensions() { - return extensions; - } - - @Override - public String getLanguageName() { - return "EMCAScript"; - } - - @Override - public String getLanguageVersion() { - return "1.8"; - } - - @Override - public String getMethodCallSyntax(String obj, String m, String... args) { - StringBuilder s = new StringBuilder(); - s.append(obj); - s.append("."); - s.append(m); - s.append("("); - - for (int i = 0; i < args.length; ++i) { - s.append(args[i]); - if (i < args.length - 1) { - s.append(","); - } - } - - s.append(")"); - - return s.toString(); - } - - @Override - public List getMimeTypes() { - return mimeTypes; - } - - @Override - public List getNames() { - return names; - } - - @Override - public String getOutputStatement(String str) { - return "print(" + str.replace("\\", "\\\\") - .replace("\"", "\\\\\"") - .replace(";", "\\\\;") + ")"; - } - - @Override - public Object getParameter(String key) { - switch (key) { - case ScriptEngine.ENGINE: - return getEngineName(); - case ScriptEngine.ENGINE_VERSION: - return getEngineVersion(); - case ScriptEngine.NAME: - return getEngineName(); - case ScriptEngine.LANGUAGE: - return getLanguageName(); - case ScriptEngine.LANGUAGE_VERSION: - return getLanguageVersion(); - case "THREADING": - return "MULTITHREADED"; - default: - throw new IllegalArgumentException("Invalid key"); - } - } - - @Override - public String getProgram(String... statements) { - StringBuilder s = new StringBuilder(); - for (String stmt : statements) { - s.append(stmt); - s.append(";"); - } - return s.toString(); - } - - @Override - public ScriptEngine getScriptEngine() { - return new RhinoScriptEngine(); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java index 67280031d..b558a7102 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java @@ -21,68 +21,72 @@ package com.sk89q.worldedit.util.collection; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.LocatedBlock; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.ListIterator; +import java.util.Map; /** * Wrapper around a list of blocks located in the world. */ public class LocatedBlockList implements Iterable { - private final List list; + private final Map map = new LinkedHashMap<>(); public LocatedBlockList() { - list = new ArrayList<>(); } public LocatedBlockList(Collection collection) { - list = new ArrayList<>(collection); + for (LocatedBlock locatedBlock : collection) { + map.put(locatedBlock.getLocation(), locatedBlock); + } } public void add(LocatedBlock setBlockCall) { checkNotNull(setBlockCall); - list.add(setBlockCall); + map.put(setBlockCall.getLocation(), setBlockCall); } public > void add(BlockVector3 location, B block) { add(new LocatedBlock(location, block.toBaseBlock())); } + public boolean containsLocation(BlockVector3 location) { + return map.containsKey(location); + } + + public @Nullable BaseBlock get(BlockVector3 location) { + return map.get(location).getBlock(); + } + public int size() { - return list.size(); + return map.size(); } public void clear() { - list.clear(); + map.clear(); } @Override public Iterator iterator() { - return list.iterator(); + return map.values().iterator(); } public Iterator reverseIterator() { - return new Iterator() { - - private final ListIterator backingIterator = list.listIterator(list.size()); - - @Override - public boolean hasNext() { - return backingIterator.hasPrevious(); - } - - @Override - public LocatedBlock next() { - return backingIterator.previous(); - } - }; + List data = new ArrayList<>(map.values()); + Collections.reverse(data); + return data.iterator(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/BlockDistributionResult.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/BlockDistributionResult.java deleted file mode 100644 index 797557a52..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/BlockDistributionResult.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program 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 3 of the License, or - * (at your option) any later version. - * - * This program 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. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.util.formatting.component; - -import com.google.common.base.Strings; -import com.sk89q.worldedit.util.Countable; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; -import com.sk89q.worldedit.util.formatting.text.format.TextColor; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockType; - -import java.util.List; - -public class BlockDistributionResult extends PaginationBox { - - private final List> distribution; - private final int totalBlocks; - private final boolean separateStates; - - public BlockDistributionResult(List> distribution, boolean separateStates) { - super("Block Distribution", "//distr -p %page%" + (separateStates ? " -d" : "")); - this.distribution = distribution; - // note: doing things like region.getArea is inaccurate for non-cuboids. - this.totalBlocks = distribution.stream().mapToInt(Countable::getAmount).sum(); - this.separateStates = separateStates; - setComponentsPerPage(7); - } - - @Override - public Component getComponent(int number) { - Countable c = distribution.get(number); - TextComponent.Builder line = TextComponent.builder(); - - final int count = c.getAmount(); - - final double perc = count / (double) totalBlocks * 100; - final int maxDigits = (int) (Math.log10(totalBlocks) + 1); - final int curDigits = (int) (Math.log10(count) + 1); - line.append(String.format("%s%.3f%% ", perc < 10 ? " " : "", perc), TextColor.GOLD); - final int space = maxDigits - curDigits; - String pad = Strings.repeat(" ", space == 0 ? 2 : 2 * space + 1); - line.append(String.format("%s%s", count, pad), TextColor.YELLOW); - - final BlockState state = c.getID(); - final BlockType blockType = state.getBlockType(); - TextComponent blockName = TextComponent.of(blockType.getName(), TextColor.LIGHT_PURPLE); - TextComponent toolTip; - if (separateStates && state != blockType.getDefaultState()) { - toolTip = TextComponent.of(state.getAsString(), TextColor.GRAY); - blockName = blockName.append(TextComponent.of("*", TextColor.LIGHT_PURPLE)); - } else { - toolTip = TextComponent.of(blockType.getId(), TextColor.GRAY); - } - blockName = blockName.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, toolTip)); - line.append(blockName); - - return line.build(); - } - - @Override - public int getComponentsSize() { - return distribution.size(); - } - - @Override - public Component create(int page) throws InvalidComponentException { - super.getContents().append(TextComponent.of("Total Block Count: " + totalBlocks, TextColor.GRAY)) - .append(TextComponent.newline()); - return super.create(page); - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java index fd579c6fb..2efc8b7b3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java @@ -32,14 +32,16 @@ public class CommandListBox extends PaginationBox { private List commands = Lists.newArrayList(); private boolean hideHelp; + private String helpCommand; /** * Create a new box. * * @param title the title */ - public CommandListBox(String title, String pageCommand) { + public CommandListBox(String title, String pageCommand, String helpCommand) { super(title, pageCommand); + this.helpCommand = helpCommand; } @Override @@ -72,7 +74,7 @@ public class CommandListBox extends PaginationBox { this.hideHelp = hideHelp; } - private static class CommandEntry { + private class CommandEntry { private final String alias; private final Component description; private final String insertion; @@ -87,7 +89,7 @@ public class CommandListBox extends PaginationBox { TextComponentProducer line = new TextComponentProducer(); if (!hideHelp) { line.append(SubtleFormat.wrap("? ") - .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "//help " + insertion)) + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, CommandListBox.this.helpCommand + " " + insertion)) .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Additional Help")))); } TextComponent command = TextComponent.of(alias, TextColor.GOLD); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java index e8abe0e38..579bd44a9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java @@ -45,9 +45,10 @@ public class CommandUsageBox extends TextComponentProducer { * * @param commands the commands to describe * @param commandString the commands that were used, such as "/we" or "/brush sphere" + * @param helpRootCommand the command used to get subcommand help */ - public CommandUsageBox(List commands, String commandString) throws InvalidComponentException { - this(commands, commandString, null); + public CommandUsageBox(List commands, String commandString, String helpRootCommand) throws InvalidComponentException { + this(commands, commandString, helpRootCommand, null); } /** @@ -55,15 +56,18 @@ public class CommandUsageBox extends TextComponentProducer { * * @param commands the commands to describe * @param commandString the commands that were used, such as "/we" or "/brush sphere" + * @param helpRootCommand the command used to get subcommand help * @param parameters list of parameters to use */ - public CommandUsageBox(List commands, String commandString, @Nullable CommandParameters parameters) throws InvalidComponentException { + public CommandUsageBox(List commands, String commandString, String helpRootCommand, + @Nullable CommandParameters parameters) throws InvalidComponentException { checkNotNull(commands); checkNotNull(commandString); - attachCommandUsage(commands, commandString); + checkNotNull(helpRootCommand); + attachCommandUsage(commands, commandString, helpRootCommand); } - private void attachCommandUsage(List commands, String commandString) { + private void attachCommandUsage(List commands, String commandString, String helpRootCommand) { TextComponentProducer boxContent = new TextComponentProducer() .append(HelpGenerator.create(commands).getFullHelp()); if (getSubCommands(Iterables.getLast(commands)).size() > 0) { @@ -73,7 +77,7 @@ public class CommandUsageBox extends TextComponentProducer { .append(TextComponent.builder("List Subcommands") .color(ColorConfig.getMainText()) .decoration(TextDecoration.ITALIC, true) - .clickEvent(ClickEvent.runCommand("//help -s " + commandString)) + .clickEvent(ClickEvent.runCommand(helpRootCommand + " -s " + commandString)) .hoverEvent(HoverEvent.showText(TextComponent.of("List all subcommands of this command"))) .build()) .build()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java deleted file mode 100644 index ae052d137..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program 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 3 of the License, or - * (at your option) any later version. - * - * This program 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. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.util.formatting.component; - -import com.google.common.collect.Multimap; -import com.google.common.io.Files; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; -import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; -import com.sk89q.worldedit.util.formatting.text.format.TextColor; - -import java.io.File; -import java.util.regex.Pattern; - -import static com.google.common.base.Preconditions.checkArgument; - -public class SchematicPaginationBox extends PaginationBox { - private final String prefix; - private final File[] files; - - public SchematicPaginationBox(String rootDir, File[] files, String pageCommand) { - super("Available schematics", pageCommand); - this.prefix = rootDir == null ? "" : rootDir; - this.files = files; - } - - @Override - public Component getComponent(int number) { - checkArgument(number < files.length && number >= 0); - File file = files[number]; - Multimap exts = ClipboardFormats.getFileExtensionMap(); - String format = exts.get(Files.getFileExtension(file.getName())) - .stream().findFirst().map(ClipboardFormat::getName).orElse("Unknown"); - boolean inRoot = file.getParentFile().getName().equals(prefix); - - String path = inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1]; - - return TextComponent.builder() - .content("") - .append(TextComponent.of("[L]") - .color(TextColor.GOLD) - .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/schem load " + path)) - .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to load")))) - .append(TextComponent.space()) - .append(TextComponent.of(path) - .color(TextColor.DARK_GREEN) - .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of(format)))) - .build(); - } - - @Override - public int getComponentsSize() { - return files.length; - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java index ac7484846..ab8ebe029 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java @@ -19,8 +19,9 @@ package com.sk89q.worldedit.util.paste; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import com.sk89q.worldedit.util.net.HttpRequest; -import org.json.simple.JSONValue; import java.io.IOException; import java.net.URL; @@ -33,6 +34,8 @@ public class EngineHubPaste implements Paster { private static final Pattern URL_PATTERN = Pattern.compile("https?://.+$"); + private static final Gson GSON = new Gson(); + @Override public Callable paste(String content) { return new PasteTask(content); @@ -59,10 +62,10 @@ public class EngineHubPaste implements Paster { .returnContent() .asString("UTF-8").trim(); - Object object = JSONValue.parse(result); - if (object instanceof Map) { - @SuppressWarnings("unchecked") - String urlString = String.valueOf(((Map) object).get("url")); + Map object = GSON.fromJson(result, new TypeToken>() { + }.getType()); + if (object != null) { + String urlString = String.valueOf(object.get("url")); Matcher m = URL_PATTERN.matcher(urlString); if (m.matches()) { diff --git a/worldedit-core/src/test/java/com/sk89q/minecraft/util/commands/CommandContextTest.java b/worldedit-core/src/test/java/com/sk89q/minecraft/util/commands/CommandContextTest.java index 555c83889..19bd552ec 100644 --- a/worldedit-core/src/test/java/com/sk89q/minecraft/util/commands/CommandContextTest.java +++ b/worldedit-core/src/test/java/com/sk89q/minecraft/util/commands/CommandContextTest.java @@ -19,19 +19,20 @@ package com.sk89q.minecraft.util.commands; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Arrays; import java.util.HashSet; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; public class CommandContextTest { @@ -39,7 +40,7 @@ public class CommandContextTest { private static final String firstCmdString = "herpderp -opw testers \"mani world\" 'another thing' because something"; CommandContext firstCommand; - @Before + @BeforeEach public void setUpTest() { try { firstCommand = new CommandContext(firstCmdString, new HashSet<>(Arrays.asList('o', 'w'))); @@ -49,10 +50,12 @@ public class CommandContextTest { } } - @Test(expected = CommandException.class) - public void testInvalidFlags() throws CommandException { + @Test + public void testInvalidFlags() { final String failingCommand = "herpderp -opw testers"; - new CommandContext(failingCommand, new HashSet<>(Arrays.asList('o', 'w'))); + assertThrows(CommandException.class, () -> { + new CommandContext(failingCommand, new HashSet<>(Arrays.asList('o', 'w'))); + }); } @Test diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java index 633e359f8..101509aa4 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java @@ -19,33 +19,33 @@ package com.sk89q.worldedit.extent.transform; -import static org.junit.Assert.assertEquals; - import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import java.util.HashSet; import java.util.Set; -@Ignore("A platform is currently required to get properties, preventing this test.") +import static org.junit.jupiter.api.Assertions.assertEquals; + +@Disabled("A platform is currently required to get properties, preventing this test.") public class BlockTransformExtentTest { private static final Transform ROTATE_90 = new AffineTransform().rotateY(-90); private static final Transform ROTATE_NEG_90 = new AffineTransform().rotateY(90); private final Set ignored = new HashSet<>(); - @Before - public void setUp() throws Exception { + @BeforeEach + public void setUp() { BlockType.REGISTRY.register("worldedit:test", new BlockType("worldedit:test")); } @Test - public void testTransform() throws Exception { + public void testTransform() { for (BlockType type : BlockType.REGISTRY.values()) { if (ignored.contains(type)) { continue; diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java index 7c75de4a6..c696bdabb 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java @@ -21,10 +21,10 @@ package com.sk89q.worldedit.internal.command; import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.internal.util.Substring; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static com.sk89q.worldedit.internal.command.CommandArgParser.spaceSplit; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class CommandArgParserTest { @Test diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java index 28ad67b37..d26d955d0 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java @@ -19,16 +19,6 @@ package com.sk89q.worldedit.internal.expression; -import static java.lang.Math.atan2; -import static java.lang.Math.sin; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Platform; @@ -36,9 +26,20 @@ import com.sk89q.worldedit.internal.expression.lexer.LexerException; import com.sk89q.worldedit.internal.expression.parser.ParserException; import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment; +import com.sk89q.worldedit.internal.expression.runtime.ExpressionTimeoutException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import static java.lang.Math.atan2; +import static java.lang.Math.sin; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ExpressionTest { - @Before + @BeforeEach public void setup() { Platform mockPlat = Mockito.mock(Platform.class); Mockito.when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() { @@ -51,7 +52,7 @@ public class ExpressionTest { @Test public void testEvaluate() throws ExpressionException { - // check + // check assertEquals(1 - 2 + 3, simpleEval("1 - 2 + 3"), 0); // check unary ops @@ -68,56 +69,46 @@ public class ExpressionTest { } @Test - public void testErrors() throws ExpressionException { - // test lexer errors - try { - compile("#"); - fail("Error expected"); - } catch (LexerException e) { - assertEquals("Error position", 0, e.getPosition()); - } - - // test parser errors - try { - compile("x"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); - } - try { - compile("x()"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); - } - try { - compile("("); - fail("Error expected"); - } catch (ParserException ignored) {} - try { - compile("x("); - fail("Error expected"); - } catch (ParserException ignored) {} - - // test overloader errors - try { - compile("atan2(1)"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); - } - try { - compile("atan2(1, 2, 3)"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); - } - try { - compile("rotate(1, 2, 3)"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); - } + public void testErrors() { + assertAll( + // test lexer errors + () -> { + LexerException e = assertThrows(LexerException.class, + () -> compile("#")); + assertEquals(0, e.getPosition(), "Error position"); + }, + // test parser errors + () -> { + ParserException e = assertThrows(ParserException.class, + () -> compile("x")); + assertEquals(0, e.getPosition(), "Error position"); + }, + () -> { + ParserException e = assertThrows(ParserException.class, + () -> compile("x()")); + assertEquals(0, e.getPosition(), "Error position"); + }, + () -> assertThrows(ParserException.class, + () -> compile("(")), + () -> assertThrows(ParserException.class, + () -> compile("x(")), + // test overloader errors + () -> { + ParserException e = assertThrows(ParserException.class, + () -> compile("atan2(1)")); + assertEquals(0, e.getPosition(), "Error position"); + }, + () -> { + ParserException e = assertThrows(ParserException.class, + () -> compile("atan2(1, 2, 3)")); + assertEquals(0, e.getPosition(), "Error position"); + }, + () -> { + ParserException e = assertThrows(ParserException.class, + () -> compile("rotate(1, 2, 3)")); + assertEquals(0, e.getPosition(), "Error position"); + } + ); } @Test @@ -181,13 +172,11 @@ public class ExpressionTest { } @Test - public void testTimeout() throws Exception { - try { - simpleEval("for(i=0;i<256;i++){for(j=0;j<256;j++){for(k=0;k<256;k++){for(l=0;l<256;l++){ln(pi)}}}}"); - fail("Loop was not stopped."); - } catch (EvaluationException e) { - assertTrue(e.getMessage().contains("Calculations exceeded time limit")); - } + public void testTimeout() { + ExpressionTimeoutException e = assertThrows(ExpressionTimeoutException.class, + () -> simpleEval("for(i=0;i<256;i++){for(j=0;j<256;j++){for(k=0;k<256;k++){for(l=0;l<256;l++){ln(pi)}}}}"), + "Loop was not stopped."); + assertTrue(e.getMessage().contains("Calculations exceeded time limit")); } private double simpleEval(String expressionString) throws ExpressionException { diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/util/LocationTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/util/LocationTest.java index 50dfa649e..2c990ab74 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/util/LocationTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/util/LocationTest.java @@ -19,12 +19,12 @@ package com.sk89q.worldedit.util; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; - import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.world.World; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; /** * Tests {@link Location}. diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java index 6289301dc..82fdb11c0 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java @@ -19,14 +19,14 @@ package com.sk89q.worldedit.util.eventbus; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class EventBusTest { diff --git a/worldedit-fabric/build.gradle b/worldedit-fabric/build.gradle deleted file mode 100644 index b27289bf9..000000000 --- a/worldedit-fabric/build.gradle +++ /dev/null @@ -1,105 +0,0 @@ -import net.fabricmc.loom.task.RemapJarTask - -buildscript { - repositories { - jcenter() - maven { - name = 'Fabric' - url = 'https://maven.fabricmc.net/' - } - maven { - name = 'sponge' - url = 'https://repo.spongepowered.org/maven' - } - } - - dependencies { - classpath 'net.fabricmc:fabric-loom:0.2.4-SNAPSHOT' - classpath 'org.spongepowered:mixin:0.7.11-SNAPSHOT' - } -} - -apply plugin: 'eclipse' -apply plugin: 'fabric-loom' - -def minecraftVersion = "1.14.3" -def fabricVersion = "0.3.0+build.187" -def yarnMappings = "1.14.3+build.1" -def loaderVersion = "0.4.8+build.155" - -configurations.all { Configuration it -> - it.resolutionStrategy { ResolutionStrategy rs -> - rs.force("com.google.guava:guava:21.0") - } -} - -dependencies { - compile project(':worldedit-core') - compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' - - minecraft "com.mojang:minecraft:${minecraftVersion}" - mappings "net.fabricmc:yarn:${yarnMappings}" - modCompile "net.fabricmc:fabric-loader:${loaderVersion}" - - modCompile "net.fabricmc.fabric-api:fabric-api:${fabricVersion}" - - testCompile group: 'org.mockito', name: 'mockito-core', version: '1.9.0-rc1' -} - -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - -minecraft { -} - -project.archivesBaseName = "${project.archivesBaseName}-mc${minecraftVersion}" - -processResources { - // this will ensure that this task is redone when the versions change. - inputs.property 'version', project.internalVersion - - from(sourceSets.main.resources.srcDirs) { - include "fabric.mod.json" - expand "version": project.internalVersion - } - - // copy everything else except the mod json - from(sourceSets.main.resources.srcDirs) { - exclude "fabric.mod.json" - } -} - -jar { - manifest { - attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", - "WorldEdit-Version": version) - } -} - -shadowJar { - classifier = 'dist-dev' - dependencies { - relocate "org.slf4j", "com.sk89q.worldedit.slf4j" - relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge" - - include(dependency('org.slf4j:slf4j-api')) - include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) - } -} - -task deobfJar(type: Jar) { - from sourceSets.main.output - classifier = 'dev' -} - -artifacts { - archives deobfJar -} - -task shadowJarRemap(type: RemapJarTask) { - input shadowJar.archivePath - output new File(shadowJar.archivePath.getAbsolutePath().replaceFirst('-dev\\.jar$', ".jar")) -} - -shadowJarRemap.dependsOn(shadowJar) -build.dependsOn(shadowJarRemap) \ No newline at end of file diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts new file mode 100644 index 000000000..f8cb056eb --- /dev/null +++ b/worldedit-fabric/build.gradle.kts @@ -0,0 +1,113 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import net.fabricmc.loom.task.RemapJarTask +import kotlin.reflect.KClass + +buildscript { + repositories { + jcenter() + maven { + name = "Fabric" + url = uri("https://maven.fabricmc.net/") + } + maven { + name = "sponge" + url = uri("https://repo.spongepowered.org/maven") + } + } + + dependencies { + "classpath"("net.fabricmc:fabric-loom:0.2.3-SNAPSHOT") + "classpath"("org.spongepowered:mixin:0.7.11-SNAPSHOT") + } +} + +applyPlatformAndCoreConfiguration() +applyShadowConfiguration() + +apply(plugin = "fabric-loom") + +val minecraftVersion = "1.14.4" +val fabricVersion = "0.3.0+build.200" +val yarnMappings = "1.14.4+build.1" +val loaderVersion = "0.4.8+build.155" + +configurations.all { + resolutionStrategy { + force("com.google.guava:guava:21.0") + } +} + +dependencies { + "compile"(project(":worldedit-core")) + "compile"("org.apache.logging.log4j:log4j-slf4j-impl:2.8.1") + + "minecraft"("com.mojang:minecraft:$minecraftVersion") + "mappings"("net.fabricmc:yarn:$yarnMappings") + "modCompile"("net.fabricmc:fabric-loader:$loaderVersion") + + "modCompile"("net.fabricmc.fabric-api:fabric-api:$fabricVersion") + + "testCompile"("org.mockito:mockito-core:1.9.0-rc1") +} + +configure { + archivesBaseName = "$archivesBaseName-mc$minecraftVersion" +} + +tasks.named("processResources") { + // this will ensure that this task is redone when the versions change. + inputs.property("version", project.ext["internalVersion"]) + + from(sourceSets["main"].resources.srcDirs) { + include("fabric.mod.json") + expand("version" to project.ext["internalVersion"]) + } + + // copy everything else except the mod json + from(sourceSets["main"].resources.srcDirs) { + exclude("fabric.mod.json") + } +} + +tasks.named("jar") { + manifest { + attributes("Class-Path" to "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", + "WorldEdit-Version" to project.version) + } +} + +tasks.named("shadowJar") { + archiveClassifier.set("dist-dev") + dependencies { + relocate("org.slf4j", "com.sk89q.worldedit.slf4j") + relocate("org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge") + + include(dependency("org.slf4j:slf4j-api")) + include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) + } +} + +tasks.register("deobfJar") { + from(sourceSets["main"].output) + archiveClassifier.set("dev") +} + +artifacts { + add("archives", tasks.named("deobfJar")) +} + +// intellij has trouble detecting RemapJarTask as a subclass of Task +@Suppress("UNCHECKED_CAST") +val remapJarIntellijHack = RemapJarTask::class as KClass +tasks.register("remapShadowJar", remapJarIntellijHack) { + (this as RemapJarTask).run { + val shadowJar = tasks.getByName("shadowJar") + dependsOn(shadowJar) + setInput(shadowJar.archiveFile) + setOutput(shadowJar.archiveFile.get().asFile.absolutePath.replace(Regex("-dev\\.jar$"), ".jar")) + } +} + +tasks.named("assemble").configure { + dependsOn("remapShadowJar") +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java index d96e0f81f..6bd1171d7 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java @@ -106,7 +106,7 @@ public class FabricPlayer extends AbstractPlayerActor { } @Override - public com.sk89q.worldedit.world.World getWorld() { + public World getWorld() { return FabricWorldEdit.inst.getWorld(this.player.world); } @@ -188,6 +188,19 @@ public class FabricPlayer extends AbstractPlayerActor { return null; } + @Override + public boolean isAllowedToFly() { + return player.abilities.allowFlying; + } + + @Override + public void setFlying(boolean flying) { + if (player.abilities.flying != flying) { + player.abilities.flying = flying; + player.sendAbilitiesUpdate(); + } + } + @Override public > void sendFakeBlock(BlockVector3 pos, B block) { World world = getWorld(); diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java index 8125fb0cb..93d14b753 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java @@ -202,16 +202,25 @@ public class FabricWorld extends AbstractWorld { CompoundTag tag = ((BaseBlock) block).getNbtData(); if (tag != null) { net.minecraft.nbt.CompoundTag nativeTag = NBTConverter.toNative(tag); - nativeTag.putString("id", ((BaseBlock) block).getNbtId()); - TileEntityUtils.setTileEntity(world, position, nativeTag); - successful = true; // update if TE changed as well + BlockEntity tileEntity = getWorld().getWorldChunk(pos).getBlockEntity(pos); + if (tileEntity != null) { + tileEntity.fromTag(nativeTag); + tileEntity.setPos(pos); + tileEntity.setWorld(world); + successful = true; // update if TE changed as well + } } } } if (successful && notifyAndLight) { world.getChunkManager().getLightingProvider().enqueueLightUpdate(pos); + world.scheduleBlockRender(pos, old, newState); world.updateListeners(pos, old, newState, UPDATE | NOTIFY); + world.updateNeighbors(pos, newState.getBlock()); + if (old.hasComparatorOutput()) { + world.updateHorizontalAdjacent(pos, newState.getBlock()); + } } return successful; @@ -220,7 +229,9 @@ public class FabricWorld extends AbstractWorld { @Override public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException { BlockPos pos = new BlockPos(position.getX(), position.getY(), position.getZ()); - getWorld().updateListeners(pos, FabricAdapter.adapt(previousType), getWorld().getBlockState(pos), 1 | 2); + net.minecraft.block.BlockState state = getWorld().getBlockState(pos); + getWorld().updateListeners(pos, FabricAdapter.adapt(previousType), state, 1 | 2); + getWorld().updateNeighbors(pos, state.getBlock()); return true; } @@ -496,7 +507,9 @@ public class FabricWorld extends AbstractWorld { BlockEntity tile = ((WorldChunk) getWorld().getChunk(pos)).getBlockEntity(pos, WorldChunk.CreationType.CHECK); if (tile != null) { - return getBlock(position).toBaseBlock(NBTConverter.fromNative(TileEntityUtils.copyNbtData(tile))); + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + tile.toTag(tag); + return getBlock(position).toBaseBlock(NBTConverter.fromNative(tag)); } else { return getBlock(position).toBaseBlock(); } diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/TileEntityUtils.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/TileEntityUtils.java deleted file mode 100644 index 4faec9d9e..000000000 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/TileEntityUtils.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program 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 3 of the License, or - * (at your option) any later version. - * - * This program 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. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.fabric; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.worldedit.math.BlockVector3; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.IntTag; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -import javax.annotation.Nullable; - -/** - * Utility methods for setting tile entities in the world. - */ -final class TileEntityUtils { - - private TileEntityUtils() { - } - - /** - * Update the given tag compound with position information. - * - * @param tag the tag - * @param position the position - */ - private static void updateForSet(CompoundTag tag, BlockVector3 position) { - checkNotNull(tag); - checkNotNull(position); - - tag.put("x", new IntTag(position.getBlockX())); - tag.put("y", new IntTag(position.getBlockY())); - tag.put("z", new IntTag(position.getBlockZ())); - } - - /** - * Set a tile entity at the given location using the tile entity ID from - * the tag. - * - * @param world the world - * @param position the position - * @param tag the tag for the tile entity (may be null to do nothing) - */ - static void setTileEntity(World world, BlockVector3 position, @Nullable CompoundTag tag) { - if (tag != null) { - updateForSet(tag, position); - BlockEntity tileEntity = BlockEntity.createFromTag(tag); - if (tileEntity != null) { - world.setBlockEntity(new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()), tileEntity); - } - } - } - - public static CompoundTag copyNbtData(BlockEntity tile) { - CompoundTag tag = new CompoundTag(); - tile.toTag(tag); - return tag; - } -} diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle deleted file mode 100644 index 0cddf21e5..000000000 --- a/worldedit-forge/build.gradle +++ /dev/null @@ -1,115 +0,0 @@ -buildscript { - repositories { - mavenLocal() - mavenCentral() - maven { url = "https://files.minecraftforge.net/maven" } - jcenter() - } - - dependencies { - classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true - } -} - -apply plugin: 'eclipse' -apply plugin: 'net.minecraftforge.gradle' - -def minecraftVersion = "1.14.3" -def forgeVersion = "27.0.13" - -configurations.all { Configuration it -> - it.resolutionStrategy { ResolutionStrategy rs -> - rs.force("com.google.guava:guava:21.0") - } -} - -dependencies { - compile project(':worldedit-core') - compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.11.2' - - minecraft "net.minecraftforge:forge:${minecraftVersion}-${forgeVersion}" - - testCompile group: 'org.mockito', name: 'mockito-core', version: '1.9.0-rc1' -} - -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - -minecraft { - mappings channel: 'snapshot', version: "20190626-${minecraftVersion}" - - runs { - client = { - // recommended logging data for a userdev environment - properties 'forge.logging.markers': 'SCAN,REGISTRIES,REGISTRYDUMP' - // recommended logging level for the console - properties 'forge.logging.console.level': 'debug' - workingDirectory project.file('run').canonicalPath - source sourceSets.main - } - server = { - // recommended logging data for a userdev environment - properties 'forge.logging.markers': 'SCAN,REGISTRIES,REGISTRYDUMP' - // recommended logging level for the console - properties 'forge.logging.console.level': 'debug' - workingDirectory project.file('run').canonicalPath - source sourceSets.main - } - } - -} - -project.archivesBaseName = "${project.archivesBaseName}-mc${minecraftVersion}" - -processResources { - // this will ensure that this task is redone when the versions change. - inputs.property 'version', project.internalVersion - inputs.property 'forgeVersion', forgeVersion - - // replace stuff in mcmod.info, nothing else - from(sourceSets.main.resources.srcDirs) { - include 'META-INF/mods.toml' - - // replace version and mcversion - expand 'version': project.internalVersion, 'forgeVersion': forgeVersion - } - - // copy everything else except the mcmod.info - from(sourceSets.main.resources.srcDirs) { - exclude 'META-INF/mods.toml' - } -} - -jar { - manifest { - attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", - "WorldEdit-Version": version) - } -} - -shadowJar { - dependencies { - relocate "org.slf4j", "com.sk89q.worldedit.slf4j" - relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge" - - include(dependency('org.slf4j:slf4j-api')) - include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) - } -} - -afterEvaluate { - reobf { - shadowJar { - mappings = createMcpToSrg.output - } - } -} - -task deobfJar(type: Jar) { - from sourceSets.main.output - classifier = 'dev' -} - -artifacts { - archives deobfJar -} diff --git a/worldedit-forge/build.gradle.kts b/worldedit-forge/build.gradle.kts new file mode 100644 index 000000000..89ae7fc27 --- /dev/null +++ b/worldedit-forge/build.gradle.kts @@ -0,0 +1,113 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import net.minecraftforge.gradle.common.util.RunConfig +import net.minecraftforge.gradle.userdev.UserDevExtension +import net.minecraftforge.gradle.userdev.tasks.GenerateSRG +import net.minecraftforge.gradle.userdev.tasks.RenameJarInPlace + +plugins { + id("net.minecraftforge.gradle") +} + +applyPlatformAndCoreConfiguration() +applyShadowConfiguration() + +val minecraftVersion = "1.14.4" +val mappingsMinecraftVersion = "1.14.3" +val forgeVersion = "28.0.16" + +configurations.all { + resolutionStrategy { + force("com.google.guava:guava:21.0") + } +} + +dependencies { + "compile"(project(":worldedit-core")) + "compile"("org.apache.logging.log4j:log4j-slf4j-impl:2.11.2") + + "minecraft"("net.minecraftforge:forge:$minecraftVersion-$forgeVersion") +} + +configure { + mappings(mapOf( + "channel" to "snapshot", + "version" to "20190724-$mappingsMinecraftVersion" + )) + + runs { + val runConfig = Action { + properties(mapOf( + "forge.logging.markers" to "SCAN,REGISTRIES,REGISTRYDUMP", + "forge.logging.console.level" to "debug" + )) + workingDirectory = project.file("run").canonicalPath + source(sourceSets["main"]) + } + create("client", runConfig) + create("server", runConfig) + } + +} + +configure { + archivesBaseName = "$archivesBaseName-mc$minecraftVersion" +} + +tasks.named("processResources") { + // this will ensure that this task is redone when the versions change. + inputs.property("version", project.ext["internalVersion"]) + inputs.property("forgeVersion", forgeVersion) + + // replace stuff in mcmod.info, nothing else + from(sourceSets["main"].resources.srcDirs) { + include("META-INF/mods.toml") + + // replace version and mcversion + expand( + "version" to project.ext["internalVersion"], + "forgeVersion" to forgeVersion + ) + } + + // copy everything else except the mcmod.info + from(sourceSets["main"].resources.srcDirs) { + exclude("META-INF/mods.toml") + } +} + +tasks.named("jar") { + manifest { + attributes("WorldEdit-Version" to project.version) + } +} + +tasks.named("shadowJar") { + dependencies { + relocate("org.slf4j", "com.sk89q.worldedit.slf4j") + relocate("org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge") + + include(dependency("org.slf4j:slf4j-api")) + include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) + include(dependency("de.schlichtherle:truezip")) + include(dependency("org.mozilla:rhino")) + } + minimize { + exclude(dependency("org.mozilla:rhino")) + } +} + +afterEvaluate { + val reobf = extensions.getByName>("reobf") + reobf.maybeCreate("shadowJar").run { + mappings = tasks.getByName("createMcpToSrg").output + } +} + +tasks.register("deobfJar") { + from(sourceSets["main"].output) + archiveClassifier.set("dev") +} + +artifacts { + add("archives", tasks.named("deobfJar")) +} diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java index 99ef0103e..93fea255f 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java @@ -35,7 +35,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.management.PlayerList; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SharedConstants; -import net.minecraft.world.ServerWorld; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.fml.server.ServerLifecycleHooks; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index a48ff6256..94dfb8c10 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -107,7 +107,7 @@ public class ForgePlayer extends AbstractPlayerActor { } @Override - public com.sk89q.worldedit.world.World getWorld() { + public World getWorld() { return ForgeWorldEdit.inst.getWorld(this.player.world); } @@ -189,6 +189,19 @@ public class ForgePlayer extends AbstractPlayerActor { return null; } + @Override + public boolean isAllowedToFly() { + return player.abilities.allowFlying; + } + + @Override + public void setFlying(boolean flying) { + if (player.abilities.isFlying != flying) { + player.abilities.isFlying = flying; + player.sendPlayerAbilities(); + } + } + @Override public > void sendFakeBlock(BlockVector3 pos, B block) { World world = getWorld(); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 6abda18d1..542cf884c 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -65,13 +65,11 @@ import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.ChunkPos; -import net.minecraft.world.ServerWorld; import net.minecraft.world.World; import net.minecraft.world.chunk.AbstractChunkProvider; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkStatus; import net.minecraft.world.chunk.IChunk; -import net.minecraft.world.chunk.ServerChunkProvider; import net.minecraft.world.chunk.listener.IChunkStatusListener; import net.minecraft.world.gen.feature.BigBrownMushroomFeature; import net.minecraft.world.gen.feature.BigMushroomFeatureConfig; @@ -91,11 +89,14 @@ import net.minecraft.world.gen.feature.ShrubFeature; import net.minecraft.world.gen.feature.SwampTreeFeature; import net.minecraft.world.gen.feature.TallTaigaTreeFeature; import net.minecraft.world.gen.feature.TreeFeature; +import net.minecraft.world.server.ServerChunkProvider; +import net.minecraft.world.server.ServerWorld; import net.minecraft.world.storage.SaveHandler; import net.minecraft.world.storage.WorldInfo; import javax.annotation.Nullable; import java.io.File; +import java.io.IOException; import java.lang.ref.WeakReference; import java.nio.file.Path; import java.util.Collections; @@ -329,19 +330,22 @@ public class ForgeWorld extends AbstractWorld { MinecraftServer server = originalWorld.getServer(); SaveHandler saveHandler = new SaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), server, server.getDataFixer()); - World freshWorld = new ServerWorld(server, server.getBackgroundExecutor(), saveHandler, originalWorld.getWorldInfo(), - originalWorld.dimension.getType(), originalWorld.getProfiler(), new NoOpChunkStatusListener()); + try (World freshWorld = new ServerWorld(server, server.getBackgroundExecutor(), saveHandler, originalWorld.getWorldInfo(), + originalWorld.dimension.getType(), originalWorld.getProfiler(), new NoOpChunkStatusListener())) { - // Pre-gen all the chunks - // We need to also pull one more chunk in every direction - CuboidRegion expandedPreGen = new CuboidRegion(region.getMinimumPoint().subtract(16, 0, 16), region.getMaximumPoint().add(16, 0, 16)); - for (BlockVector2 chunk : expandedPreGen.getChunks()) { - freshWorld.getChunk(chunk.getBlockX(), chunk.getBlockZ()); - } + // Pre-gen all the chunks + // We need to also pull one more chunk in every direction + CuboidRegion expandedPreGen = new CuboidRegion(region.getMinimumPoint().subtract(16, 0, 16), region.getMaximumPoint().add(16, 0, 16)); + for (BlockVector2 chunk : expandedPreGen.getChunks()) { + freshWorld.getChunk(chunk.getBlockX(), chunk.getBlockZ()); + } - ForgeWorld from = new ForgeWorld(freshWorld); - for (BlockVector3 vec : region) { - editSession.setBlock(vec, from.getFullBlock(vec)); + ForgeWorld from = new ForgeWorld(freshWorld); + for (BlockVector3 vec : region) { + editSession.setBlock(vec, from.getFullBlock(vec)); + } + } catch (IOException e) { + throw new RuntimeException(e); } } catch (MaxChangedBlocksException e) { throw new RuntimeException(e); @@ -579,15 +583,15 @@ public class ForgeWorld extends AbstractWorld { private static class NoOpChunkStatusListener implements IChunkStatusListener { @Override - public void func_219509_a(ChunkPos chunkPos) { + public void start(ChunkPos chunkPos) { } @Override - public void func_219508_a(ChunkPos chunkPos, @Nullable ChunkStatus chunkStatus) { + public void statusChanged(ChunkPos chunkPos, @Nullable ChunkStatus chunkStatus) { } @Override - public void func_219510_b() { + public void stop() { } } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java index 53897176e..971179339 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java @@ -21,7 +21,7 @@ package com.sk89q.worldedit.forge; import com.mojang.authlib.GameProfile; import net.minecraft.inventory.container.INamedContainerProvider; -import net.minecraft.world.ServerWorld; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.util.FakePlayer; import javax.annotation.Nullable; diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java index 2fd40fa23..8b26e9e33 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java @@ -22,13 +22,8 @@ package com.sk89q.worldedit.forge.net.handler; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.forge.ForgePlayer; import com.sk89q.worldedit.forge.ForgeWorldEdit; -import net.minecraft.client.Minecraft; import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.network.ThreadQuickExitException; -import net.minecraft.network.play.server.SCustomPayloadPlayPacket; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.network.NetworkEvent.ClientCustomPayloadEvent; -import net.minecraftforge.fml.network.NetworkEvent.ServerCustomPayloadEvent; import net.minecraftforge.fml.network.event.EventNetworkChannel; import java.nio.charset.Charset; @@ -47,10 +42,9 @@ public final class WECUIPacketHandler { public static void init() { HANDLER.addListener(WECUIPacketHandler::onPacketData); - HANDLER.addListener(WECUIPacketHandler::callProcessPacket); } - public static void onPacketData(ServerCustomPayloadEvent event) { + public static void onPacketData(ClientCustomPayloadEvent event) { ServerPlayerEntity player = event.getSource().get().getSender(); LocalSession session = ForgeWorldEdit.inst.getSession(player); @@ -63,15 +57,5 @@ public final class WECUIPacketHandler { session.handleCUIInitializationMessage(text, actor); session.describeCUI(actor); } - - public static void callProcessPacket(ClientCustomPayloadEvent event) { - try { - new SCustomPayloadPlayPacket( - new ResourceLocation(ForgeWorldEdit.MOD_ID, ForgeWorldEdit.CUI_PLUGIN_CHANNEL), - event.getPayload() - ).processPacket(Minecraft.getInstance().player.connection); - } catch (ThreadQuickExitException ignored) { - } - } } \ No newline at end of file diff --git a/worldedit-libs/README.md b/worldedit-libs/README.md new file mode 100644 index 000000000..6387fde12 --- /dev/null +++ b/worldedit-libs/README.md @@ -0,0 +1,9 @@ +This project shades _API_ libraries, i.e. those libraries +whose classes are publicly referenced from `-core` classes. + +This project _does not_ shade implementation libraries, i.e. +those libraries whose classes are internally depended on. + +This is because the main reason for shading those libraries is for +their internal usage in each platform, not because we need them available to +dependents of `-core` to compile and work with WorldEdit's API. diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle deleted file mode 100644 index fa57aa1d0..000000000 --- a/worldedit-libs/build.gradle +++ /dev/null @@ -1,143 +0,0 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -/* - -This project shades API libraries, i.e. those libraries -whose classes are publicly referenced from `-core` classes. - -This project does not shade implementation libraries, i.e. -those libraries whose classes are internally depended on. - -This is because the main reason for shading those libraries is for -their internal usage in each platform, not because we need them available to -dependents of `-core` to compile and work with WorldEdit's API. - - */ -configure(subprojects + project("core:ap")) { - apply plugin: 'maven' - apply plugin: 'com.github.johnrengelman.shadow' - apply plugin: 'com.jfrog.artifactory' - configurations { - create("shade") - getByName("archives").extendsFrom(getByName("default")) - } - - group = rootProject.group + ".worldedit-libs" - - tasks.register("jar", ShadowJar) { - configurations = [project.configurations.shade] - classifier = "" - - dependencies { - exclude(dependency("com.google.guava:guava")) - exclude(dependency("com.google.code.gson:gson")) - exclude(dependency("org.checkerframework:checker-qual")) - } - - relocate('net.kyori.text', 'com.sk89q.worldedit.util.formatting.text') - } - def altConfigFiles = { String artifactType -> - def deps = configurations.shade.incoming.dependencies - .collect { it.copy() } - .collect { dependency -> - dependency.artifact { artifact -> - artifact.name = dependency.name - artifact.type = artifactType - artifact.extension = 'jar' - artifact.classifier = artifactType - } - dependency - } - - return files(configurations.detachedConfiguration(deps as Dependency[]) - .resolvedConfiguration.lenientConfiguration.getArtifacts() - .findAll { it.classifier == artifactType } - .collect { zipTree(it.file) }) - } - tasks.register("sourcesJar", Jar) { - from { - altConfigFiles('sources') - } - def filePattern = ~'(.*)net/kyori/text((?:/|$).*)' - def textPattern = ~/net\.kyori\.text/ - eachFile { - it.filter { String line -> - line.replaceFirst(textPattern, 'com.sk89q.worldedit.util.formatting.text') - } - it.path = it.path.replaceFirst(filePattern, '$1com/sk89q/worldedit/util/formatting/text$2') - } - classifier = "sources" - } - - artifacts { - add("default", jar) - add("archives", sourcesJar) - } - - tasks.register("install", Upload) { - configuration = configurations.archives - repositories.mavenInstaller { - pom.version = project.version - pom.artifactId = project.name - } - } - - artifactoryPublish { - publishConfigs('default') - } - - build.dependsOn(jar, sourcesJar) -} - -def textExtrasVersion = "3.0.2" -project("core") { - def textVersion = "3.0.1" - def pistonVersion = '0.4.2' - - dependencies { - shade "net.kyori:text-api:$textVersion" - shade "net.kyori:text-serializer-gson:$textVersion" - shade "net.kyori:text-serializer-legacy:$textVersion" - shade "net.kyori:text-serializer-plain:$textVersion" - shade('com.sk89q:jchronic:0.2.4a') { - exclude(group: "junit", module: "junit") - } - shade 'com.thoughtworks.paranamer:paranamer:2.6' - shade 'com.sk89q.lib:jlibnoise:1.0.0' - shade "org.enginehub.piston:core:$pistonVersion" - shade "org.enginehub.piston.core-ap:runtime:$pistonVersion" - shade "org.enginehub.piston:default-impl:$pistonVersion" - } - - project("ap") { - dependencies { - shade "org.enginehub.piston.core-ap:annotations:$pistonVersion" - shade "org.enginehub.piston.core-ap:processor:$pistonVersion" - } - } -} -project("bukkit") { - repositories { - maven { - name = "SpigotMC" - url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" - } - } - dependencies { - shade "net.kyori:text-adapter-bukkit:$textExtrasVersion" - } -} -project("sponge") { - repositories { - maven { - name = "Sponge" - url = "https://repo.spongepowered.org/maven" - } - } - dependencies { - shade "net.kyori:text-adapter-spongeapi:$textExtrasVersion" - } -} - -tasks.register("build") { - dependsOn(subprojects.collect { it.tasks.named("build") }) -} diff --git a/worldedit-libs/build.gradle.kts b/worldedit-libs/build.gradle.kts new file mode 100644 index 000000000..40b3746a9 --- /dev/null +++ b/worldedit-libs/build.gradle.kts @@ -0,0 +1,3 @@ +tasks.register("build") { + dependsOn(subprojects.map { it.tasks.named("build") }) +} diff --git a/worldedit-libs/bukkit/build.gradle.kts b/worldedit-libs/bukkit/build.gradle.kts new file mode 100644 index 000000000..79734ff82 --- /dev/null +++ b/worldedit-libs/bukkit/build.gradle.kts @@ -0,0 +1,11 @@ +applyLibrariesConfiguration() + +repositories { + maven { + name = "SpigotMC" + url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") + } +} +dependencies { + "shade"("net.kyori:text-adapter-bukkit:${Versions.TEXT_EXTRAS}") +} \ No newline at end of file diff --git a/worldedit-libs/core/ap/build.gradle.kts b/worldedit-libs/core/ap/build.gradle.kts new file mode 100644 index 000000000..44374359b --- /dev/null +++ b/worldedit-libs/core/ap/build.gradle.kts @@ -0,0 +1,6 @@ +applyLibrariesConfiguration() + +dependencies { + "shade"("org.enginehub.piston.core-ap:annotations:${Versions.PISTON}") + "shade"("org.enginehub.piston.core-ap:processor:${Versions.PISTON}") +} diff --git a/worldedit-libs/core/build.gradle.kts b/worldedit-libs/core/build.gradle.kts new file mode 100644 index 000000000..d669216d6 --- /dev/null +++ b/worldedit-libs/core/build.gradle.kts @@ -0,0 +1,16 @@ +applyLibrariesConfiguration() + +dependencies { + "shade"("net.kyori:text-api:${Versions.TEXT}") + "shade"("net.kyori:text-serializer-gson:${Versions.TEXT}") + "shade"("net.kyori:text-serializer-legacy:${Versions.TEXT}") + "shade"("net.kyori:text-serializer-plain:${Versions.TEXT}") + "shade"("com.sk89q:jchronic:0.2.4a") { + exclude(group = "junit", module = "junit") + } + "shade"("com.thoughtworks.paranamer:paranamer:2.6") + "shade"("com.sk89q.lib:jlibnoise:1.0.0") + "shade"("org.enginehub.piston:core:${Versions.PISTON}") + "shade"("org.enginehub.piston.core-ap:runtime:${Versions.PISTON}") + "shade"("org.enginehub.piston:default-impl:${Versions.PISTON}") +} diff --git a/worldedit-libs/fabric/build.gradle.kts b/worldedit-libs/fabric/build.gradle.kts new file mode 100644 index 000000000..388618cea --- /dev/null +++ b/worldedit-libs/fabric/build.gradle.kts @@ -0,0 +1 @@ +applyLibrariesConfiguration() diff --git a/worldedit-libs/forge/build.gradle.kts b/worldedit-libs/forge/build.gradle.kts new file mode 100644 index 000000000..388618cea --- /dev/null +++ b/worldedit-libs/forge/build.gradle.kts @@ -0,0 +1 @@ +applyLibrariesConfiguration() diff --git a/worldedit-libs/sponge/build.gradle.kts b/worldedit-libs/sponge/build.gradle.kts new file mode 100644 index 000000000..5854dd616 --- /dev/null +++ b/worldedit-libs/sponge/build.gradle.kts @@ -0,0 +1,11 @@ +applyLibrariesConfiguration() + +repositories { + maven { + name = "Sponge" + url = uri("https://repo.spongepowered.org/maven") + } +} +dependencies { + "shade"("net.kyori:text-adapter-spongeapi:${Versions.TEXT_EXTRAS}") +} \ No newline at end of file diff --git a/worldedit-sponge/build.gradle b/worldedit-sponge/build.gradle deleted file mode 100644 index a745869b6..000000000 --- a/worldedit-sponge/build.gradle +++ /dev/null @@ -1,58 +0,0 @@ -buildscript { - repositories { - mavenCentral() - maven { url = "https://files.minecraftforge.net/maven" } - maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" } - jcenter() - } -} - -plugins { - id 'org.spongepowered.plugin' version '0.9.0' -} - -repositories { - maven { url "https://repo.codemc.org/repository/maven-public" } -} - -dependencies { - compile project(':worldedit-core') - compile project(':worldedit-libs:sponge') - compile 'org.spongepowered:spongeapi:7.1.0' - compile 'org.bstats:bstats-sponge:1.5' - testCompile group: 'org.mockito', name: 'mockito-core', version:'1.9.0-rc1' -} - -sourceCompatibility = JavaVersion.VERSION_1_8 -targetCompatibility = JavaVersion.VERSION_1_8 - -sponge { - plugin { - id = 'worldedit' - } -} - -jar { - manifest { - attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", - "WorldEdit-Version": version) - } -} - -shadowJar { - dependencies { - relocate ("org.bstats", "com.sk89q.worldedit.sponge.bstats") { - include(dependency('org.bstats:bstats-sponge:1.5')) - } - } -} - -if (project.hasProperty("signing")) { - apply plugin: 'signing' - - signing { - sign shadowJar - } - - build.dependsOn('signShadowJar') -} \ No newline at end of file diff --git a/worldedit-sponge/build.gradle.kts b/worldedit-sponge/build.gradle.kts new file mode 100644 index 000000000..1c5fa9453 --- /dev/null +++ b/worldedit-sponge/build.gradle.kts @@ -0,0 +1,53 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +plugins { + id("org.spongepowered.plugin") +} + +applyPlatformAndCoreConfiguration() +applyShadowConfiguration() + +repositories { + maven { url = uri("https://repo.codemc.org/repository/maven-public") } +} + +dependencies { + compile(project(":worldedit-core")) + compile(project(":worldedit-libs:sponge")) + compile("org.spongepowered:spongeapi:7.1.0") + compile("org.bstats:bstats-sponge:1.5") + testCompile("org.mockito:mockito-core:1.9.0-rc1") +} + +sponge { + plugin { + id = "worldedit" + } +} + +tasks.named("jar") { + manifest { + attributes("Class-Path" to "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", + "WorldEdit-Version" to project.version) + } +} + +tasks.named("shadowJar") { + dependencies { + relocate ("org.bstats", "com.sk89q.worldedit.sponge.bstats") { + include(dependency("org.bstats:bstats-sponge:1.5")) + } + } +} + +if (project.hasProperty("signing")) { + apply(plugin = "signing") + + configure { + sign("shadowJar") + } + + tasks.named("build").configure { + dependsOn("signShadowJar") + } +} \ No newline at end of file diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java index 82723fe93..3a5f94933 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java @@ -38,6 +38,7 @@ import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.item.ItemTypes; import org.spongepowered.api.Sponge; +import org.spongepowered.api.data.key.Keys; import org.spongepowered.api.data.type.HandTypes; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.item.ItemType; @@ -202,6 +203,16 @@ public class SpongePlayer extends AbstractPlayerActor { gameMode.getId()).get()); } + @Override + public boolean isAllowedToFly() { + return player.get(Keys.CAN_FLY).orElse(super.isAllowedToFly()); + } + + @Override + public void setFlying(boolean flying) { + player.offer(Keys.IS_FLYING, flying); + } + @Override public > void sendFakeBlock(BlockVector3 pos, B block) { org.spongepowered.api.world.Location loc = player.getWorld().getLocation(pos.getX(), pos.getY(), pos.getZ());