From 4d6fbd9d2ff179057be884ad4137fbb92f81cc5d Mon Sep 17 00:00:00 2001 From: Ben Staddon Date: Wed, 27 Jun 2018 19:23:23 +0100 Subject: [PATCH] Clean up some dimension manager code and add a command to list dimensions (#4902) --- .../server/MinecraftServer.java.patch | 2 +- .../common/DimensionManager.java | 80 ++++++++++++------- .../server/command/CommandDimensions.java | 68 ++++++++++++++++ .../server/command/ForgeCommand.java | 1 + .../resources/assets/forge/lang/en_US.lang | 2 + 5 files changed, 124 insertions(+), 29 deletions(-) create mode 100644 src/main/java/net/minecraftforge/server/command/CommandDimensions.java diff --git a/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch b/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch index e23c17f32f..fab28b0fcd 100644 --- a/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch +++ b/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch @@ -251,7 +251,7 @@ public WorldServer func_71218_a(int p_71218_1_) { - if (p_71218_1_ == -1) -+ WorldServer ret = net.minecraftforge.common.DimensionManager.getWorld(p_71218_1_); ++ WorldServer ret = net.minecraftforge.common.DimensionManager.getWorld(p_71218_1_, true); + if (ret == null) { - return this.field_71305_c[1]; diff --git a/src/main/java/net/minecraftforge/common/DimensionManager.java b/src/main/java/net/minecraftforge/common/DimensionManager.java index b1646f7753..6247005372 100644 --- a/src/main/java/net/minecraftforge/common/DimensionManager.java +++ b/src/main/java/net/minecraftforge/common/DimensionManager.java @@ -24,17 +24,22 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Hashtable; +import java.util.IdentityHashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; -import java.util.Map.Entry; import java.util.concurrent.ConcurrentMap; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntListIterator; +import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import it.unimi.dsi.fastutil.ints.IntIterator; +import it.unimi.dsi.fastutil.ints.IntLinkedOpenHashSet; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntRBTreeSet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSets; +import it.unimi.dsi.fastutil.ints.IntSortedSet; import com.google.common.collect.HashMultiset; import com.google.common.collect.Lists; @@ -71,10 +76,10 @@ public class DimensionManager private static boolean hasInit = false; - private static final Hashtable worlds = new Hashtable<>(); - private static final Hashtable dimensions = new Hashtable<>(); + private static final Int2ObjectMap worlds = Int2ObjectMaps.synchronize(new Int2ObjectLinkedOpenHashMap<>()); + private static final Int2ObjectMap dimensions = Int2ObjectMaps.synchronize(new Int2ObjectLinkedOpenHashMap<>()); private static final IntSet keepLoaded = IntSets.synchronize(new IntOpenHashSet()); - private static final IntArrayList unloadQueue = new IntArrayList(); + private static final IntSet unloadQueue = IntSets.synchronize(new IntLinkedOpenHashSet()); private static final BitSet dimensionMap = new BitSet(Long.SIZE << 4); private static final ConcurrentMap weakWorldMap = new MapMaker().weakKeys().weakValues().makeMap(); private static final Multiset leakedWorlds = HashMultiset.create(); @@ -86,17 +91,27 @@ public class DimensionManager { int[] ret = new int[dimensions.size()]; int x = 0; - for (Map.Entry ent : dimensions.entrySet()) + for (Int2ObjectMap.Entry ent : dimensions.int2ObjectEntrySet()) { if (ent.getValue().type == type) { - ret[x++] = ent.getKey(); + ret[x++] = ent.getIntKey(); } } return Arrays.copyOf(ret, x); } + public static Map getRegisteredDimensions() + { + Map map = new IdentityHashMap<>(); + for (Int2ObjectMap.Entry entry : dimensions.int2ObjectEntrySet()) + { + map.computeIfAbsent(entry.getValue().type, k -> new IntRBTreeSet()).add(entry.getIntKey()); + } + return map; + } + public static void init() { if (hasInit) @@ -182,9 +197,10 @@ public class DimensionManager } return getIDs(); } + public static Integer[] getIDs() { - return worlds.keySet().toArray(new Integer[worlds.size()]); //Only loaded dims, since usually used to cycle through loaded worlds + return worlds.keySet().toArray(new Integer[0]); // Only loaded dims, since usually used to cycle through loaded worlds } public static void setWorld(int id, @Nullable WorldServer world, MinecraftServer server) @@ -211,9 +227,9 @@ public class DimensionManager if (worlds.get( 1) != null) tmp.add(worlds.get( 1)); - for (Entry entry : worlds.entrySet()) + for (Int2ObjectMap.Entry entry : worlds.int2ObjectEntrySet()) { - int dim = entry.getKey(); + int dim = entry.getIntKey(); if (dim >= -1 && dim <= 1) { continue; @@ -221,7 +237,7 @@ public class DimensionManager tmp.add(entry.getValue()); } - server.worlds = tmp.toArray(new WorldServer[tmp.size()]); + server.worlds = tmp.toArray(new WorldServer[0]); } public static void initDimension(int dim) @@ -257,12 +273,21 @@ public class DimensionManager public static WorldServer getWorld(int id) { + return getWorld(id, false); + } + + public static WorldServer getWorld(int id, boolean resetUnloadDelay) + { + if (resetUnloadDelay && unloadQueue.contains(id)) + { + dimensions.get(id).ticksWaited = 0; + } return worlds.get(id); } public static WorldServer[] getWorlds() { - return worlds.values().toArray(new WorldServer[worlds.size()]); + return worlds.values().toArray(new WorldServer[0]); } static @@ -276,8 +301,9 @@ public class DimensionManager */ public static Integer[] getStaticDimensionIDs() { - return dimensions.keySet().toArray(new Integer[dimensions.keySet().size()]); + return dimensions.keySet().toArray(new Integer[0]); } + public static WorldProvider createProviderFor(int dim) { try @@ -322,7 +348,6 @@ public class DimensionManager /** * Queues a dimension to unload, if it can be unloaded. - * If the dimension is already queued, it will reset the delay to unload. * @param id The id of the dimension */ public static void unloadWorld(int id) @@ -330,14 +355,9 @@ public class DimensionManager WorldServer world = worlds.get(id); if (world == null || !canUnloadWorld(world)) return; - if (!unloadQueue.contains(id)) + if (unloadQueue.add(id)) { FMLLog.log.debug("Queueing dimension {} to unload", id); - unloadQueue.add(id); - } - else - { - dimensions.get(id).ticksWaited = 0; } } @@ -347,12 +367,14 @@ public class DimensionManager } /* - * To be called by the server at the appropriate time, do not call from mod code. - */ - public static void unloadWorlds(Hashtable worldTickTimes) { - IntListIterator queueIterator = unloadQueue.iterator(); - while (queueIterator.hasNext()) { - int id = queueIterator.next(); + * To be called by the server at the appropriate time, do not call from mod code. + */ + public static void unloadWorlds(Hashtable worldTickTimes) + { + IntIterator queueIterator = unloadQueue.iterator(); + while (queueIterator.hasNext()) + { + int id = queueIterator.nextInt(); Dimension dimension = dimensions.get(id); if (dimension.ticksWaited < ForgeModContainer.dimensionUnloadQueueDelay) { @@ -428,8 +450,10 @@ public class DimensionManager dimensionMap.clear(); if (compoundTag == null) { - for (Integer id : dimensions.keySet()) + IntIterator iterator = dimensions.keySet().iterator(); + while (iterator.hasNext()) { + int id = iterator.nextInt(); if (id >= 0) { dimensionMap.set(id); diff --git a/src/main/java/net/minecraftforge/server/command/CommandDimensions.java b/src/main/java/net/minecraftforge/server/command/CommandDimensions.java new file mode 100644 index 0000000000..f641f752eb --- /dev/null +++ b/src/main/java/net/minecraftforge/server/command/CommandDimensions.java @@ -0,0 +1,68 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * This library 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 version 2.1 + * of the License. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.command; + +import it.unimi.dsi.fastutil.ints.IntSortedSet; +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.world.DimensionType; +import net.minecraftforge.common.DimensionManager; + +import java.util.Map; + +public class CommandDimensions extends CommandBase +{ + @Override + public String getName() + { + return "dimensions"; + } + + @Override + public String getUsage(ICommandSender sender) + { + return "commands.forge.dimensions.usage"; + } + + @Override + public int getRequiredPermissionLevel() + { + return 0; + } + + @Override + public boolean checkPermission(MinecraftServer server, ICommandSender sender) + { + return true; + } + + @Override + public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException + { + sender.sendMessage(TextComponentHelper.createComponentTranslation(sender, "commands.forge.dimensions.list")); + for (Map.Entry entry : DimensionManager.getRegisteredDimensions().entrySet()) + { + sender.sendMessage(new TextComponentString(entry.getKey().getName() + ": " + entry.getValue())); + } + } +} diff --git a/src/main/java/net/minecraftforge/server/command/ForgeCommand.java b/src/main/java/net/minecraftforge/server/command/ForgeCommand.java index fda3560f10..612f66a8c0 100644 --- a/src/main/java/net/minecraftforge/server/command/ForgeCommand.java +++ b/src/main/java/net/minecraftforge/server/command/ForgeCommand.java @@ -33,6 +33,7 @@ public class ForgeCommand extends CommandTreeBase super.addSubcommand(new CommandGenerate()); super.addSubcommand(new CommandEntity()); super.addSubcommand(new CommandSetDimension()); + super.addSubcommand(new CommandDimensions()); super.addSubcommand(new CommandTreeHelp(this)); } diff --git a/src/main/resources/assets/forge/lang/en_US.lang b/src/main/resources/assets/forge/lang/en_US.lang index e55a0168fd..d475dd248f 100644 --- a/src/main/resources/assets/forge/lang/en_US.lang +++ b/src/main/resources/assets/forge/lang/en_US.lang @@ -19,6 +19,8 @@ commands.forge.setdim.usage=Use /forge setdim [ ] commands.forge.setdim.invalid.entity=The entity selected (%s) is not valid. commands.forge.setdim.invalid.dim=The dimension ID specified (%d) is not valid. commands.forge.setdim.invalid.nochange=The entity selected (%s) is already in the dimension specified (%d). +commands.forge.dimensions.usage=Use /forge dimensions +commands.forge.dimensions.list=Currently registered dimensions by type: commands.forge.tracking.te.enabled=Tile Entity tracking enabled for %d seconds. commands.forge.tracking.entity.enabled=Entity tracking enabled for %d seconds.