mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-12-29 04:27:38 +01:00
Rewrite the packet metadata API based on the NMS packet
Meta, if created, will persist between creation and listening.
This commit is contained in:
parent
1f5692a0c7
commit
1b23e9ec22
@ -17,37 +17,15 @@
|
|||||||
|
|
||||||
package com.comphenix.protocol.events;
|
package com.comphenix.protocol.events;
|
||||||
|
|
||||||
import java.io.DataInput;
|
import java.io.*;
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.DataOutput;
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.Sound;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.WorldType;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.potion.PotionEffectType;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
import com.comphenix.protocol.PacketType;
|
||||||
import com.comphenix.protocol.PacketType.Protocol;
|
import com.comphenix.protocol.PacketType.Protocol;
|
||||||
import com.comphenix.protocol.injector.StructureCache;
|
import com.comphenix.protocol.injector.StructureCache;
|
||||||
@ -55,41 +33,15 @@ import com.comphenix.protocol.reflect.EquivalentConverter;
|
|||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
import com.comphenix.protocol.reflect.ObjectWriter;
|
import com.comphenix.protocol.reflect.ObjectWriter;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
import com.comphenix.protocol.reflect.cloning.AggregateCloner;
|
import com.comphenix.protocol.reflect.cloning.*;
|
||||||
import com.comphenix.protocol.reflect.cloning.AggregateCloner.BuilderParameters;
|
import com.comphenix.protocol.reflect.cloning.AggregateCloner.BuilderParameters;
|
||||||
import com.comphenix.protocol.reflect.cloning.BukkitCloner;
|
|
||||||
import com.comphenix.protocol.reflect.cloning.Cloner;
|
|
||||||
import com.comphenix.protocol.reflect.cloning.CollectionCloner;
|
|
||||||
import com.comphenix.protocol.reflect.cloning.FieldCloner;
|
|
||||||
import com.comphenix.protocol.reflect.cloning.ImmutableDetector;
|
|
||||||
import com.comphenix.protocol.reflect.cloning.OptionalCloner;
|
|
||||||
import com.comphenix.protocol.reflect.cloning.SerializableCloner;
|
|
||||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||||
import com.comphenix.protocol.utility.MinecraftMethods;
|
import com.comphenix.protocol.utility.MinecraftMethods;
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.comphenix.protocol.utility.StreamSerializer;
|
import com.comphenix.protocol.utility.StreamSerializer;
|
||||||
import com.comphenix.protocol.wrappers.*;
|
import com.comphenix.protocol.wrappers.*;
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.ChatType;
|
import com.comphenix.protocol.wrappers.EnumWrappers.*;
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.ChatVisibility;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.ClientCommand;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.CombatEventType;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.Difficulty;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.EnumConverter;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.Hand;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.ItemSlot;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.Particle;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerAction;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerDigType;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.ResourcePackStatus;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.ScoreboardAction;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.SoundCategory;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.TitleAction;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.WorldBorderAction;
|
|
||||||
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
||||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||||
@ -101,6 +53,15 @@ import com.google.common.collect.Sets;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.UnpooledByteBufAllocator;
|
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.WorldType;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.potion.PotionEffectType;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a Minecraft packet indirectly.
|
* Represents a Minecraft packet indirectly.
|
||||||
*
|
*
|
||||||
@ -1201,21 +1162,52 @@ public class PacketContainer implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---- Metadata
|
// ---- Metadata
|
||||||
// This map will only be initialized if it is actually used
|
|
||||||
private Map<String, Object> metadata;
|
/**
|
||||||
|
* Gets the metadata value for a given key if it exists. Packet metadata expires after a minute, which is far longer
|
||||||
|
* than a packet will ever be held in processing.
|
||||||
|
*
|
||||||
|
* @param key Metadata key
|
||||||
|
* @param <T> Metadata type
|
||||||
|
* @return The metadata value, or an empty optional
|
||||||
|
*/
|
||||||
|
public <T> Optional<T> getMeta(String key) {
|
||||||
|
return PacketMetadata.get(handle, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the metadata value at a given key. Packet metadata expires after a minute, which is far longer than a packet
|
||||||
|
* will ever be held in processing.
|
||||||
|
*
|
||||||
|
* @param key Metadata key
|
||||||
|
* @param value Metadata value
|
||||||
|
* @param <T> Metadata type
|
||||||
|
*/
|
||||||
|
public <T> void setMeta(String key, T value) {
|
||||||
|
PacketMetadata.set(handle, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the metadata for a given key if it exists.
|
||||||
|
* @param key Key to remove meta for
|
||||||
|
*/
|
||||||
|
public void removeMeta(String key) {
|
||||||
|
PacketMetadata.remove(handle, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Old Metadata API
|
||||||
|
// Scheduled for removal in 4.5
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the metadata value for a given key.
|
* Gets the metadata value for a given key.
|
||||||
*
|
*
|
||||||
* @param key Metadata key
|
* @param key Metadata key
|
||||||
* @return Metadata value, or null if nonexistent.
|
* @return Metadata value, or null if nonexistent.
|
||||||
|
* @deprecated Replaced with {@link #getMeta(String)}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Object getMetadata(String key) {
|
public Object getMetadata(String key) {
|
||||||
if (metadata != null) {
|
return getMeta(key).orElse(null);
|
||||||
return metadata.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1225,13 +1217,11 @@ public class PacketContainer implements Serializable {
|
|||||||
*
|
*
|
||||||
* @param key Metadata key
|
* @param key Metadata key
|
||||||
* @param value Metadata value
|
* @param value Metadata value
|
||||||
|
* @deprecated Replaced by {@link #setMeta(String, Object)}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void addMetadata(String key, Object value) {
|
public void addMetadata(String key, Object value) {
|
||||||
if (metadata == null) {
|
setMeta(key, value);
|
||||||
metadata = new HashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata.put(key, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1241,18 +1231,11 @@ public class PacketContainer implements Serializable {
|
|||||||
*
|
*
|
||||||
* @param key Metadata key
|
* @param key Metadata key
|
||||||
* @return The previous value, or null if nonexistant.
|
* @return The previous value, or null if nonexistant.
|
||||||
|
* @deprecated Replaced by {@link #removeMeta(String)}. This one was pretty much just for naming consistency.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Object removeMetadata(String key) {
|
public Object removeMetadata(String key) {
|
||||||
if (metadata != null) {
|
return PacketMetadata.remove(handle, key).orElseGet(null);
|
||||||
Object value = metadata.remove(key);
|
|
||||||
if (metadata.isEmpty()) {
|
|
||||||
metadata = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1260,9 +1243,11 @@ public class PacketContainer implements Serializable {
|
|||||||
*
|
*
|
||||||
* @param key Metadata key
|
* @param key Metadata key
|
||||||
* @return True if this packet has metadata for the key, false if not.
|
* @return True if this packet has metadata for the key, false if not.
|
||||||
|
* @deprecated Replaced with {@code getMeta(key).isPresent()}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public boolean hasMetadata(String key) {
|
public boolean hasMetadata(String key) {
|
||||||
return metadata != null && metadata.containsKey(key);
|
return getMeta(key).isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,143 @@
|
|||||||
|
/**
|
||||||
|
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||||
|
* Copyright (C) 2017 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.events;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.google.common.cache.Cache;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores and retrieves metadata for applicable packet objects.
|
||||||
|
* @author dmulloy2
|
||||||
|
*/
|
||||||
|
class PacketMetadata {
|
||||||
|
|
||||||
|
private static class MetaObject<T> {
|
||||||
|
private final String key;
|
||||||
|
private final T value;
|
||||||
|
|
||||||
|
private MetaObject(String key, T value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o == this) return true;
|
||||||
|
|
||||||
|
if (o instanceof MetaObject) {
|
||||||
|
MetaObject that = (MetaObject) o;
|
||||||
|
return that.key.equals(this.key) &&
|
||||||
|
that.value.equals(this.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "MetaObject[" + key + "=" + value + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Packet meta cache
|
||||||
|
private static Cache<Object, List<MetaObject>> META_CACHE;
|
||||||
|
|
||||||
|
public static <T> Optional<T> get(Object packet, String key) {
|
||||||
|
Validate.notNull(key, "Null keys are not permitted!");
|
||||||
|
|
||||||
|
if (META_CACHE == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<MetaObject> meta = META_CACHE.getIfPresent(packet);
|
||||||
|
if (meta == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (MetaObject object : meta) {
|
||||||
|
if (object.key.equals(key)) {
|
||||||
|
return Optional.of((T) object.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void createCache() {
|
||||||
|
META_CACHE = CacheBuilder
|
||||||
|
.newBuilder()
|
||||||
|
.expireAfterWrite(1, TimeUnit.MINUTES)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void set(Object packet, String key, T value) {
|
||||||
|
Validate.notNull(key, "Null keys are not permitted!");
|
||||||
|
|
||||||
|
if (META_CACHE == null) {
|
||||||
|
createCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<MetaObject> packetMeta;
|
||||||
|
|
||||||
|
try {
|
||||||
|
packetMeta = META_CACHE.get(packet, ArrayList::new);
|
||||||
|
} catch (ExecutionException ex) {
|
||||||
|
// Not possible, but let's humor the array list constructor having an issue
|
||||||
|
packetMeta = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
packetMeta.removeIf(meta -> meta.key.equals(key));
|
||||||
|
packetMeta.add(new MetaObject<>(key, value));
|
||||||
|
META_CACHE.put(packet, packetMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Optional<T> remove(Object packet, String key) {
|
||||||
|
Validate.notNull(key, "Null keys are not permitted!");
|
||||||
|
|
||||||
|
if (META_CACHE == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<MetaObject> packetMeta = META_CACHE.getIfPresent(packet);
|
||||||
|
if (packetMeta == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<T> value = Optional.empty();
|
||||||
|
Iterator<MetaObject> iter = packetMeta.iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
MetaObject meta = iter.next();
|
||||||
|
if (meta.key.equals(key)) {
|
||||||
|
value = Optional.of((T) meta.value);
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user