{"action":"created","comment":{"url":"https://api.github.com/repos/EngineHub/WorldEdit/pulls/comments/297173490","pull_request_review_id":253985144,"id":297173490,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDI5NzE3MzQ5MA==","diff_hunk":"@@ -0,0 +1,593 @@\n+/*\n+ * WorldEdit, a Minecraft world manipulation toolkit\n+ * Copyright (C) sk89q <http://www.sk89q.com>\n+ * Copyright (C) WorldEdit team and contributors\n+ *\n+ * This program is free software: you can redistribute it and/or modify it\n+ * under the terms of the GNU Lesser General Public License as published by the\n+ * Free Software Foundation, either version 3 of the License, or\n+ * (at your option) any later version.\n+ *\n+ * This program is distributed in the hope that it will be useful, but WITHOUT\n+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\n+ * for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public License\n+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\n+ */\n+\n+package com.sk89q.worldedit.fabric;\n+\n+import static com.google.common.base.Preconditions.checkNotNull;\n+\n+import com.google.common.cache.CacheBuilder;\n+import com.google.common.cache.CacheLoader;\n+import com.google.common.cache.LoadingCache;\n+import com.google.common.io.Files;\n+import com.sk89q.jnbt.CompoundTag;\n+import com.sk89q.worldedit.EditSession;\n+import com.sk89q.worldedit.MaxChangedBlocksException;\n+import com.sk89q.worldedit.WorldEditException;\n+import com.sk89q.worldedit.blocks.BaseItem;\n+import com.sk89q.worldedit.blocks.BaseItemStack;\n+import com.sk89q.worldedit.entity.BaseEntity;\n+import com.sk89q.worldedit.entity.Entity;\n+import com.sk89q.worldedit.internal.Constants;\n+import com.sk89q.worldedit.internal.block.BlockStateIdAccess;\n+import com.sk89q.worldedit.math.BlockVector2;\n+import com.sk89q.worldedit.math.BlockVector3;\n+import com.sk89q.worldedit.math.Vector3;\n+import com.sk89q.worldedit.regions.CuboidRegion;\n+import com.sk89q.worldedit.regions.Region;\n+import com.sk89q.worldedit.util.Direction;\n+import com.sk89q.worldedit.util.Location;\n+import com.sk89q.worldedit.util.TreeGenerator.TreeType;\n+import com.sk89q.worldedit.world.AbstractWorld;\n+import com.sk89q.worldedit.world.biome.BiomeType;\n+import com.sk89q.worldedit.world.block.BaseBlock;\n+import com.sk89q.worldedit.world.block.BlockState;\n+import com.sk89q.worldedit.world.block.BlockStateHolder;\n+import com.sk89q.worldedit.world.item.ItemTypes;\n+import com.sk89q.worldedit.world.weather.WeatherType;\n+import com.sk89q.worldedit.world.weather.WeatherTypes;\n+import net.minecraft.block.Block;\n+import net.minecraft.block.Blocks;\n+import net.minecraft.block.LeavesBlock;\n+import net.minecraft.block.entity.BlockEntity;\n+import net.minecraft.entity.EntityType;\n+import net.minecraft.entity.ItemEntity;\n+import net.minecraft.inventory.Inventory;\n+import net.minecraft.item.ItemStack;\n+import net.minecraft.item.ItemUsageContext;\n+import net.minecraft.server.MinecraftServer;\n+import net.minecraft.server.WorldGenerationProgressListener;\n+import net.minecraft.server.world.ServerChunkManager;\n+import net.minecraft.server.world.ServerWorld;\n+import net.minecraft.util.ActionResult;\n+import net.minecraft.util.Hand;\n+import net.minecraft.util.hit.BlockHitResult;\n+import net.minecraft.util.math.BlockPos;\n+import net.minecraft.util.math.ChunkPos;\n+import net.minecraft.world.World;\n+import net.minecraft.world.WorldSaveHandler;\n+import net.minecraft.world.chunk.Chunk;\n+import net.minecraft.world.chunk.ChunkManager;\n+import net.minecraft.world.chunk.ChunkStatus;\n+import net.minecraft.world.chunk.WorldChunk;\n+import net.minecraft.world.gen.feature.BirchTreeFeature;\n+import net.minecraft.world.gen.feature.DarkOakTreeFeature;\n+import net.minecraft.world.gen.feature.DefaultFeatureConfig;\n+import net.minecraft.world.gen.feature.Feature;\n+import net.minecraft.world.gen.feature.FeatureConfig;\n+import net.minecraft.world.gen.feature.HugeBrownMushroomFeature;\n+import net.minecraft.world.gen.feature.HugeRedMushroomFeature;\n+import net.minecraft.world.gen.feature.JungleGroundBushFeature;\n+import net.minecraft.world.gen.feature.JungleTreeFeature;\n+import net.minecraft.world.gen.feature.LargeOakTreeFeature;\n+import net.minecraft.world.gen.feature.MegaJungleTreeFeature;\n+import net.minecraft.world.gen.feature.MegaPineTreeFeature;\n+import net.minecraft.world.gen.feature.OakTreeFeature;\n+import net.minecraft.world.gen.feature.PineTreeFeature;\n+import net.minecraft.world.gen.feature.PlantedFeatureConfig;\n+import net.minecraft.world.gen.feature.SavannaTreeFeature;\n+import net.minecraft.world.gen.feature.SpruceTreeFeature;\n+import net.minecraft.world.gen.feature.SwampTreeFeature;\n+import net.minecraft.world.level.LevelProperties;\n+\n+import java.io.File;\n+import java.lang.ref.WeakReference;\n+import java.util.Collections;\n+import java.util.List;\n+import java.util.Optional;\n+import java.util.OptionalInt;\n+import java.util.Random;\n+import java.util.concurrent.ExecutionException;\n+import java.util.concurrent.ThreadLocalRandom;\n+import java.util.stream.Collectors;\n+\n+import javax.annotation.Nullable;\n+\n+/**\n+ * An adapter to Minecraft worlds for WorldEdit.\n+ */\n+public class FabricWorld extends AbstractWorld {\n+\n+    private static final Random random = new Random();\n+    private static final int UPDATE = 1, NOTIFY = 2;\n+\n+    private static final net.minecraft.block.BlockState JUNGLE_LOG = Blocks.JUNGLE_LOG.getDefaultState();\n+    private static final net.minecraft.block.BlockState JUNGLE_LEAF = Blocks.JUNGLE_LEAVES.getDefaultState().with(LeavesBlock.PERSISTENT, Boolean.TRUE);\n+    private static final net.minecraft.block.BlockState JUNGLE_SHRUB = Blocks.OAK_LEAVES.getDefaultState().with(LeavesBlock.PERSISTENT, Boolean.TRUE);\n+\n+    private final WeakReference<World> worldRef;\n+\n+    /**\n+     * Construct a new world.\n+     *\n+     * @param world the world\n+     */\n+    FabricWorld(World world) {\n+        checkNotNull(world);\n+        this.worldRef = new WeakReference<>(world);\n+    }\n+\n+    /**\n+     * Get the underlying handle to the world.\n+     *\n+     * @return the world\n+     * @throws WorldEditException thrown if a reference to the world was lost (i.e. world was unloaded)\n+     */\n+    public World getWorldChecked() throws WorldEditException {\n+        World world = worldRef.get();\n+        if (world != null) {\n+            return world;\n+        } else {\n+            throw new WorldReferenceLostException(\"The reference to the world was lost (i.e. the world may have been unloaded)\");\n+        }\n+    }\n+\n+    /**\n+     * Get the underlying handle to the world.\n+     *\n+     * @return the world\n+     * @throws RuntimeException thrown if a reference to the world was lost (i.e. world was unloaded)\n+     */\n+    public World getWorld() {\n+        World world = worldRef.get();\n+        if (world != null) {\n+            return world;\n+        } else {\n+            throw new RuntimeException(\"The reference to the world was lost (i.e. the world may have been unloaded)\");\n+        }\n+    }\n+\n+    @Override\n+    public String getName() {\n+        return getWorld().getLevelProperties().getLevelName();\n+    }\n+\n+    @Override\n+    public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException {\n+        checkNotNull(position);\n+        checkNotNull(block);\n+\n+        World world = getWorldChecked();\n+        int x = position.getBlockX();\n+        int y = position.getBlockY();\n+        int z = position.getBlockZ();\n+\n+        // First set the block\n+        Chunk chunk = world.getChunk(x >> 4, z >> 4);\n+        BlockPos pos = new BlockPos(x, y, z);\n+        net.minecraft.block.BlockState old = chunk.getBlockState(pos);\n+        OptionalInt stateId = BlockStateIdAccess.getBlockStateId(block.toImmutableState());\n+        net.minecraft.block.BlockState newState = stateId.isPresent() ? Block.getStateFromRawId(stateId.getAsInt()) : FabricAdapter.adapt(block.toImmutableState());\n+        net.minecraft.block.BlockState successState = chunk.setBlockState(pos, newState, false);\n+        boolean successful = successState != null;\n+\n+        // Create the TileEntity\n+        if (successful || old == newState) {\n+            if (block instanceof BaseBlock) {\n+                CompoundTag tag = ((BaseBlock) block).getNbtData();\n+                if (tag != null) {\n+                    net.minecraft.nbt.CompoundTag nativeTag = NBTConverter.toNative(tag);\n+                    nativeTag.putString(\"id\", ((BaseBlock) block).getNbtId());\n+                    TileEntityUtils.setTileEntity(world, position, nativeTag);\n+                    successful = true; // update if TE changed as well\n+                }\n+            }\n+        }\n+\n+        if (successful && notifyAndLight) {\n+            world.getChunkManager().getLightingProvider().enqueueLightUpdate(pos);\n+            world.updateListeners(pos, old, newState, UPDATE | NOTIFY);\n+        }\n+\n+        return successful;\n+    }\n+\n+    @Override\n+    public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {\n+        BlockPos pos = new BlockPos(position.getX(), position.getY(), position.getZ());\n+        getWorld().updateListeners(pos, FabricAdapter.adapt(previousType), getWorld().getBlockState(pos), 1 | 2);\n+        return true;\n+    }\n+\n+    @Override\n+    public int getBlockLightLevel(BlockVector3 position) {\n+        checkNotNull(position);\n+        return getWorld().getLightLevel(FabricAdapter.toBlockPos(position));\n+    }\n+\n+    @Override\n+    public boolean clearContainerBlockContents(BlockVector3 position) {\n+        checkNotNull(position);\n+        BlockEntity tile = getWorld().getBlockEntity(FabricAdapter.toBlockPos(position));\n+        if ((tile instanceof Inventory)) {\n+            Inventory inv = (Inventory) tile;\n+            int size = inv.getInvSize();\n+            for (int i = 0; i < size; i++) {\n+                inv.setInvStack(i, ItemStack.EMPTY);\n+            }\n+            return true;\n+        }\n+        return false;\n+    }\n+\n+    @Override\n+    public BiomeType getBiome(BlockVector2 position) {\n+        checkNotNull(position);\n+        return FabricAdapter.adapt(getWorld().getBiome(new BlockPos(position.getBlockX(), 0, position.getBlockZ())));\n+    }\n+\n+    @Override\n+    public boolean setBiome(BlockVector2 position, BiomeType biome) {\n+        checkNotNull(position);\n+        checkNotNull(biome);\n+\n+        Chunk chunk = getWorld().getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4, ChunkStatus.FULL, false);\n+        if (chunk == null) {\n+            return false;\n+        }\n+        chunk.getBiomeArray()[((position.getBlockZ() & 0xF) << 4 | position.getBlockX() & 0xF)] = FabricAdapter.adapt(biome);\n+        return true;\n+    }\n+\n+    private static LoadingCache<ServerWorld, WorldEditFakePlayer> fakePlayers\n+            = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(WorldEditFakePlayer::new));\n+\n+    @Override\n+    public boolean useItem(BlockVector3 position, BaseItem item, Direction face) {\n+        ItemStack stack = FabricAdapter.adapt(new BaseItemStack(item.getType(), item.getNbtData(), 1));\n+        ServerWorld world = (ServerWorld) getWorld();\n+        final WorldEditFakePlayer fakePlayer;\n+        try {\n+            fakePlayer = fakePlayers.get(world);\n+        } catch (ExecutionException ignored) {\n+            return false;\n+        }\n+        fakePlayer.setStackInHand(Hand.MAIN_HAND, stack);\n+        fakePlayer.setPositionAndAngles(position.getBlockX(), position.getBlockY(), position.getBlockZ(),\n+                (float) face.toVector().toYaw(), (float) face.toVector().toPitch());\n+        final BlockPos blockPos = FabricAdapter.toBlockPos(position);\n+        final BlockHitResult rayTraceResult = new BlockHitResult(FabricAdapter.toVec3(position),\n+                FabricAdapter.adapt(face), blockPos, false);\n+        ItemUsageContext itemUseContext = new ItemUsageContext(fakePlayer, Hand.MAIN_HAND, rayTraceResult);\n+        ActionResult used = stack.useOnBlock(itemUseContext);\n+        if (used != ActionResult.SUCCESS) {\n+            // try activating the block\n+            if (getWorld().getBlockState(blockPos).activate(world, fakePlayer, Hand.MAIN_HAND, rayTraceResult)) {\n+                used = ActionResult.SUCCESS;\n+            } else {\n+                used = stack.getItem().use(world, fakePlayer, Hand.MAIN_HAND).getResult();\n+            }\n+        }\n+        return used == ActionResult.SUCCESS;\n+    }\n+\n+    @Override\n+    public void dropItem(Vector3 position, BaseItemStack item) {\n+        checkNotNull(position);\n+        checkNotNull(item);\n+\n+        if (item.getType() == ItemTypes.AIR) {\n+            return;\n+        }\n+\n+        ItemEntity entity = new ItemEntity(getWorld(), position.getX(), position.getY(), position.getZ(), FabricAdapter.adapt(item));\n+        entity.setPickupDelay(10);\n+        getWorld().spawnEntity(entity);\n+    }\n+\n+    @Override\n+    public void simulateBlockMine(BlockVector3 position) {\n+        BlockPos pos = FabricAdapter.toBlockPos(position);\n+        getWorld().breakBlock(pos, true);\n+    }\n+\n+    @Override\n+    public boolean regenerate(Region region, EditSession editSession) {\n+        // Don't even try to regen if it's going to fail.\n+        ChunkManager provider = getWorld().getChunkManager();\n+        if (!(provider instanceof ServerChunkManager)) {\n+            return false;\n+        }\n+\n+        File saveFolder = Files.createTempDir();\n+        // register this just in case something goes wrong\n+        // normally it should be deleted at the end of this method\n+        saveFolder.deleteOnExit();\n+        try {\n+            ServerWorld originalWorld = (ServerWorld) getWorld();\n+\n+            MinecraftServer server = originalWorld.getServer();\n+            WorldSaveHandler saveHandler = new WorldSaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDir().getName(), server, server.getDataFixer());\n+            World freshWorld = new ServerWorld(server, server.getWorkerExecutor(), saveHandler, originalWorld.getLevelProperties(),\n+                    originalWorld.dimension.getType(), originalWorld.getProfiler(), new NoOpChunkStatusListener());\n+\n+            // Pre-gen all the chunks\n+            // We need to also pull one more chunk in every direction\n+            CuboidRegion expandedPreGen = new CuboidRegion(region.getMinimumPoint().subtract(16, 0, 16), region.getMaximumPoint().add(16, 0, 16));\n+            for (BlockVector2 chunk : expandedPreGen.getChunks()) {\n+                freshWorld.getChunk(chunk.getBlockX(), chunk.getBlockZ());\n+            }\n+\n+            FabricWorld from = new FabricWorld(freshWorld);\n+            for (BlockVector3 vec : region) {\n+                editSession.setBlock(vec, from.getFullBlock(vec));\n+            }\n+        } catch (MaxChangedBlocksException e) {\n+            throw new RuntimeException(e);\n+        } finally {\n+            saveFolder.delete();\n+        }\n+\n+        return true;\n+    }\n+\n+    @Nullable\n+    private static Feature<? extends FeatureConfig> createTreeFeatureGenerator(TreeType type) {\n+        switch (type) {\n+            case TREE: return new OakTreeFeature(DefaultFeatureConfig::deserialize, true);\n+            case BIG_TREE: return new LargeOakTreeFeature(DefaultFeatureConfig::deserialize, true);\n+            case REDWOOD: return new PineTreeFeature(DefaultFeatureConfig::deserialize);\n+            case TALL_REDWOOD: return new SpruceTreeFeature(DefaultFeatureConfig::deserialize, true);\n+            case BIRCH: return new BirchTreeFeature(DefaultFeatureConfig::deserialize, true, false);\n+            case JUNGLE: return new MegaJungleTreeFeature(DefaultFeatureConfig::deserialize, true, 10, 20, JUNGLE_LOG, JUNGLE_LEAF);\n+            case SMALL_JUNGLE: return new JungleTreeFeature(DefaultFeatureConfig::deserialize, true, 4 + random.nextInt(7), JUNGLE_LOG, JUNGLE_LEAF, false);\n+            case SHORT_JUNGLE: return new JungleTreeFeature(DefaultFeatureConfig::deserialize, true, 4 + random.nextInt(7), JUNGLE_LOG, JUNGLE_LEAF, true);\n+            case JUNGLE_BUSH: return new JungleGroundBushFeature(DefaultFeatureConfig::deserialize, JUNGLE_LOG, JUNGLE_SHRUB);\n+            case SWAMP: return new SwampTreeFeature(DefaultFeatureConfig::deserialize);\n+            case ACACIA: return new SavannaTreeFeature(DefaultFeatureConfig::deserialize, true);\n+            case DARK_OAK: return new DarkOakTreeFeature(DefaultFeatureConfig::deserialize, true);\n+            case MEGA_REDWOOD: return new MegaPineTreeFeature(DefaultFeatureConfig::deserialize, true, random.nextBoolean());\n+            case TALL_BIRCH: return new BirchTreeFeature(DefaultFeatureConfig::deserialize, true, true);\n+            case RED_MUSHROOM: return new HugeRedMushroomFeature(PlantedFeatureConfig::deserialize);\n+            case BROWN_MUSHROOM: return new HugeBrownMushroomFeature(PlantedFeatureConfig::deserialize);\n+            case RANDOM: return createTreeFeatureGenerator(TreeType.values()[ThreadLocalRandom.current().nextInt(TreeType.values().length)]);\n+            default:\n+                return null;\n+        }\n+    }\n+\n+    private FeatureConfig createFeatureConfig(TreeType type) {\n+        if (type == TreeType.RED_MUSHROOM || type == TreeType.BROWN_MUSHROOM) {\n+            return new PlantedFeatureConfig(true);\n+        } else {\n+            return new DefaultFeatureConfig();\n+        }\n+    }\n+\n+    @Override\n+    public boolean generateTree(TreeType type, EditSession editSession, BlockVector3 position) throws MaxChangedBlocksException {\n+        @SuppressWarnings(\"unchecked\")\n+        Feature<FeatureConfig> generator = (Feature<FeatureConfig>) createTreeFeatureGenerator(type);\n+        return generator != null\n+                && generator.generate(getWorld(), getWorld().getChunkManager().getChunkGenerator(), random,\n+                FabricAdapter.toBlockPos(position), createFeatureConfig(type));\n+    }\n+\n+    @Override\n+    public void checkLoadedChunk(BlockVector3 pt) {\n+        getWorld().getChunk(FabricAdapter.toBlockPos(pt));\n+    }\n+\n+    @Override\n+    public void fixAfterFastMode(Iterable<BlockVector2> chunks) {\n+        fixLighting(chunks);\n+    }\n+\n+    @Override\n+    public void fixLighting(Iterable<BlockVector2> chunks) {\n+        World world = getWorld();\n+        for (BlockVector2 chunk : chunks) {\n+            world.getChunkManager().getLightingProvider().suppressLight(new ChunkPos(chunk.getBlockX(), chunk.getBlockZ()), true);","path":"worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java","position":411,"original_position":405,"commit_id":"b4ea6cc2b205d2539aea3b48af9c2ffdb2fd6f7c","original_commit_id":"c693933139c4240686d9df4d1a96df105fdbe442","user":{"login":"me4502","id":546754,"node_id":"MDQ6VXNlcjU0Njc1NA==","avatar_url":"https://avatars1.githubusercontent.com/u/546754?v=4","gravatar_id":"","url":"https://api.github.com/users/me4502","html_url":"https://github.com/me4502","followers_url":"https://api.github.com/users/me4502/followers","following_url":"https://api.github.com/users/me4502/following{/other_user}","gists_url":"https://api.github.com/users/me4502/gists{/gist_id}","starred_url":"https://api.github.com/users/me4502/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/me4502/subscriptions","organizations_url":"https://api.github.com/users/me4502/orgs","repos_url":"https://api.github.com/users/me4502/repos","events_url":"https://api.github.com/users/me4502/events{/privacy}","received_events_url":"https://api.github.com/users/me4502/received_events","type":"User","site_admin":false},"body":"Yeah, it's what the other platforms use. Will look into it sometime.","created_at":"2019-06-25T12:58:53Z","updated_at":"2019-06-25T12:58:53Z","html_url":"https://github.com/EngineHub/WorldEdit/pull/491#discussion_r297173490","pull_request_url":"https://api.github.com/repos/EngineHub/WorldEdit/pulls/491","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/EngineHub/WorldEdit/pulls/comments/297173490"},"html":{"href":"https://github.com/EngineHub/WorldEdit/pull/491#discussion_r297173490"},"pull_request":{"href":"https://api.github.com/repos/EngineHub/WorldEdit/pulls/491"}},"in_reply_to_id":296986235},"pull_request":{"url":"https://api.github.com/repos/EngineHub/WorldEdit/pulls/491","id":291035947,"node_id":"MDExOlB1bGxSZXF1ZXN0MjkxMDM1OTQ3","html_url":"https://github.com/EngineHub/WorldEdit/pull/491","diff_url":"https://github.com/EngineHub/WorldEdit/pull/491.diff","patch_url":"https://github.com/EngineHub/WorldEdit/pull/491.patch","issue_url":"https://api.github.com/repos/EngineHub/WorldEdit/issues/491","number":491,"state":"open","locked":false,"title":"feature(fabric): added fabric support","user":{"login":"me4502","id":546754,"node_id":"MDQ6VXNlcjU0Njc1NA==","avatar_url":"https://avatars1.githubusercontent.com/u/546754?v=4","gravatar_id":"","url":"https://api.github.com/users/me4502","html_url":"https://github.com/me4502","followers_url":"https://api.github.com/users/me4502/followers","following_url":"https://api.github.com/users/me4502/following{/other_user}","gists_url":"https://api.github.com/users/me4502/gists{/gist_id}","starred_url":"https://api.github.com/users/me4502/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/me4502/subscriptions","organizations_url":"https://api.github.com/users/me4502/orgs","repos_url":"https://api.github.com/users/me4502/repos","events_url":"https://api.github.com/users/me4502/events{/privacy}","received_events_url":"https://api.github.com/users/me4502/received_events","type":"User","site_admin":false},"body":"All the basics work, left click air messaging isn't setup, and WECUI messaging isn't setup.","created_at":"2019-06-24T08:56:47Z","updated_at":"2019-06-25T12:58:53Z","closed_at":null,"merged_at":null,"merge_commit_sha":"cc5638d789aa20c62fdedd7d31df630c0e0dec48","assignee":null,"assignees":[],"requested_reviewers":[{"login":"kenzierocks","id":2093023,"node_id":"MDQ6VXNlcjIwOTMwMjM=","avatar_url":"https://avatars1.githubusercontent.com/u/2093023?v=4","gravatar_id":"","url":"https://api.github.com/users/kenzierocks","html_url":"https://github.com/kenzierocks","followers_url":"https://api.github.com/users/kenzierocks/followers","following_url":"https://api.github.com/users/kenzierocks/following{/other_user}","gists_url":"https://api.github.com/users/kenzierocks/gists{/gist_id}","starred_url":"https://api.github.com/users/kenzierocks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kenzierocks/subscriptions","organizations_url":"https://api.github.com/users/kenzierocks/orgs","repos_url":"https://api.github.com/users/kenzierocks/repos","events_url":"https://api.github.com/users/kenzierocks/events{/privacy}","received_events_url":"https://api.github.com/users/kenzierocks/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/EngineHub/WorldEdit/pulls/491/commits","review_comments_url":"https://api.github.com/repos/EngineHub/WorldEdit/pulls/491/comments","review_comment_url":"https://api.github.com/repos/EngineHub/WorldEdit/pulls/comments{/number}","comments_url":"https://api.github.com/repos/EngineHub/WorldEdit/issues/491/comments","statuses_url":"https://api.github.com/repos/EngineHub/WorldEdit/statuses/b4ea6cc2b205d2539aea3b48af9c2ffdb2fd6f7c","head":{"label":"EngineHub:feature/fabric","ref":"feature/fabric","sha":"b4ea6cc2b205d2539aea3b48af9c2ffdb2fd6f7c","user":{"login":"EngineHub","id":3753025,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM3NTMwMjU=","avatar_url":"https://avatars0.githubusercontent.com/u/3753025?v=4","gravatar_id":"","url":"https://api.github.com/users/EngineHub","html_url":"https://github.com/EngineHub","followers_url":"https://api.github.com/users/EngineHub/followers","following_url":"https://api.github.com/users/EngineHub/following{/other_user}","gists_url":"https://api.github.com/users/EngineHub/gists{/gist_id}","starred_url":"https://api.github.com/users/EngineHub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EngineHub/subscriptions","organizations_url":"https://api.github.com/users/EngineHub/orgs","repos_url":"https://api.github.com/users/EngineHub/repos","events_url":"https://api.github.com/users/EngineHub/events{/privacy}","received_events_url":"https://api.github.com/users/EngineHub/received_events","type":"Organization","site_admin":false},"repo":{"id":944926,"node_id":"MDEwOlJlcG9zaXRvcnk5NDQ5MjY=","name":"WorldEdit","full_name":"EngineHub/WorldEdit","private":false,"owner":{"login":"EngineHub","id":3753025,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM3NTMwMjU=","avatar_url":"https://avatars0.githubusercontent.com/u/3753025?v=4","gravatar_id":"","url":"https://api.github.com/users/EngineHub","html_url":"https://github.com/EngineHub","followers_url":"https://api.github.com/users/EngineHub/followers","following_url":"https://api.github.com/users/EngineHub/following{/other_user}","gists_url":"https://api.github.com/users/EngineHub/gists{/gist_id}","starred_url":"https://api.github.com/users/EngineHub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EngineHub/subscriptions","organizations_url":"https://api.github.com/users/EngineHub/orgs","repos_url":"https://api.github.com/users/EngineHub/repos","events_url":"https://api.github.com/users/EngineHub/events{/privacy}","received_events_url":"https://api.github.com/users/EngineHub/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/EngineHub/WorldEdit","description":"An in-game voxel map editor for Minecraft","fork":false,"url":"https://api.github.com/repos/EngineHub/WorldEdit","forks_url":"https://api.github.com/repos/EngineHub/WorldEdit/forks","keys_url":"https://api.github.com/repos/EngineHub/WorldEdit/keys{/key_id}","collaborators_url":"https://api.github.com/repos/EngineHub/WorldEdit/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/EngineHub/WorldEdit/teams","hooks_url":"https://api.github.com/repos/EngineHub/WorldEdit/hooks","issue_events_url":"https://api.github.com/repos/EngineHub/WorldEdit/issues/events{/number}","events_url":"https://api.github.com/repos/EngineHub/WorldEdit/events","assignees_url":"https://api.github.com/repos/EngineHub/WorldEdit/assignees{/user}","branches_url":"https://api.github.com/repos/EngineHub/WorldEdit/branches{/branch}","tags_url":"https://api.github.com/repos/EngineHub/WorldEdit/tags","blobs_url":"https://api.github.com/repos/EngineHub/WorldEdit/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/EngineHub/WorldEdit/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/EngineHub/WorldEdit/git/refs{/sha}","trees_url":"https://api.github.com/repos/EngineHub/WorldEdit/git/trees{/sha}","statuses_url":"https://api.github.com/repos/EngineHub/WorldEdit/statuses/{sha}","languages_url":"https://api.github.com/repos/EngineHub/WorldEdit/languages","stargazers_url":"https://api.github.com/repos/EngineHub/WorldEdit/stargazers","contributors_url":"https://api.github.com/repos/EngineHub/WorldEdit/contributors","subscribers_url":"https://api.github.com/repos/EngineHub/WorldEdit/subscribers","subscription_url":"https://api.github.com/repos/EngineHub/WorldEdit/subscription","commits_url":"https://api.github.com/repos/EngineHub/WorldEdit/commits{/sha}","git_commits_url":"https://api.github.com/repos/EngineHub/WorldEdit/git/commits{/sha}","comments_url":"https://api.github.com/repos/EngineHub/WorldEdit/comments{/number}","issue_comment_url":"https://api.github.com/repos/EngineHub/WorldEdit/issues/comments{/number}","contents_url":"https://api.github.com/repos/EngineHub/WorldEdit/contents/{+path}","compare_url":"https://api.github.com/repos/EngineHub/WorldEdit/compare/{base}...{head}","merges_url":"https://api.github.com/repos/EngineHub/WorldEdit/merges","archive_url":"https://api.github.com/repos/EngineHub/WorldEdit/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/EngineHub/WorldEdit/downloads","issues_url":"https://api.github.com/repos/EngineHub/WorldEdit/issues{/number}","pulls_url":"https://api.github.com/repos/EngineHub/WorldEdit/pulls{/number}","milestones_url":"https://api.github.com/repos/EngineHub/WorldEdit/milestones{/number}","notifications_url":"https://api.github.com/repos/EngineHub/WorldEdit/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/EngineHub/WorldEdit/labels{/name}","releases_url":"https://api.github.com/repos/EngineHub/WorldEdit/releases{/id}","deployments_url":"https://api.github.com/repos/EngineHub/WorldEdit/deployments","created_at":"2010-09-28T08:11:57Z","updated_at":"2019-06-25T08:52:23Z","pushed_at":"2019-06-25T12:58:23Z","git_url":"git://github.com/EngineHub/WorldEdit.git","ssh_url":"git@github.com:EngineHub/WorldEdit.git","clone_url":"https://github.com/EngineHub/WorldEdit.git","svn_url":"https://github.com/EngineHub/WorldEdit","homepage":"http://www.enginehub.org/worldedit","size":13225,"stargazers_count":1253,"watchers_count":1253,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":601,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":14,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":601,"open_issues":14,"watchers":1253,"default_branch":"master"}},"base":{"label":"EngineHub:master","ref":"master","sha":"79910c57d78e27ae945910af13b9ac1d40fbf8ce","user":{"login":"EngineHub","id":3753025,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM3NTMwMjU=","avatar_url":"https://avatars0.githubusercontent.com/u/3753025?v=4","gravatar_id":"","url":"https://api.github.com/users/EngineHub","html_url":"https://github.com/EngineHub","followers_url":"https://api.github.com/users/EngineHub/followers","following_url":"https://api.github.com/users/EngineHub/following{/other_user}","gists_url":"https://api.github.com/users/EngineHub/gists{/gist_id}","starred_url":"https://api.github.com/users/EngineHub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EngineHub/subscriptions","organizations_url":"https://api.github.com/users/EngineHub/orgs","repos_url":"https://api.github.com/users/EngineHub/repos","events_url":"https://api.github.com/users/EngineHub/events{/privacy}","received_events_url":"https://api.github.com/users/EngineHub/received_events","type":"Organization","site_admin":false},"repo":{"id":944926,"node_id":"MDEwOlJlcG9zaXRvcnk5NDQ5MjY=","name":"WorldEdit","full_name":"EngineHub/WorldEdit","private":false,"owner":{"login":"EngineHub","id":3753025,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM3NTMwMjU=","avatar_url":"https://avatars0.githubusercontent.com/u/3753025?v=4","gravatar_id":"","url":"https://api.github.com/users/EngineHub","html_url":"https://github.com/EngineHub","followers_url":"https://api.github.com/users/EngineHub/followers","following_url":"https://api.github.com/users/EngineHub/following{/other_user}","gists_url":"https://api.github.com/users/EngineHub/gists{/gist_id}","starred_url":"https://api.github.com/users/EngineHub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EngineHub/subscriptions","organizations_url":"https://api.github.com/users/EngineHub/orgs","repos_url":"https://api.github.com/users/EngineHub/repos","events_url":"https://api.github.com/users/EngineHub/events{/privacy}","received_events_url":"https://api.github.com/users/EngineHub/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/EngineHub/WorldEdit","description":"An in-game voxel map editor for Minecraft","fork":false,"url":"https://api.github.com/repos/EngineHub/WorldEdit","forks_url":"https://api.github.com/repos/EngineHub/WorldEdit/forks","keys_url":"https://api.github.com/repos/EngineHub/WorldEdit/keys{/key_id}","collaborators_url":"https://api.github.com/repos/EngineHub/WorldEdit/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/EngineHub/WorldEdit/teams","hooks_url":"https://api.github.com/repos/EngineHub/WorldEdit/hooks","issue_events_url":"https://api.github.com/repos/EngineHub/WorldEdit/issues/events{/number}","events_url":"https://api.github.com/repos/EngineHub/WorldEdit/events","assignees_url":"https://api.github.com/repos/EngineHub/WorldEdit/assignees{/user}","branches_url":"https://api.github.com/repos/EngineHub/WorldEdit/branches{/branch}","tags_url":"https://api.github.com/repos/EngineHub/WorldEdit/tags","blobs_url":"https://api.github.com/repos/EngineHub/WorldEdit/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/EngineHub/WorldEdit/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/EngineHub/WorldEdit/git/refs{/sha}","trees_url":"https://api.github.com/repos/EngineHub/WorldEdit/git/trees{/sha}","statuses_url":"https://api.github.com/repos/EngineHub/WorldEdit/statuses/{sha}","languages_url":"https://api.github.com/repos/EngineHub/WorldEdit/languages","stargazers_url":"https://api.github.com/repos/EngineHub/WorldEdit/stargazers","contributors_url":"https://api.github.com/repos/EngineHub/WorldEdit/contributors","subscribers_url":"https://api.github.com/repos/EngineHub/WorldEdit/subscribers","subscription_url":"https://api.github.com/repos/EngineHub/WorldEdit/subscription","commits_url":"https://api.github.com/repos/EngineHub/WorldEdit/commits{/sha}","git_commits_url":"https://api.github.com/repos/EngineHub/WorldEdit/git/commits{/sha}","comments_url":"https://api.github.com/repos/EngineHub/WorldEdit/comments{/number}","issue_comment_url":"https://api.github.com/repos/EngineHub/WorldEdit/issues/comments{/number}","contents_url":"https://api.github.com/repos/EngineHub/WorldEdit/contents/{+path}","compare_url":"https://api.github.com/repos/EngineHub/WorldEdit/compare/{base}...{head}","merges_url":"https://api.github.com/repos/EngineHub/WorldEdit/merges","archive_url":"https://api.github.com/repos/EngineHub/WorldEdit/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/EngineHub/WorldEdit/downloads","issues_url":"https://api.github.com/repos/EngineHub/WorldEdit/issues{/number}","pulls_url":"https://api.github.com/repos/EngineHub/WorldEdit/pulls{/number}","milestones_url":"https://api.github.com/repos/EngineHub/WorldEdit/milestones{/number}","notifications_url":"https://api.github.com/repos/EngineHub/WorldEdit/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/EngineHub/WorldEdit/labels{/name}","releases_url":"https://api.github.com/repos/EngineHub/WorldEdit/releases{/id}","deployments_url":"https://api.github.com/repos/EngineHub/WorldEdit/deployments","created_at":"2010-09-28T08:11:57Z","updated_at":"2019-06-25T08:52:23Z","pushed_at":"2019-06-25T12:58:23Z","git_url":"git://github.com/EngineHub/WorldEdit.git","ssh_url":"git@github.com:EngineHub/WorldEdit.git","clone_url":"https://github.com/EngineHub/WorldEdit.git","svn_url":"https://github.com/EngineHub/WorldEdit","homepage":"http://www.enginehub.org/worldedit","size":13225,"stargazers_count":1253,"watchers_count":1253,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":601,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":14,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":601,"open_issues":14,"watchers":1253,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/EngineHub/WorldEdit/pulls/491"},"html":{"href":"https://github.com/EngineHub/WorldEdit/pull/491"},"issue":{"href":"https://api.github.com/repos/EngineHub/WorldEdit/issues/491"},"comments":{"href":"https://api.github.com/repos/EngineHub/WorldEdit/issues/491/comments"},"review_comments":{"href":"https://api.github.com/repos/EngineHub/WorldEdit/pulls/491/comments"},"review_comment":{"href":"https://api.github.com/repos/EngineHub/WorldEdit/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/EngineHub/WorldEdit/pulls/491/commits"},"statuses":{"href":"https://api.github.com/repos/EngineHub/WorldEdit/statuses/b4ea6cc2b205d2539aea3b48af9c2ffdb2fd6f7c"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"me4502"}}