Merge branch 'master' into fix/quoted

This commit is contained in:
Kenzie Togami 2019-07-27 17:41:44 -07:00
commit d134820bcb
No known key found for this signature in database
GPG Key ID: 5D200B325E157A81
92 changed files with 1767 additions and 1637 deletions

View File

@ -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 7.0.0
See https://matthewmiller.dev/blog/introducing-worldedit-7/ for a friendlier explanation of some new features See https://matthewmiller.dev/blog/introducing-worldedit-7/ for a friendlier explanation of some new features

View File

@ -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*'
}
}

28
build.gradle.kts Normal file
View File

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

36
buildSrc/build.gradle.kts Normal file
View File

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

View File

@ -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<ArtifactoryPluginConvention> {
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<ArtifactoryTask>("artifactoryPublish") {
isSkip = true
}
}
fun Project.applyCommonArtifactoryConfig() {
tasks.named<ArtifactoryTask>("artifactoryPublish") {
publishConfigs("archives")
}
}

View File

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

View File

@ -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<JavaPluginConvention>().sourceSets

View File

@ -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<ShadowJar>("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<ModuleDependency>()
.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<Jar>("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<Upload>("install") {
configuration = configurations["archives"]
(repositories as HasConvention).convention.getPlugin<MavenRepositoryHandlerConvention>().mavenInstaller {
pom.version = project.version.toString()
pom.artifactId = project.name
}
}
applyCommonArtifactoryConfig()
}

View File

