VillagerTradeLimiter/src/com/pretzel/dev/villagertradelimiter/nms/NBTList.java

430 lines
8.1 KiB
Java

package com.pretzel.dev.villagertradelimiter.nms;
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;
import com.pretzel.dev.villagertradelimiter.nms.utils.MinecraftVersion;
import com.pretzel.dev.villagertradelimiter.nms.utils.nmsmappings.ReflectionMethod;
/**
* Abstract List implementation for ListCompounds
*
* @author tr7zw
*
* @param <T>
*/
public abstract class NBTList<T> implements List<T> {
private String listName;
private NBTCompound parent;
private NBTType type;
protected Object listObject;
protected NBTList(NBTCompound owner, String name, NBTType type, Object list) {
parent = owner;
listName = name;
this.type = type;
this.listObject = list;
}
/**
* @return Name of this list-compound
*/
public String getName() {
return listName;
}
/**
* @return The Compound's parent Object
*/
public NBTCompound getParent() {
return parent;
}
protected void save() {
parent.set(listName, listObject);
}
protected abstract Object asTag(T object);
@Override
public boolean add(T element) {
try {
parent.getWriteLock().lock();
if (MinecraftVersion.getVersion().getVersionId() >= MinecraftVersion.MC1_14_R1.getVersionId()) {
ReflectionMethod.LIST_ADD.run(listObject, size(), asTag(element));
} else {
ReflectionMethod.LEGACY_LIST_ADD.run(listObject, asTag(element));
}
save();
return true;
} catch (Exception ex) {
throw new NbtApiException(ex);
} finally {
parent.getWriteLock().unlock();
}
}
@Override
public void add(int index, T element) {
try {
parent.getWriteLock().lock();
if (MinecraftVersion.getVersion().getVersionId() >= MinecraftVersion.MC1_14_R1.getVersionId()) {
ReflectionMethod.LIST_ADD.run(listObject, index, asTag(element));
} else {
ReflectionMethod.LEGACY_LIST_ADD.run(listObject, asTag(element));
}
save();
} catch (Exception ex) {
throw new NbtApiException(ex);
} finally {
parent.getWriteLock().unlock();
}
}
@Override
public T set(int index, T element) {
try {
parent.getWriteLock().lock();
T prev = get(index);
ReflectionMethod.LIST_SET.run(listObject, index, asTag(element));
save();
return prev;
} catch (Exception ex) {
throw new NbtApiException(ex);
} finally {
parent.getWriteLock().unlock();
}
}
public T remove(int i) {
try {
parent.getWriteLock().lock();
T old = get(i);
ReflectionMethod.LIST_REMOVE_KEY.run(listObject, i);
save();
return old;
} catch (Exception ex) {
throw new NbtApiException(ex);
} finally {
parent.getWriteLock().unlock();
}
}
public int size() {
try {
parent.getReadLock().lock();
return (int) ReflectionMethod.LIST_SIZE.run(listObject);
} catch (Exception ex) {
throw new NbtApiException(ex);
} finally {
parent.getReadLock().unlock();
}
}
/**
* @return The type that this list contains
*/
public NBTType getType() {
return type;
}
@Override
public boolean isEmpty() {
return size() == 0;
}
@Override
public void clear() {
while (!isEmpty()) {
remove(0);
}
}
@Override
public boolean contains(Object o) {
try {
parent.getReadLock().lock();
for (int i = 0; i < size(); i++) {
if (o.equals(get(i)))
return true;
}
return false;
} finally {
parent.getReadLock().unlock();
}
}
@Override
public int indexOf(Object o) {
try {
parent.getReadLock().lock();
for (int i = 0; i < size(); i++) {
if (o.equals(get(i)))
return i;
}
return -1;
} finally {
parent.getReadLock().unlock();
}
}
@Override
public boolean addAll(Collection<? extends T> c) {
try {
parent.getWriteLock().lock();
int size = size();
for (T ele : c) {
add(ele);
}
return size != size();
} finally {
parent.getWriteLock().unlock();
}
}
@Override
public boolean addAll(int index, Collection<? extends T> c) {
try {
parent.getWriteLock().lock();
int size = size();
for (T ele : c) {
add(index++, ele);
}
return size != size();
} finally {
parent.getWriteLock().unlock();
}
}
@Override
public boolean containsAll(Collection<?> c) {
try {
parent.getReadLock().lock();
for (Object ele : c) {
if (!contains(ele))
return false;
}
return true;
} finally {
parent.getReadLock().unlock();
}
}
@Override
public int lastIndexOf(Object o) {
try {
parent.getReadLock().lock();
int index = -1;
for (int i = 0; i < size(); i++) {
if (o.equals(get(i)))
index = i;
}
return index;
} finally {
parent.getReadLock().unlock();
}
}
@Override
public boolean removeAll(Collection<?> c) {
try {
parent.getWriteLock().lock();
int size = size();
for (Object obj : c) {
remove(obj);
}
return size != size();
} finally {
parent.getWriteLock().unlock();
}
}
@Override
public boolean retainAll(Collection<?> c) {
try {
parent.getWriteLock().lock();
int size = size();
for (Object obj : c) {
for (int i = 0; i < size(); i++) {
if (!obj.equals(get(i))) {
remove(i--);
}
}
}
return size != size();
} finally {
parent.getWriteLock().unlock();
}
}
@Override
public boolean remove(Object o) {
try {
parent.getWriteLock().lock();
int size = size();
int id = -1;
while ((id = indexOf(o)) != -1) {
remove(id);
}
return size != size();
} finally {
parent.getWriteLock().unlock();
}
}
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
private int index = -1;
@Override
public boolean hasNext() {
return size() > index + 1;
}
@Override
public T next() {
if (!hasNext())
throw new NoSuchElementException();
return get(++index);
}
@Override
public void remove() {
NBTList.this.remove(index);
index--;
}
};
}
@Override
public ListIterator<T> listIterator() {
return listIterator(0);
}
@Override
public ListIterator<T> listIterator(int startIndex) {
final NBTList<T> list = this;
return new ListIterator<T>() {
int index = startIndex - 1;
@Override
public void add(T e) {
list.add(index, e);
}
@Override
public boolean hasNext() {
return size() > index + 1;
}
@Override
public boolean hasPrevious() {
return index >= 0 && index <= size();
}
@Override
public T next() {
if (!hasNext())
throw new NoSuchElementException();
return get(++index);
}
@Override
public int nextIndex() {
return index + 1;
}
@Override
public T previous() {
if (!hasPrevious())
throw new NoSuchElementException("Id: " + (index - 1));
return get(index--);
}
@Override
public int previousIndex() {
return index - 1;
}
@Override
public void remove() {
list.remove(index);
index--;
}
@Override
public void set(T e) {
list.set(index, e);
}
};
}
@Override
public Object[] toArray() {
try {
parent.getReadLock().lock();
Object[] ar = new Object[size()];
for (int i = 0; i < size(); i++)
ar[i] = get(i);
return ar;
} finally {
parent.getReadLock().unlock();
}
}
@SuppressWarnings("unchecked")
@Override
public <E> E[] toArray(E[] a) {
try {
parent.getReadLock().lock();
E[] ar = Arrays.copyOf(a, size());
Arrays.fill(ar, null);
Class<?> arrayclass = a.getClass().getComponentType();
for (int i = 0; i < size(); i++) {
T obj = get(i);
if (arrayclass.isInstance(obj)) {
ar[i] = (E) get(i);
} else {
throw new ArrayStoreException("The array does not match the objects stored in the List.");
}
}
return ar;
} finally {
parent.getReadLock().unlock();
}
}
@Override
public List<T> subList(int fromIndex, int toIndex) {
try {
parent.getReadLock().lock();
ArrayList<T> list = new ArrayList<>();
for (int i = fromIndex; i < toIndex; i++)
list.add(get(i));
return list;
} finally {
parent.getReadLock().unlock();
}
}
@Override
public String toString() {
try {
parent.getReadLock().lock();
return listObject.toString();
} finally {
parent.getReadLock().unlock();
}
}
}