/** * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * Copyright (C) 2015 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.wrappers; import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.FieldAccessor; import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract; import com.comphenix.protocol.utility.MinecraftReflection; import org.jetbrains.annotations.NotNull; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Represents a wrapper around registrable objects. * * @author portlek */ public final class WrappedRegistrable extends AbstractWrapper implements ClonableWrapper { @NotNull private final Factory factory; private WrappedRegistrable( @NotNull final Factory factory, @NotNull final Object handle ) { super(factory.registrableClass); this.factory = factory; setHandle(handle); } @NotNull public static WrappedRegistrable fromHandle( @NotNull final Factory factory, @NotNull final Object handle ) { return new WrappedRegistrable(factory, handle); } @NotNull public static WrappedRegistrable fromHandle( @NotNull final Class registrableClass, @NotNull final Object handle ) { return fromHandle(Factory.getOrCreate(registrableClass), handle); } @NotNull public static WrappedRegistrable fromClassAndKey( @NotNull final Class registrableClass, @NotNull final MinecraftKey key ) { final Factory factory = Factory.getOrCreate(registrableClass); return fromHandle(factory, factory.getHandle(key)); } @NotNull public static WrappedRegistrable fromClassAndKey( @NotNull final Class registrableClass, @NotNull final String key ) { return fromClassAndKey(registrableClass, new MinecraftKey(key)); } @NotNull public static WrappedRegistrable blockEntityType( @NotNull final MinecraftKey key ) { return fromClassAndKey(MinecraftReflection.getBlockEntityTypeClass(), key); } @NotNull public static WrappedRegistrable blockEntityType( @NotNull final String key ) { return blockEntityType(new MinecraftKey(key)); } /** * Gets this registrable object's Minecraft key * * @return The Minecraft key */ public MinecraftKey getKey() { return factory.getKey(handle); } /** * Sets this registrable object's Minecraft key * * @param key Minecraft key */ public void setKey(MinecraftKey key) { setHandle(factory.getHandle(key)); } public WrappedRegistrable deepClone() { return fromHandle(factory, handle); } @Override public String toString() { return "WrappedRegistrable[handle=" + handle + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + getKey().hashCode(); return result; } @Override public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof WrappedRegistrable)) { return false; } final WrappedRegistrable that = (WrappedRegistrable) o; return handle.equals(that.handle) || (getKey() == that.getKey()); } private static final class Factory { private static final Map, Factory> CACHE = new ConcurrentHashMap<>(); @NotNull private final Class registrableClass; @NotNull private final WrappedRegistry registry; @NotNull private final FieldAccessor fieldAccessor; private Factory(@NotNull final Class registrableClass) { this.registrableClass = registrableClass; this.registry = WrappedRegistry.getRegistry(registrableClass); this.fieldAccessor = Accessors.getFieldAccessor( FuzzyReflection.fromClass(registrableClass, true) .getField( FuzzyFieldContract.newBuilder() .typeExact(registrableClass) .build() ) ); } @NotNull public static Factory getOrCreate( @NotNull final Class registrableClass ) { return CACHE.computeIfAbsent(registrableClass, Factory::new); } @NotNull public MinecraftKey getKey(@NotNull final Object handle) { return registry.getKey(fieldAccessor.get(handle)); } @NotNull public Object getHandle(MinecraftKey key) { return registry.get(key); } } }