@ -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<JavaPluginConvention> {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
configure<CheckstyleExtension> {
configFile = rootProject.file("config/checkstyle/checkstyle.xml")
toolVersion = "7.6.1"
}
tasks.withType<Test>().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<Javadoc>().configureEach {
(options as CoreJavadocOptions).addStringOption("Xdoclint:none", "-quiet")
}
tasks.register<Jar>("javadocJar") {
dependsOn("javadoc")
archiveClassifier.set("javadoc")
from(tasks.getByName<Javadoc>("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<Jar>("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<LicenseExtension> {
header = rootProject.file("HEADER.txt")
include("**/*.java")
}
}
fun Project.applyShadowConfiguration() {
tasks.named<ShadowJar>("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()
}
}

View File

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

View File

@ -1,4 +1,4 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties. group=com.sk89q.worldedit
# This is required to provide enough memory for the Minecraft decompilation process. version=7.0.1-SNAPSHOT
#org.gradle.jvmargs=-Xmx3G
org.gradle.daemon=false org.gradle.jvmargs=-Xmx1G

Binary file not shown.

View File

@ -1,6 +1,5 @@
#Thu Mar 14 00:19:48 PDT 2019
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip

18
gradlew vendored
View File

@ -1,5 +1,21 @@
#!/usr/bin/env sh #!/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 ## Gradle start up script for UN*X
@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` 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. # 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. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD="maximum"

18
gradlew.bat vendored
View File

@ -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 @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% 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. @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 @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome

View File

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

11
settings.gradle.kts Normal file
View File

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

View File

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

View File

@ -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<Copy>("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>("jar") {
manifest {
attributes("Class-Path" to "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar",
"WorldEdit-Version" to project.version)
}
}
tasks.named<ShadowJar>("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")
}

View File

@ -335,7 +335,11 @@ public class BukkitAdapter {
* @return WorldEdit EntityType * @return WorldEdit EntityType
*/ */
public static EntityType adapt(org.bukkit.entity.EntityType 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) { public static org.bukkit.entity.EntityType adapt(EntityType entityType) {

View File

@ -185,14 +185,13 @@ public class BukkitPlayer extends AbstractPlayerActor {
} }
@Override @Override
public void floatAt(int x, int y, int z, boolean alwaysGlass) { public boolean isAllowedToFly() {
if (alwaysGlass || !player.getAllowFlight()) { return player.getAllowFlight();
super.floatAt(x, y, z, alwaysGlass); }
return;
}
setPosition(Vector3.at(x + 0.5, y, z + 0.5)); @Override
player.setFlying(true); public void setFlying(boolean flying) {
player.setFlying(flying);
} }
@Override @Override

View File

@ -316,15 +316,16 @@ public class BukkitWorld extends AbstractWorld {
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
if (worldRef.get() == null) { final World ref = worldRef.get();
if (ref == null) {
return false; return false;
} else if (other == null) { } else if (other == null) {
return false; return false;
} else if ((other instanceof BukkitWorld)) { } else if ((other instanceof BukkitWorld)) {
World otherWorld = ((BukkitWorld) other).worldRef.get(); 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) { } 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 { } else {
return false; return false;
} }

View File

@ -96,7 +96,6 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
private static final Logger log = LoggerFactory.getLogger(WorldEditPlugin.class); private static final Logger log = LoggerFactory.getLogger(WorldEditPlugin.class);
public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui"; public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui";
private static WorldEditPlugin INSTANCE; private static WorldEditPlugin INSTANCE;
private static WorldInitListener worldInitListener = null;
private BukkitImplAdapter bukkitAdapter; private BukkitImplAdapter bukkitAdapter;
private BukkitServerInterface server; private BukkitServerInterface server;
@ -139,22 +138,19 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
getServer().getPluginManager().registerEvents(new AsyncTabCompleteListener(), this); getServer().getPluginManager().registerEvents(new AsyncTabCompleteListener(), this);
} }
// register this so we can load world-dependent data right as the first world is loading initializeRegistries(); // this creates the objects matching Bukkit's enums - but doesn't fill them with data yet
if (worldInitListener != null) { 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."); getLogger().warning("Server reload detected. This may cause various issues with WorldEdit and dependent plugins.");
try { try {
// these don't stick around between reload setupPreWorldData();
loadAdapter(); // since worlds are loaded already, we can do this now
loadConfig(); setupWorldData();
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
} catch (Throwable ignored) { } 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 // Enable metrics
@ -162,12 +158,19 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
PaperLib.suggestPaper(this); PaperLib.suggestPaper(this);
} }
private void setupPreWorldData() {
loadAdapter();
loadConfig();
WorldEdit.getInstance().loadMappings();
}
private void setupWorldData() { 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()); WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
} }
private void setupRegistries() { private void initializeRegistries() {
// Biome // Biome
for (Biome biome : Biome.values()) { for (Biome biome : Biome.values()) {
String lowerCaseBiomeName = biome.name().toLowerCase(Locale.ROOT); String lowerCaseBiomeName = biome.name().toLowerCase(Locale.ROOT);
@ -487,9 +490,9 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
if (!event.isCommand()) return; if (!event.isCommand()) return;
String buffer = event.getBuffer(); String buffer = event.getBuffer();
final String[] parts = buffer.split(" "); int firstSpace = buffer.indexOf(' ');
if (parts.length < 1) return; if (firstSpace < 0) return;
final String label = parts[0]; final String label = buffer.substring(0, firstSpace);
final Optional<org.enginehub.piston.Command> command final Optional<org.enginehub.piston.Command> command
= WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getCommandManager().getCommand(label); = WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getCommandManager().getCommand(label);
if (!command.isPresent()) return; if (!command.isPresent()) return;

View File

@ -19,20 +19,20 @@
package com.sk89q.wepif; 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.Server;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; 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 { public class DinnerPermsResolverTest {
private DinnerPermsResolver resolver; private DinnerPermsResolver resolver;
@Before @BeforeEach
public void setUp() { public void setUp() {
Server server = mock(Server.class); Server server = mock(Server.class);
when(server.getPluginManager()).thenReturn(mock(PluginManager.class)); when(server.getPluginManager()).thenReturn(mock(PluginManager.class));

View File

@ -20,15 +20,16 @@
package com.sk89q.worldedit.bukkit; package com.sk89q.worldedit.bukkit;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class BukkitWorldTest { public class BukkitWorldTest {
@Test @Test
public void testTreeTypeMapping() { public void testTreeTypeMapping() {
for (TreeGenerator.TreeType type : TreeGenerator.TreeType.values()) { for (TreeGenerator.TreeType type : TreeGenerator.TreeType.values()) {
Assert.assertNotNull("No mapping for: " + type, BukkitWorld.toBukkitTreeType(type)); assertNotNull(BukkitWorld.toBukkitTreeType(type), "No mapping for: " + type);
} }
} }

View File

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

View File

@ -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<JavaCompile>().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")
}
}
}

View File

@ -1,17 +1,15 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { plugins {
kotlin("jvm") version "1.3.31" kotlin("jvm") version "1.3.41"
} }
applyCommonConfiguration()
tasks.withType<KotlinCompile> { tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8" kotlinOptions.jvmTarget = "1.8"
} }
repositories {
jcenter()
}
dependencies { dependencies {
"implementation"(project(":worldedit-libs:core:ap")) "implementation"(project(":worldedit-libs:core:ap"))
"implementation"(project(":worldedit-core")) "implementation"(project(":worldedit-core"))

View File

@ -180,7 +180,8 @@ public class BiomeCommands {
Mask2D mask2d = mask != null ? mask.toMask2D() : null; Mask2D mask2d = mask != null ? mask.toMask2D() : null;
if (atPosition) { 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 { } else {
region = session.getSelection(world); region = session.getSelection(world);
} }

View File

@ -26,6 +26,7 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.internal.anvil.ChunkDeleter; import com.sk89q.worldedit.internal.anvil.ChunkDeleter;
import com.sk89q.worldedit.internal.anvil.ChunkDeletionInfo; 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.regions.Region;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.component.PaginationBox; 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.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor; 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.nio.file.Path;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
@ -93,11 +95,11 @@ public class ChunkCommands {
@CommandPermissions("worldedit.listchunks") @CommandPermissions("worldedit.listchunks")
public void listChunks(Player player, LocalSession session, public void listChunks(Player player, LocalSession session,
@ArgFlag(name = 'p', desc = "Page number.", def = "1") int page) throws WorldEditException { @ArgFlag(name = 'p', desc = "Page number.", def = "1") int page) throws WorldEditException {
Set<BlockVector2> chunks = session.getSelection(player.getWorld()).getChunks(); final Region region = session.getSelection(player.getWorld());
PaginationBox paginationBox = PaginationBox.fromStrings("Selected Chunks", "/listchunks -p %page%", WorldEditAsyncCommandBuilder.createAndSendMessage(player,
chunks.stream().map(BlockVector2::toString).collect(Collectors.toList())); () -> new ChunkListPaginationBox(region).create(page),
player.print(paginationBox.create(page)); "Listing chunks for " + player.getName());
} }
@Command( @Command(
@ -134,8 +136,8 @@ public class ChunkCommands {
newBatch.backup = true; newBatch.backup = true;
final Region selection = session.getSelection(player.getWorld()); final Region selection = session.getSelection(player.getWorld());
if (selection instanceof CuboidRegion) { if (selection instanceof CuboidRegion) {
newBatch.minChunk = BlockVector2.at(selection.getMinimumPoint().getBlockX() >> 4, selection.getMinimumPoint().getBlockZ() >> 4); newBatch.minChunk = selection.getMinimumPoint().shr(4).toBlockVector2();
newBatch.maxChunk = BlockVector2.at(selection.getMaximumPoint().getBlockX() >> 4, selection.getMaximumPoint().getBlockZ() >> 4); newBatch.maxChunk = selection.getMaximumPoint().shr(4).toBlockVector2();
} else { } else {
// this has a possibility to OOM for very large selections still // this has a possibility to OOM for very large selections still
Set<BlockVector2> chunks = selection.getChunks(); Set<BlockVector2> chunks = selection.getChunks();
@ -168,4 +170,27 @@ public class ChunkCommands {
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop")))); .clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop"))));
} }
private static class ChunkListPaginationBox extends PaginationBox {
//private final Region region;
private final List<BlockVector2> 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();
}
}
} }

View File

@ -162,13 +162,13 @@ public class GenerationCommands {
final double radiusX, radiusY, radiusZ; final double radiusX, radiusY, radiusZ;
switch (radii.size()) { switch (radii.size()) {
case 1: case 1:
radiusX = radiusY = radiusZ = Math.max(1, radii.get(0)); radiusX = radiusY = radiusZ = Math.max(0, radii.get(0));
break; break;
case 3: case 3:
radiusX = Math.max(1, radii.get(0)); radiusX = Math.max(0, radii.get(0));
radiusY = Math.max(1, radii.get(1)); radiusY = Math.max(0, radii.get(1));
radiusZ = Math.max(1, radii.get(2)); radiusZ = Math.max(0, radii.get(2));
break; break;
default: default:
@ -205,7 +205,7 @@ public class GenerationCommands {
@Arg(desc = "The density of the forest, between 0 and 100", def = "5") @Arg(desc = "The density of the forest, between 0 and 100", def = "5")
double density) throws WorldEditException { double density) throws WorldEditException {
checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100"); 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); int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type);
player.print(affected + " trees created."); player.print(affected + " trees created.");
return affected; return affected;

View File

@ -19,6 +19,8 @@
package com.sk89q.worldedit.command; 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.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; 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.CodeFormat;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat; import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.PaginationBox; 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.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent; 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.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.io.Closer; import com.sk89q.worldedit.util.io.Closer;
import com.sk89q.worldedit.util.io.file.FilenameException; import com.sk89q.worldedit.util.io.file.FilenameException;
@ -68,7 +70,9 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable; 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; import static com.google.common.base.Preconditions.checkNotNull;
/** /**
@ -404,4 +408,44 @@ public class SchematicCommands {
} }
return fileList; 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<String, ClipboardFormat> 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;
}
}
} }

View File

@ -19,6 +19,7 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import com.google.common.base.Strings;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; 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.session.ClipboardHolder;
import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.Location; 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.CommandListBox;
import com.sk89q.worldedit.util.formatting.component.InvalidComponentException;
import com.sk89q.worldedit.util.formatting.component.PaginationBox; import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat; import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
import com.sk89q.worldedit.util.formatting.component.TextComponentProducer; 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.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; 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.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockState; 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.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.storage.ChunkStore; import com.sk89q.worldedit.world.storage.ChunkStore;
@ -570,7 +574,7 @@ public class SelectionCommands {
} }
case LIST: case LIST:
default: default:
CommandListBox box = new CommandListBox("Selection modes", null); CommandListBox box = new CommandListBox("Selection modes", null, null);
box.setHidingHelp(true); box.setHidingHelp(true);
TextComponentProducer contents = box.getContents(); TextComponentProducer contents = box.getContents();
contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline(); contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline();
@ -608,4 +612,62 @@ public class SelectionCommands {
session.dispatchCUISelection(player); session.dispatchCUISelection(player);
} }
private static class BlockDistributionResult extends PaginationBox {
private final List<Countable<BlockState>> distribution;
private final int totalBlocks;
private final boolean separateStates;
BlockDistributionResult(List<Countable<BlockState>> 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<BlockState> 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);
}
}
} }

View File

@ -523,7 +523,8 @@ public class UtilityCommands {
int page, int page,
@Arg(desc = "The command to retrieve help for", def = "", variable = true) @Arg(desc = "The command to retrieve help for", def = "", variable = true)
List<String> command) throws WorldEditException { List<String> command) throws WorldEditException {
PrintCommandHelp.help(command, page, listSubCommands, we, actor); PrintCommandHelp.help(command, page, listSubCommands,
we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "//help");
} }
} }

View File

@ -164,6 +164,7 @@ public class WorldEditCommands {
int page, int page,
@Arg(desc = "The command to retrieve help for", def = "", variable = true) @Arg(desc = "The command to retrieve help for", def = "", variable = true)
List<String> command) throws WorldEditException { List<String> command) throws WorldEditException {
PrintCommandHelp.help(command, page, listSubCommands, we, actor); PrintCommandHelp.help(command, page, listSubCommands,
we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "/worldedit help");
} }
} }

View File

@ -92,7 +92,7 @@ public class BrushTool implements TraceTool {
* @return the mask used to stop block traces * @return the mask used to stop block traces
*/ */
public @Nullable Mask getTraceMask() { public @Nullable Mask getTraceMask() {
return mask; return this.traceMask;
} }
/** /**

View File

@ -23,12 +23,13 @@ import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3; 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 com.sk89q.worldedit.world.block.BlockTypes;
import java.util.ArrayList; import java.util.LinkedHashSet;
import java.util.Collections; import java.util.Set;
import java.util.List;
public class GravityBrush implements Brush { public class GravityBrush implements Brush {
@ -40,27 +41,60 @@ public class GravityBrush implements Brush {
@Override @Override
public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException {
final double startY = fullHeight ? editSession.getWorld().getMaxY() : position.getBlockY() + size; double yMax = fullHeight ? editSession.getWorld().getMaxY() : position.getY() + size;
for (double x = position.getBlockX() + size; x > position.getBlockX() - size; --x) { double yMin = Math.max(position.getY() - size, 0);
for (double z = position.getBlockZ() + size; z > position.getBlockZ() - size; --z) { LocatedBlockList column = new LocatedBlockList();
double y = startY; Set<BlockVector3> removedBlocks = new LinkedHashSet<>();
final List<BlockState> blockTypes = new ArrayList<>(); for (double x = position.getX() - size; x <= position.getX() + size; x++) {
for (; y > position.getBlockY() - size; --y) { for (double z = position.getZ() - size; z <= position.getZ() + size; z++) {
final BlockVector3 pt = BlockVector3.at(x, y, z); /*
final BlockState block = editSession.getBlock(pt); * Algorithm:
if (!block.getBlockType().getMaterial().isAir()) { * 1. Find lowest air block in the selection -> $lowestAir = position
blockTypes.add(block); * 2. Move the first non-air block above it down to $lowestAir
editSession.setBlock(pt, BlockTypes.AIR.getDefaultState()); * 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); if (lowestAir == null) {
Collections.reverse(blockTypes); // no place to move the block to
for (int i = 0; i < blockTypes.size();) { continue;
if (editSession.getBlock(pt).getBlockType().getMaterial().isAir()) {
editSession.setBlock(pt, blockTypes.get(i++));
} }
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();
} }
} }
} }

View File

@ -67,11 +67,11 @@ public class PrintCommandHelp {
return mapping.orElse(null); return mapping.orElse(null);
} }
public static void help(List<String> commandPath, int page, boolean listSubCommands, WorldEdit we, Actor actor) throws InvalidComponentException { public static void help(List<String> commandPath, int page, boolean listSubCommands,
CommandManager manager = we.getPlatformManager().getPlatformCommandManager().getCommandManager(); CommandManager manager, Actor actor, String helpRootCommand) throws InvalidComponentException {
if (commandPath.isEmpty()) { if (commandPath.isEmpty()) {
printCommands(page, manager.getAllCommands(), actor, ImmutableList.of()); printCommands(page, manager.getAllCommands(), actor, ImmutableList.of(), helpRootCommand);
return; return;
} }
@ -93,7 +93,7 @@ public class PrintCommandHelp {
toCommandString(visited), subCommand)); toCommandString(visited), subCommand));
// full help for single command // full help for single command
CommandUsageBox box = new CommandUsageBox(visited, visited.stream() CommandUsageBox box = new CommandUsageBox(visited, visited.stream()
.map(Command::getName).collect(Collectors.joining(" "))); .map(Command::getName).collect(Collectors.joining(" ")), helpRootCommand);
actor.print(box.create()); actor.print(box.create());
return; return;
} }
@ -105,7 +105,7 @@ public class PrintCommandHelp {
actor.printError(String.format("The sub-command '%s' under '%s' could not be found.", actor.printError(String.format("The sub-command '%s' under '%s' could not be found.",
subCommand, toCommandString(visited))); subCommand, toCommandString(visited)));
// list subcommands for currentCommand // 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; return;
} }
} }
@ -114,10 +114,10 @@ public class PrintCommandHelp {
if (subCommands.isEmpty() || !listSubCommands) { if (subCommands.isEmpty() || !listSubCommands) {
// Create the message // Create the message
CommandUsageBox box = new CommandUsageBox(visited, toCommandString(visited)); CommandUsageBox box = new CommandUsageBox(visited, toCommandString(visited), helpRootCommand);
actor.print(box.create()); actor.print(box.create());
} else { } 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<Command> commandStream, Actor actor, private static void printCommands(int page, Stream<Command> commandStream, Actor actor,
List<Command> commandList) throws InvalidComponentException { List<Command> commandList, String helpRootCommand) throws InvalidComponentException {
// Get a list of aliases // Get a list of aliases
List<Command> commands = commandStream List<Command> commands = commandStream
.sorted(byCleanName()) .sorted(byCleanName())
@ -135,7 +135,8 @@ public class PrintCommandHelp {
String used = commandList.isEmpty() ? null : toCommandString(commandList); String used = commandList.isEmpty() ? null : toCommandString(commandList);
CommandListBox box = new CommandListBox( CommandListBox box = new CommandListBox(
(used == null ? "Help" : "Subcommands: " + used), (used == null ? "Help" : "Subcommands: " + used),
"//help -s -p %page%" + (used == null ? "" : " " + used)); helpRootCommand + " -s -p %page%" + (used == null ? "" : " " + used),
helpRootCommand);
if (!actor.isPlayer()) { if (!actor.isPlayer()) {
box.formatForConsole(); box.formatForConsole();
} }

View File

@ -19,7 +19,10 @@
package com.sk89q.worldedit.extension.platform; 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.NotABlockException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.Extent; 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.Location;
import com.sk89q.worldedit.util.TargetBlock; import com.sk89q.worldedit.util.TargetBlock;
import com.sk89q.worldedit.util.auth.AuthorizationException; 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.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
@ -173,7 +177,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
if (spots == 2) { if (spots == 2) {
final BlockVector3 platform = BlockVector3.at(x, y - 2, z); final BlockVector3 platform = BlockVector3.at(x, y - 2, z);
final BlockState block = world.getBlock(platform); 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! // Don't get put in lava!
if (type == BlockTypes.LAVA) { if (type == BlockTypes.LAVA) {
@ -259,6 +263,13 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
// Found a ceiling! // Found a ceiling!
if (world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) { if (world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) {
int platformY = Math.max(initialY, y - 3 - clearance); 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); floatAt(x, platformY + 1, z, alwaysGlass);
return true; return true;
} }
@ -302,25 +313,49 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override @Override
public void floatAt(int x, int y, int z, boolean alwaysGlass) { public void floatAt(int x, int y, int z, boolean alwaysGlass) {
try { if (alwaysGlass || !isAllowedToFly()) {
BlockVector3 spot = BlockVector3.at(x, y - 1, z); BlockVector3 spot = BlockVector3.at(x, y - 1, z);
if (!getLocation().getExtent().getBlock(spot).getBlockType().getMaterial().isMovementBlocker()) { final World world = getWorld();
getLocation().getExtent().setBlock(spot, BlockTypes.GLASS.getDefaultState()); 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) { } else {
e.printStackTrace(); setFlying(true);
} }
setPosition(Vector3.at(x + 0.5, y, z + 0.5)); 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 @Override
public Location getBlockIn() { public Location getBlockIn() {
return getLocation().setPosition(getLocation().toVector().floor()); final Location location = getLocation();
return location.setPosition(location.toVector().floor());
} }
@Override @Override
public Location getBlockOn() { 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 @Override
@ -369,15 +404,16 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override @Override
public Direction getCardinalDirection(int yawOffset) { public Direction getCardinalDirection(int yawOffset) {
if (getLocation().getPitch() > 67.5) { final Location location = getLocation();
if (location.getPitch() > 67.5) {
return Direction.DOWN; return Direction.DOWN;
} }
if (getLocation().getPitch() < -67.5) { if (location.getPitch() < -67.5) {
return Direction.UP; return Direction.UP;
} }
// From hey0's code // 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) { if (rot < 0) {
rot += 360.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. * Advances the block target block until the current block is a wall
* * @return true if a wall is found
* @return yaw
*/ */
private boolean advanceToWall(TargetBlock hitBlox) {
@Override Location curBlock;
public boolean passThroughForwardWall(int range) { while ((curBlock = hitBlox.getCurrentBlock()) != null) {
int searchDist = 0; if (!canPassThroughBlock(curBlock)) {
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);
return true; 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; return false;
@ -446,7 +493,8 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override @Override
public void setPosition(Vector3 pos) { public void setPosition(Vector3 pos) {
setPosition(pos, getLocation().getPitch(), getLocation().getYaw()); final Location location = getLocation();
setPosition(pos, location.getPitch(), location.getYaw());
} }
@Override @Override

View File

@ -178,4 +178,9 @@ class PlayerProxy extends AbstractPlayerActor {
public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) { public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) {
basePlayer.sendFakeBlock(pos, block); basePlayer.sendFakeBlock(pos, block);
} }
@Override
public void floatAt(int x, int y, int z, boolean alwaysGlass) {
basePlayer.floatAt(x, y, z, alwaysGlass);
}
} }

View File

@ -0,0 +1,67 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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 <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 location, T block) throws WorldEditException;
protected final <T extends BlockStateHolder<T>> 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<BaseBlock> getBufferedBlock(BlockVector3 position);
}

View File

@ -21,16 +21,16 @@ package com.sk89q.worldedit.extent.buffer;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.sk89q.worldedit.WorldEditException; 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.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkNotNull; 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, * Buffers changes to an {@link Extent} and allows retrieval of the changed blocks,
* without modifying the underlying extent. * without modifying the underlying extent.
*/ */
public class ExtentBuffer extends AbstractDelegateExtent { public class ExtentBuffer extends AbstractBufferingExtent {
private final Map<BlockVector3, BaseBlock> buffer = Maps.newHashMap(); private final Map<BlockVector3, BaseBlock> buffer = Maps.newHashMap();
private final Mask mask; private final Mask mask;
@ -67,23 +67,11 @@ public class ExtentBuffer extends AbstractDelegateExtent {
} }
@Override @Override
public BlockState getBlock(BlockVector3 position) { protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) {
if (mask.test(position)) { if (mask.test(position)) {
return getOrDefault(position).toImmutableState(); return Optional.of(buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos))));
} }
return super.getBlock(position); return Optional.empty();
}
@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)));
} }
@Override @Override

View File

@ -206,6 +206,8 @@ public class MCEditSchematicReader extends NBTSchematicReader {
} }
if (values.isEmpty()) { if (values.isEmpty()) {
t = null; t = null;
} else {
t = new CompoundTag(values);
} }
if (fixer != null && t != null) { if (fixer != null && t != null) {
@ -378,6 +380,24 @@ public class MCEditSchematicReader extends NBTSchematicReader {
return "note_block"; return "note_block";
case "Structure": case "Structure":
return "structure_block"; 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: default:
return id; return id;
} }

View File

@ -111,7 +111,7 @@ public class SpongeSchematicReader extends NBTSchematicReader {
} else if (dataVersion < liveDataVersion) { } else if (dataVersion < liveDataVersion) {
fixer = platform.getDataFixer(); fixer = platform.getDataFixer();
if (fixer != null) { 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); dataVersion, liveDataVersion);
} else { } else {
log.info("Schematic was made in an older Minecraft version ({} < {}), but DFU is not available. Data may be incompatible.", log.info("Schematic was made in an older Minecraft version ({} < {}), but DFU is not available. Data may be incompatible.",

View File

@ -260,8 +260,9 @@ public class SpongeSchematicWriter implements ClipboardWriter {
} }
values.remove("id"); values.remove("id");
values.put("Id", new StringTag(state.getType().getId())); values.put("Id", new StringTag(state.getType().getId()));
values.put("Pos", writeVector(e.getLocation().toVector())); final Location location = e.getLocation();
values.put("Rotation", writeRotation(e.getLocation())); values.put("Pos", writeVector(location.toVector()));
values.put("Rotation", writeRotation(location));
return new CompoundTag(values); return new CompoundTag(values);
}).filter(Objects::nonNull).collect(Collectors.toList()); }).filter(Objects::nonNull).collect(Collectors.toList());

View File

@ -19,22 +19,25 @@
package com.sk89q.worldedit.extent.reorder; 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.WorldEditException;
import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.AbstractBufferingExtent;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.RunContext; 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.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; 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 com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.SortedMap; import java.util.Map;
import java.util.TreeMap; import java.util.Optional;
import java.util.Set;
/** /**
* A special extent that batches changes into Minecraft chunks. This helps * 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 * loaded repeatedly, however it does take more memory due to caching the
* blocks. * blocks.
*/ */
public class ChunkBatchingExtent extends AbstractDelegateExtent { public class ChunkBatchingExtent extends AbstractBufferingExtent {
/** /**
* Comparator optimized for sorting chunks by the region file they reside * Comparator optimized for sorting chunks by the region file they reside
* in. This allows for file caches to be used while loading the chunk. * in. This allows for file caches to be used while loading the chunk.
*/ */
private static final Comparator<BlockVector2> REGION_OPTIMIZED_SORT = private static final Comparator<BlockVector2> 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); .thenComparing(BlockVector2.COMPARING_GRID_ARRANGEMENT);
private final SortedMap<BlockVector2, LocatedBlockList> batches = new TreeMap<>(REGION_OPTIMIZED_SORT); private final Table<BlockVector2, BlockVector3, BaseBlock> batches =
TreeBasedTable.create(REGION_OPTIMIZED_SORT, BlockVector3.sortByCoordsYzx());
private final Set<BlockVector3> containedBlocks = new HashSet<>();
private boolean enabled; private boolean enabled;
public ChunkBatchingExtent(Extent extent) { public ChunkBatchingExtent(Extent extent) {
@ -76,16 +81,34 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent {
return enabled; 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 @Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException { public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
if (!enabled) { if (!enabled) {
return getExtent().setBlock(location, block); return setDelegateBlock(location, block);
} }
BlockVector2 chunkPos = BlockVector2.at(location.getBlockX() >> 4, location.getBlockZ() >> 4); BlockVector2 chunkPos = getChunkPos(location);
batches.computeIfAbsent(chunkPos, k -> new LocatedBlockList()).add(location, block); BlockVector3 inChunkPos = getInChunkPos(location);
batches.put(chunkPos, inChunkPos, block.toBaseBlock());
containedBlocks.add(location);
return true; return true;
} }
@Override
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) {
if (!containedBlocks.contains(position)) {
return Optional.empty();
}
return Optional.of(batches.get(getChunkPos(position), getInChunkPos(position)));
}
@Override @Override
protected Operation commitBefore() { protected Operation commitBefore() {
if (!commitRequired()) { if (!commitRequired()) {
@ -94,17 +117,22 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent {
return new Operation() { return new Operation() {
// we get modified between create/resume -- only create this on resume to prevent CME // we get modified between create/resume -- only create this on resume to prevent CME
private Iterator<LocatedBlockList> batchIterator; private Iterator<Map.Entry<BlockVector2, Map<BlockVector3, BaseBlock>>> batchIterator;
@Override @Override
public Operation resume(RunContext run) throws WorldEditException { public Operation resume(RunContext run) throws WorldEditException {
if (batchIterator == null) { if (batchIterator == null) {
batchIterator = batches.values().iterator(); batchIterator = batches.rowMap().entrySet().iterator();
} }
if (!batchIterator.hasNext()) { if (!batchIterator.hasNext()) {
return null; return null;
} }
new SetLocatedBlocks(getExtent(), batchIterator.next()).resume(run); Map.Entry<BlockVector2, Map<BlockVector3, BaseBlock>> next = batchIterator.next();
BlockVector3 chunkOffset = next.getKey().toBlockVector3().shl(4);
for (Map.Entry<BlockVector3, BaseBlock> block : next.getValue().entrySet()) {
getExtent().setBlock(block.getKey().add(chunkOffset), block.getValue());
containedBlocks.remove(block.getKey());
}
batchIterator.remove(); batchIterator.remove();
return this; return this;
} }

View File

@ -20,7 +20,7 @@
package com.sk89q.worldedit.extent.reorder; package com.sk89q.worldedit.extent.reorder;
import com.sk89q.worldedit.WorldEditException; 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.extent.Extent;
import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.OperationQueue; 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.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
/** /**
* Re-orders blocks into several stages. * Re-orders blocks into several stages.
*/ */
public class MultiStageReorder extends AbstractDelegateExtent implements ReorderingExtent { public class MultiStageReorder extends AbstractBufferingExtent implements ReorderingExtent {
private static final Map<BlockType, PlacementPriority> priorityMap = new HashMap<>(); private static final Map<BlockType, PlacementPriority> priorityMap = new HashMap<>();
@ -139,6 +143,7 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder
priorityMap.put(BlockTypes.MOVING_PISTON, PlacementPriority.FINAL); priorityMap.put(BlockTypes.MOVING_PISTON, PlacementPriority.FINAL);
} }
private final Set<BlockVector3> containedBlocks = new HashSet<>();
private Map<PlacementPriority, LocatedBlockList> stages = new HashMap<>(); private Map<PlacementPriority, LocatedBlockList> stages = new HashMap<>();
private boolean enabled; private boolean enabled;
@ -212,7 +217,7 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder
@Override @Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException { public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
if (!enabled) { if (!enabled) {
return super.setBlock(location, block); return setDelegateBlock(location, block);
} }
BlockState existing = getBlock(location); BlockState existing = getBlock(location);
@ -240,9 +245,21 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder
} }
stages.get(priority).add(location, block); stages.get(priority).add(location, block);
containedBlocks.add(location);
return !existing.equalsFuzzy(block); return !existing.equalsFuzzy(block);
} }
@Override
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) {
if (!containedBlocks.contains(position)) {
return Optional.empty();
}
return stages.values().stream()
.map(blocks -> blocks.get(position))
.filter(Objects::nonNull)
.findAny();
}
@Override @Override
public Operation commitBefore() { public Operation commitBefore() {
if (!commitRequired()) { if (!commitRequired()) {

View File

@ -55,7 +55,9 @@ public class BlockOptimizedHistory extends ArrayListHistory {
if (change instanceof BlockChange) { if (change instanceof BlockChange) {
BlockChange blockChange = (BlockChange) change; BlockChange blockChange = (BlockChange) change;
BlockVector3 position = blockChange.getPosition(); BlockVector3 position = blockChange.getPosition();
previous.add(position, blockChange.getPrevious()); if (!previous.containsLocation(position)) {
previous.add(position, blockChange.getPrevious());
}
current.add(position, blockChange.getCurrent()); current.add(position, blockChange.getCurrent());
} else { } else {
super.add(change); super.add(change);

View File

@ -32,6 +32,7 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; 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.BaseBlock;
import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypes;
@ -114,11 +115,12 @@ public class ServerCUIHandler {
} }
// Borrowed this math from FAWE // Borrowed this math from FAWE
double rotX = player.getLocation().getYaw(); final Location location = player.getLocation();
double rotY = player.getLocation().getPitch(); double rotX = location.getYaw();
double rotY = location.getPitch();
double xz = Math.cos(Math.toRadians(rotY)); double xz = Math.cos(Math.toRadians(rotY));
int x = (int) (player.getLocation().getX() - (-xz * Math.sin(Math.toRadians(rotX))) * 12); int x = (int) (location.getX() - (-xz * Math.sin(Math.toRadians(rotX))) * 12);
int z = (int) (player.getLocation().getZ() - (xz * Math.cos(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)); int y = Math.max(0, Math.min(Math.min(255, posY + 32), posY + 3));
Map<String, Tag> structureTag = new HashMap<>(); Map<String, Tag> structureTag = new HashMap<>();

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.math; package com.sk89q.worldedit.math;
import com.google.common.collect.ComparisonChain;
import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.AffineTransform;
import java.util.Comparator; import java.util.Comparator;
@ -48,12 +47,8 @@ public final class BlockVector2 {
* cdef * cdef
* </pre> * </pre>
*/ */
public static final Comparator<BlockVector2> COMPARING_GRID_ARRANGEMENT = (a, b) -> { public static final Comparator<BlockVector2> COMPARING_GRID_ARRANGEMENT =
return ComparisonChain.start() Comparator.comparingInt(BlockVector2::getZ).thenComparingInt(BlockVector2::getX);
.compare(a.getBlockZ(), b.getBlockZ())
.compare(a.getBlockX(), b.getBlockX())
.result();
};
public static BlockVector2 at(double x, double z) { public static BlockVector2 at(double x, double z) {
return at((int) Math.floor(x), (int) Math.floor(z)); return at((int) Math.floor(x), (int) Math.floor(z));
@ -303,6 +298,27 @@ public final class BlockVector2 {
return divide(n, n); 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. * Get the length of the vector.
* *
@ -532,5 +548,4 @@ public final class BlockVector2 {
public String toString() { public String toString() {
return "(" + x + ", " + z + ")"; return "(" + x + ", " + z + ")";
} }
} }

View File

@ -19,13 +19,12 @@
package com.sk89q.worldedit.math; 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 com.sk89q.worldedit.math.transform.AffineTransform;
import java.util.Comparator; import java.util.Comparator;
import static com.google.common.base.Preconditions.checkArgument;
/** /**
* An immutable 3-dimensional vector. * An immutable 3-dimensional vector.
*/ */
@ -64,13 +63,10 @@ public final class BlockVector3 {
// thread-safe initialization idiom // thread-safe initialization idiom
private static final class YzxOrderComparator { private static final class YzxOrderComparator {
private static final Comparator<BlockVector3> YZX_ORDER = (a, b) -> { private static final Comparator<BlockVector3> YZX_ORDER =
return ComparisonChain.start() Comparator.comparingInt(BlockVector3::getY)
.compare(a.y, b.y) .thenComparingInt(BlockVector3::getZ)
.compare(a.z, b.z) .thenComparingInt(BlockVector3::getX);
.compare(a.x, b.x)
.result();
};
} }
/** /**
@ -348,6 +344,50 @@ public final class BlockVector3 {
return divide(n, n, n); 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. * Get the length of the vector.
* *

View File

@ -0,0 +1,41 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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");
}
}

View File

@ -50,6 +50,7 @@ public class RhinoCraftScriptEngine implements CraftScriptEngine {
throws ScriptException, Throwable { throws ScriptException, Throwable {
RhinoContextFactory factory = new RhinoContextFactory(timeLimit); RhinoContextFactory factory = new RhinoContextFactory(timeLimit);
Context cx = factory.enterContext(); Context cx = factory.enterContext();
cx.setClassShutter(new MinecraftHidingClassShutter());
ScriptableObject scriptable = new ImporterTopLevel(cx); ScriptableObject scriptable = new ImporterTopLevel(cx);
Scriptable scope = cx.initStandardObjects(scriptable); Scriptable scope = cx.initStandardObjects(scriptable);

View File

@ -1,134 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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
? "<unknown>" : 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
? "<unknown>" : 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;
}
}

View File

@ -1,153 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<String> names;
private static List<String> mimeTypes;
private static List<String> 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<String> 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<String> getMimeTypes() {
return mimeTypes;
}
@Override
public List<String> 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();
}
}

View File

@ -21,68 +21,72 @@ package com.sk89q.worldedit.util.collection;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.LocatedBlock; import com.sk89q.worldedit.util.LocatedBlock;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Map;
/** /**
* Wrapper around a list of blocks located in the world. * Wrapper around a list of blocks located in the world.
*/ */
public class LocatedBlockList implements Iterable<LocatedBlock> { public class LocatedBlockList implements Iterable<LocatedBlock> {
private final List<LocatedBlock> list; private final Map<BlockVector3, LocatedBlock> map = new LinkedHashMap<>();
public LocatedBlockList() { public LocatedBlockList() {
list = new ArrayList<>();
} }
public LocatedBlockList(Collection<? extends LocatedBlock> collection) { public LocatedBlockList(Collection<? extends LocatedBlock> collection) {
list = new ArrayList<>(collection); for (LocatedBlock locatedBlock : collection) {
map.put(locatedBlock.getLocation(), locatedBlock);
}
} }
public void add(LocatedBlock setBlockCall) { public void add(LocatedBlock setBlockCall) {
checkNotNull(setBlockCall); checkNotNull(setBlockCall);
list.add(setBlockCall); map.put(setBlockCall.getLocation(), setBlockCall);
} }
public <B extends BlockStateHolder<B>> void add(BlockVector3 location, B block) { public <B extends BlockStateHolder<B>> void add(BlockVector3 location, B block) {
add(new LocatedBlock(location, block.toBaseBlock())); 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() { public int size() {
return list.size(); return map.size();
} }
public void clear() { public void clear() {
list.clear(); map.clear();
} }
@Override @Override
public Iterator<LocatedBlock> iterator() { public Iterator<LocatedBlock> iterator() {
return list.iterator(); return map.values().iterator();
} }
public Iterator<LocatedBlock> reverseIterator() { public Iterator<LocatedBlock> reverseIterator() {
return new Iterator<LocatedBlock>() { List<LocatedBlock> data = new ArrayList<>(map.values());
Collections.reverse(data);
private final ListIterator<LocatedBlock> backingIterator = list.listIterator(list.size()); return data.iterator();
@Override
public boolean hasNext() {
return backingIterator.hasPrevious();
}
@Override
public LocatedBlock next() {
return backingIterator.previous();
}
};
} }
} }

View File

@ -1,90 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<Countable<BlockState>> distribution;
private final int totalBlocks;
private final boolean separateStates;
public BlockDistributionResult(List<Countable<BlockState>> 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<BlockState> 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);
}
}

View File

@ -32,14 +32,16 @@ public class CommandListBox extends PaginationBox {
private List<CommandEntry> commands = Lists.newArrayList(); private List<CommandEntry> commands = Lists.newArrayList();
private boolean hideHelp; private boolean hideHelp;
private String helpCommand;
/** /**
* Create a new box. * Create a new box.
* *
* @param title the title * @param title the title
*/ */
public CommandListBox(String title, String pageCommand) { public CommandListBox(String title, String pageCommand, String helpCommand) {
super(title, pageCommand); super(title, pageCommand);
this.helpCommand = helpCommand;
} }
@Override @Override
@ -72,7 +74,7 @@ public class CommandListBox extends PaginationBox {
this.hideHelp = hideHelp; this.hideHelp = hideHelp;
} }
private static class CommandEntry { private class CommandEntry {
private final String alias; private final String alias;
private final Component description; private final Component description;
private final String insertion; private final String insertion;
@ -87,7 +89,7 @@ public class CommandListBox extends PaginationBox {
TextComponentProducer line = new TextComponentProducer(); TextComponentProducer line = new TextComponentProducer();
if (!hideHelp) { if (!hideHelp) {
line.append(SubtleFormat.wrap("? ") 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")))); .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Additional Help"))));
} }
TextComponent command = TextComponent.of(alias, TextColor.GOLD); TextComponent command = TextComponent.of(alias, TextColor.GOLD);

View File

@ -45,9 +45,10 @@ public class CommandUsageBox extends TextComponentProducer {
* *
* @param commands the commands to describe * @param commands the commands to describe
* @param commandString the commands that were used, such as "/we" or "/brush sphere" * @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<Command> commands, String commandString) throws InvalidComponentException { public CommandUsageBox(List<Command> commands, String commandString, String helpRootCommand) throws InvalidComponentException {
this(commands, commandString, null); this(commands, commandString, helpRootCommand, null);
} }
/** /**
@ -55,15 +56,18 @@ public class CommandUsageBox extends TextComponentProducer {
* *
* @param commands the commands to describe * @param commands the commands to describe
* @param commandString the commands that were used, such as "/we" or "/brush sphere" * @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 * @param parameters list of parameters to use
*/ */
public CommandUsageBox(List<Command> commands, String commandString, @Nullable CommandParameters parameters) throws InvalidComponentException { public CommandUsageBox(List<Command> commands, String commandString, String helpRootCommand,
@Nullable CommandParameters parameters) throws InvalidComponentException {
checkNotNull(commands); checkNotNull(commands);
checkNotNull(commandString); checkNotNull(commandString);
attachCommandUsage(commands, commandString); checkNotNull(helpRootCommand);
attachCommandUsage(commands, commandString, helpRootCommand);
} }
private void attachCommandUsage(List<Command> commands, String commandString) { private void attachCommandUsage(List<Command> commands, String commandString, String helpRootCommand) {
TextComponentProducer boxContent = new TextComponentProducer() TextComponentProducer boxContent = new TextComponentProducer()
.append(HelpGenerator.create(commands).getFullHelp()); .append(HelpGenerator.create(commands).getFullHelp());
if (getSubCommands(Iterables.getLast(commands)).size() > 0) { if (getSubCommands(Iterables.getLast(commands)).size() > 0) {
@ -73,7 +77,7 @@ public class CommandUsageBox extends TextComponentProducer {
.append(TextComponent.builder("List Subcommands") .append(TextComponent.builder("List Subcommands")
.color(ColorConfig.getMainText()) .color(ColorConfig.getMainText())
.decoration(TextDecoration.ITALIC, true) .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"))) .hoverEvent(HoverEvent.showText(TextComponent.of("List all subcommands of this command")))
.build()) .build())
.build()); .build());

View File

@ -1,75 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<String, ClipboardFormat> 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;
}
}

View File

@ -19,8 +19,9 @@
package com.sk89q.worldedit.util.paste; 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 com.sk89q.worldedit.util.net.HttpRequest;
import org.json.simple.JSONValue;
import java.io.IOException; import java.io.IOException;
import java.net.URL; 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 Pattern URL_PATTERN = Pattern.compile("https?://.+$");
private static final Gson GSON = new Gson();
@Override @Override
public Callable<URL> paste(String content) { public Callable<URL> paste(String content) {
return new PasteTask(content); return new PasteTask(content);
@ -59,10 +62,10 @@ public class EngineHubPaste implements Paster {
.returnContent() .returnContent()
.asString("UTF-8").trim(); .asString("UTF-8").trim();
Object object = JSONValue.parse(result); Map<Object, Object> object = GSON.fromJson(result, new TypeToken<Map<Object, Object>>() {
if (object instanceof Map) { }.getType());
@SuppressWarnings("unchecked") if (object != null) {
String urlString = String.valueOf(((Map<Object, Object>) object).get("url")); String urlString = String.valueOf(object.get("url"));
Matcher m = URL_PATTERN.matcher(urlString); Matcher m = URL_PATTERN.matcher(urlString);
if (m.matches()) { if (m.matches()) {

View File

@ -19,19 +19,20 @@
package com.sk89q.minecraft.util.commands; package com.sk89q.minecraft.util.commands;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import static org.junit.Assert.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.fail; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class CommandContextTest { public class CommandContextTest {
@ -39,7 +40,7 @@ public class CommandContextTest {
private static final String firstCmdString = "herpderp -opw testers \"mani world\" 'another thing' because something"; private static final String firstCmdString = "herpderp -opw testers \"mani world\" 'another thing' because something";
CommandContext firstCommand; CommandContext firstCommand;
@Before @BeforeEach
public void setUpTest() { public void setUpTest() {
try { try {
firstCommand = new CommandContext(firstCmdString, new HashSet<>(Arrays.asList('o', 'w'))); firstCommand = new CommandContext(firstCmdString, new HashSet<>(Arrays.asList('o', 'w')));
@ -49,10 +50,12 @@ public class CommandContextTest {
} }
} }
@Test(expected = CommandException.class) @Test
public void testInvalidFlags() throws CommandException { public void testInvalidFlags() {
final String failingCommand = "herpderp -opw testers"; 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 @Test

View File

@ -19,33 +19,33 @@
package com.sk89q.worldedit.extent.transform; 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.AffineTransform;
import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockType;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.Ignore; import org.junit.jupiter.api.Disabled;
import org.junit.Test; import org.junit.jupiter.api.Test;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; 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 { public class BlockTransformExtentTest {
private static final Transform ROTATE_90 = new AffineTransform().rotateY(-90); private static final Transform ROTATE_90 = new AffineTransform().rotateY(-90);
private static final Transform ROTATE_NEG_90 = new AffineTransform().rotateY(90); private static final Transform ROTATE_NEG_90 = new AffineTransform().rotateY(90);
private final Set<BlockType> ignored = new HashSet<>(); private final Set<BlockType> ignored = new HashSet<>();
@Before @BeforeEach
public void setUp() throws Exception { public void setUp() {
BlockType.REGISTRY.register("worldedit:test", new BlockType("worldedit:test")); BlockType.REGISTRY.register("worldedit:test", new BlockType("worldedit:test"));
} }
@Test @Test
public void testTransform() throws Exception { public void testTransform() {
for (BlockType type : BlockType.REGISTRY.values()) { for (BlockType type : BlockType.REGISTRY.values()) {
if (ignored.contains(type)) { if (ignored.contains(type)) {
continue; continue;

View File

@ -21,10 +21,10 @@ package com.sk89q.worldedit.internal.command;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.internal.util.Substring; 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 com.sk89q.worldedit.internal.command.CommandArgParser.spaceSplit;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
public class CommandArgParserTest { public class CommandArgParserTest {
@Test @Test

View File

@ -19,16 +19,6 @@
package com.sk89q.worldedit.internal.expression; 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.LocalConfiguration;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Platform; 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.parser.ParserException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment; 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 { public class ExpressionTest {
@Before @BeforeEach
public void setup() { public void setup() {
Platform mockPlat = Mockito.mock(Platform.class); Platform mockPlat = Mockito.mock(Platform.class);
Mockito.when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() { Mockito.when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() {
@ -68,56 +69,46 @@ public class ExpressionTest {
} }
@Test @Test
public void testErrors() throws ExpressionException { public void testErrors() {
// test lexer errors assertAll(
try { // test lexer errors
compile("#"); () -> {
fail("Error expected"); LexerException e = assertThrows(LexerException.class,
} catch (LexerException e) { () -> compile("#"));
assertEquals("Error position", 0, e.getPosition()); assertEquals(0, e.getPosition(), "Error position");
} },
// test parser errors
// test parser errors () -> {
try { ParserException e = assertThrows(ParserException.class,
compile("x"); () -> compile("x"));
fail("Error expected"); assertEquals(0, e.getPosition(), "Error position");
} catch (ParserException e) { },
assertEquals("Error position", 0, e.getPosition()); () -> {
} ParserException e = assertThrows(ParserException.class,
try { () -> compile("x()"));
compile("x()"); assertEquals(0, e.getPosition(), "Error position");
fail("Error expected"); },
} catch (ParserException e) { () -> assertThrows(ParserException.class,
assertEquals("Error position", 0, e.getPosition()); () -> compile("(")),
} () -> assertThrows(ParserException.class,
try { () -> compile("x(")),
compile("("); // test overloader errors
fail("Error expected"); () -> {
} catch (ParserException ignored) {} ParserException e = assertThrows(ParserException.class,
try { () -> compile("atan2(1)"));
compile("x("); assertEquals(0, e.getPosition(), "Error position");
fail("Error expected"); },
} catch (ParserException ignored) {} () -> {
ParserException e = assertThrows(ParserException.class,
// test overloader errors () -> compile("atan2(1, 2, 3)"));
try { assertEquals(0, e.getPosition(), "Error position");
compile("atan2(1)"); },
fail("Error expected"); () -> {
} catch (ParserException e) { ParserException e = assertThrows(ParserException.class,
assertEquals("Error position", 0, e.getPosition()); () -> compile("rotate(1, 2, 3)"));
} assertEquals(0, e.getPosition(), "Error position");
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());
}
} }
@Test @Test
@ -181,13 +172,11 @@ public class ExpressionTest {
} }
@Test @Test
public void testTimeout() throws Exception { public void testTimeout() {
try { 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)}}}}"); () -> 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."); "Loop was not stopped.");
} catch (EvaluationException e) { assertTrue(e.getMessage().contains("Calculations exceeded time limit"));
assertTrue(e.getMessage().contains("Calculations exceeded time limit"));
}
} }
private double simpleEval(String expressionString) throws ExpressionException { private double simpleEval(String expressionString) throws ExpressionException {

View File

@ -19,12 +19,12 @@
package com.sk89q.worldedit.util; 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.math.Vector3;
import com.sk89q.worldedit.world.World; 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}. * Tests {@link Location}.

View File

@ -19,14 +19,14 @@
package com.sk89q.worldedit.util.eventbus; package com.sk89q.worldedit.util.eventbus;
import org.junit.Test; import org.junit.jupiter.api.Test;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
public class EventBusTest { public class EventBusTest {

View File

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

View File

@ -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<BasePluginConvention> {
archivesBaseName = "$archivesBaseName-mc$minecraftVersion"
}
tasks.named<Copy>("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>("jar") {
manifest {
attributes("Class-Path" to "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar",
"WorldEdit-Version" to project.version)
}
}
tasks.named<ShadowJar>("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<Jar>("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<Task>
tasks.register("remapShadowJar", remapJarIntellijHack) {
(this as RemapJarTask).run {
val shadowJar = tasks.getByName<ShadowJar>("shadowJar")
dependsOn(shadowJar)
setInput(shadowJar.archiveFile)
setOutput(shadowJar.archiveFile.get().asFile.absolutePath.replace(Regex("-dev\\.jar$"), ".jar"))
}
}
tasks.named("assemble").configure {
dependsOn("remapShadowJar")
}

View File

@ -106,7 +106,7 @@ public class FabricPlayer extends AbstractPlayerActor {
} }
@Override @Override
public com.sk89q.worldedit.world.World getWorld() { public World getWorld() {
return FabricWorldEdit.inst.getWorld(this.player.world); return FabricWorldEdit.inst.getWorld(this.player.world);
} }
@ -188,6 +188,19 @@ public class FabricPlayer extends AbstractPlayerActor {
return null; 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 @Override
public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) { public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) {
World world = getWorld(); World world = getWorld();

View File

@ -202,16 +202,25 @@ public class FabricWorld extends AbstractWorld {
CompoundTag tag = ((BaseBlock) block).getNbtData(); CompoundTag tag = ((BaseBlock) block).getNbtData();
if (tag != null) { if (tag != null) {
net.minecraft.nbt.CompoundTag nativeTag = NBTConverter.toNative(tag); net.minecraft.nbt.CompoundTag nativeTag = NBTConverter.toNative(tag);
nativeTag.putString("id", ((BaseBlock) block).getNbtId()); BlockEntity tileEntity = getWorld().getWorldChunk(pos).getBlockEntity(pos);
TileEntityUtils.setTileEntity(world, position, nativeTag); if (tileEntity != null) {
successful = true; // update if TE changed as well tileEntity.fromTag(nativeTag);
tileEntity.setPos(pos);
tileEntity.setWorld(world);
successful = true; // update if TE changed as well
}
} }
} }
} }
if (successful && notifyAndLight) { if (successful && notifyAndLight) {
world.getChunkManager().getLightingProvider().enqueueLightUpdate(pos); world.getChunkManager().getLightingProvider().enqueueLightUpdate(pos);
world.scheduleBlockRender(pos, old, newState);
world.updateListeners(pos, old, newState, UPDATE | NOTIFY); world.updateListeners(pos, old, newState, UPDATE | NOTIFY);
world.updateNeighbors(pos, newState.getBlock());
if (old.hasComparatorOutput()) {
world.updateHorizontalAdjacent(pos, newState.getBlock());
}
} }
return successful; return successful;
@ -220,7 +229,9 @@ public class FabricWorld extends AbstractWorld {
@Override @Override
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException { public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {
BlockPos pos = new BlockPos(position.getX(), position.getY(), position.getZ()); 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; return true;
} }
@ -496,7 +507,9 @@ public class FabricWorld extends AbstractWorld {
BlockEntity tile = ((WorldChunk) getWorld().getChunk(pos)).getBlockEntity(pos, WorldChunk.CreationType.CHECK); BlockEntity tile = ((WorldChunk) getWorld().getChunk(pos)).getBlockEntity(pos, WorldChunk.CreationType.CHECK);
if (tile != null) { 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 { } else {
return getBlock(position).toBaseBlock(); return getBlock(position).toBaseBlock();
} }

View File

@ -1,79 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

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

View File

@ -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<UserDevExtension> {
mappings(mapOf(
"channel" to "snapshot",
"version" to "20190724-$mappingsMinecraftVersion"
))
runs {
val runConfig = Action<RunConfig> {
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<BasePluginConvention> {
archivesBaseName = "$archivesBaseName-mc$minecraftVersion"
}
tasks.named<Copy>("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>("jar") {
manifest {
attributes("WorldEdit-Version" to project.version)
}
}
tasks.named<ShadowJar>("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<NamedDomainObjectContainer<RenameJarInPlace>>("reobf")
reobf.maybeCreate("shadowJar").run {
mappings = tasks.getByName<GenerateSRG>("createMcpToSrg").output
}
}
tasks.register<Jar>("deobfJar") {
from(sourceSets["main"].output)
archiveClassifier.set("dev")
}
artifacts {
add("archives", tasks.named("deobfJar"))
}

View File

@ -35,7 +35,7 @@ import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.PlayerList; import net.minecraft.server.management.PlayerList;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SharedConstants; import net.minecraft.util.SharedConstants;
import net.minecraft.world.ServerWorld; import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.fml.server.ServerLifecycleHooks; import net.minecraftforge.fml.server.ServerLifecycleHooks;
import org.enginehub.piston.Command; import org.enginehub.piston.Command;
import org.enginehub.piston.CommandManager; import org.enginehub.piston.CommandManager;

View File

@ -107,7 +107,7 @@ public class ForgePlayer extends AbstractPlayerActor {
} }
@Override @Override
public com.sk89q.worldedit.world.World getWorld() { public World getWorld() {
return ForgeWorldEdit.inst.getWorld(this.player.world); return ForgeWorldEdit.inst.getWorld(this.player.world);
} }
@ -189,6 +189,19 @@ public class ForgePlayer extends AbstractPlayerActor {
return null; 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 @Override
public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) { public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) {
World world = getWorld(); World world = getWorld();

View File

@ -65,13 +65,11 @@ import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.ServerWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.chunk.AbstractChunkProvider; import net.minecraft.world.chunk.AbstractChunkProvider;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkStatus; import net.minecraft.world.chunk.ChunkStatus;
import net.minecraft.world.chunk.IChunk; import net.minecraft.world.chunk.IChunk;
import net.minecraft.world.chunk.ServerChunkProvider;
import net.minecraft.world.chunk.listener.IChunkStatusListener; import net.minecraft.world.chunk.listener.IChunkStatusListener;
import net.minecraft.world.gen.feature.BigBrownMushroomFeature; import net.minecraft.world.gen.feature.BigBrownMushroomFeature;
import net.minecraft.world.gen.feature.BigMushroomFeatureConfig; 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.SwampTreeFeature;
import net.minecraft.world.gen.feature.TallTaigaTreeFeature; import net.minecraft.world.gen.feature.TallTaigaTreeFeature;
import net.minecraft.world.gen.feature.TreeFeature; 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.SaveHandler;
import net.minecraft.world.storage.WorldInfo; import net.minecraft.world.storage.WorldInfo;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collections; import java.util.Collections;
@ -329,19 +330,22 @@ public class ForgeWorld extends AbstractWorld {
MinecraftServer server = originalWorld.getServer(); MinecraftServer server = originalWorld.getServer();
SaveHandler saveHandler = new SaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), server, server.getDataFixer()); SaveHandler saveHandler = new SaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), server, server.getDataFixer());
World freshWorld = new ServerWorld(server, server.getBackgroundExecutor(), saveHandler, originalWorld.getWorldInfo(), try (World freshWorld = new ServerWorld(server, server.getBackgroundExecutor(), saveHandler, originalWorld.getWorldInfo(),
originalWorld.dimension.getType(), originalWorld.getProfiler(), new NoOpChunkStatusListener()); originalWorld.dimension.getType(), originalWorld.getProfiler(), new NoOpChunkStatusListener())) {
// Pre-gen all the chunks // Pre-gen all the chunks
// We need to also pull one more chunk in every direction // 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)); CuboidRegion expandedPreGen = new CuboidRegion(region.getMinimumPoint().subtract(16, 0, 16), region.getMaximumPoint().add(16, 0, 16));
for (BlockVector2 chunk : expandedPreGen.getChunks()) { for (BlockVector2 chunk : expandedPreGen.getChunks()) {
freshWorld.getChunk(chunk.getBlockX(), chunk.getBlockZ()); freshWorld.getChunk(chunk.getBlockX(), chunk.getBlockZ());
} }
ForgeWorld from = new ForgeWorld(freshWorld); ForgeWorld from = new ForgeWorld(freshWorld);
for (BlockVector3 vec : region) { for (BlockVector3 vec : region) {
editSession.setBlock(vec, from.getFullBlock(vec)); editSession.setBlock(vec, from.getFullBlock(vec));
}
} catch (IOException e) {
throw new RuntimeException(e);
} }
} catch (MaxChangedBlocksException e) { } catch (MaxChangedBlocksException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@ -579,15 +583,15 @@ public class ForgeWorld extends AbstractWorld {
private static class NoOpChunkStatusListener implements IChunkStatusListener { private static class NoOpChunkStatusListener implements IChunkStatusListener {
@Override @Override
public void func_219509_a(ChunkPos chunkPos) { public void start(ChunkPos chunkPos) {
} }
@Override @Override
public void func_219508_a(ChunkPos chunkPos, @Nullable ChunkStatus chunkStatus) { public void statusChanged(ChunkPos chunkPos, @Nullable ChunkStatus chunkStatus) {
} }
@Override @Override
public void func_219510_b() { public void stop() {
} }
} }
} }

View File

@ -21,7 +21,7 @@ package com.sk89q.worldedit.forge;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.world.ServerWorld; import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.common.util.FakePlayer;
import javax.annotation.Nullable; import javax.annotation.Nullable;

View File

@ -22,13 +22,8 @@ package com.sk89q.worldedit.forge.net.handler;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.forge.ForgePlayer; import com.sk89q.worldedit.forge.ForgePlayer;
import com.sk89q.worldedit.forge.ForgeWorldEdit; import com.sk89q.worldedit.forge.ForgeWorldEdit;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.ServerPlayerEntity; 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.ClientCustomPayloadEvent;
import net.minecraftforge.fml.network.NetworkEvent.ServerCustomPayloadEvent;
import net.minecraftforge.fml.network.event.EventNetworkChannel; import net.minecraftforge.fml.network.event.EventNetworkChannel;
import java.nio.charset.Charset; import java.nio.charset.Charset;
@ -47,10 +42,9 @@ public final class WECUIPacketHandler {
public static void init() { public static void init() {
HANDLER.addListener(WECUIPacketHandler::onPacketData); 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(); ServerPlayerEntity player = event.getSource().get().getSender();
LocalSession session = ForgeWorldEdit.inst.getSession(player); LocalSession session = ForgeWorldEdit.inst.getSession(player);
@ -64,14 +58,4 @@ public final class WECUIPacketHandler {
session.describeCUI(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) {
}
}
} }

9
worldedit-libs/README.md Normal file
View File

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

View File

@ -1,143 +0,0 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
/*
This project shades <em>API</em> libraries, i.e. those libraries
whose classes are publicly referenced from `-core` classes.
This project <em>does not</em> 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") })
}

View File

@ -0,0 +1,3 @@
tasks.register("build") {
dependsOn(subprojects.map { it.tasks.named("build") })
}

View File

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

View File

@ -0,0 +1,6 @@
applyLibrariesConfiguration()
dependencies {
"shade"("org.enginehub.piston.core-ap:annotations:${Versions.PISTON}")
"shade"("org.enginehub.piston.core-ap:processor:${Versions.PISTON}")
}

View File

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

View File

@ -0,0 +1 @@
applyLibrariesConfiguration()

View File

@ -0,0 +1 @@
applyLibrariesConfiguration()

View File

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

View File

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

View File

@ -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>("jar") {
manifest {
attributes("Class-Path" to "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar",
"WorldEdit-Version" to project.version)
}
}
tasks.named<ShadowJar>("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<SigningExtension> {
sign("shadowJar")
}
tasks.named("build").configure {
dependsOn("signShadowJar")
}
}

View File

@ -38,6 +38,7 @@ import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.gamemode.GameModes;
import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.item.ItemTypes;
import org.spongepowered.api.Sponge; import org.spongepowered.api.Sponge;
import org.spongepowered.api.data.key.Keys;
import org.spongepowered.api.data.type.HandTypes; import org.spongepowered.api.data.type.HandTypes;
import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.ItemType;
@ -202,6 +203,16 @@ public class SpongePlayer extends AbstractPlayerActor {
gameMode.getId()).get()); 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 @Override
public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) { public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) {
org.spongepowered.api.world.Location<World> loc = player.getWorld().getLocation(pos.getX(), pos.getY(), pos.getZ()); org.spongepowered.api.world.Location<World> loc = player.getWorld().getLocation(pos.getX(), pos.getY(), pos.getZ());