/******************************************************************************* * AbyssalCraft * Copyright (c) 2012 - 2017 Shinoow. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v3 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl-3.0.txt * * Contributors: * Shinoow - implementation ******************************************************************************/ package com.shinoow.abyssalcraft.api.ritual; import java.util.ArrayList; import java.util.List; import java.util.Map; import net.minecraft.block.Block; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraftforge.fml.common.FMLLog; import net.minecraftforge.oredict.OreDictionary; import org.apache.logging.log4j.Level; import com.google.common.collect.Lists; import com.google.common.collect.Maps; /** * Registry class for Necronomicon Rituals * @author shinoow * * @since 1.4 */ public class RitualRegistry { private Map<Integer, Integer> dimToBookType = Maps.newHashMap(); private Map<Integer, String> dimToName = Maps.newHashMap(); private Map<NecronomiconRitual, Integer> ritualToBookType = Maps.newHashMap(); private ArrayList<NecronomiconRitual> rituals = Lists.newArrayList(); private static final RitualRegistry instance = new RitualRegistry(); public static RitualRegistry instance(){ return instance; } /** * Maps a dimension to a book type, in order to specify dimensions where a ritual of that book type can be performed * @param dim The Dimension ID * @param bookType The Necronomicon book type required * * @since 1.4 */ public void addDimensionToBookType(int dim, int bookType){ if(bookType <= 4 && bookType >= 0) if(dim != -1 && dim != 1) dimToBookType.put(dim, bookType); else FMLLog.log("RitualRegistry", Level.ERROR, "You're not allowed to register that Dimension ID: %d", dim); else FMLLog.log("RitualRegistry", Level.ERROR, "Necronomicon book type does not exist: %d", bookType); } /** * Maps a dimension to a name, in order to display it in the Necronomicon if rituals can only be performed in said dimension * @param dim The Dimension ID * @param name A String representing the name * * @since 1.4.5 */ public void addDimensionToName(int dim, String name){ if(dim != -1 && dim != 1) dimToName.put(dim, name); else FMLLog.log("RitualRegistry", Level.ERROR, "You're not allowed to register that Dimension ID: %d", dim); } /** * Maps a dimension to a book type, in order to specify dimensions where a ritual of that book type can be performed,<br> * and maps it to a name, in order to display it in the Necronomicon if rituals can only be performed in said dimension * @param dim The Dimension ID * @param bookType The Necronomicon book type required * @param name A String representing the name * * @since 1.4.5 */ public void addDimensionToBookTypeAndName(int dim, int bookType, String name){ addDimensionToBookType(dim, bookType); addDimensionToName(dim, name); } /** * Checks if any Ritual-related action can be performed in this dimension with the current Necronomicon * @param dim The dimension ID * @param bookType The Necronomicon book type * @return True if the action can be performed, otherwise false * * @since 1.4 */ public boolean canPerformAction(int dim, int bookType){ if(!dimToBookType.containsKey(dim)) return false; return bookType >= dimToBookType.get(dim); } /** * A more sensitive version of {@link #canPerformAction(int, int)} * @param dim The dimension ID * @param bookType The Necronomicon book type * @return True if the book types match, otherwise false * * @since 1.4 */ public boolean sameBookType(int dim, int bookType){ if(!dimToBookType.containsKey(dim)) return false; return bookType == dimToBookType.get(dim); } /** * Registers a Necronomicon Ritual * @param ritual The Ritual, contains all data used to perform it * * @since 1.4 */ public void registerRitual(NecronomiconRitual ritual){ if(ritual.getBookType() <= 4 && ritual.getBookType() >= 0){ for(NecronomiconRitual entry : rituals) if(ritual.getUnlocalizedName().equals(entry.getUnlocalizedName())){ FMLLog.log("RitualRegistry", Level.ERROR, "Necronomicon Ritual already registered: %s", ritual.getUnlocalizedName()); return; } rituals.add(ritual); } else FMLLog.log("RitualRegistry", Level.ERROR, "Necronomicon book type does not exist: %d", ritual.getBookType()); } /** * Used to fetch a list of rituals * @return An ArrayList containing all registered Necronomicon Rituals * * @since 1.4 */ public List<NecronomiconRitual> getRituals(){ return rituals; } /** * Used to fetch the dimension/name mappings * @return A HashMap containing Dimension IDs and Strings associated with them */ public Map<Integer, String> getDimensionNameMappings(){ return dimToName; } /** * Attempts to fetch a ritual * @param dimension The provided dimension * @param bookType The provided book type * @param offerings The provided offerings * @param sacrifice The provided sacrifice (object placed on the altar) * @return A Necronomicon Ritual, or null if none was found * * @since 1.4 */ public NecronomiconRitual getRitual(int dimension, int bookType, ItemStack[] offerings, ItemStack sacrifice){ for(NecronomiconRitual ritual : rituals) if(areRitualsSame(ritual, dimension, bookType, offerings, sacrifice)) return ritual; return null; } /** * Used to check if a Necronomicon Ritual has the same values as the supplied values * @param ritual The ritual in question * @param dimension The supplied dimension ID * @param bookType The supplied book type * @param offerings The supplied offerings * @param sacrifice The supplied sacrifice * @return True if the rituals match, otherwise false * * @since 1.4 */ private boolean areRitualsSame(NecronomiconRitual ritual, int dimension, int bookType, ItemStack[] offerings, ItemStack sacrifice){ if(ritual.getDimension() == dimension || ritual.getDimension() == -1) if(ritual.getBookType() <= bookType) if(ritual.getOfferings() != null && offerings != null) if(areItemStackArraysEqual(ritual.getOfferings(), offerings, ritual.isNBTSensitive())) if(ritual.requiresItemSacrifice() || ritual.getSacrifice() == null && sacrifice.isEmpty() || areObjectsEqual(sacrifice, ritual.getSacrifice(), false)) return true; return false; } private boolean areItemStackArraysEqual(Object[] array1, ItemStack[] array2, boolean nbt){ List<Object> compareList = Lists.newArrayList(array1); List<ItemStack> itemList = Lists.newArrayList(); for(ItemStack item : array2) if(!item.isEmpty()) itemList.add(item); if(itemList.size() == compareList.size()) for(ItemStack item : itemList) for(Object compare : compareList) if(areObjectsEqual(item, compare, nbt)){ compareList.remove(compare); break; } return compareList.isEmpty(); } public boolean areObjectsEqual(ItemStack stack, Object obj, boolean nbt){ if(obj instanceof ItemStack) return areStacksEqual(stack, (ItemStack)obj, nbt); else if(obj instanceof Item) return areStacksEqual(stack, new ItemStack((Item)obj), nbt); else if(obj instanceof Block) return areStacksEqual(stack, new ItemStack((Block)obj), nbt); else if(obj instanceof ItemStack[]){ for(ItemStack item : (ItemStack[])obj) if(areStacksEqual(stack, item, nbt)) return true; } else if(obj instanceof String){ for(ItemStack item : OreDictionary.getOres((String)obj)) if(areStacksEqual(stack, item, nbt)) return true; } else if(obj instanceof List) for(ItemStack item :(List<ItemStack>)obj) if(areStacksEqual(stack, item, nbt)) return true; return false; } public boolean areStacksEqual(ItemStack stack1, ItemStack stack2, boolean nbt){ if(stack1.isEmpty() || stack2.isEmpty()) return false; return nbt ? areStacksEqual(stack1, stack2) && ItemStack.areItemStackTagsEqual(stack2, stack1) : areStacksEqual(stack1, stack2); } public boolean areStacksEqual(ItemStack stack1, ItemStack stack2) { if (stack1.isEmpty() || stack2.isEmpty()) return false; return stack1.getItem() == stack2.getItem() && (stack2.getItemDamage() == OreDictionary.WILDCARD_VALUE || stack1.getItemDamage() == stack2.getItemDamage()); } }