|
24 | 24 | import java.util.Map;
|
25 | 25 | import java.util.concurrent.ConcurrentHashMap;
|
26 | 26 |
|
| 27 | +import org.bukkit.Bukkit; |
| 28 | +import org.bukkit.entity.Player; |
| 29 | + |
27 | 30 | import com.comphenix.protocol.ProtocolLibrary;
|
28 | 31 | import com.comphenix.protocol.error.ErrorReporter;
|
29 | 32 | import com.comphenix.protocol.error.Report;
|
30 | 33 | import com.comphenix.protocol.error.ReportType;
|
31 | 34 | import com.comphenix.protocol.injector.PacketConstructor.Unwrapper;
|
32 | 35 | import com.comphenix.protocol.reflect.FieldUtils;
|
33 | 36 | import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
| 37 | +import com.comphenix.protocol.utility.MinecraftReflection; |
34 | 38 | import com.google.common.primitives.Primitives;
|
35 | 39 |
|
36 | 40 | /**
|
@@ -182,20 +186,55 @@ public Object unwrapItem(Object wrappedObject) {
|
182 | 186 | Report.newBuilder(REPORT_SECURITY_LIMITATION).error(e).callerParam(type)
|
183 | 187 | );
|
184 | 188 | } catch (NoSuchMethodException e) {
|
| 189 | + // Maybe it's a proxy? |
| 190 | + Unwrapper proxyUnwrapper = getProxyUnwrapper(type); |
| 191 | + if (proxyUnwrapper != null) |
| 192 | + return proxyUnwrapper; |
| 193 | + |
185 | 194 | // Try getting the field unwrapper too
|
186 | 195 | Unwrapper fieldUnwrapper = getFieldUnwrapper(type);
|
187 |
| - |
188 | 196 | if (fieldUnwrapper != null)
|
189 | 197 | return fieldUnwrapper;
|
190 | 198 | else
|
191 | 199 | reporter.reportDetailed(this,
|
192 | 200 | Report.newBuilder(REPORT_CANNOT_FIND_UNWRAP_METHOD).error(e).callerParam(type));
|
193 | 201 | }
|
194 |
| - |
| 202 | + |
195 | 203 | // Default method
|
196 | 204 | return null;
|
197 | 205 | }
|
198 |
| - |
| 206 | + |
| 207 | + // Players should /always/ be able to be unwrapped |
| 208 | + // We should only get here if the 'Player' is a proxy |
| 209 | + private Unwrapper getProxyUnwrapper(final Class<?> type) { |
| 210 | + try { |
| 211 | + if (Player.class.isAssignableFrom(type)) { |
| 212 | + final Method getHandle = MinecraftReflection.getCraftPlayerClass().getMethod("getHandle"); |
| 213 | + |
| 214 | + Unwrapper unwrapper = new Unwrapper() { |
| 215 | + @Override |
| 216 | + public Object unwrapItem(Object wrapped) { |
| 217 | + try { |
| 218 | + return getHandle.invoke(((Player) wrapped).getPlayer()); |
| 219 | + } catch (Throwable ex) { |
| 220 | + try { |
| 221 | + return getHandle.invoke(Bukkit.getPlayer(((Player) wrapped).getUniqueId())); |
| 222 | + } catch (ReflectiveOperationException ex1) { |
| 223 | + throw new RuntimeException("Failed to unwrap proxy " + wrapped, ex); |
| 224 | + } |
| 225 | + } |
| 226 | + } |
| 227 | + }; |
| 228 | + |
| 229 | + unwrapperCache.put(type, unwrapper); |
| 230 | + return unwrapper; |
| 231 | + } |
| 232 | + } catch (Throwable ignored) { |
| 233 | + } |
| 234 | + |
| 235 | + return null; |
| 236 | + } |
| 237 | + |
199 | 238 | /**
|
200 | 239 | * Retrieve a cached unwrapper using the handle field.
|
201 | 240 | * @param type - a cached field unwrapper.
|
|
0 commit comments