From 2db47f8fd434066013e96f56315273a303a2ea36 Mon Sep 17 00:00:00 2001 From: Wyatt Childers Date: Tue, 2 Feb 2016 01:28:27 -0500 Subject: [PATCH] Initial work on WorldEdit Sponge --- settings.gradle | 2 +- worldedit-sponge/build.gradle | 99 +++++++ worldedit-sponge/src/main/ant/build.xml | 150 ++++++++++ .../worldedit/sponge/CommandWrapper.java | 71 +++++ .../worldedit/sponge/ForgeWorldData.java | 47 +++ .../com/sk89q/worldedit/sponge/IDHelper.java | 58 ++++ .../sk89q/worldedit/sponge/NBTConverter.java | 236 ++++++++++++++++ .../com/sk89q/worldedit/sponge/NMSHelper.java | 49 ++++ .../sponge/SponePermissionsProvider.java | 32 +++ .../sk89q/worldedit/sponge/SpongeAdapter.java | 45 +++ .../worldedit/sponge/SpongeBiomeRegistry.java | 81 ++++++ .../worldedit/sponge/SpongeConfiguration.java | 45 +++ .../sk89q/worldedit/sponge/SpongeEntity.java | 102 +++++++ .../worldedit/sponge/SpongeEntityType.java | 142 ++++++++++ .../worldedit/sponge/SpongeForgeWorld.java | 246 ++++++++++++++++ .../worldedit/sponge/SpongePlatform.java | 174 ++++++++++++ .../sk89q/worldedit/sponge/SpongePlayer.java | 220 +++++++++++++++ .../sk89q/worldedit/sponge/SpongeWorld.java | 251 ++++++++++++++++ .../worldedit/sponge/SpongeWorldEdit.java | 267 ++++++++++++++++++ .../worldedit/sponge/ThreadSafeCache.java | 81 ++++++ .../worldedit/sponge/TileEntityBaseBlock.java | 40 +++ .../worldedit/sponge/TileEntityUtils.java | 146 ++++++++++ .../main/resources/META-INF/worldedit_at.cfg | 4 + .../resources/defaults/worldedit.properties | 32 +++ 24 files changed, 2619 insertions(+), 1 deletion(-) create mode 100644 worldedit-sponge/build.gradle create mode 100644 worldedit-sponge/src/main/ant/build.xml create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandWrapper.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/ForgeWorldData.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/IDHelper.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/NBTConverter.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/NMSHelper.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SponePermissionsProvider.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeAdapter.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBiomeRegistry.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeConfiguration.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntity.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntityType.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeForgeWorld.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/ThreadSafeCache.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/TileEntityBaseBlock.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/TileEntityUtils.java create mode 100644 worldedit-sponge/src/main/resources/META-INF/worldedit_at.cfg create mode 100644 worldedit-sponge/src/main/resources/defaults/worldedit.properties diff --git a/settings.gradle b/settings.gradle index 271359482..576283ecc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,3 @@ rootProject.name = 'worldedit' -include 'worldedit-core', 'worldedit-bukkit', 'worldedit-forge' \ No newline at end of file +include 'worldedit-core', 'worldedit-bukkit', 'worldedit-forge', 'worldedit-sponge' \ No newline at end of file diff --git a/worldedit-sponge/build.gradle b/worldedit-sponge/build.gradle new file mode 100644 index 000000000..b5f073a29 --- /dev/null +++ b/worldedit-sponge/build.gradle @@ -0,0 +1,99 @@ +apply plugin: 'eclipse' +apply plugin: 'idea' + +buildscript { + repositories { + mavenCentral() + maven { url = "http://files.minecraftforge.net/maven" } + maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" } + jcenter() + } + + dependencies { + classpath 'net.minecraftforge.gradle:ForgeGradle:2.1-SNAPSHOT' + } +} + +apply plugin: 'net.minecraftforge.gradle.forge' + +dependencies { + compile project(':worldedit-core') + compile 'org.spongepowered:spongeapi:3.1.0-SNAPSHOT' + compile('org.spongepowered:spongeforge:1.8-1577-2.1-DEV-957') { + exclude module: 'spongeapi' + exclude module: 'spongecommon' + } + testCompile group: 'org.mockito', name: 'mockito-core', version:'1.9.0-rc1' +} + +repositories { + maven { + name = 'forge' + url = 'http://files.minecraftforge.net/maven' + } + maven { + name = "Sponge" + url = "https://repo.spongepowered.org/maven" + } +} + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +version = "6.1.1" +ext.forgeVersion = "11.15.0.1695" +ext.internalVersion = version + ";" + gitCommitHash + +minecraft { + version = "1.8.9-${project.forgeVersion}" + mappings = "snapshot_20160111" + runDir = 'run' + + replaceIn "com/sk89q/worldedit/forge/ForgeWorldEdit.java" + replace "%VERSION%", project.version +} + +project.archivesBaseName = "${project.archivesBaseName}-mc${minecraft.version}" + +processResources { + from (sourceSets.main.resources.srcDirs) { + expand 'version': project.version, + 'mcVersion': project.minecraft.version, + 'forgeVersion': project.forgeVersion, + 'internalVersion': project.internalVersion + include 'mcmod.info' + } + + from (sourceSets.main.resources.srcDirs) { + exclude 'mcmod.info' + } +} + +jar { + manifest { + attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", + "WorldEdit-Version": version, + "FMLAT": "worldedit_at.cfg") + } +} + +shadowJar { + dependencies { + include(dependency(':worldedit-core')) + } +} + +reobf { + shadowJar { + mappingType = 'SEARGE' + } +} + +task deobfJar(type: Jar) { + from sourceSets.main.output + classifier = 'dev' +} + +artifacts { + archives deobfJar +} diff --git a/worldedit-sponge/src/main/ant/build.xml b/worldedit-sponge/src/main/ant/build.xml new file mode 100644 index 000000000..5753b52ce --- /dev/null +++ b/worldedit-sponge/src/main/ant/build.xml @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandWrapper.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandWrapper.java new file mode 100644 index 000000000..62b0dadd6 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandWrapper.java @@ -0,0 +1,71 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.util.command.CommandMapping; +import org.spongepowered.api.command.CommandCallable; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.Texts; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class CommandWrapper implements CommandCallable { + private CommandMapping command; + + protected CommandWrapper(CommandMapping command) { + this.command = command; + } + + @Override + public CommandResult process(CommandSource source, String arguments) throws CommandException { + return null; + } + + @Override + public List getSuggestions(CommandSource source, String arguments) throws CommandException { + return null; + } + + @Override + public boolean testPermission(CommandSource source) { + return true; + } + + @Override + public Optional getShortDescription(CommandSource source) { + return null; + } + + @Override + public Optional getHelp(CommandSource source) { + return null; + } + + @Override + public Text getUsage(CommandSource source) { + return Text.of(command.getDescription().getUsage()); + } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/ForgeWorldData.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/ForgeWorldData.java new file mode 100644 index 000000000..177932daf --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/ForgeWorldData.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.world.registry.BiomeRegistry; +import com.sk89q.worldedit.world.registry.LegacyWorldData; + +/** + * World data for the Forge platform. + */ +class ForgeWorldData extends LegacyWorldData { + + private static final ForgeWorldData INSTANCE = new ForgeWorldData(); + private final BiomeRegistry biomeRegistry = new SpongeBiomeRegistry(); + + @Override + public BiomeRegistry getBiomeRegistry() { + return biomeRegistry; + } + + /** + * Get a static instance. + * + * @return an instance + */ + public static ForgeWorldData getInstance() { + return INSTANCE; + } + +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/IDHelper.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/IDHelper.java new file mode 100644 index 000000000..13fc241bb --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/IDHelper.java @@ -0,0 +1,58 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.entity.BaseEntity; +import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.item.ItemType; +import org.spongepowered.api.world.biome.BiomeType; + +final class IDHelper { + + private IDHelper() { } + + public static int resolve(ItemType type) { + return 0; + } + + public static int resolve(BlockType type) { + return 0; + } + + public static int resolve(BiomeType type) { + return 0; + } + + + public static ItemType resolveItem(int ID) { + return null; + } + + public static BlockType resolveBlock(int ID) { + return null; + } + + public static BiomeType resolveBiome(int ID) { + return null; + } + + +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/NBTConverter.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/NBTConverter.java new file mode 100644 index 000000000..a026a51cf --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/NBTConverter.java @@ -0,0 +1,236 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.jnbt.*; +import net.minecraft.nbt.*; + +import java.util.*; +import java.util.Map.Entry; + +/** + * Converts between JNBT and Minecraft NBT classes. + */ +final class NBTConverter { + + private NBTConverter() { + } + + public static NBTBase 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 NBTTagIntArray toNative(IntArrayTag tag) { + int[] value = tag.getValue(); + return new NBTTagIntArray(Arrays.copyOf(value, value.length)); + } + + public static NBTTagList toNative(ListTag tag) { + NBTTagList list = new NBTTagList(); + for (Tag child : tag.getValue()) { + if (child instanceof EndTag) { + continue; + } + list.appendTag(toNative(child)); + } + return list; + } + + public static NBTTagLong toNative(LongTag tag) { + return new NBTTagLong(tag.getValue()); + } + + public static NBTTagString toNative(StringTag tag) { + return new NBTTagString(tag.getValue()); + } + + public static NBTTagInt toNative(IntTag tag) { + return new NBTTagInt(tag.getValue()); + } + + public static NBTTagByte toNative(ByteTag tag) { + return new NBTTagByte(tag.getValue()); + } + + public static NBTTagByteArray toNative(ByteArrayTag tag) { + byte[] value = tag.getValue(); + return new NBTTagByteArray(Arrays.copyOf(value, value.length)); + } + + public static NBTTagCompound toNative(CompoundTag tag) { + NBTTagCompound compound = new NBTTagCompound(); + for (Entry child : tag.getValue().entrySet()) { + compound.setTag(child.getKey(), toNative(child.getValue())); + } + return compound; + } + + public static NBTTagFloat toNative(FloatTag tag) { + return new NBTTagFloat(tag.getValue()); + } + + public static NBTTagShort toNative(ShortTag tag) { + return new NBTTagShort(tag.getValue()); + } + + public static NBTTagDouble toNative(DoubleTag tag) { + return new NBTTagDouble(tag.getValue()); + } + + public static Tag fromNative(NBTBase other) { + if (other instanceof NBTTagIntArray) { + return fromNative((NBTTagIntArray) other); + + } else if (other instanceof NBTTagList) { + return fromNative((NBTTagList) other); + + } else if (other instanceof NBTTagEnd) { + return fromNative((NBTTagEnd) other); + + } else if (other instanceof NBTTagLong) { + return fromNative((NBTTagLong) other); + + } else if (other instanceof NBTTagString) { + return fromNative((NBTTagString) other); + + } else if (other instanceof NBTTagInt) { + return fromNative((NBTTagInt) other); + + } else if (other instanceof NBTTagByte) { + return fromNative((NBTTagByte) other); + + } else if (other instanceof NBTTagByteArray) { + return fromNative((NBTTagByteArray) other); + + } else if (other instanceof NBTTagCompound) { + return fromNative((NBTTagCompound) other); + + } else if (other instanceof NBTTagFloat) { + return fromNative((NBTTagFloat) other); + + } else if (other instanceof NBTTagShort) { + return fromNative((NBTTagShort) other); + + } else if (other instanceof NBTTagDouble) { + return fromNative((NBTTagDouble) other); + } else { + throw new IllegalArgumentException("Can't convert other of type " + other.getClass().getCanonicalName()); + } + } + + public static IntArrayTag fromNative(NBTTagIntArray other) { + int[] value = other.getIntArray(); + return new IntArrayTag(Arrays.copyOf(value, value.length)); + } + + public static ListTag fromNative(NBTTagList other) { + other = (NBTTagList) other.copy(); + List list = new ArrayList(); + Class listClass = StringTag.class; + int tags = other.tagCount(); + for (int i = 0; i < tags; i++) { + Tag child = fromNative(other.removeTag(0)); + list.add(child); + listClass = child.getClass(); + } + return new ListTag(listClass, list); + } + + public static EndTag fromNative(NBTTagEnd other) { + return new EndTag(); + } + + public static LongTag fromNative(NBTTagLong other) { + return new LongTag(other.getLong()); + } + + public static StringTag fromNative(NBTTagString other) { + return new StringTag(other.getString()); + } + + public static IntTag fromNative(NBTTagInt other) { + return new IntTag(other.getInt()); + } + + public static ByteTag fromNative(NBTTagByte other) { + return new ByteTag(other.getByte()); + } + + public static ByteArrayTag fromNative(NBTTagByteArray other) { + byte[] value = other.getByteArray(); + return new ByteArrayTag(Arrays.copyOf(value, value.length)); + } + + public static CompoundTag fromNative(NBTTagCompound other) { + @SuppressWarnings("unchecked") Set tags = other.getKeySet(); + Map map = new HashMap(); + for (String tagName : tags) { + map.put(tagName, fromNative(other.getTag(tagName))); + } + return new CompoundTag(map); + } + + public static FloatTag fromNative(NBTTagFloat other) { + return new FloatTag(other.getFloat()); + } + + public static ShortTag fromNative(NBTTagShort other) { + return new ShortTag(other.getShort()); + } + + public static DoubleTag fromNative(NBTTagDouble other) { + return new DoubleTag(other.getDouble()); + } + +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/NMSHelper.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/NMSHelper.java new file mode 100644 index 000000000..da8abf3e5 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/NMSHelper.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.entity.BaseEntity; +import net.minecraft.item.Item; +import net.minecraft.nbt.NBTTagCompound; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.item.inventory.ItemStack; + +import java.util.Map; + +final class NMSHelper { + + private NMSHelper() { } + + public static ItemStack makeSpongeStack(BaseItemStack itemStack) { + net.minecraft.item.ItemStack newStack = new net.minecraft.item.ItemStack(Item.getItemById(itemStack.getType()), itemStack.getAmount(), itemStack.getData()); + for (Map.Entry entry : itemStack.getEnchantments().entrySet()) { + newStack.addEnchantment(net.minecraft.enchantment.Enchantment.getEnchantmentById(entry.getKey()), entry.getValue()); + } + return (ItemStack) (Object) newStack; + } + + public static BaseEntity createBaseEntity(Entity entity) { + String id = entity.getType().getId(); + NBTTagCompound tag = new NBTTagCompound(); + ((net.minecraft.entity.Entity) entity).writeToNBT(tag); + return new BaseEntity(id, NBTConverter.fromNative(tag)); + } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SponePermissionsProvider.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SponePermissionsProvider.java new file mode 100644 index 000000000..967b25a55 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SponePermissionsProvider.java @@ -0,0 +1,32 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import org.spongepowered.api.command.CommandCallable; +import org.spongepowered.api.entity.living.player.Player; + +public class SponePermissionsProvider { + + public boolean hasPermission(Player player, String permission) { + return player.hasPermission(permission); + } + + public void registerPermission(CommandCallable command, String permission) { } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeAdapter.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeAdapter.java new file mode 100644 index 000000000..3d9c756d6 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeAdapter.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.flowpowered.math.vector.Vector3d; +import com.flowpowered.math.vector.Vector3i; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.NullWorld; +import com.sk89q.worldedit.world.World; + +final class SpongeAdapter { + + private SpongeAdapter() { + } + + public static World adapt(org.spongepowered.api.world.World world) { + return new SpongeForgeWorld(world); + } + + public static Location adapt(org.spongepowered.api.world.Location loc, Vector3d rot) { + Vector position = new Vector(loc.getX(), loc.getY(), loc.getZ()); + Vector dir = new Vector(rot.getX(), rot.getY(), rot.getZ()); + + return new Location(SpongeAdapter.adapt(loc.getExtent()), position, dir); + } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBiomeRegistry.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBiomeRegistry.java new file mode 100644 index 000000000..5bf2ef088 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBiomeRegistry.java @@ -0,0 +1,81 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.world.biome.BaseBiome; +import com.sk89q.worldedit.world.biome.BiomeData; +import com.sk89q.worldedit.world.registry.BiomeRegistry; + +import org.spongepowered.api.Sponge; +import org.spongepowered.api.world.biome.BiomeType; + +import javax.annotation.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * Provides access to biome data in Forge. + */ +class SpongeBiomeRegistry implements BiomeRegistry { + + @Nullable + @Override + public BaseBiome createFromId(int id) { + return new BaseBiome(id); + } + + @Override + public List getBiomes() { + List list = new ArrayList(); + for (BiomeType biome : Sponge.getGame().getRegistry().getAllOf(BiomeType.class)) { + list.add(new BaseBiome(IDHelper.resolve(biome))); + } + return list; + } + + @Nullable + @Override + public BiomeData getData(BaseBiome biome) { + return new SpongeBiomeData(IDHelper.resolveBiome(biome.getId())); + } + + /** + * Cached biome data information. + */ + private static class SpongeBiomeData implements BiomeData { + private final BiomeType biome; + + /** + * Create a new instance. + * + * @param biome the base biome + */ + private SpongeBiomeData(BiomeType biome) { + this.biome = biome; + } + + @Override + public String getName() { + return biome.getName(); + } + } + +} \ No newline at end of file diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeConfiguration.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeConfiguration.java new file mode 100644 index 000000000..13c755fd4 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeConfiguration.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.util.PropertiesConfiguration; + +import java.io.File; + +public class SpongeConfiguration extends PropertiesConfiguration { + + public boolean creativeEnable = false; + public boolean cheatMode = false; + + public SpongeConfiguration(SpongeWorldEdit mod) { + super(new File(mod.getWorkingDir() + File.separator + "worldedit.properties")); + } + + @Override + protected void loadExtra() { + creativeEnable = getBool("use-in-creative", false); + cheatMode = getBool("cheat-mode", false); + } + + @Override + public File getWorkingDirectory() { + return SpongeWorldEdit.inst.getWorkingDir(); + } +} \ No newline at end of file diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntity.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntity.java new file mode 100644 index 000000000..5c93aeafe --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntity.java @@ -0,0 +1,102 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.flowpowered.math.vector.Vector3d; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.metadata.EntityType; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.NullWorld; +import org.spongepowered.api.world.World; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; + +import static com.google.common.base.Preconditions.checkNotNull; + +class SpongeEntity implements Entity { + + private final WeakReference entityRef; + + SpongeEntity(org.spongepowered.api.entity.Entity entity) { + checkNotNull(entity); + this.entityRef = new WeakReference<>(entity); + } + + @Override + public BaseEntity getState() { + org.spongepowered.api.entity.Entity entity = entityRef.get(); + if (entity != null) { + return NMSHelper.createBaseEntity(entity); + } else { + return null; + } + } + + @Override + public Location getLocation() { + org.spongepowered.api.entity.Entity entity = entityRef.get(); + if (entity != null) { + org.spongepowered.api.world.Location entityLoc = entity.getLocation(); + Vector3d entityRot = entity.getRotation(); + + return SpongeAdapter.adapt(entityLoc, entityRot); + } else { + return new Location(NullWorld.getInstance()); + } + } + + @Override + public Extent getExtent() { + org.spongepowered.api.entity.Entity entity = entityRef.get(); + if (entity != null) { + return SpongeAdapter.adapt(entity.getWorld()); + } else { + return NullWorld.getInstance(); + } + } + + @Override + public boolean remove() { + org.spongepowered.api.entity.Entity entity = entityRef.get(); + if (entity != null) { + entity.remove(); + } + return true; + } + + @SuppressWarnings("unchecked") + @Nullable + @Override + public T getFacet(Class cls) { + org.spongepowered.api.entity.Entity entity = entityRef.get(); + if (entity != null) { + if (EntityType.class.isAssignableFrom(cls)) { + return (T) new SpongeEntityType(entity); + } else { + return null; + } + } else { + return null; + } + } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntityType.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntityType.java new file mode 100644 index 000000000..afd2393cc --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntityType.java @@ -0,0 +1,142 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.entity.metadata.EntityType; +import org.spongepowered.api.data.key.Keys; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.entity.ExperienceOrb; +import org.spongepowered.api.entity.FallingBlock; +import org.spongepowered.api.entity.Item; +import org.spongepowered.api.entity.explosive.PrimedTNT; +import org.spongepowered.api.entity.hanging.ItemFrame; +import org.spongepowered.api.entity.hanging.Painting; +import org.spongepowered.api.entity.living.*; +import org.spongepowered.api.entity.living.animal.Animal; +import org.spongepowered.api.entity.living.golem.Golem; +import org.spongepowered.api.entity.projectile.Projectile; +import org.spongepowered.api.entity.vehicle.Boat; +import org.spongepowered.api.entity.vehicle.minecart.Minecart; +import org.spongepowered.api.text.Text; + +import java.util.Optional; +import java.util.UUID; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class SpongeEntityType implements EntityType { + + private final Entity entity; + + public SpongeEntityType(Entity entity) { + checkNotNull(entity); + this.entity = entity; + } + + @Override + public boolean isPlayerDerived() { + return entity instanceof Humanoid; + } + + @Override + public boolean isProjectile() { + return entity instanceof Projectile; + } + + @Override + public boolean isItem() { + return entity instanceof Item; + } + + @Override + public boolean isFallingBlock() { + return entity instanceof FallingBlock; + } + + @Override + public boolean isPainting() { + return entity instanceof Painting; + } + + @Override + public boolean isItemFrame() { + return entity instanceof ItemFrame; + } + + @Override + public boolean isBoat() { + return entity instanceof Boat; + } + + @Override + public boolean isMinecart() { + return entity instanceof Minecart; + } + + @Override + public boolean isTNT() { + return entity instanceof PrimedTNT; + } + + @Override + public boolean isExperienceOrb() { + return entity instanceof ExperienceOrb; + } + + @Override + public boolean isLiving() { + return entity instanceof Living; + } + + @Override + public boolean isAnimal() { + return entity instanceof Animal; + } + + @Override + public boolean isAmbient() { + return entity instanceof Ambient; + } + + @Override + public boolean isNPC() { + return entity instanceof Villager; + } + + @Override + public boolean isGolem() { + return entity instanceof Golem; + } + + @Override + public boolean isTamed() { + return entity.get(Keys.TAMED_OWNER).orElse(Optional.empty()).isPresent(); + } + + @Override + public boolean isTagged() { + return entity.get(Keys.DISPLAY_NAME).orElse(Text.EMPTY).isEmpty(); + } + + @Override + public boolean isArmorStand() { + return entity instanceof ArmorStand; + } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeForgeWorld.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeForgeWorld.java new file mode 100644 index 000000000..c6c16cf1e --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeForgeWorld.java @@ -0,0 +1,246 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.flowpowered.math.vector.Vector3d; +import com.flowpowered.math.vector.Vector3i; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.LazyBlock; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.*; +import net.minecraft.block.*; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.IInventory; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BlockPos; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.gen.ChunkProviderServer; +import net.minecraft.world.gen.feature.*; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.block.BlockSnapshot; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.entity.EntitySnapshot; +import org.spongepowered.api.entity.EntityType; +import org.spongepowered.api.world.Location; +import org.spongepowered.api.world.World; +import org.spongepowered.common.block.SpongeBlockSnapshot; +import org.spongepowered.common.block.SpongeBlockSnapshotBuilder; +import org.spongepowered.common.entity.SpongeEntitySnapshot; +import org.spongepowered.common.entity.SpongeEntitySnapshotBuilder; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.logging.Level; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class SpongeForgeWorld extends SpongeWorld { + + private final SpongeBlockSnapshotBuilder blockBuilder = new SpongeBlockSnapshotBuilder(); + private final SpongeEntitySnapshotBuilder entityBuilder = new SpongeEntitySnapshotBuilder(); + + private static final IBlockState JUNGLE_LOG = Blocks.log.getDefaultState().withProperty(BlockOldLog.VARIANT, BlockPlanks.EnumType.JUNGLE); + private static final IBlockState JUNGLE_LEAF = Blocks.leaves.getDefaultState().withProperty(BlockOldLeaf.VARIANT, BlockPlanks.EnumType.JUNGLE).withProperty(BlockLeaves.CHECK_DECAY, Boolean.valueOf(false)); + private static final IBlockState JUNGLE_SHRUB = Blocks.leaves.getDefaultState().withProperty(BlockOldLeaf.VARIANT, BlockPlanks.EnumType.OAK).withProperty(BlockLeaves.CHECK_DECAY, Boolean.valueOf(false)); + + /** + * Construct a new world. + * + * @param world the world + */ + public SpongeForgeWorld(World world) { + super(world); + } + + @Override + protected BlockSnapshot createBlockSnapshot(Vector position, BaseBlock block) { + this.blockBuilder.reset(); + Location location = new Location<>(getWorld(), new Vector3i(position.getX(), position.getY(), position.getZ())); + + this.blockBuilder.blockState((BlockState) Block.getBlockById(block.getId()).getStateFromMeta(block.getData())); + this.blockBuilder.worldId(location.getExtent().getUniqueId()); + this.blockBuilder.position(location.getBlockPosition()); + + if (block.hasNbtData()) { + this.blockBuilder.unsafeNbt(NBTConverter.toNative(block.getNbtData())); + } + + return new SpongeBlockSnapshot(this.blockBuilder, 0); + } + + @Override + protected EntitySnapshot createEntitySnapshot(com.sk89q.worldedit.util.Location location, BaseEntity entity) { + this.entityBuilder.reset(); + + this.entityBuilder.position(new Vector3d(location.getX(), location.getY(), location.getZ())); + // TODO Rotation code + // this.entityBuilder.rotation() + this.entityBuilder.type(Sponge.getRegistry().getType(EntityType.class, entity.getTypeId()).get()); + if (entity.hasNbtData()) { + this.entityBuilder.unsafeCompound(NBTConverter.toNative(entity.getNbtData())); + } + return this.entityBuilder.build(); + } + + @Override + public boolean clearContainerBlockContents(Vector position) { + BlockPos pos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + TileEntity tile =((net.minecraft.world.World) getWorld()).getTileEntity(pos); + if (tile instanceof IInventory) { + IInventory inv = (IInventory) tile; + int size = inv.getSizeInventory(); + for (int i = 0; i < size; i++) { + inv.setInventorySlotContents(i, null); + } + return true; + } + return false; + } + + @Override + public boolean regenerate(Region region, EditSession editSession) { + BaseBlock[] history = new BaseBlock[256 * (getMaxY() + 1)]; + + for (Vector2D chunk : region.getChunks()) { + Vector min = new Vector(chunk.getBlockX() * 16, 0, chunk.getBlockZ() * 16); + + for (int x = 0; x < 16; x++) { + for (int y = 0; y < getMaxY() + 1; y++) { + for (int z = 0; z < 16; z++) { + Vector pt = min.add(x, y, z); + int index = y * 16 * 16 + z * 16 + x; + history[index] = editSession.getBlock(pt); + } + } + } + try { + Set chunks = region.getChunks(); + IChunkProvider provider = ((net.minecraft.world.World) getWorld()).getChunkProvider(); + if (!(provider instanceof ChunkProviderServer)) { + return false; + } + ChunkProviderServer chunkServer = (ChunkProviderServer) provider; + IChunkProvider chunkProvider = chunkServer.serverChunkGenerator; + + for (Vector2D coord : chunks) { + long pos = ChunkCoordIntPair.chunkXZ2Int(coord.getBlockX(), coord.getBlockZ()); + Chunk mcChunk; + if (chunkServer.chunkExists(coord.getBlockX(), coord.getBlockZ())) { + mcChunk = chunkServer.loadChunk(coord.getBlockX(), coord.getBlockZ()); + mcChunk.onChunkUnload(); + } + chunkServer.droppedChunksSet.remove(pos); + chunkServer.id2ChunkMap.remove(pos); + mcChunk = chunkProvider.provideChunk(coord.getBlockX(), coord.getBlockZ()); + chunkServer.id2ChunkMap.add(pos, mcChunk); + chunkServer.loadedChunks.add(mcChunk); + if (mcChunk != null) { + mcChunk.onChunkLoad(); + mcChunk.populateChunk(chunkProvider, chunkProvider, coord.getBlockX(), coord.getBlockZ()); + } + } + } catch (Throwable t) { + logger.log(Level.WARNING, "Failed to generate chunk", t); + return false; + } + + for (int x = 0; x < 16; x++) { + for (int y = 0; y < getMaxY() + 1; y++) { + for (int z = 0; z < 16; z++) { + Vector pt = min.add(x, y, z); + int index = y * 16 * 16 + z * 16 + x; + + if (!region.contains(pt)) + editSession.smartSetBlock(pt, history[index]); + else { + editSession.rememberChange(pt, history[index], editSession.rawGetBlock(pt)); + } + } + } + } + } + + return false; + } + + @Nullable + private static WorldGenerator createWorldGenerator(TreeGenerator.TreeType type) { + switch (type) { + case TREE: return new WorldGenTrees(true); + case BIG_TREE: return new WorldGenBigTree(true); + case REDWOOD: return new WorldGenTaiga2(true); + case TALL_REDWOOD: return new WorldGenTaiga1(); + case BIRCH: return new WorldGenForest(true, false); + case JUNGLE: return new WorldGenMegaJungle(true, 10, 20, JUNGLE_LOG, JUNGLE_LEAF); + case SMALL_JUNGLE: return new WorldGenTrees(true, 4 + random.nextInt(7), JUNGLE_LOG, JUNGLE_LEAF, false); + case SHORT_JUNGLE: return new WorldGenTrees(true, 4 + random.nextInt(7), JUNGLE_LOG, JUNGLE_LEAF, true); + case JUNGLE_BUSH: return new WorldGenShrub(JUNGLE_LOG, JUNGLE_SHRUB); + case RED_MUSHROOM: return new WorldGenBigMushroom(Blocks.brown_mushroom_block); + case BROWN_MUSHROOM: return new WorldGenBigMushroom(Blocks.red_mushroom_block); + case SWAMP: return new WorldGenSwamp(); + case ACACIA: return new WorldGenSavannaTree(true); + case DARK_OAK: return new WorldGenCanopyTree(true); + case MEGA_REDWOOD: return new WorldGenMegaPineTree(false, random.nextBoolean()); + case TALL_BIRCH: return new WorldGenForest(true, true); + case RANDOM: + case PINE: + case RANDOM_REDWOOD: + default: + return null; + } + } + + @Override + public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, Vector pos) throws MaxChangedBlocksException { + WorldGenerator generator = createWorldGenerator(type); + return generator != null && generator.generate((net.minecraft.world.World) getWorld(), random, new BlockPos(pos.getX(), pos.getY(), pos.getZ())); + } + + @Override + public BaseBlock getBlock(Vector position) { + World world = getWorld(); + BlockPos pos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + IBlockState state = ((net.minecraft.world.World) world).getBlockState(pos); + TileEntity tile = ((net.minecraft.world.World) world).getTileEntity(pos); + + if (tile != null) { + return new TileEntityBaseBlock(Block.getIdFromBlock(state.getBlock()), state.getBlock().getMetaFromState(state), tile); + } else { + return new BaseBlock(Block.getIdFromBlock(state.getBlock()), state.getBlock().getMetaFromState(state)); + } + } + + @Override + public BaseBlock getLazyBlock(Vector position) { + World world = getWorld(); + BlockPos pos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + IBlockState state = ((net.minecraft.world.World) world).getBlockState(pos); + return new LazyBlock(Block.getIdFromBlock(state.getBlock()), state.getBlock().getMetaFromState(state), this, position); + } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java new file mode 100644 index 000000000..6790ccc61 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java @@ -0,0 +1,174 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +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.util.command.CommandMapping; +import com.sk89q.worldedit.util.command.Dispatcher; +import com.sk89q.worldedit.world.World; + +import org.spongepowered.api.Sponge; +import org.spongepowered.api.entity.EntityType; +import org.spongepowered.api.item.ItemType; +import org.spongepowered.api.scheduler.Task; + +import javax.annotation.Nullable; + +import java.util.*; + +class SpongePlatform extends AbstractPlatform implements MultiUserPlatform { + + private final SpongeWorldEdit mod; + private boolean hookingEvents = false; + + SpongePlatform(SpongeWorldEdit mod) { + this.mod = mod; + } + + boolean isHookingEvents() { + return hookingEvents; + } + + @Override + public int resolveItem(String name) { + if (name == null) return 0; + + Optional optType = Sponge.getRegistry().getType(ItemType.class, name); + + if (optType.isPresent()) { + return IDHelper.resolve(optType.get()); + } + + return 0; + } + + @Override + public boolean isValidMobType(String type) { + return Sponge.getRegistry().getType(EntityType.class, type).isPresent(); + } + + @Override + public void reload() { + getConfiguration().load(); + } + + @Override + public int schedule(long delay, long period, Runnable task) { + Task.builder().delayTicks(delay).intervalTicks(period).execute(task).submit(SpongeWorldEdit.inst); + return 0; // TODO This isn't right, but we only check for -1 values + } + + @Override + public List getWorlds() { + Collection worlds = Sponge.getServer().getWorlds(); + List ret = new ArrayList<>(worlds.size()); + for (org.spongepowered.api.world.World world : worlds) { + ret.add(new SpongeForgeWorld(world)); + } + return ret; + } + + @Nullable + @Override + public Player matchPlayer(Player player) { + if (player instanceof SpongePlayer) { + return player; + } else { + Optional optPlayer = Sponge.getServer().getPlayer(player.getUniqueId()); + return optPlayer.isPresent() ? new SpongePlayer(this, optPlayer.get()) : null; + } + } + + @Nullable + @Override + public World matchWorld(World world) { + if (world instanceof SpongeWorld) { + return world; + } else { + for (org.spongepowered.api.world.World ws : Sponge.getServer().getWorlds()) { + if (ws.getName().equals(world.getName())) { + return new SpongeForgeWorld(ws); + } + } + + return null; + } + } + + @Override + public void registerCommands(Dispatcher dispatcher) { + for (final CommandMapping command : dispatcher.getCommands()) { + Sponge.getCommandManager().register(SpongeWorldEdit.inst, new CommandWrapper(command), command.getAllAliases()); + } + } + + @Override + public void registerGameHooks() { + // We registered the events already anyway, so we just 'turn them on' + hookingEvents = true; + } + + @Override + public SpongeConfiguration getConfiguration() { + return mod.getConfig(); + } + + @Override + public String getVersion() { + return mod.getInternalVersion(); + } + + @Override + public String getPlatformName() { + return "Sponge-Official"; + } + + @Override + public String getPlatformVersion() { + return mod.getInternalVersion(); + } + + @Override + public Map getCapabilities() { + Map capabilities = new EnumMap<>(Capability.class); + capabilities.put(Capability.CONFIGURATION, Preference.PREFER_OTHERS); + // TODO WorldEditCUI Support + // 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 getConnectedUsers() { + List users = new ArrayList(); + for (org.spongepowered.api.entity.living.player.Player player : Sponge.getServer().getOnlinePlayers()) { + users.add(new SpongePlayer(this, player)); + } + return users; + } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java new file mode 100644 index 000000000..d2086533b --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java @@ -0,0 +1,220 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.flowpowered.math.vector.Vector3d; +import com.sk89q.util.StringUtil; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldVector; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.platform.AbstractPlayerActor; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.internal.LocalWorldAdapter; +import com.sk89q.worldedit.internal.cui.CUIEvent; +import com.sk89q.worldedit.session.SessionKey; +import com.sk89q.worldedit.util.Location; + +import org.spongepowered.api.Sponge; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColor; +import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.world.World; + +import javax.annotation.Nullable; + +import java.util.Optional; +import java.util.UUID; + +public class SpongePlayer extends AbstractPlayerActor { + + private final Player player; + + protected SpongePlayer(SpongePlatform platform, Player player) { + this.player = player; + ThreadSafeCache.getInstance().getOnlineIds().add(getUniqueId()); + } + + @Override + public UUID getUniqueId() { + return player.getUniqueId(); + } + + @Override + public int getItemInHand() { + Optional is = this.player.getItemInHand(); + return is.isPresent() ? IDHelper.resolve(is.get().getItem()) : 0; + } + + @Override + public String getName() { + return this.player.getName(); + } + + @Override + public BaseEntity getState() { + throw new UnsupportedOperationException("Cannot create a state from this object"); + } + + @Override + public Location getLocation() { + org.spongepowered.api.world.Location entityLoc = this.player.getLocation(); + Vector3d entityRot = this.player.getRotation(); + + return SpongeAdapter.adapt(entityLoc, entityRot); + } + + @Override + public WorldVector getPosition() { + Vector3d pos = this.player.getLocation().getPosition(); + return new WorldVector(LocalWorldAdapter.adapt(SpongeAdapter.adapt(this.player.getWorld())), pos.getX(), pos.getY(), pos.getZ()); + } + + @Override + public com.sk89q.worldedit.world.World getWorld() { + return SpongeAdapter.adapt(player.getWorld()); + } + + @Override + public double getPitch() { + return getLocation().getPitch(); + } + + @Override + public double getYaw() { + return getLocation().getYaw(); + } + + @Override + public void giveItem(int type, int amt) { + this.player.getInventory().offer(ItemStack.of(IDHelper.resolveItem(type), amt)); + } + + @Override + public void dispatchCUIEvent(CUIEvent event) { + String[] params = event.getParameters(); + String send = event.getTypeId(); + if (params.length > 0) { + send = send + "|" + StringUtil.joinString(params, "|"); + } + } + + @Override + public void printRaw(String msg) { + for (String part : msg.split("\n")) { + this.player.sendMessage(Text.of(part)); + } + } + + @Override + public void printDebug(String msg) { + sendColorized(msg, TextColors.GRAY); + } + + @Override + public void print(String msg) { + sendColorized(msg, TextColors.LIGHT_PURPLE); + } + + @Override + public void printError(String msg) { + sendColorized(msg, TextColors.RED); + } + + private void sendColorized(String msg, TextColor formatting) { + for (String part : msg.split("\n")) { + this.player.sendMessage(Text.of(formatting, part)); + } + } + + @Override + public void setPosition(Vector pos, float pitch, float yaw) { + org.spongepowered.api.world.Location loc = new org.spongepowered.api.world.Location( + this.player.getWorld(), pos.getX(), pos.getY(), pos.getZ() + ); + + // TODO Rotation code + this.player.setLocation(loc); + } + + @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 SpongeWorldEdit.inst.getPermissionsProvider().hasPermission(player, perm); + } + + @Nullable + @Override + public T getFacet(Class cls) { + return null; + } + + @Override + public SessionKey getSessionKey() { + return new SessionKeyImpl(player.getUniqueId(), player.getName()); + } + + 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; + } + + } + +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java new file mode 100644 index 000000000..c6b8a979d --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java @@ -0,0 +1,251 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.flowpowered.math.vector.Vector3d; +import com.flowpowered.math.vector.Vector3i; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.AbstractWorld; +import com.sk89q.worldedit.world.biome.BaseBiome; +import com.sk89q.worldedit.world.registry.WorldData; + +import java.lang.ref.WeakReference; +import java.util.*; +import java.util.logging.Logger; +import javax.annotation.Nullable; +import org.spongepowered.api.block.BlockSnapshot; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.data.key.Keys; +import org.spongepowered.api.data.property.block.GroundLuminanceProperty; +import org.spongepowered.api.data.property.block.SkyLuminanceProperty; +import org.spongepowered.api.entity.EntitySnapshot; +import org.spongepowered.api.entity.EntityTypes; +import org.spongepowered.api.event.cause.Cause; +import org.spongepowered.api.world.World; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An adapter to Minecraft worlds for WorldEdit. + */ +public abstract class SpongeWorld extends AbstractWorld { + + protected static final Random random = new Random(); + protected static final int UPDATE = 1, NOTIFY = 2, NOTIFY_CLIENT = 4; + protected static final Logger logger = Logger.getLogger(SpongeWorld.class.getCanonicalName()); + + private final WeakReference worldRef; + + /** + * Construct a new world. + * + * @param world the world + */ + SpongeWorld(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().getName(); + } + + protected abstract BlockSnapshot createBlockSnapshot(Vector position, BaseBlock block); + + @Override + public boolean setBlock(Vector position, BaseBlock block, boolean notifyAndLight) throws WorldEditException { + checkNotNull(position); + checkNotNull(block); + + return createBlockSnapshot(position, block).restore(true, notifyAndLight); + } + + @Override + public int getBlockLightLevel(Vector position) { + checkNotNull(position); + + BlockState state = getWorld().getBlock(new Vector3i(position.getX(), position.getY(), position.getZ())); + + Optional groundLuminanceProperty = state.getProperty(GroundLuminanceProperty.class); + Optional skyLuminanceProperty = state.getProperty(SkyLuminanceProperty.class); + + if (!groundLuminanceProperty.isPresent() || !skyLuminanceProperty.isPresent()) { + return 0; + } + + //noinspection ConstantConditions + return (int) Math.max(groundLuminanceProperty.get().getValue(), skyLuminanceProperty.get().getValue()); + + } + + @Override + public BaseBiome getBiome(Vector2D position) { + checkNotNull(position); + return new BaseBiome(IDHelper.resolve(getWorld().getBiome(position.getBlockX(), position.getBlockZ()))); + } + + @Override + public boolean setBiome(Vector2D position, BaseBiome biome) { + checkNotNull(position); + checkNotNull(biome); + + getWorld().setBiome(position.getBlockX(), position.getBlockZ(), IDHelper.resolveBiome(biome.getId())); + return true; + } + + @Override + public void dropItem(Vector position, BaseItemStack item) { + checkNotNull(position); + checkNotNull(item); + + if (item.getType() == 0) { + return; + } + + Optional optItem = getWorld().createEntity( + EntityTypes.ITEM, + new Vector3d(position.getX(), position.getY(), position.getZ()) + ); + + if (optItem.isPresent()) { + org.spongepowered.api.entity.Entity entity = optItem.get(); + entity.offer(Keys.REPRESENTED_ITEM, SpongeWorldEdit.toSpongeItemStack(item).createSnapshot()); + getWorld().spawnEntity(entity, Cause.of(SpongeWorldEdit.inst)); + } + } + + + + @Override + public WorldData getWorldData() { + return ForgeWorldData.getInstance(); + } + + @Override + public boolean isValidBlockType(int id) { + return (id == 0) || (IDHelper.resolveItem(id) != null); + } + + @Override + public int hashCode() { + return getWorld().hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o == null) { + return false; + } else if ((o instanceof SpongeWorld)) { + SpongeWorld other = ((SpongeWorld) o); + World otherWorld = other.worldRef.get(); + World thisWorld = worldRef.get(); + return otherWorld != null && thisWorld != 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 getEntities(Region region) { + List entities = new ArrayList<>(); + for (org.spongepowered.api.entity.Entity entity : getWorld().getEntities()) { + org.spongepowered.api.world.Location loc = entity.getLocation(); + if (region.contains(new Vector(loc.getX(), loc.getY(), loc.getZ()))) { + entities.add(new SpongeEntity(entity)); + } + } + return entities; + } + + @Override + public List getEntities() { + List entities = new ArrayList<>(); + for (org.spongepowered.api.entity.Entity entity : getWorld().getEntities()) { + entities.add(new SpongeEntity(entity)); + } + return entities; + } + + protected abstract EntitySnapshot createEntitySnapshot(Location location, BaseEntity entity); + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + EntitySnapshot snapshot = createEntitySnapshot(location, entity); + if (snapshot != null) { + Optional restoredEnt = snapshot.restore(); + if (restoredEnt.isPresent()) { + return new SpongeEntity(restoredEnt.get()); + } + } + return null; + } + + /** + * Thrown when the reference to the world is lost. + */ + private static class WorldReferenceLostException extends WorldEditException { + private WorldReferenceLostException(String message) { + super(message); + } + } + +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java new file mode 100644 index 000000000..173e7e8e7 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java @@ -0,0 +1,267 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.google.inject.Inject; +import org.apache.logging.log4j.Logger; + +import com.google.common.base.Joiner; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldVector; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.event.platform.PlatformReadyEvent; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.internal.LocalWorldAdapter; + +import java.io.File; +import java.nio.file.Path; +import java.util.Map; +import java.util.Optional; + +import org.spongepowered.api.Sponge; +import org.spongepowered.api.block.BlockSnapshot; +import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.block.BlockTypes; +import org.spongepowered.api.config.ConfigManager; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.block.InteractBlockEvent; +import org.spongepowered.api.event.cause.NamedCause; +import org.spongepowered.api.event.game.state.*; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.plugin.Plugin; +import org.spongepowered.api.world.Location; +import org.spongepowered.api.world.World; +import org.spongepowered.mod.mixin.core.event.state.MixinEventServerAboutToStart; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The Sponge implementation of WorldEdit. + */ +@Plugin(id = "SpongeWorldEdit.MOD_ID", name = "WorldEdit", version = "%VERSION%") +public class SpongeWorldEdit { + + @Inject + private java.util.logging.Logger logger; + + public static final String MOD_ID = "worldedit"; + public static final String CUI_PLUGIN_CHANNEL = "WECUI"; + + private SponePermissionsProvider provider; + + public static SpongeWorldEdit inst; + + private SpongePlatform platform; + private SpongeConfiguration config; + private File workingDir; + + @Listener + public void preInit(GamePreInitializationEvent event) { + // Setup working directory + ConfigManager service = Sponge.getGame().getConfigManager(); + Path path = service.getPluginConfig(this).getDirectory(); + + workingDir = path.toFile(); + workingDir.mkdir(); + + config = new SpongeConfiguration(this); + config.load(); + + Sponge.getEventManager().registerListeners(this, ThreadSafeCache.getInstance()); + } + + @Listener + public void init(GameInitializationEvent event) { + // WECUIPacketHandler.init(); + } + + @Listener + public void postInit(GamePostInitializationEvent event) { + logger.info("WorldEdit for Forge (version " + getInternalVersion() + ") is loaded"); + } + + @Listener + public void serverAboutToStart(GameAboutToStartServerEvent event) { + if (this.platform != null) { + logger.warning("FMLServerStartingEvent occurred when FMLServerStoppingEvent hasn't"); + WorldEdit.getInstance().getPlatformManager().unregister(platform); + } + + this.platform = new SpongePlatform(this); + this.provider = new SponePermissionsProvider(); + + WorldEdit.getInstance().getPlatformManager().register(platform); + } + + @Listener + public void serverStopping(GameStoppingServerEvent event) { + WorldEdit.getInstance().getPlatformManager().unregister(platform); + } + + @Listener + public void serverStarted(GameStartedServerEvent event) { + WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); + } + + /*@Listener + public void onCommandEvent(CommandEvent event) { + if ((event.sender instanceof EntityPlayerMP)) { + if (((EntityPlayerMP) event.sender).worldObj.isRemote) return; + String[] split = new String[event.parameters.length + 1]; + System.arraycopy(event.parameters, 0, split, 1, event.parameters.length); + split[0] = event.command.getCommandName(); + com.sk89q.worldedit.event.platform.CommandEvent weEvent = + new com.sk89q.worldedit.event.platform.CommandEvent(wrap((EntityPlayerMP) event.sender), Joiner.on(" ").join(split)); + WorldEdit.getInstance().getEventBus().post(weEvent); + } + }*/ + + @Listener + public void onPlayerInteract(InteractBlockEvent event) { + if (platform == null) { + return; + } + + if (!platform.isHookingEvents()) return; // We have to be told to catch these events + + WorldEdit we = WorldEdit.getInstance(); + Optional optPlayer = event.getCause().get(NamedCause.SOURCE, Player.class); + SpongePlayer player = wrap(optPlayer.get()); + com.sk89q.worldedit.world.World world = player.getWorld(); + + BlockSnapshot targetBlock = event.getTargetBlock(); + Location loc = targetBlock.getLocation().get(); + BlockType interactedType = targetBlock.getState().getType(); + + if (event instanceof InteractBlockEvent.Primary) { + if (interactedType != BlockTypes.AIR) { + WorldVector pos = new WorldVector(LocalWorldAdapter.adapt(world), loc.getX(), loc.getY(), loc.getZ()); + + if (we.handleBlockLeftClick(player, pos)) { + event.setCancelled(true); + } + + if (we.handleArmSwing(player)) { + event.setCancelled(true); + } + } + } else if (event instanceof InteractBlockEvent.Secondary) { + if (interactedType != BlockTypes.AIR) { + WorldVector pos = new WorldVector(LocalWorldAdapter.adapt(world), loc.getX(), loc.getY(), loc.getZ()); + + if (we.handleBlockRightClick(player, pos)) { + event.setCancelled(true); + } + + if (we.handleRightClick(player)) { + event.setCancelled(true); + } + } else { + if (we.handleRightClick(player)) { + event.setCancelled(true); + } + } + } + } + + public static ItemStack toSpongeItemStack(BaseItemStack item) { + return NMSHelper.makeSpongeStack(item); + } + + /** + * Get the configuration. + * + * @return the Forge configuration + */ + SpongeConfiguration getConfig() { + return this.config; + } + + /** + * Get the WorldEdit proxy for the given player. + * + * @param player the player + * @return the WorldEdit player + */ + public SpongePlayer wrap(Player player) { + checkNotNull(player); + return new SpongePlayer(platform, player); + } + + /** + * Get the session for a player. + * + * @param player the player + * @return the session + */ + public LocalSession getSession(Player player) { + checkNotNull(player); + return WorldEdit.getInstance().getSessionManager().get(wrap(player)); + } + + /** + * Get the WorldEdit proxy for the given world. + * + * @param world the world + * @return the WorldEdit world + */ + public SpongeWorld getWorld(World world) { + checkNotNull(world); + return new SpongeForgeWorld(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; + } + + /** + * Get the version of the WorldEdit-for-Forge implementation. + * + * @return a version string + */ + String getInternalVersion() { + return SpongeWorldEdit.class.getAnnotation(Plugin.class).version(); + } + + public void setPermissionsProvider(SponePermissionsProvider provider) { + this.provider = provider; + } + + public SponePermissionsProvider getPermissionsProvider() { + return provider; + } + +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/ThreadSafeCache.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/ThreadSafeCache.java new file mode 100644 index 000000000..9655e015e --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/ThreadSafeCache.java @@ -0,0 +1,81 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +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 { + + private static final long REFRESH_DELAY = 1000 * 30; + private static final ThreadSafeCache INSTANCE = new ThreadSafeCache(); + private Set onlineIds = Collections.emptySet(); + private long lastRefresh = 0; + + /** + * Get an concurrent-safe set of UUIDs of online players. + * + * @return a set of UUIDs + */ + public Set getOnlineIds() { + return onlineIds; + } + + @SubscribeEvent + public void tickStart(TickEvent event) { + long now = System.currentTimeMillis(); + + if (now - lastRefresh > REFRESH_DELAY) { + Set onlineIds = new HashSet(); + + MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance(); + if (server == null || server.getConfigurationManager() == null) { + return; + } + for (Object object : FMLCommonHandler.instance().getMinecraftServerInstance().getConfigurationManager().playerEntityList) { + if (object != null) { + EntityPlayerMP player = (EntityPlayerMP) object; + onlineIds.add(player.getUniqueID()); + } + } + + this.onlineIds = new CopyOnWriteArraySet(onlineIds); + + lastRefresh = now; + } + } + + public static ThreadSafeCache getInstance() { + return INSTANCE; + } + +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/TileEntityBaseBlock.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/TileEntityBaseBlock.java new file mode 100644 index 000000000..9004474b5 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/TileEntityBaseBlock.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.TileEntityBlock; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; + +public class TileEntityBaseBlock extends BaseBlock implements TileEntityBlock { + + public TileEntityBaseBlock(int type, int data, TileEntity tile) { + super(type, data); + setNbtData(NBTConverter.fromNative(copyNbtData(tile))); + } + + private static NBTTagCompound copyNbtData(TileEntity tile) { + NBTTagCompound tag = new NBTTagCompound(); + tile.writeToNBT(tag); + return tag; + } + +} \ No newline at end of file diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/TileEntityUtils.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/TileEntityUtils.java new file mode 100644 index 000000000..2be2092d0 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/TileEntityUtils.java @@ -0,0 +1,146 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.Vector; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagInt; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BlockPos; +import net.minecraft.world.World; + +import javax.annotation.Nullable; + +import java.lang.reflect.Constructor; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * 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 + * @return a tag compound + */ + private static NBTTagCompound updateForSet(NBTTagCompound tag, Vector position) { + checkNotNull(tag); + checkNotNull(position); + + tag.setTag("x", new NBTTagInt(position.getBlockX())); + tag.setTag("y", new NBTTagInt(position.getBlockY())); + tag.setTag("z", new NBTTagInt(position.getBlockZ())); + + return tag; + } + + /** + * Set a tile entity at the given location. + * + * @param world the world + * @param position the position + * @param clazz the tile entity class + * @param tag the tag for the tile entity (may be null to not set NBT data) + */ + static void setTileEntity(World world, Vector position, Class clazz, @Nullable NBTTagCompound tag) { + checkNotNull(world); + checkNotNull(position); + checkNotNull(clazz); + + TileEntity tileEntity = constructTileEntity(world, position, clazz); + + if (tileEntity == null) { + return; + } + + if (tag != null) { + // Set X, Y, Z + updateForSet(tag, position); + tileEntity.readFromNBT(tag); + } + + world.setTileEntity(new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()), tileEntity); + } + + /** + * 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, Vector position, @Nullable NBTTagCompound tag) { + if (tag != null) { + updateForSet(tag, position); + TileEntity tileEntity = TileEntity.createAndLoadEntity(tag); + if (tileEntity != null) { + world.setTileEntity(new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()), tileEntity); + } + } + } + + /** + * Construct a tile entity from the given class. + * + * @param world the world + * @param position the position + * @param clazz the class + * @return a tile entity (may be null if it failed) + */ + @Nullable + static TileEntity constructTileEntity(World world, Vector position, Class clazz) { + Constructor baseConstructor; + try { + baseConstructor = clazz.getConstructor(); // creates "blank" TE + } catch (Throwable e) { + return null; // every TE *should* have this constructor, so this isn't necessary + } + + TileEntity genericTE; + try { + // Downcast here for return while retaining the type + genericTE = (TileEntity) baseConstructor.newInstance(); + } catch (Throwable e) { + return null; + } + + /* + genericTE.blockType = Block.blocksList[block.getId()]; + genericTE.blockMetadata = block.getData(); + genericTE.xCoord = pt.getBlockX(); + genericTE.yCoord = pt.getBlockY(); + genericTE.zCoord = pt.getBlockZ(); + genericTE.worldObj = world; + */ // handled by internal code + + return genericTE; + } + + +} diff --git a/worldedit-sponge/src/main/resources/META-INF/worldedit_at.cfg b/worldedit-sponge/src/main/resources/META-INF/worldedit_at.cfg new file mode 100644 index 000000000..33f039ce3 --- /dev/null +++ b/worldedit-sponge/src/main/resources/META-INF/worldedit_at.cfg @@ -0,0 +1,4 @@ +public net.minecraft.world.gen.ChunkProviderServer field_73248_b # droppedChunksSet +public net.minecraft.world.gen.ChunkProviderServer field_73244_f # id2ChunkMap +public net.minecraft.world.gen.ChunkProviderServer field_73245_g # loadedChunks +public net.minecraft.world.gen.ChunkProviderServer field_73246_d # serverChunkGenerator diff --git a/worldedit-sponge/src/main/resources/defaults/worldedit.properties b/worldedit-sponge/src/main/resources/defaults/worldedit.properties new file mode 100644 index 000000000..9c3f5d327 --- /dev/null +++ b/worldedit-sponge/src/main/resources/defaults/worldedit.properties @@ -0,0 +1,32 @@ +#Don't put comments; they get removed +default-max-polygon-points=-1 +schematic-save-dir=schematics +allow-extra-data-values=false +super-pickaxe-many-drop-items=true +register-help=true +nav-wand-item=345 +profile=false +super-pickaxe-drop-items=true +disallowed-blocks=6,26,27,28,31,32,34,36,37,38,39,40,46,50,51,55,59,66,69,75,76,93,94,77,81,83,7,14,15,16,56 +max-super-pickaxe-size=5 +max-brush-radius=10 +craftscript-dir=craftscripts +no-double-slash=false +wand-item=271 +shell-save-type= +scripting-timeout=3000 +snapshots-dir= +use-inventory-creative-override=false +log-file=worldedit.log +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