Clean up Gradle configuration

This commit is contained in:
Octavia Togami 2024-04-29 17:29:02 -07:00
parent ada0a80faa
commit 28ca2e6b96
No known key found for this signature in database
GPG Key ID: CC364524D1983C99
85 changed files with 631 additions and 9056 deletions

View File

@ -3,26 +3,7 @@
}
repositories {
maven {
name = "PaperMC"
url = uri("https://repo.papermc.io/repository/maven-public/")
content {
includeGroupAndSubgroups("io.papermc")
}
}
maven {
name = "NeoForged Maven"
url = uri("https://maven.neoforged.net/releases")
content {
includeGroupAndSubgroups("net.neoforged")
}
}
mavenCentral()
gradlePluginPortal()
maven {
name = "Fabric"
url = uri("https://maven.fabricmc.net/")
}
maven {
name = "EngineHub Repository"
url = uri("https://maven.enginehub.org/repo/")
@ -36,11 +17,8 @@
implementation(libs.japicmp)
implementation(libs.shadow)
implementation(libs.jfrog.buildinfo)
implementation(libs.neoGradle.userdev)
implementation(libs.fabric.loom)
implementation(libs.fabric.mixin)
implementation(libs.codecov)
implementation(libs.paperweight)
implementation(libs.gson)
constraints {
val asmVersion = "[${libs.versions.minimumAsm.get()},)"
implementation("org.ow2.asm:asm:$asmVersion") {

View File

@ -0,0 +1,26 @@
import buildlogic.stringyLibs
import buildlogic.getVersion
plugins {
`java-library`
id("buildlogic.common")
id("buildlogic.common-java")
id("io.papermc.paperweight.userdev")
}
configure<buildlogic.CommonJavaExtension> {
banSlf4j = false
}
dependencies {
"implementation"(project(":worldedit-bukkit"))
constraints {
"remapper"("net.fabricmc:tiny-remapper:[${stringyLibs.getVersion("minimumTinyRemapper")},)") {
because("Need remapper to support Java 21")
}
}
}
tasks.named("assemble") {
dependsOn("reobfJar")
}

View File

@ -0,0 +1,35 @@
import org.gradle.api.Project
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
plugins {
id("com.jfrog.artifactory")
}
val ARTIFACTORY_CONTEXT_URL = "artifactory_contextUrl"
val ARTIFACTORY_USER = "artifactory_user"
val ARTIFACTORY_PASSWORD = "artifactory_password"
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] = ""
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
}

View File

@ -0,0 +1,10 @@
plugins {
id("com.jfrog.artifactory")
}
// Artifactory eagerly evaluates publications, so this must run after all changes to artifacts are done
afterEvaluate {
tasks.named<org.jfrog.gradle.plugin.artifactory.task.ArtifactoryTask>("artifactoryPublish") {
publications("maven")
}
}

View File

@ -0,0 +1,82 @@
import buildlogic.stringyLibs
import buildlogic.getLibrary
plugins {
id("eclipse")
id("idea")
id("checkstyle")
id("buildlogic.common")
}
val commonJava = extensions.create<buildlogic.CommonJavaExtension>("commonJava")
commonJava.banSlf4j.convention(true)
tasks
.withType<JavaCompile>()
.matching { it.name == "compileJava" || it.name == "compileTestJava" }
.configureEach {
// TODO: re-enable this-escape when ANTLR suppresses it properly
val disabledLint = listOf(
"processing", "path", "fallthrough", "serial", "overloads", "this-escape",
)
options.release.set(21)
options.compilerArgs.addAll(listOf("-Xlint:all") + disabledLint.map { "-Xlint:-$it" })
options.isDeprecation = true
options.encoding = "UTF-8"
options.compilerArgs.add("-parameters")
options.compilerArgs.add("-Werror")
}
configure<CheckstyleExtension> {
configFile = rootProject.file("config/checkstyle/checkstyle.xml")
toolVersion = "9.1"
}
tasks.withType<Test>().configureEach {
useJUnitPlatform()
}
dependencies {
"compileOnly"(stringyLibs.getLibrary("jsr305"))
"testImplementation"(platform(stringyLibs.getLibrary("junit-bom")))
"testImplementation"(stringyLibs.getLibrary("junit-jupiter-api"))
"testImplementation"(stringyLibs.getLibrary("junit-jupiter-params"))
"testImplementation"(platform(stringyLibs.getLibrary("mockito-bom")))
"testImplementation"(stringyLibs.getLibrary("mockito-core"))
"testImplementation"(stringyLibs.getLibrary("mockito-junit-jupiter"))
"testRuntimeOnly"(stringyLibs.getLibrary("junit-jupiter-engine"))
}
// Java 8 turns on doclint which we fail
tasks.withType<Javadoc>().configureEach {
options.encoding = "UTF-8"
(options as StandardJavadocDocletOptions).apply {
addBooleanOption("Werror", true)
addBooleanOption("Xdoclint:all", true)
addBooleanOption("Xdoclint:-missing", true)
tags(
"apiNote:a:API Note:",
"implSpec:a:Implementation Requirements:",
"implNote:a:Implementation Note:"
)
}
}
configure<JavaPluginExtension> {
withJavadocJar()
withSourcesJar()
}
configurations["compileClasspath"].apply {
resolutionStrategy.componentSelection {
withModule("org.slf4j:slf4j-api") {
if (commonJava.banSlf4j.get()) {
reject("No SLF4J allowed on compile classpath")
}
}
}
}
tasks.named("check").configure {
dependsOn("checkstyleMain", "checkstyleTest")
}

View File

@ -0,0 +1,68 @@
import buildlogic.getLibrary
import buildlogic.stringyLibs
import org.gradle.plugins.ide.idea.model.IdeaModel
plugins {
id("org.cadixdev.licenser")
}
group = rootProject.group
version = rootProject.version
repositories {
maven {
name = "EngineHub"
url = uri("https://maven.enginehub.org/repo/")
}
}
configurations.all {
resolutionStrategy {
cacheChangingModulesFor(1, TimeUnit.DAYS)
}
}
plugins.withId("java") {
the<JavaPluginExtension>().toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
dependencies {
for (conf in listOf("implementation", "api")) {
if (!configurations.names.contains(conf)) {
continue
}
add(conf, platform(stringyLibs.getLibrary("log4j-bom")).map {
val dep = create(it)
dep.because("Mojang provides Log4j")
dep
})
constraints {
add(conf, stringyLibs.getLibrary("guava")) {
because("Mojang provides Guava")
}
add(conf, stringyLibs.getLibrary("gson")) {
because("Mojang provides Gson")
}
add(conf, stringyLibs.getLibrary("fastutil")) {
because("Mojang provides FastUtil")
}
}
}
}
license {
header(rootProject.file("HEADER.txt"))
include("**/*.java")
include("**/*.kt")
}
plugins.withId("idea") {
configure<IdeaModel> {
module {
isDownloadSources = true
isDownloadJavadoc = true
}
}
}

View File

@ -0,0 +1,23 @@
plugins {
id("java")
id("maven-publish")
id("buildlogic.common-java")
id("buildlogic.artifactory-sub")
}
ext["internalVersion"] = "$version+${rootProject.ext["gitCommitHash"]}"
publishing {
publications {
register<MavenPublication>("maven") {
versionMapping {
usage("java-api") {
fromResolutionOf("runtimeClasspath")
}
usage("java-runtime") {
fromResolutionResult()
}
}
}
}
}

View File

@ -0,0 +1,180 @@
plugins {
id("java-base")
id("maven-publish")
id("com.github.johnrengelman.shadow")
id("com.jfrog.artifactory")
id("buildlogic.common")
id("buildlogic.artifactory-sub")
}
// A horrible hack because `softwareComponentFactory` has to be gotten via plugin
// gradle why
internal open class LibsConfigPluginHack @Inject constructor(
private val softwareComponentFactory: SoftwareComponentFactory
) : Plugin<Project> {
override fun apply(project: Project) {
val libsComponents = softwareComponentFactory.adhoc("libs")
project.components.add(libsComponents)
}
}
configurations {
create("shade")
}
group = "${rootProject.group}.worldedit-libs"
val relocations = mapOf(
"net.kyori.text" to "com.sk89q.worldedit.util.formatting.text",
"net.kyori.minecraft" to "com.sk89q.worldedit.util.kyori",
)
tasks.register<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("jar") {
configurations = listOf(project.configurations["shade"])
archiveClassifier.set("")
// Yeet module-info's
exclude("module-info.class")
dependencies {
exclude(dependency("com.google.guava:guava"))
exclude(dependency("com.google.code.gson:gson"))
exclude(dependency("com.google.errorprone:error_prone_annotations"))
exclude(dependency("com.google.guava:failureaccess"))
exclude(dependency("org.checkerframework:checker-qual"))
exclude(dependency("org.jetbrains:annotations"))
exclude(dependency("org.apache.logging.log4j:log4j-api"))
exclude(dependency("com.google.code.findbugs:jsr305"))
exclude {
it.moduleGroup == "org.jetbrains.kotlin"
}
}
relocations.forEach { (from, to) ->
relocate(from, to)
}
}
val altConfigFiles = { artifactType: String ->
val deps = configurations["shade"].incoming.dependencies
.filterIsInstance<ModuleDependency>()
.map { it.copy() }
.map { dependency ->
val category = dependency.attributes.getAttribute(Category.CATEGORY_ATTRIBUTE)?.name
if (category == Category.REGULAR_PLATFORM || category == Category.ENFORCED_PLATFORM) {
return@map dependency
}
try {
dependency.artifact {
name = dependency.name
type = artifactType
extension = "jar"
classifier = artifactType
}
} catch (e: Exception) {
throw RuntimeException("Failed to add artifact to dependency: $dependency", e)
}
dependency
}
files(configurations.detachedConfiguration(*deps.toTypedArray())
.resolvedConfiguration.lenientConfiguration.artifacts
.filter { it.classifier == artifactType }
.map { zipTree(it.file) })
}
tasks.register<Jar>("sourcesJar") {
from({
altConfigFiles("sources")
})
// Yeet module-info's
exclude("module-info.java")
relocations.forEach { (from, to) ->
val filePattern = Regex("(.*)${from.replace('.', '/')}((?:/|$).*)")
val textPattern = Regex.fromLiteral(from)
eachFile {
filter {
it.replaceFirst(textPattern, to)
}
path = path.replaceFirst(filePattern, "$1${to.replace('.', '/')}$2")
}
}
archiveClassifier.set("sources")
}
tasks.named("assemble").configure {
dependsOn("jar", "sourcesJar")
}
project.apply<LibsConfigPluginHack>()
val libsComponent = project.components["libs"] as AdhocComponentWithVariants
val apiElements = project.configurations.register("apiElements") {
isVisible = false
description = "API elements for libs"
isCanBeResolved = false
isCanBeConsumed = true
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_API))
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY))
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR))
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 16)
}
outgoing.artifact(tasks.named("jar"))
}
val runtimeElements = project.configurations.register("runtimeElements") {
isVisible = false
description = "Runtime elements for libs"
isCanBeResolved = false
isCanBeConsumed = true
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY))
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR))
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 16)
}
outgoing.artifact(tasks.named("jar"))
}
val sourcesElements = project.configurations.register("sourcesElements") {
isVisible = false
description = "Source elements for libs"
isCanBeResolved = false
isCanBeConsumed = true
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.DOCUMENTATION))
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED))
attribute(DocsType.DOCS_TYPE_ATTRIBUTE, project.objects.named(DocsType.SOURCES))
}
outgoing.artifact(tasks.named("sourcesJar"))
}
libsComponent.addVariantsFromConfiguration(apiElements.get()) {
mapToMavenScope("compile")
}
libsComponent.addVariantsFromConfiguration(runtimeElements.get()) {
mapToMavenScope("runtime")
}
libsComponent.addVariantsFromConfiguration(sourcesElements.get()) {
mapToMavenScope("runtime")
}
configure<PublishingExtension> {
publications {
register<MavenPublication>("maven") {
from(libsComponent)
}
}
}
if (project != project(":worldedit-libs:core")) {
evaluationDependsOn(":worldedit-libs:core")
configurations["shade"].shouldResolveConsistentlyWith(project(":worldedit-libs:core").configurations["shade"])
}

View File

@ -0,0 +1,53 @@
plugins {
id("com.github.johnrengelman.shadow")
id("buildlogic.core-and-platform")
}
val platform = extensions.create<buildlogic.PlatformExtension>("platform")
platform.includeClasspath.convention(false)
platform.extraAttributes.convention(mapOf())
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
archiveClassifier.set("dist")
dependencies {
include(project(":worldedit-libs:core"))
include(project(":worldedit-libs:${project.name.replace("worldedit-", "")}"))
include(project(":worldedit-core"))
exclude("com.google.code.findbugs:jsr305")
}
exclude("GradleStart**")
exclude(".cache")
exclude("LICENSE*")
exclude("META-INF/maven/**")
minimize()
}
val javaComponent = components["java"] as AdhocComponentWithVariants
// I don't think we want this published (it's the shadow jar)
javaComponent.withVariantsFromConfiguration(configurations["shadowRuntimeElements"]) {
skip()
}
afterEvaluate {
tasks.named<Jar>("jar") {
val kind = platform.kind.get()
val includeClasspath = platform.includeClasspath.get()
val extraAttributes = platform.extraAttributes.get()
val version = project(":worldedit-core").version
inputs.property("version", version)
val attributes = mutableMapOf(
"Implementation-Version" to version,
"WorldEdit-Version" to version,
"WorldEdit-Kind" to kind.name,
"Main-Class" to kind.mainClass
)
if (includeClasspath) {
attributes["Class-Path"] = listOf("truezip", "truevfs", "js")
.map { "$it.jar" }
.flatMap { listOf(it, "WorldEdit/$it") }
.joinToString(separator = " ")
}
attributes.putAll(extraAttributes)
manifest.attributes(attributes)
}
}

View File

@ -0,0 +1,7 @@
package buildlogic
import org.gradle.api.provider.Property
interface CommonJavaExtension {
val banSlf4j: Property<Boolean>
}

View File

@ -1,3 +1,5 @@
package buildlogic
import org.gradle.api.Project
import org.gradle.api.artifacts.MinimalExternalModuleDependency
import org.gradle.api.artifacts.VersionCatalog

View File

@ -0,0 +1,19 @@
package buildlogic
import org.gradle.api.provider.MapProperty
import org.gradle.api.provider.Property
interface PlatformExtension {
val kind: Property<WorldEditKind>
val includeClasspath: Property<Boolean>
val extraAttributes: MapProperty<String, String>
}
sealed class WorldEditKind(
val name: String,
val mainClass: String = "com.sk89q.worldedit.internal.util.InfoEntryPoint"
) {
class Standalone(mainClass: String) : WorldEditKind("STANDALONE", mainClass)
object Mod : WorldEditKind("MOD")
object Plugin : WorldEditKind("PLUGIN")
}

View File

