Fix missing TileEntity write methods

Fixes #249
This commit is contained in:
Dan Mulloy 2016-08-27 13:07:49 -04:00
parent 828302150a
commit 588f736348
3 changed files with 58 additions and 28 deletions

View File

@ -46,7 +46,7 @@ class TileEntityAccessor<T extends BlockState> {
private boolean writeDetected;
private boolean readDetected;
private TileEntityAccessor() {
TileEntityAccessor() {
// Do nothing
}
@ -59,27 +59,30 @@ class TileEntityAccessor<T extends BlockState> {
if (tileEntityField != null) {
this.tileEntityField = tileEntityField;
Class<?> type = tileEntityField.getField().getType();
// Possible read/write methods
try {
findMethodsUsingASM();
} catch (IOException ex1) {
try {
// Much slower though
findMethodUsingCGLib(state);
} catch (Exception ex2) {
throw new RuntimeException("Cannot find read/write methods in " + type, ex2);
}
}
// Ensure we found them
if (readCompound == null)
throw new RuntimeException("Unable to find read method in " + type);
if (writeCompound == null)
throw new RuntimeException("Unable to find write method in " + type);
findMethods(type, state);
}
}
void findMethods(Class<?> type, T state) {
// Possible read/write methods
try {
findMethodsUsingASM();
} catch (IOException ex1) {
try {
// Much slower though
findMethodUsingCGLib(state);
} catch (Exception ex2) {
throw new RuntimeException("Cannot find read/write methods in " + type, ex2);
}
}
// Ensure we found them
if (readCompound == null)
throw new RuntimeException("Unable to find read method in " + type);
if (writeCompound == null)
throw new RuntimeException("Unable to find write method in " + type);
}
/**
* Find the read/write methods in TileEntity.
* @throws IOException If we cannot find these methods.
@ -90,7 +93,7 @@ class TileEntityAccessor<T extends BlockState> {
final ClassReader reader = new ClassReader(tileEntityClass.getCanonicalName());
final String tagCompoundName = getJarName(MinecraftReflection.getNBTCompoundClass());
final String expectedDesc = "(L" + tagCompoundName + ";)V";
final String expectedDesc = "(L" + tagCompoundName + ";)";
reader.accept(new EmptyClassVisitor() {
@Override
@ -98,7 +101,7 @@ class TileEntityAccessor<T extends BlockState> {
final String methodName = name;
// Detect read/write calls to NBTTagCompound
if (expectedDesc.equals(desc)) {
if (desc.startsWith(expectedDesc)) {
return new EmptyMethodVisitor() {
private int readMethods;
private int writeMethods;
@ -106,9 +109,9 @@ class TileEntityAccessor<T extends BlockState> {
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
// This must be a virtual call on NBTTagCompound that accepts a String
if (opcode == Opcodes.INVOKEVIRTUAL &&
tagCompoundName.equals(owner) &&
desc.startsWith("(Ljava/lang/String")) {
if (opcode == Opcodes.INVOKEVIRTUAL
&& tagCompoundName.equals(owner)
&& desc.startsWith("(Ljava/lang/String")) {
// Is this a write call?
if (desc.endsWith(")V")) {
@ -126,10 +129,12 @@ class TileEntityAccessor<T extends BlockState> {
} else if (writeMethods > readMethods) {
writeCompound = Accessors.getMethodAccessor(tileEntityClass, methodName, nbtCompoundClass);
}
super.visitEnd();
}
};
}
return null;
}
}, 0);

View File

@ -24,6 +24,7 @@ import net.minecraft.server.v1_10_R1.DispenserRegistry;
*/
public class BukkitInitialization {
private static boolean initialized;
private static boolean packaged;
/**
* Initialize Bukkit and ProtocolLib such that we can perfrom unit testing.
@ -34,6 +35,8 @@ public class BukkitInitialization {
// Denote that we're done
initialized = true;
initializePackage();
DispenserRegistry.c(); // Basically registers everything
// Mock the server object
@ -50,7 +53,7 @@ public class BukkitInitialization {
// Inject this fake server
Bukkit.setServer(mockedServer);
initializePackage();
}
}
@ -58,8 +61,11 @@ public class BukkitInitialization {
* Ensure that package names are correctly set up.
*/
public static void initializePackage() {
// Initialize reflection
MinecraftReflection.setMinecraftPackage(Constants.NMS, Constants.OBC);
MinecraftVersion.setCurrentVersion(MinecraftVersion.COMBAT_UPDATE);
if (!packaged) {
packaged = true;
MinecraftReflection.setMinecraftPackage(Constants.NMS, Constants.OBC);
MinecraftVersion.setCurrentVersion(MinecraftVersion.FROSTBURN_UPDATE);
}
}
}

View File

@ -1,3 +1,19 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2016 dmulloy2
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol;
import static org.junit.Assert.assertEquals;
@ -16,6 +32,9 @@ import com.comphenix.protocol.injector.netty.ProtocolRegistry;
import net.minecraft.server.v1_10_R1.PacketLoginInStart;
/**
* @author dmulloy2
*/
public class PacketTypeTest {
@BeforeClass