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.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
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.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||
import com.comphenix.protocol.wrappers.ChunkPosition;
|
||||
|
||||
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) {
|
||||
// Automatically wrap all parameters to the delegate with a NULL check
|
||||
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