ForgePatch/src/main/java/net/minecraftforge/common/capabilities/CapabilityDispatcher.java

147 lines
4.9 KiB
Java

/*
* Minecraft Forge
* Copyright (c) 2016-2018.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.capabilities;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Lists;
import net.minecraft.nbt.INBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.util.INBTSerializable;
/**
* A high-speed implementation of a capability delegator.
* This is used to wrap the results of the AttachCapabilitiesEvent.
* It is HIGHLY recommended that you DO NOT use this approach unless
* you MUST delegate to multiple providers instead just implement y
* our handlers using normal if statements.
*
* Internally the handlers are baked into arrays for fast iteration.
* The ResourceLocations will be used for the NBT Key when serializing.
*/
public final class CapabilityDispatcher implements INBTSerializable<NBTTagCompound>, ICapabilityProvider
{
private ICapabilityProvider[] caps;
private INBTSerializable<INBTBase>[] writers;
private String[] names;
public CapabilityDispatcher(Map<ResourceLocation, ICapabilityProvider> list)
{
this(list, null);
}
@SuppressWarnings("unchecked")
public CapabilityDispatcher(Map<ResourceLocation, ICapabilityProvider> list, @Nullable ICapabilityProvider parent)
{
List<ICapabilityProvider> lstCaps = Lists.newArrayList();
List<INBTSerializable<INBTBase>> lstWriters = Lists.newArrayList();
List<String> lstNames = Lists.newArrayList();
if (parent != null) // Parents go first!
{
lstCaps.add(parent);
if (parent instanceof INBTSerializable)
{
lstWriters.add((INBTSerializable<INBTBase>)parent);
lstNames.add("Parent");
}
}
for (Map.Entry<ResourceLocation, ICapabilityProvider> entry : list.entrySet())
{
ICapabilityProvider prov = entry.getValue();
lstCaps.add(prov);
if (prov instanceof INBTSerializable)
{
lstWriters.add((INBTSerializable<INBTBase>)prov);
lstNames.add(entry.getKey().toString());
}
}
caps = lstCaps.toArray(new ICapabilityProvider[lstCaps.size()]);
writers = lstWriters.toArray(new INBTSerializable[lstWriters.size()]);
names = lstNames.toArray(new String[lstNames.size()]);
}
@Override
public boolean hasCapability(@Nonnull Capability<?> capability, @Nullable EnumFacing facing)
{
for (ICapabilityProvider cap : caps)
{
if (cap.hasCapability(capability, facing))
{
return true;
}
}
return false;
}
@Override
@Nullable
public <T> T getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing)
{
for (ICapabilityProvider cap : caps)
{
T ret = cap.getCapability(capability, facing);
if (ret != null)
{
return ret;
}
}
return null;
}
@Override
public NBTTagCompound serializeNBT()
{
NBTTagCompound nbt = new NBTTagCompound();
for (int x = 0; x < writers.length; x++)
{
nbt.setTag(names[x], writers[x].serializeNBT());
}
return nbt;
}
@Override
public void deserializeNBT(NBTTagCompound nbt)
{
for (int x = 0; x < writers.length; x++)
{
if (nbt.hasKey(names[x]))
{
writers[x].deserializeNBT(nbt.getTag(names[x]));
}
}
}
public boolean areCompatible(CapabilityDispatcher other) //Called from ItemStack to compare equality.
{ // Only compares serializeable caps.
if (other == null) return this.writers.length == 0; // Done this way so we can do some pre-checks before doing the costly NBT serialization and compare
if (this.writers.length == 0) return other.writers.length == 0;
return this.serializeNBT().equals(other.serializeNBT());
}
}