@ -1,21 +1,25 @@
import org.ajoberstar.grgit.Grgit
// needed for fabric to know where FF executor is....
buildscript {
repositories {
mavenCentral()
maven {
name = "EngineHub"
url = uri("https://maven.enginehub.org/repo/")
}
maven {
name = "Fabric"
url = uri("https://maven.fabricmc.net/")
}
}
dependencies {
classpath(libs.fabric.loom)
// needed for fabric to know where FF executor is....
}
}
plugins {
id("org.enginehub.codecov")
alias(libs.plugins.codecov)
jacoco
id("buildlogic.common")
id("buildlogic.artifactory-root")
}
if (!project.hasProperty("gitCommitHash")) {
@ -29,23 +33,6 @@
}
}
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
*******************************************
""")
applyCommonConfiguration()
applyRootArtifactoryConfig()
val totalReport = tasks.register<JacocoReport>("jacocoTotalReport") {
for (proj in subprojects) {
proj.apply(plugin = "jacoco")

View File

@ -1,29 +0,0 @@
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.dependencies
// For specific version pinning, see
// https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/
fun Project.applyPaperweightAdapterConfiguration(javaRelease: Int = 21) {
applyCommonConfiguration()
apply(plugin = "java-library")
applyCommonJavaConfiguration(
sourcesJar = true,
javaRelease = javaRelease,
banSlf4j = false,
)
apply(plugin = "io.papermc.paperweight.userdev")
dependencies {
"implementation"(project(":worldedit-bukkit"))
constraints {
"remapper"("net.fabricmc:tiny-remapper:[${stringyLibs.getVersion("minimumTinyRemapper")},)") {
because("Need remapper to support Java 21")
}
}
}
tasks.named("assemble") {
dependsOn("reobfJar")
}
}

View File

@ -1,43 +0,0 @@
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() {
// Artifactory eagerly evaluates publications, so this must run after all changes to artifacts are done
afterEvaluate {
tasks.named<ArtifactoryTask>("artifactoryPublish") {
publications("maven")
}
}
}

View File

@ -1,82 +0,0 @@
import groovy.lang.Closure
import org.cadixdev.gradle.licenser.LicenseExtension
import org.gradle.api.Project
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ExternalModuleDependency
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.kotlin.dsl.*
import org.gradle.plugins.ide.idea.model.IdeaModel
import java.util.concurrent.TimeUnit
fun Project.applyCommonConfiguration() {
group = rootProject.group
version = rootProject.version
repositories {
mavenCentral {
mavenContent {
releasesOnly()
}
}
maven { url = uri("https://maven.enginehub.org/repo/") }
maven {
url = uri("https://oss.sonatype.org/content/repositories/snapshots/")
mavenContent {
snapshotsOnly()
}
}
}
configurations.all {
resolutionStrategy {
cacheChangingModulesFor(1, TimeUnit.DAYS)
}
}
plugins.withId("java") {
the<JavaPluginExtension>().toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
dependencies {
for (conf in listOf("implementation", "api")) {
if (!configurations.names.contains(conf)) {
continue
}
add(conf, platform(stringyLibs.getLibrary("log4j-bom")).map {
val dep = create(it)
dep.because("Mojang provides Log4j")
dep
})
constraints {
add(conf, stringyLibs.getLibrary("guava")) {
because("Mojang provides Guava")
}
add(conf, stringyLibs.getLibrary("gson")) {
because("Mojang provides Gson")
}
add(conf, stringyLibs.getLibrary("fastutil")) {
because("Mojang provides FastUtil")
}
}
}
}
apply(plugin = "org.cadixdev.licenser")
configure<LicenseExtension> {
header(rootProject.file("HEADER.txt"))
include("**/*.java")
include("**/*.kt")
}
plugins.withId("idea") {
configure<IdeaModel> {
module {
isDownloadSources = true
isDownloadJavadoc = true
}
}
}
}

View File

@ -1,91 +0,0 @@
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.plugins.quality.CheckstyleExtension
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.api.tasks.testing.Test
import org.gradle.external.javadoc.StandardJavadocDocletOptions
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.withType
fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, javaRelease: Int = 17, banSlf4j: Boolean = true) {
applyCommonConfiguration()
apply(plugin = "eclipse")
apply(plugin = "idea")
apply(plugin = "checkstyle")
tasks
.withType<JavaCompile>()
.matching { it.name == "compileJava" || it.name == "compileTestJava" }
.configureEach {
// TODO: re-enable this-escape when ANTLR suppresses it properly
val disabledLint = listOf(
"processing", "path", "fallthrough", "serial", "overloads", "this-escape",
)
options.release.set(javaRelease)
options.compilerArgs.addAll(listOf("-Xlint:all") + disabledLint.map { "-Xlint:-$it" })
options.isDeprecation = true
options.encoding = "UTF-8"
options.compilerArgs.add("-parameters")
options.compilerArgs.add("-Werror")
}
configure<CheckstyleExtension> {
configFile = rootProject.file("config/checkstyle/checkstyle.xml")
toolVersion = "9.1"
}
tasks.withType<Test>().configureEach {
useJUnitPlatform()
}
dependencies {
"compileOnly"(stringyLibs.getLibrary("jsr305"))
"testImplementation"(platform(stringyLibs.getLibrary("junit-bom")))
"testImplementation"(stringyLibs.getLibrary("junit-jupiter-api"))
"testImplementation"(stringyLibs.getLibrary("junit-jupiter-params"))
"testImplementation"(platform(stringyLibs.getLibrary("mockito-bom")))
"testImplementation"(stringyLibs.getLibrary("mockito-core"))
"testImplementation"(stringyLibs.getLibrary("mockito-junit-jupiter"))
"testRuntimeOnly"(stringyLibs.getLibrary("junit-jupiter-engine"))
}
// Java 8 turns on doclint which we fail
tasks.withType<Javadoc>().configureEach {
options.encoding = "UTF-8"
(options as StandardJavadocDocletOptions).apply {
addBooleanOption("Werror", true)
addBooleanOption("Xdoclint:all", true)
addBooleanOption("Xdoclint:-missing", true)
tags(
"apiNote:a:API Note:",
"implSpec:a:Implementation Requirements:",
"implNote:a:Implementation Note:"
)
}
}
configure<JavaPluginExtension> {
withJavadocJar()
if (sourcesJar) {
withSourcesJar()
}
}
if (banSlf4j) {
configurations["compileClasspath"].apply {
resolutionStrategy.componentSelection {
withModule("org.slf4j:slf4j-api") {
reject("No SLF4J allowed on compile classpath")
}
}
}
}
tasks.named("check").configure {
dependsOn("checkstyleMain", "checkstyleTest")
}
}

View File

@ -1,214 +0,0 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.ExternalModuleDependency
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.attributes.Bundling
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.DocsType
import org.gradle.api.attributes.LibraryElements
import org.gradle.api.attributes.Usage
import org.gradle.api.attributes.java.TargetJvmVersion
import org.gradle.api.component.AdhocComponentWithVariants
import org.gradle.api.component.SoftwareComponentFactory
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.bundling.Jar
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.exclude
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.invoke
import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.register
import javax.inject.Inject
fun Project.applyLibrariesConfiguration() {
applyCommonConfiguration()
apply(plugin = "java-base")
apply(plugin = "maven-publish")
apply(plugin = "com.github.johnrengelman.shadow")
apply(plugin = "com.jfrog.artifactory")
configurations {
create("shade")
}
group = "${rootProject.group}.worldedit-libs"
val relocations = mapOf(
"net.kyori.text" to "com.sk89q.worldedit.util.formatting.text",
"net.kyori.minecraft" to "com.sk89q.worldedit.util.kyori",
)
tasks.register<ShadowJar>("jar") {
configurations = listOf(project.configurations["shade"])
archiveClassifier.set("")
// Yeet module-info's
exclude("module-info.class")
dependencies {
exclude(dependency("com.google.guava:guava"))
exclude(dependency("com.google.code.gson:gson"))
exclude(dependency("com.google.errorprone:error_prone_annotations"))
exclude(dependency("com.google.guava:failureaccess"))
exclude(dependency("org.checkerframework:checker-qual"))
exclude(dependency("org.jetbrains:annotations"))
exclude(dependency("org.apache.logging.log4j:log4j-api"))
exclude(dependency("com.google.code.findbugs:jsr305"))
exclude {
it.moduleGroup == "org.jetbrains.kotlin"
}
}
relocations.forEach { (from, to) ->
relocate(from, to)
}
}
val altConfigFiles = { artifactType: String ->
val deps = configurations["shade"].incoming.dependencies
.filterIsInstance<ModuleDependency>()
.map { it.copy() }
.map { dependency ->
val category = dependency.attributes.getAttribute(Category.CATEGORY_ATTRIBUTE)?.name
if (category == Category.REGULAR_PLATFORM || category == Category.ENFORCED_PLATFORM) {
return@map dependency
}
try {
dependency.artifact {
name = dependency.name
type = artifactType
extension = "jar"
classifier = artifactType
}
} catch (e: Exception) {
throw RuntimeException("Failed to add artifact to dependency: $dependency", e)
}
dependency
}
files(configurations.detachedConfiguration(*deps.toTypedArray())
.resolvedConfiguration.lenientConfiguration.artifacts
.filter { it.classifier == artifactType }
.map { zipTree(it.file) })
}
tasks.register<Jar>("sourcesJar") {
from({
altConfigFiles("sources")
})
// Yeet module-info's
exclude("module-info.java")
relocations.forEach { (from, to) ->
val filePattern = Regex("(.*)${from.replace('.', '/')}((?:/|$).*)")
val textPattern = Regex.fromLiteral(from)
eachFile {
filter {
it.replaceFirst(textPattern, to)
}
path = path.replaceFirst(filePattern, "$1${to.replace('.', '/')}$2")
}
}
archiveClassifier.set("sources")
}
tasks.named("assemble").configure {
dependsOn("jar", "sourcesJar")
}
project.apply<LibsConfigPluginHack>()
val libsComponent = project.components["libs"] as AdhocComponentWithVariants
val apiElements = project.configurations.register("apiElements") {
isVisible = false
description = "API elements for libs"
isCanBeResolved = false
isCanBeConsumed = true
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_API))
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY))
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR))
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 16)
}
outgoing.artifact(tasks.named("jar"))
}
val runtimeElements = project.configurations.register("runtimeElements") {
isVisible = false
description = "Runtime elements for libs"
isCanBeResolved = false
isCanBeConsumed = true
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY))
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR))
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 16)
}
outgoing.artifact(tasks.named("jar"))
}
val sourcesElements = project.configurations.register("sourcesElements") {
isVisible = false
description = "Source elements for libs"
isCanBeResolved = false
isCanBeConsumed = true
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.DOCUMENTATION))
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED))
attribute(DocsType.DOCS_TYPE_ATTRIBUTE, project.objects.named(DocsType.SOURCES))
}
outgoing.artifact(tasks.named("sourcesJar"))
}
libsComponent.addVariantsFromConfiguration(apiElements.get()) {
mapToMavenScope("compile")
}
libsComponent.addVariantsFromConfiguration(runtimeElements.get()) {
mapToMavenScope("runtime")
}
libsComponent.addVariantsFromConfiguration(sourcesElements.get()) {
mapToMavenScope("runtime")
}
configure<PublishingExtension> {
publications {
register<MavenPublication>("maven") {
from(libsComponent)
}
}
}
applyCommonArtifactoryConfig()
}
// A horrible hack because `softwareComponentFactory` has to be gotten via plugin
// gradle why
internal open class LibsConfigPluginHack @Inject constructor(
private val softwareComponentFactory: SoftwareComponentFactory
) : Plugin<Project> {
override fun apply(project: Project) {
val libsComponents = softwareComponentFactory.adhoc("libs")
project.components.add(libsComponents)
}
}
fun Project.constrainDependenciesToLibsCore() {
evaluationDependsOn(":worldedit-libs:core")
val coreDeps = project(":worldedit-libs:core").configurations["shade"].dependencies
.filterIsInstance<ExternalModuleDependency>()
dependencies.constraints {
for (coreDep in coreDeps) {
add("shade", "${coreDep.group}:${coreDep.name}:${coreDep.version}") {
because("libs should align with libs:core")
}
}
}
}

View File

@ -1,98 +0,0 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.Project
import org.gradle.api.component.AdhocComponentWithVariants
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.bundling.Jar
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.register
import kotlin.collections.set
fun Project.applyPlatformAndCoreConfiguration(javaRelease: Int = 21) {
applyCommonConfiguration()
apply(plugin = "java")
apply(plugin = "maven-publish")
apply(plugin = "com.jfrog.artifactory")
applyCommonJavaConfiguration(
sourcesJar = name in setOf("worldedit-core", "worldedit-bukkit", "worldedit-fabric"),
javaRelease = javaRelease,
banSlf4j = name !in setOf("worldedit-fabric", "worldedit-neoforge", "worldedit-sponge"),
)
ext["internalVersion"] = "$version+${rootProject.ext["gitCommitHash"]}"
configure<PublishingExtension> {
publications {
register<MavenPublication>("maven") {
versionMapping {
usage("java-api") {
fromResolutionOf("runtimeClasspath")
}
usage("java-runtime") {
fromResolutionResult()
}
}
}
}
}
applyCommonArtifactoryConfig()
}
fun Project.applyShadowConfiguration() {
apply(plugin = "com.github.johnrengelman.shadow")
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("com.google.code.findbugs:jsr305")
}
exclude("GradleStart**")
exclude(".cache")
exclude("LICENSE*")
exclude("META-INF/maven/**")
minimize()
}
val javaComponent = components["java"] as AdhocComponentWithVariants
// I don't think we want this published (it's the shadow jar)
javaComponent.withVariantsFromConfiguration(configurations["shadowRuntimeElements"]) {
skip()
}
}
private val CLASSPATH = listOf("truezip", "truevfs", "js")
.map { "$it.jar" }
.flatMap { listOf(it, "WorldEdit/$it") }
.joinToString(separator = " ")
sealed class WorldEditKind(
val name: String,
val mainClass: String = "com.sk89q.worldedit.internal.util.InfoEntryPoint"
) {
class Standalone(mainClass: String) : WorldEditKind("STANDALONE", mainClass)
object Mod : WorldEditKind("MOD")
object Plugin : WorldEditKind("PLUGIN")
}
fun Project.addJarManifest(kind: WorldEditKind, includeClasspath: Boolean = false, extraAttributes: Map<String, String> = mapOf()) {
tasks.named<Jar>("jar") {
val version = project(":worldedit-core").version
inputs.property("version", version)
val attributes = mutableMapOf(
"Implementation-Version" to version,
"WorldEdit-Version" to version,
"WorldEdit-Kind" to kind.name,
"Main-Class" to kind.mainClass
)
if (includeClasspath) {
attributes["Class-Path"] = CLASSPATH
}
attributes.putAll(extraAttributes)
manifest.attributes(attributes)
}
}

View File

@ -1,6 +1,9 @@
[versions]
neoGradle = "7.0.107"
[plugins]
codecov = "org.enginehub.codecov:0.2.0"
neogradle-userdev = "net.neoforged.gradle.userdev:7.0.107"
fabric-loom = "fabric-loom:1.6.9"
[versions]
kyoriText = "3.0.4"
piston = "0.5.10"
autoValue = "1.10.4"
@ -29,10 +32,8 @@ japicmp = "me.champeau.gradle:japicmp-gradle-plugin:0.4.2"
shadow = "com.github.johnrengelman:shadow:8.1.1"
jfrog-buildinfo = "org.jfrog.buildinfo:build-info-extractor-gradle:5.2.0"
fabric-loom = "net.fabricmc:fabric-loom:1.6.9"
fabric-mixin = "net.fabricmc:sponge-mixin:0.13.3+mixin.0.8.5"
codecov = "org.enginehub.gradle:gradle-codecov-plugin:0.2.0"
paperweight = "io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.6.0"
linBus-bom = "org.enginehub.lin-bus:lin-bus-bom:0.1.0-SNAPSHOT"
@ -89,10 +90,6 @@ fastutil = "it.unimi.dsi:fastutil:8.5.12!!"
# may not be the same as the ones in the latest Bukkit API.
snakeyaml = "org.yaml:snakeyaml:2.0"
[libraries.neoGradle-userdev]
module = "net.neoforged.gradle:userdev"
version.ref = "neoGradle"
[libraries.kyoriText-api]
module = "net.kyori:text-api"
version.ref = "kyoriText"

View File

@ -1,10 +1,9 @@
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
maven {
name = "Fabric"
url = uri("https://maven.fabricmc.net/")
name = "EngineHub"
url = uri("https://maven.enginehub.org/repo/")
}
}
}
@ -12,8 +11,24 @@
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}
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
*******************************************
""")
rootProject.name = "worldedit"
includeBuild("build-logic")
include("worldedit-libs")
listOf("1.19.4", "1.20", "1.20.2", "1.20.4", "1.20.5").forEach {

View File

@ -74,6 +74,19 @@
(this as? ModuleDependency)?.isTransitive = false
}
)
val resolvedOldJar = files({
try {
conf.resolvedConfiguration.rethrowFailure()
conf
} catch (e: ResolveException) {
if (e.cause is ModuleVersionNotFoundException) {
logger.warn("Skipping check for $projectFragment API compatibility because there is no jar to compare against")
setOf<File>()
} else {
throw e
}
}
})
val checkApi = tasks.register<JapicmpTask>("check${capitalizedFragment}ApiCompatibility") {
group = "API Compatibility"
description = "Check API compatibility for $capitalizedFragment API"
@ -89,20 +102,10 @@
onlyIf {
// Only check if we have a jar to compare against
try {
conf.resolvedConfiguration.rethrowFailure()
true
} catch (e: ResolveException) {
if (e.cause is ModuleVersionNotFoundException) {
it.logger.warn("Skipping check for $projectFragment API compatibility because there is no jar to compare against")
false
} else {
throw e
}
}
!resolvedOldJar.isEmpty
}
oldClasspath.from(conf)
oldClasspath.from(resolvedOldJar)
newClasspath.from(proj.tasks.named("jar"))
onlyModified.set(false)
failOnModification.set(false) // report does the failing (so we can accept)

View File

@ -1,8 +0,0 @@
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
applyPaperweightAdapterConfiguration()
dependencies {
// https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.18.2-R0.1-20220920.010157-167")
}

View File

@ -1,98 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.bukkit.adapter.impl.v1_18_R2;
import com.mojang.authlib.GameProfile;
import net.minecraft.network.chat.ChatType;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ServerboundClientInformationPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.Stat;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.entity.SignBlockEntity;
import net.minecraft.world.phys.Vec3;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import java.util.OptionalInt;
import java.util.UUID;
class PaperweightFakePlayer extends ServerPlayer {
private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]");
private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D);
PaperweightFakePlayer(ServerLevel world) {
super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE);
}
@Override
public Vec3 position() {
return ORIGIN;
}
@Override
public void tick() {
}
@Override
public void die(DamageSource damagesource) {
}
@Override
public Entity changeDimension(ServerLevel worldserver, TeleportCause cause) {
return this;
}
@Override
public OptionalInt openMenu(MenuProvider factory) {
return OptionalInt.empty();
}
@Override
public void updateOptions(ServerboundClientInformationPacket packet) {
}
@Override
public void displayClientMessage(Component message, boolean actionBar) {
}
@Override
public void sendMessage(Component message, ChatType type, UUID sender) {
}
@Override
public void awardStat(Stat<?> stat, int amount) {
}
@Override
public void awardStat(Stat<?> stat) {
}
@Override
public boolean isInvulnerableTo(DamageSource damageSource) {
return true;
}
@Override
public void openTextEdit(SignBlockEntity sign) {
}
}

View File

@ -1,189 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.bukkit.adapter.impl.v1_18_R2;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import java.lang.ref.WeakReference;
import java.util.Objects;
import javax.annotation.Nullable;
public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
private static final int UPDATE = 1;
private static final int NOTIFY = 2;
private final PaperweightAdapter adapter;
private final WeakReference<ServerLevel> world;
private SideEffectSet sideEffectSet;
public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference<ServerLevel> world) {
this.adapter = adapter;
this.world = world;
}
private ServerLevel getWorld() {
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
}
@Override
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
this.sideEffectSet = sideEffectSet;
}
@Override
public LevelChunk getChunk(int x, int z) {
return getWorld().getChunk(x, z);
}
@Override
public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.stateById(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
}
@Override
public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) {
return chunk.getBlockState(position);
}
@Nullable
@Override
public net.minecraft.world.level.block.state.BlockState setBlockState(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState state) {
return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE));
}
@Override
public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(net.minecraft.world.level.block.state.BlockState block, BlockPos position) {
return Block.updateFromNeighbourShapes(block, getWorld(), position);
}
@Override
public BlockPos getPosition(int x, int y, int z) {
return new BlockPos(x, y, z);
}
@Override
public void updateLightingForBlock(BlockPos position) {
getWorld().getChunkSource().getLightEngine().checkBlock(position);
}
@Override
public boolean updateTileEntity(BlockPos position, LinCompoundTag tag) {
// We will assume that the tile entity was created for us
BlockEntity tileEntity = getWorld().getBlockEntity(position);
if (tileEntity == null) {
return false;
}
Tag nativeTag = adapter.fromNative(tag);
PaperweightAdapter.readTagIntoTileEntity((CompoundTag) nativeTag, tileEntity);
return true;
}
@Override
public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) {
getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY);
}
}
@Override
public boolean isChunkTicking(LevelChunk chunk) {
return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING);
}
@Override
public void markBlockChanged(LevelChunk chunk, BlockPos position) {
if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) {
getWorld().getChunkSource().blockChanged(position);
}
}
@Override
public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
world.updateNeighborsAt(pos, oldState.getBlock());
} else {
// When we don't want events, manually run the physics without them.
Block block = oldState.getBlock();
fireNeighborChanged(pos, world, block, pos.west());
fireNeighborChanged(pos, world, block, pos.east());
fireNeighborChanged(pos, world, block, pos.below());
fireNeighborChanged(pos, world, block, pos.above());
fireNeighborChanged(pos, world, block, pos.north());
fireNeighborChanged(pos, world, block, pos.south());
}
if (newState.hasAnalogOutputSignal()) {
world.updateNeighbourForOutputSignal(pos, newState.getBlock());
}
}
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
newState.onPlace(world, pos, oldState, false);
}
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false);
}
@Override
public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) {
ServerLevel world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld();
BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
world.getCraftServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
}
newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit);
newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
}
@Override
public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
getWorld().onBlockStateChange(pos, oldState, newState);
}
}

View File

