Add the ability to read and write ChunkPositions.
Dieser Commit ist enthalten in:
Ursprung
5bb6f7649a
Commit
a567721114
@ -25,6 +25,9 @@ import java.io.ObjectOutputStream;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
@ -40,6 +43,8 @@ import com.comphenix.protocol.injector.StructureCache;
|
|||||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||||
|
import com.comphenix.protocol.wrappers.ChunkPosition;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
import net.minecraft.server.Packet;
|
||||||
|
|
||||||
@ -327,6 +332,91 @@ public class PacketContainer implements Serializable {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a read/write structure for chunk positions.
|
||||||
|
* @return A modifier for a ChunkPosition.
|
||||||
|
*/
|
||||||
|
public StructureModifier<ChunkPosition> getPositionModifier() {
|
||||||
|
// Convert to and from the Bukkit wrapper
|
||||||
|
return structureModifier.withType(
|
||||||
|
net.minecraft.server.ChunkPosition.class,
|
||||||
|
ChunkPosition.getConverter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a read/write structure for collections of chunk positions.
|
||||||
|
* <p>
|
||||||
|
* This modifier will automatically marshall between the visible ProtocolLib ChunkPosition and the
|
||||||
|
* internal Minecraft ChunkPosition.
|
||||||
|
* @return A modifier for ChunkPosition array fields.
|
||||||
|
*/
|
||||||
|
public StructureModifier<List<ChunkPosition>> getPositionCollectionModifier() {
|
||||||
|
final EquivalentConverter<ChunkPosition> converter = ChunkPosition.getConverter();
|
||||||
|
|
||||||
|
// Convert to and from the ProtocolLib wrapper
|
||||||
|
final StructureModifier<List<ChunkPosition>> modifier = structureModifier.withType(
|
||||||
|
Collection.class,
|
||||||
|
getIgnoreNull(new EquivalentConverter<List<ChunkPosition>>() {
|
||||||
|
private Class<?> collectionType;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public List<ChunkPosition> getSpecific(Object generic) {
|
||||||
|
if (generic instanceof Collection) {
|
||||||
|
List<ChunkPosition> positions = new ArrayList<ChunkPosition>();
|
||||||
|
|
||||||
|
// Save the type
|
||||||
|
collectionType = generic.getClass();
|
||||||
|
|
||||||
|
// Copy everything to a new list
|
||||||
|
for (Object item : (Collection<Object>) generic) {
|
||||||
|
ChunkPosition result = converter.getSpecific(item);
|
||||||
|
|
||||||
|
if (item != null)
|
||||||
|
positions.add(result);
|
||||||
|
}
|
||||||
|
return positions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not valid
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public Object getGeneric(List<ChunkPosition> specific) {
|
||||||
|
// Just go by the first field
|
||||||
|
if (collectionType == null) {
|
||||||
|
collectionType = structureModifier.withType(Collection.class).getFields().get(0).getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<Object> newContainer = (Collection<Object>) DefaultInstances.DEFAULT.getDefault(collectionType);
|
||||||
|
|
||||||
|
// Convert each object
|
||||||
|
for (ChunkPosition position : specific) {
|
||||||
|
Object converted = converter.getGeneric(position);
|
||||||
|
|
||||||
|
if (position == null)
|
||||||
|
newContainer.add(null);
|
||||||
|
else if (converted != null)
|
||||||
|
newContainer.add(converted);
|
||||||
|
}
|
||||||
|
return newContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public Class<List<ChunkPosition>> getSpecificType() {
|
||||||
|
// Damn you Java
|
||||||
|
Class<?> dummy = List.class;
|
||||||
|
return (Class<List<ChunkPosition>>) dummy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
return modifier;
|
||||||
|
}
|
||||||
|
|
||||||
private <TType> EquivalentConverter<TType> getIgnoreNull(final EquivalentConverter<TType> delegate) {
|
private <TType> EquivalentConverter<TType> getIgnoreNull(final EquivalentConverter<TType> delegate) {
|
||||||
// Automatically wrap all parameters to the delegate with a NULL check
|
// Automatically wrap all parameters to the delegate with a NULL check
|
||||||
return new EquivalentConverter<TType>() {
|
return new EquivalentConverter<TType>() {
|
||||||
|
@ -0,0 +1,146 @@
|
|||||||
|
package com.comphenix.protocol.wrappers;
|
||||||
|
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||||
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a immutable net.minecraft.server.ChunkPosition, which represents a integer 3D vector.
|
||||||
|
*
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
public class ChunkPosition {
|
||||||
|
// Use protected members, like Bukkit
|
||||||
|
protected final int x;
|
||||||
|
protected final int y;
|
||||||
|
protected final int z;
|
||||||
|
|
||||||
|
// Used to access a ChunkPosition, in case it's names are changed
|
||||||
|
private static StructureModifier<Integer> intModifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an immutable 3D vector.
|
||||||
|
*/
|
||||||
|
public ChunkPosition(int x, int y, int z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an immutable integer 3D vector from a mutable Bukkit vector.
|
||||||
|
* @param vector - the mutable real Bukkit vector to copy.
|
||||||
|
*/
|
||||||
|
public ChunkPosition(Vector vector) {
|
||||||
|
if (vector == null)
|
||||||
|
throw new IllegalArgumentException("Vector cannot be NULL.");
|
||||||
|
this.x = vector.getBlockX();
|
||||||
|
this.y = vector.getBlockY();
|
||||||
|
this.z = vector.getBlockZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert this instance to an equivalent real 3D vector.
|
||||||
|
* @return Real 3D vector.
|
||||||
|
*/
|
||||||
|
public Vector toVector() {
|
||||||
|
return new Vector(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the x-coordinate.
|
||||||
|
* @return X coordinate.
|
||||||
|
*/
|
||||||
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the y-coordinate.
|
||||||
|
* @return Y coordinate.
|
||||||
|
*/
|
||||||
|
public int getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the z-coordinate.
|
||||||
|
* @return Z coordinate.
|
||||||
|
*/
|
||||||
|
public int getZ() {
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to convert between NMS ChunkPosition and the wrapper instance.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static EquivalentConverter<ChunkPosition> getConverter() {
|
||||||
|
return new EquivalentConverter<ChunkPosition>() {
|
||||||
|
@Override
|
||||||
|
public Object getGeneric(ChunkPosition specific) {
|
||||||
|
return new net.minecraft.server.ChunkPosition(specific.x, specific.z, specific.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChunkPosition getSpecific(Object generic) {
|
||||||
|
if (generic instanceof net.minecraft.server.ChunkPosition) {
|
||||||
|
net.minecraft.server.ChunkPosition other = (net.minecraft.server.ChunkPosition) generic;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (intModifier == null)
|
||||||
|
return new ChunkPosition(other.x, other.y, other.z);
|
||||||
|
} catch (LinkageError e) {
|
||||||
|
// It could happen. If it does, use a structure modifier instead
|
||||||
|
intModifier = new StructureModifier<Object>(other.getClass(), null, false).withType(int.class);
|
||||||
|
|
||||||
|
// Damn it all
|
||||||
|
if (intModifier.size() < 3) {
|
||||||
|
throw new IllegalStateException("Cannot read class " + other.getClass() + " for its integer fields.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intModifier.size() >= 3) {
|
||||||
|
try {
|
||||||
|
return new ChunkPosition(intModifier.read(0), intModifier.read(1), intModifier.read(2));
|
||||||
|
} catch (FieldAccessException e) {
|
||||||
|
// This is an exeptional work-around, so we don't want to burden the caller with the messy details
|
||||||
|
throw new RuntimeException("Field access error.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, return NULL
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thanks Java Generics!
|
||||||
|
@Override
|
||||||
|
public Class<ChunkPosition> getSpecificType() {
|
||||||
|
return ChunkPosition.class;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
// Fast checks
|
||||||
|
if (this == obj) return true;
|
||||||
|
if (obj == null) return false;
|
||||||
|
|
||||||
|
// Only compare objects of similar type
|
||||||
|
if (obj instanceof ChunkPosition) {
|
||||||
|
ChunkPosition other = (ChunkPosition) obj;
|
||||||
|
return x == other.x && y == other.y && z == other.z;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(x, y, z);
|
||||||
|
}
|
||||||
|
}
|
In neuem Issue referenzieren
Einen Benutzer sperren