From 67cce53b72f9146822cbbd16e9ca836a535e3214 Mon Sep 17 00:00:00 2001 From: KennyTV Date: Mon, 22 Jun 2020 17:45:10 +0200 Subject: [PATCH] Revert removal of concurrency hacks Apparently still causes issues with PS, we'll investigate this properly at a later date --- .../us/myles/ViaVersion/ViaVersionPlugin.java | 8 + .../bukkit/platform/BukkitViaInjector.java | 25 +- .../myles/ViaVersion/util/ConcurrentList.java | 278 ++++++++++++++++++ .../us/myles/ViaVersion/util/ListWrapper.java | 4 + 4 files changed, 313 insertions(+), 2 deletions(-) create mode 100644 common/src/main/java/us/myles/ViaVersion/util/ConcurrentList.java diff --git a/bukkit/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java b/bukkit/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java index 7ceb80d8a..69df37eef 100644 --- a/bukkit/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java +++ b/bukkit/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java @@ -60,6 +60,14 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform // Check if we're using protocol support too protocolSupport = Bukkit.getPluginManager().getPlugin("ProtocolSupport") != null; + if (protocolSupport) { + getLogger().info("Hooking into ProtocolSupport, to prevent issues!"); + try { + BukkitViaInjector.patchLists(); + } catch (Exception e) { + e.printStackTrace(); + } + } } @Override diff --git a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaInjector.java b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaInjector.java index da7459fcd..0960248d5 100644 --- a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaInjector.java +++ b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaInjector.java @@ -12,12 +12,14 @@ import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.platform.ViaInjector; import us.myles.ViaVersion.bukkit.handlers.BukkitChannelInitializer; import us.myles.ViaVersion.bukkit.util.NMSUtil; +import us.myles.ViaVersion.util.ConcurrentList; import us.myles.ViaVersion.util.ListWrapper; import us.myles.ViaVersion.util.ReflectionUtil; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collection; import java.util.List; public class BukkitViaInjector implements ViaInjector { @@ -33,7 +35,7 @@ public class BukkitViaInjector implements ViaInjector { } for (Field field : connection.getClass().getDeclaredFields()) { field.setAccessible(true); - final Object value = field.get(connection); + Object value = field.get(connection); if (value instanceof List) { // Inject the list List wrapper = new ListWrapper((List) value) { @@ -318,4 +320,23 @@ public class BukkitViaInjector implements ViaInjector { data.addProperty("binded", isBinded()); return data; } -} + + public static void patchLists() throws Exception { + Object connection = getServerConnection(); + if (connection == null) { + Via.getPlatform().getLogger().warning("We failed to find the core component 'ServerConnection', please file an issue on our GitHub."); + return; + } + + for (Field field : connection.getClass().getDeclaredFields()) { + field.setAccessible(true); + Object value = field.get(connection); + if (!(value instanceof List)) continue; + if (value instanceof ConcurrentList) continue; + + ConcurrentList list = new ConcurrentList(); + list.addAll((Collection) value); + field.set(connection, list); + } + } +} \ No newline at end of file diff --git a/common/src/main/java/us/myles/ViaVersion/util/ConcurrentList.java b/common/src/main/java/us/myles/ViaVersion/util/ConcurrentList.java new file mode 100644 index 000000000..77c1dca85 --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/util/ConcurrentList.java @@ -0,0 +1,278 @@ +package us.myles.ViaVersion.util; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +/** + * Created by wea_ondara licensed under MIT + * Same license as in LICENSE + *

+ * Taken from: + * https://github.com/weaondara/BungeePerms/blob/master/src/main/java/net/alpenblock/bungeeperms/util/ConcurrentList.java + * + * @param List Type + * @deprecated get rid of this at some point + */ +@Deprecated +public class ConcurrentList extends ArrayList { + + private final Object lock = new Object(); + + @Override + public boolean add(E e) { + synchronized (lock) { + return super.add(e); + } + } + + @Override + public void add(int index, E element) { + synchronized (lock) { + super.add(index, element); + } + } + + @Override + public boolean addAll(Collection c) { + synchronized (lock) { + return super.addAll(c); + } + } + + @Override + public boolean addAll(int index, Collection c) { + synchronized (lock) { + return super.addAll(index, c); + } + } + + @Override + public void clear() { + synchronized (lock) { + super.clear(); + } + } + + @Override + public Object clone() { + synchronized (lock) { + try { + ConcurrentList clist = (ConcurrentList) super.clone(); + clist.modCount = 0; + Field f = ArrayList.class.getDeclaredField("elementData"); + f.setAccessible(true); + f.set(clist, Arrays.copyOf((Object[]) f.get(this), this.size())); + + return clist; + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + } + + @Override + public boolean contains(Object o) { + synchronized (lock) { + return super.contains(o); + } + } + + @Override + public void ensureCapacity(int minCapacity) { + synchronized (lock) { + super.ensureCapacity(minCapacity); + } + } + + @Override + public E get(int index) { + synchronized (lock) { + return super.get(index); + } + } + + @Override + public int indexOf(Object o) { + synchronized (lock) { + return super.indexOf(o); + } + } + + @Override + public int lastIndexOf(Object o) { + synchronized (lock) { + return super.lastIndexOf(o); + } + } + + @Override + public E remove(int index) { + synchronized (lock) { + return super.remove(index); + } + } + + @Override + public boolean remove(Object o) { + synchronized (lock) { + return super.remove(o); + } + } + + @Override + public boolean removeAll(Collection c) { + synchronized (lock) { + return super.removeAll(c); + } + } + + @Override + public boolean retainAll(Collection c) { + synchronized (lock) { + return super.retainAll(c); + } + } + + @Override + public E set(int index, E element) { + synchronized (lock) { + return super.set(index, element); + } + } + + @Override + public List subList(int fromIndex, int toIndex) { + synchronized (lock) { + return super.subList(fromIndex, toIndex); + } + } + + @Override + public Object[] toArray() { + synchronized (lock) { + return super.toArray(); + } + } + + @Override + public T[] toArray(T[] a) { + synchronized (lock) { + return super.toArray(a); + } + } + + @Override + public void trimToSize() { + synchronized (lock) { + super.trimToSize(); + } + } + + @Override + public ListIterator listIterator() { + return new ListItr(0); + } + + @Override + public Iterator iterator() { + return new Itr(); + } + + private class Itr implements Iterator { + + protected int cursor; + protected int lastRet; + final ConcurrentList l; + + public Itr() { + cursor = 0; + lastRet = -1; + l = (ConcurrentList) ConcurrentList.this.clone(); + } + + @Override + public boolean hasNext() { + return cursor < l.size(); + } + + @Override + public E next() { + int i = cursor; + if (i >= l.size()) { + throw new NoSuchElementException(); + } + cursor = i + 1; + return (E) l.get(lastRet = i); + } + + @Override + public void remove() { + if (lastRet < 0) { + throw new IllegalStateException(); + } + + l.remove(lastRet); + ConcurrentList.this.remove(lastRet); + cursor = lastRet; + lastRet = -1; + } + } + + public class ListItr extends Itr implements ListIterator { + + ListItr(int index) { + super(); + cursor = index; + } + + @Override + public boolean hasPrevious() { + return cursor > 0; + } + + @Override + public int nextIndex() { + return cursor; + } + + @Override + public int previousIndex() { + return cursor - 1; + } + + @Override + public E previous() { + int i = cursor - 1; + if (i < 0) { + throw new NoSuchElementException(); + } + cursor = i; + return (E) l.get(lastRet = i); + } + + @Override + public void set(E e) { + if (lastRet < 0) { + throw new IllegalStateException(); + } + + l.set(lastRet, e); + ConcurrentList.this.set(lastRet, e); + } + + @Override + public void add(E e) { + int i = cursor; + l.add(i, e); + ConcurrentList.this.add(i, e); + cursor = i + 1; + lastRet = -1; + } + } +} \ No newline at end of file diff --git a/common/src/main/java/us/myles/ViaVersion/util/ListWrapper.java b/common/src/main/java/us/myles/ViaVersion/util/ListWrapper.java index 4e3837bfb..9237fd8ce 100644 --- a/common/src/main/java/us/myles/ViaVersion/util/ListWrapper.java +++ b/common/src/main/java/us/myles/ViaVersion/util/ListWrapper.java @@ -5,6 +5,10 @@ import java.util.Iterator; import java.util.List; import java.util.ListIterator; +/** + * @deprecated scary + */ +@Deprecated public abstract class ListWrapper implements List { private final List list;