@ -1,6 +1,8 @@
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
applyPaperweightAdapterConfiguration()
plugins {
id("buildlogic.adapter")
}
dependencies {
// https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/

View File

@ -1,6 +1,8 @@
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
applyPaperweightAdapterConfiguration()
plugins {
id("buildlogic.adapter")
}
dependencies {
// https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/

View File

@ -1,6 +1,8 @@
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
applyPaperweightAdapterConfiguration()
plugins {
id("buildlogic.adapter")
}
dependencies {
// https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/

View File

@ -1,6 +1,8 @@
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
applyPaperweightAdapterConfiguration()
plugins {
id("buildlogic.adapter")
}
dependencies {
// https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/

View File

@ -1,6 +1,8 @@
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
applyPaperweightAdapterConfiguration()
plugins {
id("buildlogic.adapter")
}
dependencies {
// https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/

View File

@ -3,14 +3,19 @@
plugins {
`java-library`
id("buildlogic.platform")
}
applyPlatformAndCoreConfiguration()
applyShadowConfiguration()
platform {
kind = buildlogic.WorldEditKind.Plugin
includeClasspath = true
}
repositories {
maven { url = uri("https://hub.spigotmc.org/nexus/content/groups/public") }
maven { url = uri("https://repo.papermc.io/repository/maven-public/") }
maven {
name = "Spigot"
url = uri("https://hub.spigotmc.org/nexus/content/groups/public")
}
}
val localImplementation = configurations.create("localImplementation") {
@ -79,8 +84,6 @@
}
}
addJarManifest(WorldEditKind.Plugin, includeClasspath = true)
tasks.named<ShadowJar>("shadowJar") {
configurations.add(adapters)
dependencies {

View File

@ -2,17 +2,16 @@
plugins {
`java-library`
id("buildlogic.platform")
}
applyPlatformAndCoreConfiguration()
applyShadowConfiguration()
addJarManifest(
WorldEditKind.Standalone("com.sk89q.worldedit.cli.CLIWorldEdit"),
platform {
kind = buildlogic.WorldEditKind.Standalone("com.sk89q.worldedit.cli.CLIWorldEdit")
extraAttributes = mapOf(
// We don't have any multi-release stuff, but Log4J does.
"Multi-Release" to "true",
),
)
)
}
dependencies {
"compileOnly"(project(":worldedit-libs:core:ap"))

View File

@ -4,10 +4,9 @@
plugins {
`java-library`
antlr
id("buildlogic.core-and-platform")
}
applyPlatformAndCoreConfiguration()
repositories {
ivy {
url = uri("https://repo.enginehub.org/language-files/")

View File

@ -1,10 +1,9 @@
plugins {
kotlin("jvm") version "1.9.23"
application
id("buildlogic.common")
}
applyCommonConfiguration()
application.mainClass.set("com.sk89q.worldedit.internal.util.DocumentationPrinter")
tasks.named<JavaExec>("run") {
workingDir = rootProject.projectDir

View File

@ -5,12 +5,20 @@
import net.fabricmc.loom.task.RunGameTask
plugins {
id("fabric-loom")
alias(libs.plugins.fabric.loom)
`java-library`
id("buildlogic.platform")
}
applyPlatformAndCoreConfiguration()
applyShadowConfiguration()
commonJava {
// Not easy to do, because it's in a bunch of separate configurations
banSlf4j = false
}
platform {
kind = buildlogic.WorldEditKind.Mod
includeClasspath = true
}
val fabricApiConfiguration: Configuration = configurations.create("fabricApi")
@ -24,12 +32,12 @@
repositories {
maven {
name = "Fabric"
url = uri("https://maven.fabricmc.net/")
name = "EngineHub"
url = uri("https://maven.enginehub.org/repo/")
}
getByName("Mojang") {
content {
includeGroupByRegex("com\\.mojang\\..*")
includeGroupAndSubgroups("com.mojang")
}
}
}
@ -60,11 +68,6 @@
// No need for this at runtime
"modCompileOnly"(libs.fabric.permissions.api)
// Hook these up manually, because Fabric doesn't seem to quite do it properly.
"compileOnly"(libs.fabric.mixin)
"annotationProcessor"(libs.fabric.mixin)
"annotationProcessor"(libs.fabric.loom)
// Silence some warnings, since apparently this isn't on the compile classpath like it should be.
"compileOnly"(libs.errorprone.annotations)
}
@ -88,8 +91,6 @@
}
}
addJarManifest(WorldEditKind.Mod, includeClasspath = true)
tasks.named<ShadowJar>("shadowJar") {
archiveClassifier.set("dist-dev")
dependencies {

View File

@ -1,11 +1,5 @@
applyLibrariesConfiguration()
constrainDependenciesToLibsCore()
repositories {
maven {
name = "SpigotMC"
url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
}
plugins {
id("buildlogic.libs")
}
dependencies {

View File

@ -1 +1,3 @@
applyLibrariesConfiguration()
plugins {
id("buildlogic.libs")
}

View File

@ -1,4 +1,6 @@
applyLibrariesConfiguration()
plugins {
id("buildlogic.libs")
}
dependencies {
// These are here because they use net.kyori:text-api -- so they need to be relocated too

View File

@ -1,4 +1,6 @@
applyLibrariesConfiguration()
plugins {
id("buildlogic.libs")
}
dependencies {
"shade"(libs.kyoriText.api)

View File

@ -1 +1,3 @@
applyLibrariesConfiguration()
plugins {
id("buildlogic.libs")
}

View File

@ -1 +1,3 @@
applyLibrariesConfiguration()
plugins {
id("buildlogic.libs")
}

View File

@ -1,11 +0,0 @@
applyLibrariesConfiguration()
constrainDependenciesToLibsCore()
repositories {
maven {
name = "Sponge"
url = uri("https://repo.spongepowered.org/maven")
}
}
dependencies {
}

View File

@ -4,10 +4,10 @@
plugins {
base
id("buildlogic.common")
alias(libs.plugins.fabric.loom) apply false
}
applyCommonConfiguration()
open class MergeManifests : DefaultTask() {
@InputFiles
val inputManifests: ConfigurableFileCollection = project.objects.fileCollection()

View File

@ -2,12 +2,19 @@
import net.neoforged.gradle.dsl.common.runs.run.Run
plugins {
id("net.neoforged.gradle.userdev")
alias(libs.plugins.neogradle.userdev)
`java-library`
id("buildlogic.platform")
}
applyPlatformAndCoreConfiguration()
applyShadowConfiguration()
commonJava {
// Not easy to do, because it's in a bunch of separate configurations
banSlf4j = false
}
platform {
kind = buildlogic.WorldEditKind.Mod
}
val minecraftVersion = libs.versions.neoforge.minecraft.get()
val nextMajorMinecraftVersion: String = minecraftVersion.split('.').let { (useless, major) ->
@ -20,20 +27,16 @@
}
repositories {
val toRemove = mutableListOf<MavenArtifactRepository>()
for (repo in project.repositories) {
if (repo is MavenArtifactRepository && repo.url.toString() == "https://maven.neoforged.net/releases/") {
repo.mavenContent {
includeGroupAndSubgroups("net.neoforged")
}
toRemove.add(repo)
}
}
// For Fabric's mixin fork
toRemove.forEach { remove(it) }
maven {
name = "Fabric"
url = uri("https://maven.fabricmc.net/")
mavenContent {
includeGroup("net.fabricmc")
}
name = "EngineHub"
url = uri("https://maven.enginehub.org/repo/")
}
}
@ -106,8 +109,6 @@
from(project(":worldedit-core").tasks.named("processResources"))
}
addJarManifest(WorldEditKind.Mod, includeClasspath = false)
tasks.named<ShadowJar>("shadowJar") {
dependencies {
relocate("org.antlr.v4", "com.sk89q.worldedit.antlr4")

View File

@ -1,81 +0,0 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.spongepowered.gradle.plugin.config.PluginLoaders
import org.spongepowered.plugin.metadata.model.PluginDependency
plugins {
id("org.spongepowered.gradle.plugin")
id("org.spongepowered.gradle.vanilla")
}
applyPlatformAndCoreConfiguration()
applyShadowConfiguration()
repositories {
mavenCentral()
}
minecraft {
version("1.20")
}
val spongeApiVersion = "11.0.0-SNAPSHOT";
sponge {
apiVersion(spongeApiVersion)
license("GPL-3.0-or-later")
plugin("worldedit") {
loader {
name(PluginLoaders.JAVA_PLAIN)
version("1.0")
}
displayName("WorldEdit")
version(project.ext["internalVersion"].toString())
entrypoint("com.sk89q.worldedit.sponge.SpongeWorldEdit")
description("WorldEdit is an easy-to-use in-game world editor for Minecraft, supporting both single- and multi-player.")
links {
homepage("https://enginehub.org/worldedit/")
source("https://github.com/EngineHub/WorldEdit")
issues("https://github.com/EngineHub/WorldEdit/issues")
}
contributor("EngineHub") {
description("Various members of the EngineHub team")
}
dependency("spongeapi") {
loadOrder(PluginDependency.LoadOrder.AFTER)
optional(false)
}
}
}
dependencies {
api(project(":worldedit-core"))
api(project(":worldedit-libs:sponge"))
api("org.apache.logging.log4j:log4j-api")
implementation("org.bstats:bstats-sponge:3.0.0")
implementation("it.unimi.dsi:fastutil")
// Silence some warnings, since apparently this isn't on the compile classpath like it should be.
compileOnly("com.google.errorprone:error_prone_annotations:2.11.0")
}
configure<BasePluginExtension> {
archivesName.set("${project.name}-api$spongeApiVersion")
}
addJarManifest(WorldEditKind.Mod, includeClasspath = true)
tasks.named<ShadowJar>("shadowJar") {
dependencies {
include(dependency("org.bstats:"))
include(dependency("org.antlr:antlr4-runtime"))
include(dependency("com.sk89q.lib:jlibnoise"))
relocate("org.antlr.v4", "com.sk89q.worldedit.antlr4")
relocate("org.bstats", "com.sk89q.worldedit.sponge.bstats")
relocate("net.royawesome.jlibnoise", "com.sk89q.worldedit.jlibnoise")
}
}
tasks.named("assemble").configure {
dependsOn("shadowJar")
}

View File

@ -1,67 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.util.lifecycle.SimpleLifecycled;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.lifecycle.RegisterChannelEvent;
import org.spongepowered.api.network.ServerPlayerConnection;
import org.spongepowered.api.network.channel.ChannelBuf;
import org.spongepowered.api.network.channel.raw.RawDataChannel;
import org.spongepowered.api.network.channel.raw.play.RawPlayDataHandler;
import java.nio.charset.StandardCharsets;
public class CUIChannelHandler implements RawPlayDataHandler<ServerPlayerConnection> {
public static final ResourceKey CUI_PLUGIN_CHANNEL = ResourceKey.of("worldedit", "cui");
private static final SimpleLifecycled<RawDataChannel> CHANNEL = SimpleLifecycled.invalid();
public static final class RegistrationHandler {
@Listener
public void onChannelRegistration(RegisterChannelEvent event) {
RawDataChannel channel = event.register(CUI_PLUGIN_CHANNEL, RawDataChannel.class);
channel.play().addHandler(ServerPlayerConnection.class, new CUIChannelHandler());
CHANNEL.newValue(channel);
}
}
public static RawDataChannel channel() {
return CHANNEL.valueOrThrow();
}
@Override
public void handlePayload(ChannelBuf data, ServerPlayerConnection connection) {
ServerPlayer player = connection.player();
SpongePlayer spongePlayer = SpongeAdapter.adapt(player);
LocalSession session = WorldEdit.getInstance().getSessionManager().get(
spongePlayer
);
session.handleCUIInitializationMessage(
new String(data.readBytes(data.available()), StandardCharsets.UTF_8),
spongePlayer
);
}
}

View File

@ -1,81 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.command.util.PermissionCondition;
import com.sk89q.worldedit.sponge.internal.LocaleResolver;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.enginehub.piston.Command;
import org.spongepowered.api.command.CommandCause;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
public abstract class CommandAdapter implements org.spongepowered.api.command.Command.Raw {
private final Command command;
protected CommandAdapter(Command command) {
this.command = command;
}
@Override
public boolean canExecute(CommandCause cause) {
Set<String> permissions = command.getCondition().as(PermissionCondition.class)
.map(PermissionCondition::getPermissions)
.orElseGet(Collections::emptySet);
// Allow commands without permission nodes to always execute.
if (permissions.isEmpty()) {
return true;
}
for (String perm : permissions) {
if (cause.hasPermission(perm)) {
return true;
}
}
return false;
}
@Override
public Optional<Component> shortDescription(CommandCause cause) {
return Optional.of(command.getDescription())
.map(desc -> SpongeTextAdapter.convert(desc, LocaleResolver.resolveLocale(cause.audience())));
}
@Override
public Optional<Component> extendedDescription(CommandCause cause) {
return command.getFooter()
.map(footer -> SpongeTextAdapter.convert(footer, LocaleResolver.resolveLocale(cause.audience())));
}
@Override
public Optional<Component> help(@NonNull CommandCause cause) {
return Optional.of(command.getFullHelp())
.map(help -> SpongeTextAdapter.convert(help, LocaleResolver.resolveLocale(cause.audience())));
}
@Override
public Component usage(CommandCause cause) {
return SpongeTextAdapter.convert(command.getUsage(), LocaleResolver.resolveLocale(cause.audience()));
}
}

View File

@ -1,39 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import org.spongepowered.api.data.persistence.DataQuery;
/**
* Kinda mirrors Sponge Common's Constants class.
*
* <p>Internal. Do not use.</p>
*/
public class Constants {
public static class Sponge {
public static final DataQuery UNSAFE_NBT = DataQuery.of("UnsafeData");
private Sponge() {
}
}
private Constants() {
}
}

View File

@ -1,249 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.sponge.internal.NbtAdapter;
import com.sk89q.worldedit.sponge.internal.SpongeTransmogrifier;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.item.ItemTypes;
import net.minecraft.world.level.block.Block;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.data.persistence.DataContainer;
import org.spongepowered.api.data.persistence.DataView;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import org.spongepowered.api.item.inventory.ItemStack;
import org.spongepowered.api.registry.RegistryKey;
import org.spongepowered.api.registry.RegistryReference;
import org.spongepowered.api.registry.RegistryTypes;
import org.spongepowered.api.world.biome.Biome;
import org.spongepowered.api.world.server.ServerLocation;
import org.spongepowered.api.world.server.ServerWorld;
import org.spongepowered.math.vector.Vector3d;
import org.spongepowered.math.vector.Vector3i;
import java.util.Objects;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Adapts between Sponge and WorldEdit equivalent objects.
*/
public class SpongeAdapter {
public static org.spongepowered.api.block.BlockState adapt(BlockState blockState) {
int blockStateId = BlockStateIdAccess.getBlockStateId(blockState);
if (!BlockStateIdAccess.isValidInternalId(blockStateId)) {
return SpongeTransmogrifier.transmogToMinecraft(blockState);
}
return (org.spongepowered.api.block.BlockState) Block.stateById(blockStateId);
}
public static BlockState adapt(org.spongepowered.api.block.BlockState blockState) {
int blockStateId = Block.getId((net.minecraft.world.level.block.state.BlockState) blockState);
BlockState worldEdit = BlockStateIdAccess.getBlockStateById(blockStateId);
if (worldEdit == null) {
return SpongeTransmogrifier.transmogToWorldEdit(blockState);
}
return worldEdit;
}
/**
* Create a WorldEdit world from a Sponge world.
*
* @param world the Sponge world
* @return a WorldEdit world
*/
public static World adapt(ServerWorld world) {
checkNotNull(world);
return new SpongeWorld(world);
}
/**
* Create a WorldEdit Player from a Sponge Player.
*
* @param player The Sponge player
* @return The WorldEdit player
*/
public static SpongePlayer adapt(ServerPlayer player) {
Objects.requireNonNull(player);
return new SpongePlayer(player);
}
/**
* Create a Sponge Player from a WorldEdit Player.
*
* @param player The WorldEdit player
* @return The Bukkit player
*/
public static Player adapt(com.sk89q.worldedit.entity.Player player) {
return ((SpongePlayer) player).getPlayer();
}
/**
* Create a Sponge world from a WorldEdit world.
*
* @param world the WorldEdit world
* @return a Sponge world
*/
public static ServerWorld adapt(World world) {
checkNotNull(world);
if (world instanceof SpongeWorld) {
return ((SpongeWorld) world).getWorld();
} else {
// Currently this is 99% certain to fail, we don't have consistent world name/id mapping
ServerWorld match = Sponge.server().worldManager().world(
ResourceKey.resolve(world.getName())
).orElse(null);
if (match != null) {
return match;
} else {
throw new IllegalArgumentException("Can't find a Sponge world for " + world);
}
}
}
public static RegistryReference<Biome> adapt(BiomeType biomeType) {
return RegistryKey.of(RegistryTypes.BIOME, ResourceKey.resolve(biomeType.id()))
.asReference();
}
public static BiomeType adapt(Biome biomeType) {
return BiomeType.REGISTRY.get(biomeType.toString());
}
/**
* Create a WorldEdit location from a Sponge location.
*
* @param location the Sponge location
* @return a WorldEdit location
*/
public static Location adapt(ServerLocation location, Vector3d rotation) {
checkNotNull(location);
Vector3 position = asVector(location);
return new Location(
adapt(location.world()),
position,
(float) rotation.y(),
(float) rotation.x()
);
}
/**
* Create a Sponge location from a WorldEdit location.
*
* @param location the WorldEdit location
* @return a Sponge location
*/
public static ServerLocation adapt(Location location) {
checkNotNull(location);
Vector3 position = location.toVector();
return ServerLocation.of(
adapt((World) location.getExtent()),
position.x(), position.y(), position.z()
);
}
/**
* Create a Sponge rotation from a WorldEdit location.
*
* @param location the WorldEdit location
* @return a Sponge rotation
*/
public static Vector3d adaptRotation(Location location) {
checkNotNull(location);
return new Vector3d(location.getPitch(), location.getYaw(), 0);
}
/**
* Create a WorldEdit Vector from a Sponge location.
*
* @param location The Sponge location
* @return a WorldEdit vector
*/
public static Vector3 asVector(ServerLocation location) {
checkNotNull(location);
return Vector3.at(location.x(), location.y(), location.z());
}
/**
* Create a WorldEdit BlockVector from a Sponge location.
*
* @param location The Sponge location
* @return a WorldEdit vector
*/
public static BlockVector3 asBlockVector(ServerLocation location) {
checkNotNull(location);
return BlockVector3.at(location.x(), location.y(), location.z());
}
public static BaseItemStack adapt(ItemStack itemStack) {
DataView tag = itemStack.toContainer().getView(Constants.Sponge.UNSAFE_NBT)
.orElse(null);
return new BaseItemStack(
ItemTypes.get(itemStack.type().key(RegistryTypes.ITEM_TYPE).asString()),
tag == null ? null : LazyReference.from(() -> NbtAdapter.adaptToWorldEdit(tag)),
itemStack.quantity()
);
}
public static ItemStack adapt(BaseItemStack itemStack) {
ItemStack stack = ItemStack.builder()
.itemType(() -> Sponge.game().registry(RegistryTypes.ITEM_TYPE)
.value(ResourceKey.resolve(itemStack.getType().id())))
.quantity(itemStack.getAmount())
.build();
LinCompoundTag nbt = itemStack.getNbt();
if (nbt != null) {
stack.setRawData(
DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED)
.set(Constants.Sponge.UNSAFE_NBT, NbtAdapter.adaptFromWorldEdit(nbt))
);
}
return stack;
}
public static Direction adapt(org.spongepowered.api.util.Direction direction) {
return Direction.valueOf(direction.name());
}
public static Vector3i adaptVector3i(BlockVector3 bv3) {
return new Vector3i(bv3.x(), bv3.y(), bv3.z());
}
public static BlockVector3 adaptVector3i(Vector3i vec3i) {
return BlockVector3.at(vec3i.x(), vec3i.y(), vec3i.z());
}
private SpongeAdapter() {
}
}

View File

@ -1,71 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.translation.TranslationManager;
import com.sk89q.worldedit.world.biome.BiomeData;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import org.spongepowered.api.registry.RegistryReference;
import org.spongepowered.api.world.biome.Biome;
import javax.annotation.Nullable;
/**
* Provides access to biome data in Sponge.
*/
class SpongeBiomeRegistry implements BiomeRegistry {
@Override
public Component getRichName(com.sk89q.worldedit.world.biome.BiomeType biomeType) {
return TranslatableComponent.of(
TranslationManager.makeTranslationKey("biome", biomeType.id())
);
}
@Deprecated
@Nullable
@Override
public BiomeData getData(com.sk89q.worldedit.world.biome.BiomeType biome) {
return new SpongeBiomeData(SpongeAdapter.adapt(biome));
}
@Deprecated
private static class SpongeBiomeData implements BiomeData {
private final RegistryReference<Biome> biome;
/**
* Create a new instance.
*
* @param biome the base biome
*/
private SpongeBiomeData(RegistryReference<Biome> biome) {
this.biome = biome;
}
@SuppressWarnings("deprecation")
@Override
public String getName() {
return biome.location().asString();
}
}
}

View File

@ -1,44 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BlockCategoryRegistry;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.registry.Registry;
import org.spongepowered.api.registry.RegistryTypes;
import org.spongepowered.api.tag.Tag;
import java.util.Set;
import java.util.stream.Collectors;
public class SpongeBlockCategoryRegistry implements BlockCategoryRegistry {
@Override
public Set<BlockType> getCategorisedByName(String category) {
Registry<org.spongepowered.api.block.BlockType> blockTypeRegistry =
Sponge.game().registry(RegistryTypes.BLOCK_TYPE);
return blockTypeRegistry.taggedValues(Tag.of(RegistryTypes.BLOCK_TYPE, ResourceKey.resolve(category)))
.stream()
.map(blockType -> BlockType.REGISTRY.get(blockTypeRegistry.valueKey(blockType).formatted()))
.collect(Collectors.toSet());
}
}

View File

@ -1,183 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.AbstractCommandBlockActor;
import com.sk89q.worldedit.session.SessionKey;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.block.BlockState;
import org.spongepowered.api.block.BlockType;
import org.spongepowered.api.block.BlockTypes;
import org.spongepowered.api.block.entity.CommandBlock;
import org.spongepowered.api.data.Keys;
import org.spongepowered.api.scheduler.Task;
import org.spongepowered.api.util.Ticks;
import org.spongepowered.math.vector.Vector3d;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.UUID;
import static com.google.common.base.Preconditions.checkNotNull;
public class SpongeBlockCommandSender extends AbstractCommandBlockActor {
private final SpongeWorldEdit worldEdit;
private final CommandBlock sender;
private final UUID uuid;
public SpongeBlockCommandSender(SpongeWorldEdit worldEdit, CommandBlock sender) {
super(SpongeAdapter.adapt(checkNotNull(sender).serverLocation(), Vector3d.ZERO));
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
this.sender = sender;
this.uuid = UUID.nameUUIDFromBytes((UUID_PREFIX + sender.name()).getBytes(StandardCharsets.UTF_8));
}
@Override
public String getName() {
return sender.name();
}
@Override
@Deprecated
public void printRaw(String msg) {
for (String part : msg.split("\n")) {
sendMessage(net.kyori.adventure.text.Component.text(part));
}
}
@Override
@Deprecated
public void print(String msg) {
for (String part : msg.split("\n")) {
print(TextComponent.of(part, TextColor.LIGHT_PURPLE));
}
}
@Override
@Deprecated
public void printDebug(String msg) {
for (String part : msg.split("\n")) {
print(TextComponent.of(part, TextColor.GRAY));
}
}
@Override
@Deprecated
public void printError(String msg) {
for (String part : msg.split("\n")) {
print(TextComponent.of(part, TextColor.RED));
}
}
@Override
public void print(Component component) {
sendMessage(SpongeTextAdapter.convert(component, getLocale()));
}
private void sendMessage(net.kyori.adventure.text.Component textComponent) {
this.sender.offer(Keys.LAST_COMMAND_OUTPUT, textComponent);
}
@Override
public Locale getLocale() {
return WorldEdit.getInstance().getConfiguration().defaultLocale;
}
@Override
public UUID getUniqueId() {
return uuid;
}
@Override
public String[] getGroups() {
return new String[0];
}
@Override
public void checkPermission(String permission) throws AuthorizationException {
if (!hasPermission(permission)) {
throw new AuthorizationException();
}
}
@Override
public boolean hasPermission(String permission) {
return sender.hasPermission(permission);
}
public CommandBlock getSender() {
return this.sender;
}
@Override
public SessionKey getSessionKey() {
return new SessionKey() {
private volatile boolean active = true;
private void updateActive() {
BlockState block = sender.block();
if (!sender.serverLocation().world().isChunkLoadedAtBlock(sender.blockPosition(), false)) {
active = false;
return;
}
BlockType type = block.type();
active = type == BlockTypes.COMMAND_BLOCK.get()
|| type == BlockTypes.CHAIN_COMMAND_BLOCK.get()
|| type == BlockTypes.REPEATING_COMMAND_BLOCK.get();
}
@Override
public String getName() {
return sender.name();
}
@Override
public boolean isActive() {
if (Sponge.server().onMainThread()) {
// we can update eagerly
updateActive();
} else {
// we should update it eventually
Task task = Task.builder().delay(Ticks.zero()).plugin(worldEdit.getPluginContainer()).execute(this::updateActive).build();
Sponge.server().scheduler().submit(task);
}
return active;
}
@Override
public boolean isPersistent() {
return true;
}
@Override
public UUID getUniqueId() {
return uuid;
}
};
}
}

View File

@ -1,96 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.world.registry.BlockMaterial;
import com.sk89q.worldedit.world.registry.PassthroughBlockMaterial;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.PushReaction;
import javax.annotation.Nullable;
/**
* Sponge block material that pulls as much info as possible from the Minecraft
* Material, and passes the rest to another implementation, typically the
* bundled block info.
*/
public class SpongeBlockMaterial extends PassthroughBlockMaterial {
private final BlockState block;
public SpongeBlockMaterial(BlockState block, @Nullable BlockMaterial secondary) {
super(secondary);
this.block = block;
}
@Override
public boolean isAir() {
return block.isAir() || super.isAir();
}
@Override
public boolean isOpaque() {
return block.canOcclude();
}
@Override
@SuppressWarnings("deprecation")
public boolean isLiquid() {
return block.liquid();
}
@Override
@SuppressWarnings("deprecation")
public boolean isSolid() {
return block.isSolid();
}
@Override
public boolean isFragileWhenPushed() {
return block.getPistonPushReaction() == PushReaction.DESTROY;
}
@Override
public boolean isUnpushable() {
return block.getPistonPushReaction() == PushReaction.BLOCK;
}
@Override
@SuppressWarnings("deprecation")
public boolean isMovementBlocker() {
return block.blocksMotion();
}
@Override
public boolean isBurnable() {
return block.ignitedByLava();
}
@Override
public boolean isToolRequired() {
return block.requiresCorrectToolForDrops();
}
@Override
public boolean isReplacedDuringPlacement() {
return block.canBeReplaced();
}
}

View File

@ -1,91 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.sponge.internal.SpongeTransmogrifier;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BlockMaterial;
import com.sk89q.worldedit.world.registry.BundledBlockRegistry;
import net.minecraft.world.level.block.Block;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.registry.RegistryTypes;
import org.spongepowered.api.state.StateProperty;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.OptionalInt;
import java.util.TreeMap;
public class SpongeBlockRegistry extends BundledBlockRegistry {
private final Map<org.spongepowered.api.block.BlockState, SpongeBlockMaterial> materialMap =
new HashMap<>();
@Override
public Component getRichName(BlockType blockType) {
return SpongeTextAdapter.convert(Sponge.game().registry(RegistryTypes.BLOCK_TYPE)
.value(ResourceKey.resolve(blockType.id())).asComponent());
}
@Override
public BlockMaterial getMaterial(BlockType blockType) {
org.spongepowered.api.block.BlockType spongeBlockType =
Sponge.game().registry(RegistryTypes.BLOCK_TYPE)
.value(ResourceKey.resolve(blockType.id()));
return materialMap.computeIfAbsent(
spongeBlockType.defaultState(),
m -> {
net.minecraft.world.level.block.state.BlockState blockState =
(net.minecraft.world.level.block.state.BlockState) m;
return new SpongeBlockMaterial(
blockState,
super.getMaterial(blockType)
);
}
);
}
@Override
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
org.spongepowered.api.block.BlockType spongeBlockType =
Sponge.game().registry(RegistryTypes.BLOCK_TYPE)
.value(ResourceKey.resolve(blockType.id()));
Map<String, Property<?>> map = new TreeMap<>();
Collection<StateProperty<?>> propertyKeys = spongeBlockType
.defaultState().stateProperties();
for (StateProperty<?> key : propertyKeys) {
map.put(key.name(), SpongeTransmogrifier.transmogToWorldEditProperty(key));
}
return map;
}
@Override
public OptionalInt getInternalBlockStateId(BlockState state) {
org.spongepowered.api.block.BlockState equivalent = SpongeAdapter.adapt(state);
return OptionalInt.of(Block.getId(
(net.minecraft.world.level.block.state.BlockState) equivalent
));
}
}

View File

@ -1,172 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.session.SessionKey;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import net.kyori.adventure.audience.Audience;
import org.spongepowered.api.entity.living.player.Player;
import java.io.File;
import java.util.Locale;
import java.util.UUID;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
public class SpongeCommandSender implements Actor {
/**
* One time generated ID.
*/
private static final UUID DEFAULT_ID = UUID.fromString("a233eb4b-4cab-42cd-9fd9-7e7b9a3f74be");
private final Audience sender;
public SpongeCommandSender(Audience sender) {
checkNotNull(sender);
checkArgument(
!(sender instanceof Player),
"Players should be wrapped using the specialized class"
);
this.sender = sender;
}
@Override
public UUID getUniqueId() {
return DEFAULT_ID;
}
@Override
public String getName() {
return "Console";
}
@Override
@Deprecated
public void printRaw(String msg) {
for (String part : msg.split("\n")) {
sender.sendMessage(net.kyori.adventure.text.Component.text(part));
}
}
@Override
@Deprecated
public void print(String msg) {
for (String part : msg.split("\n")) {
print(TextComponent.of(part, TextColor.LIGHT_PURPLE));
}
}
@Override
@Deprecated
public void printDebug(String msg) {
for (String part : msg.split("\n")) {
print(TextComponent.of(part, TextColor.GRAY));
}
}
@Override
@Deprecated
public void printError(String msg) {
for (String part : msg.split("\n")) {
print(TextComponent.of(part, TextColor.RED));
}
}
@Override
public void print(Component component) {
sender.sendMessage(SpongeTextAdapter.convert(component, getLocale()));
}
@Override
public boolean canDestroyBedrock() {
return true;
}
@Override
public String[] getGroups() {
return new String[0];
}
@Override
public boolean hasPermission(String perm) {
return true;
}
@Override
public void checkPermission(String permission) {
}
@Override
public boolean isPlayer() {
return false;
}
@Override
public File openFileOpenDialog(String[] extensions) {
return null;
}
@Override
public File openFileSaveDialog(String[] extensions) {
return null;
}
@Override
public void dispatchCUIEvent(CUIEvent event) {
}
@Override
public Locale getLocale() {
return WorldEdit.getInstance().getConfiguration().defaultLocale;
}
@Override
public SessionKey getSessionKey() {
return new SessionKey() {
@Override
public String getName() {
return "Console";
}
@Override
public boolean isActive() {
return true;
}
@Override
public boolean isPersistent() {
return true;
}
@Override
public UUID getUniqueId() {
return DEFAULT_ID;
}
};
}
}

View File

@ -1,125 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.metadata.EntityProperties;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.sponge.internal.NbtAdapter;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.world.NullWorld;
import com.sk89q.worldedit.world.entity.EntityType;
import org.spongepowered.api.data.persistence.DataView;
import org.spongepowered.api.registry.RegistryTypes;
import org.spongepowered.api.world.server.ServerLocation;
import org.spongepowered.math.vector.Vector3d;
import java.lang.ref.WeakReference;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
class SpongeEntity implements Entity {
private final WeakReference<org.spongepowered.api.entity.Entity> entityRef;
SpongeEntity(org.spongepowered.api.entity.Entity entity) {
checkNotNull(entity);
this.entityRef = new WeakReference<>(entity);
}
@Override
public BaseEntity getState() {
org.spongepowered.api.entity.Entity entity = entityRef.get();
if (entity == null || entity.vehicle().isPresent()) {
return null;
}
EntityType entityType = EntityType.REGISTRY.get(entity.type().key(RegistryTypes.ENTITY_TYPE).asString());
if (entityType == null) {
return null;
}
DataView dataView = entity.toContainer().getView(Constants.Sponge.UNSAFE_NBT)
.orElse(null);
return new BaseEntity(
entityType,
dataView == null ? null : LazyReference.from(() -> NbtAdapter.adaptToWorldEdit(dataView))
);
}
@Override
public Location getLocation() {
org.spongepowered.api.entity.Entity entity = entityRef.get();
if (entity != null) {
ServerLocation entityLoc = entity.serverLocation();
Vector3d entityRot = entity.rotation();
return SpongeAdapter.adapt(entityLoc, entityRot);
} else {
return new Location(NullWorld.getInstance());
}
}
@Override
public boolean setLocation(Location location) {
org.spongepowered.api.entity.Entity entity = entityRef.get();
if (entity != null) {
return entity.setLocation(SpongeAdapter.adapt(location));
} else {
return false;
}
}
@Override
public Extent getExtent() {
org.spongepowered.api.entity.Entity entity = entityRef.get();
if (entity != null) {
return SpongeAdapter.adapt(entity.serverLocation().world());
} else {
return NullWorld.getInstance();
}
}
@Override
public boolean remove() {
org.spongepowered.api.entity.Entity entity = entityRef.get();
if (entity != null) {
entity.remove();
}
return true;
}
@SuppressWarnings("unchecked")
@Nullable
@Override
public <T> T getFacet(Class<? extends T> cls) {
org.spongepowered.api.entity.Entity entity = entityRef.get();
if (entity != null) {
if (EntityProperties.class.isAssignableFrom(cls)) {
return (T) new SpongeEntityProperties(entity);
} else {
return null;
}
} else {
return null;
}
}
}

View File

@ -1,155 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.entity.metadata.EntityProperties;
import org.spongepowered.api.data.Keys;
import org.spongepowered.api.entity.Entity;
import org.spongepowered.api.entity.ExperienceOrb;
import org.spongepowered.api.entity.FallingBlock;
import org.spongepowered.api.entity.Item;
import org.spongepowered.api.entity.explosive.fused.PrimedTNT;
import org.spongepowered.api.entity.hanging.ItemFrame;
import org.spongepowered.api.entity.hanging.Painting;
import org.spongepowered.api.entity.living.Ambient;
import org.spongepowered.api.entity.living.ArmorStand;
import org.spongepowered.api.entity.living.ComplexLivingPart;
import org.spongepowered.api.entity.living.Humanoid;
import org.spongepowered.api.entity.living.Living;
import org.spongepowered.api.entity.living.animal.Animal;
import org.spongepowered.api.entity.living.aquatic.Aquatic;
import org.spongepowered.api.entity.living.golem.Golem;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.entity.living.trader.Trader;
import org.spongepowered.api.entity.projectile.Projectile;
import org.spongepowered.api.entity.vehicle.Boat;
import org.spongepowered.api.entity.vehicle.minecart.Minecart;
import static com.google.common.base.Preconditions.checkNotNull;
public class SpongeEntityProperties implements EntityProperties {
private final Entity entity;
public SpongeEntityProperties(Entity entity) {
checkNotNull(entity);
this.entity = entity;
}
@Override
public boolean isPlayerDerived() {
return entity instanceof Humanoid;
}
@Override
public boolean isProjectile() {
return entity instanceof Projectile;
}
@Override
public boolean isItem() {
return entity instanceof Item;
}
@Override
public boolean isFallingBlock() {
return entity instanceof FallingBlock;
}
@Override
public boolean isPainting() {
return entity instanceof Painting;
}
@Override
public boolean isItemFrame() {
return entity instanceof ItemFrame;
}
@Override
public boolean isBoat() {
return entity instanceof Boat;
}
@Override
public boolean isMinecart() {
return entity instanceof Minecart;
}
@Override
public boolean isTNT() {
return entity instanceof PrimedTNT;
}
@Override
public boolean isExperienceOrb() {
return entity instanceof ExperienceOrb;
}
@Override
public boolean isLiving() {
return entity instanceof Living;
}
@Override
public boolean isAnimal() {
return entity instanceof Animal;
}
@Override
public boolean isAmbient() {
return entity instanceof Ambient;
}
@Override
public boolean isNPC() {
return entity instanceof Trader;
}
@Override
public boolean isGolem() {
return entity instanceof Golem;
}
@Override
public boolean isTamed() {
return entity.get(Keys.IS_TAMED).orElse(false);
}
@Override
public boolean isTagged() {
return entity.get(Keys.CUSTOM_NAME).isPresent();
}
@Override
public boolean isArmorStand() {
return entity instanceof ArmorStand;
}
@Override
public boolean isPasteable() {
return !(entity instanceof Player || entity instanceof ComplexLivingPart);
}
@Override
public boolean isWaterCreature() {
return entity instanceof Aquatic;
}
}

View File

@ -1,46 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.registry.ItemCategoryRegistry;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.block.BlockType;
import org.spongepowered.api.registry.Registry;
import org.spongepowered.api.registry.RegistryTypes;
import org.spongepowered.api.tag.Tag;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
public class SpongeItemCategoryRegistry implements ItemCategoryRegistry {
@Override
public Set<ItemType> getCategorisedByName(String category) {
Registry<org.spongepowered.api.item.ItemType> itemTypeRegistry =
Sponge.game().registry(RegistryTypes.ITEM_TYPE);
return itemTypeRegistry.taggedValues(Tag.of(RegistryTypes.ITEM_TYPE, ResourceKey.resolve(category)))
.stream()
.map(itemType -> ItemType.REGISTRY.get(itemTypeRegistry.valueKey(itemType).formatted()))
.collect(Collectors.toSet());
}
}

View File

@ -1,47 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.registry.BundledItemRegistry;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.registry.RegistryTypes;
public class SpongeItemRegistry extends BundledItemRegistry {
@Override
public Component getRichName(ItemType itemType) {
return SpongeTextAdapter.convert(Sponge.game().registry(RegistryTypes.ITEM_TYPE)
.value(ResourceKey.resolve(itemType.id())).asComponent());
}
@Override
public Component getRichName(BaseItemStack itemStack) {
return TranslatableComponent.of(
((ItemStack) (Object) SpongeAdapter.adapt(itemStack)).getDescriptionId()
);
}
}

View File

@ -1,47 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.SubjectReference;
public class SpongePermissionsProvider {
public boolean hasPermission(ServerPlayer player, String permission) {
return player.hasPermission(permission);
}
public void registerPermission(String permission) {
Sponge.game().serviceProvider().registration(PermissionService.class).ifPresent((permissionService -> {
PermissionDescription.Builder permissionBuilder = permissionService.service()
.newDescriptionBuilder(SpongeWorldEdit.inst().getPluginContainer());
permissionBuilder.id(permission).register();
}));
}
public String[] getGroups(ServerPlayer player) {
return player.parents().stream()
.map(SubjectReference::subjectIdentifier)
.toArray(String[]::new);
}
}

View File

@ -1,200 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.google.common.collect.ImmutableSet;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.AbstractPlatform;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.MultiUserPlatform;
import com.sk89q.worldedit.extension.platform.Preference;
import com.sk89q.worldedit.sponge.config.SpongeConfiguration;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.registry.Registries;
import org.enginehub.piston.CommandManager;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import org.spongepowered.api.registry.RegistryTypes;
import org.spongepowered.api.scheduler.Task;
import org.spongepowered.api.util.Ticks;
import org.spongepowered.api.world.server.ServerWorld;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
import static java.util.stream.Collectors.toList;
class SpongePlatform extends AbstractPlatform implements MultiUserPlatform {
private final SpongeWorldEdit mod;
private boolean hookingEvents = false;
private int nextTaskId = 0;
SpongePlatform(SpongeWorldEdit mod) {
this.mod = mod;
}
boolean isHookingEvents() {
return hookingEvents;
}
@Override
public Registries getRegistries() {
return SpongeRegistries.getInstance();
}
@Override
public int getDataVersion() {
return Sponge.platform().minecraftVersion().dataVersion().orElse(-1);
}
@Override
public boolean isValidMobType(String type) {
return Sponge.game().registry(RegistryTypes.ENTITY_TYPE)
.findValue(ResourceKey.resolve(type)).isPresent();
}
@Override
public void reload() {
getConfiguration().load();
super.reload();
}
@Override
public int schedule(long delay, long period, Runnable task) {
Sponge.server().scheduler().submit(Task.builder()
.delay(Ticks.of(delay))
.interval(Ticks.of(period))
.execute(task)
.plugin(SpongeWorldEdit.inst().getPluginContainer())
.build());
return nextTaskId++;
}
@Override
public List<? extends com.sk89q.worldedit.world.World> getWorlds() {
Collection<ServerWorld> worlds = Sponge.server().worldManager().worlds();
List<com.sk89q.worldedit.world.World> ret = new ArrayList<>(worlds.size());
for (ServerWorld world : worlds) {
ret.add(SpongeAdapter.adapt(world));
}
return ret;
}
@Nullable
@Override
public Player matchPlayer(Player player) {
if (player instanceof SpongePlayer) {
return player;
} else {
Optional<ServerPlayer> optPlayer = Sponge.server().player(player.getUniqueId());
return optPlayer.map(SpongePlayer::new).orElse(null);
}
}
@Nullable
@Override
public World matchWorld(World world) {
if (world instanceof SpongeWorld) {
return world;
} else {
// TODO this needs fixing for world name shenanigans
for (ServerWorld spongeWorld : Sponge.server().worldManager().worlds()) {
if (spongeWorld.key().toString().equals(world.getName())) {
return SpongeAdapter.adapt(spongeWorld);
}
}
return null;
}
}
@Override
public void registerCommands(CommandManager manager) {
}
@Override
public void setGameHooksEnabled(boolean enabled) {
this.hookingEvents = enabled;
}
@Override
public SpongeConfiguration getConfiguration() {
return mod.getConfig();
}
@Override
public String getVersion() {
return mod.getInternalVersion();
}
@Override
public String getPlatformName() {
return "Sponge-Official";
}
@Override
public String getPlatformVersion() {
return mod.getInternalVersion();
}
@Override
public String id() {
return "enginehub:sponge";
}
@Override
public Map<Capability, Preference> getCapabilities() {
Map<Capability, Preference> capabilities = new EnumMap<>(Capability.class);
capabilities.put(Capability.CONFIGURATION, Preference.NORMAL);
capabilities.put(Capability.WORLDEDIT_CUI, Preference.NORMAL);
capabilities.put(Capability.GAME_HOOKS, Preference.NORMAL);
capabilities.put(Capability.PERMISSIONS, Preference.NORMAL);
capabilities.put(Capability.USER_COMMANDS, Preference.NORMAL);
capabilities.put(Capability.WORLD_EDITING, Preference.PREFERRED);
return capabilities;
}
@Override
public Set<SideEffect> getSupportedSideEffects() {
return ImmutableSet.of(
SideEffect.UPDATE, SideEffect.ENTITY_AI, SideEffect.LIGHTING, SideEffect.NEIGHBORS
);
}
@Override
public long getTickCount() {
return Sponge.server().runningTimeTicks().ticks();
}
@Override
public Collection<Actor> getConnectedUsers() {
return Sponge.server().onlinePlayers().stream().map(SpongePlayer::new).collect(toList());
}
}

View File

@ -1,308 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.util.StringUtil;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extension.platform.AbstractPlayerActor;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.session.SessionKey;
import com.sk89q.worldedit.sponge.internal.NbtAdapter;
import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.gamemode.GameModes;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.level.block.entity.StructureBlockEntity;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.block.BlockState;
import org.spongepowered.api.data.Keys;
import org.spongepowered.api.data.type.HandTypes;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import org.spongepowered.api.item.inventory.ItemStack;
import org.spongepowered.api.registry.RegistryTypes;
import org.spongepowered.api.world.server.ServerLocation;
import org.spongepowered.math.vector.Vector3d;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.UUID;
import javax.annotation.Nullable;
public class SpongePlayer extends AbstractPlayerActor {
private static final int STRUCTURE_BLOCK_PACKET_ID = 7;
private final ServerPlayer player;
protected SpongePlayer(ServerPlayer player) {
this.player = player;
ThreadSafeCache.getInstance().getOnlineIds().add(getUniqueId());
}
@Override
public UUID getUniqueId() {
return player.uniqueId();
}
@Override
public BaseItemStack getItemInHand(HandSide handSide) {
ItemStack is = this.player.itemInHand(
handSide == HandSide.MAIN_HAND ? HandTypes.MAIN_HAND : HandTypes.OFF_HAND
);
return SpongeAdapter.adapt(is);
}
@Override
public String getName() {
return this.player.name();
}
@Override
public String getDisplayName() {
return LegacyComponentSerializer.legacySection().serialize(player.displayName().get());
}
@Override
public BaseEntity getState() {
throw new UnsupportedOperationException("Cannot create a state from this object");
}
@Override
public Location getLocation() {
ServerLocation entityLoc = this.player.serverLocation();
Vector3d entityRot = this.player.rotation();
return SpongeAdapter.adapt(entityLoc, entityRot);
}
@Override
public boolean setLocation(Location location) {
return player.setLocation(SpongeAdapter.adapt(location));
}
@Override
public com.sk89q.worldedit.world.World getWorld() {
return SpongeAdapter.adapt(player.serverLocation().world());
}
@Override
public void giveItem(BaseItemStack itemStack) {
this.player.inventory().offer(SpongeAdapter.adapt(itemStack));
}
@Override
public void dispatchCUIEvent(CUIEvent event) {
String[] params = event.getParameters();
String send = event.getTypeId();
if (params.length > 0) {
send = send + "|" + StringUtil.joinString(params, "|");
}
String finalData = send;
CUIChannelHandler.channel().play().sendTo(
player,
buffer -> buffer.writeBytes(finalData.getBytes(StandardCharsets.UTF_8))
);
}
@Override
@Deprecated
public void printRaw(String msg) {
for (String part : msg.split("\n")) {
this.player.sendMessage(LegacyComponentSerializer.legacySection().deserialize(part));
}
}
@Override
@Deprecated
public void printDebug(String msg) {
sendColorized(msg, NamedTextColor.GRAY);
}
@Override
@Deprecated
public void print(String msg) {
sendColorized(msg, NamedTextColor.LIGHT_PURPLE);
}
@Override
@Deprecated
public void printError(String msg) {
sendColorized(msg, NamedTextColor.RED);
}
@Override
public void print(Component component) {
player.sendMessage(SpongeTextAdapter.convert(component, getLocale()));
}
private void sendColorized(String msg, TextColor formatting) {
for (String part : msg.split("\n")) {
this.player.sendMessage(
LegacyComponentSerializer.legacySection().deserialize(part).color(formatting)
);
}
}
@Override
public boolean trySetPosition(Vector3 pos, float pitch, float yaw) {
ServerLocation loc = ServerLocation.of(
this.player.world(), pos.x(), pos.y(), pos.z()
);
return this.player.setLocationAndRotation(loc, new Vector3d(pitch, yaw, 0));
}
@Override
public String[] getGroups() {
return SpongeWorldEdit.inst().getPermissionsProvider().getGroups(this.player);
}
@Override
public BlockBag getInventoryBlockBag() {
return null;
}
@Override
public boolean hasPermission(String perm) {
return SpongeWorldEdit.inst().getPermissionsProvider().hasPermission(player, perm);
}
@Nullable
@Override
public <T> T getFacet(Class<? extends T> cls) {
return null;
}
@Override
public GameMode getGameMode() {
return GameModes.get(player.gameMode().get().key(RegistryTypes.GAME_MODE).asString());
}
@Override
public void setGameMode(GameMode gameMode) {
player.gameMode().set(
Sponge.game().registry(RegistryTypes.GAME_MODE).value(
ResourceKey.resolve(gameMode.id())
)
);
}
@Override
public boolean isAllowedToFly() {
return player.get(Keys.CAN_FLY).orElse(super.isAllowedToFly());
}
@Override
public void setFlying(boolean flying) {
player.offer(Keys.IS_FLYING, flying);
}
@Override
public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) {
if (block == null) {
player.resetBlockChange(pos.x(), pos.y(), pos.z());
} else {
BlockState spongeBlock = SpongeAdapter.adapt(block.toImmutableState());
player.sendBlockChange(pos.x(), pos.y(), pos.z(), spongeBlock);
if (block instanceof final BaseBlock baseBlock
&& block.getBlockType().equals(com.sk89q.worldedit.world.block.BlockTypes.STRUCTURE_BLOCK)) {
final LinCompoundTag nbtData = baseBlock.getNbt();
if (nbtData != null) {
net.minecraft.world.level.block.state.BlockState nativeBlock =
(net.minecraft.world.level.block.state.BlockState) spongeBlock;
net.minecraft.nbt.CompoundTag nativeNbtData = NbtAdapter.adaptNMSToWorldEdit(nbtData);
net.minecraft.server.level.ServerPlayer nativePlayer =
((net.minecraft.server.level.ServerPlayer) player);
StructureBlockEntity structureBlockEntity =
new StructureBlockEntity(new BlockPos(pos.x(), pos.y(), pos.z()), nativeBlock);
structureBlockEntity.load(nativeNbtData);
nativePlayer.connection.send(
ClientboundBlockEntityDataPacket.create(structureBlockEntity, it -> nativeNbtData));
}
}
}
}
@Override
public Locale getLocale() {
return player.locale();
}
@Override
public SessionKey getSessionKey() {
return new SessionKeyImpl(player);
}
static class SessionKeyImpl implements SessionKey {
// If not static, this will leak a reference
private final UUID uuid;
private final String name;
SessionKeyImpl(Player player) {
this.uuid = player.uniqueId();
this.name = player.name();
}
@Override
public UUID getUniqueId() {
return uuid;
}
@Nullable
@Override
public String getName() {
return name;
}
@Override
public boolean isActive() {
// We can't directly check if the player is online because
// the list of players is not thread safe
return ThreadSafeCache.getInstance().getOnlineIds().contains(uuid);
}
@Override
public boolean isPersistent() {
return true;
}
}
public Player getPlayer() {
return player;
}
}

View File

@ -1,70 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import com.sk89q.worldedit.world.registry.BlockCategoryRegistry;
import com.sk89q.worldedit.world.registry.BlockRegistry;
import com.sk89q.worldedit.world.registry.BundledRegistries;
import com.sk89q.worldedit.world.registry.ItemCategoryRegistry;
import com.sk89q.worldedit.world.registry.ItemRegistry;
/**
* World data for the Sponge platform.
*/
class SpongeRegistries extends BundledRegistries {
private static final SpongeRegistries INSTANCE = new SpongeRegistries();
public static SpongeRegistries getInstance() {
return INSTANCE;
}
private final BiomeRegistry biomeRegistry = new SpongeBiomeRegistry();
private final BlockRegistry blockRegistry = new SpongeBlockRegistry();
private final BlockCategoryRegistry blockCategoryRegistry = new SpongeBlockCategoryRegistry();
private final ItemRegistry itemRegistry = new SpongeItemRegistry();
private final ItemCategoryRegistry itemCategoryRegistry = new SpongeItemCategoryRegistry();
@Override
public BiomeRegistry getBiomeRegistry() {
return biomeRegistry;
}
@Override
public BlockRegistry getBlockRegistry() {
return blockRegistry;
}
@Override
public BlockCategoryRegistry getBlockCategoryRegistry() {
return blockCategoryRegistry;
}
@Override
public ItemRegistry getItemRegistry() {
return itemRegistry;
}
@Override
public ItemCategoryRegistry getItemCategoryRegistry() {
return itemCategoryRegistry;
}
}

View File

@ -1,45 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.sk89q.worldedit.util.formatting.WorldEditText;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer;
import java.util.Locale;
public class SpongeTextAdapter {
public static net.kyori.adventure.text.Component convert(Component component, Locale locale) {
component = WorldEditText.format(component, locale);
return net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson()
.deserialize(GsonComponentSerializer.INSTANCE.serialize(component));
}
public static Component convert(net.kyori.adventure.text.Component component) {
return GsonComponentSerializer.INSTANCE.deserialize(
net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson()
.serialize(component)
);
}
private SpongeTextAdapter() {
}
}

View File

@ -1,507 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.google.common.collect.Sets;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.sponge.internal.NbtAdapter;
import com.sk89q.worldedit.sponge.internal.SpongeWorldNativeAccess;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType;
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.item.ItemTypes;
import com.sk89q.worldedit.world.weather.WeatherType;
import com.sk89q.worldedit.world.weather.WeatherTypes;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.worldgen.features.EndFeatures;
import net.minecraft.data.worldgen.features.TreeFeatures;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import org.apache.logging.log4j.Logger;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinIntTag;
import org.enginehub.linbus.tree.LinStringTag;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Server;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.block.entity.BlockEntity;
import org.spongepowered.api.block.entity.BlockEntityArchetype;
import org.spongepowered.api.block.entity.BlockEntityType;
import org.spongepowered.api.data.Keys;
import org.spongepowered.api.entity.EntityArchetype;
import org.spongepowered.api.entity.EntityType;
import org.spongepowered.api.entity.EntityTypes;
import org.spongepowered.api.entity.Item;
import org.spongepowered.api.registry.RegistryTypes;
import org.spongepowered.api.util.Ticks;
import org.spongepowered.api.world.BlockChangeFlags;
import org.spongepowered.api.world.LightTypes;
import org.spongepowered.api.world.SerializationBehavior;
import org.spongepowered.api.world.server.ServerLocation;
import org.spongepowered.api.world.server.ServerWorld;
import org.spongepowered.api.world.server.WorldTemplate;
import org.spongepowered.api.world.volume.stream.StreamOptions;
import org.spongepowered.math.vector.Vector3d;
import org.spongepowered.math.vector.Vector3i;
import java.lang.ref.WeakReference;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* An adapter to Minecraft worlds for WorldEdit.
*/
public final class SpongeWorld extends AbstractWorld {
private static final RandomSource random = RandomSource.create();
private static final Logger LOGGER = LogManagerCompat.getLogger();
private final WeakReference<ServerWorld> worldRef;
private final SpongeWorldNativeAccess worldNativeAccess;
/**
* Construct a new world.
*
* @param world the world
*/
SpongeWorld(ServerWorld world) {
checkNotNull(world);
this.worldRef = new WeakReference<>(world);
this.worldNativeAccess = new SpongeWorldNativeAccess(new WeakReference<>((ServerLevel) world));
}
/**
* Get the underlying handle to the world.
*
* @return the world
* @throws RuntimeException thrown if a reference to the world was lost (i.e. world was
* unloaded)
*/
ServerWorld getWorld() {
ServerWorld world = worldRef.get();
if (world != null) {
return world;
} else {
throw new RuntimeException("The reference to the world was lost (i.e. the world may have been unloaded)");
}
}
// This is sus but leaving it for later world name/id reworks
@Override
public String getName() {
return getWorld().key().asString();
}
@Override
public String id() {
return getWorld().key().asString();
}
@Override
public Path getStoragePath() {
return getWorld().directory();
}
@Override
public BlockState getBlock(BlockVector3 position) {
return SpongeAdapter.adapt(getWorld().block(
position.x(), position.y(), position.z()
));
}
@Override
public BaseBlock getFullBlock(BlockVector3 position) {
BlockEntity blockEntity = getWorld().blockEntity(
position.x(), position.y(), position.z()
).orElse(null);
LinCompoundTag blockEntityData = null;
if (blockEntity != null) {
BlockEntityArchetype blockEntityArchetype = blockEntity.createArchetype();
BlockEntityType blockEntityType = blockEntityArchetype.blockEntityType();
ResourceKey blockEntityId = blockEntityType.key(RegistryTypes.BLOCK_ENTITY_TYPE);
blockEntityData = NbtAdapter.adaptToWorldEdit(blockEntityArchetype.blockEntityData());
// Add ID and position since Sponge's #blockEntityData does not save metadata
LinCompoundTag.Builder fullBlockEntityDataBuilder = blockEntityData.toBuilder();
fullBlockEntityDataBuilder.put("id", LinStringTag.of(blockEntityId.formatted()));
fullBlockEntityDataBuilder.put("x", LinIntTag.of(position.x()));
fullBlockEntityDataBuilder.put("y", LinIntTag.of(position.y()));
fullBlockEntityDataBuilder.put("z", LinIntTag.of(position.z()));
blockEntityData = fullBlockEntityDataBuilder.build();
}
return getBlock(position).toBaseBlock(blockEntityData);
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException {
checkNotNull(position);
checkNotNull(block);
ServerWorld world = getWorld();
org.spongepowered.api.block.BlockState newState = SpongeAdapter.adapt(block.toImmutableState());
boolean didSet = world.setBlock(
position.x(), position.y(), position.z(),
newState,
BlockChangeFlags.NONE
.withUpdateNeighbors(sideEffects.shouldApply(SideEffect.NEIGHBORS))
.withNotifyClients(true)
.withPhysics(sideEffects.shouldApply(SideEffect.UPDATE))
.withNotifyObservers(sideEffects.shouldApply(SideEffect.UPDATE))
.withLightingUpdates(sideEffects.shouldApply(SideEffect.LIGHTING))
.withPathfindingUpdates(sideEffects.shouldApply(SideEffect.ENTITY_AI))
.withNeighborDropsAllowed(false)
.withBlocksMoving(false)
.withForcedReRender(false)
.withIgnoreRender(false)
);
if (!didSet) {
// still update NBT if the block is the same
if (world.block(position.x(), position.y(), position.z()) == newState) {
didSet = block.toBaseBlock().getNbt() != null;
}
}
// Create the TileEntity
if (didSet && block instanceof BaseBlock baseBlock) {
LinCompoundTag nbt = baseBlock.getNbt();
if (nbt != null) {
BlockEntityArchetype.builder()
.blockEntity(
Sponge.game().registry(RegistryTypes.BLOCK_ENTITY_TYPE)
.<BlockEntityType>value(ResourceKey.resolve(baseBlock.getNbtId()))
)
.blockEntityData(NbtAdapter.adaptFromWorldEdit(nbt))
.state(newState)
.build()
.apply(ServerLocation.of(world, position.x(), position.y(), position.z()));
}
}
return true;
}
@Override
public Set<SideEffect> applySideEffects(BlockVector3 position, com.sk89q.worldedit.world.block.BlockState previousType, SideEffectSet sideEffectSet) throws WorldEditException {
checkNotNull(position);
worldNativeAccess.applySideEffects(position, previousType, sideEffectSet);
return Sets.intersection(
SpongeWorldEdit.inst().getInternalPlatform().getSupportedSideEffects(),
sideEffectSet.getSideEffectsToApply()
);
}
@Override
public boolean clearContainerBlockContents(BlockVector3 position) {
getWorld().removeBlockEntity(position.x(), position.y(), position.z());
return true;
}
@Override
public boolean regenerate(Region region, Extent extent, RegenOptions options) {
Server server = Sponge.server();
final String id = "worldedittemp_" + getWorld().key().value();
WorldTemplate tempWorldProperties = WorldTemplate.builder().from(getWorld())
.key(ResourceKey.of("worldedit", id))
.add(Keys.IS_LOAD_ON_STARTUP, false)
.add(Keys.SERIALIZATION_BEHAVIOR, SerializationBehavior.NONE)
.add(Keys.SEED, options.getSeed().orElse(getWorld().properties().worldGenerationConfig().seed()))
.build();
ServerWorld tempWorld;
try {
tempWorld = server.worldManager().loadWorld(tempWorldProperties).get();
} catch (InterruptedException | ExecutionException e) {
LOGGER.error("Failed to load temp world", e);
return false;
}
try {
// Pre-gen all the chunks
// We need to also pull one more chunk in every direction
CuboidRegion expandedPreGen = new CuboidRegion(region.getMinimumPoint().subtract(16, 16, 16), region.getMaximumPoint().add(16, 16, 16));
for (BlockVector3 chunk : expandedPreGen.getChunkCubes()) {
tempWorld.loadChunk(chunk.x(), chunk.y(), chunk.z(), true);
}
World from = SpongeAdapter.adapt(tempWorld);
for (BlockVector3 vec : region) {
extent.setBlock(vec, from.getFullBlock(vec));
if (options.shouldRegenBiomes()) {
extent.setBiome(vec, from.getBiome(vec));
}
}
} catch (WorldEditException e) {
throw new RuntimeException(e);
} finally {
// Remove temp world
server.worldManager().unloadWorld(tempWorldProperties.key()).thenRun(() -> server.worldManager().deleteWorld(tempWorldProperties.key()));
}
return true;
}
@Nullable
private static net.minecraft.resources.ResourceKey<ConfiguredFeature<?, ?>> createTreeFeatureGenerator(TreeGenerator.TreeType type) {
return switch (type) {
// Based off of the SaplingGenerator class, as well as uses of DefaultBiomeFeatures fields
case TREE -> TreeFeatures.OAK;
case BIG_TREE -> TreeFeatures.FANCY_OAK;
case REDWOOD -> TreeFeatures.SPRUCE;
case TALL_REDWOOD -> TreeFeatures.MEGA_SPRUCE;
case MEGA_REDWOOD -> TreeFeatures.MEGA_PINE;
case BIRCH -> TreeFeatures.BIRCH;
case JUNGLE -> TreeFeatures.MEGA_JUNGLE_TREE;
case SMALL_JUNGLE -> TreeFeatures.JUNGLE_TREE;
case SHORT_JUNGLE -> TreeFeatures.JUNGLE_TREE_NO_VINE;
case JUNGLE_BUSH -> TreeFeatures.JUNGLE_BUSH;
case SWAMP -> TreeFeatures.SWAMP_OAK;
case ACACIA -> TreeFeatures.ACACIA;
case DARK_OAK -> TreeFeatures.DARK_OAK;
case TALL_BIRCH -> TreeFeatures.SUPER_BIRCH_BEES_0002;
case RED_MUSHROOM -> TreeFeatures.HUGE_RED_MUSHROOM;
case BROWN_MUSHROOM -> TreeFeatures.HUGE_BROWN_MUSHROOM;
case WARPED_FUNGUS -> TreeFeatures.WARPED_FUNGUS;
case CRIMSON_FUNGUS -> TreeFeatures.CRIMSON_FUNGUS;
case CHORUS_PLANT -> EndFeatures.CHORUS_PLANT;
case MANGROVE -> TreeFeatures.MANGROVE;
case TALL_MANGROVE -> TreeFeatures.TALL_MANGROVE;
case CHERRY -> TreeFeatures.CHERRY;
case RANDOM ->
createTreeFeatureGenerator(TreeGenerator.TreeType.values()[ThreadLocalRandom.current().nextInt(TreeGenerator.TreeType.values().length)]);
default -> null;
};
}
@Override
public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) {
ServerLevel world = (ServerLevel) getWorld();
ConfiguredFeature<?, ?> generator = Optional.ofNullable(createTreeFeatureGenerator(type))
.map(k -> world.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(k))
.orElse(null);
return generator != null && generator.place(
world, world.getChunkSource().getGenerator(), random,
new BlockPos(position.x(), position.y(), position.z())
);
}
@Override
public int getBlockLightLevel(BlockVector3 position) {
checkNotNull(position);
int skyLight = getWorld().light(LightTypes.SKY, position.x(), position.y(), position.z());
int groundLight = getWorld().light(LightTypes.BLOCK, position.x(), position.y(), position.z());
return Math.max(skyLight, groundLight);
}
@Override
public BiomeType getBiome(BlockVector3 position) {
checkNotNull(position);
return BiomeType.REGISTRY.get(
getWorld().registry(RegistryTypes.BIOME)
.valueKey(getWorld().biome(position.x(), position.y(), position.z()))
.asString()
);
}
@Override
public boolean setBiome(BlockVector3 position, BiomeType biome) {
checkNotNull(position);
checkNotNull(biome);
getWorld().setBiome(
position.x(), position.y(), position.z(),
getWorld().registry(RegistryTypes.BIOME).value(
ResourceKey.resolve(biome.id())
)
);
return true;
}
@Override
public void dropItem(Vector3 position, BaseItemStack item) {
checkNotNull(position);
checkNotNull(item);
if (item.getType() == ItemTypes.AIR) {
return;
}
Item itemEntity = getWorld().createEntity(
EntityTypes.ITEM,
new Vector3d(position.x(), position.y(), position.z())
);
itemEntity.item().set(
SpongeAdapter.adapt(item).createSnapshot()
);
getWorld().spawnEntity(itemEntity);
}
@Override
public void simulateBlockMine(BlockVector3 position) {
getWorld().destroyBlock(
new Vector3i(position.x(), position.y(), position.z()),
true
);
}
@Override
public boolean canPlaceAt(BlockVector3 position, com.sk89q.worldedit.world.block.BlockState blockState) {
return ((net.minecraft.world.level.block.state.BlockState) SpongeAdapter.adapt(blockState))
.canSurvive(
((LevelReader) getWorld()),
new BlockPos(position.x(), position.y(), position.z())
);
}
@Override
public int hashCode() {
return getWorld().hashCode();
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
} else if ((o instanceof SpongeWorld other)) {
ServerWorld otherWorld = other.worldRef.get();
ServerWorld thisWorld = worldRef.get();
return otherWorld != null && otherWorld.equals(thisWorld);
} else {
return o instanceof com.sk89q.worldedit.world.World
&& ((com.sk89q.worldedit.world.World) o).getName().equals(getName());
}
}
@Override
public List<? extends Entity> getEntities(Region region) {
return getWorld()
.entityStream(
SpongeAdapter.adaptVector3i(region.getMinimumPoint()),
SpongeAdapter.adaptVector3i(region.getMaximumPoint()),
// We don't need to force load or clone to copy entities
StreamOptions.builder()
.setCarbonCopy(false)
.setLoadingStyle(StreamOptions.LoadingStyle.NONE)
.build()
)
.toStream()
.map(ve -> new SpongeEntity(ve.type()))
.collect(Collectors.toList());
}
@Override
public List<? extends Entity> getEntities() {
return getWorld().entities().stream()
.map(SpongeEntity::new)
.collect(Collectors.toList());
}
@Nullable
@Override
public Entity createEntity(Location location, BaseEntity entity) {
Optional<EntityType<?>> entityType = Sponge.game().registry(RegistryTypes.ENTITY_TYPE)
.findValue(ResourceKey.resolve(entity.getType().id()));
if (entityType.isEmpty()) {
return null;
}
EntityArchetype.Builder builder = EntityArchetype.builder().type(entityType.get());
var nativeTag = entity.getNbt();
if (nativeTag != null) {
builder.entityData(NbtAdapter.adaptFromWorldEdit(nativeTag));
}
return builder.build().apply(SpongeAdapter.adapt(location)).map(SpongeEntity::new).orElse(null);
}
@Override
public WeatherType getWeather() {
return WeatherTypes.get(
getWorld().weather().type().key(RegistryTypes.WEATHER_TYPE).asString()
);
}
@Override
public long getRemainingWeatherDuration() {
return getWorld().weather().remainingDuration().ticks();
}
@Override
public void setWeather(WeatherType weatherType) {
getWorld().setWeather(
Sponge.game().registry(RegistryTypes.WEATHER_TYPE).value(
ResourceKey.resolve(weatherType.id())
)
);
}
@Override
public void setWeather(WeatherType weatherType, long duration) {
getWorld().setWeather(
Sponge.game().registry(RegistryTypes.WEATHER_TYPE).value(
ResourceKey.resolve(weatherType.id())
),
Ticks.of(duration)
);
}
@Override
public BlockVector3 getSpawnPosition() {
return SpongeAdapter.adaptVector3i(getWorld().properties().spawnPosition());
}
}

View File

@ -1,485 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import com.google.common.base.Joiner;
import com.google.inject.Inject;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.PermissionCondition;
import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
import com.sk89q.worldedit.event.platform.PlatformUnreadyEvent;
import com.sk89q.worldedit.event.platform.PlatformsRegisteredEvent;
import com.sk89q.worldedit.event.platform.SessionIdleEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extension.platform.PlatformManager;
import com.sk89q.worldedit.internal.anvil.ChunkDeleter;
import com.sk89q.worldedit.internal.command.CommandUtil;
import com.sk89q.worldedit.internal.event.InteractionDebouncer;
import com.sk89q.worldedit.sponge.config.SpongeConfiguration;
import com.sk89q.worldedit.world.biome.BiomeCategory;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockCategory;
import com.sk89q.worldedit.world.item.ItemCategory;
import net.kyori.adventure.audience.Audience;
import org.apache.logging.log4j.Logger;
import org.bstats.sponge.Metrics;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Server;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.block.BlockSnapshot;
import org.spongepowered.api.block.BlockType;
import org.spongepowered.api.block.entity.BlockEntity;
import org.spongepowered.api.block.entity.CommandBlock;
import org.spongepowered.api.command.Command;
import org.spongepowered.api.command.CommandCause;
import org.spongepowered.api.command.CommandCompletion;
import org.spongepowered.api.command.CommandResult;
import org.spongepowered.api.command.parameter.ArgumentReader;
import org.spongepowered.api.config.ConfigDir;
import org.spongepowered.api.data.type.HandTypes;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import org.spongepowered.api.event.EventContextKeys;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.action.InteractEvent;
import org.spongepowered.api.event.block.InteractBlockEvent;
import org.spongepowered.api.event.filter.cause.Root;
import org.spongepowered.api.event.item.inventory.InteractItemEvent;
import org.spongepowered.api.event.lifecycle.ConstructPluginEvent;
import org.spongepowered.api.event.lifecycle.RegisterCommandEvent;
import org.spongepowered.api.event.lifecycle.StartedEngineEvent;
import org.spongepowered.api.event.lifecycle.StartingEngineEvent;
import org.spongepowered.api.event.lifecycle.StoppingEngineEvent;
import org.spongepowered.api.event.network.ServerSideConnectionEvent;
import org.spongepowered.api.registry.RegistryTypes;
import org.spongepowered.api.scheduler.Task;
import org.spongepowered.api.world.LocatableBlock;
import org.spongepowered.api.world.server.ServerLocation;
import org.spongepowered.api.world.server.ServerWorld;
import org.spongepowered.math.vector.Vector3d;
import org.spongepowered.plugin.PluginContainer;
import org.spongepowered.plugin.builtin.jvm.Plugin;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME;
import static java.util.stream.Collectors.toList;
/**
* The Sponge implementation of WorldEdit.
*/
@Plugin(SpongeWorldEdit.MOD_ID)
public class SpongeWorldEdit {
public static final String MOD_ID = "worldedit";
private static final int BSTATS_PLUGIN_ID = 3329;
private static SpongeWorldEdit inst;
public static SpongeWorldEdit inst() {
return inst;
}
private final Logger logger;
private final PluginContainer container;
private final SpongeConfiguration config;
private final Path workingDir;
private InteractionDebouncer debouncer;
private SpongePermissionsProvider provider;
private SpongePlatform platform;
@Inject
public SpongeWorldEdit(Logger logger,
PluginContainer container,
SpongeConfiguration config,
Metrics.Factory metricsFactory,
@ConfigDir(sharedRoot = false)
Path workingDir) {
this.logger = logger;
this.container = container;
this.config = config;
this.workingDir = workingDir;
metricsFactory.make(BSTATS_PLUGIN_ID);
inst = this;
}
@Listener
public void onPluginConstruction(ConstructPluginEvent event) {
this.platform = new SpongePlatform(this);
debouncer = new InteractionDebouncer(platform);
WorldEdit.getInstance().getPlatformManager().register(platform);
this.provider = new SpongePermissionsProvider();
event.game().eventManager().registerListeners(
container,
new CUIChannelHandler.RegistrationHandler()
);
logger.info("WorldEdit for Sponge (version " + getInternalVersion() + ") is loaded");
}
@Listener
public void serverStarting(StartingEngineEvent<Server> event) {
final Path delChunks = workingDir.resolve(DELCHUNKS_FILE_NAME);
if (Files.exists(delChunks)) {
ChunkDeleter.runFromFile(delChunks, true);
}
}
@Listener
public void serverStarted(StartedEngineEvent<Server> event) {
event.engine().scheduler().submit(Task.builder()
.plugin(container)
.interval(30, TimeUnit.SECONDS)
.execute(ThreadSafeCache.getInstance())
.build());
event.game().registry(RegistryTypes.BLOCK_TYPE).streamEntries().forEach(blockType -> {
String id = blockType.key().asString();
if (!com.sk89q.worldedit.world.block.BlockType.REGISTRY.keySet().contains(id)) {
com.sk89q.worldedit.world.block.BlockType.REGISTRY.register(id, new com.sk89q.worldedit.world.block.BlockType(
id,
input -> {
BlockType spongeBlockType = Sponge.game().registry(RegistryTypes.BLOCK_TYPE).value(
ResourceKey.resolve(input.getBlockType().id())
);
return SpongeAdapter.adapt(spongeBlockType.defaultState());
}
));
}
});
event.game().registry(RegistryTypes.ITEM_TYPE).streamEntries().forEach(itemType -> {
String id = itemType.key().asString();
if (!com.sk89q.worldedit.world.item.ItemType.REGISTRY.keySet().contains(id)) {
com.sk89q.worldedit.world.item.ItemType.REGISTRY.register(id, new com.sk89q.worldedit.world.item.ItemType(id));
}
});
event.game().registry(RegistryTypes.ENTITY_TYPE).streamEntries().forEach(entityType -> {
String id = entityType.key().asString();
if (!com.sk89q.worldedit.world.entity.EntityType.REGISTRY.keySet().contains(id)) {
com.sk89q.worldedit.world.entity.EntityType.REGISTRY.register(id, new com.sk89q.worldedit.world.entity.EntityType(id));
}
});
for (ServerWorld world : event.engine().worldManager().worlds()) {
world.registry(RegistryTypes.BIOME).streamEntries().forEach(biomeType -> {
String id = biomeType.key().asString();
if (!BiomeType.REGISTRY.keySet().contains(id)) {
BiomeType.REGISTRY.register(id, new BiomeType(id));
}
});
}
event.game().registry(RegistryTypes.BLOCK_TYPE).tags().forEach(blockTypeTag -> {
String id = blockTypeTag.key().asString();
if (!BlockCategory.REGISTRY.keySet().contains(id)) {
BlockCategory.REGISTRY.register(id, new BlockCategory(id));
}
});
event.game().registry(RegistryTypes.ITEM_TYPE).tags().forEach(itemTypeTag -> {
String id = itemTypeTag.key().asString();
if (!ItemCategory.REGISTRY.keySet().contains(id)) {
ItemCategory.REGISTRY.register(id, new ItemCategory(id));
}
});
event.game().registry(RegistryTypes.BIOME).tags().forEach(biomeTag -> {
String id = biomeTag.key().asString();
if (!BiomeCategory.REGISTRY.keySet().contains(id)) {
BiomeCategory.REGISTRY.register(id, new BiomeCategory(id, () -> event.game().registry(RegistryTypes.BIOME).taggedValues(biomeTag).stream().map(SpongeAdapter::adapt).collect(Collectors.toSet())));
}
});
config.load();
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent(platform));
}
@Listener
public void serverStopping(StoppingEngineEvent<Server> event) {
WorldEdit worldEdit = WorldEdit.getInstance();
worldEdit.getSessionManager().unload();
WorldEdit.getInstance().getEventBus().post(new PlatformUnreadyEvent(platform));
}
@Listener
public void registerCommand(RegisterCommandEvent<Command.Raw> event) {
WorldEdit.getInstance().getEventBus().post(new PlatformsRegisteredEvent());
PlatformManager manager = WorldEdit.getInstance().getPlatformManager();
Platform commandsPlatform = manager.queryCapability(Capability.USER_COMMANDS);
if (commandsPlatform != platform || !platform.isHookingEvents()) {
// We're not in control of commands/events -- do not register.
return;
}
List<org.enginehub.piston.Command> commands = manager.getPlatformCommandManager().getCommandManager()
.getAllCommands().toList();
for (org.enginehub.piston.Command command : commands) {
registerAdaptedCommand(event, command);
Set<String> perms = command.getCondition().as(PermissionCondition.class)
.map(PermissionCondition::getPermissions)
.orElseGet(Collections::emptySet);
if (!perms.isEmpty()) {
perms.forEach(getPermissionsProvider()::registerPermission);
}
}
}
private String rebuildArguments(String commandLabel, String args) {
int plSep = commandLabel.indexOf(':');
if (plSep >= 0 && plSep < commandLabel.length() + 1) {
commandLabel = commandLabel.substring(plSep + 1);
}
StringBuilder sb = new StringBuilder("/").append(commandLabel);
String[] split = args.split(" ", -1);
if (split.length > 0) {
sb.append(" ");
}
return Joiner.on(" ").appendTo(sb, split).toString();
}
private void registerAdaptedCommand(RegisterCommandEvent<Command.Raw> event, org.enginehub.piston.Command command) {
CommandAdapter adapter = new CommandAdapter(command) {
@Override
public CommandResult process(CommandCause cause, ArgumentReader.Mutable arguments) {
CommandEvent weEvent = new CommandEvent(SpongeWorldEdit.inst().wrapCommandCause(cause), rebuildArguments(command.getName(), arguments.remaining()).trim());
WorldEdit.getInstance().getEventBus().post(weEvent);
return weEvent.isCancelled() ? CommandResult.success() : CommandResult.builder().build();
}
@Override
public List<CommandCompletion> complete(CommandCause cause, ArgumentReader.Mutable arguments) {
String args = rebuildArguments(command.getName(), arguments.remaining());
CommandSuggestionEvent weEvent = new CommandSuggestionEvent(SpongeWorldEdit.inst().wrapCommandCause(cause), args);
WorldEdit.getInstance().getEventBus().post(weEvent);
return CommandUtil.fixSuggestions(args, weEvent.getSuggestions())
.stream().map(CommandCompletion::of).collect(toList());
}
};
event.register(
container, adapter, command.getName(), command.getAliases().toArray(new String[0])
);
}
private boolean skipEvents() {
return platform == null || !platform.isHookingEvents();
}
private boolean skipInteractionEvent(InteractEvent event) {
return skipEvents() || event.context().get(EventContextKeys.USED_HAND).orElse(null) != HandTypes.MAIN_HAND.get();
}
@Listener
public void onPlayerInteractItemPrimary(InteractItemEvent.Primary event, @Root ServerPlayer spongePlayer) {
if (skipInteractionEvent(event)) {
return;
}
WorldEdit we = WorldEdit.getInstance();
SpongePlayer player = SpongeAdapter.adapt(spongePlayer);
Optional<Boolean> previousResult = debouncer.getDuplicateInteractionResult(player);
if (previousResult.isPresent()) {
return;
}
boolean result = we.handleArmSwing(player);
debouncer.setLastInteraction(player, result);
}
@Listener
public void onPlayerInteractItemSecondary(InteractItemEvent.Secondary event, @Root ServerPlayer spongePlayer) {
if (skipInteractionEvent(event)) {
return;
}
WorldEdit we = WorldEdit.getInstance();
SpongePlayer player = SpongeAdapter.adapt(spongePlayer);
Optional<Boolean> previousResult = debouncer.getDuplicateInteractionResult(player);
if (previousResult.isPresent()) {
if (previousResult.get()) {
event.setCancelled(true);
}
return;
}
boolean result = we.handleRightClick(player);
debouncer.setLastInteraction(player, result);
if (result) {
event.setCancelled(true);
}
}
@Listener
public void onPlayerInteractBlockPrimary(InteractBlockEvent.Primary.Start event, @Root ServerPlayer spongePlayer) {
if (skipInteractionEvent(event)) {
return;
}
WorldEdit we = WorldEdit.getInstance();
SpongePlayer player = SpongeAdapter.adapt(spongePlayer);
BlockSnapshot targetBlock = event.block();
Optional<ServerLocation> optLoc = targetBlock.location();
boolean result = false;
if (optLoc.isPresent()) {
ServerLocation loc = optLoc.get();
com.sk89q.worldedit.util.Location pos = SpongeAdapter.adapt(loc, Vector3d.ZERO);
result = we.handleBlockLeftClick(player, pos, SpongeAdapter.adapt(event.targetSide()));
}
result = we.handleArmSwing(player) || result;
debouncer.setLastInteraction(player, result);
if (result) {
event.setCancelled(true);
}
}
@Listener
public void onPlayerInteractBlockSecondary(InteractBlockEvent.Secondary event, @Root ServerPlayer spongePlayer) {
if (skipInteractionEvent(event)) {
return;
}
WorldEdit we = WorldEdit.getInstance();
SpongePlayer player = SpongeAdapter.adapt(spongePlayer);
BlockSnapshot targetBlock = event.block();
Optional<ServerLocation> optLoc = targetBlock.location();
boolean result = false;
if (optLoc.isPresent()) {
ServerLocation loc = optLoc.get();
com.sk89q.worldedit.util.Location pos = SpongeAdapter.adapt(loc, Vector3d.ZERO);
result = we.handleBlockRightClick(player, pos, SpongeAdapter.adapt(event.targetSide()));
}
result = we.handleRightClick(player) || result;
debouncer.setLastInteraction(player, result);
if (result) {
event.setCancelled(true);
}
}
@Listener
public void onPlayerQuit(ServerSideConnectionEvent.Disconnect event) {
debouncer.clearInteraction(SpongeAdapter.adapt(event.player()));
WorldEdit.getInstance().getEventBus()
.post(new SessionIdleEvent(new SpongePlayer.SessionKeyImpl(event.player())));
}
public PluginContainer getPluginContainer() {
return container;
}
/**
* Get the configuration.
*
* @return the Sponge configuration
*/
SpongeConfiguration getConfig() {
return this.config;
}
public Actor wrapCommandCause(CommandCause cause) {
Object rootCause = cause.root();
if (rootCause instanceof ServerPlayer) {
return SpongeAdapter.adapt((ServerPlayer) rootCause);
}
if (rootCause instanceof LocatableBlock locatableBlock) {
Optional<? extends BlockEntity> optionalBlockEntity = locatableBlock.world().blockEntity(locatableBlock.blockPosition());
if (optionalBlockEntity.isPresent()) {
BlockEntity blockEntity = optionalBlockEntity.get();
if (blockEntity instanceof CommandBlock commandBlock) {
return new SpongeBlockCommandSender(this, commandBlock);
}
}
}
if (rootCause instanceof Audience) {
return new SpongeCommandSender((Audience) rootCause);
}
throw new UnsupportedOperationException("Cannot wrap " + rootCause.getClass());
}
/**
* Get the WorldEdit proxy for the platform.
*
* @return the WorldEdit platform
*/
public Platform getPlatform() {
return this.platform;
}
SpongePlatform getInternalPlatform() {
return this.platform;
}
/**
* Get the working directory where WorldEdit's files are stored.
*
* @return the working directory
*/
public Path getWorkingDir() {
return this.workingDir;
}
/**
* Get the version of the WorldEdit Sponge implementation.
*
* @return a version string
*/
String getInternalVersion() {
return container.metadata().version().toString();
}
public void setPermissionsProvider(SpongePermissionsProvider provider) {
this.provider = provider;
}
public SpongePermissionsProvider getPermissionsProvider() {
return provider;
}
}

View File

@ -1,63 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* Caches data that cannot be accessed from another thread safely.
*/
public class ThreadSafeCache implements Runnable {
private static final ThreadSafeCache INSTANCE = new ThreadSafeCache();
private Set<UUID> onlineIds = new CopyOnWriteArraySet<>();
/**
* Get an concurrent-safe set of UUIDs of online players.
*
* @return a set of UUIDs
*/
public Set<UUID> getOnlineIds() {
return onlineIds;
}
@Override
public void run() {
List<UUID> onlineIds = new ArrayList<>();
for (ServerPlayer player : Sponge.server().onlinePlayers()) {
onlineIds.add(player.uniqueId());
}
this.onlineIds = new CopyOnWriteArraySet<>(onlineIds);
}
public static ThreadSafeCache getInstance() {
return INSTANCE;
}
}

View File

@ -1,149 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge.config;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.session.SessionManager;
import com.sk89q.worldedit.util.report.Unreported;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import org.apache.logging.log4j.Logger;
import org.spongepowered.configurate.CommentedConfigurationNode;
import org.spongepowered.configurate.ConfigurationOptions;
import org.spongepowered.configurate.loader.ConfigurationLoader;
import org.spongepowered.configurate.serialize.SerializationException;
import java.io.IOException;
import java.util.HashSet;
import java.util.Locale;
public class ConfigurateConfiguration extends LocalConfiguration {
@Unreported
protected final ConfigurationLoader<CommentedConfigurationNode> config;
@Unreported
protected final Logger logger;
@Unreported
protected CommentedConfigurationNode node;
public ConfigurateConfiguration(ConfigurationLoader<CommentedConfigurationNode> config, Logger logger) {
this.config = config;
this.logger = logger;
}
@Override
public void load() {
try {
ConfigurationOptions options = ConfigurationOptions.defaults();
options = options.shouldCopyDefaults(true);
node = config.load(options);
} catch (IOException e) {
logger.warn("Error loading WorldEdit configuration", e);
}
profile = node.node("debug").getBoolean(profile);
traceUnflushedSessions = node.node("debugging", "trace-unflushed-sessions").getBoolean(traceUnflushedSessions);
wandItem = node.node("wand-item").getString(wandItem).toLowerCase(Locale.ROOT);
try {
wandItem = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(wandItem)).id();
} catch (Throwable ignored) {
}
defaultChangeLimit = Math.max(-1, node.node("limits", "max-blocks-changed", "default").getInt(defaultChangeLimit));
maxChangeLimit = Math.max(-1, node.node("limits", "max-blocks-changed", "maximum").getInt(maxChangeLimit));
defaultVerticalHeight = Math.max(1, node.node("limits", "vertical-height", "default").getInt(defaultVerticalHeight));
defaultMaxPolygonalPoints = Math.max(-1, node.node("limits", "max-polygonal-points", "default").getInt(defaultMaxPolygonalPoints));
maxPolygonalPoints = Math.max(-1, node.node("limits", "max-polygonal-points", "maximum").getInt(maxPolygonalPoints));
maxRadius = Math.max(-1, node.node("limits", "max-radius").getInt(maxRadius));
maxBrushRadius = node.node("limits", "max-brush-radius").getInt(maxBrushRadius);
maxSuperPickaxeSize = Math.max(1, node.node("limits", "max-super-pickaxe-size").getInt(maxSuperPickaxeSize));
butcherDefaultRadius = Math.max(-1, node.node("limits", "butcher-radius", "default").getInt(butcherDefaultRadius));
butcherMaxRadius = Math.max(-1, node.node("limits", "butcher-radius", "maximum").getInt(butcherMaxRadius));
try {
disallowedBlocks = new HashSet<>(
node.node("limits", "disallowed-blocks").getList(
String.class,
ImmutableList.copyOf(getDefaultDisallowedBlocks())
)
);
} catch (SerializationException e) {
logger.warn("Error loading WorldEdit configuration", e);
}
try {
allowedDataCycleBlocks = new HashSet<>(
node.node("limits", "allowed-data-cycle-blocks").getList(String.class, ImmutableList.of())
);
} catch (SerializationException e) {
logger.warn("Error loading WorldEdit configuration", e);
}
registerHelp = node.node("register-help").getBoolean(true);
logCommands = node.node("logging", "log-commands").getBoolean(logCommands);
logFile = node.node("logging", "file").getString(logFile);
logFormat = node.node("logging", "format").getString(logFormat);
superPickaxeDrop = node.node("super-pickaxe", "drop-items").getBoolean(superPickaxeDrop);
superPickaxeManyDrop = node.node("super-pickaxe", "many-drop-items").getBoolean(superPickaxeManyDrop);
useInventory = node.node("use-inventory", "enable").getBoolean(useInventory);
useInventoryOverride = node.node("use-inventory", "allow-override").getBoolean(useInventoryOverride);
useInventoryCreativeOverride = node.node("use-inventory", "creative-mode-overrides").getBoolean(useInventoryCreativeOverride);
navigationWand = node.node("navigation-wand", "item").getString(navigationWand).toLowerCase(Locale.ROOT);
try {
navigationWand = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(navigationWand)).id();
} catch (Throwable ignored) {
}
navigationWandMaxDistance = node.node("navigation-wand", "max-distance").getInt(navigationWandMaxDistance);
navigationUseGlass = node.node("navigation", "use-glass").getBoolean(navigationUseGlass);
scriptTimeout = node.node("scripting", "timeout").getInt(scriptTimeout);
scriptsDir = node.node("scripting", "dir").getString(scriptsDir);
saveDir = node.node("saving", "dir").getString(saveDir);
allowSymlinks = node.node("files", "allow-symbolic-links").getBoolean(false);
LocalSession.MAX_HISTORY_SIZE = Math.max(0, node.node("history", "size").getInt(15));
SessionManager.EXPIRATION_GRACE = node.node("history", "expiration").getInt(10) * 60 * 1000;
showHelpInfo = node.node("show-help-on-first-use").getBoolean(true);
serverSideCUI = node.node("server-side-cui").getBoolean(true);
String snapshotsDir = node.node("snapshots", "directory").getString("");
boolean experimentalSnapshots = node.node("snapshots", "experimental").getBoolean(false);
initializeSnapshotConfiguration(snapshotsDir, experimentalSnapshots);
String type = node.node("shell-save-type").getString("").trim();
shellSaveType = type.isEmpty() ? null : type;
extendedYLimit = node.node("compat", "extended-y-limit").getBoolean(false);
setDefaultLocaleName(node.node("default-locale").getString(defaultLocaleName));
commandBlockSupport = node.node("command-block-support").getBoolean(false);
}
}

View File

@ -1,62 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge.config;
import com.google.inject.Inject;
import com.sk89q.worldedit.sponge.SpongeWorldEdit;
import org.apache.logging.log4j.Logger;
import org.spongepowered.api.config.DefaultConfig;
import org.spongepowered.configurate.CommentedConfigurationNode;
import org.spongepowered.configurate.loader.ConfigurationLoader;
import java.io.IOException;
import java.nio.file.Path;
public class SpongeConfiguration extends ConfigurateConfiguration {
public boolean creativeEnable = false;
public boolean cheatMode = false;
@Inject
public SpongeConfiguration(@DefaultConfig(sharedRoot = false)
ConfigurationLoader<CommentedConfigurationNode> config,
Logger logger) {
super(config, logger);
}
@Override
public void load() {
super.load();
creativeEnable = node.node("use-in-creative").getBoolean(false);
cheatMode = node.node("cheat-mode").getBoolean(false);
try {
config.save(node);
} catch (IOException e) {
logger.warn("Error loading WorldEdit configuration", e);
}
}
@Override
public Path getWorkingDirectoryPath() {
return SpongeWorldEdit.inst().getWorkingDir();
}
}

View File

@ -1,43 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge.internal;
import com.sk89q.worldedit.util.SideEffect;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LevelChunk;
import javax.annotation.Nullable;
public interface ExtendedChunk {
/**
* {@link LevelChunk#setBlockState(BlockPos, BlockState, boolean)} with the extra
* {@link SideEffect#UPDATE} flag.
*
* @param pos the position to set
* @param state the state to set
* @param moved I honestly have no idea and can't be bothered to investigate, we pass {@code
* false}
* @param update the update flag, see side-effect for details
* @return the old block state, or {@code null} if unchanged
*/
@Nullable
BlockState setBlockState(BlockPos pos, BlockState state, boolean moved, boolean update);
}

View File

@ -1,35 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge.internal;
import com.sk89q.worldedit.WorldEdit;
import net.kyori.adventure.audience.Audience;
import org.spongepowered.api.util.locale.LocaleSource;
import java.util.Locale;
public class LocaleResolver {
public static Locale resolveLocale(Audience audience) {
if (audience instanceof LocaleSource) {
return ((LocaleSource) audience).locale();
}
return WorldEdit.getInstance().getConfiguration().defaultLocale;
}
}

View File

@ -1,272 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge.internal;
import net.minecraft.nbt.ByteArrayTag;
import net.minecraft.nbt.ByteTag;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.DoubleTag;
import net.minecraft.nbt.FloatTag;
import net.minecraft.nbt.IntArrayTag;
import net.minecraft.nbt.IntTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.LongArrayTag;
import net.minecraft.nbt.LongTag;
import net.minecraft.nbt.ShortTag;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import org.enginehub.linbus.tree.LinByteArrayTag;
import org.enginehub.linbus.tree.LinByteTag;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinDoubleTag;
import org.enginehub.linbus.tree.LinFloatTag;
import org.enginehub.linbus.tree.LinIntArrayTag;
import org.enginehub.linbus.tree.LinIntTag;
import org.enginehub.linbus.tree.LinListTag;
import org.enginehub.linbus.tree.LinLongArrayTag;
import org.enginehub.linbus.tree.LinLongTag;
import org.enginehub.linbus.tree.LinShortTag;
import org.enginehub.linbus.tree.LinStringTag;
import org.enginehub.linbus.tree.LinTag;
import org.enginehub.linbus.tree.LinTagType;
import org.spongepowered.api.data.persistence.DataContainer;
import org.spongepowered.api.data.persistence.DataQuery;
import org.spongepowered.api.data.persistence.DataSerializable;
import org.spongepowered.api.data.persistence.DataView;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class NbtAdapter {
/**
* A separator to introduce errors if there is something to be separated. We should only see
* single-part keys.
*/
private static final String BREAKING_SEPARATOR = "if you see this, something is wrong";
public static LinCompoundTag adaptToWorldEdit(DataView view) {
LinCompoundTag.Builder builder = LinCompoundTag.builder();
for (Map.Entry<DataQuery, Object> entry : view.values(false).entrySet()) {
builder.put(
entry.getKey().asString(BREAKING_SEPARATOR),
adaptUnknownToWorldEdit(entry.getValue())
);
}
return builder.build();
}
private static LinTag<?> adaptUnknownToWorldEdit(Object object) {
if (object instanceof DataView) {
return adaptToWorldEdit((DataView) object);
}
if (object instanceof Boolean) {
return LinByteTag.of((byte) ((Boolean) object ? 1 : 0));
}
if (object instanceof Byte) {
return LinByteTag.of((Byte) object);
}
if (object instanceof Short) {
return LinShortTag.of(((Short) object));
}
if (object instanceof Integer) {
return LinIntTag.of(((Integer) object));
}
if (object instanceof Long) {
return LinLongTag.of(((Long) object));
}
if (object instanceof Float) {
return LinFloatTag.of(((Float) object));
}
if (object instanceof Double) {
return LinDoubleTag.of(((Double) object));
}
if (object instanceof String) {
return LinStringTag.of((String) object);
}
if (object instanceof byte[]) {
return LinByteArrayTag.of(((byte[]) object));
}
if (object instanceof Byte[] array) {
byte[] copy = new byte[array.length];
for (int i = 0; i < copy.length; i++) {
copy[i] = array[i];
}
return LinByteArrayTag.of(copy);
}
if (object instanceof int[]) {
return LinIntArrayTag.of(((int[]) object));
}
if (object instanceof Integer[] array) {
int[] copy = new int[array.length];
for (int i = 0; i < copy.length; i++) {
copy[i] = array[i];
}
return LinIntArrayTag.of(copy);
}
if (object instanceof long[]) {
return LinLongArrayTag.of(((long[]) object));
}
if (object instanceof Long[] array) {
long[] copy = new long[array.length];
for (int i = 0; i < copy.length; i++) {
copy[i] = array[i];
}
return LinLongArrayTag.of(copy);
}
if (object instanceof List<?> objects) {
if (objects.isEmpty()) {
return LinListTag.empty(LinTagType.endTag());
}
LinTag<?> first = adaptUnknownToWorldEdit(objects.get(0));
@SuppressWarnings("unchecked")
LinListTag.Builder<LinTag<?>> builder = LinListTag.builder((LinTagType<LinTag<?>>) first.type());
builder.add(first);
for (int i = 1; i < objects.size(); i++) {
Object value = objects.get(i);
builder.add(adaptUnknownToWorldEdit(value));
}
return builder.build();
}
if (object instanceof Map) {
LinCompoundTag.Builder builder = LinCompoundTag.builder();
for (Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) {
String key = entry.getKey() instanceof DataQuery
? ((DataQuery) entry.getKey()).asString(BREAKING_SEPARATOR)
: entry.getKey().toString();
builder.put(key, adaptUnknownToWorldEdit(entry.getValue()));
}
return builder.build();
}
if (object instanceof DataSerializable) {
return adaptToWorldEdit(((DataSerializable) object).toContainer());
}
throw new UnsupportedOperationException("Unable to translate into NBT: " + object.getClass());
}
public static DataContainer adaptFromWorldEdit(LinCompoundTag tag) {
// copy to container, no cloning used because it's unlikely to leak
// and it's cheaper this way
DataContainer container = DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED);
for (var entry : tag.value().entrySet()) {
container.set(DataQuery.of(entry.getKey()), adaptTagFromWorldEdit(entry.getValue()));
}
return container;
}
private static Object adaptTagFromWorldEdit(LinTag<?> value) {
if (value instanceof LinListTag<?> listTag) {
return listTag.value().stream()
.map(NbtAdapter::adaptTagFromWorldEdit)
.collect(Collectors.toList());
}
if (value instanceof LinCompoundTag compoundTag) {
return adaptFromWorldEdit(compoundTag);
}
// everything else is raw JDK types, so we can use it directly
return value.value();
}
public static Tag adaptNMSToWorldEdit(LinTag<?> tag) {
if (tag instanceof LinIntArrayTag intArrayTag) {
return adaptNMSToWorldEdit(intArrayTag);
} else if (tag instanceof LinListTag<?> listTag) {
return adaptNMSToWorldEdit(listTag);
} else if (tag instanceof LinLongTag longTag) {
return adaptNMSToWorldEdit(longTag);
} else if (tag instanceof LinLongArrayTag longArrayTag) {
return adaptNMSToWorldEdit(longArrayTag);
} else if (tag instanceof LinStringTag stringTag) {
return adaptNMSToWorldEdit(stringTag);
} else if (tag instanceof LinIntTag intTag) {
return adaptNMSToWorldEdit(intTag);
} else if (tag instanceof LinByteTag byteTag) {
return adaptNMSToWorldEdit(byteTag);
} else if (tag instanceof LinByteArrayTag byteArrayTag) {
return adaptNMSToWorldEdit(byteArrayTag);
} else if (tag instanceof LinCompoundTag compoundTag) {
return adaptNMSToWorldEdit(compoundTag);
} else if (tag instanceof LinFloatTag floatTag) {
return adaptNMSToWorldEdit(floatTag);
} else if (tag instanceof LinShortTag shortTag) {
return adaptNMSToWorldEdit(shortTag);
} else if (tag instanceof LinDoubleTag doubleTag) {
return adaptNMSToWorldEdit(doubleTag);
} else {
throw new IllegalArgumentException("Can't convert tag of type " + tag.getClass().getCanonicalName());
}
}
public static IntArrayTag adaptNMSToWorldEdit(LinIntArrayTag tag) {
return new IntArrayTag(tag.value());
}
public static ListTag adaptNMSToWorldEdit(LinListTag<?> tag) {
ListTag list = new ListTag();
for (LinTag<?> child : tag.value()) {
list.add(adaptNMSToWorldEdit(child));
}
return list;
}
public static LongTag adaptNMSToWorldEdit(LinLongTag tag) {
return LongTag.valueOf(tag.valueAsLong());
}
public static LongArrayTag adaptNMSToWorldEdit(LinLongArrayTag tag) {
return new LongArrayTag(tag.value());
}
public static StringTag adaptNMSToWorldEdit(LinStringTag tag) {
return StringTag.valueOf(tag.value());
}
public static IntTag adaptNMSToWorldEdit(LinIntTag tag) {
return IntTag.valueOf(tag.valueAsInt());
}
public static ByteTag adaptNMSToWorldEdit(LinByteTag tag) {
return ByteTag.valueOf(tag.valueAsByte());
}
public static ByteArrayTag adaptNMSToWorldEdit(LinByteArrayTag tag) {
return new ByteArrayTag(tag.value());
}
public static CompoundTag adaptNMSToWorldEdit(LinCompoundTag tag) {
CompoundTag compound = new CompoundTag();
for (var child : tag.value().entrySet()) {
compound.put(child.getKey(), adaptNMSToWorldEdit(child.getValue()));
}
return compound;
}
public static FloatTag adaptNMSToWorldEdit(LinFloatTag tag) {
return FloatTag.valueOf(tag.valueAsFloat());
}
public static ShortTag adaptNMSToWorldEdit(LinShortTag tag) {
return ShortTag.valueOf(tag.valueAsShort());
}
public static DoubleTag adaptNMSToWorldEdit(LinDoubleTag tag) {
return DoubleTag.valueOf(tag.valueAsDouble());
}
}

View File

@ -1,210 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge.internal;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.registry.state.BooleanProperty;
import com.sk89q.worldedit.registry.state.DirectionalProperty;
import com.sk89q.worldedit.registry.state.EnumProperty;
import com.sk89q.worldedit.registry.state.IntegerProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import net.minecraft.util.StringRepresentable;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.registry.RegistryTypes;
import org.spongepowered.api.state.StateProperty;
import java.util.Comparator;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
/**
* Raw, un-cached transformations.
*/
public class SpongeTransmogrifier {
private static final LoadingCache<StateProperty<?>, Property<?>> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<>() {
@Override
public Property<?> load(StateProperty<?> property) {
net.minecraft.world.level.block.state.properties.Property<?> nativeProperty =
(net.minecraft.world.level.block.state.properties.Property<?>) property;
String propertyName = nativeProperty.getName();
if (nativeProperty instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
return new BooleanProperty(propertyName,
ImmutableList.copyOf(((net.minecraft.world.level.block.state.properties.BooleanProperty) nativeProperty).getPossibleValues()));
}
if (nativeProperty instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(propertyName,
ImmutableList.copyOf(((net.minecraft.world.level.block.state.properties.IntegerProperty) nativeProperty).getPossibleValues()));
}
if (isDirectionProperty(nativeProperty)) {
return new DirectionalProperty(propertyName,
((net.minecraft.world.level.block.state.properties.EnumProperty<?>) nativeProperty).getPossibleValues().stream()
.map(x -> adaptDirection((net.minecraft.core.Direction) x))
.toList()
);
}
if (nativeProperty instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(propertyName,
((net.minecraft.world.level.block.state.properties.EnumProperty<?>) nativeProperty).getPossibleValues().stream()
.map(StringRepresentable::getSerializedName)
.toList());
}
throw new IllegalStateException("Unknown property type");
}
});
public static Property<?> transmogToWorldEditProperty(StateProperty<?> property) {
return PROPERTY_CACHE.getUnchecked(property);
}
private static Map<Property<?>, Object> transmogToWorldEditProperties(
BlockType block,
net.minecraft.world.level.block.state.BlockState blockState
) {
Map<Property<?>, Object> properties = new TreeMap<>(Comparator.comparing(Property::getName));
for (net.minecraft.world.level.block.state.properties.Property<?> nativeProperty: blockState.getProperties()) {
Object value = blockState.getValue(nativeProperty);
if (isDirectionProperty(nativeProperty)) {
net.minecraft.core.Direction nativeDirectionValue = (net.minecraft.core.Direction) value;
value = adaptDirection(nativeDirectionValue);
} else if (nativeProperty instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
value = ((StringRepresentable) value).getSerializedName();
}
properties.put(block.getProperty(nativeProperty.getName()), value);
}
return properties;
}
private static boolean isDirectionProperty(net.minecraft.world.level.block.state.properties.Property<?> property) {
return property instanceof net.minecraft.world.level.block.state.properties.EnumProperty
&& property.getValueClass().isAssignableFrom(net.minecraft.core.Direction.class);
}
private static Direction adaptDirection(net.minecraft.core.Direction direction) {
switch (direction) {
case UP:
return Direction.UP;
case DOWN:
return Direction.DOWN;
case EAST:
return Direction.EAST;
case WEST:
return Direction.WEST;
case NORTH:
return Direction.NORTH;
case SOUTH:
return Direction.SOUTH;
default:
throw new AssertionError("New direction added: " + direction);
}
}
private static net.minecraft.core.Direction adaptDirection(Direction direction) {
switch (direction) {
case UP:
return net.minecraft.core.Direction.UP;
case DOWN:
return net.minecraft.core.Direction.DOWN;
case EAST:
return net.minecraft.core.Direction.EAST;
case WEST:
return net.minecraft.core.Direction.WEST;
case NORTH:
return net.minecraft.core.Direction.NORTH;
case SOUTH:
return net.minecraft.core.Direction.SOUTH;
default:
throw new AssertionError("New direction added: " + direction);
}
}
private static net.minecraft.world.level.block.state.properties.Property<?> findPropertyByName(
net.minecraft.world.level.block.state.BlockState blockState,
String propertyName
) {
for (net.minecraft.world.level.block.state.properties.Property<?> property: blockState.getProperties()) {
if (property.getName().equals(propertyName)) {
return property;
}
}
throw new IllegalStateException("Missing property in " + blockState.getBlock() + ": " + propertyName);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private static org.spongepowered.api.block.BlockState transmogToMinecraftProperties(
org.spongepowered.api.block.BlockState blockState,
Map<Property<?>, Object> states
) {
net.minecraft.world.level.block.state.BlockState nativeBlockState =
(net.minecraft.world.level.block.state.BlockState) blockState;
for (Map.Entry<Property<?>, Object> stateEntry: states.entrySet()) {
Property<?> property = stateEntry.getKey();
Object value = stateEntry.getValue();
net.minecraft.world.level.block.state.properties.Property<?> nativeProperty =
findPropertyByName(nativeBlockState, property.getName());
Comparable<?> nativeValue;
if (property instanceof DirectionalProperty) {
Direction directionValue = (Direction) value;
nativeValue = adaptDirection(directionValue);
} else if (property instanceof EnumProperty) {
String valueName = (String) value;
Optional<? extends Comparable<?>> nativeValueOpt = nativeProperty.getValue(valueName);
if (nativeValueOpt.isEmpty()) {
throw new IllegalStateException("Failed to parse " + valueName + " into " + property.getName());
}
nativeValue = nativeValueOpt.get();
} else {
nativeValue = (Comparable<?>) value;
}
nativeBlockState = nativeBlockState.setValue(
(net.minecraft.world.level.block.state.properties.Property) nativeProperty, (Comparable) nativeValue);
}
return (org.spongepowered.api.block.BlockState) nativeBlockState;
}
public static org.spongepowered.api.block.BlockState transmogToMinecraft(BlockState blockState) {
org.spongepowered.api.block.BlockType mcBlock = Sponge.game().registry(RegistryTypes.BLOCK_TYPE)
.value(ResourceKey.resolve(blockState.getBlockType().id()));
org.spongepowered.api.block.BlockState newState = mcBlock.defaultState();
Map<Property<?>, Object> states = blockState.getStates();
return transmogToMinecraftProperties(newState, states);
}
public static BlockState transmogToWorldEdit(org.spongepowered.api.block.BlockState blockState) {
BlockType blockType = BlockType.REGISTRY.get(
blockState.type().key(RegistryTypes.BLOCK_TYPE).asString()
);
return blockType.getState(transmogToWorldEditProperties(blockType,
(net.minecraft.world.level.block.state.BlockState) blockState));
}
private SpongeTransmogrifier() {
}
}

View File

@ -1,159 +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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.sponge.internal;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.sponge.SpongeAdapter;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.storage.ChunkStore;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LevelChunk;
import org.enginehub.linbus.tree.LinCompoundTag;
import java.lang.ref.WeakReference;
import java.util.Objects;
import javax.annotation.Nullable;
public class SpongeWorldNativeAccess implements WorldNativeAccess<LevelChunk, BlockState, BlockPos> {
private static final int UPDATE = 1;
private static final int NOTIFY = 2;
private final WeakReference<ServerLevel> world;
private SideEffectSet sideEffectSet;
public SpongeWorldNativeAccess(WeakReference<ServerLevel> world) {
this.world = world;
}
private ServerLevel getWorld() {
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
}
@Override
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
this.sideEffectSet = sideEffectSet;
}
@Override
public LevelChunk getChunk(int x, int z) {
return getWorld().getChunk(x, z);
}
@Override
public BlockState toNative(com.sk89q.worldedit.world.block.BlockState state) {
return (BlockState) SpongeAdapter.adapt(state);
}
@Override
public BlockState getBlockState(LevelChunk chunk, BlockPos position) {
return chunk.getBlockState(position);
}
@Nullable
@Override
public BlockState setBlockState(LevelChunk chunk, BlockPos position, BlockState state) {
if (chunk instanceof ExtendedChunk) {
return ((ExtendedChunk) chunk).setBlockState(
position, state, false, sideEffectSet.shouldApply(SideEffect.UPDATE)
);
}
return chunk.setBlockState(position, state, false);
}
@Override
public BlockState getValidBlockForPosition(BlockState block, BlockPos position) {
return Block.updateFromNeighbourShapes(block, getWorld(), position);
}
@Override
public BlockPos getPosition(int x, int y, int z) {
return new BlockPos(x, y, z);
}
@Override
public void updateLightingForBlock(BlockPos position) {
getWorld().getChunkSource().getLightEngine().checkBlock(position);
}
@Override
public boolean updateTileEntity(BlockPos position, LinCompoundTag tag) {
CompoundTag nativeTag = NbtAdapter.adaptNMSToWorldEdit(tag);
BlockEntity tileEntity = getWorld().getChunk(position).getBlockEntity(position);
if (tileEntity == null) {
return false;
}
tileEntity.setLevel(getWorld());
tileEntity.load(nativeTag);
return true;
}
@Override
public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, BlockState oldState, BlockState newState) {
if (chunk.getSections()[position.getY() >> ChunkStore.CHUNK_SHIFTS] != null) { // TODO 1.17 - world.get().getSectionIndex(position.getY())
getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY);
}
}
@Override
public boolean isChunkTicking(LevelChunk chunk) {
return chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING);
}
@Override
public void markBlockChanged(LevelChunk chunk, BlockPos position) {
if (chunk.getSections()[position.getY() >> ChunkStore.CHUNK_SHIFTS] != null) { // TODO 1.17 - world.getSectionIndex(position.getY())
getWorld().getChunkSource().blockChanged(position);
}
}
@Override
public void notifyNeighbors(BlockPos pos, BlockState oldState, BlockState newState) {
getWorld().updateNeighborsAt(pos, oldState.getBlock());
if (newState.hasAnalogOutputSignal()) {
getWorld().updateNeighbourForOutputSignal(pos, newState.getBlock());
}
}
@Override
public void updateBlock(BlockPos pos, BlockState oldState, BlockState newState) {
ServerLevel world = getWorld();
newState.onPlace(world, pos, oldState, false);
}
@Override
public void updateNeighbors(BlockPos pos, BlockState oldState, BlockState newState, int recursionLimit) {
ServerLevel world = getWorld();
oldState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit);
newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit);
}
@Override
public void onBlockStateChange(BlockPos pos, BlockState oldState, BlockState newState) {
getWorld().onBlockStateChange(pos, oldState, newState);
}
}