mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-11-27 05:05:24 +01:00
fix exceptions when reloading the server (#1689)
This commit is contained in:
parent
a2bf242097
commit
4f18d37832
@ -4,10 +4,14 @@ import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
final class ListeningList implements List<Object> {
|
||||
@ -25,17 +29,23 @@ final class ListeningList implements List<Object> {
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.original.size();
|
||||
synchronized (this) {
|
||||
return this.original.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.original.isEmpty();
|
||||
synchronized (this) {
|
||||
return this.original.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return this.original.contains(o);
|
||||
synchronized (this) {
|
||||
return this.original.contains(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -43,81 +53,113 @@ final class ListeningList implements List<Object> {
|
||||
return this.original.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super Object> action) {
|
||||
synchronized (this) {
|
||||
this.original.forEach(action);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return this.original.toArray();
|
||||
synchronized (this) {
|
||||
return this.original.toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
//noinspection SuspiciousToArrayCall
|
||||
return this.original.toArray(a);
|
||||
synchronized (this) {
|
||||
//noinspection SuspiciousToArrayCall
|
||||
return this.original.toArray(a);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Object o) {
|
||||
this.processInsert(o);
|
||||
return this.original.add(o);
|
||||
synchronized (this) {
|
||||
this.processInsert(o);
|
||||
return this.original.add(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, Object element) {
|
||||
this.processInsert(element);
|
||||
this.original.add(index, element);
|
||||
synchronized (this) {
|
||||
this.processInsert(element);
|
||||
this.original.add(index, element);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<?> c) {
|
||||
c.forEach(this::processInsert);
|
||||
return this.original.addAll(c);
|
||||
synchronized (this) {
|
||||
c.forEach(this::processInsert);
|
||||
return this.original.addAll(c);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<?> c) {
|
||||
c.forEach(this::processInsert);
|
||||
return this.original.addAll(index, c);
|
||||
synchronized (this) {
|
||||
c.forEach(this::processInsert);
|
||||
return this.original.addAll(index, c);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object set(int index, Object element) {
|
||||
this.processInsert(element);
|
||||
synchronized (this) {
|
||||
this.processInsert(element);
|
||||
|
||||
Object prev = this.original.set(index, element);
|
||||
this.processRemove(prev);
|
||||
Object prev = this.original.set(index, element);
|
||||
this.processRemove(prev);
|
||||
|
||||
return prev;
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
if (this.original.remove(o)) {
|
||||
this.processRemove(o);
|
||||
return true;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (this.original.remove(o)) {
|
||||
this.processRemove(o);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return this.original.containsAll(c);
|
||||
synchronized (this) {
|
||||
//noinspection SlowListContainsAll
|
||||
return this.original.containsAll(c);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(int index) {
|
||||
Object removed = this.original.remove(index);
|
||||
this.processRemove(removed);
|
||||
return removed;
|
||||
synchronized (this) {
|
||||
Object removed = this.original.remove(index);
|
||||
this.processRemove(removed);
|
||||
return removed;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object o) {
|
||||
return this.original.indexOf(o);
|
||||
synchronized (this) {
|
||||
return this.original.indexOf(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object o) {
|
||||
return this.original.lastIndexOf(o);
|
||||
synchronized (this) {
|
||||
return this.original.lastIndexOf(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -132,33 +174,77 @@ final class ListeningList implements List<Object> {
|
||||
|
||||
@Override
|
||||
public List<Object> subList(int fromIndex, int toIndex) {
|
||||
return this.original.subList(fromIndex, toIndex);
|
||||
synchronized (this) {
|
||||
return this.original.subList(fromIndex, toIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
c.forEach(element -> {
|
||||
if (this.original.contains(element)) {
|
||||
this.processRemove(element);
|
||||
}
|
||||
});
|
||||
return this.original.removeAll(c);
|
||||
synchronized (this) {
|
||||
c.forEach(element -> {
|
||||
if (this.original.contains(element)) {
|
||||
this.processRemove(element);
|
||||
}
|
||||
});
|
||||
return this.original.removeAll(c);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeIf(Predicate<? super Object> filter) {
|
||||
synchronized (this) {
|
||||
return this.original.removeIf(object -> {
|
||||
boolean shouldRemove = filter.test(object);
|
||||
if (shouldRemove) {
|
||||
this.processRemove(object);
|
||||
}
|
||||
return shouldRemove;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return this.original.retainAll(c);
|
||||
synchronized (this) {
|
||||
return this.original.retainAll(c);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAll(UnaryOperator<Object> operator) {
|
||||
synchronized (this) {
|
||||
this.original.replaceAll(value -> {
|
||||
Object newValue = operator.apply(value);
|
||||
if (newValue != value) {
|
||||
this.processRemove(value);
|
||||
this.processInsert(newValue);
|
||||
}
|
||||
return newValue;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sort(Comparator<? super Object> c) {
|
||||
synchronized (this) {
|
||||
this.original.sort(c);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.original.forEach(this::processRemove);
|
||||
this.original.clear();
|
||||
synchronized (this) {
|
||||
this.original.forEach(this::processRemove);
|
||||
this.original.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(int index) {
|
||||
return this.original.get(index);
|
||||
synchronized (this) {
|
||||
return this.original.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
private void processInsert(Object element) {
|
||||
|
@ -26,7 +26,6 @@ import io.netty.channel.ChannelFuture;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -205,7 +204,7 @@ public class NetworkManagerInjector implements ChannelListener {
|
||||
//noinspection SynchronizationOnLocalVariableOrMethodParameter
|
||||
synchronized (value) {
|
||||
// override the list field with our list
|
||||
List<Object> newList = Collections.synchronizedList(new ListeningList(value, this.pipelineInjectorHandler));
|
||||
List<Object> newList = new ListeningList(value, this.pipelineInjectorHandler);
|
||||
accessor.set(serverConnection, newList);
|
||||
}
|
||||
}
|
||||
@ -215,7 +214,6 @@ public class NetworkManagerInjector implements ChannelListener {
|
||||
this.injected = true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void close() {
|
||||
if (this.closed || !this.injected) {
|
||||
return;
|
||||
@ -229,10 +227,10 @@ public class NetworkManagerInjector implements ChannelListener {
|
||||
for (Pair<Object, FieldAccessor> list : this.overriddenLists) {
|
||||
// get the value of the field we've overridden, if it is no longer a ListeningList someone probably jumped in
|
||||
// and replaced the field himself - we are out safely as the other person needs to clean the mess...
|
||||
List<Object> value = (List<Object>) list.getSecond().get(list.getFirst());
|
||||
if (value instanceof ListeningList) {
|
||||
Object currentFieldValue = list.getSecond().get(list.getFirst());
|
||||
if (currentFieldValue instanceof ListeningList) {
|
||||
// just reset to the list we wrapped originally
|
||||
ListeningList ourList = (ListeningList) value;
|
||||
ListeningList ourList = (ListeningList) currentFieldValue;
|
||||
List<Object> original = ourList.getOriginal();
|
||||
//noinspection SynchronizationOnLocalVariableOrMethodParameter
|
||||
synchronized (original) {
|
||||
|
Loading…
Reference in New Issue
Block a user