dynamic, registry driven hazard system

now with 20% more ore dict!
This commit is contained in:
Boblet 2021-09-16 14:00:46 +02:00
parent d5c77d90b5
commit 4b7deebed3
9 changed files with 410 additions and 0 deletions

View File

@ -0,0 +1,52 @@
package com.hbm.hazard;
import java.util.ArrayList;
import java.util.List;
import com.hbm.hazard.type.HazardTypeBase;
public class HazardData {
/*
* Purges all previously loaded data when read, useful for when specific items should fully override ore dict data.
*/
boolean doesOverride = false;
/*
* MUTEX, even more precise to make only specific entries mutually exclusive, for example oredict aliases such as plutonium238 and pu238.
* Does the opposite of overrides, if a previous entry collides with this one, this one will yield.
*
* RESERVED BITS (please keep this up to date)
* -1: base material aliases ("ingotX")
*/
int mutexBits = 0b0000_0000_0000_0000_0000_0000_0000_0000;
List<HazardEntry> entries = new ArrayList();
public HazardData addEntry(HazardTypeBase hazard) {
return this.addEntry(hazard, 1F, false);
}
public HazardData addEntry(HazardTypeBase hazard, float level) {
return this.addEntry(hazard, level, false);
}
public HazardData addEntry(HazardTypeBase hazard, float level, boolean override) {
this.entries.add(new HazardEntry(hazard, level));
this.doesOverride = override;
return this;
}
public HazardData addEntry(HazardEntry entry) {
this.entries.add(entry);
return this;
}
public HazardData setMutex(int mutex) {
this.mutexBits = mutex;
return this;
}
public int getMutex() {
return mutexBits;
}
}

View File

@ -0,0 +1,42 @@
package com.hbm.hazard;
import java.util.ArrayList;
import java.util.List;
import com.hbm.hazard.type.HazardTypeBase;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
public class HazardEntry {
HazardTypeBase type;
float baseLevel;
/*
* Modifiers are evaluated in the order they're being applied to the entry.
*/
List<HazardModifier> mods = new ArrayList();
public HazardEntry(HazardTypeBase type) {
this(type, 1F);
}
public HazardEntry(HazardTypeBase type, float level) {
this.type = type;
this.baseLevel = level;
}
public HazardEntry addMod(HazardModifier mod) {
this.mods.add(mod);
return this;
}
public void applyHazard(ItemStack stack, EntityLivingBase entity) {
type.onUpdate(entity, HazardModifier.evalAllModifiers(stack, entity, baseLevel, mods));
}
public HazardTypeBase getType() {
return this.type;
}
}

View File

@ -0,0 +1,28 @@
package com.hbm.hazard;
import java.util.List;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
public abstract class HazardModifier {
public abstract float modify(ItemStack stack, EntityLivingBase holder, float level);
/**
* Returns the level after applying all modifiers to it, in order.
* @param stack
* @param entity
* @param level
* @param mods
* @return
*/
public static float evalAllModifiers(ItemStack stack, EntityLivingBase entity, float level, List<HazardModifier> mods) {
for(HazardModifier mod : mods) {
level = mod.modify(stack, entity, level);
}
return level;
}
}

View File

@ -0,0 +1,26 @@
package com.hbm.hazard;
import com.hbm.hazard.type.HazardTypeBase;
import com.hbm.hazard.type.HazardTypeRadiation;
import com.hbm.items.special.ItemHazard;
public class HazardRegistry {
public static final HazardTypeBase RADIATION = new HazardTypeRadiation();
public static void registerItems() {
HazardSystem.register("ingotPlutonium", makeData(RADIATION, ItemHazard.pu * ItemHazard.ingot));
}
private static HazardData makeData() { return new HazardData(); }
private static HazardData makeData(HazardTypeBase hazard) { return new HazardData().addEntry(hazard); }
private static HazardData makeData(HazardTypeBase hazard, float level) { return new HazardData().addEntry(hazard, level); }
private static HazardData makeData(HazardTypeBase hazard, float level, boolean override) { return new HazardData().addEntry(hazard, level, override); }
public static void reloadSystem() {
HazardSystem.oreMap.clear();
HazardSystem.itemMap.clear();
HazardSystem.stackMap.clear();
registerItems();
}
}

View File

