Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-12-25 10:30:04 +01:00
feature(fabric): added fabric support (#491)
* Initial work towards Fabric compat. This does not compile yet * Further updates - should compile but Gradle is being weird. * Remove useless buildscript extras * Added mixins to buildscript classpath to fix Loom crash * Make it compile * Got it building and added interaction * Fixed review comments * Use ServerPlayerEntity for FakePlayer * Use method references for nicer names * Fixed remaining comments and added networking for CUI * Output as dist.jar * Added mixins for left click air * Use regex for cleanliness
Dieser Commit ist enthalten in:
Ursprung
7d558ccffa
Commit
aa8d34c913
@ -30,7 +30,7 @@ println """
|
|||||||
1) Read COMPILING.md if you haven't yet
|
1) Read COMPILING.md if you haven't yet
|
||||||
2) Try running 'build' in a separate Gradle run
|
2) Try running 'build' in a separate Gradle run
|
||||||
3) Use gradlew and not gradle
|
3) Use gradlew and not gradle
|
||||||
4) If you still need help, ask on IRC! irc.esper.net #sk89q
|
4) If you still need help, ask on Discord! https://discord.gg/enginehub
|
||||||
|
|
||||||
Output files will be in [subproject]/build/libs
|
Output files will be in [subproject]/build/libs
|
||||||
*******************************************
|
*******************************************
|
||||||
@ -85,7 +85,7 @@ subprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configure(['core', 'bukkit', 'forge', 'sponge'].collect { project(":worldedit-$it") }) {
|
configure(['core', 'bukkit', 'forge', 'sponge', 'fabric'].collect { project(":worldedit-$it") }) {
|
||||||
apply plugin: 'java'
|
apply plugin: 'java'
|
||||||
apply plugin: 'maven'
|
apply plugin: 'maven'
|
||||||
apply plugin: 'checkstyle'
|
apply plugin: 'checkstyle'
|
||||||
@ -118,7 +118,7 @@ configure(['core', 'bukkit', 'forge', 'sponge'].collect { project(":worldedit-$i
|
|||||||
archives javadocJar
|
archives javadocJar
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(name.equals('worldedit-forge') || name.equals('worldedit-sponge'))) {
|
if (name == "worldedit-core" || name == "worldedit-bukkit") {
|
||||||
task sourcesJar(type: Jar, dependsOn: classes) {
|
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||||
classifier = 'sources'
|
classifier = 'sources'
|
||||||
from sourceSets.main.allSource
|
from sourceSets.main.allSource
|
||||||
@ -144,7 +144,7 @@ configure(['core', 'bukkit', 'forge', 'sponge'].collect { project(":worldedit-$i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configure(['bukkit', 'forge', 'sponge'].collect { project(":worldedit-$it") }) {
|
configure(['bukkit', 'forge', 'sponge', 'fabric'].collect { project(":worldedit-$it") }) {
|
||||||
shadowJar {
|
shadowJar {
|
||||||
classifier 'dist'
|
classifier 'dist'
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -60,6 +60,18 @@
|
|||||||
<allow pkg="com.mojang.datafixers" />
|
<allow pkg="com.mojang.datafixers" />
|
||||||
</subpackage>
|
</subpackage>
|
||||||
|
|
||||||
|
<subpackage name="fabric">
|
||||||
|
<allow pkg="net.minecraft"/>
|
||||||
|
<allow pkg="net.fabricmc"/>
|
||||||
|
<allow pkg="com.mojang.authlib"/>
|
||||||
|
<allow pkg="org.apache.logging.log4j"/>
|
||||||
|
<allow pkg="org.lwjgl"/>
|
||||||
|
<allow pkg="io.netty.buffer"/>
|
||||||
|
<allow pkg="org.spongepowered" />
|
||||||
|
<allow pkg="com.mojang.brigadier" />
|
||||||
|
<allow pkg="com.mojang.datafixers" />
|
||||||
|
</subpackage>
|
||||||
|
|
||||||
<subpackage name="sponge">
|
<subpackage name="sponge">
|
||||||
<allow pkg="net.minecraft"/>
|
<allow pkg="net.minecraft"/>
|
||||||
<allow pkg="com.google.inject" />
|
<allow pkg="com.google.inject" />
|
||||||
|
@ -2,7 +2,7 @@ rootProject.name = 'worldedit'
|
|||||||
|
|
||||||
include 'worldedit-libs'
|
include 'worldedit-libs'
|
||||||
|
|
||||||
['bukkit', 'core', 'forge', 'sponge'].forEach {
|
['bukkit', 'core', 'forge', 'sponge', 'fabric'].forEach {
|
||||||
include "worldedit-libs:$it"
|
include "worldedit-libs:$it"
|
||||||
include "worldedit-$it"
|
include "worldedit-$it"
|
||||||
}
|
}
|
||||||
|
105
worldedit-fabric/build.gradle
Normale Datei
105
worldedit-fabric/build.gradle
Normale Datei
@ -0,0 +1,105 @@
|
|||||||
|
import net.fabricmc.loom.task.RemapJarTask
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
maven {
|
||||||
|
name = 'Fabric'
|
||||||
|
url = 'https://maven.fabricmc.net/'
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name = 'sponge'
|
||||||
|
url = 'https://repo.spongepowered.org/maven'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath 'net.fabricmc:fabric-loom:0.2.4-SNAPSHOT'
|
||||||
|
classpath 'org.spongepowered:mixin:0.7.11-SNAPSHOT'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'eclipse'
|
||||||
|
apply plugin: 'fabric-loom'
|
||||||
|
|
||||||
|
def minecraftVersion = "1.14.2"
|
||||||
|
def fabricVersion = "0.3.0+build.185"
|
||||||
|
def yarnMappings = "1.14.2+build.7"
|
||||||
|
def loaderVersion = "0.4.8+build.155"
|
||||||
|
|
||||||
|
configurations.all { Configuration it ->
|
||||||
|
it.resolutionStrategy { ResolutionStrategy rs ->
|
||||||
|
rs.force("com.google.guava:guava:21.0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(':worldedit-core')
|
||||||
|
compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1'
|
||||||
|
|
||||||
|
minecraft "com.mojang:minecraft:${minecraftVersion}"
|
||||||
|
mappings "net.fabricmc:yarn:${yarnMappings}"
|
||||||
|
modCompile "net.fabricmc:fabric-loader:${loaderVersion}"
|
||||||
|
|
||||||
|
modCompile "net.fabricmc.fabric-api:fabric-api:${fabricVersion}"
|
||||||
|
|
||||||
|
testCompile group: 'org.mockito', name: 'mockito-core', version: '1.9.0-rc1'
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceCompatibility = 1.8
|
||||||
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
|
minecraft {
|
||||||
|
}
|
||||||
|
|
||||||
|
project.archivesBaseName = "${project.archivesBaseName}-mc${minecraftVersion}"
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
// this will ensure that this task is redone when the versions change.
|
||||||
|
inputs.property 'version', project.internalVersion
|
||||||
|
|
||||||
|
from(sourceSets.main.resources.srcDirs) {
|
||||||
|
include "fabric.mod.json"
|
||||||
|
expand "version": project.internalVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy everything else except the mod json
|
||||||
|
from(sourceSets.main.resources.srcDirs) {
|
||||||
|
exclude "fabric.mod.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar",
|
||||||
|
"WorldEdit-Version": version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowJar {
|
||||||
|
classifier = 'dist-dev'
|
||||||
|
dependencies {
|
||||||
|
relocate "org.slf4j", "com.sk89q.worldedit.slf4j"
|
||||||
|
relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge"
|
||||||
|
|
||||||
|
include(dependency('org.slf4j:slf4j-api'))
|
||||||
|
include(dependency("org.apache.logging.log4j:log4j-slf4j-impl"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task deobfJar(type: Jar) {
|
||||||
|
from sourceSets.main.output
|
||||||
|
classifier = 'dev'
|
||||||
|
}
|
||||||
|
|
||||||
|
artifacts {
|
||||||
|
archives deobfJar
|
||||||
|
}
|
||||||
|
|
||||||
|
task shadowJarRemap(type: RemapJarTask) {
|
||||||
|
input shadowJar.archivePath
|
||||||
|
output new File(shadowJar.archivePath.getAbsolutePath().replaceFirst('-dev\\.jar$', ".jar"))
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowJarRemap.dependsOn(shadowJar)
|
||||||
|
build.dependsOn(shadowJarRemap)
|
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import static com.sk89q.worldedit.fabric.FabricAdapter.adaptPlayer;
|
||||||
|
import static net.minecraft.server.command.CommandManager.argument;
|
||||||
|
import static net.minecraft.server.command.CommandManager.literal;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.mojang.brigadier.Command;
|
||||||
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import com.mojang.brigadier.context.StringRange;
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import com.mojang.brigadier.suggestion.Suggestion;
|
||||||
|
import com.mojang.brigadier.suggestion.Suggestions;
|
||||||
|
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||||
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
|
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
|
||||||
|
import com.sk89q.worldedit.extension.platform.Actor;
|
||||||
|
import com.sk89q.worldedit.internal.util.Substring;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import org.enginehub.piston.inject.InjectedValueStore;
|
||||||
|
import org.enginehub.piston.inject.Key;
|
||||||
|
import org.enginehub.piston.inject.MapBackedValueStore;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
|
||||||
|
public final class CommandWrapper {
|
||||||
|
|
||||||
|
private CommandWrapper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register(CommandDispatcher<ServerCommandSource> dispatcher, org.enginehub.piston.Command command) {
|
||||||
|
ImmutableList.Builder<String> aliases = ImmutableList.builder();
|
||||||
|
aliases.add(command.getName()).addAll(command.getAliases());
|
||||||
|
|
||||||
|
Command<ServerCommandSource> commandRunner =
|
||||||
|
ctx -> {
|
||||||
|
WorldEdit.getInstance().getEventBus().post(new com.sk89q.worldedit.event.platform.CommandEvent(
|
||||||
|
adaptPlayer(ctx.getSource().getPlayer()),
|
||||||
|
ctx.getInput()
|
||||||
|
));
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (String alias : aliases.build()) {
|
||||||
|
LiteralArgumentBuilder<ServerCommandSource> base = literal(alias).executes(commandRunner)
|
||||||
|
.then(argument("args", StringArgumentType.greedyString())
|
||||||
|
.suggests(CommandWrapper::suggest)
|
||||||
|
.executes(commandRunner));
|
||||||
|
if (command.getCondition() != org.enginehub.piston.Command.Condition.TRUE) {
|
||||||
|
base.requires(requirementsFor(command));
|
||||||
|
}
|
||||||
|
dispatcher.register(base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Predicate<ServerCommandSource> requirementsFor(org.enginehub.piston.Command mapping) {
|
||||||
|
return ctx -> {
|
||||||
|
final Entity entity = ctx.getEntity();
|
||||||
|
if (!(entity instanceof ServerPlayerEntity)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
final Actor actor = FabricAdapter.adaptPlayer(((ServerPlayerEntity) entity));
|
||||||
|
InjectedValueStore store = MapBackedValueStore.create();
|
||||||
|
store.injectValue(Key.of(Actor.class), context -> Optional.of(actor));
|
||||||
|
return mapping.getCondition().satisfied(store);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CompletableFuture<Suggestions> suggest(CommandContext<ServerCommandSource> context,
|
||||||
|
SuggestionsBuilder builder) throws CommandSyntaxException {
|
||||||
|
CommandSuggestionEvent event = new CommandSuggestionEvent(
|
||||||
|
FabricAdapter.adaptPlayer(context.getSource().getPlayer()),
|
||||||
|
builder.getInput()
|
||||||
|
);
|
||||||
|
WorldEdit.getInstance().getEventBus().post(event);
|
||||||
|
List<Substring> suggestions = event.getSuggestions();
|
||||||
|
|
||||||
|
ImmutableList.Builder<Suggestion> result = ImmutableList.builder();
|
||||||
|
|
||||||
|
for (Substring suggestion : suggestions) {
|
||||||
|
String suggestionText = suggestion.getSubstring();
|
||||||
|
// If at end, we are actually suggesting the next argument
|
||||||
|
// Ensure there is a space!
|
||||||
|
if (suggestion.getStart() == suggestion.getEnd()
|
||||||
|
&& suggestion.getEnd() == builder.getInput().length()
|
||||||
|
&& !builder.getInput().endsWith(" ")) {
|
||||||
|
suggestionText = " " + suggestionText;
|
||||||
|
}
|
||||||
|
result.add(new Suggestion(
|
||||||
|
StringRange.between(suggestion.getStart(), suggestion.getEnd()),
|
||||||
|
suggestionText
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return CompletableFuture.completedFuture(
|
||||||
|
Suggestions.create(builder.getInput(), result.build())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,241 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.jnbt.Tag;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||||
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
|
import com.sk89q.worldedit.math.Vector3;
|
||||||
|
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.World;
|
||||||
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
|
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockType;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||||
|
import com.sk89q.worldedit.world.item.ItemType;
|
||||||
|
import com.sk89q.worldedit.world.item.ItemTypes;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.state.StateFactory;
|
||||||
|
import net.minecraft.state.property.DirectionProperty;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.StringIdentifiable;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.util.registry.Registry;
|
||||||
|
import net.minecraft.world.biome.Biome;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public final class FabricAdapter {
|
||||||
|
|
||||||
|
private FabricAdapter() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static World adapt(net.minecraft.world.World world) {
|
||||||
|
return new FabricWorld(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Biome adapt(BiomeType biomeType) {
|
||||||
|
return Registry.BIOME.get(new Identifier(biomeType.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BiomeType adapt(Biome biome) {
|
||||||
|
return BiomeTypes.get(Registry.BIOME.getId(biome).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 adapt(Vec3d vector) {
|
||||||
|
return Vector3.at(vector.x, vector.y, vector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockVector3 adapt(BlockPos pos) {
|
||||||
|
return BlockVector3.at(pos.getX(), pos.getY(), pos.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vec3d toVec3(BlockVector3 vector) {
|
||||||
|
return new Vec3d(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.minecraft.util.math.Direction adapt(Direction face) {
|
||||||
|
switch (face) {
|
||||||
|
case NORTH: return net.minecraft.util.math.Direction.NORTH;
|
||||||
|
case SOUTH: return net.minecraft.util.math.Direction.SOUTH;
|
||||||
|
case WEST: return net.minecraft.util.math.Direction.WEST;
|
||||||
|
case EAST: return net.minecraft.util.math.Direction.EAST;
|
||||||
|
case DOWN: return net.minecraft.util.math.Direction.DOWN;
|
||||||
|
case UP:
|
||||||
|
default:
|
||||||
|
return net.minecraft.util.math.Direction.UP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Direction adaptEnumFacing(net.minecraft.util.math.Direction face) {
|
||||||
|
switch (face) {
|
||||||
|
case NORTH: return Direction.NORTH;
|
||||||
|
case SOUTH: return Direction.SOUTH;
|
||||||
|
case WEST: return Direction.WEST;
|
||||||
|
case EAST: return Direction.EAST;
|
||||||
|
case DOWN: return Direction.DOWN;
|
||||||
|
case UP:
|
||||||
|
default:
|
||||||
|
return Direction.UP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockPos toBlockPos(BlockVector3 vector) {
|
||||||
|
return new BlockPos(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Property<?> adaptProperty(net.minecraft.state.property.Property<?> property) {
|
||||||
|
if (property instanceof net.minecraft.state.property.BooleanProperty) {
|
||||||
|
return new BooleanProperty(property.getName(), ImmutableList.copyOf(((net.minecraft.state.property.BooleanProperty) property).getValues()));
|
||||||
|
}
|
||||||
|
if (property instanceof net.minecraft.state.property.IntProperty) {
|
||||||
|
return new IntegerProperty(property.getName(), ImmutableList.copyOf(((net.minecraft.state.property.IntProperty) property).getValues()));
|
||||||
|
}
|
||||||
|
if (property instanceof DirectionProperty) {
|
||||||
|
return new DirectionalProperty(property.getName(), ((DirectionProperty) property).getValues().stream()
|
||||||
|
.map(FabricAdapter::adaptEnumFacing)
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
if (property instanceof net.minecraft.state.property.EnumProperty) {
|
||||||
|
// Note: do not make x.asString a method reference.
|
||||||
|
// It will cause runtime bootstrap exceptions.
|
||||||
|
return new EnumProperty(property.getName(), ((net.minecraft.state.property.EnumProperty<?>) property).getValues().stream()
|
||||||
|
.map(x -> x.asString())
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
return new PropertyAdapter<>(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<Property<?>, Object> adaptProperties(BlockType block, Map<net.minecraft.state.property.Property<?>, Comparable<?>> mcProps) {
|
||||||
|
Map<Property<?>, Object> props = new TreeMap<>(Comparator.comparing(Property::getName));
|
||||||
|
for (Map.Entry<net.minecraft.state.property.Property<?>, Comparable<?>> prop : mcProps.entrySet()) {
|
||||||
|
Object value = prop.getValue();
|
||||||
|
if (prop.getKey() instanceof DirectionProperty) {
|
||||||
|
value = adaptEnumFacing((net.minecraft.util.math.Direction) value);
|
||||||
|
} else if (prop.getKey() instanceof net.minecraft.state.property.EnumProperty) {
|
||||||
|
value = ((StringIdentifiable) value).asString();
|
||||||
|
}
|
||||||
|
props.put(block.getProperty(prop.getKey().getName()), value);
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static net.minecraft.block.BlockState applyProperties(StateFactory<Block, net.minecraft.block.BlockState> stateContainer,
|
||||||
|
net.minecraft.block.BlockState newState, Map<Property<?>, Object> states) {
|
||||||
|
for (Map.Entry<Property<?>, Object> state : states.entrySet()) {
|
||||||
|
net.minecraft.state.property.Property property = stateContainer.getProperty(state.getKey().getName());
|
||||||
|
Comparable value = (Comparable) state.getValue();
|
||||||
|
// we may need to adapt this value, depending on the source prop
|
||||||
|
if (property instanceof DirectionProperty) {
|
||||||
|
Direction dir = (Direction) value;
|
||||||
|
value = adapt(dir);
|
||||||
|
} else if (property instanceof net.minecraft.state.property.EnumProperty) {
|
||||||
|
String enumName = (String) value;
|
||||||
|
value = ((net.minecraft.state.property.EnumProperty<?>) property).getValue((String) value).orElseGet(() -> {
|
||||||
|
throw new IllegalStateException("Enum property " + property.getName() + " does not contain " + enumName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
newState = newState.with(property, value);
|
||||||
|
}
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.minecraft.block.BlockState adapt(BlockState blockState) {
|
||||||
|
Block mcBlock = adapt(blockState.getBlockType());
|
||||||
|
net.minecraft.block.BlockState newState = mcBlock.getDefaultState();
|
||||||
|
Map<Property<?>, Object> states = blockState.getStates();
|
||||||
|
return applyProperties(mcBlock.getStateFactory(), newState, states);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockState adapt(net.minecraft.block.BlockState blockState) {
|
||||||
|
BlockType blockType = adapt(blockState.getBlock());
|
||||||
|
return blockType.getState(adaptProperties(blockType, blockState.getEntries()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Block adapt(BlockType blockType) {
|
||||||
|
return Registry.BLOCK.get(new Identifier(blockType.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockType adapt(Block block) {
|
||||||
|
return BlockTypes.get(Registry.BLOCK.getId(block).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Item adapt(ItemType itemType) {
|
||||||
|
return Registry.ITEM.get(new Identifier(itemType.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemType adapt(Item item) {
|
||||||
|
return ItemTypes.get(Registry.ITEM.getId(item).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemStack adapt(BaseItemStack baseItemStack) {
|
||||||
|
net.minecraft.nbt.CompoundTag fabricCompound = null;
|
||||||
|
if (baseItemStack.getNbtData() != null) {
|
||||||
|
fabricCompound = NBTConverter.toNative(baseItemStack.getNbtData());
|
||||||
|
}
|
||||||
|
final ItemStack itemStack = new ItemStack(adapt(baseItemStack.getType()), baseItemStack.getAmount());
|
||||||
|
itemStack.setTag(fabricCompound);
|
||||||
|
return itemStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BaseItemStack adapt(ItemStack itemStack) {
|
||||||
|
CompoundTag tag = NBTConverter.fromNative(itemStack.toTag(new net.minecraft.nbt.CompoundTag()));
|
||||||
|
if (tag.getValue().isEmpty()) {
|
||||||
|
tag = null;
|
||||||
|
} else {
|
||||||
|
final Tag tagTag = tag.getValue().get("tag");
|
||||||
|
if (tagTag instanceof CompoundTag) {
|
||||||
|
tag = ((CompoundTag) tagTag);
|
||||||
|
} else {
|
||||||
|
tag = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new BaseItemStack(adapt(itemStack.getItem()), tag, itemStack.getCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the WorldEdit proxy for the given player.
|
||||||
|
*
|
||||||
|
* @param player the player
|
||||||
|
* @return the WorldEdit player
|
||||||
|
*/
|
||||||
|
public static FabricPlayer adaptPlayer(ServerPlayerEntity player) {
|
||||||
|
checkNotNull(player);
|
||||||
|
return new FabricPlayer(player);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.world.biome.BiomeData;
|
||||||
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
|
import com.sk89q.worldedit.world.registry.BiomeRegistry;
|
||||||
|
import net.minecraft.world.biome.Biome;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides access to biome data in Fabric.
|
||||||
|
*/
|
||||||
|
class FabricBiomeRegistry implements BiomeRegistry {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BiomeData getData(BiomeType biome) {
|
||||||
|
return new FabricBiomeData(FabricAdapter.adapt(biome));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cached biome data information.
|
||||||
|
*/
|
||||||
|
private static class FabricBiomeData implements BiomeData {
|
||||||
|
private final Biome biome;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance.
|
||||||
|
*
|
||||||
|
* @param biome the base biome
|
||||||
|
*/
|
||||||
|
private FabricBiomeData(Biome biome) {
|
||||||
|
this.biome = biome;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return biome.getTextComponent().getString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.registry.Category;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockType;
|
||||||
|
import com.sk89q.worldedit.world.registry.BlockCategoryRegistry;
|
||||||
|
import net.minecraft.tag.BlockTags;
|
||||||
|
import net.minecraft.tag.Tag;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class FabricBlockCategoryRegistry implements BlockCategoryRegistry {
|
||||||
|
@Override
|
||||||
|
public Set<BlockType> getCategorisedByName(String category) {
|
||||||
|
return Optional.ofNullable(BlockTags.getContainer().get(new Identifier(category)))
|
||||||
|
.map(Tag::values).orElse(Collections.emptySet())
|
||||||
|
.stream().map(FabricAdapter::adapt).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<BlockType> getAll(Category<BlockType> category) {
|
||||||
|
return getCategorisedByName(category.getId());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||||
|
import com.sk89q.worldedit.world.registry.PassthroughBlockMaterial;
|
||||||
|
import net.minecraft.block.Material;
|
||||||
|
import net.minecraft.block.piston.PistonBehavior;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fabric 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 FabricBlockMaterial extends PassthroughBlockMaterial {
|
||||||
|
|
||||||
|
private final Material delegate;
|
||||||
|
|
||||||
|
public FabricBlockMaterial(Material delegate, @Nullable BlockMaterial secondary) {
|
||||||
|
super(secondary);
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAir() {
|
||||||
|
return delegate == Material.AIR || super.isAir();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpaque() {
|
||||||
|
return delegate.blocksLight();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLiquid() {
|
||||||
|
return delegate.isLiquid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSolid() {
|
||||||
|
return delegate.isSolid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFragileWhenPushed() {
|
||||||
|
return delegate.getPistonBehavior() == PistonBehavior.DESTROY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUnpushable() {
|
||||||
|
return delegate.getPistonBehavior() == PistonBehavior.BLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMovementBlocker() {
|
||||||
|
return delegate.blocksMovement();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBurnable() {
|
||||||
|
return delegate.isBurnable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isToolRequired() {
|
||||||
|
return !delegate.canBreakByHand();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReplacedDuringPlacement() {
|
||||||
|
return delegate.isReplaceable();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.registry.state.Property;
|
||||||
|
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.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.Material;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
public class FabricBlockRegistry extends BundledBlockRegistry {
|
||||||
|
|
||||||
|
private Map<Material, FabricBlockMaterial> materialMap = new HashMap<>();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getName(BlockType blockType) {
|
||||||
|
Block block = FabricAdapter.adapt(blockType);
|
||||||
|
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
|
||||||
|
return block.getTextComponent().getFormattedText();
|
||||||
|
} else {
|
||||||
|
return super.getName(blockType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockMaterial getMaterial(BlockType blockType) {
|
||||||
|
Block block = FabricAdapter.adapt(blockType);
|
||||||
|
return materialMap.computeIfAbsent(block.getDefaultState().getMaterial(),
|
||||||
|
m -> new FabricBlockMaterial(m, super.getMaterial(blockType)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
|
||||||
|
Block block = FabricAdapter.adapt(blockType);
|
||||||
|
Map<String, Property<?>> map = new TreeMap<>();
|
||||||
|
Collection<net.minecraft.state.property.Property<?>> propertyKeys = block
|
||||||
|
.getDefaultState()
|
||||||
|
.getProperties();
|
||||||
|
for (net.minecraft.state.property.Property<?> key : propertyKeys) {
|
||||||
|
map.put(key.getName(), FabricAdapter.adaptProperty(key));
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OptionalInt getInternalBlockStateId(BlockState state) {
|
||||||
|
net.minecraft.block.BlockState equivalent = FabricAdapter.adapt(state);
|
||||||
|
return OptionalInt.of(Block.getRawIdFromState(equivalent));
|
||||||
|
}
|
||||||
|
}
|
@ -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 Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.util.PropertiesConfiguration;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class FabricConfiguration extends PropertiesConfiguration {
|
||||||
|
|
||||||
|
public boolean creativeEnable = false;
|
||||||
|
public boolean cheatMode = false;
|
||||||
|
|
||||||
|
public FabricConfiguration(FabricWorldEdit mod) {
|
||||||
|
super(new File(mod.getWorkingDir(), "worldedit.properties"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void loadExtra() {
|
||||||
|
creativeEnable = getBool("use-in-creative", false);
|
||||||
|
cheatMode = getBool("cheat-mode", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getWorkingDirectory() {
|
||||||
|
return FabricWorldEdit.inst.getWorkingDir();
|
||||||
|
}
|
||||||
|
}
|
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.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.math.Vector3;
|
||||||
|
import com.sk89q.worldedit.util.Location;
|
||||||
|
import com.sk89q.worldedit.world.NullWorld;
|
||||||
|
import com.sk89q.worldedit.world.entity.EntityTypes;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.registry.Registry;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
class FabricEntity implements Entity {
|
||||||
|
|
||||||
|
private final WeakReference<net.minecraft.entity.Entity> entityRef;
|
||||||
|
|
||||||
|
FabricEntity(net.minecraft.entity.Entity entity) {
|
||||||
|
checkNotNull(entity);
|
||||||
|
this.entityRef = new WeakReference<>(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseEntity getState() {
|
||||||
|
net.minecraft.entity.Entity entity = entityRef.get();
|
||||||
|
if (entity != null) {
|
||||||
|
Identifier id = Registry.ENTITY_TYPE.getId(entity.getType());
|
||||||
|
CompoundTag tag = new CompoundTag();
|
||||||
|
entity.toTag(tag);
|
||||||
|
return new BaseEntity(EntityTypes.get(id.toString()), NBTConverter.fromNative(tag));
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location getLocation() {
|
||||||
|
net.minecraft.entity.Entity entity = entityRef.get();
|
||||||
|
if (entity != null) {
|
||||||
|
Vector3 position = Vector3.at(entity.x, entity.y, entity.z);
|
||||||
|
float yaw = entity.yaw;
|
||||||
|
float pitch = entity.pitch;
|
||||||
|
|
||||||
|
return new Location(FabricAdapter.adapt(entity.world), position, yaw, pitch);
|
||||||
|
} else {
|
||||||
|
return new Location(NullWorld.getInstance());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setLocation(Location location) {
|
||||||
|
// TODO unused atm
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Extent getExtent() {
|
||||||
|
net.minecraft.entity.Entity entity = entityRef.get();
|
||||||
|
if (entity != null) {
|
||||||
|
return FabricAdapter.adapt(entity.world);
|
||||||
|
} else {
|
||||||
|
return NullWorld.getInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove() {
|
||||||
|
net.minecraft.entity.Entity entity = entityRef.get();
|
||||||
|
if (entity != null) {
|
||||||
|
entity.remove();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public <T> T getFacet(Class<? extends T> cls) {
|
||||||
|
net.minecraft.entity.Entity entity = entityRef.get();
|
||||||
|
if (entity != null) {
|
||||||
|
if (EntityProperties.class.isAssignableFrom(cls)) {
|
||||||
|
return (T) new FabricEntityProperties(entity);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.entity.metadata.EntityProperties;
|
||||||
|
import net.minecraft.entity.EnderEyeEntity;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.ExperienceOrbEntity;
|
||||||
|
import net.minecraft.entity.FallingBlockEntity;
|
||||||
|
import net.minecraft.entity.ItemEntity;
|
||||||
|
import net.minecraft.entity.Npc;
|
||||||
|
import net.minecraft.entity.TntEntity;
|
||||||
|
import net.minecraft.entity.boss.dragon.EnderDragonEntity;
|
||||||
|
import net.minecraft.entity.decoration.ArmorStandEntity;
|
||||||
|
import net.minecraft.entity.decoration.ItemFrameEntity;
|
||||||
|
import net.minecraft.entity.decoration.painting.PaintingEntity;
|
||||||
|
import net.minecraft.entity.mob.AmbientEntity;
|
||||||
|
import net.minecraft.entity.mob.MobEntity;
|
||||||
|
import net.minecraft.entity.passive.AnimalEntity;
|
||||||
|
import net.minecraft.entity.passive.TameableEntity;
|
||||||
|
import net.minecraft.entity.passive.GolemEntity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.entity.projectile.Projectile;
|
||||||
|
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
|
||||||
|
import net.minecraft.entity.vehicle.BoatEntity;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.village.Trader;
|
||||||
|
|
||||||
|
public class FabricEntityProperties implements EntityProperties {
|
||||||
|
|
||||||
|
private final Entity entity;
|
||||||
|
|
||||||
|
public FabricEntityProperties(Entity entity) {
|
||||||
|
checkNotNull(entity);
|
||||||
|
this.entity = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPlayerDerived() {
|
||||||
|
return entity instanceof PlayerEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isProjectile() {
|
||||||
|
return entity instanceof EnderEyeEntity || entity instanceof Projectile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isItem() {
|
||||||
|
return entity instanceof ItemEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFallingBlock() {
|
||||||
|
return entity instanceof FallingBlockEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPainting() {
|
||||||
|
return entity instanceof PaintingEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isItemFrame() {
|
||||||
|
return entity instanceof ItemFrameEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBoat() {
|
||||||
|
return entity instanceof BoatEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMinecart() {
|
||||||
|
return entity instanceof AbstractMinecartEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTNT() {
|
||||||
|
return entity instanceof TntEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExperienceOrb() {
|
||||||
|
return entity instanceof ExperienceOrbEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLiving() {
|
||||||
|
return entity instanceof MobEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAnimal() {
|
||||||
|
return entity instanceof AnimalEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAmbient() {
|
||||||
|
return entity instanceof AmbientEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNPC() {
|
||||||
|
return entity instanceof Npc || entity instanceof Trader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isGolem() {
|
||||||
|
return entity instanceof GolemEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTamed() {
|
||||||
|
return entity instanceof TameableEntity && ((TameableEntity) entity).isTamed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTagged() {
|
||||||
|
return entity.hasCustomName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isArmorStand() {
|
||||||
|
return entity instanceof ArmorStandEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPasteable() {
|
||||||
|
return !(entity instanceof ServerPlayerEntity || entity instanceof EnderDragonEntity);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.registry.Category;
|
||||||
|
import com.sk89q.worldedit.world.item.ItemType;
|
||||||
|
import com.sk89q.worldedit.world.registry.ItemCategoryRegistry;
|
||||||
|
import net.minecraft.tag.ItemTags;
|
||||||
|
import net.minecraft.tag.Tag;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class FabricItemCategoryRegistry implements ItemCategoryRegistry {
|
||||||
|
@Override
|
||||||
|
public Set<ItemType> getCategorisedByName(String category) {
|
||||||
|
return Optional.ofNullable(ItemTags.getContainer().get(new Identifier(category)))
|
||||||
|
.map(Tag::values).orElse(Collections.emptySet())
|
||||||
|
.stream().map(FabricAdapter::adapt).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<ItemType> getAll(Category<ItemType> category) {
|
||||||
|
return getCategorisedByName(category.getId());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.world.item.ItemType;
|
||||||
|
import com.sk89q.worldedit.world.registry.BundledItemRegistry;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.client.resource.language.I18n;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class FabricItemRegistry extends BundledItemRegistry {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getName(ItemType itemType) {
|
||||||
|
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
|
||||||
|
final Item item = FabricAdapter.adapt(itemType);
|
||||||
|
return I18n.translate(item.getTranslationKey());
|
||||||
|
}
|
||||||
|
return super.getName(itemType);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.world.GameMode;
|
||||||
|
|
||||||
|
public interface FabricPermissionsProvider {
|
||||||
|
|
||||||
|
boolean hasPermission(ServerPlayerEntity player, String permission);
|
||||||
|
|
||||||
|
void registerPermission(String permission);
|
||||||
|
|
||||||
|
class VanillaPermissionsProvider implements FabricPermissionsProvider {
|
||||||
|
|
||||||
|
private FabricPlatform platform;
|
||||||
|
|
||||||
|
public VanillaPermissionsProvider(FabricPlatform platform) {
|
||||||
|
this.platform = platform;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(ServerPlayerEntity player, String permission) {
|
||||||
|
FabricConfiguration configuration = platform.getConfiguration();
|
||||||
|
return configuration.cheatMode ||
|
||||||
|
player.server.getPlayerManager().isOperator(player.getGameProfile()) ||
|
||||||
|
(configuration.creativeEnable && player.interactionManager.getGameMode() == GameMode.CREATIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerPermission(String permission) {}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.command.util.PermissionCondition;
|
||||||
|
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.world.DataFixer;
|
||||||
|
import com.sk89q.worldedit.world.World;
|
||||||
|
import com.sk89q.worldedit.world.registry.Registries;
|
||||||
|
import net.minecraft.SharedConstants;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.PlayerManager;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.registry.Registry;
|
||||||
|
import org.enginehub.piston.Command;
|
||||||
|
import org.enginehub.piston.CommandManager;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
|
class FabricPlatform extends AbstractPlatform implements MultiUserPlatform {
|
||||||
|
|
||||||
|
private final FabricWorldEdit mod;
|
||||||
|
private final MinecraftServer server;
|
||||||
|
private final FabricDataFixer dataFixer;
|
||||||
|
private boolean hookingEvents = false;
|
||||||
|
|
||||||
|
FabricPlatform(FabricWorldEdit mod, MinecraftServer server) {
|
||||||
|
this.mod = mod;
|
||||||
|
this.server = server;
|
||||||
|
this.dataFixer = new FabricDataFixer(getDataVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isHookingEvents() {
|
||||||
|
return hookingEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Registries getRegistries() {
|
||||||
|
return FabricRegistries.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDataVersion() {
|
||||||
|
return SharedConstants.getGameVersion().getWorldVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataFixer getDataFixer() {
|
||||||
|
return dataFixer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidMobType(String type) {
|
||||||
|
return Registry.ENTITY_TYPE.containsId(new Identifier(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reload() {
|
||||||
|
getConfiguration().load();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int schedule(long delay, long period, Runnable task) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<? extends World> getWorlds() {
|
||||||
|
Iterable<ServerWorld> worlds = server.getWorlds();
|
||||||
|
List<World> ret = new ArrayList<>();
|
||||||
|
for (ServerWorld world : worlds) {
|
||||||
|
ret.add(new FabricWorld(world));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Player matchPlayer(Player player) {
|
||||||
|
if (player instanceof FabricPlayer) {
|
||||||
|
return player;
|
||||||
|
} else {
|
||||||
|
ServerPlayerEntity entity = server.getPlayerManager().getPlayer(player.getName());
|
||||||
|
return entity != null ? new FabricPlayer(entity) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public World matchWorld(World world) {
|
||||||
|
if (world instanceof FabricWorld) {
|
||||||
|
return world;
|
||||||
|
} else {
|
||||||
|
for (ServerWorld ws : server.getWorlds()) {
|
||||||
|
if (ws.getLevelProperties().getLevelName().equals(world.getName())) {
|
||||||
|
return new FabricWorld(ws);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerCommands(CommandManager manager) {
|
||||||
|
if (server == null) return;
|
||||||
|
net.minecraft.server.command.CommandManager mcMan = server.getCommandManager();
|
||||||
|
|
||||||
|
for (Command command : manager.getAllCommands().collect(toList())) {
|
||||||
|
CommandWrapper.register(mcMan.getDispatcher(), command);
|
||||||
|
Set<String> perms = command.getCondition().as(PermissionCondition.class)
|
||||||
|
.map(PermissionCondition::getPermissions)
|
||||||
|
.orElseGet(Collections::emptySet);
|
||||||
|
if (!perms.isEmpty()) {
|
||||||
|
perms.forEach(FabricWorldEdit.inst.getPermissionsProvider()::registerPermission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerGameHooks() {
|
||||||
|
// We registered the events already anyway, so we just 'turn them on'
|
||||||
|
hookingEvents = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FabricConfiguration getConfiguration() {
|
||||||
|
return mod.getConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVersion() {
|
||||||
|
return mod.getInternalVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPlatformName() {
|
||||||
|
return "Fabric-Official";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPlatformVersion() {
|
||||||
|
return mod.getInternalVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Capability, Preference> getCapabilities() {
|
||||||
|
Map<Capability, Preference> capabilities = new EnumMap<>(Capability.class);
|
||||||
|
capabilities.put(Capability.CONFIGURATION, Preference.PREFER_OTHERS);
|
||||||
|
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 Collection<Actor> getConnectedUsers() {
|
||||||
|
List<Actor> users = new ArrayList<>();
|
||||||
|
PlayerManager scm = server.getPlayerManager();
|
||||||
|
for (ServerPlayerEntity entity : scm.getPlayerList()) {
|
||||||
|
if (entity != null) {
|
||||||
|
users.add(new FabricPlayer(entity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,267 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
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.fabric.net.handler.WECUIPacketHandler;
|
||||||
|
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.util.HandSide;
|
||||||
|
import com.sk89q.worldedit.util.Location;
|
||||||
|
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||||
|
import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer;
|
||||||
|
import com.sk89q.worldedit.world.World;
|
||||||
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import net.minecraft.ChatFormat;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.client.network.packet.BlockEntityUpdateS2CPacket;
|
||||||
|
import net.minecraft.client.network.packet.BlockUpdateS2CPacket;
|
||||||
|
import net.minecraft.client.network.packet.CustomPayloadS2CPacket;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.network.chat.TextComponent;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.PacketByteBuf;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class FabricPlayer extends AbstractPlayerActor {
|
||||||
|
|
||||||
|
// see ClientPlayNetHandler: search for "invalid update packet", lots of hardcoded consts
|
||||||
|
private static final int STRUCTURE_BLOCK_PACKET_ID = 7;
|
||||||
|
private final ServerPlayerEntity player;
|
||||||
|
|
||||||
|
protected FabricPlayer(ServerPlayerEntity player) {
|
||||||
|
this.player = player;
|
||||||
|
ThreadSafeCache.getInstance().getOnlineIds().add(getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUniqueId() {
|
||||||
|
return player.getUuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseItemStack getItemInHand(HandSide handSide) {
|
||||||
|
ItemStack is = this.player.getStackInHand(handSide == HandSide.MAIN_HAND ? Hand.MAIN_HAND : Hand.OFF_HAND);
|
||||||
|
return FabricAdapter.adapt(is);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return this.player.getName().getFormattedText();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseEntity getState() {
|
||||||
|
throw new UnsupportedOperationException("Cannot create a state from this object");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location getLocation() {
|
||||||
|
Vector3 position = Vector3.at(this.player.x, this.player.y, this.player.z);
|
||||||
|
return new Location(
|
||||||
|
FabricWorldEdit.inst.getWorld(this.player.world),
|
||||||
|
position,
|
||||||
|
this.player.yaw,
|
||||||
|
this.player.pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setLocation(Location location) {
|
||||||
|
// TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public com.sk89q.worldedit.world.World getWorld() {
|
||||||
|
return FabricWorldEdit.inst.getWorld(this.player.world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void giveItem(BaseItemStack itemStack) {
|
||||||
|
this.player.inventory.insertStack(FabricAdapter.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, "|");
|
||||||
|
}
|
||||||
|
PacketByteBuf buffer = new PacketByteBuf(Unpooled.copiedBuffer(send.getBytes(WECUIPacketHandler.UTF_8_CHARSET)));
|
||||||
|
CustomPayloadS2CPacket packet = new CustomPayloadS2CPacket(new Identifier(FabricWorldEdit.MOD_ID, FabricWorldEdit.CUI_PLUGIN_CHANNEL), buffer);
|
||||||
|
this.player.networkHandler.sendPacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printRaw(String msg) {
|
||||||
|
for (String part : msg.split("\n")) {
|
||||||
|
this.player.sendMessage(new TextComponent(part));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printDebug(String msg) {
|
||||||
|
sendColorized(msg, ChatFormat.GRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(String msg) {
|
||||||
|
sendColorized(msg, ChatFormat.LIGHT_PURPLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printError(String msg) {
|
||||||
|
sendColorized(msg, ChatFormat.RED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(Component component) {
|
||||||
|
this.player.sendMessage(net.minecraft.network.chat.Component.Serializer.fromJsonString(GsonComponentSerializer.INSTANCE.serialize(component)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendColorized(String msg, ChatFormat formatting) {
|
||||||
|
for (String part : msg.split("\n")) {
|
||||||
|
TextComponent component = new TextComponent(part);
|
||||||
|
component.getStyle().setColor(formatting);
|
||||||
|
this.player.sendMessage(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPosition(Vector3 pos, float pitch, float yaw) {
|
||||||
|
this.player.networkHandler.requestTeleport(pos.getX(), pos.getY(), pos.getZ(), yaw, pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getGroups() {
|
||||||
|
return new String[]{}; // WorldEditMod.inst.getPermissionsResolver().getGroups(this.player.username);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockBag getInventoryBlockBag() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(String perm) {
|
||||||
|
return FabricWorldEdit.inst.getPermissionsProvider().hasPermission(player, perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public <T> T getFacet(Class<? extends T> cls) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) {
|
||||||
|
World world = getWorld();
|
||||||
|
if (!(world instanceof FabricWorld)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BlockPos loc = FabricAdapter.toBlockPos(pos);
|
||||||
|
if (block == null) {
|
||||||
|
final BlockUpdateS2CPacket packetOut = new BlockUpdateS2CPacket(((FabricWorld) world).getWorld(), loc);
|
||||||
|
player.networkHandler.sendPacket(packetOut);
|
||||||
|
} else {
|
||||||
|
final BlockUpdateS2CPacket packetOut = new BlockUpdateS2CPacket();
|
||||||
|
PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer());
|
||||||
|
buf.writeBlockPos(loc);
|
||||||
|
buf.writeVarInt(Block.getRawIdFromState(FabricAdapter.adapt(block.toImmutableState())));
|
||||||
|
try {
|
||||||
|
packetOut.read(buf);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
player.networkHandler.sendPacket(packetOut);
|
||||||
|
if (block instanceof BaseBlock && block.getBlockType().equals(BlockTypes.STRUCTURE_BLOCK)) {
|
||||||
|
final BaseBlock baseBlock = (BaseBlock) block;
|
||||||
|
final CompoundTag nbtData = baseBlock.getNbtData();
|
||||||
|
if (nbtData != null) {
|
||||||
|
player.networkHandler.sendPacket(new BlockEntityUpdateS2CPacket(
|
||||||
|
new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()),
|
||||||
|
STRUCTURE_BLOCK_PACKET_ID,
|
||||||
|
NBTConverter.toNative(nbtData))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SessionKey getSessionKey() {
|
||||||
|
return new SessionKeyImpl(player.getUuid(), player.getName().getString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SessionKeyImpl implements SessionKey {
|
||||||
|
// If not static, this will leak a reference
|
||||||
|
|
||||||
|
private final UUID uuid;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import 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 Fabric platform.
|
||||||
|
*/
|
||||||
|
class FabricRegistries extends BundledRegistries {
|
||||||
|
|
||||||
|
private static final FabricRegistries INSTANCE = new FabricRegistries();
|
||||||
|
private final BlockRegistry blockRegistry = new FabricBlockRegistry();
|
||||||
|
private final BiomeRegistry biomeRegistry = new FabricBiomeRegistry();
|
||||||
|
private final ItemRegistry itemRegistry = new FabricItemRegistry();
|
||||||
|
private final BlockCategoryRegistry blockCategoryRegistry = new FabricBlockCategoryRegistry();
|
||||||
|
private final ItemCategoryRegistry itemCategoryRegistry = new FabricItemCategoryRegistry();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockRegistry getBlockRegistry() {
|
||||||
|
return blockRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BiomeRegistry getBiomeRegistry() {
|
||||||
|
return biomeRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemRegistry getItemRegistry() {
|
||||||
|
return itemRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockCategoryRegistry getBlockCategoryRegistry() {
|
||||||
|
return blockCategoryRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemCategoryRegistry getItemCategoryRegistry() {
|
||||||
|
return itemCategoryRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a static instance.
|
||||||
|
*
|
||||||
|
* @return an instance
|
||||||
|
*/
|
||||||
|
public static FabricRegistries getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,597 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.cache.CacheLoader;
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
|
import com.google.common.io.Files;
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.worldedit.EditSession;
|
||||||
|
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseItem;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||||
|
import com.sk89q.worldedit.entity.BaseEntity;
|
||||||
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
|
import com.sk89q.worldedit.internal.Constants;
|
||||||
|
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
||||||
|
import com.sk89q.worldedit.math.BlockVector2;
|
||||||
|
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.util.Direction;
|
||||||
|
import com.sk89q.worldedit.util.Location;
|
||||||
|
import com.sk89q.worldedit.util.TreeGenerator.TreeType;
|
||||||
|
import com.sk89q.worldedit.world.AbstractWorld;
|
||||||
|
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.block.Block;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.block.LeavesBlock;
|
||||||
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.entity.EntityType;
|
||||||
|
import net.minecraft.entity.ItemEntity;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.ItemUsageContext;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.WorldGenerationProgressListener;
|
||||||
|
import net.minecraft.server.world.ServerChunkManager;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.Clearable;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.ChunkPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldSaveHandler;
|
||||||
|
import net.minecraft.world.chunk.Chunk;
|
||||||
|
import net.minecraft.world.chunk.ChunkManager;
|
||||||
|
import net.minecraft.world.chunk.ChunkStatus;
|
||||||
|
import net.minecraft.world.chunk.WorldChunk;
|
||||||
|
import net.minecraft.world.gen.feature.BirchTreeFeature;
|
||||||
|
import net.minecraft.world.gen.feature.DarkOakTreeFeature;
|
||||||
|
import net.minecraft.world.gen.feature.DefaultFeatureConfig;
|
||||||
|
import net.minecraft.world.gen.feature.Feature;
|
||||||
|
import net.minecraft.world.gen.feature.FeatureConfig;
|
||||||
|
import net.minecraft.world.gen.feature.HugeBrownMushroomFeature;
|
||||||
|
import net.minecraft.world.gen.feature.HugeRedMushroomFeature;
|
||||||
|
import net.minecraft.world.gen.feature.JungleGroundBushFeature;
|
||||||
|
import net.minecraft.world.gen.feature.JungleTreeFeature;
|
||||||
|
import net.minecraft.world.gen.feature.LargeOakTreeFeature;
|
||||||
|
import net.minecraft.world.gen.feature.MegaJungleTreeFeature;
|
||||||
|
import net.minecraft.world.gen.feature.MegaPineTreeFeature;
|
||||||
|
import net.minecraft.world.gen.feature.OakTreeFeature;
|
||||||
|
import net.minecraft.world.gen.feature.PineTreeFeature;
|
||||||
|
import net.minecraft.world.gen.feature.PlantedFeatureConfig;
|
||||||
|
import net.minecraft.world.gen.feature.SavannaTreeFeature;
|
||||||
|
import net.minecraft.world.gen.feature.SpruceTreeFeature;
|
||||||
|
import net.minecraft.world.gen.feature.SwampTreeFeature;
|
||||||
|
import net.minecraft.world.level.LevelProperties;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An adapter to Minecraft worlds for WorldEdit.
|
||||||
|
*/
|
||||||
|
public class FabricWorld extends AbstractWorld {
|
||||||
|
|
||||||
|
private static final Random random = new Random();
|
||||||
|
private static final int UPDATE = 1, NOTIFY = 2;
|
||||||
|
|
||||||
|
private static final net.minecraft.block.BlockState JUNGLE_LOG = Blocks.JUNGLE_LOG.getDefaultState();
|
||||||
|
private static final net.minecraft.block.BlockState JUNGLE_LEAF = Blocks.JUNGLE_LEAVES.getDefaultState().with(LeavesBlock.PERSISTENT, Boolean.TRUE);
|
||||||
|
private static final net.minecraft.block.BlockState JUNGLE_SHRUB = Blocks.OAK_LEAVES.getDefaultState().with(LeavesBlock.PERSISTENT, Boolean.TRUE);
|
||||||
|
|
||||||
|
private final WeakReference<World> worldRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new world.
|
||||||
|
*
|
||||||
|
* @param world the world
|
||||||
|
*/
|
||||||
|
FabricWorld(World world) {
|
||||||
|
checkNotNull(world);
|
||||||
|
this.worldRef = new WeakReference<>(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the underlying handle to the world.
|
||||||
|
*
|
||||||
|
* @return the world
|
||||||
|
* @throws WorldEditException thrown if a reference to the world was lost (i.e. world was unloaded)
|
||||||
|
*/
|
||||||
|
public World getWorldChecked() throws WorldEditException {
|
||||||
|
World world = worldRef.get();
|
||||||
|
if (world != null) {
|
||||||
|
return world;
|
||||||
|
} else {
|
||||||
|
throw new WorldReferenceLostException("The reference to the world was lost (i.e. the world may have been unloaded)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
public World getWorld() {
|
||||||
|
World 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)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return getWorld().getLevelProperties().getLevelName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path getStoragePath() {
|
||||||
|
final World world = getWorld();
|
||||||
|
if (world instanceof ServerWorld) {
|
||||||
|
return ((ServerWorld) world).getSaveHandler().getWorldDir().toPath();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException {
|
||||||
|
checkNotNull(position);
|
||||||
|
checkNotNull(block);
|
||||||
|
|
||||||
|
World world = getWorldChecked();
|
||||||
|
int x = position.getBlockX();
|
||||||
|
int y = position.getBlockY();
|
||||||
|
int z = position.getBlockZ();
|
||||||
|
|
||||||
|
// First set the block
|
||||||
|
Chunk chunk = world.getChunk(x >> 4, z >> 4);
|
||||||
|
BlockPos pos = new BlockPos(x, y, z);
|
||||||
|
net.minecraft.block.BlockState old = chunk.getBlockState(pos);
|
||||||
|
OptionalInt stateId = BlockStateIdAccess.getBlockStateId(block.toImmutableState());
|
||||||
|
net.minecraft.block.BlockState newState = stateId.isPresent() ? Block.getStateFromRawId(stateId.getAsInt()) : FabricAdapter.adapt(block.toImmutableState());
|
||||||
|
net.minecraft.block.BlockState successState = chunk.setBlockState(pos, newState, false);
|
||||||
|
boolean successful = successState != null;
|
||||||
|
|
||||||
|
// Create the TileEntity
|
||||||
|
if (successful || old == newState) {
|
||||||
|
if (block instanceof BaseBlock) {
|
||||||
|
CompoundTag tag = ((BaseBlock) block).getNbtData();
|
||||||
|
if (tag != null) {
|
||||||
|
net.minecraft.nbt.CompoundTag nativeTag = NBTConverter.toNative(tag);
|
||||||
|
nativeTag.putString("id", ((BaseBlock) block).getNbtId());
|
||||||
|
TileEntityUtils.setTileEntity(world, position, nativeTag);
|
||||||
|
successful = true; // update if TE changed as well
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (successful && notifyAndLight) {
|
||||||
|
world.getChunkManager().getLightingProvider().enqueueLightUpdate(pos);
|
||||||
|
world.updateListeners(pos, old, newState, UPDATE | NOTIFY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {
|
||||||
|
BlockPos pos = new BlockPos(position.getX(), position.getY(), position.getZ());
|
||||||
|
getWorld().updateListeners(pos, FabricAdapter.adapt(previousType), getWorld().getBlockState(pos), 1 | 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockLightLevel(BlockVector3 position) {
|
||||||
|
checkNotNull(position);
|
||||||
|
return getWorld().getLightLevel(FabricAdapter.toBlockPos(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean clearContainerBlockContents(BlockVector3 position) {
|
||||||
|
checkNotNull(position);
|
||||||
|
BlockEntity tile = getWorld().getBlockEntity(FabricAdapter.toBlockPos(position));
|
||||||
|
if ((tile instanceof Clearable)) {
|
||||||
|
((Clearable) tile).clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BiomeType getBiome(BlockVector2 position) {
|
||||||
|
checkNotNull(position);
|
||||||
|
return FabricAdapter.adapt(getWorld().getBiome(new BlockPos(position.getBlockX(), 0, position.getBlockZ())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setBiome(BlockVector2 position, BiomeType biome) {
|
||||||
|
checkNotNull(position);
|
||||||
|
checkNotNull(biome);
|
||||||
|
|
||||||
|
Chunk chunk = getWorld().getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4, ChunkStatus.FULL, false);
|
||||||
|
if (chunk == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
chunk.getBiomeArray()[((position.getBlockZ() & 0xF) << 4 | position.getBlockX() & 0xF)] = FabricAdapter.adapt(biome);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final LoadingCache<ServerWorld, WorldEditFakePlayer> fakePlayers
|
||||||
|
= CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(WorldEditFakePlayer::new));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useItem(BlockVector3 position, BaseItem item, Direction face) {
|
||||||
|
ItemStack stack = FabricAdapter.adapt(new BaseItemStack(item.getType(), item.getNbtData(), 1));
|
||||||
|
ServerWorld world = (ServerWorld) getWorld();
|
||||||
|
final WorldEditFakePlayer fakePlayer;
|
||||||
|
try {
|
||||||
|
fakePlayer = fakePlayers.get(world);
|
||||||
|
} catch (ExecutionException ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fakePlayer.setStackInHand(Hand.MAIN_HAND, stack);
|
||||||
|
fakePlayer.setPositionAndAngles(position.getBlockX(), position.getBlockY(), position.getBlockZ(),
|
||||||
|
(float) face.toVector().toYaw(), (float) face.toVector().toPitch());
|
||||||
|
final BlockPos blockPos = FabricAdapter.toBlockPos(position);
|
||||||
|
final BlockHitResult rayTraceResult = new BlockHitResult(FabricAdapter.toVec3(position),
|
||||||
|
FabricAdapter.adapt(face), blockPos, false);
|
||||||
|
ItemUsageContext itemUseContext = new ItemUsageContext(fakePlayer, Hand.MAIN_HAND, rayTraceResult);
|
||||||
|
ActionResult used = stack.useOnBlock(itemUseContext);
|
||||||
|
if (used != ActionResult.SUCCESS) {
|
||||||
|
// try activating the block
|
||||||
|
if (getWorld().getBlockState(blockPos).activate(world, fakePlayer, Hand.MAIN_HAND, rayTraceResult)) {
|
||||||
|
used = ActionResult.SUCCESS;
|
||||||
|
} else {
|
||||||
|
used = stack.getItem().use(world, fakePlayer, Hand.MAIN_HAND).getResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return used == ActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dropItem(Vector3 position, BaseItemStack item) {
|
||||||
|
checkNotNull(position);
|
||||||
|
checkNotNull(item);
|
||||||
|
|
||||||
|
if (item.getType() == ItemTypes.AIR) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemEntity entity = new ItemEntity(getWorld(), position.getX(), position.getY(), position.getZ(), FabricAdapter.adapt(item));
|
||||||
|
entity.setPickupDelay(10);
|
||||||
|
getWorld().spawnEntity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void simulateBlockMine(BlockVector3 position) {
|
||||||
|
BlockPos pos = FabricAdapter.toBlockPos(position);
|
||||||
|
getWorld().breakBlock(pos, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean regenerate(Region region, EditSession editSession) {
|
||||||
|
// Don't even try to regen if it's going to fail.
|
||||||
|
ChunkManager provider = getWorld().getChunkManager();
|
||||||
|
if (!(provider instanceof ServerChunkManager)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
File saveFolder = Files.createTempDir();
|
||||||
|
// register this just in case something goes wrong
|
||||||
|
// normally it should be deleted at the end of this method
|
||||||
|
saveFolder.deleteOnExit();
|
||||||
|
try {
|
||||||
|
ServerWorld originalWorld = (ServerWorld) getWorld();
|
||||||
|
|
||||||
|
MinecraftServer server = originalWorld.getServer();
|
||||||
|
WorldSaveHandler saveHandler = new WorldSaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDir().getName(), server, server.getDataFixer());
|
||||||
|
World freshWorld = new ServerWorld(server, server.getWorkerExecutor(), saveHandler, originalWorld.getLevelProperties(),
|
||||||
|
originalWorld.dimension.getType(), originalWorld.getProfiler(), new NoOpChunkStatusListener());
|
||||||
|
|
||||||
|
// Pre-gen all the chunks
|
||||||
|
// We need to also pull one more chunk in every direction
|
||||||
|
CuboidRegion expandedPreGen = new CuboidRegion(region.getMinimumPoint().subtract(16, 0, 16), region.getMaximumPoint().add(16, 0, 16));
|
||||||
|
for (BlockVector2 chunk : expandedPreGen.getChunks()) {
|
||||||
|
freshWorld.getChunk(chunk.getBlockX(), chunk.getBlockZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
FabricWorld from = new FabricWorld(freshWorld);
|
||||||
|
for (BlockVector3 vec : region) {
|
||||||
|
editSession.setBlock(vec, from.getFullBlock(vec));
|
||||||
|
}
|
||||||
|
} catch (MaxChangedBlocksException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
saveFolder.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static Feature<? extends FeatureConfig> createTreeFeatureGenerator(TreeType type) {
|
||||||
|
switch (type) {
|
||||||
|
case TREE: return new OakTreeFeature(DefaultFeatureConfig::deserialize, true);
|
||||||
|
case BIG_TREE: return new LargeOakTreeFeature(DefaultFeatureConfig::deserialize, true);
|
||||||
|
case REDWOOD: return new PineTreeFeature(DefaultFeatureConfig::deserialize);
|
||||||
|
case TALL_REDWOOD: return new SpruceTreeFeature(DefaultFeatureConfig::deserialize, true);
|
||||||
|
case BIRCH: return new BirchTreeFeature(DefaultFeatureConfig::deserialize, true, false);
|
||||||
|
case JUNGLE: return new MegaJungleTreeFeature(DefaultFeatureConfig::deserialize, true, 10, 20, JUNGLE_LOG, JUNGLE_LEAF);
|
||||||
|
case SMALL_JUNGLE: return new JungleTreeFeature(DefaultFeatureConfig::deserialize, true, 4 + random.nextInt(7), JUNGLE_LOG, JUNGLE_LEAF, false);
|
||||||
|
case SHORT_JUNGLE: return new JungleTreeFeature(DefaultFeatureConfig::deserialize, true, 4 + random.nextInt(7), JUNGLE_LOG, JUNGLE_LEAF, true);
|
||||||
|
case JUNGLE_BUSH: return new JungleGroundBushFeature(DefaultFeatureConfig::deserialize, JUNGLE_LOG, JUNGLE_SHRUB);
|
||||||
|
case SWAMP: return new SwampTreeFeature(DefaultFeatureConfig::deserialize);
|
||||||
|
case ACACIA: return new SavannaTreeFeature(DefaultFeatureConfig::deserialize, true);
|
||||||
|
case DARK_OAK: return new DarkOakTreeFeature(DefaultFeatureConfig::deserialize, true);
|
||||||
|
case MEGA_REDWOOD: return new MegaPineTreeFeature(DefaultFeatureConfig::deserialize, true, random.nextBoolean());
|
||||||
|
case TALL_BIRCH: return new BirchTreeFeature(DefaultFeatureConfig::deserialize, true, true);
|
||||||
|
case RED_MUSHROOM: return new HugeRedMushroomFeature(PlantedFeatureConfig::deserialize);
|
||||||
|
case BROWN_MUSHROOM: return new HugeBrownMushroomFeature(PlantedFeatureConfig::deserialize);
|
||||||
|
case RANDOM: return createTreeFeatureGenerator(TreeType.values()[ThreadLocalRandom.current().nextInt(TreeType.values().length)]);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private FeatureConfig createFeatureConfig(TreeType type) {
|
||||||
|
if (type == TreeType.RED_MUSHROOM || type == TreeType.BROWN_MUSHROOM) {
|
||||||
|
return new PlantedFeatureConfig(true);
|
||||||
|
} else {
|
||||||
|
return new DefaultFeatureConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean generateTree(TreeType type, EditSession editSession, BlockVector3 position) throws MaxChangedBlocksException {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Feature<FeatureConfig> generator = (Feature<FeatureConfig>) createTreeFeatureGenerator(type);
|
||||||
|
return generator != null
|
||||||
|
&& generator.generate(getWorld(), getWorld().getChunkManager().getChunkGenerator(), random,
|
||||||
|
FabricAdapter.toBlockPos(position), createFeatureConfig(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkLoadedChunk(BlockVector3 pt) {
|
||||||
|
getWorld().getChunk(FabricAdapter.toBlockPos(pt));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fixAfterFastMode(Iterable<BlockVector2> chunks) {
|
||||||
|
fixLighting(chunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fixLighting(Iterable<BlockVector2> chunks) {
|
||||||
|
World world = getWorld();
|
||||||
|
for (BlockVector2 chunk : chunks) {
|
||||||
|
world.getChunkManager().getLightingProvider().suppressLight(new ChunkPos(chunk.getBlockX(), chunk.getBlockZ()), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean playEffect(Vector3 position, int type, int data) {
|
||||||
|
getWorld().playLevelEvent(type, FabricAdapter.toBlockPos(position.toBlockPoint()), data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WeatherType getWeather() {
|
||||||
|
LevelProperties info = getWorld().getLevelProperties();
|
||||||
|
if (info.isThundering()) {
|
||||||
|
return WeatherTypes.THUNDER_STORM;
|
||||||
|
}
|
||||||
|
if (info.isRaining()) {
|
||||||
|
return WeatherTypes.RAIN;
|
||||||
|
}
|
||||||
|
return WeatherTypes.CLEAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getRemainingWeatherDuration() {
|
||||||
|
LevelProperties info = getWorld().getLevelProperties();
|
||||||
|
if (info.isThundering()) {
|
||||||
|
return info.getThunderTime();
|
||||||
|
}
|
||||||
|
if (info.isRaining()) {
|
||||||
|
return info.getRainTime();
|
||||||
|
}
|
||||||
|
return info.getClearWeatherTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWeather(WeatherType weatherType) {
|
||||||
|
setWeather(weatherType, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWeather(WeatherType weatherType, long duration) {
|
||||||
|
LevelProperties info = getWorld().getLevelProperties();
|
||||||
|
if (weatherType == WeatherTypes.THUNDER_STORM) {
|
||||||
|
info.setClearWeatherTime(0);
|
||||||
|
info.setThundering(true);
|
||||||
|
info.setThunderTime((int) duration);
|
||||||
|
} else if (weatherType == WeatherTypes.RAIN) {
|
||||||
|
info.setClearWeatherTime(0);
|
||||||
|
info.setRaining(true);
|
||||||
|
info.setRainTime((int) duration);
|
||||||
|
} else if (weatherType == WeatherTypes.CLEAR) {
|
||||||
|
info.setRaining(false);
|
||||||
|
info.setThundering(false);
|
||||||
|
info.setClearWeatherTime((int) duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxY() {
|
||||||
|
return getWorld().getHeight() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockVector3 getSpawnPosition() {
|
||||||
|
return FabricAdapter.adapt(getWorld().getSpawnPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getBlock(BlockVector3 position) {
|
||||||
|
net.minecraft.block.BlockState mcState = getWorld()
|
||||||
|
.getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4)
|
||||||
|
.getBlockState(FabricAdapter.toBlockPos(position));
|
||||||
|
|
||||||
|
BlockState matchingBlock = BlockStateIdAccess.getBlockStateById(Block.getRawIdFromState(mcState));
|
||||||
|
if (matchingBlock != null) {
|
||||||
|
return matchingBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FabricAdapter.adapt(mcState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseBlock getFullBlock(BlockVector3 position) {
|
||||||
|
BlockPos pos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||||
|
// Avoid creation by using the CHECK mode -- if it's needed, it'll be re-created anyways
|
||||||
|
BlockEntity tile = ((WorldChunk) getWorld().getChunk(pos)).getBlockEntity(pos, WorldChunk.CreationType.CHECK);
|
||||||
|
|
||||||
|
if (tile != null) {
|
||||||
|
return getBlock(position).toBaseBlock(NBTConverter.fromNative(TileEntityUtils.copyNbtData(tile)));
|
||||||
|
} else {
|
||||||
|
return getBlock(position).toBaseBlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getWorld().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if ((o instanceof FabricWorld)) {
|
||||||
|
FabricWorld other = ((FabricWorld) o);
|
||||||
|
World otherWorld = other.worldRef.get();
|
||||||
|
World thisWorld = worldRef.get();
|
||||||
|
return otherWorld != null && otherWorld.equals(thisWorld);
|
||||||
|
} else if (o instanceof com.sk89q.worldedit.world.World) {
|
||||||
|
return ((com.sk89q.worldedit.world.World) o).getName().equals(getName());
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<? extends Entity> getEntities(Region region) {
|
||||||
|
final World world = getWorld();
|
||||||
|
if (!(world instanceof ServerWorld)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return ((ServerWorld) world).getEntities(null, entity -> true)
|
||||||
|
.stream()
|
||||||
|
.filter(e -> region.contains(FabricAdapter.adapt(e.getBlockPos())))
|
||||||
|
.map(FabricEntity::new).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<? extends Entity> getEntities() {
|
||||||
|
final World world = getWorld();
|
||||||
|
if (!(world instanceof ServerWorld)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return ((ServerWorld) world).getEntities(null, entity -> true)
|
||||||
|
.stream()
|
||||||
|
.map(FabricEntity::new)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Entity createEntity(Location location, BaseEntity entity) {
|
||||||
|
World world = getWorld();
|
||||||
|
final Optional<EntityType<?>> entityType = EntityType.get(entity.getType().getId());
|
||||||
|
if (!entityType.isPresent()) return null;
|
||||||
|
net.minecraft.entity.Entity createdEntity = entityType.get().create(world);
|
||||||
|
if (createdEntity != null) {
|
||||||
|
CompoundTag nativeTag = entity.getNbtData();
|
||||||
|
if (nativeTag != null) {
|
||||||
|
net.minecraft.nbt.CompoundTag tag = NBTConverter.toNative(entity.getNbtData());
|
||||||
|
for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||||
|
tag.remove(name);
|
||||||
|
}
|
||||||
|
createdEntity.fromTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
createdEntity.setPositionAndAngles(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
|
||||||
|
|
||||||
|
world.spawnEntity(createdEntity);
|
||||||
|
return new FabricEntity(createdEntity);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when the reference to the world is lost.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
private static final class WorldReferenceLostException extends WorldEditException {
|
||||||
|
private WorldReferenceLostException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NoOpChunkStatusListener implements WorldGenerationProgressListener {
|
||||||
|
@Override
|
||||||
|
public void start(ChunkPos chunkPos) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setChunkStatus(ChunkPos chunkPos, @Nullable ChunkStatus chunkStatus) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,326 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.sk89q.worldedit.fabric.FabricAdapter.adaptPlayer;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.LocalSession;
|
||||||
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
|
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
|
||||||
|
import com.sk89q.worldedit.extension.platform.Platform;
|
||||||
|
import com.sk89q.worldedit.fabric.net.handler.WECUIPacketHandler;
|
||||||
|
import com.sk89q.worldedit.util.Location;
|
||||||
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockCategory;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockType;
|
||||||
|
import com.sk89q.worldedit.world.entity.EntityType;
|
||||||
|
import com.sk89q.worldedit.world.item.ItemCategory;
|
||||||
|
import com.sk89q.worldedit.world.item.ItemType;
|
||||||
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
|
||||||
|
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||||
|
import net.fabricmc.fabric.api.event.player.UseItemCallback;
|
||||||
|
import net.fabricmc.fabric.api.event.server.ServerStartCallback;
|
||||||
|
import net.fabricmc.fabric.api.event.server.ServerStopCallback;
|
||||||
|
import net.fabricmc.fabric.api.event.server.ServerTickCallback;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.fabricmc.loader.api.ModContainer;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.tag.BlockTags;
|
||||||
|
import net.minecraft.tag.ItemTags;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.registry.Registry;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Fabric implementation of WorldEdit.
|
||||||
|
*/
|
||||||
|
public class FabricWorldEdit implements ModInitializer {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger();
|
||||||
|
public static final String MOD_ID = "worldedit";
|
||||||
|
public static final String CUI_PLUGIN_CHANNEL = "cui";
|
||||||
|
|
||||||
|
private FabricPermissionsProvider provider;
|
||||||
|
|
||||||
|
public static FabricWorldEdit inst;
|
||||||
|
|
||||||
|
private FabricPlatform platform;
|
||||||
|
private FabricConfiguration config;
|
||||||
|
private Path workingDir;
|
||||||
|
|
||||||
|
private ModContainer container;
|
||||||
|
|
||||||
|
public FabricWorldEdit() {
|
||||||
|
inst = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitialize() {
|
||||||
|
this.container = FabricLoader.getInstance().getModContainer("worldedit").orElseThrow(
|
||||||
|
() -> new IllegalStateException("WorldEdit mod missing in Fabric")
|
||||||
|
);
|
||||||
|
|
||||||
|
// Setup working directory
|
||||||
|
workingDir = new File(FabricLoader.getInstance().getConfigDirectory(), "worldedit").toPath();
|
||||||
|
if (!Files.exists(workingDir)) {
|
||||||
|
try {
|
||||||
|
Files.createDirectory(workingDir);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WECUIPacketHandler.init();
|
||||||
|
|
||||||
|
ServerTickCallback.EVENT.register(ThreadSafeCache.getInstance());
|
||||||
|
ServerStartCallback.EVENT.register(this::onStartServer);
|
||||||
|
ServerStopCallback.EVENT.register(this::onStopServer);
|
||||||
|
AttackBlockCallback.EVENT.register(this::onLeftClickBlock);
|
||||||
|
UseBlockCallback.EVENT.register(this::onRightClickBlock);
|
||||||
|
UseItemCallback.EVENT.register(this::onRightClickAir);
|
||||||
|
LOGGER.info("WorldEdit for Fabric (version " + getInternalVersion() + ") is loaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupPlatform(MinecraftServer server) {
|
||||||
|
this.platform = new FabricPlatform(this, server);
|
||||||
|
|
||||||
|
WorldEdit.getInstance().getPlatformManager().register(platform);
|
||||||
|
|
||||||
|
this.provider = new FabricPermissionsProvider.VanillaPermissionsProvider(platform);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupRegistries() {
|
||||||
|
// Blocks
|
||||||
|
for (Identifier name : Registry.BLOCK.getIds()) {
|
||||||
|
if (BlockType.REGISTRY.get(name.toString()) == null) {
|
||||||
|
BlockType.REGISTRY.register(name.toString(), new BlockType(name.toString(),
|
||||||
|
input -> FabricAdapter.adapt(FabricAdapter.adapt(input.getBlockType()).getDefaultState())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Items
|
||||||
|
for (Identifier name : Registry.ITEM.getIds()) {
|
||||||
|
if (ItemType.REGISTRY.get(name.toString()) == null) {
|
||||||
|
ItemType.REGISTRY.register(name.toString(), new ItemType(name.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Entities
|
||||||
|
for (Identifier name : Registry.ENTITY_TYPE.getIds()) {
|
||||||
|
if (EntityType.REGISTRY.get(name.toString()) == null) {
|
||||||
|
EntityType.REGISTRY.register(name.toString(), new EntityType(name.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Biomes
|
||||||
|
for (Identifier name : Registry.BIOME.getIds()) {
|
||||||
|
if (BiomeType.REGISTRY.get(name.toString()) == null) {
|
||||||
|
BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Tags
|
||||||
|
for (Identifier name : BlockTags.getContainer().getKeys()) {
|
||||||
|
if (BlockCategory.REGISTRY.get(name.toString()) == null) {
|
||||||
|
BlockCategory.REGISTRY.register(name.toString(), new BlockCategory(name.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Identifier name : ItemTags.getContainer().getKeys()) {
|
||||||
|
if (ItemCategory.REGISTRY.get(name.toString()) == null) {
|
||||||
|
ItemCategory.REGISTRY.register(name.toString(), new ItemCategory(name.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onStartServer(MinecraftServer minecraftServer) {
|
||||||
|
setupPlatform(minecraftServer);
|
||||||
|
setupRegistries();
|
||||||
|
|
||||||
|
config = new FabricConfiguration(this);
|
||||||
|
config.load();
|
||||||
|
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onStopServer(MinecraftServer minecraftServer) {
|
||||||
|
WorldEdit worldEdit = WorldEdit.getInstance();
|
||||||
|
worldEdit.getSessionManager().unload();
|
||||||
|
worldEdit.getPlatformManager().unregister(platform);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldSkip() {
|
||||||
|
if (platform == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !platform.isHookingEvents(); // We have to be told to catch these events
|
||||||
|
}
|
||||||
|
|
||||||
|
private ActionResult onLeftClickBlock(PlayerEntity playerEntity, World world, Hand hand, BlockPos blockPos, Direction direction) {
|
||||||
|
if (shouldSkip() || hand == Hand.OFF_HAND || world.isClient) {
|
||||||
|
return ActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
WorldEdit we = WorldEdit.getInstance();
|
||||||
|
FabricPlayer player = adaptPlayer((ServerPlayerEntity) playerEntity);
|
||||||
|
FabricWorld localWorld = getWorld(world);
|
||||||
|
Location pos = new Location(localWorld,
|
||||||
|
blockPos.getX(),
|
||||||
|
blockPos.getY(),
|
||||||
|
blockPos.getZ()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (we.handleBlockLeftClick(player, pos)) {
|
||||||
|
return ActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (we.handleArmSwing(player)) {
|
||||||
|
return ActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onLeftClickAir(PlayerEntity playerEntity, World world, Hand hand) {
|
||||||
|
WorldEdit we = WorldEdit.getInstance();
|
||||||
|
FabricPlayer player = adaptPlayer((ServerPlayerEntity) playerEntity);
|
||||||
|
we.handleArmSwing(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ActionResult onRightClickBlock(PlayerEntity playerEntity, World world, Hand hand, BlockHitResult blockHitResult) {
|
||||||
|
if (shouldSkip() || hand == Hand.OFF_HAND || world.isClient) {
|
||||||
|
return ActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
WorldEdit we = WorldEdit.getInstance();
|
||||||
|
FabricPlayer player = adaptPlayer((ServerPlayerEntity) playerEntity);
|
||||||
|
FabricWorld localWorld = getWorld(world);
|
||||||
|
Location pos = new Location(localWorld,
|
||||||
|
blockHitResult.getBlockPos().getX(),
|
||||||
|
blockHitResult.getBlockPos().getY(),
|
||||||
|
blockHitResult.getBlockPos().getZ()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (we.handleBlockRightClick(player, pos)) {
|
||||||
|
return ActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (we.handleRightClick(player)) {
|
||||||
|
return ActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ActionResult onRightClickAir(PlayerEntity playerEntity, World world, Hand hand) {
|
||||||
|
if (shouldSkip() || hand == Hand.OFF_HAND || world.isClient) {
|
||||||
|
return ActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
WorldEdit we = WorldEdit.getInstance();
|
||||||
|
FabricPlayer player = adaptPlayer((ServerPlayerEntity) playerEntity);
|
||||||
|
|
||||||
|
if (we.handleRightClick(player)) {
|
||||||
|
return ActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Pass empty left click to server
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configuration.
|
||||||
|
*
|
||||||
|
* @return the Fabric configuration
|
||||||
|
*/
|
||||||
|
FabricConfiguration getConfig() {
|
||||||
|
return this.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the session for a player.
|
||||||
|
*
|
||||||
|
* @param player the player
|
||||||
|
* @return the session
|
||||||
|
*/
|
||||||
|
public LocalSession getSession(ServerPlayerEntity player) {
|
||||||
|
checkNotNull(player);
|
||||||
|
return WorldEdit.getInstance().getSessionManager().get(adaptPlayer(player));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the WorldEdit proxy for the given world.
|
||||||
|
*
|
||||||
|
* @param world the world
|
||||||
|
* @return the WorldEdit world
|
||||||
|
*/
|
||||||
|
public FabricWorld getWorld(World world) {
|
||||||
|
checkNotNull(world);
|
||||||
|
return new FabricWorld(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the WorldEdit proxy for the platform.
|
||||||
|
*
|
||||||
|
* @return the WorldEdit platform
|
||||||
|
*/
|
||||||
|
public Platform getPlatform() {
|
||||||
|
return this.platform;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the working directory where WorldEdit's files are stored.
|
||||||
|
*
|
||||||
|
* @return the working directory
|
||||||
|
*/
|
||||||
|
public File getWorkingDir() {
|
||||||
|
return this.workingDir.toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the version of the WorldEdit-Fabric implementation.
|
||||||
|
*
|
||||||
|
* @return a version string
|
||||||
|
*/
|
||||||
|
String getInternalVersion() {
|
||||||
|
return container.getMetadata().getVersion().getFriendlyString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPermissionsProvider(FabricPermissionsProvider provider) {
|
||||||
|
this.provider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FabricPermissionsProvider getPermissionsProvider() {
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,252 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import com.sk89q.jnbt.ByteArrayTag;
|
||||||
|
import com.sk89q.jnbt.ByteTag;
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.jnbt.DoubleTag;
|
||||||
|
import com.sk89q.jnbt.EndTag;
|
||||||
|
import com.sk89q.jnbt.FloatTag;
|
||||||
|
import com.sk89q.jnbt.IntArrayTag;
|
||||||
|
import com.sk89q.jnbt.IntTag;
|
||||||
|
import com.sk89q.jnbt.ListTag;
|
||||||
|
import com.sk89q.jnbt.LongTag;
|
||||||
|
import com.sk89q.jnbt.ShortTag;
|
||||||
|
import com.sk89q.jnbt.StringTag;
|
||||||
|
import com.sk89q.jnbt.Tag;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts between JNBT and Minecraft NBT classes.
|
||||||
|
*/
|
||||||
|
final class NBTConverter {
|
||||||
|
|
||||||
|
private NBTConverter() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.minecraft.nbt.Tag toNative(Tag tag) {
|
||||||
|
if (tag instanceof IntArrayTag) {
|
||||||
|
return toNative((IntArrayTag) tag);
|
||||||
|
|
||||||
|
} else if (tag instanceof ListTag) {
|
||||||
|
return toNative((ListTag) tag);
|
||||||
|
|
||||||
|
} else if (tag instanceof LongTag) {
|
||||||
|
return toNative((LongTag) tag);
|
||||||
|
|
||||||
|
} else if (tag instanceof StringTag) {
|
||||||
|
return toNative((StringTag) tag);
|
||||||
|
|
||||||
|
} else if (tag instanceof IntTag) {
|
||||||
|
return toNative((IntTag) tag);
|
||||||
|
|
||||||
|
} else if (tag instanceof ByteTag) {
|
||||||
|
return toNative((ByteTag) tag);
|
||||||
|
|
||||||
|
} else if (tag instanceof ByteArrayTag) {
|
||||||
|
return toNative((ByteArrayTag) tag);
|
||||||
|
|
||||||
|
} else if (tag instanceof CompoundTag) {
|
||||||
|
return toNative((CompoundTag) tag);
|
||||||
|
|
||||||
|
} else if (tag instanceof FloatTag) {
|
||||||
|
return toNative((FloatTag) tag);
|
||||||
|
|
||||||
|
} else if (tag instanceof ShortTag) {
|
||||||
|
return toNative((ShortTag) tag);
|
||||||
|
|
||||||
|
} else if (tag instanceof DoubleTag) {
|
||||||
|
return toNative((DoubleTag) tag);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Can't convert tag of type " + tag.getClass().getCanonicalName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.minecraft.nbt.IntArrayTag toNative(IntArrayTag tag) {
|
||||||
|
int[] value = tag.getValue();
|
||||||
|
return new net.minecraft.nbt.IntArrayTag(Arrays.copyOf(value, value.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.minecraft.nbt.ListTag toNative(ListTag tag) {
|
||||||
|
net.minecraft.nbt.ListTag list = new net.minecraft.nbt.ListTag();
|
||||||
|
for (Tag child : tag.getValue()) {
|
||||||
|
if (child instanceof EndTag) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
list.add(toNative(child));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.minecraft.nbt.LongTag toNative(LongTag tag) {
|
||||||
|
return new net.minecraft.nbt.LongTag(tag.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.minecraft.nbt.StringTag toNative(StringTag tag) {
|
||||||
|
return new net.minecraft.nbt.StringTag(tag.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.minecraft.nbt.IntTag toNative(IntTag tag) {
|
||||||
|
return new net.minecraft.nbt.IntTag(tag.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.minecraft.nbt.ByteTag toNative(ByteTag tag) {
|
||||||
|
return new net.minecraft.nbt.ByteTag(tag.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.minecraft.nbt.ByteArrayTag toNative(ByteArrayTag tag) {
|
||||||
|
byte[] value = tag.getValue();
|
||||||
|
return new net.minecraft.nbt.ByteArrayTag(Arrays.copyOf(value, value.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.minecraft.nbt.CompoundTag toNative(CompoundTag tag) {
|
||||||
|
net.minecraft.nbt.CompoundTag compound = new net.minecraft.nbt.CompoundTag();
|
||||||
|
for (Entry<String, Tag> child : tag.getValue().entrySet()) {
|
||||||
|
compound.put(child.getKey(), toNative(child.getValue()));
|
||||||
|
}
|
||||||
|
return compound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.minecraft.nbt.FloatTag toNative(FloatTag tag) {
|
||||||
|
return new net.minecraft.nbt.FloatTag(tag.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.minecraft.nbt.ShortTag toNative(ShortTag tag) {
|
||||||
|
return new net.minecraft.nbt.ShortTag(tag.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.minecraft.nbt.DoubleTag toNative(DoubleTag tag) {
|
||||||
|
return new net.minecraft.nbt.DoubleTag(tag.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tag fromNative(net.minecraft.nbt.Tag other) {
|
||||||
|
if (other instanceof net.minecraft.nbt.IntArrayTag) {
|
||||||
|
return fromNative((net.minecraft.nbt.IntArrayTag) other);
|
||||||
|
|
||||||
|
} else if (other instanceof net.minecraft.nbt.ListTag) {
|
||||||
|
return fromNative((net.minecraft.nbt.ListTag) other);
|
||||||
|
|
||||||
|
} else if (other instanceof net.minecraft.nbt.EndTag) {
|
||||||
|
return fromNative((net.minecraft.nbt.EndTag) other);
|
||||||
|
|
||||||
|
} else if (other instanceof net.minecraft.nbt.LongTag) {
|
||||||
|
return fromNative((net.minecraft.nbt.LongTag) other);
|
||||||
|
|
||||||
|
} else if (other instanceof net.minecraft.nbt.StringTag) {
|
||||||
|
return fromNative((net.minecraft.nbt.StringTag) other);
|
||||||
|
|
||||||
|
} else if (other instanceof net.minecraft.nbt.IntTag) {
|
||||||
|
return fromNative((net.minecraft.nbt.IntTag) other);
|
||||||
|
|
||||||
|
} else if (other instanceof net.minecraft.nbt.ByteTag) {
|
||||||
|
return fromNative((net.minecraft.nbt.ByteTag) other);
|
||||||
|
|
||||||
|
} else if (other instanceof net.minecraft.nbt.ByteArrayTag) {
|
||||||
|
return fromNative((net.minecraft.nbt.ByteArrayTag) other);
|
||||||
|
|
||||||
|
} else if (other instanceof net.minecraft.nbt.CompoundTag) {
|
||||||
|
return fromNative((net.minecraft.nbt.CompoundTag) other);
|
||||||
|
|
||||||
|
} else if (other instanceof net.minecraft.nbt.FloatTag) {
|
||||||
|
return fromNative((net.minecraft.nbt.FloatTag) other);
|
||||||
|
|
||||||
|
} else if (other instanceof net.minecraft.nbt.ShortTag) {
|
||||||
|
return fromNative((net.minecraft.nbt.ShortTag) other);
|
||||||
|
|
||||||
|
} else if (other instanceof net.minecraft.nbt.DoubleTag) {
|
||||||
|
return fromNative((net.minecraft.nbt.DoubleTag) other);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Can't convert other of type " + other.getClass().getCanonicalName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntArrayTag fromNative(net.minecraft.nbt.IntArrayTag other) {
|
||||||
|
int[] value = other.getIntArray();
|
||||||
|
return new IntArrayTag(Arrays.copyOf(value, value.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ListTag fromNative(net.minecraft.nbt.ListTag other) {
|
||||||
|
other = (net.minecraft.nbt.ListTag) other.copy();
|
||||||
|
List<Tag> list = new ArrayList<>();
|
||||||
|
Class<? extends Tag> listClass = StringTag.class;
|
||||||
|
int tags = other.size();
|
||||||
|
for (int i = 0; i < tags; i++) {
|
||||||
|
Tag child = fromNative(other.remove(0));
|
||||||
|
list.add(child);
|
||||||
|
listClass = child.getClass();
|
||||||
|
}
|
||||||
|
return new ListTag(listClass, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EndTag fromNative(net.minecraft.nbt.EndTag other) {
|
||||||
|
return new EndTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LongTag fromNative(net.minecraft.nbt.LongTag other) {
|
||||||
|
return new LongTag(other.getLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringTag fromNative(net.minecraft.nbt.StringTag other) {
|
||||||
|
return new StringTag(other.asString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntTag fromNative(net.minecraft.nbt.IntTag other) {
|
||||||
|
return new IntTag(other.getInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteTag fromNative(net.minecraft.nbt.ByteTag other) {
|
||||||
|
return new ByteTag(other.getByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteArrayTag fromNative(net.minecraft.nbt.ByteArrayTag other) {
|
||||||
|
byte[] value = other.getByteArray();
|
||||||
|
return new ByteArrayTag(Arrays.copyOf(value, value.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompoundTag fromNative(net.minecraft.nbt.CompoundTag other) {
|
||||||
|
Set<String> tags = other.getKeys();
|
||||||
|
Map<String, Tag> map = new HashMap<>();
|
||||||
|
for (String tagName : tags) {
|
||||||
|
map.put(tagName, fromNative(other.getTag(tagName)));
|
||||||
|
}
|
||||||
|
return new CompoundTag(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FloatTag fromNative(net.minecraft.nbt.FloatTag other) {
|
||||||
|
return new FloatTag(other.getFloat());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShortTag fromNative(net.minecraft.nbt.ShortTag other) {
|
||||||
|
return new ShortTag(other.getShort());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DoubleTag fromNative(net.minecraft.nbt.DoubleTag other) {
|
||||||
|
return new DoubleTag(other.getDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.sk89q.worldedit.registry.state.Property;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
class PropertyAdapter<T extends Comparable<T>> implements Property<T> {
|
||||||
|
|
||||||
|
private final net.minecraft.state.property.Property<T> property;
|
||||||
|
private final List<T> values;
|
||||||
|
|
||||||
|
public PropertyAdapter(net.minecraft.state.property.Property<T> property) {
|
||||||
|
this.property = property;
|
||||||
|
this.values = ImmutableList.copyOf(property.getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return property.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<T> getValues() {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getValueFor(String string) throws IllegalArgumentException {
|
||||||
|
Optional<T> val = property.getValue(string);
|
||||||
|
checkArgument(val.isPresent(), "%s has no value for %s", getName(), string);
|
||||||
|
return val.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getName().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (!(obj instanceof Property)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return getName().equals(((Property<?>) obj).getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.event.server.ServerTickCallback;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
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 ServerTickCallback {
|
||||||
|
|
||||||
|
private static final long REFRESH_DELAY = 1000 * 30;
|
||||||
|
private static final ThreadSafeCache INSTANCE = new ThreadSafeCache();
|
||||||
|
private Set<UUID> onlineIds = Collections.emptySet();
|
||||||
|
private long lastRefresh = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an concurrent-safe set of UUIDs of online players.
|
||||||
|
*
|
||||||
|
* @return a set of UUIDs
|
||||||
|
*/
|
||||||
|
public Set<UUID> getOnlineIds() {
|
||||||
|
return onlineIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick(MinecraftServer server) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
if (now - lastRefresh > REFRESH_DELAY) {
|
||||||
|
Set<UUID> onlineIds = new HashSet<>();
|
||||||
|
|
||||||
|
if (server == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (ServerPlayerEntity player : server.getPlayerManager().getPlayerList()) {
|
||||||
|
if (player != null) {
|
||||||
|
onlineIds.add(player.getUuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onlineIds = new CopyOnWriteArraySet<>(onlineIds);
|
||||||
|
|
||||||
|
lastRefresh = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ThreadSafeCache getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.IntTag;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility methods for setting tile entities in the world.
|
||||||
|
*/
|
||||||
|
final class TileEntityUtils {
|
||||||
|
|
||||||
|
private TileEntityUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the given tag compound with position information.
|
||||||
|
*
|
||||||
|
* @param tag the tag
|
||||||
|
* @param position the position
|
||||||
|
*/
|
||||||
|
private static void updateForSet(CompoundTag tag, BlockVector3 position) {
|
||||||
|
checkNotNull(tag);
|
||||||
|
checkNotNull(position);
|
||||||
|
|
||||||
|
tag.put("x", new IntTag(position.getBlockX()));
|
||||||
|
tag.put("y", new IntTag(position.getBlockY()));
|
||||||
|
tag.put("z", new IntTag(position.getBlockZ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a tile entity at the given location using the tile entity ID from
|
||||||
|
* the tag.
|
||||||
|
*
|
||||||
|
* @param world the world
|
||||||
|
* @param position the position
|
||||||
|
* @param tag the tag for the tile entity (may be null to do nothing)
|
||||||
|
*/
|
||||||
|
static void setTileEntity(World world, BlockVector3 position, @Nullable CompoundTag tag) {
|
||||||
|
if (tag != null) {
|
||||||
|
updateForSet(tag, position);
|
||||||
|
BlockEntity tileEntity = BlockEntity.createFromTag(tag);
|
||||||
|
if (tileEntity != null) {
|
||||||
|
world.setBlockEntity(new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()), tileEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompoundTag copyNbtData(BlockEntity tile) {
|
||||||
|
CompoundTag tag = new CompoundTag();
|
||||||
|
tile.toTag(tag);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric;
|
||||||
|
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.damage.DamageSource;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.server.network.ServerPlayerInteractionManager;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.stat.Stat;
|
||||||
|
import net.minecraft.world.dimension.DimensionType;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class WorldEditFakePlayer extends ServerPlayerEntity {
|
||||||
|
private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]");
|
||||||
|
|
||||||
|
public WorldEditFakePlayer(ServerWorld world) {
|
||||||
|
super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, new ServerPlayerInteractionManager(world));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void increaseStat(Stat<?> stat, int incrementer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void incrementStat(Stat<?> stat) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(Component component) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addChatMessage(Component component, boolean opt) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Entity changeDimension(DimensionType dimensionType) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInvulnerableTo(DamageSource damageSource) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -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 Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric.mixin;
|
||||||
|
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import com.sk89q.worldedit.fabric.FabricWorldEdit;
|
||||||
|
import net.minecraft.container.ContainerListener;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(ServerPlayerEntity.class)
|
||||||
|
public abstract class MixinServerPlayerEntity extends PlayerEntity implements ContainerListener {
|
||||||
|
|
||||||
|
public MixinServerPlayerEntity(World world, GameProfile gameProfile) {
|
||||||
|
super(world, gameProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "swingHand", at = @At(value = "HEAD"))
|
||||||
|
public void onSwing(Hand hand, CallbackInfo injectionInfo) {
|
||||||
|
FabricWorldEdit.inst.onLeftClickAir(this, this.world, hand);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.fabric.net.handler;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.LocalSession;
|
||||||
|
import com.sk89q.worldedit.fabric.FabricAdapter;
|
||||||
|
import com.sk89q.worldedit.fabric.FabricPlayer;
|
||||||
|
import com.sk89q.worldedit.fabric.FabricWorldEdit;
|
||||||
|
import net.fabricmc.fabric.api.network.PacketConsumer;
|
||||||
|
import net.fabricmc.fabric.api.network.PacketContext;
|
||||||
|
import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.network.packet.CustomPayloadS2CPacket;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.server.network.packet.CustomPayloadC2SPacket;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.PacketByteBuf;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public final class WECUIPacketHandler {
|
||||||
|
private WECUIPacketHandler() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Charset UTF_8_CHARSET = StandardCharsets.UTF_8;
|
||||||
|
private static final Identifier CUI_IDENTIFIER = new Identifier(FabricWorldEdit.MOD_ID, FabricWorldEdit.CUI_PLUGIN_CHANNEL);
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
ServerSidePacketRegistry.INSTANCE.register(CUI_IDENTIFIER, (packetContext, packetByteBuf) -> {
|
||||||
|
ServerPlayerEntity player = (ServerPlayerEntity) packetContext.getPlayer();
|
||||||
|
LocalSession session = FabricWorldEdit.inst.getSession(player);
|
||||||
|
|
||||||
|
if (session.hasCUISupport()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String text = packetByteBuf.toString(UTF_8_CHARSET);
|
||||||
|
final FabricPlayer actor = FabricAdapter.adaptPlayer(player);
|
||||||
|
session.handleCUIInitializationMessage(text, actor);
|
||||||
|
session.describeCUI(actor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
BIN
worldedit-fabric/src/main/resources/assets/worldedit/icon.png
Normale Datei
BIN
worldedit-fabric/src/main/resources/assets/worldedit/icon.png
Normale Datei
Binäre Datei nicht angezeigt.
Nachher Breite: | Höhe: | Größe: 5.5 KiB |
33
worldedit-fabric/src/main/resources/defaults/worldedit.properties
Normale Datei
33
worldedit-fabric/src/main/resources/defaults/worldedit.properties
Normale Datei
@ -0,0 +1,33 @@
|
|||||||
|
#Don't put comments; they get removed
|
||||||
|
default-max-polygon-points=-1
|
||||||
|
schematic-save-dir=schematics
|
||||||
|
super-pickaxe-many-drop-items=true
|
||||||
|
register-help=true
|
||||||
|
nav-wand-item=minecraft:compass
|
||||||
|
profile=false
|
||||||
|
trace-unflushed-sessions=false
|
||||||
|
super-pickaxe-drop-items=true
|
||||||
|
disallowed-blocks=minecraft:oak_sapling,minecraft:jungle_sapling,minecraft:dark_oak_sapling,minecraft:spruce_sapling,minecraft:birch_sapling,minecraft:acacia_sapling,minecraft:black_bed,minecraft:blue_bed,minecraft:brown_bed,minecraft:cyan_bed,minecraft:gray_bed,minecraft:green_bed,minecraft:light_blue_bed,minecraft:light_gray_bed,minecraft:lime_bed,minecraft:magenta_bed,minecraft:orange_bed,minecraft:pink_bed,minecraft:purple_bed,minecraft:red_bed,minecraft:white_bed,minecraft:yellow_bed,minecraft:powered_rail,minecraft:detector_rail,minecraft:grass,minecraft:dead_bush,minecraft:moving_piston,minecraft:piston_head,minecraft:sunflower,minecraft:rose_bush,minecraft:dandelion,minecraft:poppy,minecraft:brown_mushroom,minecraft:red_mushroom,minecraft:tnt,minecraft:torch,minecraft:fire,minecraft:redstone_wire,minecraft:wheat,minecraft:potatoes,minecraft:carrots,minecraft:melon_stem,minecraft:pumpkin_stem,minecraft:beetroots,minecraft:rail,minecraft:lever,minecraft:redstone_torch,minecraft:redstone_wall_torch,minecraft:repeater,minecraft:comparator,minecraft:stone_button,minecraft:birch_button,minecraft:acacia_button,minecraft:dark_oak_button,minecraft:jungle_button,minecraft:oak_button,minecraft:spruce_button,minecraft:cactus,minecraft:sugar_cane,minecraft:bedrock
|
||||||
|
max-super-pickaxe-size=5
|
||||||
|
max-brush-radius=10
|
||||||
|
craftscript-dir=craftscripts
|
||||||
|
no-double-slash=false
|
||||||
|
wand-item=minecraft:wooden_axe
|
||||||
|
shell-save-type=
|
||||||
|
scripting-timeout=3000
|
||||||
|
snapshots-dir=
|
||||||
|
use-inventory-creative-override=false
|
||||||
|
log-file=worldedit.log
|
||||||
|
log-format=[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s]: %5$s%6$s%n
|
||||||
|
max-changed-blocks=-1
|
||||||
|
nav-wand-distance=50
|
||||||
|
butcher-default-radius=-1
|
||||||
|
default-max-changed-blocks=-1
|
||||||
|
history-size=15
|
||||||
|
use-inventory=false
|
||||||
|
allow-symbolic-links=false
|
||||||
|
use-inventory-override=false
|
||||||
|
log-commands=false
|
||||||
|
butcher-max-radius=-1
|
||||||
|
max-polygon-points=20
|
||||||
|
max-radius=-1
|
37
worldedit-fabric/src/main/resources/fabric.mod.json
Normale Datei
37
worldedit-fabric/src/main/resources/fabric.mod.json
Normale Datei
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "worldedit",
|
||||||
|
"version": "${version}",
|
||||||
|
|
||||||
|
"name": "WorldEdit",
|
||||||
|
"description": "WorldEdit is an easy-to-use in-game world editor for Minecraft, supporting both single- and multi-player.",
|
||||||
|
"authors": [
|
||||||
|
"sk89q",
|
||||||
|
"wizjany",
|
||||||
|
"TomyLobo",
|
||||||
|
"kenzierocks",
|
||||||
|
"Me4502"
|
||||||
|
],
|
||||||
|
"contact": {
|
||||||
|
"homepage": "https://enginehub.org/worldedit/",
|
||||||
|
"sources": "https://github.com/EngineHub/WorldEdit"
|
||||||
|
},
|
||||||
|
|
||||||
|
"license": "GPL3",
|
||||||
|
"icon": "assets/worldedit/icon.png",
|
||||||
|
|
||||||
|
"environment": "*",
|
||||||
|
"entrypoints": {
|
||||||
|
"main": [
|
||||||
|
"com.sk89q.worldedit.fabric.FabricWorldEdit"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"depends": {
|
||||||
|
"fabricloader": ">=0.4.0",
|
||||||
|
"fabric": "*"
|
||||||
|
},
|
||||||
|
"mixins": [
|
||||||
|
"worldedit.mixins.json"
|
||||||
|
]
|
||||||
|
}
|
6
worldedit-fabric/src/main/resources/pack.mcmeta
Normale Datei
6
worldedit-fabric/src/main/resources/pack.mcmeta
Normale Datei
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"description": "WorldEdit Resources",
|
||||||
|
"pack_format": 4
|
||||||
|
}
|
||||||
|
}
|
13
worldedit-fabric/src/main/resources/worldedit.mixins.json
Normale Datei
13
worldedit-fabric/src/main/resources/worldedit.mixins.json
Normale Datei
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"package": "com.sk89q.worldedit.fabric.mixin",
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"mixins": [
|
||||||
|
"MixinServerPlayerEntity"
|
||||||
|
],
|
||||||
|
"server": [
|
||||||
|
],
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 1
|
||||||
|
}
|
||||||
|
}
|
@ -124,7 +124,7 @@ public class ForgePlayer extends AbstractPlayerActor {
|
|||||||
send = send + "|" + StringUtil.joinString(params, "|");
|
send = send + "|" + StringUtil.joinString(params, "|");
|
||||||
}
|
}
|
||||||
PacketBuffer buffer = new PacketBuffer(Unpooled.copiedBuffer(send.getBytes(WECUIPacketHandler.UTF_8_CHARSET)));
|
PacketBuffer buffer = new PacketBuffer(Unpooled.copiedBuffer(send.getBytes(WECUIPacketHandler.UTF_8_CHARSET)));
|
||||||
SCustomPayloadPlayPacket packet = new SCustomPayloadPlayPacket(new ResourceLocation(ForgeWorldEdit.CUI_PLUGIN_CHANNEL), buffer);
|
SCustomPayloadPlayPacket packet = new SCustomPayloadPlayPacket(new ResourceLocation(ForgeWorldEdit.MOD_ID, ForgeWorldEdit.CUI_PLUGIN_CHANNEL), buffer);
|
||||||
this.player.connection.sendPacket(packet);
|
this.player.connection.sendPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren