Move the field cloning reponsibility to FieldCloner.
Dieser Commit ist enthalten in:
Ursprung
8b91e3034d
Commit
dea725e1e3
@ -213,13 +213,16 @@ class InjectedServerConnection {
|
|||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 2070481080950500367L;
|
private static final long serialVersionUID = 2070481080950500367L;
|
||||||
|
|
||||||
|
// Object writer we'll use
|
||||||
|
private final ObjectWriter writer = new ObjectWriter();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onReplacing(Object inserting, Object replacement) {
|
protected void onReplacing(Object inserting, Object replacement) {
|
||||||
// Is this a normal Minecraft object?
|
// Is this a normal Minecraft object?
|
||||||
if (!(inserting instanceof Factory)) {
|
if (!(inserting instanceof Factory)) {
|
||||||
// If so, copy the content of the old element to the new
|
// If so, copy the content of the old element to the new
|
||||||
try {
|
try {
|
||||||
ObjectWriter.copyTo(inserting, replacement, inserting.getClass());
|
writer.copyTo(inserting, replacement, inserting.getClass());
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
reporter.reportDetailed(InjectedServerConnection.this, "Cannot copy old " + inserting +
|
reporter.reportDetailed(InjectedServerConnection.this, "Cannot copy old " + inserting +
|
||||||
" to new.", e, inserting, replacement);
|
" to new.", e, inserting, replacement);
|
||||||
|
@ -66,6 +66,9 @@ public class NetworkServerInjector extends PlayerInjector {
|
|||||||
// Whether or not the player has disconnected
|
// Whether or not the player has disconnected
|
||||||
private boolean hasDisconnected;
|
private boolean hasDisconnected;
|
||||||
|
|
||||||
|
// Used to copy fields
|
||||||
|
private final ObjectWriter writer = new ObjectWriter();
|
||||||
|
|
||||||
public NetworkServerInjector(
|
public NetworkServerInjector(
|
||||||
ClassLoader classLoader, ErrorReporter reporter, Player player,
|
ClassLoader classLoader, ErrorReporter reporter, Player player,
|
||||||
ListenerInvoker invoker, IntegerSet sendingFilters,
|
ListenerInvoker invoker, IntegerSet sendingFilters,
|
||||||
@ -248,7 +251,7 @@ public class NetworkServerInjector extends PlayerInjector {
|
|||||||
@Override
|
@Override
|
||||||
protected void cleanHook() {
|
protected void cleanHook() {
|
||||||
if (serverHandlerRef != null && serverHandlerRef.isCurrentSet()) {
|
if (serverHandlerRef != null && serverHandlerRef.isCurrentSet()) {
|
||||||
ObjectWriter.copyTo(serverHandlerRef.getValue(), serverHandlerRef.getOldValue(), serverHandler.getClass());
|
writer.copyTo(serverHandlerRef.getValue(), serverHandlerRef.getOldValue(), serverHandler.getClass());
|
||||||
serverHandlerRef.revertValue();
|
serverHandlerRef.revertValue();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -23,8 +23,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import com.comphenix.protocol.injector.StructureCache;
|
import com.comphenix.protocol.injector.StructureCache;
|
||||||
import com.comphenix.protocol.reflect.cloning.Cloner;
|
|
||||||
import com.comphenix.protocol.reflect.cloning.IdentityCloner;
|
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,11 +36,6 @@ public class ObjectWriter {
|
|||||||
private static ConcurrentMap<Class, StructureModifier<Object>> cache =
|
private static ConcurrentMap<Class, StructureModifier<Object>> cache =
|
||||||
new ConcurrentHashMap<Class, StructureModifier<Object>>();
|
new ConcurrentHashMap<Class, StructureModifier<Object>>();
|
||||||
|
|
||||||
/**
|
|
||||||
* The default value cloner to use.
|
|
||||||
*/
|
|
||||||
private static final Cloner DEFAULT_CLONER = new IdentityCloner();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a usable structure modifier for the given object type.
|
* Retrieve a usable structure modifier for the given object type.
|
||||||
* <p>
|
* <p>
|
||||||
@ -50,7 +43,7 @@ public class ObjectWriter {
|
|||||||
* @param type - the type of the object we are modifying.
|
* @param type - the type of the object we are modifying.
|
||||||
* @return A structure modifier for the given type.
|
* @return A structure modifier for the given type.
|
||||||
*/
|
*/
|
||||||
private static StructureModifier<Object> getModifier(Class<?> type) {
|
private StructureModifier<Object> getModifier(Class<?> type) {
|
||||||
Class<?> packetClass = MinecraftReflection.getPacketClass();
|
Class<?> packetClass = MinecraftReflection.getPacketClass();
|
||||||
|
|
||||||
// Handle subclasses of the packet class with our custom structure cache
|
// Handle subclasses of the packet class with our custom structure cache
|
||||||
@ -82,26 +75,24 @@ public class ObjectWriter {
|
|||||||
* @param destination - fields to copy to.
|
* @param destination - fields to copy to.
|
||||||
* @param commonType - type containing each field to copy.
|
* @param commonType - type containing each field to copy.
|
||||||
*/
|
*/
|
||||||
public static void copyTo(Object source, Object destination, Class<?> commonType) {
|
public void copyTo(Object source, Object destination, Class<?> commonType) {
|
||||||
// Note that we indicate that public fields will be copied the first time around
|
// Note that we indicate that public fields will be copied the first time around
|
||||||
copyToInternal(source, destination, commonType, DEFAULT_CLONER, true);
|
copyToInternal(source, destination, commonType, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy every field in object A to object B. Each value is copied using the supplied cloner.
|
* Called for every non-static field that will be copied.
|
||||||
* <p>
|
* @param modifierSource - modifier for the original object.
|
||||||
* The two objects must have the same number of fields of the same type.
|
* @param modifierDest - modifier for the new cloned object.
|
||||||
* @param source - fields to copy.
|
* @param fieldIndex - the current field index.
|
||||||
* @param destination - fields to copy to.
|
|
||||||
* @param commonType - type containing each field to copy.
|
|
||||||
* @param valueCloner - a object responsible for copying the content of each field.
|
|
||||||
*/
|
*/
|
||||||
public static void copyTo(Object source, Object destination, Class<?> commonType, Cloner valueCloner) {
|
protected void transformField(StructureModifier<Object> modifierSource, StructureModifier<Object> modifierDest, int fieldIndex) {
|
||||||
copyToInternal(source, destination, commonType, valueCloner, true);
|
Object value = modifierSource.read(fieldIndex);
|
||||||
|
modifierDest.write(fieldIndex, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal method that will actually implement the recursion
|
// Internal method that will actually implement the recursion
|
||||||
private static void copyToInternal(Object source, Object destination, Class<?> commonType, Cloner valueCloner, boolean copyPublic) {
|
private void copyToInternal(Object source, Object destination, Class<?> commonType, boolean copyPublic) {
|
||||||
if (source == null)
|
if (source == null)
|
||||||
throw new IllegalArgumentException("Source cannot be NULL");
|
throw new IllegalArgumentException("Source cannot be NULL");
|
||||||
if (destination == null)
|
if (destination == null)
|
||||||
@ -119,10 +110,9 @@ public class ObjectWriter {
|
|||||||
Field field = modifierSource.getField(i);
|
Field field = modifierSource.getField(i);
|
||||||
int mod = field.getModifiers();
|
int mod = field.getModifiers();
|
||||||
|
|
||||||
// Skip static fields. We also get the "public" field fairly often, so we'll skip that.
|
// Skip static fields. We also get the "public" fields fairly often, so we'll skip that.
|
||||||
if (!Modifier.isStatic(mod) && (!Modifier.isPublic(mod) || copyPublic)) {
|
if (!Modifier.isStatic(mod) && (!Modifier.isPublic(mod) || copyPublic)) {
|
||||||
Object value = modifierSource.read(i);
|
transformField(modifierSource, modifierDest, i);
|
||||||
modifierDest.write(i, valueCloner.clone(value));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +120,7 @@ public class ObjectWriter {
|
|||||||
Class<?> superclass = commonType.getSuperclass();
|
Class<?> superclass = commonType.getSuperclass();
|
||||||
|
|
||||||
if (!superclass.equals(Object.class)) {
|
if (!superclass.equals(Object.class)) {
|
||||||
copyToInternal(source, destination, superclass, valueCloner, false);
|
copyToInternal(source, destination, superclass, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (FieldAccessException e) {
|
} catch (FieldAccessException e) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.comphenix.protocol.reflect.cloning;
|
package com.comphenix.protocol.reflect.cloning;
|
||||||
|
|
||||||
import com.comphenix.protocol.reflect.ObjectWriter;
|
import com.comphenix.protocol.reflect.ObjectWriter;
|
||||||
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
import com.comphenix.protocol.reflect.instances.InstanceProvider;
|
import com.comphenix.protocol.reflect.instances.InstanceProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12,6 +13,9 @@ public class FieldCloner implements Cloner {
|
|||||||
private final Cloner defaultCloner;
|
private final Cloner defaultCloner;
|
||||||
private final InstanceProvider instanceProvider;
|
private final InstanceProvider instanceProvider;
|
||||||
|
|
||||||
|
// Used to clone objects
|
||||||
|
private final ObjectWriter writer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a field cloner that copies objects by reading and writing the internal fields directly.
|
* Constructs a field cloner that copies objects by reading and writing the internal fields directly.
|
||||||
* @param defaultCloner - the default cloner used while copying fields.
|
* @param defaultCloner - the default cloner used while copying fields.
|
||||||
@ -20,6 +24,16 @@ public class FieldCloner implements Cloner {
|
|||||||
public FieldCloner(Cloner defaultCloner, InstanceProvider instanceProvider) {
|
public FieldCloner(Cloner defaultCloner, InstanceProvider instanceProvider) {
|
||||||
this.defaultCloner = defaultCloner;
|
this.defaultCloner = defaultCloner;
|
||||||
this.instanceProvider = instanceProvider;
|
this.instanceProvider = instanceProvider;
|
||||||
|
|
||||||
|
// Remember to clone the value too
|
||||||
|
this.writer = new ObjectWriter() {
|
||||||
|
@Override
|
||||||
|
protected void transformField(StructureModifier<Object> modifierSource,
|
||||||
|
StructureModifier<Object> modifierDest, int fieldIndex) {
|
||||||
|
Object value = modifierSource.read(fieldIndex);
|
||||||
|
modifierDest.write(fieldIndex, getDefaultCloner().clone(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -38,8 +52,8 @@ public class FieldCloner implements Cloner {
|
|||||||
|
|
||||||
Object copy = instanceProvider.create(source.getClass());
|
Object copy = instanceProvider.create(source.getClass());
|
||||||
|
|
||||||
// Copy public and private fields alike. Skip static and transient fields.
|
// Copy public and private fields alike. Skip static fields.
|
||||||
ObjectWriter.copyTo(source, copy, source.getClass(), defaultCloner);
|
writer.copyTo(source, copy, source.getClass());
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,6 +369,8 @@ public class PacketContainerTest {
|
|||||||
private Object[] getArray(Object val) {
|
private Object[] getArray(Object val) {
|
||||||
if (val instanceof Object[])
|
if (val instanceof Object[])
|
||||||
return (Object[]) val;
|
return (Object[]) val;
|
||||||
|
if (val == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
int arrlength = Array.getLength(val);
|
int arrlength = Array.getLength(val);
|
||||||
Object[] outputArray = new Object[arrlength];
|
Object[] outputArray = new Object[arrlength];
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren