Archiviert
13
0

Add the ability to read and write ChunkPositions.

Dieser Commit ist enthalten in:
Kristian S. Stangeland 2012-11-11 07:24:45 +01:00
Ursprung 5bb6f7649a
Commit a567721114
2 geänderte Dateien mit 236 neuen und 0 gelöschten Zeilen

Datei anzeigen

@ -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>() {

Datei anzeigen

@ -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);
}
}