From e6d5ce81659fc82bb24b7c94b3586b1fc85c0e8d Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sun, 18 Nov 2018 17:47:43 +1000 Subject: [PATCH 01/20] Start work on Forge 1.13 --- gradle/wrapper/gradle-wrapper.jar | Bin 56177 -> 54413 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- worldedit-forge/build.gradle | 47 ++++++++++------------- 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 29953ea141f55e3b8fc691d31b5ca8816d89fa87..0d4a9516871afd710a9d84d89e31ba77745607bd 100644 GIT binary patch delta 47733 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

Gauk6VzRKaGELdj)1bl0ug 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 Date: Sat, 15 Dec 2018 18:57:37 +1000 Subject: [PATCH 02/20] Further attempts --- build.gradle | 10 ++++------ worldedit-forge/build.gradle | 8 +------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/build.gradle b/build.gradle index 6b63f5caf..8bdb1a122 100644 --- a/build.gradle +++ b/build.gradle @@ -7,20 +7,19 @@ buildscript { configurations.all { resolutionStrategy { - force 'com.google.guava:guava:21.0' - force 'org.ow2.asm:asm:6.0_BETA' + force 'commons-io:commons-io:2.4' } } dependencies { classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4' - classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.7.5' - classpath 'org.ajoberstar:gradle-git:1.7.2' + classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.8.1' } } plugins { id 'net.minecrell.licenser' version '0.4.1' apply false + id "org.ajoberstar.grgit" version "2.3.0" } println """ @@ -48,7 +47,7 @@ if (!project.hasProperty("artifactory_password")) ext.artifactory_password = "" if (!project.hasProperty("gitCommitHash") && !JavaVersion.current().isJava6()) { try { - def repo = org.ajoberstar.grgit.Grgit.open(dir: '.') + def repo = grgit.open() ext.gitCommitHash = repo.head().abbreviatedId } catch (Exception e) { println "Error getting commit hash: " + e.getMessage() @@ -100,7 +99,6 @@ subprojects { repositories { mavenCentral() - maven { url "http://repo.bukkit.org/content/groups/public" } maven { url "http://maven.sk89q.com/repo/" } maven { url "http://repo.maven.apache.org/maven2" } } diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 054bd138b..229f4447b 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -13,12 +13,6 @@ buildscript { apply plugin: 'net.minecraftforge.gradle' -configurations.all { - resolutionStrategy { - force 'org.ow2.asm:asm:5.2' - } -} - def minecraftVersion = "1.13" def forgeVersion = "24.0.16-1.13-pre" @@ -34,7 +28,7 @@ sourceCompatibility = 1.8 targetCompatibility = 1.8 minecraft { - mappings channel: 'snapshot', version: '20181117' + mappings channel: 'snapshot', version: '20181215' // runDir = 'run' // replaceIn "com/sk89q/worldedit/forge/ForgeWorldEdit.java" From 7a08098b03749305830b8117f30f11d9e41cbc88 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sat, 15 Dec 2018 22:13:13 +1000 Subject: [PATCH 03/20] Further work on Forge 1.13 compat. --- worldedit-forge/build.gradle | 32 ++++++------ .../worldedit/forge/ForgeBlockMaterial.java | 6 +-- .../forge/ForgeEntityProperties.java | 2 +- .../sk89q/worldedit/forge/ForgeWorldEdit.java | 46 ++++++++++-------- .../forge/InternalPacketHandler.java | 11 +++-- .../com/sk89q/worldedit/forge/KeyHandler.java | 4 +- .../worldedit/forge/ThreadSafeCache.java | 3 +- .../worldedit/forge/TileEntityUtils.java | 6 +-- .../worldedit/forge/WECUIPacketHandler.java | 2 +- .../src/main/resources/META-INF/mods.toml | 30 ++++++++++++ worldedit-forge/src/main/resources/mcmod.info | 21 -------- .../src/main/resources/worldedit-icon.png | Bin 0 -> 5636 bytes 12 files changed, 89 insertions(+), 74 deletions(-) create mode 100644 worldedit-forge/src/main/resources/META-INF/mods.toml delete mode 100644 worldedit-forge/src/main/resources/mcmod.info create mode 100644 worldedit-forge/src/main/resources/worldedit-icon.png diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 229f4447b..3885ff369 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -2,7 +2,7 @@ buildscript { repositories { mavenLocal() mavenCentral() - maven { url = "http://files.minecraftforge.net/maven" } + maven { url = "https://files.minecraftforge.net/maven" } jcenter() } @@ -14,7 +14,7 @@ buildscript { apply plugin: 'net.minecraftforge.gradle' def minecraftVersion = "1.13" -def forgeVersion = "24.0.16-1.13-pre" +def forgeVersion = "24.0.32-1.13-pre" dependencies { compile project(':worldedit-core') @@ -28,26 +28,28 @@ sourceCompatibility = 1.8 targetCompatibility = 1.8 minecraft { - mappings channel: 'snapshot', version: '20181215' -// runDir = 'run' - -// replaceIn "com/sk89q/worldedit/forge/ForgeWorldEdit.java" -// replace "%VERSION%", project.version + mappings channel: 'snapshot', version: '20180921-1.13' } project.archivesBaseName = "${project.archivesBaseName}-mc${minecraftVersion}" processResources { - from (sourceSets.main.resources.srcDirs) { - expand 'version': project.version, - 'mcVersion': minecraftVersion, - 'forgeVersion': forgeVersion, - 'internalVersion': project.internalVersion - include 'mcmod.info' + // this will ensure that this task is redone when the versions change. + inputs.property 'version', project.version + inputs.property 'mcversion', minecraftVersion + inputs.property 'internalVersion', internalVersion + + // replace stuff in mcmod.info, nothing else + from(sourceSets.main.resources.srcDirs) { + include 'META_INF/mods.toml' + + // replace version and mcversion + expand 'version':project.version, 'mcversion': minecraftVersion, 'internalVersion': internalVersion } - from (sourceSets.main.resources.srcDirs) { - exclude 'mcmod.info' + // copy everything else except the mcmod.info + from(sourceSets.main.resources.srcDirs) { + exclude 'META_INF/mods.toml' } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockMaterial.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockMaterial.java index 9d98f39ef..5f15a683b 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockMaterial.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockMaterial.java @@ -63,12 +63,12 @@ public class ForgeBlockMaterial extends PassthroughBlockMaterial { @Override public boolean isFragileWhenPushed() { - return delegate.getMobilityFlag() == EnumPushReaction.DESTROY; + return delegate.getPushReaction() == EnumPushReaction.DESTROY; } @Override public boolean isUnpushable() { - return delegate.getMobilityFlag() == EnumPushReaction.BLOCK; + return delegate.getPushReaction() == EnumPushReaction.BLOCK; } @Override @@ -78,7 +78,7 @@ public class ForgeBlockMaterial extends PassthroughBlockMaterial { @Override public boolean isBurnable() { - return delegate.getCanBurn(); + return delegate.isFlammable(); } @Override diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntityProperties.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntityProperties.java index bf6a16ae2..6e07e18ad 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntityProperties.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntityProperties.java @@ -136,7 +136,7 @@ public class ForgeEntityProperties implements EntityProperties { @Override public boolean isTagged() { - return entity instanceof EntityLiving && ((EntityLiving) entity).hasCustomName(); + return entity.hasCustomName(); } @Override diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index 5a5a217ad..9d182c32e 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -44,10 +44,10 @@ import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.CommandEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickEmpty; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.Mod.EventHandler; -import net.minecraftforge.fml.common.Mod.Instance; import net.minecraftforge.fml.common.SidedProxy; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; @@ -56,7 +56,8 @@ import net.minecraftforge.fml.common.event.FMLServerAboutToStartEvent; import net.minecraftforge.fml.common.event.FMLServerStartedEvent; import net.minecraftforge.fml.common.event.FMLServerStoppingEvent; import net.minecraftforge.fml.common.eventhandler.Event.Result; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.javafmlmod.FMLModLoadingContext; +import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.io.File; @@ -64,16 +65,15 @@ import java.io.File; /** * The Forge implementation of WorldEdit. */ -@Mod(modid = ForgeWorldEdit.MOD_ID, name = "WorldEdit", version = "%VERSION%", acceptableRemoteVersions = "*") +@Mod(ForgeWorldEdit.MOD_ID) public class ForgeWorldEdit { - public static Logger logger; + private static final Logger LOGGER = LogManager.getLogger(); public static final String MOD_ID = "worldedit"; public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui"; private ForgePermissionsProvider provider; - @Instance(MOD_ID) public static ForgeWorldEdit inst; @SidedProxy(serverSide = "com.sk89q.worldedit.forge.CommonProxy", clientSide = "com.sk89q.worldedit.forge.ClientProxy") @@ -83,36 +83,42 @@ public class ForgeWorldEdit { private ForgeConfiguration config; private File workingDir; - @EventHandler + public ForgeWorldEdit() { + inst = this; + + FMLModLoadingContext.get().getModEventBus().addListener(this::preInit); + FMLModLoadingContext.get().getModEventBus().addListener(this::init); + FMLModLoadingContext.get().getModEventBus().addListener(this::postInit); + FMLModLoadingContext.get().getModEventBus().addListener(this::serverAboutToStart); + FMLModLoadingContext.get().getModEventBus().addListener(this::serverStopping); + FMLModLoadingContext.get().getModEventBus().addListener(this::serverStarted); + + MinecraftForge.EVENT_BUS.register(ThreadSafeCache.getInstance()); + MinecraftForge.EVENT_BUS.register(this); + } + public void preInit(FMLPreInitializationEvent event) { - logger = event.getModLog(); // Setup working directory workingDir = new File(event.getModConfigurationDirectory() + File.separator + "worldedit"); workingDir.mkdir(); config = new ForgeConfiguration(this); config.load(); - - MinecraftForge.EVENT_BUS.register(ThreadSafeCache.getInstance()); } - @EventHandler public void init(FMLInitializationEvent event) { - MinecraftForge.EVENT_BUS.register(this); WECUIPacketHandler.init(); InternalPacketHandler.init(); proxy.registerHandlers(); } - @EventHandler public void postInit(FMLPostInitializationEvent event) { - logger.info("WorldEdit for Forge (version " + getInternalVersion() + ") is loaded"); + LOGGER.info("WorldEdit for Forge (version " + getInternalVersion() + ") is loaded"); } - @EventHandler public void serverAboutToStart(FMLServerAboutToStartEvent event) { if (this.platform != null) { - logger.warn("FMLServerStartingEvent occurred when FMLServerStoppingEvent hasn't"); + LOGGER.warn("FMLServerStartingEvent occurred when FMLServerStoppingEvent hasn't"); WorldEdit.getInstance().getPlatformManager().unregister(platform); } @@ -141,14 +147,12 @@ public class ForgeWorldEdit { } } - @EventHandler public void serverStopping(FMLServerStoppingEvent event) { WorldEdit worldEdit = WorldEdit.getInstance(); worldEdit.getSessionManager().unload(); worldEdit.getPlatformManager().unregister(platform); } - @EventHandler public void serverStarted(FMLServerStartedEvent event) { WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); } @@ -183,11 +187,11 @@ public class ForgeWorldEdit { boolean isLeftDeny = event instanceof PlayerInteractEvent.LeftClickBlock && ((PlayerInteractEvent.LeftClickBlock) event) - .getUseItem() == Result.DENY; + .getUseItem() == Event.Result.DENY; boolean isRightDeny = event instanceof PlayerInteractEvent.RightClickBlock && ((PlayerInteractEvent.RightClickBlock) event) - .getUseItem() == Result.DENY; + .getUseItem() == Event.Result.DENY; if (isLeftDeny || isRightDeny || event.getEntity().world.isRemote) { return; } @@ -233,7 +237,7 @@ public class ForgeWorldEdit { if (item.getNbtData() != null) { forgeCompound = NBTConverter.toNative(item.getNbtData()); } - return new ItemStack(Item.getByNameOrId(item.getType().getId()), item.getAmount(), 0, forgeCompound); + return new ItemStack(Item.REGISTRY.get(new ResourceLocation(item.getType().getId())), item.getAmount(), 0, forgeCompound); } /** diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/InternalPacketHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/InternalPacketHandler.java index afac351ac..c81062121 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/InternalPacketHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/InternalPacketHandler.java @@ -20,18 +20,19 @@ package com.sk89q.worldedit.forge; import com.sk89q.worldedit.forge.net.LeftClickAirEventMessage; -import net.minecraftforge.fml.common.network.NetworkRegistry; -import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper; -import net.minecraftforge.fml.relauncher.Side; +import javafx.geometry.Side; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.network.NetworkRegistry; +import net.minecraftforge.fml.network.simple.SimpleChannel; import java.nio.charset.Charset; public class InternalPacketHandler { public static final Charset UTF_8_CHARSET = Charset.forName("UTF-8"); - public static SimpleNetworkWrapper CHANNEL; + public static SimpleChannel CHANNEL; public static void init() { - CHANNEL = NetworkRegistry.INSTANCE.newSimpleChannel(ForgeWorldEdit.MOD_ID); + CHANNEL = NetworkRegistry.newSimpleChannel(new ResourceLocation(ForgeWorldEdit.MOD_ID, "worldedit"), () -> "1", check -> true, check -> true); CHANNEL.registerMessage(LeftClickAirEventMessage.Handler.class, LeftClickAirEventMessage.class, 0, Side.SERVER); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java index 76e726884..1395beb87 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java @@ -22,14 +22,14 @@ package com.sk89q.worldedit.forge; import com.sk89q.worldedit.forge.gui.GuiHandler; import net.minecraft.client.Minecraft; import net.minecraft.client.settings.KeyBinding; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.client.registry.ClientRegistry; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.InputEvent.KeyInputEvent; import org.lwjgl.input.Keyboard; public class KeyHandler { - private static Minecraft mc = Minecraft.getMinecraft(); + private static Minecraft mc = Minecraft.getInstance(); private static KeyBinding mainKey = new KeyBinding("WorldEdit Reference", Keyboard.KEY_L, "WorldEdit"); public KeyHandler() { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java index a52233564..91fdc3fcd 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java @@ -21,8 +21,7 @@ package com.sk89q.worldedit.forge; 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.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; import java.util.Collections; diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/TileEntityUtils.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/TileEntityUtils.java index 4147d835c..8a65feaf4 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/TileEntityUtils.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/TileEntityUtils.java @@ -81,7 +81,7 @@ final class TileEntityUtils { if (tag != null) { // Set X, Y, Z updateForSet(tag, position); - tileEntity.readFromNBT(tag); + tileEntity.read(tag); } world.setTileEntity(new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()), tileEntity); @@ -98,7 +98,7 @@ final class TileEntityUtils { static void setTileEntity(World world, BlockVector3 position, @Nullable NBTTagCompound tag) { if (tag != null) { updateForSet(tag, position); - TileEntity tileEntity = TileEntity.create(world, tag); + TileEntity tileEntity = TileEntity.create(tag); if (tileEntity != null) { world.setTileEntity(new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()), tileEntity); } @@ -143,7 +143,7 @@ final class TileEntityUtils { public static NBTTagCompound copyNbtData(TileEntity tile) { NBTTagCompound tag = new NBTTagCompound(); - tile.writeToNBT(tag); + tile.write(tag); return tag; } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WECUIPacketHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WECUIPacketHandler.java index c6cf673e4..276eadcc6 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WECUIPacketHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WECUIPacketHandler.java @@ -25,7 +25,7 @@ import net.minecraft.network.NetHandlerPlayServer; import net.minecraft.network.PacketBuffer; import net.minecraft.network.ThreadQuickExitException; import net.minecraft.network.play.server.SPacketCustomPayload; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.network.FMLEventChannel; import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientCustomPacketEvent; import net.minecraftforge.fml.common.network.FMLNetworkEvent.ServerCustomPacketEvent; diff --git a/worldedit-forge/src/main/resources/META-INF/mods.toml b/worldedit-forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 000000000..7a8a52407 --- /dev/null +++ b/worldedit-forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,30 @@ +# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml +modLoader="javafml" +# A version range to match for said mod loader - for regular FML @Mod it will be the minecraft version (without the 1.) +loaderVersion="[13,)" +# A URL to refer people to when problems occur with this mod +issueTrackerURL="https://discord.gg/YKbmj7V" +# A URL for the "homepage" for this mod, displayed in the mod UI +displayURL="http://wiki.sk89q.com/wiki/WorldEdit/" +# A file name (in the root of the mod JAR) containing a logo for display +logoFile="worldedit-icon.png" +# A text field displayed in the mod UI +authors="sk89q, wizjany, TomyLobo, kenzierocks, Me4502" +# A list of mods - how many allowed here is determined by the individual mod loader +[[worldedit]] +# The modid of the mod +modId="worldedit" +# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it +version="${internalVersion}" + # A display name for the mod +displayName="WorldEdit" +# The description text for the mod (multi line!) +description=''' +WorldEdit is an easy-to-use in-game world editor for Minecraft, supporting both single player and multiplayer. +''' +[[dependencies.sponge]] + modId="sponge" + mandatory=false + versionRange="[1.13]" + ordering="NONE" + side="BOTH" \ No newline at end of file diff --git a/worldedit-forge/src/main/resources/mcmod.info b/worldedit-forge/src/main/resources/mcmod.info deleted file mode 100644 index bcee1cd4a..000000000 --- a/worldedit-forge/src/main/resources/mcmod.info +++ /dev/null @@ -1,21 +0,0 @@ -[{ - "modid": "worldedit", - "name": "WorldEdit", - "description": "WorldEdit is an easy-to-use in-game world editor for Minecraft, supporting both single player and multiplayer.", - "version": "${internalVersion}", - "mcversion": "${mcVersion}", - "url": "http://wiki.sk89q.com/wiki/WorldEdit", - "updateUrl": "", - "authors": [ "sk89q", "wizjany", "TomyLobo", "kenzierocks", "Me4502" ], - "credits": "", - "logoFile": "", - "screenshots": [], - "requiredMods": [ - "Forge@[${forgeVersion},)" - ], - "dependencies": [ - "Forge@[${forgeVersion},)", - "sponge" - ], - "dependants": [] -}] diff --git a/worldedit-forge/src/main/resources/worldedit-icon.png b/worldedit-forge/src/main/resources/worldedit-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..dc269dcf7b17ffb3d5b4ba950c2dda74a3b5c26b GIT binary patch literal 5636 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�v@D{EVq36fj3OY$AQ03_h`Fl*CG)v2XGC^PGR=7O z{$l^i#c2V&AD3yLVqie&B=8xu%U4jf+165lxYgek4iT(jrc#V-Ck8NxjE#~Ra0MX1 zNxCHW_h2+9hq0tdHwv;w#PNt^ZV|vRQ@aibo3H!*qYnjup;TwWRW^mhIWp8iXK-!S zr%Wgmzz9Jm7~vT3U~KncaMy^rQz}qYGZ+RijNJr;p(sV;a;{o79GFT408r!M>~DY+ ztHlp&8bF1n!c-Fw){Hgz{uPUx1+w{!ZCaqHrW1hSGj=BsHedg#04DUiYQ8mbZ<+o6 zoFP-!sr?Tg+kWn)#r}Jjr9iqUfhPy3okubtW`#3#*k|45<48O9^`4fd~G>cI#X z%`nV?nTKJlw>aqAvpYGo+tyWXbKB`L&M0|&0Z(=gh_XJFt!4~8c$MHZ#?yYR;ZJ) z{g?OU`|nxOtQ~j+hN&G~Xad85*9Q=mwVt$jvJx6(%KGUL zhEcB@nBC*arTii5Q8;bhd+W6s)`colTNeL}6NL@13FZ<{HfcDSdIch~?F7;lp`K>M z2nbU%z}F1+84a^5>4TnZ^W;%an(IyqG zVi?@jA`FeecwfU0u>=Nnx24+fm-OI=OWseq4$Y_fD6r z)qf94wXN5cYY8BWm3n-+DVtfu#tax*Zzur6Cd~w3!XTX}WS{Zz`j)ngC4P&DC-ge* zZxmshz;KHv`ciRq6$=rQR2ruOhCmF5L4=kEn3cYd?H5a?1wPZBvc5||vQlatjn!8e z5`ksm^(DN~i_ky?#uXqd`;3nv5SEM(k7sS`Tt%Ri5u6cF1O~)zgkx%xF|DrH=fyr_ z^vj949DFYjpx@vfWWoh6g9z=n7#$cBPO5NK&zu18ZmB+ulMSEovD6R~%Br-5rzn5{ z#SL-Bwy(7f);Ps59yVZ%0x|qWClP&1DGy4}RTBA9Vyc3Lp;cN+2L4!X#k6;hnyktR z$?r*mhlxn=GA`7oyyg+BG(Z3a*W5b=l(5n_sv#^E!XpCU0tKK{c=@mv3SApJS#t`6 zwWGwstn`g)NMa~>msGS(0o@M-%{mhpPC{xFrimhB2{KXbmA+9REWc0$IYM|0h%!D7 zp*tQcG&{3)7;F02OpO8=nXDHCXG?&GfCz(}3O8nB$ekOSQ40ECC&Cy70s?U@5lxT) zw~-HpgFt@H5f~cIdR}^Lj!~yRGAMTdz-$RXQZJ(PMS+&!nmgis7&|}C7}XFK1h`EA ze54etM4;x-N-hnD09+!vLkRpa01PsKQ6RfSY{Ulz!gGU)W-EXbkl+A~WTS7Qi0F13 e@il_R8-E89rZjGhc4GJd0000 Date: Wed, 26 Dec 2018 22:46:18 +1000 Subject: [PATCH 04/20] Fixed a lot of the errors, still more to go. Gotta switch to Forge registries once they exist. --- worldedit-forge/build.gradle | 4 +- .../sk89q/worldedit/forge/ForgeAdapter.java | 26 +++---- .../worldedit/forge/ForgeBiomeRegistry.java | 2 +- .../worldedit/forge/ForgeBlockRegistry.java | 6 +- .../sk89q/worldedit/forge/ForgeEntity.java | 4 +- .../sk89q/worldedit/forge/ForgePlayer.java | 13 ++-- .../com/sk89q/worldedit/forge/ForgeWorld.java | 67 +++++++++---------- .../worldedit/forge/IPropertyAdapter.java | 5 +- .../sk89q/worldedit/forge/NBTConverter.java | 14 ++-- 9 files changed, 68 insertions(+), 73 deletions(-) diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 3885ff369..9b033cab8 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -14,7 +14,7 @@ buildscript { apply plugin: 'net.minecraftforge.gradle' def minecraftVersion = "1.13" -def forgeVersion = "24.0.32-1.13-pre" +def forgeVersion = "24.0.44-1.13-pre" dependencies { compile project(':worldedit-core') @@ -29,6 +29,8 @@ targetCompatibility = 1.8 minecraft { mappings channel: 'snapshot', version: '20180921-1.13' + + accessTransformer = file('worldedit_at.cfg') } project.archivesBaseName = "${project.archivesBaseName}-mc${minecraftVersion}" diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java index f28e35a0b..a3523ddb6 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java @@ -33,12 +33,12 @@ import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; import net.minecraft.block.properties.IProperty; -import net.minecraft.block.properties.PropertyBool; -import net.minecraft.block.properties.PropertyDirection; -import net.minecraft.block.properties.PropertyEnum; -import net.minecraft.block.properties.PropertyInteger; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; +import net.minecraft.state.DirectionProperty; +import net.minecraft.state.IProperty; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.IStringSerializable; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.biome.Biome; @@ -105,20 +105,20 @@ final class ForgeAdapter { } public static Property adaptProperty(IProperty property) { - if (property instanceof PropertyBool) { - return new BooleanProperty(property.getName(), ImmutableList.copyOf(((PropertyBool) property).getAllowedValues())); + if (property instanceof net.minecraft.state.BooleanProperty) { + return new BooleanProperty(property.getName(), ImmutableList.copyOf(((net.minecraft.state.BooleanProperty) property).getAllowedValues())); } - if (property instanceof PropertyInteger) { - return new IntegerProperty(property.getName(), ImmutableList.copyOf(((PropertyInteger) property).getAllowedValues())); + if (property instanceof net.minecraft.state.IntegerProperty) { + return new IntegerProperty(property.getName(), ImmutableList.copyOf(((net.minecraft.state.IntegerProperty) property).getAllowedValues())); } - if (property instanceof PropertyDirection) { - return new DirectionalProperty(property.getName(), ((PropertyDirection) property).getAllowedValues().stream() + if (property instanceof DirectionProperty) { + return new DirectionalProperty(property.getName(), ((DirectionProperty) property).getAllowedValues().stream() .map(ForgeAdapter::adaptEnumFacing) .collect(Collectors.toList())); } - if (property instanceof PropertyEnum) { - return new EnumProperty(property.getName(), ((PropertyEnum) property).getAllowedValues().stream() - .map(e -> e.getName()) + if (property instanceof net.minecraft.state.EnumProperty) { + return new EnumProperty(property.getName(), ((net.minecraft.state.EnumProperty) property).getAllowedValues().stream() + .map(IStringSerializable::getName) .collect(Collectors.toList())); } return new IPropertyAdapter<>(property); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java index 986a3afc2..cbe2102c9 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java @@ -52,7 +52,7 @@ class ForgeBiomeRegistry implements BiomeRegistry { @Override public String getName() { - return biome.getBiomeName(); + return biome.getDisplayName().getString(); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java index ddf3762bb..f77dc2304 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java @@ -26,7 +26,7 @@ import com.sk89q.worldedit.world.registry.BundledBlockRegistry; import net.minecraft.block.Block; import net.minecraft.block.material.Material; -import net.minecraft.block.properties.IProperty; +import net.minecraft.state.IProperty; import net.minecraft.util.ResourceLocation; import java.util.Collection; @@ -43,7 +43,7 @@ public class ForgeBlockRegistry extends BundledBlockRegistry { @Nullable @Override public String getName(BlockType blockType) { - return Block.REGISTRY.getObject(new ResourceLocation(blockType.getId())).getLocalizedName(); + return Block.REGISTRY.get(new ResourceLocation(blockType.getId())).getNameTextComponent().getFormattedText(); } @Override @@ -57,7 +57,7 @@ public class ForgeBlockRegistry extends BundledBlockRegistry { Map> map = new TreeMap<>(); Collection> propertyKeys = Block.getBlockFromName(blockType.getId()) .getDefaultState() - .getPropertyKeys(); + .getProperties(); for (IProperty key : propertyKeys) { map.put(key.getName(), ForgeAdapter.adaptProperty(key)); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java index e4b391fe0..1c428e0c1 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java @@ -52,7 +52,7 @@ class ForgeEntity implements Entity { String id = EntityList.getEntityString(entity); if (id != null) { NBTTagCompound tag = new NBTTagCompound(); - entity.writeToNBT(tag); + entity.writeWithoutTypeId(tag); return new BaseEntity(EntityTypes.get(id), NBTConverter.fromNative(tag)); } else { return null; @@ -96,7 +96,7 @@ class ForgeEntity implements Entity { public boolean remove() { net.minecraft.entity.Entity entity = entityRef.get(); if (entity != null) { - entity.setDead(); + entity.remove(); } return true; } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index a20abd100..65705004c 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -41,10 +41,10 @@ import net.minecraft.network.PacketBuffer; import net.minecraft.network.play.server.SPacketCustomPayload; import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextFormatting; -import net.minecraftforge.fml.common.registry.ForgeRegistries; import java.util.UUID; @@ -69,12 +69,12 @@ public class ForgePlayer extends AbstractPlayerActor { @Override public BaseItemStack getItemInHand(HandSide handSide) { ItemStack is = this.player.getHeldItem(handSide == HandSide.MAIN_HAND ? EnumHand.MAIN_HAND : EnumHand.OFF_HAND); - return new BaseItemStack(ItemTypes.get(ForgeRegistries.ITEMS.getKey(is.getItem()).toString())); + return new BaseItemStack(ItemTypes.get(Item.REGISTRY.getKey(is.getItem()).toString())); } @Override public String getName() { - return this.player.getName(); + return this.player.getName().getFormattedText(); } @Override @@ -105,8 +105,7 @@ public class ForgePlayer extends AbstractPlayerActor { @Override public void giveItem(BaseItemStack itemStack) { - this.player.inventory.addItemStackToInventory( - new ItemStack(Item.getByNameOrId(itemStack.getType().getId()), itemStack.getAmount(), 0)); + this.player.inventory.addItemStackToInventory(new ItemStack(Item.REGISTRY.get(new ResourceLocation(itemStack.getType().getId())), itemStack.getAmount(), null)); } @Override @@ -117,7 +116,7 @@ public class ForgePlayer extends AbstractPlayerActor { send = send + "|" + StringUtil.joinString(params, "|"); } PacketBuffer buffer = new PacketBuffer(Unpooled.copiedBuffer(send.getBytes(WECUIPacketHandler.UTF_8_CHARSET))); - SPacketCustomPayload packet = new SPacketCustomPayload(ForgeWorldEdit.CUI_PLUGIN_CHANNEL, buffer); + SPacketCustomPayload packet = new SPacketCustomPayload(new ResourceLocation(ForgeWorldEdit.CUI_PLUGIN_CHANNEL), buffer); this.player.connection.sendPacket(packet); } @@ -197,7 +196,7 @@ public class ForgePlayer extends AbstractPlayerActor { @Override public SessionKey getSessionKey() { - return new SessionKeyImpl(player.getUniqueID(), player.getName()); + return new SessionKeyImpl(player.getUniqueID(), player.getName().getString()); } private static class SessionKeyImpl implements SessionKey { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 09fcc4241..13205b726 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -51,15 +51,7 @@ import com.sk89q.worldedit.world.weather.WeatherType; import com.sk89q.worldedit.world.weather.WeatherTypes; import net.minecraft.block.Block; import net.minecraft.block.BlockLeaves; -import net.minecraft.block.BlockOldLeaf; -import net.minecraft.block.BlockOldLog; -import net.minecraft.block.BlockPlanks; -import net.minecraft.block.properties.IProperty; -import net.minecraft.block.properties.PropertyDirection; -import net.minecraft.block.properties.PropertyEnum; -import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.EntityList; import net.minecraft.entity.item.EntityItem; import net.minecraft.init.Blocks; import net.minecraft.inventory.IInventory; @@ -67,6 +59,9 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.server.MinecraftServer; +import net.minecraft.state.DirectionProperty; +import net.minecraft.state.EnumProperty; +import net.minecraft.state.IProperty; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumFacing; @@ -77,6 +72,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraft.world.biome.Biome; +import net.minecraft.world.chunk.BlockStateContainer; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.IChunkProvider; import net.minecraft.world.chunk.storage.AnvilSaveHandler; @@ -116,9 +112,9 @@ public class ForgeWorld extends AbstractWorld { private static final Random random = new Random(); private static final int UPDATE = 1, NOTIFY = 2; - 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)); + private static final IBlockState JUNGLE_LOG = Blocks.JUNGLE_LOG.getDefaultState(); + private static final IBlockState JUNGLE_LEAF = Blocks.JUNGLE_LEAVES.getDefaultState().with(BlockLeaves.PERSISTENT, Boolean.TRUE); + private static final IBlockState JUNGLE_SHRUB = Blocks.OAK_LEAVES.getDefaultState().with(BlockLeaves.PERSISTENT, Boolean.TRUE); private final WeakReference worldRef; @@ -178,7 +174,7 @@ public class ForgeWorld extends AbstractWorld { int z = position.getBlockZ(); // First set the block - Chunk chunk = world.getChunkFromChunkCoords(x >> 4, z >> 4); + Chunk chunk = world.getChunk(x >> 4, z >> 4); BlockPos pos = new BlockPos(x, y, z); IBlockState old = chunk.getBlockState(pos); Block mcBlock = Block.getBlockFromName(block.getBlockType().getId()); @@ -224,17 +220,17 @@ public class ForgeWorld extends AbstractWorld { IProperty 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 PropertyDirection) { + if (property instanceof DirectionProperty) { Direction dir = (Direction) value; value = ForgeAdapter.adapt(dir); - } else if (property instanceof PropertyEnum) { + } else if (property instanceof EnumProperty) { String enumName = (String) value; - value = ((PropertyEnum) property).parseValue((String) value).or(() -> { + value = ((EnumProperty) property).parseValue((String) value).orElseGet(() -> { throw new IllegalStateException("Enum property " + property.getName() + " does not contain " + enumName); }); } - newState = newState.withProperty(property, value); + newState = newState.with(property, value); } return newState; } @@ -271,7 +267,7 @@ public class ForgeWorld extends AbstractWorld { checkNotNull(position); checkNotNull(biome); - Chunk chunk = getWorld().getChunkFromBlockCoords(new BlockPos(position.getBlockX(), 0, position.getBlockZ())); + Chunk chunk = getWorld().getChunk(new BlockPos(position.getBlockX(), 0, position.getBlockZ())); if (chunk.isLoaded()) { chunk.getBiomeArray()[((position.getBlockZ() & 0xF) << 4 | position.getBlockX() & 0xF)] = (byte) Biome.getIdForBiome(ForgeAdapter.adapt(biome)); return true; @@ -282,12 +278,12 @@ public class ForgeWorld extends AbstractWorld { @Override public boolean useItem(BlockVector3 position, BaseItem item, Direction face) { - Item nativeItem = Item.getByNameOrId(item.getType().getId()); + Item nativeItem = Item.REGISTRY.get(new ResourceLocation(item.getType().getId())); ItemStack stack = null; if (item.getNbtData() == null) { - stack = new ItemStack(nativeItem, 1, 0); + stack = new ItemStack(nativeItem, 1); } else { - stack = new ItemStack(nativeItem, 1, 0, NBTConverter.toNative(item.getNbtData())); + stack = new ItemStack(nativeItem, 1, NBTConverter.toNative(item.getNbtData())); } World world = getWorld(); EnumActionResult used = stack.onItemUse(new WorldEditFakePlayer((WorldServer) world), world, ForgeAdapter.toBlockPos(position), @@ -333,16 +329,15 @@ public class ForgeWorld extends AbstractWorld { WorldServer originalWorld = (WorldServer) getWorld(); MinecraftServer server = originalWorld.getMinecraftServer(); - AnvilSaveHandler saveHandler = new AnvilSaveHandler(saveFolder, - originalWorld.getSaveHandler().getWorldDirectory().getName(), true, server.getDataFixer()); + AnvilSaveHandler saveHandler = new AnvilSaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), true, server.getDataFixer()); World freshWorld = new WorldServer(server, saveHandler, originalWorld.getWorldInfo(), - originalWorld.provider.getDimension(), originalWorld.profiler).init(); + originalWorld.dimension.getId(), originalWorld.profiler).init(); // 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.getChunkFromChunkCoords(chunk.getBlockX(), chunk.getBlockZ()); + freshWorld.getChunk(chunk.getBlockX(), chunk.getBlockZ()); } ForgeWorld from = new ForgeWorld(freshWorld); @@ -354,8 +349,8 @@ public class ForgeWorld extends AbstractWorld { throw new RuntimeException(e); } finally { saveFolder.delete(); - DimensionManager.setWorld(originalWorld.provider.getDimension(), null, server); - DimensionManager.setWorld(originalWorld.provider.getDimension(), originalWorld, server); + DimensionManager.setWorld(originalWorld.dimension.getId(), null, server); + DimensionManager.setWorld(originalWorld.dimension.getId(), originalWorld, server); } return true; @@ -396,7 +391,7 @@ public class ForgeWorld extends AbstractWorld { @Override public void checkLoadedChunk(BlockVector3 pt) { - getWorld().getChunkFromBlockCoords(ForgeAdapter.toBlockPos(pt)); + getWorld().getChunk(ForgeAdapter.toBlockPos(pt)); } @Override @@ -408,7 +403,7 @@ public class ForgeWorld extends AbstractWorld { public void fixLighting(Iterable chunks) { World world = getWorld(); for (BlockVector2 chunk : chunks) { - world.getChunkFromChunkCoords(chunk.getBlockX(), chunk.getBlockZ()).resetRelightChecks(); + world.getChunk(chunk.getBlockX(), chunk.getBlockZ()).resetRelightChecks(); } } @@ -439,7 +434,7 @@ public class ForgeWorld extends AbstractWorld { if (info.isRaining()) { return info.getRainTime(); } - return info.getCleanWeatherTime(); + return info.getClearWeatherTime(); } @Override @@ -451,17 +446,17 @@ public class ForgeWorld extends AbstractWorld { public void setWeather(WeatherType weatherType, long duration) { WorldInfo info = getWorld().getWorldInfo(); if (WeatherTypes.THUNDER_STORM.equals(weatherType)) { - info.setCleanWeatherTime(0); + info.setClearWeatherTime(0); info.setThundering(true); info.setThunderTime((int) duration); } else if (WeatherTypes.RAIN.equals(weatherType)) { - info.setCleanWeatherTime(0); + info.setClearWeatherTime(0); info.setRaining(true); info.setRainTime((int) duration); } else if (WeatherTypes.CLEAR.equals(weatherType)) { info.setRaining(false); info.setThundering(false); - info.setCleanWeatherTime((int) duration); + info.setClearWeatherTime((int) duration); } } @@ -476,7 +471,7 @@ public class ForgeWorld extends AbstractWorld { BlockPos pos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); IBlockState mcState = world.getBlockState(pos); - BlockType blockType = BlockType.REGISTRY.get(Block.REGISTRY.getNameForObject(mcState.getBlock()).toString()); + BlockType blockType = BlockType.REGISTRY.get(Block.REGISTRY.getKey(mcState.getBlock()).toString()); return blockType.getState(adaptProperties(blockType, mcState.getProperties())); } @@ -484,9 +479,9 @@ public class ForgeWorld extends AbstractWorld { Map, Object> props = new TreeMap<>(Comparator.comparing(Property::getName)); for (Map.Entry, Comparable> prop : mcProps.entrySet()) { Object value = prop.getValue(); - if (prop.getKey() instanceof PropertyDirection) { + if (prop.getKey() instanceof DirectionProperty) { value = ForgeAdapter.adaptEnumFacing((EnumFacing) value); - } else if (prop.getKey() instanceof PropertyEnum) { + } else if (prop.getKey() instanceof EnumProperty) { value = ((IStringSerializable) value).getName(); } props.put(block.getProperty(prop.getKey().getName()), value); @@ -559,7 +554,7 @@ public class ForgeWorld extends AbstractWorld { for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { tag.removeTag(name); } - createdEntity.readFromNBT(tag); + createdEntity.read(tag); } createdEntity.setLocationAndAngles(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/IPropertyAdapter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/IPropertyAdapter.java index 0ac900a55..e024f6e93 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/IPropertyAdapter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/IPropertyAdapter.java @@ -21,13 +21,12 @@ package com.sk89q.worldedit.forge; import static com.google.common.base.Preconditions.checkArgument; -import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.registry.state.Property; - -import net.minecraft.block.properties.IProperty; +import net.minecraft.state.IProperty; import java.util.List; +import java.util.Optional; class IPropertyAdapter> implements Property { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/NBTConverter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/NBTConverter.java index 0992d3d4f..f05fbef47 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/NBTConverter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/NBTConverter.java @@ -32,7 +32,7 @@ import com.sk89q.jnbt.LongTag; import com.sk89q.jnbt.ShortTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; -import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.INBTBase; import net.minecraft.nbt.NBTTagByte; import net.minecraft.nbt.NBTTagByteArray; import net.minecraft.nbt.NBTTagCompound; @@ -62,7 +62,7 @@ final class NBTConverter { private NBTConverter() { } - public static NBTBase toNative(Tag tag) { + public static INBTBase toNative(Tag tag) { if (tag instanceof IntArrayTag) { return toNative((IntArrayTag) tag); @@ -111,7 +111,7 @@ final class NBTConverter { if (child instanceof EndTag) { continue; } - list.appendTag(toNative(child)); + list.add(toNative(child)); } return list; } @@ -157,7 +157,7 @@ final class NBTConverter { return new NBTTagDouble(tag.getValue()); } - public static Tag fromNative(NBTBase other) { + public static Tag fromNative(INBTBase other) { if (other instanceof NBTTagIntArray) { return fromNative((NBTTagIntArray) other); @@ -207,9 +207,9 @@ final class NBTConverter { other = other.copy(); List list = new ArrayList<>(); Class listClass = StringTag.class; - int tags = other.tagCount(); + int tags = other.size(); for (int i = 0; i < tags; i++) { - Tag child = fromNative(other.removeTag(0)); + Tag child = fromNative(other.remove(0)); list.add(child); listClass = child.getClass(); } @@ -242,7 +242,7 @@ final class NBTConverter { } public static CompoundTag fromNative(NBTTagCompound other) { - Set tags = other.getKeySet(); + Set tags = other.keySet(); Map map = new HashMap<>(); for (String tagName : tags) { map.put(tagName, fromNative(other.getTag(tagName))); From 9fccfdfaeb34ab68bb50a70c416ddd3adbadf99f Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sat, 29 Dec 2018 16:04:36 +1000 Subject: [PATCH 05/20] Further work on 1.13 --- worldedit-forge/build.gradle | 2 +- .../sk89q/worldedit/forge/CommonProxy.java | 2 +- .../sk89q/worldedit/forge/ForgeAdapter.java | 40 ++++++ .../worldedit/forge/ForgeBiomeRegistry.java | 2 +- .../worldedit/forge/ForgeBlockRegistry.java | 18 ++- .../sk89q/worldedit/forge/ForgeEntity.java | 3 +- .../forge/ForgePermissionsProvider.java | 3 +- .../sk89q/worldedit/forge/ForgePlatform.java | 4 +- .../sk89q/worldedit/forge/ForgePlayer.java | 4 +- .../com/sk89q/worldedit/forge/ForgeWorld.java | 124 ++++++++++-------- .../sk89q/worldedit/forge/ForgeWorldEdit.java | 29 ++-- .../com/sk89q/worldedit/forge/KeyHandler.java | 4 +- .../worldedit/forge/ThreadSafeCache.java | 3 +- .../worldedit/forge/gui/GuiReferenceCard.java | 4 +- 14 files changed, 144 insertions(+), 98 deletions(-) diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 9b033cab8..42a242d65 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -14,7 +14,7 @@ buildscript { apply plugin: 'net.minecraftforge.gradle' def minecraftVersion = "1.13" -def forgeVersion = "24.0.44-1.13-pre" +def forgeVersion = "24.0.45-1.13-pre" dependencies { compile project(':worldedit-core') diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommonProxy.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommonProxy.java index 18a7de68f..9f60936c0 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommonProxy.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommonProxy.java @@ -20,7 +20,7 @@ package com.sk89q.worldedit.forge; import com.sk89q.worldedit.forge.gui.GuiHandler; -import net.minecraftforge.fml.common.network.NetworkRegistry; +import net.minecraftforge.fml.network.NetworkRegistry; public class CommonProxy { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java index a3523ddb6..ef05edfaa 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java @@ -20,6 +20,8 @@ package com.sk89q.worldedit.forge; import com.google.common.collect.ImmutableList; +import com.sk89q.jnbt.CompoundTag; +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; @@ -35,13 +37,23 @@ import com.sk89q.worldedit.world.biome.BiomeTypes; import net.minecraft.block.properties.IProperty; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; +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.nbt.NBTTagCompound; import net.minecraft.state.DirectionProperty; import net.minecraft.state.IProperty; import net.minecraft.util.EnumFacing; import net.minecraft.util.IStringSerializable; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.biome.Biome; +import net.minecraftforge.registries.ForgeRegistries; import java.util.stream.Collectors; @@ -124,4 +136,32 @@ final class ForgeAdapter { return new IPropertyAdapter<>(property); } + public static Block adapt(BlockType blockType) { + return ForgeRegistries.BLOCKS.getValue(new ResourceLocation(blockType.getId())); + } + + public static BlockType adapt(Block block) { + return BlockTypes.get(ForgeRegistries.BLOCKS.getKey(block).toString()); + } + + public static Item adapt(ItemType itemType) { + return ForgeRegistries.ITEMS.getValue(new ResourceLocation(itemType.getId())); + } + + public static ItemType adapt(Item item) { + return ItemTypes.get(ForgeRegistries.ITEMS.getKey(item).toString()); + } + + public static ItemStack adapt(BaseItemStack baseItemStack) { + NBTTagCompound forgeCompound = null; + if (baseItemStack.getNbtData() != null) { + forgeCompound = NBTConverter.toNative(baseItemStack.getNbtData()); + } + return new ItemStack(adapt(baseItemStack.getType()), baseItemStack.getAmount(), forgeCompound); + } + + public static BaseItemStack adapt(ItemStack itemStack) { + CompoundTag tag = NBTConverter.fromNative(itemStack.serializeNBT()); + return new BaseItemStack(adapt(itemStack.getItem()), tag, itemStack.getCount()); + } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java index cbe2102c9..b38a625ab 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java @@ -23,13 +23,13 @@ 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; +import net.minecraftforge.registries.ForgeRegistries; /** * Provides access to biome data in Forge. */ class ForgeBiomeRegistry implements BiomeRegistry { - @Override public BiomeData getData(BiomeType biome) { return new ForgeBiomeData(ForgeAdapter.adapt(biome)); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java index f77dc2304..91c0b4cc8 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java @@ -23,11 +23,9 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BundledBlockRegistry; - import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.state.IProperty; -import net.minecraft.util.ResourceLocation; import java.util.Collection; import java.util.HashMap; @@ -43,19 +41,29 @@ public class ForgeBlockRegistry extends BundledBlockRegistry { @Nullable @Override public String getName(BlockType blockType) { - return Block.REGISTRY.get(new ResourceLocation(blockType.getId())).getNameTextComponent().getFormattedText(); + Block block = ForgeAdapter.adapt(blockType); + if (block != null) { + return block.getNameTextComponent().getFormattedText(); + } else { + return super.getName(blockType); + } } @Override public BlockMaterial getMaterial(BlockType blockType) { - return materialMap.computeIfAbsent(Block.getBlockFromName(blockType.getId()).getDefaultState().getMaterial(), + Block block = ForgeAdapter.adapt(blockType); + if (block == null) { + return super.getMaterial(blockType); + } + return materialMap.computeIfAbsent(block.getDefaultState().getMaterial(), m -> new ForgeBlockMaterial(m, super.getMaterial(blockType))); } @Override public Map> getProperties(BlockType blockType) { + Block block = ForgeAdapter.adapt(blockType); Map> map = new TreeMap<>(); - Collection> propertyKeys = Block.getBlockFromName(blockType.getId()) + Collection> propertyKeys = block .getDefaultState() .getProperties(); for (IProperty key : propertyKeys) { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java index 1c428e0c1..595effbe3 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java @@ -29,7 +29,6 @@ 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.entity.EntityList; import net.minecraft.nbt.NBTTagCompound; import java.lang.ref.WeakReference; @@ -49,7 +48,7 @@ class ForgeEntity implements Entity { public BaseEntity getState() { net.minecraft.entity.Entity entity = entityRef.get(); if (entity != null) { - String id = EntityList.getEntityString(entity); + String id = entity.getType().getRegistryName().toString(); if (id != null) { NBTTagCompound tag = new NBTTagCompound(); entity.writeWithoutTypeId(tag); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java index bc6820c0d..7fe30a943 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java @@ -23,6 +23,7 @@ import net.minecraft.command.ICommand; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.world.GameType; import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.server.ServerLifecycleHooks; import org.spongepowered.api.entity.living.player.Player; public interface ForgePermissionsProvider { @@ -43,7 +44,7 @@ public interface ForgePermissionsProvider { public boolean hasPermission(EntityPlayerMP player, String permission) { ForgeConfiguration configuration = platform.getConfiguration(); return configuration.cheatMode || - FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().canSendCommands(player.getGameProfile()) || + ServerLifecycleHooks.getCurrentServer().getPlayerList().canSendCommands(player.getGameProfile()) || (configuration.creativeEnable && player.interactionManager.getGameType() == GameType.CREATIVE); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java index 2eb66bf14..543285447 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java @@ -37,7 +37,7 @@ import net.minecraft.server.management.PlayerList; import net.minecraft.util.ResourceLocation; import net.minecraft.world.WorldServer; import net.minecraftforge.common.DimensionManager; -import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.server.ServerLifecycleHooks; import java.util.ArrayList; import java.util.Collection; @@ -55,7 +55,7 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { ForgePlatform(ForgeWorldEdit mod) { this.mod = mod; - this.server = FMLCommonHandler.instance().getMinecraftServerInstance(); + this.server = ServerLifecycleHooks.getCurrentServer(); } boolean isHookingEvents() { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index 65705004c..c36e06471 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -69,7 +69,7 @@ public class ForgePlayer extends AbstractPlayerActor { @Override public BaseItemStack getItemInHand(HandSide handSide) { ItemStack is = this.player.getHeldItem(handSide == HandSide.MAIN_HAND ? EnumHand.MAIN_HAND : EnumHand.OFF_HAND); - return new BaseItemStack(ItemTypes.get(Item.REGISTRY.getKey(is.getItem()).toString())); + return ForgeAdapter.adapt(is); } @Override @@ -105,7 +105,7 @@ public class ForgePlayer extends AbstractPlayerActor { @Override public void giveItem(BaseItemStack itemStack) { - this.player.inventory.addItemStackToInventory(new ItemStack(Item.REGISTRY.get(new ResourceLocation(itemStack.getType().getId())), itemStack.getAmount(), null)); + this.player.inventory.addItemStackToInventory(ForgeAdapter.adapt(itemStack)); } @Override diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 13205b726..991db00f0 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -52,44 +52,48 @@ import com.sk89q.worldedit.world.weather.WeatherTypes; import net.minecraft.block.Block; import net.minecraft.block.BlockLeaves; import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EntityType; import net.minecraft.entity.item.EntityItem; import net.minecraft.init.Blocks; import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUseContext; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.server.MinecraftServer; import net.minecraft.state.DirectionProperty; import net.minecraft.state.EnumProperty; import net.minecraft.state.IProperty; +import net.minecraft.state.StateContainer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; import net.minecraft.util.IStringSerializable; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraft.world.biome.Biome; -import net.minecraft.world.chunk.BlockStateContainer; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.IChunkProvider; import net.minecraft.world.chunk.storage.AnvilSaveHandler; import net.minecraft.world.gen.ChunkProviderServer; -import net.minecraft.world.gen.feature.WorldGenBigMushroom; -import net.minecraft.world.gen.feature.WorldGenBigTree; -import net.minecraft.world.gen.feature.WorldGenBirchTree; -import net.minecraft.world.gen.feature.WorldGenCanopyTree; -import net.minecraft.world.gen.feature.WorldGenMegaJungle; -import net.minecraft.world.gen.feature.WorldGenMegaPineTree; -import net.minecraft.world.gen.feature.WorldGenSavannaTree; -import net.minecraft.world.gen.feature.WorldGenShrub; -import net.minecraft.world.gen.feature.WorldGenSwamp; -import net.minecraft.world.gen.feature.WorldGenTaiga1; -import net.minecraft.world.gen.feature.WorldGenTaiga2; -import net.minecraft.world.gen.feature.WorldGenTrees; -import net.minecraft.world.gen.feature.WorldGenerator; +import net.minecraft.world.gen.feature.BigBrownMushroomFeature; +import net.minecraft.world.gen.feature.BigRedMushroomFeature; +import net.minecraft.world.gen.feature.BigTreeFeature; +import net.minecraft.world.gen.feature.BirchTreeFeature; +import net.minecraft.world.gen.feature.CanopyTreeFeature; +import net.minecraft.world.gen.feature.Feature; +import net.minecraft.world.gen.feature.JungleTreeFeature; +import net.minecraft.world.gen.feature.MegaJungleFeature; +import net.minecraft.world.gen.feature.MegaPineTree; +import net.minecraft.world.gen.feature.NoFeatureConfig; +import net.minecraft.world.gen.feature.PointyTaigaTreeFeature; +import net.minecraft.world.gen.feature.SavannaTreeFeature; +import net.minecraft.world.gen.feature.ShrubFeature; +import net.minecraft.world.gen.feature.SwampTreeFeature; +import net.minecraft.world.gen.feature.TallTaigaTreeFeature; +import net.minecraft.world.gen.feature.TreeFeature; import net.minecraft.world.storage.WorldInfo; import net.minecraftforge.common.DimensionManager; @@ -101,6 +105,7 @@ import java.util.List; import java.util.Map; import java.util.Random; import java.util.TreeMap; +import java.util.concurrent.ThreadLocalRandom; import javax.annotation.Nullable; @@ -180,8 +185,8 @@ public class ForgeWorld extends AbstractWorld { Block mcBlock = Block.getBlockFromName(block.getBlockType().getId()); IBlockState newState = mcBlock.getDefaultState(); Map, Object> states = block.getStates(); - newState = applyProperties(mcBlock.getBlockState(), newState, states); - IBlockState successState = chunk.setBlockState(pos, newState); + newState = applyProperties(mcBlock.getStateContainer(), newState, states); + IBlockState successState = chunk.setBlockState(pos, newState, false); boolean successful = successState != null; // Create the TileEntity @@ -212,12 +217,9 @@ public class ForgeWorld extends AbstractWorld { return false; } - // Can't get the "Object" to be right for withProperty w/o this - @SuppressWarnings({ "rawtypes", "unchecked" }) - private IBlockState applyProperties(BlockStateContainer stateContainer, IBlockState newState, Map, Object> states) { + private IBlockState applyProperties(StateContainer stateContainer, IBlockState newState, Map, Object> states) { for (Map.Entry, Object> state : states.entrySet()) { - - IProperty property = stateContainer.getProperty(state.getKey().getName()); + IProperty 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) { @@ -259,7 +261,7 @@ public class ForgeWorld extends AbstractWorld { @Override public BiomeType getBiome(BlockVector2 position) { checkNotNull(position); - return ForgeAdapter.adapt(getWorld().getBiomeForCoordsBody(new BlockPos(position.getBlockX(), 0, position.getBlockZ()))); + return ForgeAdapter.adapt(getWorld().getBiomeBody(new BlockPos(position.getBlockX(), 0, position.getBlockZ()))); } @Override @@ -269,7 +271,7 @@ public class ForgeWorld extends AbstractWorld { Chunk chunk = getWorld().getChunk(new BlockPos(position.getBlockX(), 0, position.getBlockZ())); if (chunk.isLoaded()) { - chunk.getBiomeArray()[((position.getBlockZ() & 0xF) << 4 | position.getBlockX() & 0xF)] = (byte) Biome.getIdForBiome(ForgeAdapter.adapt(biome)); + chunk.getBiomes()[((position.getBlockZ() & 0xF) << 4 | position.getBlockX() & 0xF)] = ForgeAdapter.adapt(biome); return true; } @@ -278,16 +280,24 @@ public class ForgeWorld extends AbstractWorld { @Override public boolean useItem(BlockVector3 position, BaseItem item, Direction face) { - Item nativeItem = Item.REGISTRY.get(new ResourceLocation(item.getType().getId())); - ItemStack stack = null; + Item nativeItem = ForgeAdapter.adapt(item.getType()); + ItemStack stack; if (item.getNbtData() == null) { stack = new ItemStack(nativeItem, 1); } else { stack = new ItemStack(nativeItem, 1, NBTConverter.toNative(item.getNbtData())); } World world = getWorld(); - EnumActionResult used = stack.onItemUse(new WorldEditFakePlayer((WorldServer) world), world, ForgeAdapter.toBlockPos(position), - EnumHand.MAIN_HAND, ForgeAdapter.adapt(face), 0, 0, 0); + ItemUseContext itemUseContext = new ItemUseContext( + new WorldEditFakePlayer((WorldServer) world), + stack, + ForgeAdapter.toBlockPos(position), + ForgeAdapter.adapt(face), + 0f, + 0f, + 0f + ); + EnumActionResult used = stack.onItemUse(itemUseContext); return used != EnumActionResult.FAIL; } @@ -300,7 +310,7 @@ public class ForgeWorld extends AbstractWorld { return; } - EntityItem entity = new EntityItem(getWorld(), position.getX(), position.getY(), position.getZ(), ForgeWorldEdit.toForgeItemStack(item)); + EntityItem entity = new EntityItem(getWorld(), position.getX(), position.getY(), position.getZ(), ForgeAdapter.adapt(item)); entity.setPickupDelay(10); getWorld().spawnEntity(entity); } @@ -309,8 +319,8 @@ public class ForgeWorld extends AbstractWorld { public void simulateBlockMine(BlockVector3 position) { BlockPos pos = ForgeAdapter.toBlockPos(position); IBlockState state = getWorld().getBlockState(pos); - state.getBlock().dropBlockAsItem(getWorld(), pos, state, 0); - getWorld().setBlockToAir(pos); + state.dropBlockAsItem(getWorld(), pos, 0); + getWorld().removeBlock(pos); } @Override @@ -328,9 +338,9 @@ public class ForgeWorld extends AbstractWorld { WorldServer originalWorld = (WorldServer) getWorld(); - MinecraftServer server = originalWorld.getMinecraftServer(); - AnvilSaveHandler saveHandler = new AnvilSaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), true, server.getDataFixer()); - World freshWorld = new WorldServer(server, saveHandler, originalWorld.getWorldInfo(), + MinecraftServer server = originalWorld.getServer(); + AnvilSaveHandler saveHandler = new AnvilSaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), server, server.getDataFixer()); + World freshWorld = (World) new WorldServer(server, saveHandler, originalWorld.getWorldInfo(), originalWorld.dimension.getId(), originalWorld.profiler).init(); // Pre-gen all the chunks @@ -357,26 +367,26 @@ public class ForgeWorld extends AbstractWorld { } @Nullable - private static WorldGenerator createWorldGenerator(TreeType type) { + private static Feature createTreeFeatureGenerator(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 WorldGenBirchTree(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 WorldGenBirchTree(true, true); - case RANDOM: + case TREE: return new TreeFeature(true); + case BIG_TREE: return new BigTreeFeature(true); case PINE: + case REDWOOD: return new PointyTaigaTreeFeature(); + case TALL_REDWOOD: return new TallTaigaTreeFeature(true); + case BIRCH: return new BirchTreeFeature(true, false); + case JUNGLE: return new MegaJungleFeature(true, 10, 20, JUNGLE_LOG, JUNGLE_LEAF); + case SMALL_JUNGLE: return new JungleTreeFeature(true, 4 + random.nextInt(7), JUNGLE_LOG, JUNGLE_LEAF, false); + case SHORT_JUNGLE: return new JungleTreeFeature(true, 4 + random.nextInt(7), JUNGLE_LOG, JUNGLE_LEAF, true); + case JUNGLE_BUSH: return new ShrubFeature(JUNGLE_LOG, JUNGLE_SHRUB); + case RED_MUSHROOM: return new BigBrownMushroomFeature(); + case BROWN_MUSHROOM: return new BigRedMushroomFeature(); + case SWAMP: return new SwampTreeFeature(); + case ACACIA: return new SavannaTreeFeature(true); + case DARK_OAK: return new CanopyTreeFeature(true); + case MEGA_REDWOOD: return new MegaPineTree(false, random.nextBoolean()); + case TALL_BIRCH: return new BirchTreeFeature(true, true); + case RANDOM: return createTreeFeatureGenerator(TreeType.values()[ThreadLocalRandom.current().nextInt(TreeType.values().length)]); case RANDOM_REDWOOD: default: return null; @@ -385,8 +395,8 @@ public class ForgeWorld extends AbstractWorld { @Override public boolean generateTree(TreeType type, EditSession editSession, BlockVector3 position) throws MaxChangedBlocksException { - WorldGenerator generator = createWorldGenerator(type); - return generator != null && generator.generate(getWorld(), random, ForgeAdapter.toBlockPos(position)); + Feature generator = createTreeFeatureGenerator(type); + return generator != null && generator.func_212245_a(getWorld(), getWorld().getChunkProvider().getChunkGenerator(), random, ForgeAdapter.toBlockPos(position), new NoFeatureConfig()); } @Override @@ -471,8 +481,8 @@ public class ForgeWorld extends AbstractWorld { BlockPos pos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); IBlockState mcState = world.getBlockState(pos); - BlockType blockType = BlockType.REGISTRY.get(Block.REGISTRY.getKey(mcState.getBlock()).toString()); - return blockType.getState(adaptProperties(blockType, mcState.getProperties())); + BlockType blockType = ForgeAdapter.adapt(mcState.getBlock()); + return blockType.getState(adaptProperties(blockType, mcState.getValues())); } private Map, Object> adaptProperties(BlockType block, Map, Comparable> mcProps) { @@ -546,7 +556,7 @@ public class ForgeWorld extends AbstractWorld { @Override public Entity createEntity(Location location, BaseEntity entity) { World world = getWorld(); - net.minecraft.entity.Entity createdEntity = EntityList.createEntityByIDFromName(new ResourceLocation(entity.getType().getId()), world); + net.minecraft.entity.Entity createdEntity = EntityType.create(world, new ResourceLocation(entity.getType().getId())); if (createdEntity != null) { CompoundTag nativeTag = entity.getNbtData(); if (nativeTag != null) { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index 9d182c32e..3da93610e 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -24,7 +24,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.Joiner; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.event.platform.PlatformReadyEvent; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.forge.net.LeftClickAirEventMessage; @@ -33,11 +32,7 @@ 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.entity.player.EntityPlayerMP; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; @@ -46,17 +41,17 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickEmpty; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.SidedProxy; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.event.FMLServerAboutToStartEvent; import net.minecraftforge.fml.common.event.FMLServerStartedEvent; import net.minecraftforge.fml.common.event.FMLServerStoppingEvent; -import net.minecraftforge.fml.common.eventhandler.Event.Result; import net.minecraftforge.fml.javafmlmod.FMLModLoadingContext; +import net.minecraftforge.registries.ForgeRegistries; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -76,8 +71,7 @@ public class ForgeWorldEdit { public static ForgeWorldEdit inst; - @SidedProxy(serverSide = "com.sk89q.worldedit.forge.CommonProxy", clientSide = "com.sk89q.worldedit.forge.ClientProxy") - public static CommonProxy proxy; + public static CommonProxy proxy = DistExecutor.runForDist(() -> ClientProxy::new, () -> CommonProxy::new); private ForgePlatform platform; private ForgeConfiguration config; @@ -126,20 +120,21 @@ public class ForgeWorldEdit { WorldEdit.getInstance().getPlatformManager().register(platform); - if (Loader.isModLoaded("sponge")) { + if (ModList.get().isLoaded("sponge")) { this.provider = new ForgePermissionsProvider.SpongePermissionsProvider(); } else { this.provider = new ForgePermissionsProvider.VanillaPermissionsProvider(platform); } - for (ResourceLocation name : Block.REGISTRY.getKeys()) { + // TODO Setup states + for (ResourceLocation name : ForgeRegistries.BLOCKS.getKeys()) { String nameStr = name.toString(); if (!BlockType.REGISTRY.keySet().contains(nameStr)) { BlockType.REGISTRY.register(nameStr, new BlockType(nameStr)); } } - for (ResourceLocation name : Item.REGISTRY.getKeys()) { + for (ResourceLocation name : ForgeRegistries.ITEMS.getKeys()) { String nameStr = name.toString(); if (!ItemType.REGISTRY.keySet().contains(nameStr)) { ItemType.REGISTRY.register(nameStr, new ItemType(nameStr)); @@ -232,14 +227,6 @@ public class ForgeWorldEdit { } } - public static ItemStack toForgeItemStack(BaseItemStack item) { - NBTTagCompound forgeCompound = null; - if (item.getNbtData() != null) { - forgeCompound = NBTConverter.toNative(item.getNbtData()); - } - return new ItemStack(Item.REGISTRY.get(new ResourceLocation(item.getType().getId())), item.getAmount(), 0, forgeCompound); - } - /** * Get the configuration. * diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java index 1395beb87..5cd7b7e80 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java @@ -25,12 +25,12 @@ import net.minecraft.client.settings.KeyBinding; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.common.gameevent.InputEvent.KeyInputEvent; -import org.lwjgl.input.Keyboard; +import org.lwjgl.glfw.GLFW; public class KeyHandler { private static Minecraft mc = Minecraft.getInstance(); - private static KeyBinding mainKey = new KeyBinding("WorldEdit Reference", Keyboard.KEY_L, "WorldEdit"); + private static KeyBinding mainKey = new KeyBinding("WorldEdit Reference", GLFW.GLFW_KEY_L, "WorldEdit"); public KeyHandler() { ClientRegistry.registerKeyBinding(mainKey); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java index 91fdc3fcd..5f80516eb 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java @@ -23,6 +23,7 @@ import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.server.MinecraftServer; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; +import net.minecraftforge.fml.server.ServerLifecycleHooks; import java.util.Collections; import java.util.HashSet; @@ -56,7 +57,7 @@ public class ThreadSafeCache { if (now - lastRefresh > REFRESH_DELAY) { Set onlineIds = new HashSet<>(); - MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance(); + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); if (server == null || server.getPlayerList() == null) { return; } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java index a9e53d36d..f982b21df 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java @@ -37,14 +37,14 @@ public class GuiReferenceCard extends GuiScreen { } @Override - public void drawScreen(int mouseX, int mouseY, float par3) { + public void render(int mouseX, int mouseY, float par3) { int x = (this.width - this.backgroundWidth) / 2; int y = (this.height - this.backgroundHeight) / 2 - this.closeButton.height; GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); this.mc.renderEngine.bindTexture(new ResourceLocation(ForgeWorldEdit.MOD_ID, "textures/gui/reference.png")); this.drawTexturedModalRect(x, y, 0, 0, this.backgroundWidth, this.backgroundHeight); - super.drawScreen(mouseX, mouseY, par3); + super.render(mouseX, mouseY, par3); } @Override From c849f69ef418eedb32ca2a1d704a61c9839e1bd4 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sat, 29 Dec 2018 16:42:02 +1000 Subject: [PATCH 06/20] Convert across the network handlers --- .../sk89q/worldedit/forge/ForgePlatform.java | 3 +- .../sk89q/worldedit/forge/ForgePlayer.java | 3 +- .../sk89q/worldedit/forge/ForgeWorldEdit.java | 8 ++- .../worldedit/forge/WECUIPacketHandler.java | 72 ------------------- .../handler}/InternalPacketHandler.java | 23 +++--- .../forge/net/handler/WECUIPacketHandler.java | 72 +++++++++++++++++++ .../LeftClickAirEventMessage.java | 28 ++++---- 7 files changed, 104 insertions(+), 105 deletions(-) delete mode 100644 worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WECUIPacketHandler.java rename worldedit-forge/src/main/java/com/sk89q/worldedit/forge/{ => net/handler}/InternalPacketHandler.java (56%) create mode 100644 worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java rename worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/{ => packet}/LeftClickAirEventMessage.java (53%) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java index 543285447..5c2f1ab89 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java @@ -30,7 +30,6 @@ import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; import net.minecraft.command.ServerCommandManager; -import net.minecraft.entity.EntityList; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.server.MinecraftServer; import net.minecraft.server.management.PlayerList; @@ -69,7 +68,7 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { @Override public boolean isValidMobType(String type) { - return EntityList.isRegistered(new ResourceLocation(type)); + return net.minecraftforge.registries.ForgeRegistries.ENTITIES.containsKey(new ResourceLocation(type)); } @Override diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index c36e06471..5b3b2ca84 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -24,6 +24,7 @@ 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.forge.net.handler.WECUIPacketHandler; import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; @@ -32,10 +33,8 @@ import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.item.ItemTypes; import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; import net.minecraft.network.play.server.SPacketCustomPayload; diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index 3da93610e..cf3b99c37 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -26,7 +26,9 @@ 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.forge.net.LeftClickAirEventMessage; +import com.sk89q.worldedit.forge.net.handler.WECUIPacketHandler; +import com.sk89q.worldedit.forge.net.packet.LeftClickAirEventMessage; +import com.sk89q.worldedit.forge.net.handler.InternalPacketHandler; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -65,7 +67,7 @@ public class ForgeWorldEdit { private static final Logger LOGGER = LogManager.getLogger(); public static final String MOD_ID = "worldedit"; - public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui"; + public static final String CUI_PLUGIN_CHANNEL = "cui"; private ForgePermissionsProvider provider; @@ -176,7 +178,7 @@ public class ForgeWorldEdit { if (event.getWorld().isRemote && event instanceof LeftClickEmpty) { // catch LCE, pass it to server - InternalPacketHandler.CHANNEL.sendToServer(new LeftClickAirEventMessage()); + InternalPacketHandler.HANDLER.sendToServer(new LeftClickAirEventMessage()); return; } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WECUIPacketHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WECUIPacketHandler.java deleted file mode 100644 index 276eadcc6..000000000 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WECUIPacketHandler.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.forge; - -import com.sk89q.worldedit.LocalSession; -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.network.NetHandlerPlayServer; -import net.minecraft.network.PacketBuffer; -import net.minecraft.network.ThreadQuickExitException; -import net.minecraft.network.play.server.SPacketCustomPayload; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.network.FMLEventChannel; -import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientCustomPacketEvent; -import net.minecraftforge.fml.common.network.FMLNetworkEvent.ServerCustomPacketEvent; -import net.minecraftforge.fml.common.network.NetworkRegistry; - -import java.nio.charset.Charset; - -public class WECUIPacketHandler { - public static final Charset UTF_8_CHARSET = Charset.forName("UTF-8"); - public static FMLEventChannel WECUI_CHANNEL; - - public static void init() { - WECUI_CHANNEL = NetworkRegistry.INSTANCE.newEventDrivenChannel(ForgeWorldEdit.CUI_PLUGIN_CHANNEL); - WECUI_CHANNEL.register(new WECUIPacketHandler()); - } - - @SubscribeEvent - public void onPacketData(ServerCustomPacketEvent event) { - if (event.getPacket().channel().equals(ForgeWorldEdit.CUI_PLUGIN_CHANNEL)) { - EntityPlayerMP player = getPlayerFromEvent(event); - LocalSession session = ForgeWorldEdit.inst.getSession(player); - - if (session.hasCUISupport()) { - return; - } - - String text = event.getPacket().payload().toString(UTF_8_CHARSET); - session.handleCUIInitializationMessage(text); - session.describeCUI(ForgeWorldEdit.inst.wrap(player)); - } - } - - @SubscribeEvent - public void callProcessPacket(ClientCustomPacketEvent event) { - try { - new SPacketCustomPayload(event.getPacket().channel(), new PacketBuffer(event.getPacket().payload())).processPacket(event.getHandler()); - } catch (ThreadQuickExitException suppress) { - } - } - - private static EntityPlayerMP getPlayerFromEvent(ServerCustomPacketEvent event) { - return ((NetHandlerPlayServer) event.getHandler()).player; - } -} \ No newline at end of file diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/InternalPacketHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/InternalPacketHandler.java similarity index 56% rename from worldedit-forge/src/main/java/com/sk89q/worldedit/forge/InternalPacketHandler.java rename to worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/InternalPacketHandler.java index c81062121..5af96dd61 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/InternalPacketHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/InternalPacketHandler.java @@ -17,25 +17,26 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.forge; +package com.sk89q.worldedit.forge.net.handler; -import com.sk89q.worldedit.forge.net.LeftClickAirEventMessage; -import javafx.geometry.Side; +import com.sk89q.worldedit.forge.ForgeWorldEdit; +import com.sk89q.worldedit.forge.net.packet.LeftClickAirEventMessage; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.network.NetworkRegistry; import net.minecraftforge.fml.network.simple.SimpleChannel; -import java.nio.charset.Charset; - public class InternalPacketHandler { - public static final Charset UTF_8_CHARSET = Charset.forName("UTF-8"); - public static SimpleChannel CHANNEL; + private static final String PROTOCOL_VERSION = Integer.toString(1); + public static SimpleChannel HANDLER = NetworkRegistry.ChannelBuilder + .named(new ResourceLocation(ForgeWorldEdit.MOD_ID, "internal")) + .clientAcceptedVersions(PROTOCOL_VERSION::equals) + .serverAcceptedVersions(PROTOCOL_VERSION::equals) + .networkProtocolVersion(() -> PROTOCOL_VERSION) + .simpleChannel(); public static void init() { - CHANNEL = NetworkRegistry.newSimpleChannel(new ResourceLocation(ForgeWorldEdit.MOD_ID, "worldedit"), () -> "1", check -> true, check -> true); - CHANNEL.registerMessage(LeftClickAirEventMessage.Handler.class, LeftClickAirEventMessage.class, 0, Side.SERVER); - } + int disc = 0; - private InternalPacketHandler() { + HANDLER.registerMessage(disc++, LeftClickAirEventMessage.class, LeftClickAirEventMessage::encode, LeftClickAirEventMessage::decode, LeftClickAirEventMessage.Handler::handle); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java new file mode 100644 index 000000000..215e31526 --- /dev/null +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java @@ -0,0 +1,72 @@ +/* + * 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.forge.net.handler; + +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.forge.ForgeWorldEdit; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.network.ThreadQuickExitException; +import net.minecraft.network.play.server.SPacketCustomPayload; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.network.NetworkEvent; +import net.minecraftforge.fml.network.NetworkRegistry; +import net.minecraftforge.fml.network.event.EventNetworkChannel; + +import java.nio.charset.Charset; + +public class WECUIPacketHandler { + public static final Charset UTF_8_CHARSET = Charset.forName("UTF-8"); + private static final String PROTOCOL_VERSION = Integer.toString(1); + public static EventNetworkChannel HANDLER = NetworkRegistry.ChannelBuilder + .named(new ResourceLocation(ForgeWorldEdit.MOD_ID, ForgeWorldEdit.CUI_PLUGIN_CHANNEL)) + .clientAcceptedVersions(PROTOCOL_VERSION::equals) + .serverAcceptedVersions(PROTOCOL_VERSION::equals) + .networkProtocolVersion(() -> PROTOCOL_VERSION) + .eventNetworkChannel(); + + public static void init() { + HANDLER.addListener(WECUIPacketHandler::onPacketData); + HANDLER.addListener(WECUIPacketHandler::callProcessPacket); + } + + public static void onPacketData(NetworkEvent.ServerCustomPayloadEvent event) { + EntityPlayerMP player = event.getSource().get().getSender(); + LocalSession session = ForgeWorldEdit.inst.getSession(player); + + if (session.hasCUISupport()) { + return; + } + + String text = event.getPayload().toString(UTF_8_CHARSET); + session.handleCUIInitializationMessage(text); + session.describeCUI(ForgeWorldEdit.inst.wrap(player)); + } + + public static void callProcessPacket(NetworkEvent.ClientCustomPayloadEvent event) { + try { + new SPacketCustomPayload( + new ResourceLocation(ForgeWorldEdit.MOD_ID, ForgeWorldEdit.CUI_PLUGIN_CHANNEL), + event.getPayload() + ).processPacket(Minecraft.getInstance().player.connection); + } catch (ThreadQuickExitException suppress) { + } + } +} \ No newline at end of file diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/LeftClickAirEventMessage.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/packet/LeftClickAirEventMessage.java similarity index 53% rename from worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/LeftClickAirEventMessage.java rename to worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/packet/LeftClickAirEventMessage.java index 1e3b2b20e..9d983848c 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/LeftClickAirEventMessage.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/packet/LeftClickAirEventMessage.java @@ -17,34 +17,32 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.forge.net; +package com.sk89q.worldedit.forge.net.packet; import com.sk89q.worldedit.forge.ForgeWorldEdit; import io.netty.buffer.ByteBuf; +import net.minecraft.network.PacketBuffer; import net.minecraftforge.event.entity.player.PlayerInteractEvent; -import net.minecraftforge.fml.common.network.simpleimpl.IMessage; -import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; -import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import net.minecraftforge.fml.network.NetworkEvent; -public class LeftClickAirEventMessage implements IMessage { +import java.util.function.Supplier; - public static final class Handler implements IMessageHandler { +public class LeftClickAirEventMessage { - @Override - public IMessage onMessage(LeftClickAirEventMessage message, final MessageContext ctx) { - ctx.getServerHandler().player.mcServer.addScheduledTask( - () -> ForgeWorldEdit.inst.onPlayerInteract(new PlayerInteractEvent.LeftClickEmpty(ctx.getServerHandler().player))); - return null; + public static final class Handler { + + public static void handle(final LeftClickAirEventMessage message, Supplier ctx) { + NetworkEvent.Context context = ctx.get(); + context.enqueueWork(() -> ForgeWorldEdit.inst.onPlayerInteract(new PlayerInteractEvent.LeftClickEmpty(context.getSender()))); } } - @Override - public void fromBytes(ByteBuf buf) { + public static LeftClickAirEventMessage decode(ByteBuf buf) { + return new LeftClickAirEventMessage(); } - @Override - public void toBytes(ByteBuf buf) { + public static void encode(LeftClickAirEventMessage msg, PacketBuffer buf) { } } From e4ce51003e0f5550bc8dfc69ba6f3e0ea546fbf7 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sat, 26 Jan 2019 21:50:42 +1000 Subject: [PATCH 07/20] Bump to latest Forge --- worldedit-forge/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 42a242d65..1fbeb6350 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -14,7 +14,7 @@ buildscript { apply plugin: 'net.minecraftforge.gradle' def minecraftVersion = "1.13" -def forgeVersion = "24.0.45-1.13-pre" +def forgeVersion = "24.0.116-1.13-pre" dependencies { compile project(':worldedit-core') From d079f06c31287650872d5f475334901e48fafd27 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 28 Jan 2019 15:54:27 +1000 Subject: [PATCH 08/20] Make it actually load into an IDE on latest FG --- gradle.properties | 3 ++ worldedit-forge/build.gradle | 33 +++++++++++++++---- .../sk89q/worldedit/forge/ForgeEntity.java | 5 +-- 3 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 gradle.properties diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 000000000..e9b9fd5ac --- /dev/null +++ b/gradle.properties @@ -0,0 +1,3 @@ +# Sets default memory used for gradle commands. Can be overridden by user or command line properties. +# This is required to provide enough memory for the Minecraft decompilation process. +org.gradle.jvmargs=-Xmx3G diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 1fbeb6350..2f9b34717 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -14,7 +14,7 @@ buildscript { apply plugin: 'net.minecraftforge.gradle' def minecraftVersion = "1.13" -def forgeVersion = "24.0.116-1.13-pre" +def forgeVersion = "24.0.136-1.13-pre" dependencies { compile project(':worldedit-core') @@ -30,6 +30,25 @@ targetCompatibility = 1.8 minecraft { mappings channel: 'snapshot', version: '20180921-1.13' + runs { + client = { + // recommended logging data for a userdev environment + properties 'forge.logging.markers': 'SCAN,REGISTRIES,REGISTRYDUMP' + // recommended logging level for the console + properties 'forge.logging.console.level': 'debug' + workingDirectory project.file('run').canonicalPath + source sourceSets.main + } + server = { + // recommended logging data for a userdev environment + properties 'forge.logging.markers': 'SCAN,REGISTRIES,REGISTRYDUMP' + // recommended logging level for the console + properties 'forge.logging.console.level': 'debug' + workingDirectory project.file('run').canonicalPath + source sourceSets.main + } + } + accessTransformer = file('worldedit_at.cfg') } @@ -69,11 +88,13 @@ shadowJar { } } -//reobf { -// shadowJar { -// mappingType = 'SEARGE' -// } -//} +afterEvaluate { + reobf { + shadowJar { + mappings = createMcpToSrg.output + } + } +} task deobfJar(type: Jar) { from sourceSets.main.output diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java index 595effbe3..96e97cf29 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java @@ -30,6 +30,7 @@ import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.NullWorld; import com.sk89q.worldedit.world.entity.EntityTypes; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ResourceLocation; import java.lang.ref.WeakReference; @@ -48,11 +49,11 @@ class ForgeEntity implements Entity { public BaseEntity getState() { net.minecraft.entity.Entity entity = entityRef.get(); if (entity != null) { - String id = entity.getType().getRegistryName().toString(); + ResourceLocation id = entity.getType().getRegistryName(); if (id != null) { NBTTagCompound tag = new NBTTagCompound(); entity.writeWithoutTypeId(tag); - return new BaseEntity(EntityTypes.get(id), NBTConverter.fromNative(tag)); + return new BaseEntity(EntityTypes.get(id.toString()), NBTConverter.fromNative(tag)); } else { return null; } From cf435fd63d2cb77a19b9cc67f40a31f504194883 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sat, 16 Feb 2019 15:20:52 +1000 Subject: [PATCH 09/20] Bump to 1.13.2 --- worldedit-forge/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 2f9b34717..097173d49 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -13,13 +13,13 @@ buildscript { apply plugin: 'net.minecraftforge.gradle' -def minecraftVersion = "1.13" -def forgeVersion = "24.0.136-1.13-pre" +def minecraftVersion = "1.13.2" +def forgeVersion = "25.0.13" dependencies { compile project(':worldedit-core') - minecraft "net.minecraftforge.test:forge:${minecraftVersion}-${forgeVersion}" + minecraft "net.minecraftforge:forge:${minecraftVersion}-${forgeVersion}" testCompile group: 'org.mockito', name: 'mockito-core', version: '1.9.0-rc1' } From de9798bf7e397b56d3c57a54e78bf0ea0399468e Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sat, 16 Feb 2019 16:13:03 +1000 Subject: [PATCH 10/20] Further work on 1.13.2 WorldEdit for Forge. Forge still is missing too many features to finish this, and I need to work out how to port the command wrapper system over. --- gradle.properties | 1 + .../forge/ForgePermissionsProvider.java | 27 +++++++------ .../sk89q/worldedit/forge/ForgeWorldEdit.java | 38 ++++++++----------- 3 files changed, 29 insertions(+), 37 deletions(-) diff --git a/gradle.properties b/gradle.properties index e9b9fd5ac..878bf1f7e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,4 @@ # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. org.gradle.jvmargs=-Xmx3G +org.gradle.daemon=false \ No newline at end of file diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java index 7fe30a943..8f9011268 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java @@ -22,9 +22,7 @@ package com.sk89q.worldedit.forge; import net.minecraft.command.ICommand; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.world.GameType; -import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.server.ServerLifecycleHooks; -import org.spongepowered.api.entity.living.player.Player; public interface ForgePermissionsProvider { @@ -52,16 +50,17 @@ public interface ForgePermissionsProvider { public void registerPermission(ICommand command, String permission) {} } - class SpongePermissionsProvider implements ForgePermissionsProvider { - - @Override - public boolean hasPermission(EntityPlayerMP player, String permission) { - return ((Player) player).hasPermission(permission); - } - - @Override - public void registerPermission(ICommand command, String permission) { - - } - } + // TODO Re-add when Sponge for 1.13 is out +// class SpongePermissionsProvider implements ForgePermissionsProvider { +// +// @Override +// public boolean hasPermission(EntityPlayerMP player, String permission) { +// return ((Player) player).hasPermission(permission); +// } +// +// @Override +// public void registerPermission(ICommand command, String permission) { +// +// } +// } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index cf3b99c37..f0dda4960 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -46,13 +46,11 @@ import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.event.FMLInitializationEvent; -import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; -import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; -import net.minecraftforge.fml.common.event.FMLServerAboutToStartEvent; -import net.minecraftforge.fml.common.event.FMLServerStartedEvent; -import net.minecraftforge.fml.common.event.FMLServerStoppingEvent; -import net.minecraftforge.fml.javafmlmod.FMLModLoadingContext; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; +import net.minecraftforge.fml.event.server.FMLServerStartedEvent; +import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.registries.ForgeRegistries; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -82,33 +80,27 @@ public class ForgeWorldEdit { public ForgeWorldEdit() { inst = this; - FMLModLoadingContext.get().getModEventBus().addListener(this::preInit); - FMLModLoadingContext.get().getModEventBus().addListener(this::init); - FMLModLoadingContext.get().getModEventBus().addListener(this::postInit); - FMLModLoadingContext.get().getModEventBus().addListener(this::serverAboutToStart); - FMLModLoadingContext.get().getModEventBus().addListener(this::serverStopping); - FMLModLoadingContext.get().getModEventBus().addListener(this::serverStarted); + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::init); + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::serverAboutToStart); + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::serverStopping); + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::serverStarted); MinecraftForge.EVENT_BUS.register(ThreadSafeCache.getInstance()); MinecraftForge.EVENT_BUS.register(this); } - public void preInit(FMLPreInitializationEvent event) { + public void init(FMLCommonSetupEvent event) { // Setup working directory workingDir = new File(event.getModConfigurationDirectory() + File.separator + "worldedit"); workingDir.mkdir(); config = new ForgeConfiguration(this); config.load(); - } - public void init(FMLInitializationEvent event) { WECUIPacketHandler.init(); InternalPacketHandler.init(); proxy.registerHandlers(); - } - public void postInit(FMLPostInitializationEvent event) { LOGGER.info("WorldEdit for Forge (version " + getInternalVersion() + ") is loaded"); } @@ -122,11 +114,11 @@ public class ForgeWorldEdit { WorldEdit.getInstance().getPlatformManager().register(platform); - if (ModList.get().isLoaded("sponge")) { - this.provider = new ForgePermissionsProvider.SpongePermissionsProvider(); - } else { - this.provider = new ForgePermissionsProvider.VanillaPermissionsProvider(platform); - } +// TODO if (ModList.get().isLoaded("sponge")) { +// this.provider = new ForgePermissionsProvider.SpongePermissionsProvider(); +// } else { + this.provider = new ForgePermissionsProvider.VanillaPermissionsProvider(platform); +// } // TODO Setup states for (ResourceLocation name : ForgeRegistries.BLOCKS.getKeys()) { From 7faafa1635cc95e7ec0b10689f06102b6a1bd06b Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 18 Feb 2019 21:03:03 -0800 Subject: [PATCH 11/20] Update mappings and forge, correct toml keys --- worldedit-forge/build.gradle | 4 ++-- .../src/main/resources/META-INF/mods.toml | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 097173d49..faaa4931c 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -14,7 +14,7 @@ buildscript { apply plugin: 'net.minecraftforge.gradle' def minecraftVersion = "1.13.2" -def forgeVersion = "25.0.13" +def forgeVersion = "25.0.34" dependencies { compile project(':worldedit-core') @@ -28,7 +28,7 @@ sourceCompatibility = 1.8 targetCompatibility = 1.8 minecraft { - mappings channel: 'snapshot', version: '20180921-1.13' + mappings channel: 'snapshot', version: '20190217-1.13.1' runs { client = { diff --git a/worldedit-forge/src/main/resources/META-INF/mods.toml b/worldedit-forge/src/main/resources/META-INF/mods.toml index 7a8a52407..9bb66bea4 100644 --- a/worldedit-forge/src/main/resources/META-INF/mods.toml +++ b/worldedit-forge/src/main/resources/META-INF/mods.toml @@ -1,7 +1,7 @@ # The name of the mod loader type to load - for regular FML @Mod mods it should be javafml modLoader="javafml" # A version range to match for said mod loader - for regular FML @Mod it will be the minecraft version (without the 1.) -loaderVersion="[13,)" +loaderVersion="[24,)" # A URL to refer people to when problems occur with this mod issueTrackerURL="https://discord.gg/YKbmj7V" # A URL for the "homepage" for this mod, displayed in the mod UI @@ -11,7 +11,7 @@ logoFile="worldedit-icon.png" # A text field displayed in the mod UI authors="sk89q, wizjany, TomyLobo, kenzierocks, Me4502" # A list of mods - how many allowed here is determined by the individual mod loader -[[worldedit]] +[[mods]] # The modid of the mod modId="worldedit" # The version number of the mod - there's a few well known ${} variables useable here or just hardcode it @@ -20,11 +20,17 @@ version="${internalVersion}" displayName="WorldEdit" # The description text for the mod (multi line!) description=''' -WorldEdit is an easy-to-use in-game world editor for Minecraft, supporting both single player and multiplayer. +WorldEdit is an easy-to-use in-game world editor for Minecraft, supporting both single- and multi-player. ''' -[[dependencies.sponge]] +[[dependencies.worldedit]] + modId="minecraft" + mandatory=true + versionRange="[1.13.2]" + ordering="NONE" + side="SERVER" +[[dependencies.worldedit]] modId="sponge" mandatory=false versionRange="[1.13]" - ordering="NONE" - side="BOTH" \ No newline at end of file + ordering="BEFORE" + side="SERVER" \ No newline at end of file From 29b6c84230ad35a1d1aa60ed573c4141d25efb4d Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Tue, 19 Feb 2019 20:30:52 +1000 Subject: [PATCH 12/20] Rebase and properly setup the registries --- .../sk89q/worldedit/forge/ForgeAdapter.java | 58 +++++++++++-- .../worldedit/forge/ForgeBiomeRegistry.java | 1 - .../com/sk89q/worldedit/forge/ForgeWorld.java | 82 ++++--------------- .../sk89q/worldedit/forge/ForgeWorldEdit.java | 42 ++++++---- .../sk89q/worldedit/forge/NBTConverter.java | 4 +- .../worldedit/forge/TileEntityUtils.java | 6 +- 6 files changed, 101 insertions(+), 92 deletions(-) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java index ef05edfaa..58aba645c 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java @@ -31,22 +31,21 @@ 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 net.minecraft.block.properties.IProperty; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.ResourceLocation; +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.block.state.IBlockState; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.state.DirectionProperty; import net.minecraft.state.IProperty; +import net.minecraft.state.StateContainer; import net.minecraft.util.EnumFacing; import net.minecraft.util.IStringSerializable; import net.minecraft.util.ResourceLocation; @@ -55,6 +54,9 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.biome.Biome; import net.minecraftforge.registries.ForgeRegistries; +import java.util.Comparator; +import java.util.Map; +import java.util.TreeMap; import java.util.stream.Collectors; final class ForgeAdapter { @@ -67,7 +69,7 @@ final class ForgeAdapter { } public static Biome adapt(BiomeType biomeType) { - return Biome.REGISTRY.getObject(new ResourceLocation(biomeType.getId())); + return ForgeRegistries.BIOMES.getValue(new ResourceLocation(biomeType.getId())); } public static BiomeType adapt(Biome biome) { @@ -136,6 +138,52 @@ final class ForgeAdapter { return new IPropertyAdapter<>(property); } + public static Map, Object> adaptProperties(BlockType block, Map, Comparable> mcProps) { + Map, Object> props = new TreeMap<>(Comparator.comparing(Property::getName)); + for (Map.Entry, Comparable> prop : mcProps.entrySet()) { + Object value = prop.getValue(); + if (prop.getKey() instanceof DirectionProperty) { + value = adaptEnumFacing((EnumFacing) value); + } else if (prop.getKey() instanceof net.minecraft.state.EnumProperty) { + value = ((IStringSerializable) value).getName(); + } + props.put(block.getProperty(prop.getKey().getName()), value); + } + return props; + } + + private static IBlockState applyProperties(StateContainer stateContainer, IBlockState newState, Map, Object> states) { + for (Map.Entry, Object> state : states.entrySet()) { + IProperty 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 = ForgeAdapter.adapt(dir); + } else if (property instanceof net.minecraft.state.EnumProperty) { + String enumName = (String) value; + value = ((net.minecraft.state.EnumProperty) property).parseValue((String) value).orElseGet(() -> { + throw new IllegalStateException("Enum property " + property.getName() + " does not contain " + enumName); + }); + } + + newState = newState.with(property, value); + } + return newState; + } + + public static IBlockState adapt(BlockState blockState) { + Block mcBlock = ForgeAdapter.adapt(blockState.getBlockType()); + IBlockState newState = mcBlock.getDefaultState(); + Map, Object> states = blockState.getStates(); + return applyProperties(mcBlock.getStateContainer(), newState, states); + } + + public static BlockState adapt(IBlockState blockState) { + BlockType blockType = adapt(blockState.getBlock()); + return blockType.getState(ForgeAdapter.adaptProperties(blockType, blockState.getValues())); + } + public static Block adapt(BlockType blockType) { return ForgeRegistries.BLOCKS.getValue(new ResourceLocation(blockType.getId())); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java index b38a625ab..e0337d735 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java @@ -23,7 +23,6 @@ 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; -import net.minecraftforge.registries.ForgeRegistries; /** * Provides access to biome data in Forge. diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 991db00f0..da9d0bf61 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -36,7 +36,6 @@ 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.registry.state.Property; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; @@ -45,11 +44,9 @@ 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.block.BlockType; 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.BlockLeaves; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EntityType; @@ -61,19 +58,12 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.server.MinecraftServer; -import net.minecraft.state.DirectionProperty; -import net.minecraft.state.EnumProperty; -import net.minecraft.state.IProperty; -import net.minecraft.state.StateContainer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumActionResult; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.IStringSerializable; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.WorldServer; -import net.minecraft.world.biome.Biome; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.IChunkProvider; import net.minecraft.world.chunk.storage.AnvilSaveHandler; @@ -100,11 +90,8 @@ import net.minecraftforge.common.DimensionManager; import java.io.File; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; -import java.util.Map; import java.util.Random; -import java.util.TreeMap; import java.util.concurrent.ThreadLocalRandom; import javax.annotation.Nullable; @@ -182,10 +169,7 @@ public class ForgeWorld extends AbstractWorld { Chunk chunk = world.getChunk(x >> 4, z >> 4); BlockPos pos = new BlockPos(x, y, z); IBlockState old = chunk.getBlockState(pos); - Block mcBlock = Block.getBlockFromName(block.getBlockType().getId()); - IBlockState newState = mcBlock.getDefaultState(); - Map, Object> states = block.getStates(); - newState = applyProperties(mcBlock.getStateContainer(), newState, states); + IBlockState newState = ForgeAdapter.adapt(block.toImmutableState()); IBlockState successState = chunk.setBlockState(pos, newState, false); boolean successful = successState != null; @@ -195,7 +179,7 @@ public class ForgeWorld extends AbstractWorld { // Kill the old TileEntity world.removeTileEntity(pos); NBTTagCompound nativeTag = NBTConverter.toNative(((BaseBlock) block).getNbtData()); - nativeTag.setString("id", ((BaseBlock) block).getNbtId()); + nativeTag.putString("id", ((BaseBlock) block).getNbtId()); TileEntityUtils.setTileEntity(world, position, nativeTag); } } @@ -217,26 +201,6 @@ public class ForgeWorld extends AbstractWorld { return false; } - private IBlockState applyProperties(StateContainer stateContainer, IBlockState newState, Map, Object> states) { - for (Map.Entry, Object> state : states.entrySet()) { - IProperty 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 = ForgeAdapter.adapt(dir); - } else if (property instanceof EnumProperty) { - String enumName = (String) value; - value = ((EnumProperty) property).parseValue((String) value).orElseGet(() -> { - throw new IllegalStateException("Enum property " + property.getName() + " does not contain " + enumName); - }); - } - - newState = newState.with(property, value); - } - return newState; - } - @Override public int getBlockLightLevel(BlockVector3 position) { checkNotNull(position); @@ -340,8 +304,7 @@ public class ForgeWorld extends AbstractWorld { MinecraftServer server = originalWorld.getServer(); AnvilSaveHandler saveHandler = new AnvilSaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), server, server.getDataFixer()); - World freshWorld = (World) new WorldServer(server, saveHandler, originalWorld.getWorldInfo(), - originalWorld.dimension.getId(), originalWorld.profiler).init(); + World freshWorld = new WorldServer(server, saveHandler, originalWorld.getSavedDataStorage(), originalWorld.getWorldInfo(), originalWorld.dimension.getType(), originalWorld.profiler).func_212251_i__(); // Pre-gen all the chunks // We need to also pull one more chunk in every direction @@ -359,8 +322,8 @@ public class ForgeWorld extends AbstractWorld { throw new RuntimeException(e); } finally { saveFolder.delete(); - DimensionManager.setWorld(originalWorld.dimension.getId(), null, server); - DimensionManager.setWorld(originalWorld.dimension.getId(), originalWorld, server); + DimensionManager.setWorld(originalWorld.dimension.getType(), null, server); + DimensionManager.setWorld(originalWorld.dimension.getType(), originalWorld, server); } return true; @@ -396,7 +359,7 @@ public class ForgeWorld extends AbstractWorld { @Override public boolean generateTree(TreeType type, EditSession editSession, BlockVector3 position) throws MaxChangedBlocksException { Feature generator = createTreeFeatureGenerator(type); - return generator != null && generator.func_212245_a(getWorld(), getWorld().getChunkProvider().getChunkGenerator(), random, ForgeAdapter.toBlockPos(position), new NoFeatureConfig()); + return generator != null && generator.place(getWorld(), getWorld().getChunkProvider().getChunkGenerator(), random, ForgeAdapter.toBlockPos(position), new NoFeatureConfig()); } @Override @@ -455,15 +418,15 @@ public class ForgeWorld extends AbstractWorld { @Override public void setWeather(WeatherType weatherType, long duration) { WorldInfo info = getWorld().getWorldInfo(); - if (WeatherTypes.THUNDER_STORM.equals(weatherType)) { + if (weatherType == WeatherTypes.THUNDER_STORM) { info.setClearWeatherTime(0); info.setThundering(true); info.setThunderTime((int) duration); - } else if (WeatherTypes.RAIN.equals(weatherType)) { + } else if (weatherType == WeatherTypes.RAIN) { info.setClearWeatherTime(0); info.setRaining(true); info.setRainTime((int) duration); - } else if (WeatherTypes.CLEAR.equals(weatherType)) { + } else if (weatherType == WeatherTypes.CLEAR) { info.setRaining(false); info.setThundering(false); info.setClearWeatherTime((int) duration); @@ -477,26 +440,13 @@ public class ForgeWorld extends AbstractWorld { @Override public BlockState getBlock(BlockVector3 position) { - World world = getWorld(); - BlockPos pos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - IBlockState mcState = world.getBlockState(pos); + IBlockState mcState = getWorld().getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4).getBlockState( + position.getBlockX(), + position.getBlockY(), + position.getBlockZ() + ); - BlockType blockType = ForgeAdapter.adapt(mcState.getBlock()); - return blockType.getState(adaptProperties(blockType, mcState.getValues())); - } - - private Map, Object> adaptProperties(BlockType block, Map, Comparable> mcProps) { - Map, Object> props = new TreeMap<>(Comparator.comparing(Property::getName)); - for (Map.Entry, Comparable> prop : mcProps.entrySet()) { - Object value = prop.getValue(); - if (prop.getKey() instanceof DirectionProperty) { - value = ForgeAdapter.adaptEnumFacing((EnumFacing) value); - } else if (prop.getKey() instanceof EnumProperty) { - value = ((IStringSerializable) value).getName(); - } - props.put(block.getProperty(prop.getKey().getName()), value); - } - return props; + return ForgeAdapter.adapt(mcState); } @Override @@ -562,7 +512,7 @@ public class ForgeWorld extends AbstractWorld { if (nativeTag != null) { NBTTagCompound tag = NBTConverter.toNative(entity.getNbtData()); for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.removeTag(name); + tag.remove(name); } createdEntity.read(tag); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index f0dda4960..4c8ca8e1e 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -26,15 +26,18 @@ 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.forge.net.handler.InternalPacketHandler; import com.sk89q.worldedit.forge.net.handler.WECUIPacketHandler; import com.sk89q.worldedit.forge.net.packet.LeftClickAirEventMessage; -import com.sk89q.worldedit.forge.net.handler.InternalPacketHandler; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.block.BlockCategory; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.item.ItemCategory; import com.sk89q.worldedit.world.item.ItemType; -import com.sk89q.worldedit.world.item.ItemTypes; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.tags.BlockTags; +import net.minecraft.tags.ItemTags; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; @@ -44,7 +47,6 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickEmpty import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; @@ -120,19 +122,29 @@ public class ForgeWorldEdit { this.provider = new ForgePermissionsProvider.VanillaPermissionsProvider(platform); // } - // TODO Setup states - for (ResourceLocation name : ForgeRegistries.BLOCKS.getKeys()) { - String nameStr = name.toString(); - if (!BlockType.REGISTRY.keySet().contains(nameStr)) { - BlockType.REGISTRY.register(nameStr, new BlockType(nameStr)); - } - } + setupRegistries(); + } + private void setupRegistries() { + // Blocks + for (ResourceLocation name : ForgeRegistries.BLOCKS.getKeys()) { + BlockType.REGISTRY.register(name.toString(), new BlockType(name.toString(), + input -> ForgeAdapter.adapt(ForgeAdapter.adapt(input.getBlockType()).getDefaultState()))); + } + // Items for (ResourceLocation name : ForgeRegistries.ITEMS.getKeys()) { - String nameStr = name.toString(); - if (!ItemType.REGISTRY.keySet().contains(nameStr)) { - ItemType.REGISTRY.register(nameStr, new ItemType(nameStr)); - } + ItemType.REGISTRY.register(name.toString(), new ItemType(name.toString())); + } + // Entities + for (ResourceLocation name : ForgeRegistries.ENTITIES.getKeys()) { + EntityType.REGISTRY.register(name.toString(), new EntityType(name.toString())); + } + // Tags + for (ResourceLocation name : BlockTags.getCollection().getRegisteredTags()) { + BlockCategory.REGISTRY.register(name.toString(), new BlockCategory(name.toString())); + } + for (ResourceLocation name : ItemTags.getCollection().getRegisteredTags()) { + ItemCategory.REGISTRY.register(name.toString(), new ItemCategory(name.toString())); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/NBTConverter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/NBTConverter.java index f05fbef47..bae43851c 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/NBTConverter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/NBTConverter.java @@ -140,7 +140,7 @@ final class NBTConverter { public static NBTTagCompound toNative(CompoundTag tag) { NBTTagCompound compound = new NBTTagCompound(); for (Entry child : tag.getValue().entrySet()) { - compound.setTag(child.getKey(), toNative(child.getValue())); + compound.put(child.getKey(), toNative(child.getValue())); } return compound; } @@ -245,7 +245,7 @@ final class NBTConverter { Set tags = other.keySet(); Map map = new HashMap<>(); for (String tagName : tags) { - map.put(tagName, fromNative(other.getTag(tagName))); + map.put(tagName, fromNative(other.get(tagName))); } return new CompoundTag(map); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/TileEntityUtils.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/TileEntityUtils.java index 8a65feaf4..52f027f51 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/TileEntityUtils.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/TileEntityUtils.java @@ -52,9 +52,9 @@ final class TileEntityUtils { 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())); + tag.put("x", new NBTTagInt(position.getBlockX())); + tag.put("y", new NBTTagInt(position.getBlockY())); + tag.put("z", new NBTTagInt(position.getBlockZ())); return tag; } From aa295d91e896ebe186f786d57453e83fa84baf0a Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Tue, 19 Feb 2019 21:49:06 +1000 Subject: [PATCH 13/20] All but commands and config directory are ported. --- .../sk89q/worldedit/forge/CommonProxy.java | 15 +++- .../sk89q/worldedit/forge/ForgePlatform.java | 7 +- .../com/sk89q/worldedit/forge/ForgeWorld.java | 86 +++++++++---------- .../sk89q/worldedit/forge/ForgeWorldEdit.java | 8 +- .../com/sk89q/worldedit/forge/KeyHandler.java | 6 +- .../sk89q/worldedit/forge/gui/GuiHandler.java | 45 ---------- .../worldedit/forge/gui/GuiReferenceCard.java | 18 ++-- .../ResourceLocationInteractionObject.java | 65 ++++++++++++++ 8 files changed, 140 insertions(+), 110 deletions(-) delete mode 100644 worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiHandler.java create mode 100644 worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/ResourceLocationInteractionObject.java diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommonProxy.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommonProxy.java index 9f60936c0..7c5708358 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommonProxy.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommonProxy.java @@ -19,13 +19,22 @@ package com.sk89q.worldedit.forge; -import com.sk89q.worldedit.forge.gui.GuiHandler; -import net.minecraftforge.fml.network.NetworkRegistry; +import com.sk89q.worldedit.forge.gui.GuiReferenceCard; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.ExtensionPoint; +import net.minecraftforge.fml.ModLoadingContext; public class CommonProxy { + public static ResourceLocation REFERENCE_GUI = new ResourceLocation("worldedit", "resource_gui"); + public void registerHandlers() { - NetworkRegistry.INSTANCE.registerGuiHandler(ForgeWorldEdit.inst, new GuiHandler()); + ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.GUIFACTORY, () -> openContainer -> { + if (openContainer.getId().equals(REFERENCE_GUI)) { + return new GuiReferenceCard(); + } + return null; + }); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java index 5c2f1ab89..4d83e1ded 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java @@ -35,7 +35,6 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.management.PlayerList; import net.minecraft.util.ResourceLocation; import net.minecraft.world.WorldServer; -import net.minecraftforge.common.DimensionManager; import net.minecraftforge.fml.server.ServerLifecycleHooks; import java.util.ArrayList; @@ -83,8 +82,8 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { @Override public List getWorlds() { - WorldServer[] worlds = DimensionManager.getWorlds(); - List ret = new ArrayList<>(worlds.length); + Iterable worlds = server.getWorlds(); + List ret = new ArrayList<>(); for (WorldServer world : worlds) { ret.add(new ForgeWorld(world)); } @@ -108,7 +107,7 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { if (world instanceof ForgeWorld) { return world; } else { - for (WorldServer ws : DimensionManager.getWorlds()) { + for (WorldServer ws : server.getWorlds()) { if (ws.getWorldInfo().getWorldName().equals(world.getName())) { return new ForgeWorld(ws); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index da9d0bf61..8291f50ae 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.forge; import static com.google.common.base.Preconditions.checkNotNull; -import com.google.common.io.Files; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; @@ -34,7 +33,6 @@ import com.sk89q.worldedit.internal.Constants; 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; @@ -57,7 +55,6 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumActionResult; import net.minecraft.util.ResourceLocation; @@ -65,9 +62,6 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.IChunkProvider; -import net.minecraft.world.chunk.storage.AnvilSaveHandler; -import net.minecraft.world.gen.ChunkProviderServer; import net.minecraft.world.gen.feature.BigBrownMushroomFeature; import net.minecraft.world.gen.feature.BigRedMushroomFeature; import net.minecraft.world.gen.feature.BigTreeFeature; @@ -85,9 +79,7 @@ import net.minecraft.world.gen.feature.SwampTreeFeature; import net.minecraft.world.gen.feature.TallTaigaTreeFeature; import net.minecraft.world.gen.feature.TreeFeature; import net.minecraft.world.storage.WorldInfo; -import net.minecraftforge.common.DimensionManager; -import java.io.File; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -289,44 +281,46 @@ public class ForgeWorld extends AbstractWorld { @Override public boolean regenerate(Region region, EditSession editSession) { - // Don't even try to regen if it's going to fail. - IChunkProvider provider = getWorld().getChunkProvider(); - if (!(provider instanceof ChunkProviderServer)) { - 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(); - - WorldServer originalWorld = (WorldServer) getWorld(); - - MinecraftServer server = originalWorld.getServer(); - AnvilSaveHandler saveHandler = new AnvilSaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), server, server.getDataFixer()); - World freshWorld = new WorldServer(server, saveHandler, originalWorld.getSavedDataStorage(), originalWorld.getWorldInfo(), originalWorld.dimension.getType(), originalWorld.profiler).func_212251_i__(); - - // 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()); - } - - ForgeWorld from = new ForgeWorld(freshWorld); - try { - for (BlockVector3 vec : region) { - editSession.setBlock(vec, from.getFullBlock(vec)); - } - } catch (MaxChangedBlocksException e) { - throw new RuntimeException(e); - } finally { - saveFolder.delete(); - DimensionManager.setWorld(originalWorld.dimension.getType(), null, server); - DimensionManager.setWorld(originalWorld.dimension.getType(), originalWorld, server); - } - - return true; + // TODO Fix for 1.13 + return false; +// // Don't even try to regen if it's going to fail. +// IChunkProvider provider = getWorld().getChunkProvider(); +// if (!(provider instanceof ChunkProviderServer)) { +// 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(); +// +// WorldServer originalWorld = (WorldServer) getWorld(); +// +// MinecraftServer server = originalWorld.getServer(); +// AnvilSaveHandler saveHandler = new AnvilSaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), server, server.getDataFixer()); +// World freshWorld = new WorldServer(server, saveHandler, originalWorld.getSavedDataStorage(), originalWorld.getWorldInfo(), originalWorld.dimension.getType(), originalWorld.profiler).func_212251_i__(); +// +// // 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()); +// } +// +// ForgeWorld from = new ForgeWorld(freshWorld); +// try { +// for (BlockVector3 vec : region) { +// editSession.setBlock(vec, from.getFullBlock(vec)); +// } +// } catch (MaxChangedBlocksException e) { +// throw new RuntimeException(e); +// } finally { +// saveFolder.delete(); +// DimensionManager.setWorld(originalWorld.dimension.getType(), null, server); +// DimensionManager.setWorld(originalWorld.dimension.getType(), originalWorld, server); +// } +// +// return true; } @Nullable diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index 4c8ca8e1e..f25e50544 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -47,6 +47,8 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickEmpty import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.ModContainer; +import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; @@ -79,6 +81,8 @@ public class ForgeWorldEdit { private ForgeConfiguration config; private File workingDir; + private ModContainer container; + public ForgeWorldEdit() { inst = this; @@ -92,6 +96,8 @@ public class ForgeWorldEdit { } public void init(FMLCommonSetupEvent event) { + this.container = ModLoadingContext.get().getActiveContainer(); + // Setup working directory workingDir = new File(event.getModConfigurationDirectory() + File.separator + "worldedit"); workingDir.mkdir(); @@ -299,7 +305,7 @@ public class ForgeWorldEdit { * @return a version string */ String getInternalVersion() { - return ForgeWorldEdit.class.getAnnotation(Mod.class).version(); + return container.getModInfo().getVersion().toString(); } public void setPermissionsProvider(ForgePermissionsProvider provider) { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java index 5cd7b7e80..d0a23fcf1 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.forge; -import com.sk89q.worldedit.forge.gui.GuiHandler; +import com.sk89q.worldedit.forge.gui.GuiReferenceCard; import net.minecraft.client.Minecraft; import net.minecraft.client.settings.KeyBinding; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -39,7 +39,9 @@ public class KeyHandler { @SubscribeEvent public void onKey(KeyInputEvent evt) { if (mc.player != null && mc.world != null && mainKey.isPressed()) { - mc.player.openGui(ForgeWorldEdit.inst, GuiHandler.REFERENCE_ID, mc.world, 0, 0, 0); + mc.displayGuiScreen(new GuiReferenceCard()); + // TODO Seems GuiHandlers don't work on client right now +// NetworkHooks.openGui(mc.player, new ResourceLocationInteractionObject(CommonProxy.REFERENCE_GUI)); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiHandler.java deleted file mode 100644 index d88b97379..000000000 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiHandler.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.forge.gui; - -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.world.World; -import net.minecraftforge.fml.common.network.IGuiHandler; - -public class GuiHandler implements IGuiHandler { - - public static final int REFERENCE_ID = 0; - - @Override - public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { - return null; - } - - @Override - public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { - switch (id) { - case REFERENCE_ID: - return new GuiReferenceCard(); - } - - return null; - } - -} \ No newline at end of file diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java index f982b21df..23e0bb90c 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java @@ -33,7 +33,14 @@ public class GuiReferenceCard extends GuiScreen { @Override public void initGui() { - this.buttonList.add(this.closeButton = new GuiButton(0, (this.width - this.backgroundWidth + 100) / 2, (this.height + this.backgroundHeight - 60) / 2, this.backgroundWidth - 100, 20, "Close")); + this.closeButton = new GuiButton(0, (this.width - this.backgroundWidth + 100) / 2, (this.height + this.backgroundHeight - 60) / 2, this.backgroundWidth - 100, 20, "Close") { + @Override + public void onClick(double p_194829_1_, double p_194829_3_) { + super.onClick(p_194829_1_, p_194829_3_); + + mc.player.closeScreen(); + } + }; } @Override @@ -42,18 +49,11 @@ public class GuiReferenceCard extends GuiScreen { int y = (this.height - this.backgroundHeight) / 2 - this.closeButton.height; GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); - this.mc.renderEngine.bindTexture(new ResourceLocation(ForgeWorldEdit.MOD_ID, "textures/gui/reference.png")); + this.mc.textureManager.bindTexture(new ResourceLocation(ForgeWorldEdit.MOD_ID, "textures/gui/reference.png")); this.drawTexturedModalRect(x, y, 0, 0, this.backgroundWidth, this.backgroundHeight); super.render(mouseX, mouseY, par3); } - @Override - protected void actionPerformed(GuiButton button) { - if (button.id == 0) { - this.mc.player.closeScreen(); - } - } - @Override public boolean doesGuiPauseGame() { return true; diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/ResourceLocationInteractionObject.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/ResourceLocationInteractionObject.java new file mode 100644 index 000000000..6e11d02dd --- /dev/null +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/ResourceLocationInteractionObject.java @@ -0,0 +1,65 @@ +/* + * 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.forge.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.world.IInteractionObject; + +import javax.annotation.Nullable; + +public class ResourceLocationInteractionObject implements IInteractionObject { + + private ResourceLocation resourceLocation; + + public ResourceLocationInteractionObject(ResourceLocation resourceLocation) { + this.resourceLocation = resourceLocation; + } + + @Override + public Container createContainer(InventoryPlayer inventoryPlayer, EntityPlayer entityPlayer) { + throw new UnsupportedOperationException(); + } + + @Override + public String getGuiID() { + return resourceLocation.toString(); + } + + @Override + public ITextComponent getName() { + return new TextComponentString(resourceLocation.toString()); + } + + @Override + public boolean hasCustomName() { + return false; + } + + @Nullable + @Override + public ITextComponent getCustomName() { + return null; + } +} From a0f127813dda4fe9d20a347fc6cddf7240eef61b Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 21 Feb 2019 00:40:00 -0800 Subject: [PATCH 14/20] Pull config dir from FMLPaths --- .../sk89q/worldedit/forge/ForgeWorldEdit.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index f25e50544..8b26c285f 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -55,11 +55,16 @@ import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.fml.loading.FMLPaths; import net.minecraftforge.registries.ForgeRegistries; 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 Forge implementation of WorldEdit. @@ -79,7 +84,7 @@ public class ForgeWorldEdit { private ForgePlatform platform; private ForgeConfiguration config; - private File workingDir; + private Path workingDir; private ModContainer container; @@ -99,8 +104,14 @@ public class ForgeWorldEdit { this.container = ModLoadingContext.get().getActiveContainer(); // Setup working directory - workingDir = new File(event.getModConfigurationDirectory() + File.separator + "worldedit"); - workingDir.mkdir(); + workingDir = FMLPaths.CONFIGDIR.get().resolve("worldedit"); + if (!Files.exists(workingDir)) { + try { + Files.createDirectory(workingDir); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } config = new ForgeConfiguration(this); config.load(); @@ -296,7 +307,7 @@ public class ForgeWorldEdit { * @return the working directory */ public File getWorkingDir() { - return this.workingDir; + return this.workingDir.toFile(); } /** From 9ee0f000304b1b7b727312af4c47dcc4a7b70109 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 4 Mar 2019 18:31:20 -0800 Subject: [PATCH 15/20] Initial command registration setup. Pretty hacky, subcommands do not work, some arguments missing. --- worldedit-forge/build.gradle | 2 +- .../sk89q/worldedit/forge/CommandWrapper.java | 157 ++++++++++++------ .../sk89q/worldedit/forge/ForgeAdapter.java | 18 +- .../forge/ForgePermissionsProvider.java | 5 +- .../sk89q/worldedit/forge/ForgePlatform.java | 13 +- .../sk89q/worldedit/forge/ForgeWorldEdit.java | 35 +--- .../forge/net/handler/WECUIPacketHandler.java | 4 +- .../src/main/resources/META-INF/mods.toml | 8 +- .../src/main/resources/pack.mcmeta | 6 + 9 files changed, 153 insertions(+), 95 deletions(-) create mode 100644 worldedit-forge/src/main/resources/pack.mcmeta diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index faaa4931c..536739a5c 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -14,7 +14,7 @@ buildscript { apply plugin: 'net.minecraftforge.gradle' def minecraftVersion = "1.13.2" -def forgeVersion = "25.0.34" +def forgeVersion = "25.0.70" dependencies { compile project(':worldedit-core') diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java index 1ad0f10ca..cb1d051b4 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java @@ -19,60 +19,123 @@ package com.sk89q.worldedit.forge; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.tree.CommandNode; +import com.mojang.brigadier.tree.LiteralCommandNode; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.util.command.CommandMapping; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommand; -import net.minecraft.command.ICommandSender; -import net.minecraft.server.MinecraftServer; +import com.sk89q.worldedit.util.command.Parameter; +import net.minecraft.command.CommandSource; +import net.minecraft.entity.player.EntityPlayerMP; -import java.util.Arrays; -import java.util.List; +import java.util.LinkedList; +import java.util.function.Predicate; -import javax.annotation.Nullable; +import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer; +import static net.minecraft.command.Commands.argument; +import static net.minecraft.command.Commands.literal; -public class CommandWrapper extends CommandBase { - private CommandMapping command; +public class CommandWrapper { - protected CommandWrapper(CommandMapping command) { - this.command = command; - } + public static void register(CommandDispatcher dispatcher, CommandMapping command) { + LiteralArgumentBuilder base = literal(command.getPrimaryAlias()); + LinkedList> parameterStack = new LinkedList<>(); + LinkedList> optionalParameterStack = new LinkedList<>(); + boolean hasFlag = false; + for (Parameter parameter : command.getDescription().getParameters()) { + if (parameter.isValueFlag()) { + if (!hasFlag) { + hasFlag = true; + optionalParameterStack.push(argument("flags", StringArgumentType.string())); + } + } else if (parameter.isOptional()) { + optionalParameterStack.push(argument(parameter.getName(), StringArgumentType.string())); + } else { + parameterStack.push(argument(parameter.getName(), StringArgumentType.string())); + } + } - @Override - public String getName() { - return command.getPrimaryAlias(); - } - - @Override - public List getAliases() { - return Arrays.asList(command.getAllAliases()); - } - - @Override - public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { - } - - @Override - public String getUsage(ICommandSender icommandsender) { - return "/" + command.getPrimaryAlias() + " " + command.getDescription().getUsage(); - } - - @Override - public int getRequiredPermissionLevel() { - return 0; - } - - @Override - public boolean checkPermission(MinecraftServer server, ICommandSender sender) { - return true; - } - - @Override - public int compareTo(@Nullable ICommand o) { - if (o == null) { - return 0; + ArgumentBuilder argument = buildChildNodes(parameterStack, optionalParameterStack, command); + if (argument != null) { + base.then(argument); } else { - return super.compareTo(o); + base.executes(commandFor(command)); + } + LiteralCommandNode registered = + dispatcher.register( + base.requires(requirementsFor(command)) + ); + for (String alias : command.getAllAliases()) { + dispatcher.register( + literal(alias).redirect(registered) + ); } } + + /** + * Make the appropriate {@code then()} and {@code execute()} calls to emulate required and + * optional parameters, given the argument orders. + * + * @param parameterStack required parameters + * @param optionalParameterStack optional parameters + * @return the node with all calls chained + */ + private static ArgumentBuilder buildChildNodes(LinkedList> parameterStack, + LinkedList> optionalParameterStack, + CommandMapping mapping) { + ArgumentBuilder currentChild = null; + Command command = commandFor(mapping); + while (!optionalParameterStack.isEmpty()) { + ArgumentBuilder next = optionalParameterStack.removeLast(); + if (currentChild != null) { + next.then(currentChild.executes(command)); + } + currentChild = next; + } + boolean requiredExecute = false; + while (!parameterStack.isEmpty()) { + ArgumentBuilder next = parameterStack.removeLast(); + if (currentChild != null) { + next.then(currentChild); + } + if (!requiredExecute) { + // first required parameter also gets execute + requiredExecute = true; + next.executes(command); + } + currentChild = next; + } + return currentChild; + } + + private static Command commandFor(CommandMapping mapping) { + return ctx -> { + EntityPlayerMP player = ctx.getSource().asPlayer(); + if (player.world.isRemote()) { + return 0; + } + WorldEdit.getInstance().getEventBus().post(new CommandEvent( + adaptPlayer(player), + ctx.getRange().get(ctx.getInput()) + )); + return 1; + }; + } + + private static Predicate requirementsFor(CommandMapping mapping) { + return ctx -> { + ForgePermissionsProvider permsProvider = ForgeWorldEdit.inst.getPermissionsProvider(); + return ctx.getEntity() instanceof EntityPlayerMP && + mapping.getDescription().getPermissions().stream() + .allMatch(perm -> permsProvider.hasPermission( + (EntityPlayerMP) ctx.getEntity(), perm + )); + }; + } + } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java index 58aba645c..fe13ed7eb 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java @@ -40,6 +40,7 @@ import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -59,7 +60,9 @@ import java.util.Map; import java.util.TreeMap; import java.util.stream.Collectors; -final class ForgeAdapter { +import static com.google.common.base.Preconditions.checkNotNull; + +public final class ForgeAdapter { private ForgeAdapter() { } @@ -154,7 +157,7 @@ final class ForgeAdapter { private static IBlockState applyProperties(StateContainer stateContainer, IBlockState newState, Map, Object> states) { for (Map.Entry, Object> state : states.entrySet()) { - IProperty property = stateContainer.getProperty(state.getKey().getName()); + IProperty 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) { @@ -212,4 +215,15 @@ final class ForgeAdapter { CompoundTag tag = NBTConverter.fromNative(itemStack.serializeNBT()); 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 ForgePlayer adaptPlayer(EntityPlayerMP player) { + checkNotNull(player); + return new ForgePlayer(player); + } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java index 8f9011268..6129cb31b 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.forge; -import net.minecraft.command.ICommand; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.world.GameType; import net.minecraftforge.fml.server.ServerLifecycleHooks; @@ -28,7 +27,7 @@ public interface ForgePermissionsProvider { boolean hasPermission(EntityPlayerMP player, String permission); - void registerPermission(ICommand command, String permission); + void registerPermission(String permission); class VanillaPermissionsProvider implements ForgePermissionsProvider { @@ -47,7 +46,7 @@ public interface ForgePermissionsProvider { } @Override - public void registerPermission(ICommand command, String permission) {} + public void registerPermission(String permission) {} } // TODO Re-add when Sponge for 1.13 is out diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java index 4d83e1ded..0530acc54 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java @@ -29,7 +29,7 @@ import com.sk89q.worldedit.util.command.CommandMapping; import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; -import net.minecraft.command.ServerCommandManager; +import net.minecraft.command.Commands; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.server.MinecraftServer; import net.minecraft.server.management.PlayerList; @@ -37,14 +37,13 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.world.WorldServer; import net.minecraftforge.fml.server.ServerLifecycleHooks; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collection; import java.util.EnumMap; import java.util.List; import java.util.Map; -import javax.annotation.Nullable; - class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { private final ForgeWorldEdit mod; @@ -120,15 +119,13 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { @Override public void registerCommands(Dispatcher dispatcher) { if (server == null) return; - ServerCommandManager mcMan = (ServerCommandManager) server.getCommandManager(); + Commands mcMan = server.getCommandManager(); for (final CommandMapping command : dispatcher.getCommands()) { - CommandWrapper wrapper = new CommandWrapper(command); - mcMan.registerCommand(wrapper); + CommandWrapper.register(mcMan.getDispatcher(), command); if (command.getDescription().getPermissions().size() > 0) { - ForgeWorldEdit.inst.getPermissionsProvider().registerPermission(wrapper, command.getDescription().getPermissions().get(0)); for (int i = 1; i < command.getDescription().getPermissions().size(); i++) { - ForgeWorldEdit.inst.getPermissionsProvider().registerPermission(null, command.getDescription().getPermissions().get(i)); + ForgeWorldEdit.inst.getPermissionsProvider().registerPermission(command.getDescription().getPermissions().get(i)); } } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index 8b26c285f..985880a44 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.forge; import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer; import com.google.common.base.Joiner; import com.sk89q.worldedit.LocalSession; @@ -92,9 +93,6 @@ public class ForgeWorldEdit { inst = this; FMLJavaModLoadingContext.get().getModEventBus().addListener(this::init); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::serverAboutToStart); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::serverStopping); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::serverStarted); MinecraftForge.EVENT_BUS.register(ThreadSafeCache.getInstance()); MinecraftForge.EVENT_BUS.register(this); @@ -123,6 +121,7 @@ public class ForgeWorldEdit { LOGGER.info("WorldEdit for Forge (version " + getInternalVersion() + ") is loaded"); } + @SubscribeEvent public void serverAboutToStart(FMLServerAboutToStartEvent event) { if (this.platform != null) { LOGGER.warn("FMLServerStartingEvent occurred when FMLServerStoppingEvent hasn't"); @@ -165,29 +164,18 @@ public class ForgeWorldEdit { } } + @SubscribeEvent public void serverStopping(FMLServerStoppingEvent event) { WorldEdit worldEdit = WorldEdit.getInstance(); worldEdit.getSessionManager().unload(); worldEdit.getPlatformManager().unregister(platform); } + @SubscribeEvent public void serverStarted(FMLServerStartedEvent event) { WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); } - @SubscribeEvent - public void onCommandEvent(CommandEvent event) { - if ((event.getSender() instanceof EntityPlayerMP)) { - if (((EntityPlayerMP) event.getSender()).world.isRemote) return; - String[] split = new String[event.getParameters().length + 1]; - System.arraycopy(event.getParameters(), 0, split, 1, event.getParameters().length); - split[0] = event.getCommand().getName(); - com.sk89q.worldedit.event.platform.CommandEvent weEvent = - new com.sk89q.worldedit.event.platform.CommandEvent(wrap((EntityPlayerMP) event.getSender()), Joiner.on(" ").join(split)); - WorldEdit.getInstance().getEventBus().post(weEvent); - } - } - @SubscribeEvent public void onPlayerInteract(PlayerInteractEvent event) { if (platform == null) { @@ -215,7 +203,7 @@ public class ForgeWorldEdit { } WorldEdit we = WorldEdit.getInstance(); - ForgePlayer player = wrap((EntityPlayerMP) event.getEntityPlayer()); + ForgePlayer player = adaptPlayer((EntityPlayerMP) event.getEntityPlayer()); ForgeWorld world = getWorld(event.getEntityPlayer().world); if (event instanceof PlayerInteractEvent.LeftClickEmpty) { @@ -259,17 +247,6 @@ public class ForgeWorldEdit { return this.config; } - /** - * Get the WorldEdit proxy for the given player. - * - * @param player the player - * @return the WorldEdit player - */ - public ForgePlayer wrap(EntityPlayerMP player) { - checkNotNull(player); - return new ForgePlayer(player); - } - /** * Get the session for a player. * @@ -278,7 +255,7 @@ public class ForgeWorldEdit { */ public LocalSession getSession(EntityPlayerMP player) { checkNotNull(player); - return WorldEdit.getInstance().getSessionManager().get(wrap(player)); + return WorldEdit.getInstance().getSessionManager().get(adaptPlayer(player)); } /** diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java index 215e31526..c03218b01 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java @@ -32,6 +32,8 @@ import net.minecraftforge.fml.network.event.EventNetworkChannel; import java.nio.charset.Charset; +import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer; + public class WECUIPacketHandler { public static final Charset UTF_8_CHARSET = Charset.forName("UTF-8"); private static final String PROTOCOL_VERSION = Integer.toString(1); @@ -57,7 +59,7 @@ public class WECUIPacketHandler { String text = event.getPayload().toString(UTF_8_CHARSET); session.handleCUIInitializationMessage(text); - session.describeCUI(ForgeWorldEdit.inst.wrap(player)); + session.describeCUI(adaptPlayer(player)); } public static void callProcessPacket(NetworkEvent.ClientCustomPayloadEvent event) { diff --git a/worldedit-forge/src/main/resources/META-INF/mods.toml b/worldedit-forge/src/main/resources/META-INF/mods.toml index 9bb66bea4..c89f9c261 100644 --- a/worldedit-forge/src/main/resources/META-INF/mods.toml +++ b/worldedit-forge/src/main/resources/META-INF/mods.toml @@ -15,7 +15,7 @@ authors="sk89q, wizjany, TomyLobo, kenzierocks, Me4502" # The modid of the mod modId="worldedit" # The version number of the mod - there's a few well known ${} variables useable here or just hardcode it -version="${internalVersion}" +version="${version}" # A display name for the mod displayName="WorldEdit" # The description text for the mod (multi line!) @@ -23,11 +23,11 @@ description=''' WorldEdit is an easy-to-use in-game world editor for Minecraft, supporting both single- and multi-player. ''' [[dependencies.worldedit]] - modId="minecraft" + modId="forge" mandatory=true - versionRange="[1.13.2]" + versionRange="[${forge_version},)" ordering="NONE" - side="SERVER" + side="BOTH" [[dependencies.worldedit]] modId="sponge" mandatory=false diff --git a/worldedit-forge/src/main/resources/pack.mcmeta b/worldedit-forge/src/main/resources/pack.mcmeta new file mode 100644 index 000000000..b48da3b7d --- /dev/null +++ b/worldedit-forge/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "WorldEdit Resources", + "pack_format": 4 + } +} \ No newline at end of file From 4878f382500171d0837d7cacf457762f0cf0460b Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 4 Mar 2019 19:36:06 -0800 Subject: [PATCH 16/20] Fix platform registration, config setup --- .../world/registry/LegacyMapper.java | 3 ++ .../sk89q/worldedit/forge/ForgeAdapter.java | 4 +- .../sk89q/worldedit/forge/ForgeWorldEdit.java | 52 +++++++++++++++---- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java index e59cd762a..ad2eac4c0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java @@ -43,6 +43,8 @@ import java.util.logging.Logger; import javax.annotation.Nullable; +import static com.google.common.base.Preconditions.checkNotNull; + public class LegacyMapper { private static final Logger log = Logger.getLogger(LegacyMapper.class.getCanonicalName()); @@ -100,6 +102,7 @@ public class LegacyMapper { try { String id = itemEntry.getKey(); ItemType type = ItemTypes.get(itemEntry.getValue()); + checkNotNull(type); itemToStringMap.put(type, id); stringToItemMap.put(id, type); } catch (Exception e) { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java index fe13ed7eb..164ac65cf 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java @@ -134,8 +134,10 @@ public final class ForgeAdapter { .collect(Collectors.toList())); } if (property instanceof net.minecraft.state.EnumProperty) { + // Note: do not make x.getName a method reference. + // It will cause runtime bootstrap exceptions. return new EnumProperty(property.getName(), ((net.minecraft.state.EnumProperty) property).getAllowedValues().stream() - .map(IStringSerializable::getName) + .map(x -> x.getName()) .collect(Collectors.toList())); } return new IPropertyAdapter<>(property); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index 985880a44..60025a7ec 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -36,26 +36,34 @@ 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.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.tags.BlockTags; import net.minecraft.tags.ItemTags; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.CommandEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickEmpty; import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.SidedProvider; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.fml.loading.FMLCommonLaunchHandler; +import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.fml.loading.FMLPaths; import net.minecraftforge.registries.ForgeRegistries; import org.apache.logging.log4j.LogManager; @@ -92,13 +100,15 @@ public class ForgeWorldEdit { public ForgeWorldEdit() { inst = this; - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::init); + IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus(); + modBus.addListener(this::init); + modBus.addListener(this::load); MinecraftForge.EVENT_BUS.register(ThreadSafeCache.getInstance()); MinecraftForge.EVENT_BUS.register(this); } - public void init(FMLCommonSetupEvent event) { + private void init(FMLCommonSetupEvent event) { this.container = ModLoadingContext.get().getActiveContainer(); // Setup working directory @@ -111,9 +121,6 @@ public class ForgeWorldEdit { } } - config = new ForgeConfiguration(this); - config.load(); - WECUIPacketHandler.init(); InternalPacketHandler.init(); proxy.registerHandlers(); @@ -121,6 +128,14 @@ public class ForgeWorldEdit { LOGGER.info("WorldEdit for Forge (version " + getInternalVersion() + ") is loaded"); } + private void load(FMLLoadCompleteEvent event) { + if (FMLLoader.getDist() == Dist.CLIENT) { + // we want to setup platform before we hit the main menu + // but this event is async -- so we must delay until the first game loop: + Minecraft.getInstance().addScheduledTask(this::setupPlatform); + } + } + @SubscribeEvent public void serverAboutToStart(FMLServerAboutToStartEvent event) { if (this.platform != null) { @@ -128,6 +143,10 @@ public class ForgeWorldEdit { WorldEdit.getInstance().getPlatformManager().unregister(platform); } + setupPlatform(); + } + + private void setupPlatform() { this.platform = new ForgePlatform(this); WorldEdit.getInstance().getPlatformManager().register(platform); @@ -139,28 +158,41 @@ public class ForgeWorldEdit { // } setupRegistries(); + + config = new ForgeConfiguration(this); + config.load(); } private void setupRegistries() { // Blocks for (ResourceLocation name : ForgeRegistries.BLOCKS.getKeys()) { - BlockType.REGISTRY.register(name.toString(), new BlockType(name.toString(), + if (BlockType.REGISTRY.get(name.toString()) == null) { + BlockType.REGISTRY.register(name.toString(), new BlockType(name.toString(), input -> ForgeAdapter.adapt(ForgeAdapter.adapt(input.getBlockType()).getDefaultState()))); + } } // Items for (ResourceLocation name : ForgeRegistries.ITEMS.getKeys()) { - ItemType.REGISTRY.register(name.toString(), new ItemType(name.toString())); + if (ItemType.REGISTRY.get(name.toString()) == null) { + ItemType.REGISTRY.register(name.toString(), new ItemType(name.toString())); + } } // Entities for (ResourceLocation name : ForgeRegistries.ENTITIES.getKeys()) { - EntityType.REGISTRY.register(name.toString(), new EntityType(name.toString())); + if (EntityType.REGISTRY.get(name.toString()) == null) { + EntityType.REGISTRY.register(name.toString(), new EntityType(name.toString())); + } } // Tags for (ResourceLocation name : BlockTags.getCollection().getRegisteredTags()) { - BlockCategory.REGISTRY.register(name.toString(), new BlockCategory(name.toString())); + if (BlockCategory.REGISTRY.get(name.toString()) == null) { + BlockCategory.REGISTRY.register(name.toString(), new BlockCategory(name.toString())); + } } for (ResourceLocation name : ItemTags.getCollection().getRegisteredTags()) { - ItemCategory.REGISTRY.register(name.toString(), new ItemCategory(name.toString())); + if (ItemCategory.REGISTRY.get(name.toString()) == null) { + ItemCategory.REGISTRY.register(name.toString(), new ItemCategory(name.toString())); + } } } From bb33897221bed832bdfbc0d31853b19b709ae016 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 4 Mar 2019 19:57:22 -0800 Subject: [PATCH 17/20] Handle all commands like pre-1.13 for now --- .../sk89q/worldedit/forge/CommandWrapper.java | 22 +++++++++--------- .../sk89q/worldedit/forge/ForgeWorldEdit.java | 23 +++++++++++++++++++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java index cb1d051b4..b070d2a6c 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java @@ -24,6 +24,8 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.LiteralCommandNode; import com.sk89q.worldedit.WorldEdit; @@ -114,19 +116,17 @@ public class CommandWrapper { } private static Command commandFor(CommandMapping mapping) { - return ctx -> { - EntityPlayerMP player = ctx.getSource().asPlayer(); - if (player.world.isRemote()) { - return 0; - } - WorldEdit.getInstance().getEventBus().post(new CommandEvent( - adaptPlayer(player), - ctx.getRange().get(ctx.getInput()) - )); - return 1; - }; + return FAKE_COMMAND; } + public static final Command FAKE_COMMAND = ctx -> { + EntityPlayerMP player = ctx.getSource().asPlayer(); + if (player.world.isRemote()) { + return 0; + } + return 1; + }; + private static Predicate requirementsFor(CommandMapping mapping) { return ctx -> { ForgePermissionsProvider permsProvider = ForgeWorldEdit.inst.getPermissionsProvider(); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index 60025a7ec..b5a80a36b 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -23,6 +23,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer; import com.google.common.base.Joiner; +import com.mojang.brigadier.ParseResults; +import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.event.platform.PlatformReadyEvent; @@ -37,6 +39,7 @@ import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.item.ItemCategory; import com.sk89q.worldedit.world.item.ItemType; import net.minecraft.client.Minecraft; +import net.minecraft.command.CommandSource; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.tags.BlockTags; import net.minecraft.tags.ItemTags; @@ -270,6 +273,26 @@ public class ForgeWorldEdit { } } + @SubscribeEvent + public void onCommandEvent(CommandEvent event) throws CommandSyntaxException { + ParseResults parseResults = event.getParseResults(); + if (!(parseResults.getContext().getSource().getEntity() instanceof EntityPlayerMP)) { + return; + } + EntityPlayerMP player = parseResults.getContext().getSource().asPlayer(); + if (player.world.isRemote()) { + return; + } + if (parseResults.getContext().getCommand() != CommandWrapper.FAKE_COMMAND) { + return; + } + event.setCanceled(true); + WorldEdit.getInstance().getEventBus().post(new com.sk89q.worldedit.event.platform.CommandEvent( + adaptPlayer(parseResults.getContext().getSource().asPlayer()), + parseResults.getReader().getString() + )); + } + /** * Get the configuration. * From 6192ba8dc16beee21a3d4b00f99c7ce590a7ee2f Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 11 Mar 2019 00:02:51 -0400 Subject: [PATCH 18/20] Checkstyle fixes and warnings. Should get 'working' builds now. --- config/checkstyle/checkstyle.xml | 3 ++- config/checkstyle/import-control.xml | 1 + .../sk89q/worldedit/forge/CommandWrapper.java | 10 +++------- .../worldedit/forge/gui/GuiReferenceCard.java | 7 ++++--- .../net/handler/InternalPacketHandler.java | 15 +++++++++------ .../forge/net/handler/WECUIPacketHandler.java | 18 +++++++++++------- .../net/packet/LeftClickAirEventMessage.java | 14 +++++++------- 7 files changed, 37 insertions(+), 31 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 7872f45bc..a2d043d73 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -5,8 +5,9 @@ - + + diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index eedd07857..9cc735070 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -53,6 +53,7 @@ + diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java index b070d2a6c..6089040be 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java @@ -24,12 +24,7 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.LiteralCommandNode; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.util.command.CommandMapping; import com.sk89q.worldedit.util.command.Parameter; import net.minecraft.command.CommandSource; @@ -38,11 +33,12 @@ import net.minecraft.entity.player.EntityPlayerMP; import java.util.LinkedList; import java.util.function.Predicate; -import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer; import static net.minecraft.command.Commands.argument; import static net.minecraft.command.Commands.literal; -public class CommandWrapper { +public final class CommandWrapper { + private CommandWrapper() { + } public static void register(CommandDispatcher dispatcher, CommandMapping command) { LiteralArgumentBuilder base = literal(command.getPrimaryAlias()); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java index 23e0bb90c..d15642934 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java @@ -33,10 +33,11 @@ public class GuiReferenceCard extends GuiScreen { @Override public void initGui() { - this.closeButton = new GuiButton(0, (this.width - this.backgroundWidth + 100) / 2, (this.height + this.backgroundHeight - 60) / 2, this.backgroundWidth - 100, 20, "Close") { + this.closeButton = new GuiButton(0, (this.width - this.backgroundWidth + 100) / 2, + (this.height + this.backgroundHeight - 60) / 2, this.backgroundWidth - 100, 20, "Close") { @Override - public void onClick(double p_194829_1_, double p_194829_3_) { - super.onClick(p_194829_1_, p_194829_3_); + public void onClick(double mouseX, double mouseY) { + super.onClick(mouseX, mouseY); mc.player.closeScreen(); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/InternalPacketHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/InternalPacketHandler.java index 5af96dd61..17b81a852 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/InternalPacketHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/InternalPacketHandler.java @@ -21,22 +21,25 @@ package com.sk89q.worldedit.forge.net.handler; import com.sk89q.worldedit.forge.ForgeWorldEdit; import com.sk89q.worldedit.forge.net.packet.LeftClickAirEventMessage; +import com.sk89q.worldedit.forge.net.packet.LeftClickAirEventMessage.Handler; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.network.NetworkRegistry; +import net.minecraftforge.fml.network.NetworkRegistry.ChannelBuilder; import net.minecraftforge.fml.network.simple.SimpleChannel; -public class InternalPacketHandler { +public final class InternalPacketHandler { private static final String PROTOCOL_VERSION = Integer.toString(1); - public static SimpleChannel HANDLER = NetworkRegistry.ChannelBuilder + public static SimpleChannel HANDLER = ChannelBuilder .named(new ResourceLocation(ForgeWorldEdit.MOD_ID, "internal")) .clientAcceptedVersions(PROTOCOL_VERSION::equals) .serverAcceptedVersions(PROTOCOL_VERSION::equals) .networkProtocolVersion(() -> PROTOCOL_VERSION) .simpleChannel(); - public static void init() { - int disc = 0; + private InternalPacketHandler() { + } - HANDLER.registerMessage(disc++, LeftClickAirEventMessage.class, LeftClickAirEventMessage::encode, LeftClickAirEventMessage::decode, LeftClickAirEventMessage.Handler::handle); + public static void init() { + HANDLER.registerMessage(0, LeftClickAirEventMessage.class, + LeftClickAirEventMessage::encode, LeftClickAirEventMessage::decode, Handler::handle); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java index c03218b01..541577e1f 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java @@ -26,18 +26,22 @@ import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.network.ThreadQuickExitException; import net.minecraft.network.play.server.SPacketCustomPayload; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.network.NetworkEvent; -import net.minecraftforge.fml.network.NetworkRegistry; +import net.minecraftforge.fml.network.NetworkEvent.ClientCustomPayloadEvent; +import net.minecraftforge.fml.network.NetworkEvent.ServerCustomPayloadEvent; +import net.minecraftforge.fml.network.NetworkRegistry.ChannelBuilder; import net.minecraftforge.fml.network.event.EventNetworkChannel; import java.nio.charset.Charset; import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer; -public class WECUIPacketHandler { +public final class WECUIPacketHandler { + private WECUIPacketHandler() { + } + public static final Charset UTF_8_CHARSET = Charset.forName("UTF-8"); private static final String PROTOCOL_VERSION = Integer.toString(1); - public static EventNetworkChannel HANDLER = NetworkRegistry.ChannelBuilder + public static EventNetworkChannel HANDLER = ChannelBuilder .named(new ResourceLocation(ForgeWorldEdit.MOD_ID, ForgeWorldEdit.CUI_PLUGIN_CHANNEL)) .clientAcceptedVersions(PROTOCOL_VERSION::equals) .serverAcceptedVersions(PROTOCOL_VERSION::equals) @@ -49,7 +53,7 @@ public class WECUIPacketHandler { HANDLER.addListener(WECUIPacketHandler::callProcessPacket); } - public static void onPacketData(NetworkEvent.ServerCustomPayloadEvent event) { + public static void onPacketData(ServerCustomPayloadEvent event) { EntityPlayerMP player = event.getSource().get().getSender(); LocalSession session = ForgeWorldEdit.inst.getSession(player); @@ -62,13 +66,13 @@ public class WECUIPacketHandler { session.describeCUI(adaptPlayer(player)); } - public static void callProcessPacket(NetworkEvent.ClientCustomPayloadEvent event) { + public static void callProcessPacket(ClientCustomPayloadEvent event) { try { new SPacketCustomPayload( new ResourceLocation(ForgeWorldEdit.MOD_ID, ForgeWorldEdit.CUI_PLUGIN_CHANNEL), event.getPayload() ).processPacket(Minecraft.getInstance().player.connection); - } catch (ThreadQuickExitException suppress) { + } catch (ThreadQuickExitException ignored) { } } } \ No newline at end of file diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/packet/LeftClickAirEventMessage.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/packet/LeftClickAirEventMessage.java index 9d983848c..e5e5d8cdc 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/packet/LeftClickAirEventMessage.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/packet/LeftClickAirEventMessage.java @@ -22,20 +22,20 @@ package com.sk89q.worldedit.forge.net.packet; import com.sk89q.worldedit.forge.ForgeWorldEdit; import io.netty.buffer.ByteBuf; import net.minecraft.network.PacketBuffer; -import net.minecraftforge.event.entity.player.PlayerInteractEvent; -import net.minecraftforge.fml.network.NetworkEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickEmpty; +import net.minecraftforge.fml.network.NetworkEvent.Context; +import java.util.Objects; import java.util.function.Supplier; +@SuppressWarnings({"NonFinalUtilityClass", "checkstyle:hideutilityclassconstructor"}) public class LeftClickAirEventMessage { public static final class Handler { - - public static void handle(final LeftClickAirEventMessage message, Supplier ctx) { - NetworkEvent.Context context = ctx.get(); - context.enqueueWork(() -> ForgeWorldEdit.inst.onPlayerInteract(new PlayerInteractEvent.LeftClickEmpty(context.getSender()))); + public static void handle(final LeftClickAirEventMessage message, Supplier ctx) { + Context context = ctx.get(); + context.enqueueWork(() -> ForgeWorldEdit.inst.onPlayerInteract(new LeftClickEmpty(Objects.requireNonNull(context.getSender())))); } - } public static LeftClickAirEventMessage decode(ByteBuf buf) { From a59d994d84fde12763bbed88fb11bbf2de8780db Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 11 Mar 2019 00:15:21 -0400 Subject: [PATCH 19/20] Hook up the biome registry. --- .../com/sk89q/worldedit/world/registry/legacy.json | 2 +- .../java/com/sk89q/worldedit/forge/ForgeWorldEdit.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/legacy.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/legacy.json index 4bc2907a2..ec4c09040 100644 --- a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/legacy.json +++ b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/legacy.json @@ -1785,7 +1785,7 @@ "48:0": "minecraft:mossy_cobblestone", "49:0": "minecraft:obsidian", "50:0": "minecraft:torch", - "52:0": "minecraft:mob_spawner", + "52:0": "minecraft:spawner", "53:0": "minecraft:oak_stairs", "54:0": "minecraft:chest", "56:0": "minecraft:diamond_ore", diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index b5a80a36b..9793c6381 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -33,6 +33,7 @@ import com.sk89q.worldedit.forge.net.handler.InternalPacketHandler; import com.sk89q.worldedit.forge.net.handler.WECUIPacketHandler; import com.sk89q.worldedit.forge.net.packet.LeftClickAirEventMessage; 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; @@ -186,6 +187,12 @@ public class ForgeWorldEdit { EntityType.REGISTRY.register(name.toString(), new EntityType(name.toString())); } } + // Biomes + for (ResourceLocation name : ForgeRegistries.BIOMES.getKeys()) { + if (BiomeType.REGISTRY.get(name.toString()) == null) { + BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString())); + } + } // Tags for (ResourceLocation name : BlockTags.getCollection().getRegisteredTags()) { if (BlockCategory.REGISTRY.get(name.toString()) == null) { From 6e24472af5053b1245f4b367b9eb51c1ad851cc3 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 11 Mar 2019 22:45:41 +1000 Subject: [PATCH 20/20] Bump to latest forge and cleanup some old files. --- .travis.yml | 1 - worldedit-forge/build.gradle | 4 +- worldedit-forge/src/main/ant/build.xml | 150 ------------------ .../sk89q/worldedit/forge/ForgeWorldEdit.java | 4 - 4 files changed, 2 insertions(+), 157 deletions(-) delete mode 100644 worldedit-forge/src/main/ant/build.xml diff --git a/.travis.yml b/.travis.yml index f8b8492f7..1c581a696 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: java notifications: email: false before_install: chmod +x gradlew -install: ./gradlew setupCIWorkspace -s script: ./gradlew build -s jdk: - oraclejdk8 diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 536739a5c..e9dff30ae 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -14,7 +14,7 @@ buildscript { apply plugin: 'net.minecraftforge.gradle' def minecraftVersion = "1.13.2" -def forgeVersion = "25.0.70" +def forgeVersion = "25.0.76" dependencies { compile project(':worldedit-core') @@ -28,7 +28,7 @@ sourceCompatibility = 1.8 targetCompatibility = 1.8 minecraft { - mappings channel: 'snapshot', version: '20190217-1.13.1' + mappings channel: 'snapshot', version: '20190311-1.13.2' runs { client = { diff --git a/worldedit-forge/src/main/ant/build.xml b/worldedit-forge/src/main/ant/build.xml deleted file mode 100644 index 5753b52ce..000000000 --- a/worldedit-forge/src/main/ant/build.xml +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index 9793c6381..07bf6c4d9 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -22,7 +22,6 @@ package com.sk89q.worldedit.forge; import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer; -import com.google.common.base.Joiner; import com.mojang.brigadier.ParseResults; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.sk89q.worldedit.LocalSession; @@ -57,16 +56,13 @@ import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.SidedProvider; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.fml.loading.FMLCommonLaunchHandler; import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.fml.loading.FMLPaths; import net.minecraftforge.registries.ForgeRegistries;