@ -0,0 +1,169 @@
package com.hbm.hazard;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import com.hbm.interfaces.Untested;
import com.hbm.inventory.RecipesCommon.ComparableStack;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
import scala.xml.PrettyPrinter.Item;
@Untested
public class HazardSystem {
/*
* Map for OreDict entries, always evaluated first. Avoid registering HazardData with 'doesOverride', as internal order is based on the item's ore dict keys.
*/
public static final HashMap<String, HazardData> oreMap = new HashMap();
/*
* Map for items, either with wildcard meta or stuff that's expected to have a variety of damage values, like tools.
*/
public static final HashMap<Item, HazardData> itemMap = new HashMap();
/*
* Very specific stacks with item and meta matching. ComparableStack does not support NBT matching, to scale hazards with NBT please use HazardModifiers.
*/
public static final HashMap<ComparableStack, HazardData> stackMap = new HashMap();
/*
* For items that should, for whichever reason, be completely exempt from the hazard system.
*/
public static final HashSet<ComparableStack> blacklist = new HashSet();
/**
* Automatically casts the first parameter and registers it to the HazSys
* @param o
* @param data
*/
public static void register(Object o, HazardData data) {
if(o instanceof String)
oreMap.put((String)o, data);
if(o instanceof Item)
itemMap.put((Item)o, data);
if(o instanceof ItemStack)
stackMap.put(new ComparableStack((ItemStack)o), data);
if(o instanceof ComparableStack)
stackMap.put((ComparableStack)o, data);
}
/**
* Prevents the stack from returning any HazardData
* @param stack
*/
public static void blacklist(ItemStack stack) {
blacklist.add(new ComparableStack(stack).makeSingular());
}
public static boolean isItemBlacklisted(ItemStack stack) {
return blacklist.contains(new ComparableStack(stack).makeSingular());
}
/**
* Will return a full list of applicable HazardEntries for this stack.
* <br><br>ORDER:
* <ol>
* <li>ore dict (if multiple keys, in order of the ore dict keys for this stack)
* <li>item
* <li>item stack
* </ol>
*
* "Applicable" means that entries that are overridden or excluded via mutex are not in this list.
* Entries that are marked as "overriding" will delete all fetched entries that came before it.
* Entries that use mutex will prevent subsequent entries from being considered, shall they collide. The mutex system already assumes that
* two keys are the same in priority, so the flipped order doesn't matter.
* @param stack
* @return
*/
public static List<HazardEntry> getHazardsFromStack(ItemStack stack) {
if(isItemBlacklisted(stack)) {
return new ArrayList();
}
List<HazardData> chronological = new ArrayList();
/// ORE DICT ///
int[] ids = OreDictionary.getOreIDs(stack);
for(int id : ids) {
String name = OreDictionary.getOreName(id);
if(oreMap.containsKey(name))
chronological.add(oreMap.get(name));
}
/// ITEM ///
if(itemMap.containsKey(stack.getItem()))
chronological.add(itemMap.get(stack.getItem()));
/// STACK ///
ComparableStack comp = new ComparableStack(stack).makeSingular();
if(stackMap.containsKey(comp))
chronological.add(stackMap.get(comp));
List<HazardEntry> entries = new ArrayList();
int mutex = 0;
for(HazardData data : chronological) {
//if the current data is marked as an override, purge all previous data
if(data.doesOverride)
entries.clear();
if((data.getMutex() & mutex) == 0) {
entries.addAll(data.entries);
mutex = mutex | data.getMutex();
}
}
return entries;
}
/**
* Will grab and iterate through all assigned hazards of the given stack and apply their effects to the holder.
* @param stack
* @param entity
*/
public static void applyHazards(ItemStack stack, EntityLivingBase entity) {
List<HazardEntry> hazards = getHazardsFromStack(stack);
for(HazardEntry hazard : hazards) {
hazard.applyHazard(stack, entity);
}
}
/**
* Will apply the effects of all carried items, including the armor inventory.
* @param player
*/
public static void updatePlayerInventory(EntityPlayer player) {
for(ItemStack stack : player.inventory.mainInventory) {
if(stack != null) {
applyHazards(stack, player);
}
}
for(ItemStack stack : player.inventory.armorInventory) {
if(stack != null) {
applyHazards(stack, player);
}
}
}
@SideOnly(Side.CLIENT)
public static void addFullTooltip(ItemStack stack, EntityPlayer player, List list) {
List<HazardEntry> hazards = getHazardsFromStack(stack);
for(HazardEntry hazard : hazards) {
hazard.type.addHazardInformation(player, list, hazard.baseLevel, stack, hazard.mods);
}
}
}

