mirror of
https://github.com/EngineHub/WorldEdit.git
synced 2024-11-27 04:00:48 +08:00
Bring back the Sponge module, updated for 1.20.6 (#2538)
* Bring back the Sponge module * Fixes * Specify the SNAPSHOT build of SpongeAPI to use
This commit is contained in:
parent
05db94cfac
commit
ad0362367a
@ -8,6 +8,10 @@
|
||||
name = "EngineHub Repository"
|
||||
url = uri("https://maven.enginehub.org/repo/")
|
||||
}
|
||||
maven {
|
||||
name = "SpongePowered"
|
||||
url = uri("https://repo.spongepowered.org/repository/maven-public/")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@ -19,6 +23,10 @@
|
||||
implementation(libs.jfrog.buildinfo)
|
||||
implementation(libs.paperweight)
|
||||
implementation(libs.gson)
|
||||
|
||||
implementation(libs.sponge.vanillagradle)
|
||||
implementation(libs.neogradle.userdev)
|
||||
|
||||
constraints {
|
||||
val asmVersion = "[${libs.versions.minimumAsm.get()},)"
|
||||
implementation("org.ow2.asm:asm:$asmVersion") {
|
||||
|
@ -2,6 +2,8 @@
|
||||
codecov = "org.enginehub.codecov:0.2.0"
|
||||
neogradle-userdev = "net.neoforged.gradle.userdev:7.0.107"
|
||||
fabric-loom = "fabric-loom:1.6.9"
|
||||
sponge-spongegradle = "org.spongepowered.gradle.plugin:2.2.0"
|
||||
sponge-vanillagradle = "org.spongepowered.gradle.vanilla:0.2.1-20240507.024226-82"
|
||||
|
||||
[versions]
|
||||
kyoriText = "3.0.4"
|
||||
@ -26,6 +28,9 @@ lang-worldeditBase = "7.3.1"
|
||||
lang-version = "1309"
|
||||
|
||||
[libraries]
|
||||
neogradle-userdev = "net.neoforged.gradle:neoform:7.0.107"
|
||||
sponge-vanillagradle = "org.spongepowered:vanillagradle:0.2.1-20240507.024226-82"
|
||||
|
||||
licenser = "gradle.plugin.org.cadixdev.gradle:licenser:0.6.1"
|
||||
grgit = "org.ajoberstar.grgit:grgit-gradle:5.2.2"
|
||||
japicmp = "me.champeau.gradle:japicmp-gradle-plugin:0.4.2"
|
||||
|
@ -5,6 +5,10 @@
|
||||
name = "EngineHub"
|
||||
url = uri("https://maven.enginehub.org/repo/")
|
||||
}
|
||||
maven {
|
||||
name = "SpongePowered"
|
||||
url = uri("https://repo.spongepowered.org/repository/maven-public/")
|
||||
}
|
||||
}
|
||||
}
|
||||
plugins {
|
||||
@ -35,7 +39,7 @@
|
||||
include("worldedit-bukkit:adapters:adapter-$it")
|
||||
}
|
||||
|
||||
listOf("bukkit", "core", "fabric", "neoforge", "cli").forEach {
|
||||
listOf("bukkit", "core", "fabric", "neoforge", "sponge", "cli").forEach {
|
||||
include("worldedit-libs:$it")
|
||||
include("worldedit-$it")
|
||||
}
|
||||
|
@ -43,7 +43,7 @@
|
||||
// Generic setup for all tasks
|
||||
// Pull the version before our current version.
|
||||
val baseVersion = "(,${rootProject.version.toString().substringBefore("-SNAPSHOT")}["
|
||||
for (projectFragment in listOf("bukkit", "cli", "core", "fabric", "neoforge")) {
|
||||
for (projectFragment in listOf("bukkit", "cli", "core", "fabric", "neoforge", "sponge")) {
|
||||
val capitalizedFragment =
|
||||
projectFragment.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.ROOT) else it.toString() }
|
||||
val proj = project(":worldedit-$projectFragment")
|
||||
|
3
worldedit-libs/sponge/build.gradle.kts
Normal file
3
worldedit-libs/sponge/build.gradle.kts
Normal file
@ -0,0 +1,3 @@
|
||||
plugins {
|
||||
id("buildlogic.libs")
|
||||
}
|
88
worldedit-sponge/build.gradle.kts
Normal file
88
worldedit-sponge/build.gradle.kts
Normal file
@ -0,0 +1,88 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import org.spongepowered.gradle.plugin.config.PluginLoaders
|
||||
import org.spongepowered.plugin.metadata.model.PluginDependency
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.sponge.spongegradle)
|
||||
id("org.spongepowered.gradle.vanilla")
|
||||
`java-library`
|
||||
id("buildlogic.platform")
|
||||
}
|
||||
|
||||
platform {
|
||||
kind = buildlogic.WorldEditKind.Mod
|
||||
includeClasspath = true
|
||||
}
|
||||
|
||||
commonJava {
|
||||
banSlf4j = false
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
minecraft {
|
||||
version("1.20.6")
|
||||
}
|
||||
|
||||
val spongeApiVersion = "11.0.0-20240520.134918-37";
|
||||
|
||||
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")
|
||||
"testImplementation"(libs.mockito.core)
|
||||
|
||||
// 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")
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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.ServerConnectionState;
|
||||
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<ServerConnectionState.Game> {
|
||||
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(ServerConnectionState.Game.class, new CUIChannelHandler());
|
||||
CHANNEL.newValue(channel);
|
||||
}
|
||||
}
|
||||
|
||||
public static RawDataChannel channel() {
|
||||
return CHANNEL.valueOrThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePayload(ChannelBuf data, ServerConnectionState.Game 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
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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()));
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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() {
|
||||
}
|
||||
}
|
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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() {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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
|
||||
));
|
||||
}
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.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 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());
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
@ -0,0 +1,313 @@
|
||||
/*
|
||||
* 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.loadWithComponents(nativeNbtData, nativePlayer.level().registryAccess());
|
||||
nativePlayer.connection.send(
|
||||
ClientboundBlockEntityDataPacket.create(structureBlockEntity, (be, ra) -> 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();
|
||||
}
|
||||
|
||||
SessionKeyImpl(UUID uuid, String name) {
|
||||
this.uuid = uuid;
|
||||
this.name = 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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() {
|
||||
}
|
||||
}
|
@ -0,0 +1,507 @@
|
||||
/*
|
||||
* 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()
|
||||
.state(newState)
|
||||
.blockEntity(
|
||||
Sponge.game().registry(RegistryTypes.BLOCK_ENTITY_TYPE)
|
||||
.<BlockEntityType>value(ResourceKey.resolve(baseBlock.getNbtId()))
|
||||
)
|
||||
.blockEntityData(NbtAdapter.adaptFromWorldEdit(nbt))
|
||||
.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());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,487 @@
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
});
|
||||
Sponge.server().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) {
|
||||
event.profile().ifPresent(profile -> {
|
||||
debouncer.clearInteraction(profile::uniqueId);
|
||||
|
||||
WorldEdit.getInstance().getEventBus()
|
||||
.post(new SessionIdleEvent(new SpongePlayer.SessionKeyImpl(profile.uniqueId(), profile.name().orElseThrow())));
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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() {
|
||||
}
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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 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.loadWithComponents(nativeTag, getWorld().registryAccess());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, BlockState oldState, 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(FullChunkStatus.BLOCK_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, 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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user