diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index ccc025d8c..5bdffb5e9 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -28,6 +28,8 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.Preference; +import com.sk89q.worldedit.extension.platform.Watchdog; +import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.registry.Registries; import org.bukkit.Bukkit; @@ -52,6 +54,14 @@ public class BukkitServerInterface implements MultiUserPlatform { public WorldEditPlugin plugin; private CommandRegistration dynamicCommands; private boolean hookingEvents; + private final LazyReference watchdog = LazyReference.from(() -> { + if (plugin.getBukkitImplAdapter() != null) { + return plugin.getBukkitImplAdapter().supportsWatchdog() + ? new BukkitWatchdog(plugin.getBukkitImplAdapter()) + : null; + } + return null; + }); public BukkitServerInterface(WorldEditPlugin plugin, Server server) { this.plugin = plugin; @@ -103,6 +113,11 @@ public class BukkitServerInterface implements MultiUserPlatform { return Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, task, delay, period); } + @Override + public Watchdog getWatchdog() { + return watchdog.getValue(); + } + @Override public List getWorlds() { List worlds = server.getWorlds(); diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWatchdog.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWatchdog.java new file mode 100644 index 000000000..1e37852a6 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWatchdog.java @@ -0,0 +1,38 @@ +/* + * 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.bukkit; + +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.extension.platform.Watchdog; + +class BukkitWatchdog implements Watchdog { + + private final BukkitImplAdapter adapter; + + BukkitWatchdog(BukkitImplAdapter adapter) { + this.adapter = adapter; + } + + @Override + public void tick() { + adapter.tickWatchdog(); + } + +} diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java index f21d0917a..4bb915c56 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -62,6 +62,19 @@ public interface BukkitImplAdapter { @Nullable DataFixer getDataFixer(); + /** + * @return {@code true} if {@link #tickWatchdog()} is implemented + */ + default boolean supportsWatchdog() { + return false; + } + + /** + * Tick the server watchdog, if possible. + */ + default void tickWatchdog() { + } + /** * Get the block at the given location. * diff --git a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar index d1659adf2..92171a9cc 100644 Binary files a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar and b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar differ diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index e3bcac4b1..f195ed7de 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -22,6 +22,8 @@ package com.sk89q.worldedit; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.ChangeSetExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.MaskingExtent; @@ -38,6 +40,7 @@ import com.sk89q.worldedit.extent.world.BlockQuirkExtent; import com.sk89q.worldedit.extent.world.ChunkLoadingExtent; import com.sk89q.worldedit.extent.world.FastModeExtent; import com.sk89q.worldedit.extent.world.SurvivalModeExtent; +import com.sk89q.worldedit.extent.world.WatchdogTickingExtent; import com.sk89q.worldedit.function.GroundFunction; import com.sk89q.worldedit.function.RegionMaskingFilter; import com.sk89q.worldedit.function.biome.BiomeReplace; @@ -188,6 +191,7 @@ public class EditSession implements Extent, AutoCloseable { private final MultiStageReorder reorderExtent; private final MaskingExtent maskingExtent; private final BlockChangeLimiter changeLimiter; + private final List watchdogExtents = new ArrayList<>(2); private final Extent bypassReorderHistory; private final Extent bypassHistory; @@ -214,10 +218,18 @@ public class EditSession implements Extent, AutoCloseable { this.world = world; if (world != null) { + Watchdog watchdog = WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getWatchdog(); Extent extent; // These extents are ALWAYS used extent = fastModeExtent = new FastModeExtent(world, false); + if (watchdog != null) { + // Reset watchdog before world placement + WatchdogTickingExtent watchdogExtent = new WatchdogTickingExtent(extent, watchdog); + extent = watchdogExtent; + watchdogExtents.add(watchdogExtent); + } extent = survivalExtent = new SurvivalModeExtent(extent, world); extent = new BlockQuirkExtent(extent, world); extent = new ChunkLoadingExtent(extent, world); @@ -230,6 +242,13 @@ public class EditSession implements Extent, AutoCloseable { extent = reorderExtent = new MultiStageReorder(extent, false); extent = chunkBatchingExtent = new ChunkBatchingExtent(extent); extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER); + if (watchdog != null) { + // reset before buffering extents, since they may buffer all changes + // before the world-placement reset can happen, and still cause halts + WatchdogTickingExtent watchdogExtent = new WatchdogTickingExtent(extent, watchdog); + extent = watchdogExtent; + watchdogExtents.add(watchdogExtent); + } this.bypassHistory = new DataValidatorExtent(extent, world); // These extents can be skipped by calling smartSetBlock() @@ -536,6 +555,24 @@ public class EditSession implements Extent, AutoCloseable { } } + /** + * Check if this session will tick the watchdog. + * + * @return {@code true} if any watchdog extent is enabled + */ + public boolean isTickingWatchdog() { + return watchdogExtents.stream().anyMatch(WatchdogTickingExtent::isEnabled); + } + + /** + * Set all watchdog extents to the given mode. + */ + public void setTickingWatchdog(boolean active) { + for (WatchdogTickingExtent extent : watchdogExtents) { + extent.setEnabled(active); + } + } + /** * Get the number of blocks changed, including repeated block changes. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 63e915ebe..47042a88d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -102,6 +102,7 @@ public class LocalSession { private transient EditSession.ReorderMode reorderMode = EditSession.ReorderMode.MULTI_STAGE; private transient List> lastDistribution; private transient World worldOverride; + private transient boolean tickingWatchdog = false; // Saved properties private String lastScript; @@ -238,12 +239,7 @@ public class LocalSession { EditSession editSession = history.get(historyPointer); try (EditSession newEditSession = WorldEdit.getInstance().getEditSessionFactory() .getEditSession(editSession.getWorld(), -1, newBlockBag, actor)) { - newEditSession.enableStandardMode(); - newEditSession.setReorderMode(reorderMode); - newEditSession.setFastMode(fastMode); - if (newEditSession.getSurvivalExtent() != null) { - newEditSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt")); - } + prepareEditingExtents(editSession, actor); editSession.undo(newEditSession); } return editSession; @@ -266,12 +262,7 @@ public class LocalSession { EditSession editSession = history.get(historyPointer); try (EditSession newEditSession = WorldEdit.getInstance().getEditSessionFactory() .getEditSession(editSession.getWorld(), -1, newBlockBag, actor)) { - newEditSession.enableStandardMode(); - newEditSession.setReorderMode(reorderMode); - newEditSession.setFastMode(fastMode); - if (newEditSession.getSurvivalExtent() != null) { - newEditSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt")); - } + prepareEditingExtents(editSession, actor); editSession.redo(newEditSession); } ++historyPointer; @@ -294,6 +285,14 @@ public class LocalSession { this.worldOverride = worldOverride; } + public boolean isTickingWatchdog() { + return tickingWatchdog; + } + + public void setTickingWatchdog(boolean tickingWatchdog) { + this.tickingWatchdog = tickingWatchdog; + } + /** * Get the default region selector. * @@ -945,14 +944,19 @@ public class LocalSession { } Request.request().setEditSession(editSession); + editSession.setMask(mask); + prepareEditingExtents(editSession, actor); + + return editSession; + } + + private void prepareEditingExtents(EditSession editSession, Actor actor) { editSession.setFastMode(fastMode); editSession.setReorderMode(reorderMode); - editSession.setMask(mask); if (editSession.getSurvivalExtent() != null) { editSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt")); } - - return editSession; + editSession.setTickingWatchdog(tickingWatchdog); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index 5fdf2087b..495b43663 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -26,10 +26,12 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.HookMode; import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.DisallowedUsageException; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.util.formatting.component.PaginationBox; import com.sk89q.worldedit.util.formatting.text.Component; @@ -198,6 +200,29 @@ public class GeneralCommands { } } + @Command( + name = "/watchdog", + desc = "Changes watchdog hook state.", + descFooter = "This is dependent on platform implementation. " + + "Not all platforms support watchdog hooks, or contain a watchdog." + ) + @CommandPermissions("worldedit.watchdog") + public void watchdog(Actor actor, LocalSession session, + @Arg(desc = "The mode to set the watchdog hook to", def = "") + HookMode hookMode) { + if (WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getWatchdog() == null) { + actor.printError("This platform has no watchdog hook."); + return; + } + boolean previousMode = session.isTickingWatchdog(); + if (hookMode != null && (hookMode == HookMode.ACTIVE) == previousMode) { + actor.printError("Watchdog hook already " + (previousMode ? "active" : "inactive") + "."); + return; + } + session.setTickingWatchdog(!previousMode); + actor.print("Watchdog hook now " + (previousMode ? "inactive" : "active") + "."); + } + @Command( name = "gmask", aliases = {"/gmask"}, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java index 41f8bae07..d1268e466 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.command.argument; import com.google.common.collect.ImmutableSet; import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.command.util.HookMode; import com.sk89q.worldedit.util.TreeGenerator; import org.enginehub.piston.CommandManager; import org.enginehub.piston.converter.ArgumentConverter; @@ -46,6 +47,8 @@ public final class EnumConverter { full(EditSession.ReorderMode.class, r -> ImmutableSet.of(r.getDisplayName()), null)); + commandManager.registerConverter(Key.of(HookMode.class), + basic(HookMode.class)); } private static > ArgumentConverter basic(Class enumClass) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/HookMode.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/HookMode.java new file mode 100644 index 000000000..113a45613 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/HookMode.java @@ -0,0 +1,24 @@ +/* + * 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.command.util; + +public enum HookMode { + ACTIVE, INACTIVE +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java index fcbd6ff29..d82ed52c1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java @@ -83,6 +83,15 @@ public interface Platform { */ int schedule(long delay, long period, Runnable task); + /** + * Get the watchdog service. + * + * @return the watchdog service, or {@code null} if none + */ + default @Nullable Watchdog getWatchdog() { + return null; + } + /** * Get a list of available or loaded worlds. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Watchdog.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Watchdog.java new file mode 100644 index 000000000..1f822f90f --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Watchdog.java @@ -0,0 +1,29 @@ +/* + * 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.extension.platform; + +/** + * Interface to a {@link Platform}'s watchdog service. + */ +public interface Watchdog { + + void tick(); + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java new file mode 100644 index 000000000..78ddc9db8 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java @@ -0,0 +1,95 @@ +/* + * 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.extent.world; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extension.platform.Watchdog; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; + +/** + * Extent that ticks the watchdog before every world-affecting action. + */ +public class WatchdogTickingExtent extends AbstractDelegateExtent { + + // Number of operations we run per tick to the watchdog + private static final int OPS_PER_TICK = 100; + + private final Watchdog watchdog; + private boolean enabled; + private int ops; + + /** + * Create a new instance. + * + * @param extent the extent + * @param watchdog the watchdog to reset + */ + public WatchdogTickingExtent(Extent extent, Watchdog watchdog) { + super(extent); + this.watchdog = watchdog; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + private void onOperation() { + if (enabled) { + ops++; + if (ops == OPS_PER_TICK) { + watchdog.tick(); + ops = 0; + } + } + } + + @Override + public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { + onOperation(); + return super.setBlock(location, block); + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + onOperation(); + return super.createEntity(location, entity); + } + + @Override + public boolean setBiome(BlockVector2 position, BiomeType biome) { + onOperation(); + return super.setBiome(position, biome); + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java index 69ea094b2..beb6d5208 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java @@ -26,12 +26,15 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.Preference; +import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; import net.minecraft.SharedConstants; import net.minecraft.server.MinecraftServer; import net.minecraft.server.PlayerManager; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.dedicated.MinecraftDedicatedServer; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Identifier; @@ -55,12 +58,15 @@ class FabricPlatform extends AbstractPlatform implements MultiUserPlatform { private final FabricWorldEdit mod; private final MinecraftServer server; private final FabricDataFixer dataFixer; + private final @Nullable Watchdog watchdog; private boolean hookingEvents = false; FabricPlatform(FabricWorldEdit mod, MinecraftServer server) { this.mod = mod; this.server = server; this.dataFixer = new FabricDataFixer(getDataVersion()); + this.watchdog = server instanceof MinecraftDedicatedServer + ? (Watchdog) server : null; } boolean isHookingEvents() { @@ -97,6 +103,12 @@ class FabricPlatform extends AbstractPlatform implements MultiUserPlatform { return -1; } + @Override + @Nullable + public Watchdog getWatchdog() { + return watchdog; + } + @Override public List getWorlds() { Iterable worlds = server.getWorlds(); diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java new file mode 100644 index 000000000..ab73faf79 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.fabric.mixin; + +import com.sk89q.worldedit.extension.platform.Watchdog; +import net.minecraft.server.ServerTask; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.NonBlockingThreadExecutor; +import net.minecraft.util.SystemUtil; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(MinecraftServer.class) +public abstract class MixinMinecraftServer extends NonBlockingThreadExecutor implements Watchdog { + + public MixinMinecraftServer(String name) { + super(name); + } + + @Shadow + private long timeReference; + + @Override + public void tick() { + timeReference = SystemUtil.getMeasuringTimeMs(); + } + +} diff --git a/worldedit-fabric/src/main/resources/worldedit.mixins.json b/worldedit-fabric/src/main/resources/worldedit.mixins.json index 165bf44ce..fd6cd4f92 100644 --- a/worldedit-fabric/src/main/resources/worldedit.mixins.json +++ b/worldedit-fabric/src/main/resources/worldedit.mixins.json @@ -3,11 +3,12 @@ "package": "com.sk89q.worldedit.fabric.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ - "MixinServerPlayerEntity" + "MixinServerPlayerEntity", + "MixinMinecraftServer" ], "server": [ ], "injectors": { "defaultRequire": 1 } -} \ No newline at end of file +} diff --git a/worldedit-forge/build.gradle.kts b/worldedit-forge/build.gradle.kts index e71c04295..b339aa62b 100644 --- a/worldedit-forge/build.gradle.kts +++ b/worldedit-forge/build.gradle.kts @@ -34,6 +34,8 @@ configure { "version" to "20190913-$mappingsMinecraftVersion" )) + accessTransformer(file("src/main/resources/META-INF/accesstransformer.cfg")) + runs { val runConfig = Action { properties(mapOf( 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 93fea255f..f7a82a344 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 @@ -32,6 +32,7 @@ import com.sk89q.worldedit.world.registry.Registries; import net.minecraft.command.Commands; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.management.PlayerList; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SharedConstants; @@ -56,12 +57,15 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { private final ForgeWorldEdit mod; private final MinecraftServer server; private final ForgeDataFixer dataFixer; + private final @Nullable ForgeWatchdog watchdog; private boolean hookingEvents = false; ForgePlatform(ForgeWorldEdit mod) { this.mod = mod; this.server = ServerLifecycleHooks.getCurrentServer(); this.dataFixer = new ForgeDataFixer(getDataVersion()); + this.watchdog = server instanceof DedicatedServer + ? new ForgeWatchdog((DedicatedServer) server) : null; } boolean isHookingEvents() { @@ -98,6 +102,12 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { return -1; } + @Override + @Nullable + public ForgeWatchdog getWatchdog() { + return watchdog; + } + @Override public List getWorlds() { Iterable worlds = server.getWorlds(); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWatchdog.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWatchdog.java new file mode 100644 index 000000000..25f72c2c5 --- /dev/null +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWatchdog.java @@ -0,0 +1,38 @@ +/* + * 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.extension.platform.Watchdog; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.util.Util; + +class ForgeWatchdog implements Watchdog { + + private final DedicatedServer server; + + ForgeWatchdog(DedicatedServer server) { + this.server = server; + } + + @Override + public void tick() { + server.serverTime = Util.milliTime(); + } +} diff --git a/worldedit-forge/src/main/resources/META-INF/accesstransformer.cfg b/worldedit-forge/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 000000000..9c1530b89 --- /dev/null +++ b/worldedit-forge/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1 @@ +public net.minecraft.server.MinecraftServer field_211151_aa # serverTime \ No newline at end of file