View File

@ -0,0 +1,32 @@
package com.hbm.hazard.type;
import java.util.List;
import com.hbm.hazard.HazardModifier;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
public abstract class HazardTypeBase {
/**
* Does the thing. Called by HazardEntry.applyHazard
* @param target the holder
* @param level the final level after calculating all the modifiers
*/
public abstract void onUpdate(EntityLivingBase target, float level);
/**
* Adds item tooltip info. Called by Item.addInformation
* @param player
* @param list
* @param level the base level, mods are passed separately
* @param stack
* @param modifiers
*/
@SideOnly(Side.CLIENT)
public abstract void addHazardInformation(EntityPlayer player, List list, float level, ItemStack stack, List<HazardModifier> modifiers);
}

View File

@ -0,0 +1,55 @@
package com.hbm.hazard.type;
import java.util.List;
import com.hbm.config.GeneralConfig;
import com.hbm.hazard.HazardModifier;
import com.hbm.items.ModItems;
import com.hbm.util.ContaminationUtil;
import com.hbm.util.I18nUtil;
import com.hbm.util.ContaminationUtil.ContaminationType;
import com.hbm.util.ContaminationUtil.HazardType;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
public class HazardTypeRadiation extends HazardTypeBase {
@Override
public void onUpdate(EntityLivingBase target, float level) {
boolean reacher = false;
if(target instanceof EntityPlayer && !GeneralConfig.enable528)
reacher = ((EntityPlayer) target).inventory.hasItem(ModItems.reacher);
if(level > 0) {
float rad = level / 20F;
if(reacher)
rad = (float) Math.min(Math.sqrt(rad), rad); //to prevent radiation from going up when being <1
ContaminationUtil.contaminate(target, HazardType.RADIATION, ContaminationType.CREATIVE, rad);
}
}
@Override
@SideOnly(Side.CLIENT)
public void addHazardInformation(EntityPlayer player, List list, float level, ItemStack stack, List<HazardModifier> modifiers) {
level = HazardModifier.evalAllModifiers(stack, player, level, modifiers);
list.add(EnumChatFormatting.GREEN + "[" + I18nUtil.resolveKey("trait.radioactive") + "]");
String rad = "" + (Math.floor(level* 1000) / 1000);
list.add(EnumChatFormatting.YELLOW + (rad + "RAD/s"));
if(stack.stackSize > 1) {
list.add(EnumChatFormatting.YELLOW + "Stack: " + ((Math.floor(level * 1000 * stack.stackSize) / 1000) + "RAD/s"));
}
}
}

View File

@ -67,6 +67,7 @@ import com.hbm.handler.imc.IMCCentrifuge;
import com.hbm.handler.imc.IMCCrystallizer;
import com.hbm.handler.imc.IMCHandler;
import com.hbm.handler.radiation.ChunkRadiationManager;
import com.hbm.hazard.HazardRegistry;
import com.hbm.inventory.*;
import com.hbm.items.ModItems;
import com.hbm.lib.HbmWorld;
@ -250,6 +251,7 @@ public class MainRegistry {
CraftingManager.mainRegistry();
AssemblerRecipes.preInit(PreEvent.getModConfigurationDirectory());
SiegeTier.registerTiers();
HazardRegistry.registerItems();
Library.superuser.add("192af5d7-ed0f-48d8-bd89-9d41af8524f8");
Library.superuser.add("5aee1e3d-3767-4987-a222-e7ce1fbdf88e");

View File

@ -14,6 +14,7 @@ import com.hbm.extprop.HbmPlayerProps;
import com.hbm.handler.ArmorModHandler;
import com.hbm.handler.HTTPHandler;
import com.hbm.handler.HazmatRegistry;
import com.hbm.hazard.HazardSystem;
import com.hbm.interfaces.IHoldableWeapon;
import com.hbm.interfaces.IItemHUD;
import com.hbm.interfaces.Spaghetti;
@ -528,6 +529,9 @@ public class ModEventHandlerClient {
}
}
}
/// HAZARDS ///
HazardSystem.addFullTooltip(stack, event.entityPlayer, list);
}
private ResourceLocation ashes = new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_ash.png");