diff --git a/CHANGELOG.md b/CHANGELOG.md index 73444b7b0..3d94d1449 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,7 @@ * Fixed #3013 * Fixed #3027 * Fixed #2978 +* Fixed #3041 * Possibly fixed #2927 ## Release Candidate 22 (18 Apr 2021) diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/NetworkManager.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/NetworkManager.java index 2771c4893..dd726af28 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/NetworkManager.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/NetworkManager.java @@ -1,9 +1,11 @@ package io.github.thebusybiscuit.slimefun4.core.networks; import java.util.ArrayList; -import java.util.LinkedList; +import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.logging.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -12,6 +14,7 @@ import org.apache.commons.lang.Validate; import org.bukkit.Location; import org.bukkit.Server; +import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition; import io.github.thebusybiscuit.cscorelib2.config.Config; import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.api.network.Network; @@ -25,6 +28,7 @@ import me.mrCookieSlime.Slimefun.api.BlockStorage; * and providing some utility methods that would have probably been static otherwise. * * @author TheBusyBiscuit + * @author meiamsome * * @see Network * @see NetworkListener @@ -35,7 +39,16 @@ public class NetworkManager { private final int maxNodes; private final boolean enableVisualizer; private final boolean deleteExcessItems; - private final List networks = new LinkedList<>(); + + /** + * Fixes #3041 + * + * We use a {@link CopyOnWriteArrayList} here to ensure thread-safety. + * This {@link List} is also much more frequently read than being written to. + * Therefore a {@link CopyOnWriteArrayList} should be perfect for this, even + * if insertions come at a slight cost. + */ + private final List networks = new CopyOnWriteArrayList<>(); /** * This creates a new {@link NetworkManager} with the given capacity. @@ -96,12 +109,13 @@ public class NetworkManager { /** * This returns a {@link List} of every {@link Network} on the {@link Server}. + * The returned {@link List} is not modifiable. * * @return A {@link List} containing every {@link Network} on the {@link Server} */ @Nonnull public List getNetworkList() { - return networks; + return Collections.unmodifiableList(networks); } @Nonnull @@ -172,26 +186,30 @@ public class NetworkManager { public void updateAllNetworks(@Nonnull Location l) { Validate.notNull(l, "The Location cannot be null"); - /* - * No need to create a sublist and loop through it if - * there aren't even any networks on the server. - */ - if (networks.isEmpty()) { - return; - } + try { + /* + * No need to create a sublist and loop through it if + * there aren't even any networks on the server. + */ + if (networks.isEmpty()) { + return; + } - /* - * Only a Slimefun block can be part of a Network. - * This check helps to speed up performance. - * - * (Skip for Unit Tests as they don't support block info yet) - */ - if (!BlockStorage.hasBlockInfo(l) && SlimefunPlugin.getMinecraftVersion() != MinecraftVersion.UNIT_TEST) { - return; - } + /* + * Only a Slimefun block can be part of a Network. + * This check helps to speed up performance. + * + * (Skip for Unit Tests as they don't support block info yet) + */ + if (!BlockStorage.hasBlockInfo(l) && SlimefunPlugin.getMinecraftVersion() != MinecraftVersion.UNIT_TEST) { + return; + } - for (Network network : getNetworksFromLocation(l, Network.class)) { - network.markDirty(l); + for (Network network : getNetworksFromLocation(l, Network.class)) { + network.markDirty(l); + } + } catch (Exception x) { + SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Exception was thrown while causing a networks update @ " + new BlockPosition(l)); } }