Initial commit for 3.0

The altar mostly works. Sigils exist. Orbs exist. Living Armor framework exists. Probably some other things.
This commit is contained in:
Nicholas Ignoffo 2018-09-04 19:53:51 -07:00
parent ecebe75f33
commit 26af9d5c6d
1764 changed files with 7049 additions and 90817 deletions

View file

@ -0,0 +1,61 @@
package com.wayoftime.bloodmagic;
import com.google.common.collect.Lists;
import com.wayoftime.bloodmagic.api.BloodMagicPlugin;
import com.wayoftime.bloodmagic.api.IBloodMagicPlugin;
import com.wayoftime.bloodmagic.core.RegistrarBloodMagicBlocks;
import com.wayoftime.bloodmagic.core.util.PluginUtil;
import com.wayoftime.bloodmagic.proxy.IProxy;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import org.apache.commons.lang3.tuple.Pair;
import java.io.File;
import java.util.List;
@Mod(modid = BloodMagic.MODID, name = BloodMagic.NAME, version = BloodMagic.VERSION)
public class BloodMagic {
public static final String MODID = "bloodmagic";
public static final String NAME = "Blood Magic: Alchemical Wizardry";
public static final String VERSION = "${VERSION}";
public static final List<Pair<IBloodMagicPlugin, BloodMagicPlugin>> PLUGINS = Lists.newArrayList();
public static final CreativeTabs TAB_BM = new CreativeTabs(MODID) {
@Override
public ItemStack createIcon() {
return new ItemStack(RegistrarBloodMagicBlocks.BLOOD_ALTAR);
}
};
@SidedProxy(clientSide = "com.wayoftime.bloodmagic.proxy.ClientProxy", serverSide = "com.wayoftime.bloodmagic.proxy.ServerProxy")
public static IProxy PROXY;
@Mod.Instance(value = MODID)
public static BloodMagic INSTANCE;
public static File configDir;
static {
FluidRegistry.enableUniversalBucket();
}
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
configDir = new File(event.getModConfigurationDirectory(), BloodMagic.MODID);
if (!configDir.exists())
configDir.mkdirs();
PLUGINS.addAll(PluginUtil.gatherPlugins(event.getAsmData()));
PluginUtil.injectAPIInstances(PluginUtil.gatherInjections(event.getAsmData()));
PROXY.preInit(); // TODO - Remove proxy. Switch altar model to json
}
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
PluginUtil.handlePluginStep(PluginUtil.RegistrationStep.PLUGIN_REGISTER);
}
}

View file

@ -0,0 +1,67 @@
package com.wayoftime.bloodmagic.api.impl;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.wayoftime.bloodmagic.api.IBloodMagicAPI;
import com.wayoftime.bloodmagic.core.type.ComponentType;
import com.wayoftime.bloodmagic.core.util.BMLog;
import net.minecraft.block.state.IBlockState;
import javax.annotation.Nonnull;
import java.util.List;
public class BloodMagicAPI implements IBloodMagicAPI {
public static final BloodMagicAPI INSTANCE = new BloodMagicAPI();
private final BloodMagicBlacklist blacklist;
private final BloodMagicRecipeRegistrar recipeRegistrar;
private final BloodMagicValueManager valueManager;
private final Multimap<ComponentType, IBlockState> altarComponents;
public BloodMagicAPI() {
this.blacklist = new BloodMagicBlacklist();
this.recipeRegistrar = new BloodMagicRecipeRegistrar();
this.valueManager = new BloodMagicValueManager();
this.altarComponents = ArrayListMultimap.create();
}
@Nonnull
@Override
public BloodMagicBlacklist getBlacklist() {
return blacklist;
}
@Nonnull
@Override
public BloodMagicRecipeRegistrar getRecipeRegistrar() {
return recipeRegistrar;
}
@Nonnull
@Override
public BloodMagicValueManager getValueManager() {
return valueManager;
}
@Override
public void registerAltarComponent(@Nonnull IBlockState state, @Nonnull String componentType) {
ComponentType component = null;
for (ComponentType type : ComponentType.VALUES) {
if (type.name().equalsIgnoreCase(componentType)) {
component = type;
break;
}
}
if (component != null) {
BMLog.API_VERBOSE.info("Registered {} as a {} altar component.", state, componentType);
altarComponents.put(component, state);
} else BMLog.API.warn("Invalid Altar component type: {}.", componentType);
}
@Nonnull
public List<IBlockState> getComponentStates(ComponentType component) {
return (List<IBlockState>) altarComponents.get(component);
}
}

View file

@ -0,0 +1,106 @@
package com.wayoftime.bloodmagic.api.impl;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.wayoftime.bloodmagic.api.IBloodMagicBlacklist;
import com.wayoftime.bloodmagic.core.util.BMLog;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.ResourceLocation;
import javax.annotation.Nonnull;
import java.util.Set;
public class BloodMagicBlacklist implements IBloodMagicBlacklist {
private final Set<IBlockState> teleposer;
private final Set<ResourceLocation> teleposerEntities;
private final Set<IBlockState> transposition;
private final Set<IBlockState> greenGrove;
private final Set<ResourceLocation> sacrifice;
public BloodMagicBlacklist() {
this.teleposer = Sets.newHashSet();
this.teleposerEntities = Sets.newHashSet();
this.transposition = Sets.newHashSet();
this.greenGrove = Sets.newHashSet();
this.sacrifice = Sets.newHashSet();
}
@Override
public void addTeleposer(@Nonnull IBlockState state) {
if (!teleposer.contains(state)) {
BMLog.API_VERBOSE.info("Blacklist: Added {} to the Teleposer blacklist.", state);
teleposer.add(state);
}
}
public void addTeleposer(@Nonnull Block block) {
for (IBlockState state : block.getBlockState().getValidStates())
addTeleposer(state);
}
@Override
public void addTeleposer(@Nonnull ResourceLocation entityId) {
if (!teleposerEntities.contains(entityId)) {
BMLog.API_VERBOSE.info("Blacklist: Added {} to the Teleposer blacklist.", entityId);
teleposerEntities.add(entityId);
}
}
@Override
public void addTransposition(@Nonnull IBlockState state) {
if (!transposition.contains(state)) {
BMLog.API_VERBOSE.info("Blacklist: Added {} to the Transposition blacklist.", state);
transposition.add(state);
}
}
public void addTransposition(@Nonnull Block block) {
for (IBlockState state : block.getBlockState().getValidStates())
addTransposition(state);
}
@Override
public void addGreenGrove(@Nonnull IBlockState state) {
if (!greenGrove.contains(state)) {
BMLog.API_VERBOSE.info("Blacklist: Added {} to the Green Grove blacklist.", state);
greenGrove.add(state);
}
}
public void addGreenGrove(@Nonnull Block block) {
for (IBlockState state : block.getBlockState().getValidStates())
addGreenGrove(state);
}
@Override
public void addWellOfSuffering(@Nonnull ResourceLocation entityId) {
if (!sacrifice.contains(entityId)) {
BMLog.API_VERBOSE.info("Blacklist: Added {} to the Well of Suffering blacklist.", entityId);
sacrifice.add(entityId);
}
}
// Internal use getters
public Set<IBlockState> getTeleposer() {
return ImmutableSet.copyOf(teleposer);
}
public Set<ResourceLocation> getTeleposerEntities() {
return ImmutableSet.copyOf(teleposerEntities);
}
public Set<IBlockState> getTransposition() {
return ImmutableSet.copyOf(transposition);
}
public Set<IBlockState> getGreenGrove() {
return ImmutableSet.copyOf(greenGrove);
}
public Set<ResourceLocation> getSacrifice() {
return ImmutableSet.copyOf(sacrifice);
}
}

View file

@ -0,0 +1,174 @@
package com.wayoftime.bloodmagic.api.impl;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.api.BloodMagicPlugin;
import com.wayoftime.bloodmagic.api.IBloodMagicAPI;
import com.wayoftime.bloodmagic.api.IBloodMagicPlugin;
import com.wayoftime.bloodmagic.api.IBloodMagicRecipeRegistrar;
import com.wayoftime.bloodmagic.core.RegistrarBloodMagicBlocks;
import com.wayoftime.bloodmagic.core.RegistrarBloodMagicRecipes;
import com.wayoftime.bloodmagic.core.type.ComponentType;
import net.minecraft.block.Block;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.registry.ForgeRegistries;
@BloodMagicPlugin
public class BloodMagicCorePlugin implements IBloodMagicPlugin {
@Override
public void register(IBloodMagicAPI apiInterface) {
BloodMagicAPI api = (BloodMagicAPI) apiInterface;
// Add forced blacklistings
// api.getBlacklist().addTeleposer(RegistrarBloodMagicBlocks.INPUT_ROUTING_NODE);
// api.getBlacklist().addTransposition(RegistrarBloodMagicBlocks.INPUT_ROUTING_NODE);
// api.getBlacklist().addTeleposer(RegistrarBloodMagicBlocks.OUTPUT_ROUTING_NODE);
// api.getBlacklist().addTransposition(RegistrarBloodMagicBlocks.OUTPUT_ROUTING_NODE);
// api.getBlacklist().addTeleposer(RegistrarBloodMagicBlocks.ITEM_ROUTING_NODE);
// api.getBlacklist().addTransposition(RegistrarBloodMagicBlocks.ITEM_ROUTING_NODE);
// api.getBlacklist().addTeleposer(RegistrarBloodMagicBlocks.MASTER_ROUTING_NODE);
// api.getBlacklist().addTransposition(RegistrarBloodMagicBlocks.MASTER_ROUTING_NODE);
// api.getBlacklist().addTeleposer(RegistrarBloodMagicBlocks.DEMON_CRYSTAL);
// api.getBlacklist().addTransposition(RegistrarBloodMagicBlocks.DEMON_CRYSTAL);
// api.getBlacklist().addTeleposer(RegistrarBloodMagicBlocks.INVERSION_PILLAR);
// api.getBlacklist().addTransposition(RegistrarBloodMagicBlocks.INVERSION_PILLAR);
api.getBlacklist().addWellOfSuffering(new ResourceLocation("armor_stand"));
api.getBlacklist().addWellOfSuffering(new ResourceLocation(BloodMagic.MODID, "sentient_specter"));
api.getValueManager().setSacrificialValue(new ResourceLocation("armor_stand"), 0);
api.getValueManager().setSacrificialValue(new ResourceLocation(BloodMagic.MODID, "sentient_specter"), 0);
// api.getValueManager().setTranquility(Blocks.LAVA, new TranquilityStack(EnumTranquilityType.LAVA, 1.2D));
// api.getValueManager().setTranquility(Blocks.FLOWING_LAVA, new TranquilityStack(EnumTranquilityType.LAVA, 1.2D));
// api.getValueManager().setTranquility(Blocks.WATER, new TranquilityStack(EnumTranquilityType.WATER, 1.0D));
// api.getValueManager().setTranquility(Blocks.FLOWING_WATER, new TranquilityStack(EnumTranquilityType.WATER, 1.0D));
// api.getValueManager().setTranquility(RegistrarBloodMagicBlocks.LIFE_ESSENCE, new TranquilityStack(EnumTranquilityType.WATER, 1.5D));
// api.getValueManager().setTranquility(Blocks.NETHERRACK, new TranquilityStack(EnumTranquilityType.FIRE, 0.5D));
// api.getValueManager().setTranquility(Blocks.DIRT, new TranquilityStack(EnumTranquilityType.EARTHEN, 0.25D));
// api.getValueManager().setTranquility(Blocks.FARMLAND, new TranquilityStack(EnumTranquilityType.EARTHEN, 1.0D));
// api.getValueManager().setTranquility(Blocks.POTATOES, new TranquilityStack(EnumTranquilityType.CROP, 1.0D));
// api.getValueManager().setTranquility(Blocks.CARROTS, new TranquilityStack(EnumTranquilityType.CROP, 1.0D));
// api.getValueManager().setTranquility(Blocks.WHEAT, new TranquilityStack(EnumTranquilityType.CROP, 1.0D));
// api.getValueManager().setTranquility(Blocks.NETHER_WART, new TranquilityStack(EnumTranquilityType.CROP, 1.0D));
// api.getValueManager().setTranquility(Blocks.BEETROOTS, new TranquilityStack(EnumTranquilityType.CROP, 1.0D));
handleConfigValues(api);
// Add standard blocks for altar components
api.registerAltarComponent(Blocks.GLOWSTONE.getDefaultState(), ComponentType.GLOWSTONE.name());
api.registerAltarComponent(Blocks.SEA_LANTERN.getDefaultState(), ComponentType.GLOWSTONE.name());
api.registerAltarComponent(Blocks.BEACON.getDefaultState(), ComponentType.BEACON.name());
api.registerAltarComponent(RegistrarBloodMagicBlocks.BLOODSTONE_BRICK.getDefaultState(), ComponentType.BLOODSTONE.name());
api.registerAltarComponent(RegistrarBloodMagicBlocks.BLOODSTONE_TILE.getDefaultState(), ComponentType.BLOODSTONE.name());
// api.registerAltarComponent(decorative.getDefaultState().withProperty(decorative.getProperty(), EnumDecorative.CRYSTAL_BRICK), ComponentType.CRYSTAL.name());
// api.registerAltarComponent(decorative.getDefaultState().withProperty(decorative.getProperty(), EnumDecorative.CRYSTAL_TILE), ComponentType.CRYSTAL.name());
api.registerAltarComponent(RegistrarBloodMagicBlocks.BLOOD_RUNE_BLANK.getDefaultState(), ComponentType.BLOOD_RUNE.name());
api.registerAltarComponent(RegistrarBloodMagicBlocks.BLOOD_RUNE_ACCELERATION.getDefaultState(), ComponentType.BLOOD_RUNE.name());
api.registerAltarComponent(RegistrarBloodMagicBlocks.BLOOD_RUNE_CAPACITY.getDefaultState(), ComponentType.BLOOD_RUNE.name());
api.registerAltarComponent(RegistrarBloodMagicBlocks.BLOOD_RUNE_AUGMENTED_CAPACITY.getDefaultState(), ComponentType.BLOOD_RUNE.name());
api.registerAltarComponent(RegistrarBloodMagicBlocks.BLOOD_RUNE_CHARGING.getDefaultState(), ComponentType.BLOOD_RUNE.name());
api.registerAltarComponent(RegistrarBloodMagicBlocks.BLOOD_RUNE_DISPLACEMENT.getDefaultState(), ComponentType.BLOOD_RUNE.name());
api.registerAltarComponent(RegistrarBloodMagicBlocks.BLOOD_RUNE_EFFICIENCY.getDefaultState(), ComponentType.BLOOD_RUNE.name());
api.registerAltarComponent(RegistrarBloodMagicBlocks.BLOOD_RUNE_ORB.getDefaultState(), ComponentType.BLOOD_RUNE.name());
api.registerAltarComponent(RegistrarBloodMagicBlocks.BLOOD_RUNE_SACRIFICE.getDefaultState(), ComponentType.BLOOD_RUNE.name());
api.registerAltarComponent(RegistrarBloodMagicBlocks.BLOOD_RUNE_SELF_SACRIFICE.getDefaultState(), ComponentType.BLOOD_RUNE.name());
api.registerAltarComponent(RegistrarBloodMagicBlocks.BLOOD_RUNE_SPEED.getDefaultState(), ComponentType.BLOOD_RUNE.name());
}
@Override
public void registerRecipes(IBloodMagicRecipeRegistrar recipeRegistrar) {
RegistrarBloodMagicRecipes.registerAltarRecipes((BloodMagicRecipeRegistrar) recipeRegistrar);
// RegistrarBloodMagicRecipes.registerAlchemyTableRecipes((BloodMagicRecipeRegistrar) recipeRegistrar);
// RegistrarBloodMagicRecipes.registerTartaricForgeRecipes((BloodMagicRecipeRegistrar) recipeRegistrar);
// RegistrarBloodMagicRecipes.registerAlchemyArrayRecipes((BloodMagicRecipeRegistrar) recipeRegistrar);
// RegistrarBloodMagicRecipes.registerSacrificeCraftRecipes((BloodMagicRecipeRegistrar) recipeRegistrar);
}
private static void handleConfigValues(BloodMagicAPI api) {
// for (String value : ConfigHandler.values.sacrificialValues)
// {
// String[] split = value.split(";");
// if (split.length != 2) // Not valid format
// continue;
//
// api.getValueManager().setSacrificialValue(new ResourceLocation(split[0]), Integer.parseInt(split[1]));
// }
//
// for (String value : ConfigHandler.blacklist.teleposer)
// {
// EntityEntry entityEntry = ForgeRegistries.ENTITIES.getValue(new ResourceLocation(value));
// if (entityEntry == null)
// { // It's not an entity (or at least not a valid one), so let's try a block.
// String[] blockData = value.split("\\[");
// Block block = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(blockData[0]));
// if (block == Blocks.AIR || block == null) // Not a valid block either
// continue;
//
// if (blockData.length > 1)
// { // We have properties listed, so let's build a state.
// api.getBlacklist().addTeleposer(parseState(value));
// continue;
// }
//
// api.getBlacklist().addTeleposer(block);
// continue;
// }
//
// api.getBlacklist().addTeleposer(entityEntry.getRegistryName());
// }
//
// for (String value : ConfigHandler.blacklist.transposer)
// {
// String[] blockData = value.split("\\[");
// Block block = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(blockData[0]));
// if (block == Blocks.AIR || block == null) // Not a valid block
// continue;
//
// if (blockData.length > 1)
// { // We have properties listed, so let's build a state.
// api.getBlacklist().addTeleposer(parseState(value));
// continue;
// }
//
// api.getBlacklist().addTeleposer(block);
// }
//
// for (String value : ConfigHandler.blacklist.wellOfSuffering)
// {
// EntityEntry entityEntry = ForgeRegistries.ENTITIES.getValue(new ResourceLocation(value));
// if (entityEntry == null) // Not a valid entity
// continue;
//
// api.getBlacklist().addWellOfSuffering(entityEntry.getRegistryName());
// }
}
private static IBlockState parseState(String blockInfo) {
String[] split = blockInfo.split("\\[");
split[1] = split[1].substring(0, split[1].lastIndexOf("]")); // Make sure brackets are removed from state
Block block = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(split[0])); // Find the block
if (block == Blocks.AIR)
return Blocks.AIR.getDefaultState(); // The block is air, so we're looking at invalid data
BlockStateContainer blockState = block.getBlockState();
IBlockState returnState = blockState.getBaseState();
// Force our values into the state
String[] stateValues = split[1].split(","); // Splits up each value
for (String value : stateValues) {
String[] valueSplit = value.split("="); // Separates property and value
IProperty property = blockState.getProperty(valueSplit[0]);
if (property != null)
returnState = returnState.withProperty(property, (Comparable) property.parseValue(valueSplit[1]).get()); // Force the property into the state
}
return returnState;
}
}

View file

@ -0,0 +1,357 @@
package com.wayoftime.bloodmagic.api.impl;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.wayoftime.bloodmagic.api.IBloodMagicRecipeRegistrar;
import com.wayoftime.bloodmagic.api.impl.recipe.*;
import com.wayoftime.bloodmagic.core.altar.AltarTier;
import com.wayoftime.bloodmagic.core.network.IBloodOrb;
import com.wayoftime.bloodmagic.core.recipe.IngredientBloodOrb;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.crafting.CraftingHelper;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class BloodMagicRecipeRegistrar implements IBloodMagicRecipeRegistrar {
private final Set<RecipeBloodAltar> altarRecipes;
private final Set<RecipeAlchemyTable> alchemyRecipes;
private final Set<RecipeTartaricForge> tartaricForgeRecipes;
private final Set<RecipeAlchemyArray> alchemyArrayRecipes;
private final Set<RecipeSacrificeCraft> sacrificeCraftRecipes;
public BloodMagicRecipeRegistrar() {
this.altarRecipes = Sets.newHashSet();
this.alchemyRecipes = Sets.newHashSet();
this.tartaricForgeRecipes = Sets.newHashSet();
this.alchemyArrayRecipes = Sets.newHashSet();
this.sacrificeCraftRecipes = Sets.newHashSet();
}
@Override
public void addBloodAltar(@Nonnull Ingredient input, @Nonnull ItemStack output, @Nonnegative int minimumTier, @Nonnegative int syphon, @Nonnegative int consumeRate, @Nonnegative int drainRate) {
Preconditions.checkNotNull(input, "input cannot be null.");
Preconditions.checkNotNull(output, "output cannot be null.");
Preconditions.checkArgument(minimumTier >= 0, "minimumTier cannot be negative.");
Preconditions.checkArgument(syphon >= 0, "syphon cannot be negative.");
Preconditions.checkArgument(consumeRate >= 0, "consumeRate cannot be negative.");
Preconditions.checkArgument(drainRate >= 0, "drainRate cannot be negative.");
altarRecipes.add(new RecipeBloodAltar(input, output, minimumTier, syphon, consumeRate, drainRate));
}
public void addBloodAltar(@Nonnull Ingredient input, @Nonnull ItemStack output, @Nonnull AltarTier tier, @Nonnegative int syphon, @Nonnegative int consumeRate, @Nonnegative int drainRate) {
addBloodAltar(input, output, tier.ordinal(), syphon, consumeRate, drainRate);
}
@Override
public boolean removeBloodAltar(@Nonnull ItemStack input) {
Preconditions.checkNotNull(input, "input cannot be null.");
return altarRecipes.remove(getBloodAltar(input));
}
@Override
public void addAlchemyTable(@Nonnull ItemStack output, @Nonnegative int syphon, @Nonnegative int ticks, @Nonnegative int minimumTier, @Nonnull Ingredient... input) {
Preconditions.checkNotNull(output, "output cannot be null.");
Preconditions.checkArgument(syphon >= 0, "syphon cannot be negative.");
Preconditions.checkArgument(ticks >= 0, "ticks cannot be negative.");
Preconditions.checkArgument(minimumTier >= 0, "minimumTier cannot be negative.");
Preconditions.checkNotNull(input, "input cannot be null.");
NonNullList<Ingredient> inputs = NonNullList.from(Ingredient.EMPTY, input);
alchemyRecipes.add(new RecipeAlchemyTable(inputs, output, syphon, ticks, minimumTier));
}
public void addAlchemyTable(@Nonnull ItemStack output, @Nonnegative int syphon, @Nonnegative int ticks, @Nonnegative int minimumTier, @Nonnull Object... input) {
Preconditions.checkNotNull(output, "output cannot be null.");
Preconditions.checkArgument(syphon >= 0, "syphon cannot be negative.");
Preconditions.checkArgument(ticks >= 0, "ticks cannot be negative.");
Preconditions.checkArgument(minimumTier >= 0, "minimumTier cannot be negative.");
Preconditions.checkNotNull(input, "input cannot be null.");
List<Ingredient> ingredients = Lists.newArrayList();
for (Object object : input) {
if (object instanceof ItemStack && ((ItemStack) object).getItem() instanceof IBloodOrb) {
ingredients.add(new IngredientBloodOrb(((IBloodOrb) ((ItemStack) object).getItem()).getOrb((ItemStack) object)));
continue;
}
ingredients.add(CraftingHelper.getIngredient(object));
}
addAlchemyTable(output, syphon, ticks, minimumTier, ingredients.toArray(new Ingredient[0]));
}
public void addAlchemyTable(RecipeAlchemyTable recipe) {
alchemyRecipes.add(recipe);
}
@Override
public boolean removeAlchemyTable(@Nonnull ItemStack... input) {
Preconditions.checkNotNull(input, "inputs cannot be null.");
for (ItemStack stack : input)
Preconditions.checkNotNull(stack, "input cannot be null.");
return alchemyRecipes.remove(getAlchemyTable(Lists.newArrayList(input)));
}
@Override
public void addTartaricForge(@Nonnull ItemStack output, @Nonnegative double minimumSouls, @Nonnegative double soulDrain, @Nonnull Ingredient... input) {
Preconditions.checkNotNull(output, "output cannot be null.");
Preconditions.checkArgument(minimumSouls >= 0, "minimumSouls cannot be negative.");
Preconditions.checkArgument(soulDrain >= 0, "soulDrain cannot be negative.");
Preconditions.checkNotNull(input, "input cannot be null.");
NonNullList<Ingredient> inputs = NonNullList.from(Ingredient.EMPTY, input);
tartaricForgeRecipes.add(new RecipeTartaricForge(inputs, output, minimumSouls, soulDrain));
}
@Override
public boolean removeTartaricForge(@Nonnull ItemStack... input) {
Preconditions.checkNotNull(input, "inputs cannot be null.");
for (ItemStack stack : input)
Preconditions.checkNotNull(stack, "input cannot be null.");
return tartaricForgeRecipes.remove(getTartaricForge(Lists.newArrayList(input)));
}
public void addTartaricForge(@Nonnull ItemStack output, @Nonnegative double minimumSouls, @Nonnegative double soulDrain, @Nonnull Object... input) {
Preconditions.checkNotNull(output, "output cannot be null.");
Preconditions.checkArgument(minimumSouls >= 0, "minimumSouls cannot be negative.");
Preconditions.checkArgument(soulDrain >= 0, "soulDrain cannot be negative.");
Preconditions.checkNotNull(input, "input cannot be null.");
List<Ingredient> ingredients = Lists.newArrayList();
for (Object object : input) {
if (object instanceof ItemStack && ((ItemStack) object).getItem() instanceof IBloodOrb) {
ingredients.add(new IngredientBloodOrb(((IBloodOrb) ((ItemStack) object).getItem()).getOrb((ItemStack) object)));
continue;
}
ingredients.add(CraftingHelper.getIngredient(object));
}
addTartaricForge(output, minimumSouls, soulDrain, ingredients.toArray(new Ingredient[0]));
}
@Override
public void addAlchemyArray(@Nonnull Ingredient input, @Nonnull Ingredient catalyst, @Nonnull ItemStack output, @Nullable ResourceLocation circleTexture) {
Preconditions.checkNotNull(input, "input cannot be null.");
Preconditions.checkNotNull(catalyst, "catalyst cannot be null.");
Preconditions.checkNotNull(output, "output cannot be null.");
alchemyArrayRecipes.add(new RecipeAlchemyArray(input, catalyst, output, circleTexture));
}
@Override
public boolean removeAlchemyArray(@Nonnull ItemStack input, @Nonnull ItemStack catalyst) {
Preconditions.checkNotNull(input, "input cannot be null.");
Preconditions.checkNotNull(catalyst, "catalyst cannot be null.");
return alchemyArrayRecipes.remove(getAlchemyArray(input, catalyst));
}
public void addAlchemyArray(@Nonnull ItemStack input, @Nonnull ItemStack catalyst, @Nonnull ItemStack output, @Nullable ResourceLocation circleTexture) {
Preconditions.checkNotNull(input, "input cannot be null.");
Preconditions.checkNotNull(catalyst, "catalyst cannot be null.");
Preconditions.checkNotNull(output, "output cannot be null.");
addAlchemyArray(Ingredient.fromStacks(input), Ingredient.fromStacks(catalyst), output, circleTexture);
}
public void addSacrificeCraft(@Nonnull ItemStack output, @Nonnegative double healthRequired, @Nonnull Object... input) {
Preconditions.checkNotNull(output, "output cannot be null.");
Preconditions.checkArgument(healthRequired >= 0, "healthRequired cannot be negative.");
Preconditions.checkNotNull(input, "input cannot be null.");
List<Ingredient> ingredients = Lists.newArrayList();
for (Object object : input) {
if (object instanceof ItemStack && ((ItemStack) object).getItem() instanceof IBloodOrb) {
ingredients.add(new IngredientBloodOrb(((IBloodOrb) ((ItemStack) object).getItem()).getOrb((ItemStack) object)));
continue;
}
ingredients.add(CraftingHelper.getIngredient(object));
}
addSacrificeCraft(output, healthRequired, ingredients.toArray(new Ingredient[0]));
}
@Override
public boolean removeSacrificeCraft(@Nonnull ItemStack... input) {
Preconditions.checkNotNull(input, "inputs cannot be null.");
for (ItemStack stack : input)
Preconditions.checkNotNull(stack, "input cannot be null.");
return sacrificeCraftRecipes.remove(getSacrificeCraft(Lists.newArrayList(input)));
}
@Override
public void addSacrificeCraft(@Nonnull ItemStack output, @Nonnegative double healthRequired, @Nonnull Ingredient... input) {
Preconditions.checkNotNull(output, "output cannot be null.");
Preconditions.checkArgument(healthRequired >= 0, "healthRequired cannot be negative.");
Preconditions.checkNotNull(input, "input cannot be null.");
NonNullList<Ingredient> inputs = NonNullList.from(Ingredient.EMPTY, input);
sacrificeCraftRecipes.add(new RecipeSacrificeCraft(inputs, output, healthRequired));
}
@Nullable
public RecipeBloodAltar getBloodAltar(@Nonnull ItemStack input) {
Preconditions.checkNotNull(input, "input cannot be null.");
if (input.isEmpty())
return null;
for (RecipeBloodAltar recipe : altarRecipes)
if (recipe.getInput().test(input))
return recipe;
return null;
}
@Nullable
public RecipeAlchemyTable getAlchemyTable(@Nonnull List<ItemStack> input) {
Preconditions.checkNotNull(input, "input cannot be null.");
if (input.isEmpty())
return null;
mainLoop:
for (RecipeAlchemyTable recipe : alchemyRecipes) {
if (recipe.getInput().size() != input.size())
continue;
List<Ingredient> recipeInput = new ArrayList<>(recipe.getInput());
for (int i = 0; i < input.size(); i++) {
boolean matched = false;
for (int j = 0; j < recipeInput.size(); j++) {
Ingredient ingredient = recipeInput.get(j);
if (ingredient.apply(input.get(i))) {
matched = true;
recipeInput.remove(j);
break;
}
}
if (!matched)
continue mainLoop;
}
return recipe;
}
return null;
}
@Nullable
public RecipeTartaricForge getTartaricForge(@Nonnull List<ItemStack> input) {
Preconditions.checkNotNull(input, "input cannot be null.");
if (input.isEmpty())
return null;
mainLoop:
for (RecipeTartaricForge recipe : tartaricForgeRecipes) {
if (recipe.getInput().size() != input.size())
continue;
List<Ingredient> recipeInput = new ArrayList<>(recipe.getInput());
for (int i = 0; i < input.size(); i++) {
boolean matched = false;
for (int j = 0; j < recipeInput.size(); j++) {
Ingredient ingredient = recipeInput.get(j);
if (ingredient.apply(input.get(i))) {
matched = true;
recipeInput.remove(j);
break;
}
}
if (!matched)
continue mainLoop;
}
return recipe;
}
return null;
}
@Nullable
public RecipeSacrificeCraft getSacrificeCraft(@Nonnull List<ItemStack> input) {
Preconditions.checkNotNull(input, "input cannot be null.");
if (input.isEmpty())
return null;
mainLoop:
for (RecipeSacrificeCraft recipe : sacrificeCraftRecipes) {
if (recipe.getInput().size() != input.size())
continue;
List<Ingredient> recipeInput = new ArrayList<>(recipe.getInput());
for (int i = 0; i < input.size(); i++) {
boolean matched = false;
for (int j = 0; j < recipeInput.size(); j++) {
Ingredient ingredient = recipeInput.get(j);
if (ingredient.apply(input.get(i))) {
matched = true;
recipeInput.remove(j);
break;
}
}
if (!matched)
continue mainLoop;
}
return recipe;
}
return null;
}
@Nullable
public RecipeAlchemyArray getAlchemyArray(@Nonnull ItemStack input, @Nonnull ItemStack catalyst) {
Preconditions.checkNotNull(input, "input cannot be null.");
if (input.isEmpty())
return null;
for (RecipeAlchemyArray recipe : alchemyArrayRecipes)
if (recipe.getInput().test(input) && recipe.getCatalyst().test(catalyst))
return recipe;
return null;
}
public Set<RecipeBloodAltar> getAltarRecipes() {
return ImmutableSet.copyOf(altarRecipes);
}
public Set<RecipeAlchemyTable> getAlchemyRecipes() {
return ImmutableSet.copyOf(alchemyRecipes);
}
public Set<RecipeTartaricForge> getTartaricForgeRecipes() {
return ImmutableSet.copyOf(tartaricForgeRecipes);
}
public Set<RecipeAlchemyArray> getAlchemyArrayRecipes() {
return ImmutableSet.copyOf(alchemyArrayRecipes);
}
}

View file

@ -0,0 +1,62 @@
package com.wayoftime.bloodmagic.api.impl;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.wayoftime.bloodmagic.api.IBloodMagicValueManager;
import com.wayoftime.bloodmagic.core.util.BMLog;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.ResourceLocation;
import javax.annotation.Nonnull;
import java.util.Map;
public class BloodMagicValueManager implements IBloodMagicValueManager {
private final Map<ResourceLocation, Integer> sacrificial;
// private final Map<IBlockState, TranquilityStack> tranquility; // TODO - Tranquility
public BloodMagicValueManager() {
this.sacrificial = Maps.newHashMap();
// this.tranquility = Maps.newHashMap(); // TODO - Tranquility
}
@Override
public void setSacrificialValue(@Nonnull ResourceLocation entityId, int value) {
BMLog.API_VERBOSE.info("Value Manager: Set sacrificial value of {} to {}.", entityId, value);
sacrificial.put(entityId, value);
}
// TODO - Tranquility
@Override
public void setTranquility(@Nonnull IBlockState state, @Nonnull String tranquilityType, double value) {
// EnumTranquilityType tranquility = null;
// for (EnumTranquilityType type : EnumTranquilityType.values()) {
// if (type.name().equalsIgnoreCase(tranquilityType)) {
// tranquility = type;
// break;
// }
// }
//
// if (tranquility != null) {
// BMLog.API_VERBOSE.info("Value Manager: Set tranquility value of {} to {} @ {}", state, tranquilityType, value);
// this.tranquility.put(state, new TranquilityStack(tranquility, value));
// } else BMLog.API.warn("Invalid tranquility type: {}.", tranquilityType);
}
// TODO - Tranquility
// public void setTranquility(Block block, TranquilityStack tranquilityStack) {
// for (IBlockState state : block.getBlockState().getValidStates()) {
// BMLog.API_VERBOSE.info("Value Manager: Set tranquility value of {} to {} @ {}", state, tranquilityStack.type, tranquilityStack.value);
// tranquility.put(state, tranquilityStack);
// }
// }
public Map<ResourceLocation, Integer> getSacrificial() {
return ImmutableMap.copyOf(sacrificial);
}
// TODO - Tranquility
// public Map<IBlockState, TranquilityStack> getTranquility() {
// return ImmutableMap.copyOf(tranquility);
// }
}

View file

@ -0,0 +1,53 @@
package com.wayoftime.bloodmagic.api.impl.recipe;
import com.google.common.base.Preconditions;
import com.wayoftime.bloodmagic.BloodMagic;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.ResourceLocation;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class RecipeAlchemyArray {
@Nonnull
private final Ingredient input;
@Nonnull
private final Ingredient catalyst;
@Nonnull
private final ItemStack output;
@Nonnull
private final ResourceLocation circleTexture;
public RecipeAlchemyArray(@Nonnull Ingredient input, @Nonnull Ingredient catalyst, @Nonnull ItemStack output, @Nullable ResourceLocation circleTexture) {
Preconditions.checkNotNull(input, "input cannot be null.");
Preconditions.checkNotNull(catalyst, "catalyst cannot be null.");
Preconditions.checkNotNull(output, "output cannot be null.");
this.input = input;
this.catalyst = catalyst;
this.output = output;
this.circleTexture = circleTexture == null ? new ResourceLocation(BloodMagic.MODID, "textures/models/AlchemyArrays/WIPArray.png") : circleTexture;
}
@Nonnull
public Ingredient getInput() {
return input;
}
@Nonnull
public Ingredient getCatalyst() {
return catalyst;
}
@Nonnull
public ItemStack getOutput() {
return output;
}
@Nonnull
public ResourceLocation getCircleTexture() {
return circleTexture;
}
}

View file

@ -0,0 +1,59 @@
package com.wayoftime.bloodmagic.api.impl.recipe;
import com.google.common.base.Preconditions;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.NonNullList;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
public class RecipeAlchemyTable {
@Nonnull
private final NonNullList<Ingredient> input;
@Nonnull
private final ItemStack output;
@Nonnegative
private final int syphon;
@Nonnegative
private final int ticks;
@Nonnegative
private final int minimumTier;
public RecipeAlchemyTable(@Nonnull NonNullList<Ingredient> input, @Nonnull ItemStack output, int syphon, int ticks, int minimumTier) {
Preconditions.checkNotNull(input, "input cannot be null.");
Preconditions.checkNotNull(output, "output cannot be null.");
Preconditions.checkArgument(syphon >= 0, "syphon cannot be negative.");
Preconditions.checkArgument(ticks >= 0, "ticks cannot be negative.");
Preconditions.checkArgument(minimumTier >= 0, "minimumTier cannot be negative.");
this.input = input;
this.output = output;
this.syphon = syphon;
this.ticks = ticks;
this.minimumTier = minimumTier;
}
@Nonnull
public final NonNullList<Ingredient> getInput() {
return input;
}
@Nonnull
public final ItemStack getOutput() {
return output;
}
public final int getSyphon() {
return syphon;
}
public final int getTicks() {
return ticks;
}
public final int getMinimumTier() {
return minimumTier;
}
}

View file

@ -0,0 +1,72 @@
package com.wayoftime.bloodmagic.api.impl.recipe;
import com.google.common.base.Preconditions;
import com.wayoftime.bloodmagic.core.altar.AltarTier;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
public class RecipeBloodAltar {
@Nonnull
private final Ingredient input;
@Nonnull
private final ItemStack output;
@Nonnull
private final AltarTier minimumTier;
@Nonnegative
private final int syphon;
@Nonnegative
private final int consumeRate;
@Nonnegative
private final int drainRate;
public RecipeBloodAltar(@Nonnull Ingredient input, @Nonnull ItemStack output, @Nonnegative int minimumTier, @Nonnegative int syphon, @Nonnegative int consumeRate, @Nonnegative int drainRate) {
Preconditions.checkNotNull(input, "input cannot be null.");
Preconditions.checkNotNull(output, "output cannot be null.");
Preconditions.checkArgument(minimumTier >= 0, "minimumTier cannot be negative.");
Preconditions.checkArgument(minimumTier <= AltarTier.values().length, "minimumTier cannot be higher than max tier");
Preconditions.checkArgument(syphon >= 0, "syphon cannot be negative.");
Preconditions.checkArgument(consumeRate >= 0, "consumeRate cannot be negative.");
Preconditions.checkArgument(drainRate >= 0, "drain cannot be negative.");
this.input = input;
this.output = output;
this.minimumTier = AltarTier.values()[minimumTier];
this.syphon = syphon;
this.consumeRate = consumeRate;
this.drainRate = drainRate;
}
@Nonnull
public final Ingredient getInput() {
return input;
}
@Nonnull
public final ItemStack getOutput() {
return output;
}
@Nonnull
public AltarTier getMinimumTier() {
return minimumTier;
}
@Nonnegative
public final int getSyphon() {
return syphon;
}
@Nonnegative
public final int getConsumeRate() {
return consumeRate;
}
@Nonnegative
public final int getDrainRate() {
return drainRate;
}
}

View file

@ -0,0 +1,43 @@
package com.wayoftime.bloodmagic.api.impl.recipe;
import com.google.common.base.Preconditions;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.NonNullList;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
public class RecipeSacrificeCraft {
@Nonnull
private final NonNullList<Ingredient> input;
@Nonnull
private final ItemStack output;
@Nonnegative
private final double healthRequired;
public RecipeSacrificeCraft(@Nonnull NonNullList<Ingredient> input, @Nonnull ItemStack output, @Nonnegative double healthRequired) {
Preconditions.checkNotNull(input, "input cannot be null.");
Preconditions.checkNotNull(output, "output cannot be null.");
Preconditions.checkArgument(healthRequired >= 0, "healthRequired cannot be negative.");
this.input = input;
this.output = output;
this.healthRequired = healthRequired;
}
@Nonnull
public final NonNullList<Ingredient> getInput() {
return input;
}
@Nonnull
public final ItemStack getOutput() {
return output;
}
@Nonnegative
public final double getHealthRequired() {
return healthRequired;
}
}

View file

@ -0,0 +1,53 @@
package com.wayoftime.bloodmagic.api.impl.recipe;
import com.google.common.base.Preconditions;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.NonNullList;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
public class RecipeTartaricForge {
@Nonnull
private final NonNullList<Ingredient> input;
@Nonnull
private final ItemStack output;
@Nonnegative
private final double minimumSouls;
@Nonnegative
private final double soulDrain;
public RecipeTartaricForge(@Nonnull NonNullList<Ingredient> input, @Nonnull ItemStack output, @Nonnegative double minimumSouls, @Nonnegative double soulDrain) {
Preconditions.checkNotNull(input, "input cannot be null.");
Preconditions.checkNotNull(output, "output cannot be null.");
Preconditions.checkArgument(minimumSouls >= 0, "minimumSouls cannot be negative.");
Preconditions.checkArgument(soulDrain >= 0, "soulDrain cannot be negative.");
this.input = input;
this.output = output;
this.minimumSouls = minimumSouls;
this.soulDrain = soulDrain;
}
@Nonnull
public final NonNullList<Ingredient> getInput() {
return input;
}
@Nonnull
public final ItemStack getOutput() {
return output;
}
@Nonnegative
public final double getMinimumSouls() {
return minimumSouls;
}
@Nonnegative
public final double getSoulDrain() {
return soulDrain;
}
}

View file

@ -0,0 +1,133 @@
package com.wayoftime.bloodmagic.block;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.core.altar.IAltarManipulator;
import com.wayoftime.bloodmagic.core.util.register.IItemProvider;
import com.wayoftime.bloodmagic.tile.TileBloodAltar;
import net.minecraft.block.Block;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import javax.annotation.Nullable;
public class BlockBloodAltar extends Block implements IItemProvider {
public BlockBloodAltar() {
super(Material.ROCK);
setTranslationKey(BloodMagic.MODID + ":blood_altar");
setCreativeTab(BloodMagic.TAB_BM);
setHardness(2.0F);
setResistance(5.0F);
setSoundType(SoundType.STONE);
setHarvestLevel("pickaxe", 1);
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
TileEntity tile = world.getTileEntity(pos);
if (!(tile instanceof TileBloodAltar) || !tile.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null))
return false;
IItemHandler altarInv = tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
if (altarInv == null)
return false;
if (player.isSneaking()) {
ItemStack extracted = altarInv.extractItem(0, altarInv.getSlotLimit(0), false);
if (extracted.isEmpty())
return false;
ItemHandlerHelper.giveItemToPlayer(player, extracted);
tile.markDirty();
return true;
} else {
ItemStack held = player.getHeldItem(hand);
if (held.isEmpty())
return false;
if (held.getItem() instanceof IAltarManipulator && ((IAltarManipulator) held.getItem()).tryManipulate(player, held, world, pos))
return false;
if (!altarInv.extractItem(0, 1, true).isEmpty())
return false;
ItemStack insert = held.copy();
insert.setCount(1);
ItemHandlerHelper.insertItem(altarInv, insert, false);
((TileBloodAltar) tile).resetProgress();
tile.markDirty();
if (!player.capabilities.isCreativeMode)
held.shrink(1);
return true;
}
}
@Override
public void breakBlock(World world, BlockPos pos, IBlockState state) {
TileEntity tile = world.getTileEntity(pos);
if (tile == null)
return;
IItemHandler itemHandler = tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
if (itemHandler != null)
for (int i = 0; i < itemHandler.getSlots(); i++)
InventoryHelper.spawnItemStack(world, pos.getX(), pos.getY(), pos.getZ(), itemHandler.getStackInSlot(i));
}
@Override
public boolean isNormalCube(IBlockState state) {
return false;
}
@Override
public boolean isOpaqueCube(IBlockState state) {
return false;
}
@Override
public boolean causesSuffocation(IBlockState state) {
return false;
}
@Override
public boolean isFullBlock(IBlockState state) {
return false;
}
@Override
public boolean isFullCube(IBlockState state) {
return false;
}
@Override
public boolean hasTileEntity(IBlockState state) {
return true;
}
@Nullable
@Override
public TileEntity createTileEntity(World world, IBlockState state) {
return new TileBloodAltar();
}
@Nullable
@Override
public Item getItem() {
return new ItemBlock(this);
}
}

View file

@ -0,0 +1,19 @@
package com.wayoftime.bloodmagic.block;
import com.wayoftime.bloodmagic.core.type.BloodRunes;
import net.minecraft.block.material.Material;
public class BlockBloodRune extends BlockMundane {
private final BloodRunes rune;
public BlockBloodRune(BloodRunes rune) {
super(Material.ROCK, "blood_rune_" + rune.getName(), true);
this.rune = rune;
}
public BloodRunes getRune() {
return rune;
}
}

View file

@ -0,0 +1,33 @@
package com.wayoftime.bloodmagic.block;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.core.type.DemonWillType;
import net.minecraft.block.material.Material;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nullable;
import java.util.List;
public class BlockDemonDecor extends BlockMundane {
private final DemonWillType type;
public BlockDemonDecor(Material material, String decorType, DemonWillType type) {
super(material, decorType + "_" + type.getName());
setTranslationKey(BloodMagic.MODID + ":" + decorType);
this.type = type;
}
@SideOnly(Side.CLIENT)
@Override
public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> tooltip, ITooltipFlag flagIn) {
tooltip.add(I18n.format("tooltip.bloodmagic:demon_will_" + type.getName()));
}
}

View file

@ -0,0 +1,37 @@
package com.wayoftime.bloodmagic.block;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.core.util.register.IItemProvider;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import javax.annotation.Nullable;
// QoL default block
public class BlockMundane extends Block implements IItemProvider {
private final boolean hasItem;
public BlockMundane(Material material, String name, boolean withItem) {
super(material);
this.hasItem = withItem;
setTranslationKey(BloodMagic.MODID + ":" + name);
setCreativeTab(BloodMagic.TAB_BM);
setRegistryName(name);
setDefaultState(getBlockState().getBaseState());
}
public BlockMundane(Material material, String name) {
this(material, name, true);
}
@Nullable
@Override
public Item getItem() {
return hasItem ? new ItemBlock(this) : null;
}
}

View file

@ -0,0 +1,36 @@
package com.wayoftime.bloodmagic.block;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.core.util.register.IItemProvider;
import com.wayoftime.bloodmagic.core.util.register.IVariantProvider;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.block.BlockStairs;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import javax.annotation.Nullable;
// Because Mojang doesn't want us making our own stairs apparently
public class BlockStairsExtended extends BlockStairs implements IItemProvider, IVariantProvider {
public BlockStairsExtended(IBlockState modelState) {
super(modelState);
String name = modelState.getBlock().getRegistryName().getPath() + "_stairs";
setRegistryName(name);
setTranslationKey(BloodMagic.MODID + ":" + name);
setCreativeTab(BloodMagic.TAB_BM);
}
@Nullable
@Override
public Item getItem() {
return new ItemBlock(this);
}
@Override
public void collectVariants(Int2ObjectMap<String> variants) {
variants.put(0, "facing=south,half=bottom,shape=straight");
}
}

View file

@ -0,0 +1,56 @@
package com.wayoftime.bloodmagic.client;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class Sprite {
private final ResourceLocation textureLocation;
private final int textureX;
private final int textureY;
private final int textureWidth;
private final int textureHeight;
public Sprite(ResourceLocation textureLocation, int textureX, int textureY, int textureWidth, int textureHeight) {
this.textureLocation = textureLocation;
this.textureX = textureX;
this.textureY = textureY;
this.textureWidth = textureWidth;
this.textureHeight = textureHeight;
}
public ResourceLocation getTextureLocation() {
return textureLocation;
}
public int getTextureX() {
return textureX;
}
public int getTextureY() {
return textureY;
}
public int getTextureWidth() {
return textureWidth;
}
public int getTextureHeight() {
return textureHeight;
}
public void draw(int x, int y) {
float f = 0.00390625F;
float f1 = 0.00390625F;
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin(7, DefaultVertexFormats.POSITION_TEX);
buffer.pos((double) x, (double) (y + getTextureHeight()), 1.0F).tex((double) ((float) (getTextureX()) * f), (double) ((float) (getTextureY() + getTextureHeight()) * f1)).endVertex();
buffer.pos((double) (x + getTextureWidth()), (double) (y + getTextureHeight()), 1.0F).tex((double) ((float) (getTextureX() + getTextureWidth()) * f), (double) ((float) (getTextureY() + getTextureHeight()) * f1)).endVertex();
buffer.pos((double) (x + getTextureWidth()), (double) (y), 1.0F).tex((double) ((float) (getTextureX() + getTextureWidth()) * f), (double) ((float) (getTextureY()) * f1)).endVertex();
buffer.pos((double) x, (double) (y), 1.0F).tex((double) ((float) (getTextureX()) * f), (double) ((float) (getTextureY()) * f1)).endVertex();
tessellator.draw();
}
}

View file

@ -0,0 +1,87 @@
package com.wayoftime.bloodmagic.client.render;
import com.wayoftime.bloodmagic.core.RegistrarBloodMagic;
import com.wayoftime.bloodmagic.tile.TileBloodAltar;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidTank;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.items.CapabilityItemHandler;
public class TESRBloodAltar extends TileEntitySpecialRenderer<TileBloodAltar> {
private static final float MIN_HEIGHT = 0.499f;
private static final float MAX_HEIGHT = 0.745f;
private static final float SIZE = 0.8F;
@Override
public void render(TileBloodAltar te, double x, double y, double z, float partialTicks, int destroyStage, float alpha) {
GlStateManager.pushMatrix();
renderFluid(te, x, y, z);
GlStateManager.popMatrix();
GlStateManager.pushMatrix();
renderItem(te, x, y, z);
GlStateManager.popMatrix();
}
private void renderFluid(TileBloodAltar te, double x, double y, double z) {
FluidTank fluidTank = (FluidTank) te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, null);
float level = (float) fluidTank.getFluidAmount() / (float) fluidTank.getCapacity();
if (level <= 0)
return;
GlStateManager.translate(x, y, z);
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder builder = tessellator.getBuffer();
TextureAtlasSprite stillImage = Minecraft.getMinecraft().getTextureMapBlocks().getTextureExtry(RegistrarBloodMagic.FLUID_LIFE_ESSENCE.getStill().toString());
if (stillImage == null)
return;
Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
setGLColorFromInt(RegistrarBloodMagic.FLUID_LIFE_ESSENCE.getColor());
GlStateManager.translate(0.5, MIN_HEIGHT + ((MAX_HEIGHT - MIN_HEIGHT) * level), 0.5);
double uMin = (double) stillImage.getMinU();
double uMax = (double) stillImage.getMaxU();
double vMin = (double) stillImage.getMinV();
double vMax = (double) stillImage.getMaxV();
builder.begin(7, DefaultVertexFormats.POSITION_TEX);
builder.pos(SIZE / 2f, 0, SIZE / 2f).tex(uMax, vMax).endVertex();
builder.pos(SIZE / 2f, 0, -SIZE / 2f).tex(uMax, vMin).endVertex();
builder.pos(-SIZE / 2f, 0, -SIZE / 2f).tex(uMin, vMin).endVertex();
builder.pos(-SIZE / 2f, 0, SIZE / 2f).tex(uMin, vMax).endVertex();
tessellator.draw();
}
private void renderItem(TileBloodAltar te, double x, double y, double z) {
ItemStack contained = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null).getStackInSlot(0);
if (contained.isEmpty())
return;
GlStateManager.translate(x, y, z);
RenderItem itemRenderer = Minecraft.getMinecraft().getRenderItem();
float rotation = 720.0F * (System.currentTimeMillis() & 0x3FFFL) / 0x3FFFL;
GlStateManager.translate(0.5F, 0.9F, 0.5F);
GlStateManager.rotate(rotation, 0.0F, 1.0F, 0.0F);
RenderHelper.enableStandardItemLighting();
itemRenderer.renderItem(contained, ItemCameraTransforms.TransformType.GROUND);
RenderHelper.disableStandardItemLighting();
}
private static void setGLColorFromInt(int color) {
float red = (color >> 16 & 0xFF) / 255.0F;
float green = (color >> 8 & 0xFF) / 255.0F;
float blue = (color & 0xFF) / 255.0F;
GlStateManager.color(red, green, blue, 1.0F);
}
}

View file

@ -0,0 +1,19 @@
package com.wayoftime.bloodmagic.core;
import com.wayoftime.bloodmagic.BloodMagic;
import net.minecraftforge.common.config.Config;
@Config(modid = BloodMagic.MODID, name = BloodMagic.MODID + "/" + BloodMagic.MODID, category = "")
public class BloodMagicConfiguration {
public static LoggingConfig logging = new LoggingConfig();
public static class LoggingConfig {
@Config.Comment("Prints information like plugin detection and how long it takes plugins to load their various stages.")
public boolean enableApiLogging = true;
@Config.Comment("Extremely verbose logging for things like recipe addition.")
public boolean enableVerboseApiLogging;
@Config.Comment("Debug printing that may help with debugging certain issues.")
public boolean enableDebugLogging;
}
}

View file

@ -0,0 +1,41 @@
package com.wayoftime.bloodmagic.core;
import com.google.common.base.Stopwatch;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.core.util.BMLog;
import com.wayoftime.bloodmagic.core.util.PluginUtil;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@Mod.EventBusSubscriber(modid = BloodMagic.MODID)
public class RegistrarBloodMagic {
public static final Fluid FLUID_LIFE_ESSENCE = new Fluid(BloodMagic.MODID + ":life_essence", new ResourceLocation(BloodMagic.MODID, "blocks/life_essence_flowing"), new ResourceLocation(BloodMagic.MODID, "blocks/life_essence_still"), 0x8C150C);
@SubscribeEvent
public static void registerBlocks(RegistryEvent.Register<Block> event) {
Stopwatch stopwatch = Stopwatch.createStarted();
RegistrarBloodMagicBlocks.register(event.getRegistry());
BMLog.DEBUG.info("Registered blocks in {}.", stopwatch.stop());
}
@SubscribeEvent
public static void registerItems(RegistryEvent.Register<Item> event) {
Stopwatch stopwatch = Stopwatch.createStarted();
RegistrarBloodMagicItems.register(event.getRegistry());
BMLog.DEBUG.info("Registered items in {}.", stopwatch.stop());
}
@SubscribeEvent
public static void registerRecipes(RegistryEvent<IRecipe> event) {
Stopwatch stopwatch = Stopwatch.createStarted();
PluginUtil.handlePluginStep(PluginUtil.RegistrationStep.RECIPE_REGISTER);
BMLog.DEBUG.info("Registered recipes in {}.", stopwatch.stop());
}
}

View file

@ -0,0 +1,117 @@
package com.wayoftime.bloodmagic.core;
import com.google.common.collect.Lists;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.block.BlockBloodAltar;
import com.wayoftime.bloodmagic.block.BlockBloodRune;
import com.wayoftime.bloodmagic.block.BlockMundane;
import com.wayoftime.bloodmagic.client.render.TESRBloodAltar;
import com.wayoftime.bloodmagic.core.type.BloodRunes;
import com.wayoftime.bloodmagic.tile.TileBloodAltar;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.block.statemap.StateMapperBase;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.fluids.BlockFluidClassic;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.registries.IForgeRegistry;
import java.util.List;
@GameRegistry.ObjectHolder(BloodMagic.MODID)
@Mod.EventBusSubscriber(modid = BloodMagic.MODID)
public class RegistrarBloodMagicBlocks {
public static final Block LIFE_ESSENCE = Blocks.AIR;
public static final Block BLOOD_ALTAR = Blocks.AIR;
public static final Block BLOODSTONE_BRICK= Blocks.AIR;
public static final Block BLOODSTONE_TILE = Blocks.AIR;
public static final Block BLOOD_RUNE_BLANK = Blocks.AIR;
public static final Block BLOOD_RUNE_SPEED = Blocks.AIR;
public static final Block BLOOD_RUNE_EFFICIENCY = Blocks.AIR;
public static final Block BLOOD_RUNE_SACRIFICE = Blocks.AIR;
public static final Block BLOOD_RUNE_SELF_SACRIFICE = Blocks.AIR;
public static final Block BLOOD_RUNE_DISPLACEMENT = Blocks.AIR;
public static final Block BLOOD_RUNE_CAPACITY = Blocks.AIR;
public static final Block BLOOD_RUNE_AUGMENTED_CAPACITY = Blocks.AIR;
public static final Block BLOOD_RUNE_ORB = Blocks.AIR;
public static final Block BLOOD_RUNE_ACCELERATION = Blocks.AIR;
public static final Block BLOOD_RUNE_CHARGING = Blocks.AIR;
static List<Block> blocks;
public static void register(IForgeRegistry<Block> registry) {
GameRegistry.registerTileEntity(TileBloodAltar.class, new ResourceLocation(BloodMagic.MODID, "blood_altar"));
FluidRegistry.addBucketForFluid(RegistrarBloodMagic.FLUID_LIFE_ESSENCE);
blocks = Lists.newArrayList(
new BlockFluidClassic(RegistrarBloodMagic.FLUID_LIFE_ESSENCE, Material.WATER).setTranslationKey(BloodMagic.MODID + ".life_essence").setRegistryName("life_essence"),
new BlockBloodAltar().setRegistryName("blood_altar"),
new BlockMundane(Material.ROCK, "bloodstone_brick"),
new BlockMundane(Material.ROCK, "bloodstone_tile")
);
for (BloodRunes rune : BloodRunes.values())
blocks.add(new BlockBloodRune(rune));
// TODO - Re-enable whenever I feel like it
// for (DemonWillType type : DemonWillType.VALUES) {
// blocks.add(new BlockDemonDecor(Material.ROCK, "demon_stone", type));
// blocks.add(new BlockDemonDecor(Material.ROCK, "demon_stone_polished", type));
// Block brickBlock;
// blocks.add(brickBlock = new BlockDemonDecor(Material.ROCK, "demon_brick", type));
// blocks.add(new BlockDemonDecor(Material.ROCK, "demon_brick_small", type));
// blocks.add(new BlockDemonDecor(Material.ROCK, "demon_tile", type));
// blocks.add(new BlockDemonDecor(Material.ROCK, "demon_tile_special", type));
// blocks.add(new BlockDemonDecor(Material.IRON, "demon_metal", type));
// blocks.add(new BlockStairsExtended(brickBlock.getDefaultState()) {
// @SideOnly(Side.CLIENT)
// @Override
// public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> tooltip, ITooltipFlag flagIn) {
// tooltip.add(I18n.format("tooltip.bloodmagic:demon_will_" + type.getName()));
// }
// }.setTranslationKey(BloodMagic.MODID + ":demon_stairs"));
// }
registry.registerAll(blocks.toArray(new Block[0]));
}
@SideOnly(Side.CLIENT)
@SubscribeEvent
public static void registerModels(ModelRegistryEvent event) {
ClientRegistry.bindTileEntitySpecialRenderer(TileBloodAltar.class, new TESRBloodAltar());
ModelLoader.setCustomStateMapper(LIFE_ESSENCE, new StateMapperBase() {
@Override
protected ModelResourceLocation getModelResourceLocation(IBlockState state) {
return new ModelResourceLocation(state.getBlock().getRegistryName(), "fluid");
}
});
for (Block block : blocks) {
Item item = Item.getItemFromBlock(block);
if (item == Items.AIR)
continue;
boolean flag = RegistrarBloodMagicItems.handleModel(item);
if (!flag) // If we haven't registered a model by now, we don't need any special handling so we'll just use the default model.
ModelLoader.setCustomModelResourceLocation(item, 0, new ModelResourceLocation(item.getRegistryName(), "normal"));
}
}
}

View file

@ -0,0 +1,136 @@
package com.wayoftime.bloodmagic.core;
import com.google.common.collect.Lists;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.core.network.BloodOrb;
import com.wayoftime.bloodmagic.core.type.DemonWillType;
import com.wayoftime.bloodmagic.core.type.SlateType;
import com.wayoftime.bloodmagic.core.util.register.IItemProvider;
import com.wayoftime.bloodmagic.core.util.register.IVariantProvider;
import com.wayoftime.bloodmagic.item.*;
import com.wayoftime.bloodmagic.item.sigil.ItemSigil;
import com.wayoftime.bloodmagic.item.sigil.SigilAir;
import com.wayoftime.bloodmagic.item.sigil.SigilDivination;
import com.wayoftime.bloodmagic.item.sigil.SigilFastMiner;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.block.Block;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.init.Items;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.registries.IForgeRegistry;
import java.util.List;
@GameRegistry.ObjectHolder(BloodMagic.MODID)
@Mod.EventBusSubscriber(modid = BloodMagic.MODID)
public class RegistrarBloodMagicItems {
public static final Item BLOOD_ORB_WEAK = Items.AIR;
public static final Item BLOOD_ORB_APPRENTICE = Items.AIR;
public static final Item BLOOD_ORB_MAGICIAN = Items.AIR;
public static final Item BLOOD_ORB_MASTER = Items.AIR;
public static final Item BLOOD_ORB_ARCHMAGE = Items.AIR;
public static final Item BLOOD_ORB_TRANSCENDENT = Items.AIR;
public static final Item DAGGER_SELF_SACRIFICE = Items.AIR;
public static final Item DAGGER_SELF_SACRIFICE_CREATIVE = Items.AIR;
public static final Item SLATE_BLANK = Items.AIR;
public static final Item SLATE_REINFORCED = Items.AIR;
public static final Item SLATE_IMBUED = Items.AIR;
public static final Item SLATE_DEMONIC = Items.AIR;
public static final Item SLATE_ETHEREAL = Items.AIR;
public static final Item SIGIL_DIVINATION = Items.AIR;
public static final Item SIGIL_AIR = Items.AIR;
public static final Item SIGIL_FAST_MINER = Items.AIR;
public static final Item LIVING_ARMOR_HEAD = Items.AIR;
public static final Item LIVING_ARMOR_CHEST = Items.AIR;
public static final Item LIVING_ARMOR_LEGS = Items.AIR;
public static final Item LIVING_ARMOR_FEET = Items.AIR;
public static final Item LIVING_TOME = Items.AIR;
public static final Item DEMON_WILL_CRYSTAL_RAW = Items.AIR;
public static final Item DEMON_WILL_CRYSTAL_CORROSIVE = Items.AIR;
public static final Item DEMON_WILL_CRYSTAL_DESTRUCTIVE = Items.AIR;
public static final Item DEMON_WILL_CRYSTAL_VENGEFUL = Items.AIR;
public static final Item DEMON_WILL_CRYSTAL_STEADFAST = Items.AIR;
static List<Item> items = Lists.newArrayList();
public static void register(IForgeRegistry<Item> registry) {
for (Block block : RegistrarBloodMagicBlocks.blocks) {
if (block instanceof IItemProvider) {
Item item = ((IItemProvider) block).getItem();
if (item != null)
items.add(item.setRegistryName(block.getRegistryName()));
}
}
items.addAll(Lists.newArrayList(
new ItemBloodOrb(new BloodOrb(new ResourceLocation(BloodMagic.MODID, "weak"), 1, 5000, 2)),
new ItemBloodOrb(new BloodOrb(new ResourceLocation(BloodMagic.MODID, "apprentice"), 2, 25000, 5)),
new ItemBloodOrb(new BloodOrb(new ResourceLocation(BloodMagic.MODID, "magician"), 3, 150000, 15)),
new ItemBloodOrb(new BloodOrb(new ResourceLocation(BloodMagic.MODID, "master"), 4, 1000000, 25)),
new ItemBloodOrb(new BloodOrb(new ResourceLocation(BloodMagic.MODID, "archmage"), 5, 10000000, 50)),
new ItemBloodOrb(new BloodOrb(new ResourceLocation(BloodMagic.MODID, "transcendent"), 6, 30000000, 50)),
new ItemDaggerSelfSacrifice(ItemDaggerSelfSacrifice.Type.NORMAL),
new ItemDaggerSelfSacrifice(ItemDaggerSelfSacrifice.Type.CREATIVE),
new ItemMundane("slate_" + SlateType.BLANK.getName()),
new ItemMundane("slate_" + SlateType.REINFORCED.getName()),
new ItemMundane("slate_" + SlateType.IMBUED.getName()),
new ItemMundane("slate_" + SlateType.DEMONIC.getName()),
new ItemMundane("slate_" + SlateType.ETHEREAL.getName()),
new ItemSigil(new SigilDivination(), "divination"),
new ItemSigil(new SigilAir(), "air"),
new ItemSigil(new SigilFastMiner(), "fast_miner"),
new ItemLivingArmor(EntityEquipmentSlot.HEAD),
new ItemLivingArmor(EntityEquipmentSlot.CHEST),
new ItemLivingArmor(EntityEquipmentSlot.LEGS),
new ItemLivingArmor(EntityEquipmentSlot.FEET),
new ItemLivingTome(),
new ItemAltarBuilder()
));
for (DemonWillType type : DemonWillType.VALUES)
items.add(new ItemMundane("demon_will_crystal_" + type.getName()));
registry.registerAll(items.toArray(new Item[0]));
}
@SideOnly(Side.CLIENT)
@SubscribeEvent
public static void registerModels(ModelRegistryEvent event) {
for (Item item : items) {
boolean flag = handleModel(item);
if (!flag) // If we haven't registered a model by now, we don't need any special handling so we'll just use the default model.
ModelLoader.setCustomModelResourceLocation(item, 0, new ModelResourceLocation(item.getRegistryName(), item instanceof ItemBlock ? "normal" : "inventory"));
}
}
static boolean handleModel(Item item) {
if (item instanceof IVariantProvider) {
Int2ObjectMap<String> variants = new Int2ObjectOpenHashMap<>();
((IVariantProvider) item).collectVariants(variants);
for (Int2ObjectMap.Entry<String> entry : variants.int2ObjectEntrySet())
ModelLoader.setCustomModelResourceLocation(item, entry.getIntKey(), new ModelResourceLocation(item.getRegistryName(), entry.getValue()));
return true;
}
return false;
}
}

View file

@ -0,0 +1,82 @@
package com.wayoftime.bloodmagic.core;
import com.google.common.collect.Maps;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.core.living.LivingUpgrade;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import java.util.Map;
/*
* TODO - See checklist
* - [-] Upgrades (Names pulled from 2.0 class names)
* - [ ] Arrow Protect
* - [ ] Arrow Shot
* - [ ] Critical Strike
* - [ ] Digging
* - [ ] Elytra
* - This will wait for Forge to add the ability to make them properly. I'm not adding that hacky shit back in.
* - [ ] Experience
* - [ ] Fall Protect
* - [ ] Fire Resist
* - [ ] Grave Digger
* - [ ] Grim Reaper Sprint
* - [ ] Health boost
* - [-] Jump
* - [ ] Knockback Resist
* - [ ] Melee Damage
* - [ ] Night Sight
* - [ ] Physical Protect
* - [ ] Poison Resist
* - [ ] Repairing
* - [ ] Self Sacrifice
* - [ ] Solar Powered
* - [ ] Speed
* - [ ] Sprint Attack
* - [ ] Step Assist
* - [ ] Downgrades (Names pulled from 2.0 class names)
* - [ ] Battle Hungry
* - [ ] Crippled Arm
* - [ ] Dig Slowdown
* - [ ] Disoriented
* - [ ] Melee Decrease
* - [ ] Quenched
* - [ ] Slippery
* - [ ] Slow Heal
* - [ ] Slowness
* - [ ] Storm Trooper
* - [-] Equipment
* - [x] Living Helmet
* - [x] Living Chestplate
* - [x] Living Leggings
* - [x] Living Boots
* - [ ] Tools (Replacements for Bound equipment. Need their own (up|down)grade sets once implemented.)
* - [ ] Living Sword
* - [ ] Living Pickaxe
* - [ ] Living Axe
* - [ ] Living Shovel
*/
@Mod.EventBusSubscriber(modid = BloodMagic.MODID)
public class RegistrarBloodMagicLivingArmor {
public static final Map<ResourceLocation, LivingUpgrade> UPGRADES = Maps.newHashMap();
public static final LivingUpgrade JUMP = new LivingUpgrade(new ResourceLocation(BloodMagic.MODID, "jump"), levels -> {
levels.add(new LivingUpgrade.UpgradeLevel(10, 1));
levels.add(new LivingUpgrade.UpgradeLevel(20, 5));
levels.add(new LivingUpgrade.UpgradeLevel(30, 25));
levels.add(new LivingUpgrade.UpgradeLevel(40, 125));
});
@SubscribeEvent
public static void registerUpgrades(RegistryEvent.Register<Item> event) {
addUpgrade(JUMP);
}
private static void addUpgrade(LivingUpgrade upgrade) {
UPGRADES.put(upgrade.getKey(), upgrade);
}
}

View file

@ -0,0 +1,41 @@
package com.wayoftime.bloodmagic.core;
import com.wayoftime.bloodmagic.api.impl.BloodMagicRecipeRegistrar;
import com.wayoftime.bloodmagic.core.altar.AltarTier;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.oredict.OreIngredient;
import static com.wayoftime.bloodmagic.core.RegistrarBloodMagicItems.*;
public class RegistrarBloodMagicRecipes {
public static void registerAltarRecipes(BloodMagicRecipeRegistrar registrar) {
// Tier 1
registrar.addBloodAltar(new OreIngredient("gemDiamond"), new ItemStack(BLOOD_ORB_WEAK), AltarTier.ONE, 2000, 2, 1);
registrar.addBloodAltar(new OreIngredient("stone"), new ItemStack(SLATE_BLANK), AltarTier.ONE, 1000, 5, 5);
registrar.addBloodAltar(Ingredient.fromItem(Items.BUCKET), FluidUtil.getFilledBucket(new FluidStack(RegistrarBloodMagic.FLUID_LIFE_ESSENCE, 1000)), AltarTier.ONE, 1000, 5, 5);
// Tier 2
registrar.addBloodAltar(new OreIngredient("blockRedstone"), new ItemStack(BLOOD_ORB_APPRENTICE), AltarTier.TWO, 5000, 5, 5);
registrar.addBloodAltar(Ingredient.fromItem(SLATE_BLANK), new ItemStack(SLATE_REINFORCED), AltarTier.TWO, 2000, 5, 5);
// Tier 3
registrar.addBloodAltar(new OreIngredient("blockGold"), new ItemStack(BLOOD_ORB_MAGICIAN), AltarTier.THREE, 25000, 20, 20);
registrar.addBloodAltar(Ingredient.fromItem(SLATE_REINFORCED), new ItemStack(SLATE_IMBUED), AltarTier.THREE, 5000, 15, 10);
// Tier 4
registrar.addBloodAltar(new OreIngredient("ingotIron"), new ItemStack(BLOOD_ORB_MASTER), AltarTier.FOUR, 40000, 30, 50); // TODO - Blood Shard input
registrar.addBloodAltar(Ingredient.fromItem(SLATE_IMBUED), new ItemStack(SLATE_DEMONIC), AltarTier.FOUR, 15000, 20, 20);
// Tier 5
registrar.addBloodAltar(new OreIngredient("netherStar"), new ItemStack(BLOOD_ORB_ARCHMAGE), AltarTier.FIVE, 80000, 50, 100);
registrar.addBloodAltar(Ingredient.fromItem(SLATE_DEMONIC), new ItemStack(SLATE_ETHEREAL), AltarTier.FIVE, 30000, 40, 100);
// Tier 6
registrar.addBloodAltar(new OreIngredient("gemDiamond"), new ItemStack(BLOOD_ORB_TRANSCENDENT), AltarTier.SIX, 200000, 100, 200); // TODO - Whatever this input is supposed to be
}
}

View file

@ -0,0 +1,37 @@
package com.wayoftime.bloodmagic.core.altar;
import com.wayoftime.bloodmagic.core.type.ComponentType;
import net.minecraft.util.math.BlockPos;
public class AltarComponent {
private final BlockPos offset;
private final ComponentType type;
private boolean upgradeSlot;
public AltarComponent(BlockPos offset, ComponentType type) {
this.offset = offset;
this.type = type;
}
public AltarComponent(BlockPos offset) {
this(offset, ComponentType.NOT_AIR);
}
public BlockPos getOffset() {
return offset;
}
public ComponentType getType() {
return type;
}
public AltarComponent asUpgradeSlot() {
this.upgradeSlot = true;
return this;
}
public boolean isUpgradeSlot() {
return upgradeSlot;
}
}

View file

@ -0,0 +1,147 @@
package com.wayoftime.bloodmagic.core.altar;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import net.minecraft.util.math.BlockPos;
import java.util.List;
import java.util.function.Consumer;
import static com.wayoftime.bloodmagic.core.type.ComponentType.*;
public enum AltarTier {
ONE {
@Override
public void buildComponents(Consumer<AltarComponent> components) {
// No-op
}
},
TWO {
@Override
public void buildComponents(Consumer<AltarComponent> components) {
components.accept(new AltarComponent(new BlockPos(-1, -1, -1), BLOOD_RUNE));
components.accept(new AltarComponent(new BlockPos(0, -1, -1), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(1, -1, -1), BLOOD_RUNE));
components.accept(new AltarComponent(new BlockPos(-1, -1, 0), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(1, -1, 0), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(-1, -1, 1), BLOOD_RUNE));
components.accept(new AltarComponent(new BlockPos(0, -1, 1), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(1, -1, 1), BLOOD_RUNE));
}
},
THREE {
@Override
public void buildComponents(Consumer<AltarComponent> components) {
// Re-list the tier 2 non-upgrade components. Leaves out the upgradeable components so they aren't double counted
components.accept(new AltarComponent(new BlockPos(-1, -1, -1), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(1, -1, -1), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(-1, -1, 1), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(1, -1, 1), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(-3, -1, -3)));
components.accept(new AltarComponent(new BlockPos(-3, 0, -3)));
components.accept(new AltarComponent(new BlockPos(3, -1, -3)));
components.accept(new AltarComponent(new BlockPos(3, 0, -3)));
components.accept(new AltarComponent(new BlockPos(-3, -1, 3)));
components.accept(new AltarComponent(new BlockPos(-3, 0, 3)));
components.accept(new AltarComponent(new BlockPos(3, -1, 3)));
components.accept(new AltarComponent(new BlockPos(3, 0, 3)));
components.accept(new AltarComponent(new BlockPos(-3, 1, -3), GLOWSTONE));
components.accept(new AltarComponent(new BlockPos(3, 1, -3), GLOWSTONE));
components.accept(new AltarComponent(new BlockPos(-3, 1, 3), GLOWSTONE));
components.accept(new AltarComponent(new BlockPos(3, 1, 3), GLOWSTONE));
for (int i = -2; i <= 2; i++) {
components.accept(new AltarComponent(new BlockPos(3, -2, i), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(-3, -2, i), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(i, -2, 3), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(i, -2, -3), BLOOD_RUNE).asUpgradeSlot());
}
}
},
FOUR {
@Override
public void buildComponents(Consumer<AltarComponent> components) {
for (int i = -3; i <= 3; i++) {
components.accept(new AltarComponent(new BlockPos(5, -3, i), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(-5, -3, i), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(i, -3, 5), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(i, -3, -5), BLOOD_RUNE).asUpgradeSlot());
}
for (int i = -2; i <= 1; i++) {
components.accept(new AltarComponent(new BlockPos(5, i, 5)));
components.accept(new AltarComponent(new BlockPos(5, i, -5)));
components.accept(new AltarComponent(new BlockPos(-5, i, -5)));
components.accept(new AltarComponent(new BlockPos(-5, i, 5)));
}
components.accept(new AltarComponent(new BlockPos(5, 2, 5), BLOODSTONE));
components.accept(new AltarComponent(new BlockPos(5, 2, -5), BLOODSTONE));
components.accept(new AltarComponent(new BlockPos(-5, 2, -5), BLOODSTONE));
components.accept(new AltarComponent(new BlockPos(-5, 2, 5), BLOODSTONE));
}
},
FIVE {
@Override
public void buildComponents(Consumer<AltarComponent> components) {
components.accept(new AltarComponent(new BlockPos(-8, -3, 8), BEACON));
components.accept(new AltarComponent(new BlockPos(-8, -3, -8), BEACON));
components.accept(new AltarComponent(new BlockPos(8, -3, -8), BEACON));
components.accept(new AltarComponent(new BlockPos(8, -3, 8), BEACON));
for (int i = -6; i <= 6; i++) {
components.accept(new AltarComponent(new BlockPos(8, -4, i), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(-8, -4, i), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(i, -4, 8), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(i, -4, -8), BLOOD_RUNE).asUpgradeSlot());
}
}
},
SIX {
@Override
public void buildComponents(Consumer<AltarComponent> components) {
for (int i = -4; i <= 2; i++) {
components.accept(new AltarComponent(new BlockPos(11, i, 11)));
components.accept(new AltarComponent(new BlockPos(-11, i, -11)));
components.accept(new AltarComponent(new BlockPos(11, i, -11)));
components.accept(new AltarComponent(new BlockPos(-11, i, 11)));
}
components.accept(new AltarComponent(new BlockPos(11, 3, 11), CRYSTAL));
components.accept(new AltarComponent(new BlockPos(-11, 3, -11), CRYSTAL));
components.accept(new AltarComponent(new BlockPos(11, 3, -11), CRYSTAL));
components.accept(new AltarComponent(new BlockPos(-11, 3, 11), CRYSTAL));
for (int i = -9; i <= 9; i++) {
components.accept(new AltarComponent(new BlockPos(11, -5, i), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(-11, -5, i), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(i, -5, 11), BLOOD_RUNE).asUpgradeSlot());
components.accept(new AltarComponent(new BlockPos(i, -5, -11), BLOOD_RUNE).asUpgradeSlot());
}
}
};
public static final AltarTier[] VALUES = values();
private final List<AltarComponent> components;
private final int displayInt;
AltarTier() {
List<AltarComponent> list = Lists.newArrayList();
buildComponents(list::add);
this.components = ImmutableList.copyOf(list);
this.displayInt = ordinal() + 1;
}
public abstract void buildComponents(Consumer<AltarComponent> components);
public List<AltarComponent> getComponents() {
return components;
}
public int getDisplayNumber() {
return displayInt;
}
}

View file

@ -0,0 +1,71 @@
package com.wayoftime.bloodmagic.core.altar;
import com.google.common.collect.Maps;
import com.wayoftime.bloodmagic.core.type.BloodRunes;
import net.minecraftforge.fluids.Fluid;
import java.util.EnumMap;
import static com.wayoftime.bloodmagic.core.type.BloodRunes.*;
public class AltarUpgrades {
private final EnumMap<BloodRunes, Integer> upgrades;
public AltarUpgrades() {
this.upgrades = Maps.newEnumMap(BloodRunes.class);
}
public AltarUpgrades upgrade(BloodRunes runeType) {
upgrades.compute(runeType, (k, v) -> v == null ? 1 : v + 1);
return this;
}
public int getAccelerationCount() {
return getCount(ACCELERATION);
}
public float getCapacityModifier() {
return (float) ((1 * Math.pow(1.10, getCount(AUGMENTED_CAPACITY))) + 0.20 * getCount(CAPACITY));
}
public int getChargingFrequency() {
return Math.max(20 - getCount(ACCELERATION), 1);
}
public int getChargingRate() {
return (int) (10 * getCount(CHARGING) * (1 + getConsumptionModifier() / 2));
}
public float getConsumptionModifier() {
return (float) (0.20 * getCount(SPEED));
}
public float getDislocationModifier() {
return (float) (Math.pow(1.2, getCount(DISPLACEMENT)));
}
public float getEfficiencyModifier() {
return (float) Math.pow(0.85, getCount(EFFICIENCY));
}
public int getMaxCharge() {
return (int) (Fluid.BUCKET_VOLUME * Math.max(0.5 * getCapacityModifier(), 1) * getCount(CHARGING));
}
public float getOrbCapacityModifier() {
return (float) (1.02 * getCount(ORB));
}
public float getSacrificeModifier() {
return (float) (0.10 * getCount(SACRIFICE));
}
public float getSelfSacrificeModifier() {
return (float) (0.10 * getCount(SELF_SACRIFICE));
}
public int getCount(BloodRunes rune) {
return upgrades.getOrDefault(rune, 0);
}
}

View file

@ -0,0 +1,153 @@
package com.wayoftime.bloodmagic.core.altar;
import com.google.common.collect.Maps;
import com.wayoftime.bloodmagic.api.impl.BloodMagicAPI;
import com.wayoftime.bloodmagic.block.BlockBloodRune;
import com.wayoftime.bloodmagic.core.RegistrarBloodMagic;
import com.wayoftime.bloodmagic.core.RegistrarBloodMagicBlocks;
import com.wayoftime.bloodmagic.core.type.ComponentType;
import com.wayoftime.bloodmagic.core.util.BooleanResult;
import com.wayoftime.bloodmagic.event.SacrificeEvent;
import com.wayoftime.bloodmagic.tile.TileBloodAltar;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fluids.FluidStack;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.EnumMap;
import java.util.List;
public class AltarUtil {
private static final EnumMap<ComponentType, IBlockState> COMPONENT_DEFAULT_STATES;
static {
COMPONENT_DEFAULT_STATES = Maps.newEnumMap(ComponentType.class);
COMPONENT_DEFAULT_STATES.put(ComponentType.GLOWSTONE, Blocks.GLOWSTONE.getDefaultState());
COMPONENT_DEFAULT_STATES.put(ComponentType.BLOODSTONE, RegistrarBloodMagicBlocks.BLOODSTONE_BRICK.getDefaultState());
COMPONENT_DEFAULT_STATES.put(ComponentType.BEACON, Blocks.BEACON.getDefaultState());
COMPONENT_DEFAULT_STATES.put(ComponentType.BLOOD_RUNE, RegistrarBloodMagicBlocks.BLOOD_RUNE_BLANK.getDefaultState());
COMPONENT_DEFAULT_STATES.put(ComponentType.CRYSTAL, Blocks.BEDROCK.getDefaultState()); // FIXME - Crystal
COMPONENT_DEFAULT_STATES.put(ComponentType.NOT_AIR, Blocks.STONEBRICK.getDefaultState());
}
public static BooleanResult<Integer> handleSacrifice(EntityLivingBase living, int baseAmount) {
TileBloodAltar altar = findNearestAltar(living.getEntityWorld(), new BlockPos(living), 2);
if (altar == null)
return new BooleanResult<>(0, false);
boolean isPlayer = living instanceof EntityPlayer;
AltarUpgrades upgrades = altar.getUpgrades();
int modifiedAmount = (int) (baseAmount * (1 + (isPlayer ? upgrades.getSelfSacrificeModifier() : upgrades.getSacrificeModifier())));
SacrificeEvent event = isPlayer ? new SacrificeEvent.SelfSacrifice(living, baseAmount, modifiedAmount) : new SacrificeEvent(living, baseAmount, modifiedAmount);
MinecraftForge.EVENT_BUS.post(event);
modifiedAmount = event.getModifiedAmount();
int filled = altar.getTank().fill(new FluidStack(RegistrarBloodMagic.FLUID_LIFE_ESSENCE, modifiedAmount), true);
if (filled != 0)
altar.markDirty();
return new BooleanResult<>(filled, true);
}
public static BooleanResult<Integer> handleSacrifice(EntityLivingBase living) {
boolean isPlayer = living instanceof EntityPlayer;
int baseAmount = isPlayer ? 200 : BloodMagicAPI.INSTANCE.getValueManager().getSacrificial().getOrDefault(EntityList.getKey(living), 200);
return handleSacrifice(living, baseAmount);
}
@Nonnull
public static AltarTier getTier(World world, BlockPos pos) {
TileEntity tile = world.getTileEntity(pos);
if (!(tile instanceof TileBloodAltar))
return AltarTier.ONE;
AltarTier lastCheck = AltarTier.ONE;
for (AltarTier tier : AltarTier.VALUES) {
for (AltarComponent component : tier.getComponents()) {
List<IBlockState> validStates = BloodMagicAPI.INSTANCE.getComponentStates(component.getType());
IBlockState worldState = world.getBlockState(pos.add(component.getOffset()));
if (component.getType() == ComponentType.NOT_AIR && worldState.getMaterial() != Material.AIR)
continue;
if (!validStates.contains(worldState))
return lastCheck;
}
lastCheck = tier;
}
return lastCheck;
}
@Nonnull
public static AltarUpgrades getUpgrades(World world, BlockPos pos, AltarTier currentTier) {
AltarUpgrades upgrades = new AltarUpgrades();
for (AltarTier tier : AltarTier.VALUES) {
if (tier.ordinal() > currentTier.ordinal())
break;
for (AltarComponent component : tier.getComponents()) {
if (!component.isUpgradeSlot() || component.getType() != ComponentType.BLOOD_RUNE)
continue;
IBlockState state = world.getBlockState(pos.add(component.getOffset()));
if (state.getBlock() instanceof BlockBloodRune)
upgrades.upgrade(((BlockBloodRune) state.getBlock()).getRune());
}
}
return upgrades;
}
// FIXME - This does not search properly. It may provide an altar that isn't the closest
@Nullable
public static TileBloodAltar findNearestAltar(World world, BlockPos pos, int searchRadius) {
BlockPos.MutableBlockPos offsetPos = new BlockPos.MutableBlockPos(pos);
for (int x = -searchRadius; x < searchRadius; x++) {
for (int y = -searchRadius; y < searchRadius; y++) {
for (int z = -searchRadius; z < searchRadius; z++) {
TileEntity tile = world.getTileEntity(offsetPos.setPos(pos.getX() + x, pos.getY() + y, pos.getZ() + z));
if (tile instanceof TileBloodAltar)
return (TileBloodAltar) tile;
}
}
}
return null;
}
public static void constructAltar(World world, BlockPos altarPos, AltarTier buildTo) {
BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
for (AltarTier tier : AltarTier.VALUES) {
if (tier.ordinal() > buildTo.ordinal())
return;
for (AltarComponent component : tier.getComponents()) {
mutablePos.setPos(altarPos.getX() + component.getOffset().getX(), altarPos.getY() + component.getOffset().getY(), altarPos.getZ() + component.getOffset().getZ());
world.setBlockState(mutablePos, COMPONENT_DEFAULT_STATES.get(component.getType()));
}
}
}
public static void destroyAltar(World world, BlockPos altarPos) {
BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
for (AltarTier tier : AltarTier.VALUES) {
for (AltarComponent component : tier.getComponents()) {
mutablePos.setPos(altarPos.getX() + component.getOffset().getX(), altarPos.getY() + component.getOffset().getY(), altarPos.getZ() + component.getOffset().getZ());
world.setBlockToAir(mutablePos);
}
}
}
}

View file

@ -0,0 +1,13 @@
package com.wayoftime.bloodmagic.core.altar;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public interface IAltarManipulator {
default boolean tryManipulate(EntityPlayer player, ItemStack stack, World world, BlockPos pos) {
return true;
}
}

View file

@ -0,0 +1,52 @@
package com.wayoftime.bloodmagic.core.handler;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.core.network.Binding;
import com.wayoftime.bloodmagic.core.network.BloodOrb;
import com.wayoftime.bloodmagic.core.network.IBloodOrb;
import com.wayoftime.bloodmagic.core.network.SoulNetwork;
import com.wayoftime.bloodmagic.event.BindingEvent;
import com.wayoftime.bloodmagic.item.IBindable;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@Mod.EventBusSubscriber(modid = BloodMagic.MODID)
public class GenericEventHandler {
@SubscribeEvent
public static void onItemUse(PlayerInteractEvent.RightClickItem event) {
if (event.getWorld().isRemote)
return;
EntityPlayer player = event.getEntityPlayer();
ItemStack clicked = event.getItemStack();
if (player instanceof FakePlayer)
return;
if (clicked.getItem() instanceof IBindable) {
IBindable bindable = (IBindable) clicked.getItem();
Binding binding = bindable.getBinding(clicked);
if (binding == null && bindable.onBind(player, clicked)) {
binding = new Binding(player);
BindingEvent bindingEvent = new BindingEvent(clicked, binding, player);
if (!MinecraftForge.EVENT_BUS.post(bindingEvent))
IBindable.applyBinding(clicked, binding);
}
}
if (clicked.getItem() instanceof IBloodOrb) {
BloodOrb orb = ((IBloodOrb) clicked.getItem()).getOrb(clicked);
if (orb == null)
return;
SoulNetwork network = SoulNetwork.get(player.getGameProfile().getId());
if (orb.getTier() > network.getTier())
network.setTier(orb.getTier(), orb.getCapacity());
}
}
}

View file

@ -0,0 +1,54 @@
package com.wayoftime.bloodmagic.core.living;
import net.minecraft.client.resources.I18n;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.input.Keyboard;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public interface ILivingContainer {
@Nullable
default LivingStats getLivingStats(@Nonnull ItemStack stack) {
if (!stack.hasTagCompound() || !stack.getTagCompound().hasKey("livingStats"))
return null;
return LivingStats.fromNBT(stack.getTagCompound().getCompoundTag("livingStats"));
}
default void updateLivingStates(@Nonnull ItemStack stack, @Nullable LivingStats stats) {
if (stats == null) {
if (stack.hasTagCompound())
stack.getTagCompound().removeTag("livingStats");
return;
}
if (!stack.hasTagCompound())
stack.setTagCompound(new NBTTagCompound());
stack.getTagCompound().setTag("livingStats", stats.serializeNBT());
}
@SideOnly(Side.CLIENT)
static void appendLivingTooltip(LivingStats stats, List<String> tooltip, boolean trainable) {
if (stats != null) {
if (trainable)
tooltip.add(I18n.format("tooltip.bloodmagic:living_points", stats.getUsedPoints(), stats.getMaxPoints()));
stats.getUpgrades().forEach((k, v) -> {
if (k.getLevel(v) <= 0)
return;
if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || k.getNextRequirement(v) == 0)
tooltip.add(I18n.format(k.getUnlocalizedName()) + " " + I18n.format("enchantment.level." + k.getLevel(v)));
else
tooltip.add(I18n.format(k.getUnlocalizedName()) + ": " + v + "/" + k.getNextRequirement(v));
});
}
}
}

View file

@ -0,0 +1,64 @@
package com.wayoftime.bloodmagic.core.living;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.common.eventhandler.Cancelable;
import net.minecraftforge.fml.common.eventhandler.Event;
public class LivingEquipmentEvent extends Event {
private final EntityPlayer player;
private final LivingStats stats;
public LivingEquipmentEvent(EntityPlayer player, LivingStats stats) {
this.player = player;
this.stats = stats;
}
public EntityPlayer getPlayer() {
return player;
}
public LivingStats getStats() {
return stats;
}
@Cancelable
public static class GainExperience extends LivingEquipmentEvent {
private final LivingUpgrade upgrade;
private int experience;
public GainExperience(EntityPlayer player, LivingStats stats, LivingUpgrade upgrade, int experience) {
super(player, stats);
this.upgrade = upgrade;
this.experience = experience;
}
public LivingUpgrade getUpgrade() {
return upgrade;
}
public int getExperience() {
return experience;
}
public void setExperience(int experience) {
this.experience = experience;
}
}
public static class LevelUp extends LivingEquipmentEvent {
private final LivingUpgrade upgrade;
public LevelUp(EntityPlayer player, LivingStats stats, LivingUpgrade upgrade) {
super(player, stats);
this.upgrade = upgrade;
}
public LivingUpgrade getUpgrade() {
return upgrade;
}
}
}

View file

@ -0,0 +1,136 @@
package com.wayoftime.bloodmagic.core.living;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.wayoftime.bloodmagic.core.RegistrarBloodMagicLivingArmor;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.util.INBTSerializable;
import javax.annotation.Nullable;
import java.util.Map;
public class LivingStats implements INBTSerializable<NBTTagCompound> {
public static final int DEFAULT_UPGRADE_POINTS = 100;
private final Map<LivingUpgrade, Integer> upgrades;
private int maxPoints = DEFAULT_UPGRADE_POINTS;
public LivingStats(Map<LivingUpgrade, Integer> upgrades) {
this.upgrades = upgrades;
}
public LivingStats() {
this(Maps.newHashMap());
}
public Map<LivingUpgrade, Integer> getUpgrades() {
return ImmutableMap.copyOf(upgrades);
}
public LivingStats addExperience(ResourceLocation key, int experience) {
LivingUpgrade upgrade = RegistrarBloodMagicLivingArmor.UPGRADES.get(key);
int current = upgrades.getOrDefault(upgrade, 0);
if (upgrade.getNextRequirement(current) == 0)
return this;
upgrades.put(upgrade, current + experience);
return this;
}
public int getLevel(ResourceLocation key) {
LivingUpgrade upgrade = RegistrarBloodMagicLivingArmor.UPGRADES.get(key);
return upgrade.getLevel(upgrades.getOrDefault(upgrade, 0));
}
public int getUsedPoints() {
int total = 0;
for (Map.Entry<LivingUpgrade, Integer> applied : upgrades.entrySet()) {
int experience = applied.getValue();
int level = applied.getKey().getLevel(experience);
int cost = applied.getKey().getLevelCost(level);
total += cost;
}
return total;
}
public int getMaxPoints() {
return maxPoints;
}
public LivingStats setMaxPoints(int maxPoints) {
this.maxPoints = maxPoints;
return this;
}
@Override
public NBTTagCompound serializeNBT() {
NBTTagCompound compound = new NBTTagCompound();
NBTTagList statList = new NBTTagList();
upgrades.forEach((k, v) -> {
NBTTagCompound upgrade = new NBTTagCompound();
upgrade.setString("key", k.getKey().toString());
upgrade.setInteger("exp", v);
statList.appendTag(upgrade);
});
compound.setTag("upgrades", statList);
compound.setInteger("maxPoints", maxPoints);
return compound;
}
@Override
public void deserializeNBT(NBTTagCompound nbt) {
NBTTagList statList = nbt.getTagList("upgrades", 10);
for (NBTBase base : statList) {
if (!(base instanceof NBTTagCompound))
continue;
LivingUpgrade upgrade = RegistrarBloodMagicLivingArmor.UPGRADES.get(new ResourceLocation(((NBTTagCompound) base).getString("key")));
if (upgrade == null)
continue;
int experience = ((NBTTagCompound) base).getInteger("exp");
upgrades.put(upgrade, experience);
}
maxPoints = nbt.getInteger("maxPoints");
}
public static LivingStats fromNBT(NBTTagCompound statTag) {
LivingStats stats = new LivingStats();
stats.deserializeNBT(statTag);
return stats;
}
@Nullable
public static LivingStats fromPlayer(EntityPlayer player) {
return fromPlayer(player, false);
}
@Nullable
public static LivingStats fromPlayer(EntityPlayer player, boolean createNew) {
if (!LivingUtil.hasFullSet(player))
return null;
ItemStack chest = player.getItemStackFromSlot(EntityEquipmentSlot.CHEST);
LivingStats stats = ((ILivingContainer) chest.getItem()).getLivingStats(chest);
return stats == null && createNew ? new LivingStats() : stats;
}
public static void toPlayer(EntityPlayer player, LivingStats stats) {
if (!LivingUtil.hasFullSet(player))
return;
ItemStack chest = player.getItemStackFromSlot(EntityEquipmentSlot.CHEST);
((ILivingContainer) chest.getItem()).updateLivingStates(chest, stats);
}
}

View file

@ -0,0 +1,33 @@
package com.wayoftime.bloodmagic.core.living;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.core.RegistrarBloodMagicLivingArmor;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.event.entity.living.LivingEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@Mod.EventBusSubscriber(modid = BloodMagic.MODID)
public class LivingStatusWatcher {
@SubscribeEvent
public static void onJump(LivingEvent.LivingJumpEvent event) {
if (!(event.getEntity() instanceof EntityPlayer))
return;
EntityPlayer player = (EntityPlayer) event.getEntity();
LivingStats stats = LivingUtil.applyNewExperience(player, RegistrarBloodMagicLivingArmor.JUMP, 1);
if (stats == null)
return;
int level = stats.getLevel(RegistrarBloodMagicLivingArmor.JUMP.getKey());
player.motionY += 0.05 * level;
if (level >= 3) {
Vec3d lookVec = player.getLookVec();
player.motionX += player.motionX == 0 ? 0 : lookVec.x * 0.07D * level;
player.motionZ += player.motionZ == 0 ? 0 : lookVec.z * 0.07D * level;
}
}
}

View file

@ -0,0 +1,125 @@
package com.wayoftime.bloodmagic.core.living;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.DamageSource;
import net.minecraft.util.ResourceLocation;
import javax.annotation.Nullable;
import java.util.*;
import java.util.function.Consumer;
public class LivingUpgrade {
private final ResourceLocation key;
private final Set<ResourceLocation> incompatible;
private final TreeMap<Integer, Integer> experienceToLevel;
private final Map<Integer, Integer> levelToCost;
private final boolean isNegative;
private String unlocalizedName = null;
private IAttributeProvider attributeProvider;
private IArmorProvider armorProvider;
public LivingUpgrade(ResourceLocation key, Consumer<List<UpgradeLevel>> experienceMapper /* xp needed -> level */, boolean isNegative) {
this.key = key;
this.incompatible = Sets.newHashSet();
this.experienceToLevel = Maps.newTreeMap();
this.levelToCost = Maps.newHashMap();
this.isNegative = isNegative;
List<UpgradeLevel> levels = Lists.newArrayList();
experienceMapper.accept(levels);
for (int i = 0; i < levels.size(); i++) {
UpgradeLevel level = levels.get(i);
experienceToLevel.put(level.experienceNeeded, i + 1);
levelToCost.put(i + 1, level.upgradeCost);
}
}
public LivingUpgrade(ResourceLocation key, Consumer<List<UpgradeLevel>> experienceMapper /* xp needed -> level */) {
this(key, experienceMapper, false);
}
public LivingUpgrade withAttributeProvider(IAttributeProvider attributeProvider) {
this.attributeProvider = attributeProvider;
return this;
}
@Nullable
public IAttributeProvider getAttributeProvider() {
return attributeProvider;
}
public LivingUpgrade withArmorProvider(IArmorProvider armorProvider) {
this.armorProvider = armorProvider;
return this;
}
@Nullable
public IArmorProvider getArmorProvider() {
return armorProvider;
}
public String getUnlocalizedName() {
return unlocalizedName == null ? unlocalizedName = "upgrade." + key.getNamespace() + ":" + key.getPath() + ".name" : unlocalizedName;
}
public boolean isNegative() {
return isNegative;
}
public boolean isCompatible(ResourceLocation otherUpgrade) {
return !incompatible.contains(otherUpgrade);
}
public LivingUpgrade addIncompatibility(ResourceLocation... otherKeys) {
Collections.addAll(incompatible, otherKeys);
return this;
}
public int getLevel(int experience) {
Map.Entry<Integer, Integer> floor = experienceToLevel.floorEntry(experience);
return floor == null ? 0 : floor.getValue();
}
public int getNextRequirement(int experience) {
Integer ret = experienceToLevel.ceilingKey(experience + 1);
return ret == null ? 0 : ret;
}
public int getLevelCost(int level) {
return levelToCost.getOrDefault(level, 0);
}
public ResourceLocation getKey() {
return key;
}
@Override
public String toString() {
return key.toString();
}
public interface IAttributeProvider {
void handleAttributes(LivingStats stats, Multimap<String, AttributeModifier> attributeMap, int level);
}
public interface IArmorProvider {
double getProtection(EntityPlayer player, DamageSource source, int level);
}
public static class UpgradeLevel {
private final int experienceNeeded;
private final int upgradeCost;
public UpgradeLevel(int experienceNeeded, int upgradeCost) {
this.experienceNeeded = experienceNeeded;
this.upgradeCost = upgradeCost;
}
}
}

View file

@ -0,0 +1,62 @@
package com.wayoftime.bloodmagic.core.living;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraftforge.common.MinecraftForge;
import javax.annotation.Nullable;
public class LivingUtil {
@Nullable
public static LivingStats applyNewExperience(EntityPlayer player, LivingUpgrade upgrade, int experience) {
LivingStats stats = LivingStats.fromPlayer(player, true);
if (stats == null)
return null;
LivingEquipmentEvent.GainExperience event = new LivingEquipmentEvent.GainExperience(player, stats, upgrade, experience);
if (MinecraftForge.EVENT_BUS.post(event))
return stats;
experience = event.getExperience();
int currentExperience = stats.getUpgrades().getOrDefault(upgrade, 0);
int requiredForLevel = upgrade.getNextRequirement(currentExperience) - currentExperience;
// If we're going to level up from this, check points
if (requiredForLevel <= experience) {
int currentPoints = stats.getUsedPoints();
// If we're already capped or somehow over the cap, we don't want to add experience
if (currentPoints >= stats.getMaxPoints())
return stats;
int nextPointCost = upgrade.getLevelCost(upgrade.getLevel(currentExperience) + 1);
// If there's no more levels in this upgrade, we don't want to add experience
if (nextPointCost == -1)
return stats;
// If applying this new level will go over our cap, we don't want to add experience
if (currentPoints + nextPointCost > stats.getMaxPoints())
return stats;
}
int newLevel = upgrade.getLevel(currentExperience + experience);
if (upgrade.getLevel(currentExperience) != newLevel) {
MinecraftForge.EVENT_BUS.post(new LivingEquipmentEvent.LevelUp(player, stats, upgrade));
player.sendStatusMessage(new TextComponentTranslation("chat.bloodmagic:living_upgrade_level_increase", new TextComponentTranslation(upgrade.getUnlocalizedName()), newLevel), true);
}
stats.addExperience(upgrade.getKey(), experience);
LivingStats.toPlayer(player, stats);
return stats;
}
public static boolean hasFullSet(EntityPlayer player) {
for (ItemStack stack : player.inventory.armorInventory)
if (stack.isEmpty() || !(stack.getItem() instanceof ILivingContainer))
return false;
return true;
}
}

View file

@ -0,0 +1,76 @@
package com.wayoftime.bloodmagic.core.network;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTUtil;
import net.minecraftforge.common.util.INBTSerializable;
import javax.annotation.Nullable;
import java.util.UUID;
public class Binding implements INBTSerializable<NBTTagCompound> {
private UUID uuid;
private String name;
public Binding(UUID uuid, String name) {
this.uuid = uuid;
this.name = name;
}
public Binding(EntityPlayer player) {
this(player.getGameProfile().getId(), player.getGameProfile().getName());
}
private Binding() {
// No-op
}
@Override
public NBTTagCompound serializeNBT() {
NBTTagCompound tag = new NBTTagCompound();
tag.setTag("id", NBTUtil.createUUIDTag(uuid));
tag.setString("name", name);
return tag;
}
@Override
public void deserializeNBT(NBTTagCompound nbt) {
this.uuid = NBTUtil.getUUIDFromTag(nbt.getCompoundTag("id"));
this.name = nbt.getString("name");
}
public UUID getOwnerId() {
return uuid;
}
public Binding setOwnerId(UUID uuid) {
this.uuid = uuid;
return this;
}
public String getOwnerName() {
return name;
}
public Binding setOwnerName(String name) {
this.name = name;
return this;
}
@Nullable
public static Binding fromStack(ItemStack stack) {
if (!stack.hasTagCompound()) // Definitely hasn't been bound yet.
return null;
NBTBase bindingTag = stack.getTagCompound().getTag("binding");
if (bindingTag == null || bindingTag.getId() != 10 || bindingTag.isEmpty()) // Make sure it's both a tag compound and that it has actual data.
return null;
Binding binding = new Binding();
binding.deserializeNBT((NBTTagCompound) bindingTag);
return binding;
}
}

View file

@ -0,0 +1,48 @@
package com.wayoftime.bloodmagic.core.network;
import com.wayoftime.bloodmagic.core.util.OrbUtil;
import net.minecraft.util.ResourceLocation;
import org.apache.commons.lang3.builder.ToStringBuilder;
public class BloodOrb {
private final ResourceLocation name;
private final int tier;
private final int capacity;
private final int fillRate;
public BloodOrb(ResourceLocation name, int tier, int capacity, int fillRate) {
this.name = name;
this.tier = tier;
this.capacity = capacity;
this.fillRate = fillRate;
OrbUtil.addOrb(this);
}
public ResourceLocation getName() {
return name;
}
public int getTier() {
return tier;
}
public int getCapacity() {
return capacity;
}
public int getFillRate() {
return fillRate;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("name", name)
.append("tier", tier)
.append("capacity", capacity)
.append("fillRate", fillRate)
.toString();
}
}

View file

@ -0,0 +1,12 @@
package com.wayoftime.bloodmagic.core.network;
import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public interface IBloodOrb {
@Nullable
BloodOrb getOrb(@Nonnull ItemStack stack);
}

View file

@ -0,0 +1,78 @@
package com.wayoftime.bloodmagic.core.network;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.Entity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
public class NetworkInteraction {
private static final ITextComponent EMPTY = new TextComponentString("");
private final ITextComponent description;
private final int amount;
private boolean syphon;
public NetworkInteraction(ITextComponent description, int amount) {
this.description = description;
this.amount = amount;
}
public NetworkInteraction(int amount) {
this(EMPTY, amount);
}
public boolean isSyphon() {
return syphon || amount < 0;
}
public ITextComponent getDescription() {
return description;
}
public int getAmount() {
return amount;
}
public NetworkInteraction syphon() {
this.syphon = true;
return this;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof NetworkInteraction)
return ((NetworkInteraction) o).getDescription().equals(description);
return false;
}
@Override
public int hashCode() {
return description.hashCode();
}
public static NetworkInteraction asBlockInfo(World world, BlockPos pos, int amount) {
return new NetworkInteraction(new TextComponentString("block|" + world.provider.getDimension() + "|" + pos.toLong()), amount);
}
public static NetworkInteraction asItemInfo(ItemStack itemStack, World world, Entity entity, int amount) {
return new NetworkInteraction(new TextComponentString("item|" + itemStack.getItem().getRegistryName() + "|" + world.provider.getDimension() + "|" + entity.getPersistentID()), amount);
}
public static NetworkInteraction asItemInfo(ItemStack itemStack, World world, BlockPos pos, int amount) {
return new NetworkInteraction(new TextComponentString("item|" + itemStack.getItem().getRegistryName() + "|" + world.provider.getDimension() + "|" + pos.toLong()), amount);
}
public static NetworkInteraction asItemInfo(ItemStack itemStack, int amount) {
return new NetworkInteraction(new TextComponentString("item|" + itemStack.getItem().getRegistryName()), amount);
}
public static NetworkInteraction asCommandInfo(ICommandSender sender, String command, int amount) {
return new NetworkInteraction(new TextComponentString("command|" + command + "|" + sender.getName()), amount);
}
}

View file

@ -0,0 +1,81 @@
package com.wayoftime.bloodmagic.core.network;
import com.google.common.collect.Maps;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import net.minecraft.world.storage.WorldSavedData;
import net.minecraftforge.common.DimensionManager;
import javax.annotation.Nonnull;
import java.util.Map;
import java.util.UUID;
public class SNSavedData extends WorldSavedData {
public static final String ID = "bloodmagic_soul_network_data";
private final Map<UUID, SoulNetwork> networks = Maps.newHashMap();
public SNSavedData(String name) {
super(name);
}
public SNSavedData() {
this(ID);
}
public SoulNetwork getNetwork(EntityPlayer player) {
return getNetwork(player.getGameProfile().getId());
}
public SoulNetwork getNetwork(UUID uuid) {
SoulNetwork network = networks.get(uuid);
if (network == null) {
networks.put(uuid, network = SoulNetwork.newEmpty(uuid).withParent(this));
markDirty();
}
return network;
}
@Override
public void readFromNBT(NBTTagCompound nbt) {
NBTTagList networks = nbt.getTagList("networks", 10);
for (NBTBase tag : networks) {
if (tag.getId() != 10) // Only compounds
continue;
SoulNetwork network = SoulNetwork.fromNbt((NBTTagCompound) tag);
network.withParent(this);
this.networks.put(network.getOwnerId(), network);
}
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound compound) {
NBTTagList networks = new NBTTagList();
for (SoulNetwork network : this.networks.values())
networks.appendTag(network.serializeNBT());
compound.setTag("networks", networks);
return compound;
}
@Nonnull
public static SoulNetwork getSoulNetwork(UUID uuid) {
World world = DimensionManager.getWorld(0);
if (world == null || world.getMapStorage() == null)
return new SNSavedData().getNetwork(uuid);
SNSavedData savedData = (SNSavedData) world.getMapStorage().getOrLoadData(SNSavedData.class, ID);
if (savedData == null) {
savedData = new SNSavedData();
world.getMapStorage().setData(ID, savedData);
}
return savedData.getNetwork(uuid);
}
}

View file

@ -0,0 +1,140 @@
package com.wayoftime.bloodmagic.core.network;
import com.google.common.collect.EvictingQueue;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.core.util.BooleanResult;
import com.wayoftime.bloodmagic.event.SoulNetworkEvent;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.DamageSource;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.INBTSerializable;
import java.util.Queue;
import java.util.UUID;
public class SoulNetwork implements INBTSerializable<NBTTagCompound> {
public static final DamageSource WEAK_SOUL = new DamageSource(BloodMagic.MODID + ":weak_soul").setDamageBypassesArmor().setDamageIsAbsolute().setMagicDamage();
private final Queue<NetworkInteraction> interactionHistory;
private SNSavedData parent;
private UUID ownerId;
private int currentEssence;
private int currentTier;
private int maxForTier;
private SoulNetwork() {
this.interactionHistory = EvictingQueue.create(16);
}
@Override
public NBTTagCompound serializeNBT() {
NBTTagCompound tag = new NBTTagCompound();
tag.setString("owner", ownerId.toString());
tag.setInteger("essence", currentEssence);
tag.setInteger("tier", currentTier);
tag.setInteger("maxForTier", maxForTier);
return tag;
}
@Override
public void deserializeNBT(NBTTagCompound nbt) {
this.ownerId = UUID.fromString(nbt.getString("owner"));
this.currentEssence = nbt.getInteger("essence");
this.currentTier = nbt.getInteger("tier");
this.maxForTier = nbt.getInteger("maxForTier");
}
public SoulNetwork withParent(SNSavedData parent) {
this.parent = parent;
return this;
}
public SNSavedData getParent() {
return parent;
}
public UUID getOwnerId() {
return ownerId;
}
public BooleanResult<Integer> submitInteraction(NetworkInteraction interaction) {
if (interaction.getAmount() == 0)
return new BooleanResult<>(0, true);
if (!interaction.isSyphon()) {
SoulNetworkEvent.Fill event = new SoulNetworkEvent.Fill(this, interaction, maxForTier);
if (MinecraftForge.EVENT_BUS.post(event))
return new BooleanResult<>(0, false);
if (currentEssence > event.getMaximum())
return new BooleanResult<>(0, false);
int oldCurrent = currentEssence;
currentEssence = Math.min(event.getMaximum(), currentEssence + event.getTicket().getAmount());
markDirty();
interactionHistory.remove(interaction); // Allows an existing interaction to be moved back up to the top with whatever new amount is changed
interactionHistory.add(interaction);
return new BooleanResult<>(currentEssence - oldCurrent, true);
} else {
SoulNetworkEvent.Syphon event = new SoulNetworkEvent.Syphon(this, interaction);
if (MinecraftForge.EVENT_BUS.post(event))
return new BooleanResult<>(0, false);
int newEssence = currentEssence - event.getTicket().getAmount();
if (newEssence < 0) {
currentEssence = 0;
markDirty();
return new BooleanResult<>(currentEssence, false);
}
currentEssence -= event.getTicket().getAmount();
markDirty();
interactionHistory.remove(interaction);
interactionHistory.add(interaction);
return new BooleanResult<>(event.getTicket().getAmount(), true);
}
}
public int getEssence() {
return currentEssence;
}
public SoulNetwork setEssence(int essence) {
this.currentEssence = Math.min(this.maxForTier, essence);
markDirty();
return this;
}
public SoulNetwork setTier(int newTier, int maxForTier) {
this.currentTier = newTier;
this.maxForTier = maxForTier;
markDirty();
return this;
}
public int getTier() {
return currentTier;
}
public void markDirty() {
if (parent != null)
parent.markDirty();
}
public static SoulNetwork get(UUID uuid) {
return SNSavedData.getSoulNetwork(uuid);
}
public static SoulNetwork newEmpty(UUID uuid) {
SoulNetwork network = new SoulNetwork();
network.ownerId = uuid;
return network;
}
public static SoulNetwork fromNbt(NBTTagCompound tag) {
SoulNetwork network = new SoulNetwork();
network.deserializeNBT(tag);
return network;
}
}

View file

@ -0,0 +1,83 @@
package com.wayoftime.bloodmagic.core.recipe;
import com.google.common.collect.Lists;
import com.wayoftime.bloodmagic.core.network.BloodOrb;
import com.wayoftime.bloodmagic.core.network.IBloodOrb;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntComparators;
import it.unimi.dsi.fastutil.ints.IntList;
import net.minecraft.client.util.RecipeItemHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.NonNullList;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class IngredientBloodOrb extends Ingredient {
private final BloodOrb orb;
private NonNullList<ItemStack> orbs;
private IntList itemIds = null;
private ItemStack[] items;
public IngredientBloodOrb(BloodOrb orb) {
super();
this.orb = orb;
// List<ItemStack> orbGet = OrbRegistry.getOrbsDownToTier(orb.getTier());
List<ItemStack> orbGet = Lists.newArrayList();
orbs = NonNullList.withSize(orbGet.size(), ItemStack.EMPTY);
for (int i = 0; i < orbGet.size(); i++)
orbs.set(i, orbGet.get(i));
}
@Override
@Nonnull
public ItemStack[] getMatchingStacks() {
if (items == null)
items = orbs.toArray(new ItemStack[0]);
return items;
}
@Override
@Nonnull
@SideOnly(Side.CLIENT)
public IntList getValidItemStacksPacked() {
if (this.itemIds == null || itemIds.size() != orbs.size()) {
this.itemIds = new IntArrayList(orbs.size());
for (ItemStack itemstack : orbs)
this.itemIds.add(RecipeItemHelper.pack(itemstack));
this.itemIds.sort(IntComparators.NATURAL_COMPARATOR);
}
return this.itemIds;
}
@Override
public boolean apply(@Nullable ItemStack input) {
if (input == null || input.isEmpty())
return false;
if (!input.hasTagCompound())
return false;
if (!(input.getItem() instanceof IBloodOrb))
return false;
BloodOrb orb = ((IBloodOrb) input.getItem()).getOrb(input);
return orb != null && orb.getTier() >= this.orb.getTier();
}
@Override
protected void invalidate() {
this.itemIds = null;
}
}

View file

@ -0,0 +1,21 @@
package com.wayoftime.bloodmagic.core.recipe;
import com.google.gson.JsonObject;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.JsonUtils;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.crafting.IIngredientFactory;
import net.minecraftforge.common.crafting.JsonContext;
import javax.annotation.Nonnull;
public class IngredientBloodOrbFactory implements IIngredientFactory {
@Nonnull
@Override
public Ingredient parse(JsonContext context, JsonObject json) {
ResourceLocation orb = new ResourceLocation(JsonUtils.getString(json, "orb"));
// return new IngredientBloodOrb(RegistrarBloodMagic.BLOOD_ORBS.getValue(orb));
return null;
}
}

View file

@ -0,0 +1,26 @@
package com.wayoftime.bloodmagic.core.type;
import net.minecraft.util.IStringSerializable;
import java.util.Locale;
public enum BloodRunes implements IStringSerializable {
BLANK,
SPEED,
EFFICIENCY,
SACRIFICE,
SELF_SACRIFICE,
DISPLACEMENT,
CAPACITY,
AUGMENTED_CAPACITY,
ORB,
ACCELERATION,
CHARGING,
;
@Override
public String getName() {
return name().toLowerCase(Locale.ROOT);
}
}

View file

@ -0,0 +1,14 @@
package com.wayoftime.bloodmagic.core.type;
public enum ComponentType {
GLOWSTONE,
BLOODSTONE,
BEACON,
BLOOD_RUNE,
CRYSTAL,
NOT_AIR,
;
public static final ComponentType[] VALUES = values();
}

View file

@ -0,0 +1,22 @@
package com.wayoftime.bloodmagic.core.type;
import net.minecraft.util.IStringSerializable;
import java.util.Locale;
public enum DemonWillType implements IStringSerializable {
RAW,
CORROSIVE,
DESTRUCTIVE,
VENGEFUL,
STEADFAST,
;
public static final DemonWillType[] VALUES = values();
@Override
public String getName() {
return name().toLowerCase(Locale.ROOT);
}
}

View file

@ -0,0 +1,23 @@
package com.wayoftime.bloodmagic.core.type;
import java.util.Locale;
public enum SlateType {
BLANK,
REINFORCED,
IMBUED,
DEMONIC,
ETHEREAL,
;
private final String name;
SlateType() {
this.name = name().toLowerCase(Locale.ROOT);
}
public String getName() {
return name;
}
}

View file

@ -0,0 +1,61 @@
package com.wayoftime.bloodmagic.core.util;
import com.wayoftime.bloodmagic.core.BloodMagicConfiguration;
import org.apache.commons.lang3.text.WordUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public enum BMLog {
DEFAULT("Blood Magic") {
@Override
boolean enabled() {
return true;
}
},
DEBUG() {
@Override
boolean enabled() {
return BloodMagicConfiguration.logging.enableDebugLogging;
}
},
API() {
@Override
boolean enabled() {
return BloodMagicConfiguration.logging.enableApiLogging;
}
},
API_VERBOSE() {
@Override
boolean enabled() {
return BloodMagicConfiguration.logging.enableVerboseApiLogging;
}
};
private final Logger logger;
BMLog(String logName) {
logger = LogManager.getLogger(logName);
}
BMLog() {
logger = LogManager.getLogger("Blood Magic|" + WordUtils.capitalizeFully(name().replace("_", " ")));
}
abstract boolean enabled();
public void info(String input, Object... args) {
if (enabled())
logger.info(input, args);
}
public void error(String input, Object... args) {
if (enabled())
logger.error(input, args);
}
public void warn(String input, Object... args) {
if (enabled())
logger.warn(input, args);
}
}

View file

@ -0,0 +1,20 @@
package com.wayoftime.bloodmagic.core.util;
public class BooleanResult<T> {
private final T value;
private final boolean success;
public BooleanResult(T value, boolean success) {
this.value = value;
this.success = success;
}
public T getValue() {
return value;
}
public boolean isSuccess() {
return success;
}
}

View file

@ -0,0 +1,102 @@
package com.wayoftime.bloodmagic.core.util;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.io.FileUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
/**
* A simple utility for reading and writing JSON files. To handle custom (de)serialization, use
* {@link com.google.gson.annotations.JsonAdapter} on your types.
*/
public class JsonUtil {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().serializeNulls().create();
/**
* Reads a {@link T} back from the given file. If the file does not exist, a new file will be generated with the
* provided default and the default will be returned.
*
* @param token The token type to use for deserialization.
* @param file The file to read the JSON from.
* @param def The default value to use if the file does not exist.
* @param <T> The object type to give back.
* @return a {@link T} that was read from the given file or {@code def} if the file did not exist.
*/
@Nonnull
public static <T> T fromJson(@Nonnull TypeToken<T> token, @Nonnull File file, @Nonnull T def) {
T ret = fromJson(token, file);
if (ret == null) {
toJson(def, token, file);
ret = def;
}
return ret;
}
/**
* Reads a {@link T} back from the given file. If the file does not exist, {@code null} is returned. If an exception
* is thrown during deserialization, {@code null} is also returned.
*
* @param token The token type to use for deserialization.
* @param file - The file to read the JSON from.
* @param <T> The object type to give back.
* @return a {@link T} that was read from the given file, {@code null} if the file does not exist, or {@code null} if
* an exception was thrown.
*/
@Nullable
public static <T> T fromJson(@Nonnull TypeToken<T> token, @Nonnull File file) {
if (!file.exists())
return null;
try (FileReader reader = new FileReader(file)) {
return GSON.fromJson(reader, token.getType());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static <T> T fromJson(@Nonnull TypeToken<T> token, @Nonnull String json) {
return GSON.fromJson(json, token.getType());
}
/**
* Converts a {@link T} to JSON and writes it to file. If the file does not exist, a new one is created. If the file
* does exist, the contents are overwritten with the new value.
*
* @param type The object to write to JSON.
* @param token The token type to use for serialization.
* @param file The file to write the JSON to.
* @param <T> The object type to write.
*/
public static <T> void toJson(@Nonnull T type, @Nonnull TypeToken<T> token, @Nonnull File file) {
if (!file.exists()) {
try {
FileUtils.forceMkdirParent(file);
file.createNewFile();
} catch (Exception e) {
e.printStackTrace();
return;
}
}
try (FileWriter writer = new FileWriter(file)) {
writer.write(getJson(type, token));
} catch (Exception e) {
e.printStackTrace();
}
}
public static <T> String getJson(@Nonnull T type, @Nonnull TypeToken<T> token) {
return GSON.toJson(type, token.getType());
}
}

View file

@ -0,0 +1,24 @@
package com.wayoftime.bloodmagic.core.util;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.wayoftime.bloodmagic.core.network.BloodOrb;
import java.util.List;
public class OrbUtil {
public static final List<BloodOrb> ORBS = Lists.newArrayList();
public static final ArrayListMultimap<Integer, BloodOrb> TIERED = ArrayListMultimap.create();
public static void addOrb(BloodOrb orb) {
ORBS.add(orb);
TIERED.put(orb.getTier(), orb);
}
// TODO :LUL: This needs to be implemented before orb-related recipes can be added.
public static List<BloodOrb> getOrbsMatching(int tier) {
return Lists.newArrayList();
}
}

View file

@ -0,0 +1,137 @@
package com.wayoftime.bloodmagic.core.util;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.api.BloodMagicPlugin;
import com.wayoftime.bloodmagic.api.IBloodMagicAPI;
import com.wayoftime.bloodmagic.api.IBloodMagicPlugin;
import com.wayoftime.bloodmagic.api.impl.BloodMagicAPI;
import com.wayoftime.bloodmagic.api.impl.BloodMagicCorePlugin;
import net.minecraftforge.common.util.EnumHelper;
import net.minecraftforge.fml.common.discovery.ASMDataTable;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
public class PluginUtil {
@SuppressWarnings("unchecked")
@Nonnull
public static List<Pair<IBloodMagicPlugin, BloodMagicPlugin>> gatherPlugins(ASMDataTable dataTable) {
Stopwatch stopwatch = Stopwatch.createStarted();
List<Pair<IBloodMagicPlugin, BloodMagicPlugin>> discoveredAnnotations = Lists.newArrayList();
Set<ASMDataTable.ASMData> discoveredPlugins = dataTable.getAll(BloodMagicPlugin.class.getName());
for (ASMDataTable.ASMData data : discoveredPlugins) {
try {
Class<?> asmClass = Class.forName(data.getClassName());
Class<? extends IBloodMagicPlugin> pluginClass = asmClass.asSubclass(IBloodMagicPlugin.class);
IBloodMagicPlugin instance = pluginClass.newInstance();
BMLog.API.info("Discovered plugin at {}", data.getClassName());
discoveredAnnotations.add(Pair.of(instance, pluginClass.getAnnotation(BloodMagicPlugin.class)));
} catch (Exception e) {
e.printStackTrace();
}
}
// Bring core plugin up to top
discoveredAnnotations.sort((o1, o2) -> {
if (o1.getLeft().getClass() == BloodMagicCorePlugin.class)
return -1;
return o1.getClass().getCanonicalName().compareToIgnoreCase(o2.getClass().getCanonicalName());
});
BMLog.API.info("Discovered {} potential plugin(s) in {}", discoveredAnnotations.size(), stopwatch.stop());
return discoveredAnnotations;
}
@Nonnull
public static List<Field> gatherInjections(ASMDataTable dataTable) {
Stopwatch stopwatch = Stopwatch.createStarted();
List<Field> injectees = Lists.newArrayList();
Set<ASMDataTable.ASMData> discoveredInjectees = dataTable.getAll(BloodMagicPlugin.Inject.class.getName());
for (ASMDataTable.ASMData data : discoveredInjectees) {
try {
Class<?> asmClass = Class.forName(data.getClassName());
Field toInject = asmClass.getDeclaredField(data.getObjectName());
if (toInject.getType() != IBloodMagicAPI.class) {
BMLog.API.error("Mod requested API injection on field {}.{} which is an invalid type.", data.getClassName(), data.getObjectName());
continue;
}
BMLog.API.info("Discovered injection request at {}.{}", data.getClassName(), data.getObjectName());
injectees.add(toInject);
} catch (Exception e) {
e.printStackTrace();
}
}
BMLog.API.info("Discovered {} potential API injection(s) in {}", injectees.size(), stopwatch.stop());
return injectees;
}
public static void handlePluginStep(RegistrationStep step) {
Stopwatch total = Stopwatch.createStarted();
int errors = 0;
for (Pair<IBloodMagicPlugin, BloodMagicPlugin> plugin : BloodMagic.PLUGINS) {
Stopwatch per = Stopwatch.createStarted();
try {
step.getConsumer().accept(plugin);
} catch (Exception e) {
errors++;
BMLog.DEFAULT.error("Error handling plugin step {} at {}: {}: {}", step, plugin.getLeft().getClass(), e.getClass().getSimpleName(), e.getMessage());
}
BMLog.API.info("Handled plugin step {} at {} in {}", step, plugin.getLeft().getClass(), per.stop());
}
BMLog.API.info("Handled {} plugin(s) at step {} with {} errors in {}", BloodMagic.PLUGINS.size() - errors, step, errors, total.stop());
}
public static void injectAPIInstances(List<Field> injectees) {
Stopwatch total = Stopwatch.createStarted();
int errors = 0;
for (Field injectee : injectees) {
Stopwatch per = Stopwatch.createStarted();
if (!Modifier.isStatic(injectee.getModifiers()))
continue;
try {
EnumHelper.setFailsafeFieldValue(injectee, null, BloodMagicAPI.INSTANCE);
} catch (Exception e) {
errors++;
BMLog.DEFAULT.error("Error injecting API instance at {}.{}", injectee.getDeclaringClass().getCanonicalName(), injectee.getName());
}
BMLog.API.info("Injected API instance at {}.{} in {}", injectee.getDeclaringClass().getCanonicalName(), injectee.getName(), per.stop());
}
BMLog.API.info("Injected API {} times with {} errors in {}", injectees.size() - errors, errors, total.stop());
}
public enum RegistrationStep {
PLUGIN_REGISTER(p -> p.getLeft().register(BloodMagicAPI.INSTANCE)),
RECIPE_REGISTER(p -> p.getLeft().registerRecipes(BloodMagicAPI.INSTANCE.getRecipeRegistrar()))
;
private final Consumer<Pair<IBloodMagicPlugin, BloodMagicPlugin>> consumer;
RegistrationStep(Consumer<Pair<IBloodMagicPlugin, BloodMagicPlugin>> consumer) {
this.consumer = consumer;
}
@Nonnull
public Consumer<Pair<IBloodMagicPlugin, BloodMagicPlugin>> getConsumer() {
return consumer;
}
}
}

View file

@ -0,0 +1,51 @@
package com.wayoftime.bloodmagic.core.util;
import net.minecraftforge.common.util.EnumHelper;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.registries.ForgeRegistry;
import net.minecraftforge.registries.IForgeRegistry;
import net.minecraftforge.registries.IForgeRegistryEntry;
import javax.annotation.Nonnull;
import java.lang.reflect.Field;
import java.util.function.BiConsumer;
public final class RegistryAddCallbackWrapper<T extends IForgeRegistryEntry<T>> {
private static final Field CALLBACK_FIELD;
static {
try {
CALLBACK_FIELD = ForgeRegistry.class.getDeclaredField("add");
CALLBACK_FIELD.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Could not find AddCallback field.");
}
}
private final Class<T> registryType;
private final BiConsumer<T, T> addCheck;
private final Runnable postCallback;
public RegistryAddCallbackWrapper(@Nonnull Class<T> registryType, @Nonnull BiConsumer<T, T> addCheck, @Nonnull Runnable postCallback) {
this.registryType = registryType;
this.addCheck = addCheck;
this.postCallback = postCallback;
}
public void wrapParent() throws Exception {
ForgeRegistry<T> registry = (ForgeRegistry<T>) GameRegistry.findRegistry(registryType);
//noinspection unchecked
IForgeRegistry.AddCallback<T> oldCallback = (IForgeRegistry.AddCallback<T>) CALLBACK_FIELD.get(registry);
EnumHelper.setFailsafeFieldValue(CALLBACK_FIELD, registry, (IForgeRegistry.AddCallback<T>) (owner, stage, id, obj, oldObj) -> {
oldCallback.onAdd(owner, stage, id, obj, oldObj);
addCheck.accept(obj, oldObj);
});
BMLog.DEBUG.info("Wrapped add callback for {} registry.", registry.getRegistrySuperType().getSimpleName());
}
@Nonnull
public Runnable getPostCallback() {
return postCallback;
}
}

View file

@ -0,0 +1,13 @@
package com.wayoftime.bloodmagic.core.util.register;
import net.minecraft.item.Item;
import javax.annotation.Nullable;
public interface IItemProvider {
@Nullable
default Item getItem() {
return null;
}
}

View file

@ -0,0 +1,15 @@
package com.wayoftime.bloodmagic.core.util.register;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
public interface IVariantProvider {
/**
* A mapping of meta -> state variant
*
* @param variants A map to populate with all variants
*/
default void collectVariants(Int2ObjectMap<String> variants) {
variants.put(0, "inventory");
}
}

View file

@ -0,0 +1,33 @@
package com.wayoftime.bloodmagic.event;
import com.wayoftime.bloodmagic.core.network.Binding;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.common.eventhandler.Cancelable;
import net.minecraftforge.fml.common.eventhandler.Event;
@Cancelable
public class BindingEvent extends Event {
private final ItemStack stack;
private final Binding binding;
private final EntityPlayer player;
public BindingEvent(ItemStack stack, Binding binding, EntityPlayer player) {
this.stack = stack;
this.binding = binding;
this.player = player;
}
public ItemStack getStack() {
return stack;
}
public Binding getBinding() {
return binding;
}
public EntityPlayer getPlayer() {
return player;
}
}

View file

@ -0,0 +1,45 @@
package com.wayoftime.bloodmagic.event;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.common.eventhandler.Event;
public class SacrificeEvent extends Event {
protected final EntityLivingBase sacrificed;
private final int baseAmount;
private int modifiedAmount;
public SacrificeEvent(EntityLivingBase sacrificed, int baseAmount, int modifiedAmount) {
this.sacrificed = sacrificed;
this.baseAmount = baseAmount;
this.modifiedAmount = modifiedAmount;
}
public EntityLivingBase getSacrificed() {
return sacrificed;
}
public int getBaseAmount() {
return baseAmount;
}
public int getModifiedAmount() {
return modifiedAmount;
}
public void setModifiedAmount(int modifiedAmount) {
this.modifiedAmount = modifiedAmount;
}
public static class SelfSacrifice extends SacrificeEvent {
public SelfSacrifice(EntityLivingBase sacrificed, int baseAmount, int modifiedAmount) {
super(sacrificed, baseAmount, modifiedAmount);
}
public EntityPlayer getPlayer() {
return (EntityPlayer) sacrificed;
}
}
}

View file

@ -0,0 +1,99 @@
package com.wayoftime.bloodmagic.event;
import com.wayoftime.bloodmagic.core.network.SoulNetwork;
import com.wayoftime.bloodmagic.core.network.NetworkInteraction;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.common.eventhandler.Cancelable;
import net.minecraftforge.fml.common.eventhandler.Event;
public class SoulNetworkEvent extends Event {
private final SoulNetwork network;
private NetworkInteraction ticket;
public SoulNetworkEvent(SoulNetwork network, NetworkInteraction ticket) {
this.network = network;
this.ticket = ticket;
}
public SoulNetwork getNetwork() {
return network;
}
public NetworkInteraction getTicket() {
return ticket;
}
public void setTicket(NetworkInteraction ticket) {
this.ticket = ticket;
}
@Cancelable
public static class Syphon extends SoulNetworkEvent {
private boolean shouldDamage;
public Syphon(SoulNetwork network, NetworkInteraction ticket) {
super(network, ticket);
}
public boolean shouldDamage() {
return shouldDamage;
}
public void setShouldDamage(boolean shouldDamage) {
this.shouldDamage = shouldDamage;
}
public static class Item extends Syphon {
private final ItemStack stack;
public Item(SoulNetwork network, NetworkInteraction ticket, ItemStack stack) {
super(network, ticket);
this.stack = stack;
}
public ItemStack getStack() {
return stack;
}
}
public static class User extends Syphon {
private final EntityPlayer user;
public User(SoulNetwork network, NetworkInteraction ticket, EntityPlayer user) {
super(network, ticket);
this.user = user;
}
public EntityPlayer getUser() {
return user;
}
}
}
@Cancelable
public static class Fill extends SoulNetworkEvent {
private int maximum;
public Fill(SoulNetwork network, NetworkInteraction ticket, int maximum) {
super(network, ticket);
this.maximum = maximum;
}
public int getMaximum() {
return maximum;
}
public void setMaximum(int maximum) {
this.maximum = maximum;
}
}
}

View file

@ -0,0 +1,36 @@
package com.wayoftime.bloodmagic.guide;
import com.google.common.collect.Maps;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import java.util.Map;
import java.util.function.Consumer;
public class Category {
private final Guide owner;
private final String name;
private final Map<String, Entry> entries;
public Category(Guide owner, String name, Consumer<Category> $) {
this.owner = owner;
this.name = name;
entries = Maps.newLinkedHashMap();
$.accept(this);
}
@SideOnly(Side.CLIENT)
public void draw(Minecraft minecraft, ScaledResolution resolution, FontRenderer font) {
}
public Entry addEntry(Entry entry) {
entries.put(entry.getId(), entry);
return entry;
}
}

View file

@ -0,0 +1,29 @@
package com.wayoftime.bloodmagic.guide;
import com.google.common.collect.Lists;
import com.wayoftime.bloodmagic.guide.page.PageComponent;
import java.util.List;
import java.util.function.Consumer;
public class Entry {
private final String id;
private final List<PageComponent> components;
public Entry(String id, Consumer<Entry> $) {
this.id = id;
this.components = Lists.newArrayList();
$.accept(this);
}
public PageComponent appendComponent(PageComponent component) {
components.add(component);
return component;
}
public String getId() {
return id;
}
}

View file

@ -0,0 +1,34 @@
package com.wayoftime.bloodmagic.guide;
import com.google.common.collect.Lists;
import net.minecraft.util.ResourceLocation;
import java.util.List;
import java.util.function.Consumer;
public class Guide {
private final ResourceLocation id;
private final List<Category> categories;
public Guide(ResourceLocation id, Consumer<Guide> $) {
this.id = id;
this.categories = Lists.newArrayList();
$.accept(this);
}
public Category addCategory(String name, Consumer<Category> category) {
Category cat = new Category(this, name, category);
categories.add(cat);
return cat;
}
public ResourceLocation getId() {
return id;
}
public List<Category> getCategories() {
return categories;
}
}

View file

@ -0,0 +1,61 @@
package com.wayoftime.bloodmagic.guide.page;
import com.wayoftime.bloodmagic.guide.Guide;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nullable;
import java.util.function.Consumer;
public class PageComponent {
private final int height;
private IComponentSplitter splitter;
private IViewingRequirement viewingRequirement;
public PageComponent(int height) {
this.height = height;
}
@SideOnly(Side.CLIENT)
public void draw(Minecraft minecraft, ScaledResolution resolution, FontRenderer font) {
}
public int getHeight() {
return height;
}
@Nullable
public IComponentSplitter getSplitter() {
return splitter;
}
public PageComponent withComponentSplitter(IComponentSplitter splitter) {
this.splitter = splitter;
return this;
}
public IViewingRequirement getViewingRequirement() {
return viewingRequirement;
}
public PageComponent withViewingRequirement(IViewingRequirement viewingRequirement) {
this.viewingRequirement = viewingRequirement;
return this;
}
public interface IComponentSplitter {
void split(Consumer<PageComponent> components, int currentPosition, int pageHeight);
}
public interface IViewingRequirement {
boolean canView(EntityPlayer player, World world, ItemStack guideStack, Guide guide);
}
}

View file

@ -0,0 +1,8 @@
package com.wayoftime.bloodmagic.guide.page;
public class PageComponentFiller extends PageComponent {
public PageComponentFiller() {
super(-1);
}
}

View file

@ -0,0 +1,32 @@
package com.wayoftime.bloodmagic.guide.page;
import net.minecraft.util.ResourceLocation;
import javax.vecmath.Point2i;
public class PageComponentImage extends PageComponent {
private final Sprite sprite;
public PageComponentImage(Sprite sprite) {
super(sprite.size.y);
this.sprite = sprite;
}
public static class Sprite {
private final ResourceLocation location;
private final Point2i startPosition;
private final Point2i size;
public Sprite(ResourceLocation location, Point2i startPosition, Point2i size) {
this.location = location;
this.startPosition = startPosition;
this.size = size;
}
public void draw(int x, int y) {
// TODO
}
}
}

View file

@ -0,0 +1,14 @@
package com.wayoftime.bloodmagic.guide.page;
import net.minecraft.item.ItemStack;
public class PageComponentItem extends PageComponent {
private final ItemStack item;
public PageComponentItem(ItemStack item) {
super(18);
this.item = item;
}
}

View file

@ -0,0 +1,19 @@
package com.wayoftime.bloodmagic.guide.page;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.registry.ForgeRegistries;
import java.util.function.Supplier;
public class PageComponentRecipe extends PageComponent {
private final Supplier<IRecipe> recipeGetter;
private IRecipe recipe;
public PageComponentRecipe(ResourceLocation recipe) {
super(60);
this.recipeGetter = () -> ForgeRegistries.RECIPES.getValue(recipe);
}
}

View file

@ -0,0 +1,20 @@
package com.wayoftime.bloodmagic.guide.page;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipes;
import java.util.function.Supplier;
public class PageComponentSmelting extends PageComponent {
private final ItemStack output;
private final Supplier<ItemStack> inputGetter;
private ItemStack input;
public PageComponentSmelting(ItemStack output) {
super(20);
this.output = output;
this.inputGetter = () -> FurnaceRecipes.instance().getSmeltingResult(output);
}
}

View file

@ -0,0 +1,50 @@
package com.wayoftime.bloodmagic.guide.page;
import com.google.common.collect.Lists;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import java.util.List;
import java.util.function.Consumer;
public class PageComponentText extends PageComponent {
private final ITextComponent textComponent;
public PageComponentText(ITextComponent text) {
super(-1);
this.textComponent = text;
withComponentSplitter(new StringSplitter(textComponent));
}
private static class StringSplitter implements IComponentSplitter {
private final ITextComponent component;
public StringSplitter(ITextComponent component) {
this.component = component;
}
@Override
public void split(Consumer<PageComponent> components, int currentPosition, int pageHeight) {
String fullText = component.getFormattedText();
FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer;
List<String> lines = fontRenderer.listFormattedStringToWidth(fullText, 300);
int remainingSpace = pageHeight - currentPosition;
for (String line : lines) {
List<String> componentLines = Lists.newArrayList();
if (remainingSpace >= fontRenderer.FONT_HEIGHT + 3) {
componentLines.add(line);
remainingSpace += fontRenderer.FONT_HEIGHT + 3;
} else {
remainingSpace = pageHeight;
components.accept(new PageComponentText(new TextComponentString(String.join(" ", componentLines))));
componentLines.clear();
}
}
}
}
}

View file

@ -0,0 +1,56 @@
package com.wayoftime.bloodmagic.guide.test;
import com.google.common.collect.Lists;
import com.wayoftime.bloodmagic.guide.Entry;
import com.wayoftime.bloodmagic.guide.Guide;
import com.wayoftime.bloodmagic.guide.page.PageComponentFiller;
import com.wayoftime.bloodmagic.guide.page.PageComponentItem;
import com.wayoftime.bloodmagic.guide.page.PageComponentText;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.TextComponentString;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import java.util.List;
@Mod(modid = "test_guide")
@Mod.EventBusSubscriber(modid = "test_guide")
public class GuideTest {
public static final List<Guide> GUIDES = Lists.newArrayList();
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
GUIDES.add(new Guide(new ResourceLocation("guide_test", "test"), guide -> {
guide.addCategory("test_cat_1", category -> {
category.addEntry(new Entry("test_entry_1", test1 -> {
test1.appendComponent(new PageComponentText(new TextComponentString("doot")));
}));
});
guide.addCategory("test_cat_2", category -> {
category.addEntry(new Entry("test_entry_2", test2 -> {
test2.appendComponent(new PageComponentText(new TextComponentString("what's up bud")));
test2.appendComponent(new PageComponentItem(new ItemStack(Items.DIAMOND)));
test2.appendComponent(new PageComponentFiller());
}));
category.addEntry(new Entry("test_entry_3", test3 -> {
test3.appendComponent(new PageComponentFiller());
test3.appendComponent(new PageComponentFiller());
}));
});
}));
}
@SubscribeEvent
public static void registerItems(RegistryEvent.Register<Item> event) {
for (Guide guide : GUIDES)
event.getRegistry().register(new ItemGuide(guide));
}
}

View file

@ -0,0 +1,15 @@
package com.wayoftime.bloodmagic.guide.test;
import com.wayoftime.bloodmagic.guide.Guide;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
public class ItemGuide extends Item {
public ItemGuide(Guide guide) {
setRegistryName(guide.getId().toString().replace(":", "_"));
setTranslationKey(guide.getId().toString());
setMaxStackSize(1);
setCreativeTab(CreativeTabs.MISC);
}
}

View file

@ -0,0 +1,23 @@
package com.wayoftime.bloodmagic.guide.test.gui;
import com.wayoftime.bloodmagic.guide.Category;
import com.wayoftime.bloodmagic.guide.Entry;
public class Bookmark {
private Category category;
private Entry entry;
public Bookmark atPosition(Category category, Entry entry) {
this.category = category;
return this;
}
public Category getCategory() {
return category;
}
public Entry getEntry() {
return entry;
}
}

View file

@ -0,0 +1,35 @@
package com.wayoftime.bloodmagic.guide.test.gui;
import com.google.common.collect.Maps;
import com.wayoftime.bloodmagic.guide.Guide;
import net.minecraft.client.gui.GuiScreen;
import java.util.Map;
public class GuiGuide extends GuiScreen {
private static final Map<Guide, GuiGuide> SCREENS = Maps.newHashMap();
private final Guide guide;
private final Bookmark bookmark;
public GuiGuide(Guide guide) {
this.guide = guide;
this.bookmark = new Bookmark();
}
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
super.drawScreen(mouseX, mouseY, partialTicks);
}
@Override
public void onGuiClosed() {
// TODO update bookmark
super.onGuiClosed();
}
public static GuiGuide getGui(Guide guide) {
return SCREENS.compute(guide, (k, v) -> v == null ? new GuiGuide(guide) : v);
}
}

View file

@ -0,0 +1,58 @@
package com.wayoftime.bloodmagic.item;
import com.wayoftime.bloodmagic.core.network.Binding;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import javax.annotation.Nullable;
import java.util.List;
/**
* Implement this interface on any Item that can be bound to a player.
*/
public interface IBindable {
/**
* Gets an object that stores who this item is bound to.
* <p>
* If the item is not bound, this will be null.
*
* @param stack - The owned ItemStack
* @return - The binding object
*/
@Nullable
default Binding getBinding(ItemStack stack) {
Binding binding = Binding.fromStack(stack);
return !stack.isEmpty() && binding != null ? binding : null;
}
/**
* Called when the player attempts to bind the item.
*
* @param player - The Player attempting to bind the item
* @param stack - The ItemStack to attempt binding
* @return If binding was successful.
*/
default boolean onBind(EntityPlayer player, ItemStack stack) {
return true;
}
static void applyBinding(ItemStack stack, EntityPlayer player) {
Binding binding = new Binding(player);
applyBinding(stack, binding);
}
static void applyBinding(ItemStack stack, Binding binding) {
if (!stack.hasTagCompound())
stack.setTagCompound(new NBTTagCompound());
stack.getTagCompound().setTag("binding", binding.serializeNBT());
}
static void appendTooltip(Binding binding, List<String> tooltip) {
if (binding != null)
tooltip.add(I18n.format("tooltip.bloodmagic:bound_owner", binding.getOwnerName()));
}
}

View file

@ -0,0 +1,84 @@
package com.wayoftime.bloodmagic.item;
import com.wayoftime.bloodmagic.block.BlockBloodAltar;
import com.wayoftime.bloodmagic.core.altar.AltarTier;
import com.wayoftime.bloodmagic.core.altar.AltarUtil;
import com.wayoftime.bloodmagic.core.altar.IAltarManipulator;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World;
import javax.annotation.Nullable;
import java.util.List;
public class ItemAltarBuilder extends ItemMundane implements IAltarManipulator {
public ItemAltarBuilder() {
super("altar_builder");
setMaxStackSize(1);
}
@Override
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
if (world.isRemote)
return ActionResult.newResult(EnumActionResult.PASS, player.getHeldItem(hand));
if (player.isSneaking()) {
ItemStack held = player.getHeldItem(hand);
AltarTier newTier = cycleTier(held);
player.sendStatusMessage(new TextComponentTranslation("chat.bloodmagic:altar_builder_cycled", new TextComponentTranslation("enchantment.level." + newTier.getDisplayNumber())), true);
return ActionResult.newResult(EnumActionResult.SUCCESS, held);
}
return super.onItemRightClick(world, player, hand);
}
@Override
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
IBlockState state = world.getBlockState(pos);
if (state.getBlock() instanceof BlockBloodAltar) {
AltarUtil.constructAltar(world, pos, getCurrentTier(player.getHeldItem(hand)));
return EnumActionResult.SUCCESS;
}
return super.onItemUse(player, world, pos, hand, facing, hitX, hitY, hitZ);
}
@Override
public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> tooltip, ITooltipFlag flagIn) {
tooltip.add(I18n.format("tooltip.bloodmagic:tier", I18n.format("enchantment.level." + getCurrentTier(stack).getDisplayNumber())));
}
private AltarTier getCurrentTier(ItemStack stack) {
if (!stack.hasTagCompound())
return AltarTier.ONE;
return AltarTier.VALUES[Math.min(AltarTier.VALUES.length - 1, Math.max(0, stack.getTagCompound().getInteger("altar_tier")))];
}
private AltarTier cycleTier(ItemStack stack) {
AltarTier current = getCurrentTier(stack);
int nextOrdinal = current.ordinal() + 1;
if (nextOrdinal >= AltarTier.VALUES.length)
nextOrdinal = 0;
NBTTagCompound tag = stack.getTagCompound();
if (tag == null)
stack.setTagCompound(tag = new NBTTagCompound());
tag.setInteger("altar_tier", nextOrdinal);
return AltarTier.VALUES[nextOrdinal];
}
}

View file

@ -0,0 +1,26 @@
package com.wayoftime.bloodmagic.item;
import com.wayoftime.bloodmagic.core.network.Binding;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import javax.annotation.Nullable;
import java.util.List;
public class ItemBindable extends ItemMundane implements IBindable {
public ItemBindable(String name) {
super(name);
}
@Override
public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> tooltip, ITooltipFlag flagIn) {
Binding binding = getBinding(stack);
if (binding == null)
return;
tooltip.add(I18n.format("tooltip.bloodmagic:bound_owner", binding.getOwnerName()));
}
}

View file

@ -0,0 +1,55 @@
package com.wayoftime.bloodmagic.item;
import com.wayoftime.bloodmagic.core.network.*;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class ItemBloodOrb extends ItemBindable implements IBloodOrb {
private final BloodOrb orb;
public ItemBloodOrb(BloodOrb orb) {
super("blood_orb_" + orb.getName().getPath());
this.orb = orb;
setMaxStackSize(1);
}
@Override
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
ItemStack held = player.getHeldItem(hand);
Binding binding = getBinding(held);
if (binding != null) {
SoulNetwork network = SoulNetwork.get(binding.getOwnerId());
if (player.capabilities.isCreativeMode || player.attackEntityFrom(SoulNetwork.WEAK_SOUL, 1.0F))
network.submitInteraction(NetworkInteraction.asItemInfo(held, world, player, 200));
}
return super.onItemRightClick(world, player, hand);
}
@Override
public void addInformation(ItemStack stack, @Nullable World world, List<String> tooltip, ITooltipFlag flag) {
super.addInformation(stack, world, tooltip, flag);
BloodOrb orb = getOrb(stack);
if (orb != null && flag.isAdvanced())
tooltip.add(I18n.format("tooltip.bloodmagic:object_owner", orb.getName().getNamespace()));
}
@Nullable
@Override
public BloodOrb getOrb(@Nonnull ItemStack stack) {
return orb;
}
}

View file

@ -0,0 +1,55 @@
package com.wayoftime.bloodmagic.item;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.core.RegistrarBloodMagic;
import com.wayoftime.bloodmagic.core.altar.AltarUtil;
import com.wayoftime.bloodmagic.core.network.SoulNetwork;
import com.wayoftime.bloodmagic.core.util.BooleanResult;
import com.wayoftime.bloodmagic.tile.TileBloodAltar;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fluids.FluidStack;
public class ItemDaggerSelfSacrifice extends ItemMundane {
private final Type type;
public ItemDaggerSelfSacrifice(Type sacrifice) {
super("dagger_self_sacrifice" + (sacrifice == Type.CREATIVE ? "_creative" : ""));
setMaxStackSize(1);
this.type = sacrifice;
if (sacrifice != Type.CREATIVE)
addPropertyOverride(new ResourceLocation(BloodMagic.MODID, "charged"), (stack, worldIn, entityIn) -> stack.hasTagCompound() && stack.getTagCompound().hasKey("charge") ? 1.0F : 0.0F);
}
@Override
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
player.attackEntityFrom(SoulNetwork.WEAK_SOUL, 2.0F);
BooleanResult<Integer> fillResult = AltarUtil.handleSacrifice(player, type.amount);
if (!fillResult.isSuccess())
return ActionResult.newResult(EnumActionResult.PASS, player.getHeldItem(hand));
return ActionResult.newResult(EnumActionResult.SUCCESS, player.getHeldItem(hand));
}
public enum Type {
NORMAL(200),
CREATIVE(Integer.MAX_VALUE),
;
private final int amount;
Type(int amount) {
this.amount = amount;
}
}
}

View file

@ -0,0 +1,163 @@
package com.wayoftime.bloodmagic.item;
import com.google.common.collect.Multimap;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.core.RegistrarBloodMagicItems;
import com.wayoftime.bloodmagic.core.living.ILivingContainer;
import com.wayoftime.bloodmagic.core.living.LivingStats;
import com.wayoftime.bloodmagic.core.living.LivingUpgrade;
import com.wayoftime.bloodmagic.core.living.LivingUtil;
import com.wayoftime.bloodmagic.core.network.Binding;
import com.wayoftime.bloodmagic.core.network.SoulNetwork;
import com.wayoftime.bloodmagic.core.network.NetworkInteraction;
import com.wayoftime.bloodmagic.core.util.BooleanResult;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.ItemArmor;
import net.minecraft.item.ItemStack;
import net.minecraft.util.DamageSource;
import net.minecraft.world.World;
import net.minecraftforge.common.ISpecialArmor;
import net.minecraftforge.common.util.EnumHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
public class ItemLivingArmor extends ItemArmor implements ILivingContainer, ISpecialArmor, IBindable {
public static final ArmorMaterial MATERIAL = EnumHelper.addArmorMaterial("living", "living", 100, new int[]{1, 2, 3, 4}, 3, SoundEvents.ITEM_ARMOR_EQUIP_IRON, 2.0F);
public ItemLivingArmor(EntityEquipmentSlot slot) {
super(MATERIAL, 0, slot);
setTranslationKey(BloodMagic.MODID + ":living_armor_" + slot.getName());
setRegistryName("living_armor_" + slot.getName());
setCreativeTab(BloodMagic.TAB_BM);
}
@Override
public void onArmorTick(World world, EntityPlayer player, ItemStack stack) {
if (getBinding(stack) == null)
IBindable.applyBinding(stack, player);
super.onArmorTick(world, player, stack);
}
@Override
public Multimap<String, AttributeModifier> getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack) {
Multimap<String, AttributeModifier> modifiers = super.getAttributeModifiers(slot, stack);
if (slot != EntityEquipmentSlot.CHEST)
return modifiers;
LivingStats stats = getLivingStats(stack);
if (stats == null)
return modifiers;
stats.getUpgrades().forEach((k, v) -> {
if (k.getAttributeProvider() != null)
k.getAttributeProvider().handleAttributes(stats, modifiers, k.getLevel(v));
});
return modifiers;
}
@Override
public ArmorProperties getProperties(EntityLivingBase player, @Nonnull ItemStack armor, DamageSource source, double damage, int slot) {
if (source == DamageSource.DROWN || source == DamageSource.OUT_OF_WORLD)
return new ArmorProperties(-1, 0D, 0);
double armorReduction;
double damageAmount = 0.25;
double armorPenetrationReduction = 0;
int maxAbsorption = 100000;
if (armor.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_FEET || armor.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_HEAD)
damageAmount = 3d / 20d * 0.6;
else if (armor.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_LEGS)
damageAmount = 6d / 20d * 0.6;
else if (armor.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_CHEST)
damageAmount = 0.64;
if (armor.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_CHEST) {
armorReduction = 0.24 / 0.64; // This values puts it at iron level
if (!LivingUtil.hasFullSet((EntityPlayer) player))
return new ArmorProperties(-1, damageAmount * armorReduction, maxAbsorption);
LivingStats stats = getLivingStats(armor);
double protection = 1.0D;
if (stats != null)
for (Map.Entry<LivingUpgrade, Integer> entry : stats.getUpgrades().entrySet())
if (entry.getKey().getArmorProvider() != null)
protection *= 1 - entry.getKey().getArmorProvider().getProtection((EntityPlayer) player, source, entry.getKey().getLevel(entry.getValue()));
armorReduction += (1 - protection) * (1 - armorReduction);
damageAmount *= armorReduction;
return new ArmorProperties(-1, source.isUnblockable() ? 1 - protection : damageAmount, maxAbsorption);
} else if (source.isUnblockable())
return new ArmorProperties(-1, damageAmount * armorPenetrationReduction, maxAbsorption);
return new ArmorProperties(-1, damageAmount, maxAbsorption);
}
@Override
public int getArmorDisplay(EntityPlayer player, @Nonnull ItemStack armor, int slot) {
if (armor.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_HEAD)
return 3;
if (armor.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_CHEST)
return 8;
if (armor.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_LEGS)
return 6;
if (armor.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_FEET)
return 3;
return 0;
}
@Nullable
@Override
public String getArmorTexture(ItemStack stack, Entity entity, EntityEquipmentSlot slot, String type) {
if (this == RegistrarBloodMagicItems.LIVING_ARMOR_CHEST || this == RegistrarBloodMagicItems.LIVING_ARMOR_HEAD || this == RegistrarBloodMagicItems.LIVING_ARMOR_FEET)
return "bloodmagic:textures/models/armor/living_armor_layer_1.png";
if (this == RegistrarBloodMagicItems.LIVING_ARMOR_LEGS)
return "bloodmagic:textures/models/armor/living_armor_layer_2.png";
return null;
}
@Override
public void damageArmor(EntityLivingBase entity, @Nonnull ItemStack stack, DamageSource source, int damage, int slot) {
if (stack.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_CHEST && damage > getMaxDamage(stack) - getDamage(stack)) {
Binding binding = getBinding(stack);
if (binding == null) {
entity.attackEntityFrom(SoulNetwork.WEAK_SOUL, 2.0F);
return;
}
BooleanResult<Integer> result = SoulNetwork.get(binding.getOwnerId()).submitInteraction(NetworkInteraction.asItemInfo(stack, entity.getEntityWorld(), entity, damage * 100).syphon());
if (!result.isSuccess())
entity.attackEntityFrom(SoulNetwork.WEAK_SOUL, 2.0F);
return;
}
stack.damageItem(damage, entity);
}
@SideOnly(Side.CLIENT)
@Override
public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> tooltip, ITooltipFlag flagIn) {
ILivingContainer.appendLivingTooltip(getLivingStats(stack), tooltip, true);
IBindable.appendTooltip(getBinding(stack), tooltip);
}
}

View file

@ -0,0 +1,63 @@
package com.wayoftime.bloodmagic.item;
import com.wayoftime.bloodmagic.core.RegistrarBloodMagicLivingArmor;
import com.wayoftime.bloodmagic.core.living.ILivingContainer;
import com.wayoftime.bloodmagic.core.living.LivingStats;
import com.wayoftime.bloodmagic.core.living.LivingUtil;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.world.World;
import javax.annotation.Nullable;
import java.util.List;
public class ItemLivingTome extends ItemMundane implements ILivingContainer {
public ItemLivingTome() {
super("living_tome");
}
@Override
public ActionResult<ItemStack> onItemRightClick(World worldIn, EntityPlayer player, EnumHand hand) {
ItemStack held = player.getHeldItem(hand);
LivingStats armorStats = LivingStats.fromPlayer(player, true);
if (armorStats == null)
return ActionResult.newResult(EnumActionResult.PASS, held);
LivingStats tomeStats = getLivingStats(held);
if (tomeStats == null)
return ActionResult.newResult(EnumActionResult.PASS, held);
tomeStats.getUpgrades().forEach((k, v) -> LivingUtil.applyNewExperience(player, k, v));
// LivingStats.toPlayer(player, armorStats);
held.shrink(1);
return ActionResult.newResult(EnumActionResult.SUCCESS, held);
}
@Override
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> items) {
if (!isInCreativeTab(tab))
return;
RegistrarBloodMagicLivingArmor.UPGRADES.values().forEach(upgrade -> {
int exp = 0;
while ((exp = upgrade.getNextRequirement(exp)) != 0) {
ItemStack tome = new ItemStack(this);
updateLivingStates(tome, new LivingStats().setMaxPoints(upgrade.getLevelCost(exp)).addExperience(upgrade.getKey(), exp));
items.add(tome);
}
});
}
@Override
public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> tooltip, ITooltipFlag flagIn) {
ILivingContainer.appendLivingTooltip(getLivingStats(stack), tooltip, false);
}
}

View file

@ -0,0 +1,13 @@
package com.wayoftime.bloodmagic.item;
import com.wayoftime.bloodmagic.BloodMagic;
import net.minecraft.item.Item;
public class ItemMundane extends Item {
public ItemMundane(String name) {
setTranslationKey(BloodMagic.MODID + ":" + name);
setCreativeTab(BloodMagic.TAB_BM);
setRegistryName(name);
}
}

View file

@ -0,0 +1,51 @@
package com.wayoftime.bloodmagic.item.sigil;
import com.wayoftime.bloodmagic.core.network.Binding;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
public interface ISigil {
@Nonnull
default EnumActionResult onRightClick(@Nonnull ItemStack stack, @Nonnull EntityPlayer player, @Nonnull World world, @Nonnull EnumHand hand, @Nonnull Binding binding) {
return EnumActionResult.PASS;
}
default EnumActionResult onInteract(@Nonnull ItemStack stack, @Nonnull EntityPlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side, @Nonnull EnumHand hand, @Nonnull Binding binding) {
return EnumActionResult.PASS;
}
@Nonnegative
int getCost();
interface Toggle extends ISigil {
default void onToggle(boolean active, @Nonnull ItemStack stack, @Nonnull EntityPlayer player, @Nonnull World world, @Nonnull EnumHand hand, @Nonnull Binding binding) {
}
default void onUpdate(@Nonnull ItemStack stack, @Nonnull EntityPlayer player, @Nonnull World world, @Nonnegative int itemSlot, boolean isHeld, @Nonnull Binding binding) {
}
}
interface Holding extends ISigil {
int getSize(ItemStack stack);
int getEquippedSigil(ItemStack stack);
NonNullList<ItemStack> getHeldSigils(ItemStack stack);
void setHeldSigils(ItemStack stack, NonNullList<ItemStack> inventory);
}
}

View file

@ -0,0 +1,176 @@
package com.wayoftime.bloodmagic.item.sigil;
import com.wayoftime.bloodmagic.BloodMagic;
import com.wayoftime.bloodmagic.core.network.Binding;
import com.wayoftime.bloodmagic.core.network.SoulNetwork;
import com.wayoftime.bloodmagic.core.network.NetworkInteraction;
import com.wayoftime.bloodmagic.core.util.BooleanResult;
import com.wayoftime.bloodmagic.core.util.register.IVariantProvider;
import com.wayoftime.bloodmagic.item.IBindable;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.IItemPropertyGetter;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nullable;
import java.util.List;
/*
* TODO - See checklist
* - [-] Sigils
* - [x] Divination
* - [x] Air
* - [x] Fast Miner
* - [-] Haste
* - [ ] Water
* - [ ] Lava
* - [ ] Void
* - [ ] Green Grove
* - [ ] Blood Light
* - [ ] Elemental Affinity
* - [ ] Magnetism
* - [ ] Suppression
* - [ ] Seer
* - Perhaps this could be modified to show network interaction history instead of additional altar data?
* - [ ] Ender Severance
* - [ ] Whirlwind
* - [ ] Phantom Bridge
* - [ ] Compression
* - [ ] Holding
* - [ ] Teleposition
* - [ ] Transposition
* - [ ] Claw
* - [ ] Bounce
* - [ ] Frost
*/
public class ItemSigil extends Item implements IBindable, IVariantProvider {
private final ISigil sigil;
public ItemSigil(ISigil sigil, String name) {
this.sigil = sigil;
setCreativeTab(BloodMagic.TAB_BM);
setTranslationKey(BloodMagic.MODID + ":sigil_" + name);
setRegistryName("sigil_" + name);
setMaxStackSize(1);
if (sigil instanceof ISigil.Toggle) {
addPropertyOverride(new ResourceLocation(BloodMagic.MODID, "toggled"), new IItemPropertyGetter() {
@SideOnly(Side.CLIENT)
@Override
public float apply(ItemStack stack, @Nullable World worldIn, @Nullable EntityLivingBase entityIn) {
return isActive(stack) ? 1.0F : 0.0F;
}
});
}
}
@Override
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
if (player instanceof FakePlayer)
return ActionResult.newResult(EnumActionResult.FAIL, player.getHeldItem(hand));
ItemStack sigilStack = getSigilStack(player, hand);
Binding binding = getBinding(sigilStack);
if (binding == null || binding.getOwnerId() == null)
return ActionResult.newResult(EnumActionResult.FAIL, player.getHeldItem(hand));
if (sigil instanceof ISigil.Toggle && player.isSneaking()) {
boolean newState = toggleState(sigilStack);
((ISigil.Toggle) sigil).onToggle(newState, sigilStack, player, world, hand, binding);
return ActionResult.newResult(EnumActionResult.SUCCESS, player.getHeldItem(hand));
}
EnumActionResult result = sigil.onRightClick(sigilStack, player, world, hand, binding);
if (result == EnumActionResult.SUCCESS) {
BooleanResult<Integer> syphonResult = SoulNetwork.get(binding.getOwnerId()).submitInteraction(NetworkInteraction.asItemInfo(sigilStack, world, player, sigil.getCost()).syphon());
if (!syphonResult.isSuccess())
player.attackEntityFrom(SoulNetwork.WEAK_SOUL, 2.0F);
}
return ActionResult.newResult(result, player.getHeldItem(hand));
}
@Override
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
if (player instanceof FakePlayer)
return EnumActionResult.FAIL;
ItemStack stack = getSigilStack(player, hand);
Binding binding = getBinding(stack);
if (binding == null)
return EnumActionResult.FAIL;
return sigil.onInteract(stack, player, world, pos, facing, hand, binding);
}
@Override
public void onUpdate(ItemStack stack, World world, Entity entity, int itemSlot, boolean isSelected) {
if (!(entity instanceof EntityPlayer) || entity instanceof FakePlayer)
return;
ItemStack sigilStack = getSigilStack(stack);
if (sigil instanceof ISigil.Toggle) {
Binding binding = getBinding(sigilStack);
if (binding != null && isActive(sigilStack)) {
((ISigil.Toggle) sigil).onUpdate(sigilStack, (EntityPlayer) entity, world, itemSlot, isSelected, binding);
if (world.getTotalWorldTime() % 100 == 0) {
BooleanResult<Integer> result = SoulNetwork.get(binding.getOwnerId()).submitInteraction(NetworkInteraction.asItemInfo(sigilStack, world, entity, sigil.getCost()).syphon());
if (!result.isSuccess())
entity.attackEntityFrom(SoulNetwork.WEAK_SOUL, 1.0F);
}
}
}
}
@Override
public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> tooltip, ITooltipFlag flagIn) {
IBindable.appendTooltip(getBinding(stack), tooltip);
}
@Override
public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) {
return slotChanged;
}
public ISigil getSigil() {
return sigil;
}
public ItemStack getSigilStack(EntityPlayer player, EnumHand hand) {
return getSigilStack(player.getHeldItem(hand));
}
public ItemStack getSigilStack(ItemStack sigilStack) {
if (sigil instanceof ISigil.Holding) {
ISigil.Holding holding = (ISigil.Holding) sigil;
int current = holding.getEquippedSigil(sigilStack);
return holding.getHeldSigils(sigilStack).get(current);
}
return sigilStack;
}
public boolean toggleState(ItemStack stack) {
if (!stack.hasTagCompound())
return false;
boolean newState = !isActive(stack);
stack.getTagCompound().setBoolean("active", newState);
return newState;
}
public boolean isActive(ItemStack stack) {
return stack.hasTagCompound() && stack.getTagCompound().getBoolean("active");
}
}

View file

@ -0,0 +1,46 @@
package com.wayoftime.bloodmagic.item.sigil;
import com.wayoftime.bloodmagic.core.network.Binding;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
public class SigilAir implements ISigil {
@Override
public int getCost() {
return 50;
}
@Nonnull
@Override
public EnumActionResult onRightClick(@Nonnull ItemStack stack, @Nonnull EntityPlayer player, @Nonnull World world, @Nonnull EnumHand hand, Binding binding) {
if (world.isRemote) {
Vec3d vec = player.getLookVec();
double wantedVelocity = 1.7;
// TODO - Revisit after potions
// if (player.isPotionActive(RegistrarBloodMagic.BOOST)) {
// int amplifier = player.getActivePotionEffect(RegistrarBloodMagic.BOOST).getAmplifier();
// wantedVelocity += (1 + amplifier) * (0.35);
// }
player.motionX = vec.x * wantedVelocity;
player.motionY = vec.y * wantedVelocity;
player.motionZ = vec.z * wantedVelocity;
world.playSound(null, player.posX, player.posY, player.posZ, SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.BLOCKS, 0.5F, 2.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.8F);
}
if (!world.isRemote)
player.fallDistance = 0;
return EnumActionResult.SUCCESS;
}
}

View file

@ -0,0 +1,27 @@
package com.wayoftime.bloodmagic.item.sigil;
import com.wayoftime.bloodmagic.core.network.Binding;
import com.wayoftime.bloodmagic.core.network.SoulNetwork;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
public class SigilDivination implements ISigil {
@Override
public int getCost() {
return 0;
}
@Nonnull
@Override
public EnumActionResult onRightClick(@Nonnull ItemStack stack, @Nonnull EntityPlayer player, @Nonnull World world, @Nonnull EnumHand hand, Binding binding) {
player.sendStatusMessage(new TextComponentString("Current Essence: " + SoulNetwork.get(binding.getOwnerId()).getEssence()), true);
return EnumActionResult.PASS;
}
}

View file

@ -0,0 +1,23 @@
package com.wayoftime.bloodmagic.item.sigil;
import com.wayoftime.bloodmagic.core.network.Binding;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.MobEffects;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.PotionEffect;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
public class SigilFastMiner implements ISigil.Toggle {
@Override
public int getCost() {
return 100;
}
@Override
public void onUpdate(@Nonnull ItemStack stack, @Nonnull EntityPlayer player, @Nonnull World world, int itemSlot, boolean isHeld, @Nonnull Binding binding) {
player.addPotionEffect(new PotionEffect(MobEffects.HASTE, 2, 0, true, false));
}
}

View file

@ -0,0 +1,23 @@
package com.wayoftime.bloodmagic.item.sigil;
import com.wayoftime.bloodmagic.core.network.Binding;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.MobEffects;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.PotionEffect;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
public class SigilHaste implements ISigil.Toggle {
@Override
public int getCost() {
return 250;
}
@Override
public void onUpdate(@Nonnull ItemStack stack, @Nonnull EntityPlayer player, @Nonnull World world, int itemSlot, boolean isHeld, @Nonnull Binding binding) {
player.addPotionEffect(new PotionEffect(MobEffects.SPEED, 2, 0, true, false)); // TODO - RegistrarBloodMagic.BOOST
}
}

View file

@ -0,0 +1,15 @@
package com.wayoftime.bloodmagic.proxy;
import com.wayoftime.bloodmagic.BloodMagic;
import net.minecraftforge.client.model.obj.OBJLoader;
import org.lwjgl.opengl.Display;
public class ClientProxy implements IProxy {
@Override
public void preInit() {
OBJLoader.INSTANCE.addDomain(BloodMagic.MODID);
Display.setTitle("Basically 1.13"); // TODO - :BigThink:
}
}

View file

@ -0,0 +1,8 @@
package com.wayoftime.bloodmagic.proxy;
public interface IProxy {
default void preInit() {
}
}

View file

@ -0,0 +1,4 @@
package com.wayoftime.bloodmagic.proxy;
public class ServerProxy implements IProxy {
}

View file

@ -0,0 +1,268 @@
package com.wayoftime.bloodmagic.tile;
import com.wayoftime.bloodmagic.api.event.BloodMagicCraftedEvent;
import com.wayoftime.bloodmagic.api.impl.BloodMagicAPI;
import com.wayoftime.bloodmagic.api.impl.recipe.RecipeBloodAltar;
import com.wayoftime.bloodmagic.core.RegistrarBloodMagic;
import com.wayoftime.bloodmagic.core.altar.AltarTier;
import com.wayoftime.bloodmagic.core.altar.AltarUpgrades;
import com.wayoftime.bloodmagic.core.altar.AltarUtil;
import com.wayoftime.bloodmagic.core.network.*;
import com.wayoftime.bloodmagic.item.IBindable;
import com.wayoftime.bloodmagic.tile.base.TileBase;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ITickable;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTank;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fml.common.registry.ForgeRegistries;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import javax.annotation.Nullable;
/*
* TODO - See checklist
* - [-] Upgrades
* - [x] Self Sacrifice
* - [x] Sacrifice
* - [x] Capacity
* - [x] Augmented Capacity
* - [ ] Speed
* - [ ] Displacement
* - [ ] Orb
* - [ ] Acceleration
* - [ ] Charging
* - [-] Tanks
* - [x] Main tank keeps buffer filled
* - [ ] Buffer fills main tank
*/
public class TileBloodAltar extends TileBase implements ITickable {
private FluidTank tank = new FluidTank(new FluidStack(RegistrarBloodMagic.FLUID_LIFE_ESSENCE, 0), 10000);
private FluidTank buffer = new FluidTank(new FluidStack(RegistrarBloodMagic.FLUID_LIFE_ESSENCE, 0), 1000); // Buffer has 10% the capacity of the tank
private ItemStackHandler itemHandler = new ItemStackHandler(1);
private AltarTier currentTier = AltarTier.ONE;
private AltarUpgrades upgrades = new AltarUpgrades();
private float progress;
private RecipeBloodAltar recipe = null;
private int drained;
private long lastCompletionTime;
public TileBloodAltar() {
tank.setTileEntity(this);
}
@Override
public void update() {
if (getWorld().getTotalWorldTime() % 20 == 0) {
currentTier = AltarUtil.getTier(getWorld(), getPos());
upgrades = AltarUtil.getUpgrades(getWorld(), pos, currentTier);
handleTankUpdates();
}
if (getWorld().getTotalWorldTime() - lastCompletionTime > 20)
handleRecipe();
}
protected void handleTankUpdates() {
tank.setCapacity((int) (Fluid.BUCKET_VOLUME * 10 * upgrades.getCapacityModifier()));
if (tank.getCapacity() < tank.getFluidAmount())
tank.setFluid(new FluidStack(RegistrarBloodMagic.FLUID_LIFE_ESSENCE, tank.getCapacity()));
buffer.setCapacity((int) (tank.getCapacity() * 0.1D));
if (buffer.getCapacity() < buffer.getFluidAmount())
buffer.setFluid(new FluidStack(RegistrarBloodMagic.FLUID_LIFE_ESSENCE, buffer.getCapacity()));
if (buffer.getCapacity() > buffer.getFluidAmount() && tank.getFluidAmount() > 0) {
FluidStack drained = tank.drain(100, true);
if (drained != null)
buffer.fill(drained, true);
}
}
protected void handleRecipe() {
ItemStack inputItem = itemHandler.getStackInSlot(0);
if (inputItem.isEmpty())
return;
// Only look for a recipe if the altar currently has blood in it as well as the current recipe is null or the item doesn't match the recipe input
if (tank.getFluidAmount() > 0 && (recipe == null || !recipe.getInput().apply(inputItem))) {
RecipeBloodAltar newRecipe = BloodMagicAPI.INSTANCE.getRecipeRegistrar().getBloodAltar(inputItem);
if (newRecipe != null && newRecipe.getMinimumTier().ordinal() <= currentTier.ordinal())
recipe = newRecipe;
}
// Match orbs
if (recipe == null) {
if (inputItem.getItem() instanceof IBloodOrb && inputItem.getItem() instanceof IBindable) {
BloodOrb orb = ((IBloodOrb) inputItem.getItem()).getOrb(inputItem);
Binding binding = ((IBindable) inputItem.getItem()).getBinding(inputItem);
if (orb != null && binding != null) {
if (currentTier.ordinal() < orb.getTier())
return;
SoulNetwork network = SoulNetwork.get(binding.getOwnerId());
if (network.getEssence() < orb.getCapacity()) {
FluidStack drained = tank.drain(new FluidStack(RegistrarBloodMagic.FLUID_LIFE_ESSENCE, orb.getFillRate()), true);
if (drained != null)
network.submitInteraction(NetworkInteraction.asItemInfo(inputItem, world, pos, drained.amount));
}
}
}
return;
}
// Check tier
if (recipe.getMinimumTier().ordinal() > currentTier.ordinal())
return;
// Check and handle progress loss
if (tank.getFluidAmount() <= 0) {
progress = Math.max(0, progress - (recipe.getDrainRate() / (recipe.getSyphon() * inputItem.getCount())));
if (getWorld() instanceof WorldServer)
((WorldServer) getWorld()).spawnParticle(EnumParticleTypes.SMOKE_NORMAL, pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5, 1, 0.1, 0, 0.1, 0);
return;
}
FluidStack tankDrain = tank.drain(new FluidStack(RegistrarBloodMagic.FLUID_LIFE_ESSENCE, recipe.getConsumeRate()), true);
if (tankDrain == null)
return;
if (getWorld() instanceof WorldServer)
((WorldServer) getWorld()).spawnParticle(EnumParticleTypes.REDSTONE, pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5, 1, 0.2, 0, 0.2, 0);
drained += tankDrain.amount;
progress = (float) drained / (Math.max(recipe.getSyphon() * inputItem.getCount(), 1));
if (progress >= 1.0F) {
BloodMagicCraftedEvent.Altar event = new BloodMagicCraftedEvent.Altar(recipe.getOutput(), inputItem);
MinecraftForge.EVENT_BUS.post(event);
if (getWorld() instanceof WorldServer)
((WorldServer) getWorld()).spawnParticle(EnumParticleTypes.REDSTONE, pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5, 40, 0.3, 0, 0.3, 0);
itemHandler.setStackInSlot(0, event.getOutput());
lastCompletionTime = getWorld().getTotalWorldTime();
resetProgress();
}
}
@Override
public void deserialize(NBTTagCompound tag) {
tank.readFromNBT(tag.getCompoundTag("tank"));
tank.setTileEntity(this);
itemHandler.deserializeNBT(tag.getCompoundTag("inventory"));
progress = tag.getFloat("progress");
currentTier = AltarTier.VALUES[tag.getInteger("tier")];
drained = tag.getInteger("drained");
lastCompletionTime = tag.getLong("lastCompletionTime");
}
@Override
public void serialize(NBTTagCompound tag) {
tag.setTag("tank", tank.writeToNBT(new NBTTagCompound()));
tag.setTag("inventory", itemHandler.serializeNBT());
tag.setFloat("progress", progress);
tag.setInteger("tier", currentTier.ordinal());
tag.setInteger("drained", drained);
tag.setLong("lastCompletionTime", lastCompletionTime);
}
@Override
public boolean hasCapability(Capability<?> capability, @Nullable EnumFacing facing) {
return super.hasCapability(capability, facing) || capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY || capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY;
}
@Nullable
@Override
public <T> T getCapability(Capability<T> capability, @Nullable EnumFacing facing) {
if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
return facing == null ? (T) tank : (T) buffer;
if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return (T) itemHandler;
return super.getCapability(capability, facing);
}
@Override
public NBTTagCompound getUpdateTag() {
NBTTagCompound tag = new NBTTagCompound();
writeToNBT(tag);
ItemStack contained = itemHandler.getStackInSlot(0);
if (!contained.isEmpty()) {
NBTTagCompound itemTag = new NBTTagCompound();
itemTag.setString("item", contained.getItem().getRegistryName().toString());
itemTag.setInteger("count", contained.getCount());
itemTag.setInteger("data", contained.getMetadata());
NBTTagCompound shareTag = contained.getItem().getNBTShareTag(contained);
if (shareTag != null)
itemTag.setTag("nbt", shareTag);
tag.setTag("item", itemTag);
}
tag.setTag("tank", tank.writeToNBT(new NBTTagCompound()));
tag.setFloat("progress", progress);
return tag;
}
@Override
public void handleUpdateTag(NBTTagCompound tag) {
readCurrentPos(tag);
if (tag.hasKey("item")) {
Item item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(tag.getString("item")));
int count = tag.getInteger("count");
int meta = tag.getInteger("data");
NBTTagCompound nbt = null;
if (tag.hasKey("nbt"))
nbt = tag.getCompoundTag("nbt");
ItemStack stack = new ItemStack(item, count, meta);
if (nbt != null)
stack.deserializeNBT(nbt);
itemHandler.setStackInSlot(0, stack);
} else {
itemHandler.setStackInSlot(0, ItemStack.EMPTY);
}
tank.readFromNBT(tag.getCompoundTag("tank"));
progress = tag.getFloat("progress");
}
public void resetProgress() {
recipe = null;
drained = 0;
progress = 0.0F;
}
public FluidTank getTank() {
return tank;
}
public boolean isCrafting() {
return recipe != null;
}
public AltarTier getCurrentTier() {
return currentTier;
}
public float getProgress() {
return progress;
}
public AltarUpgrades getUpgrades() {
return upgrades;
}
}

View file

@ -0,0 +1,127 @@
package com.wayoftime.bloodmagic.tile.base;
import net.minecraft.block.state.IBlockState;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
/**
* Base tile class.
* <p>
* Handles data syncing and core data writing/reading.
*/
public class TileBase extends TileEntity {
@Override
public final void readFromNBT(NBTTagCompound compound) {
super.readFromNBT(compound);
if (compound.hasKey("baseData"))
deserializeBase(compound.getCompoundTag("baseData"));
deserialize(compound.getCompoundTag("tileData"));
}
@Override
public final NBTTagCompound writeToNBT(NBTTagCompound compound) {
super.writeToNBT(compound);
NBTTagCompound base = serializeBase();
if (base != null)
compound.setTag("baseData", base);
NBTTagCompound tileData = new NBTTagCompound();
serialize(tileData);
compound.setTag("tileData", tileData);
return compound;
}
/**
* Called by {@link #readFromNBT(NBTTagCompound)}
* <p>
* Internal data (such as coordinates) are handled for you. Just read the data you need.
*
* @param tagCompound - The tag compound to read from
*/
public void deserialize(NBTTagCompound tagCompound) {
}
/**
* Package private method for reading base data from the tag compound.
*
* @param tagCompound - The tag compound to read from
*/
void deserializeBase(NBTTagCompound tagCompound) {
}
/**
* Called by {@link #writeToNBT(NBTTagCompound)}
* <p>
* Internal data (such as coordinates) are handled for you. Just read the data you need.
*
* @param tagCompound - The tag compound to write to.
* @return the modified tag compound
*/
public void serialize(NBTTagCompound tagCompound) {
}
/**
* Package private method for writing base data to the tag compound.
*
* @return the modified tag compound
*/
NBTTagCompound serializeBase() {
return null;
}
protected final NBTTagCompound writeCurrentPos(NBTTagCompound compound) {
compound.setString("id", getKey(getClass()).toString());
compound.setInteger("x", this.pos.getX());
compound.setInteger("y", this.pos.getY());
compound.setInteger("z", this.pos.getZ());
return compound;
}
protected final void readCurrentPos(NBTTagCompound tag) {
this.pos = new BlockPos(tag.getInteger("x"), tag.getInteger("y"), tag.getInteger("z"));
}
public void notifyUpdate() {
IBlockState state = world.getBlockState(pos);
getWorld().notifyBlockUpdate(pos, state, state, 3);
}
// Data syncing
@Override
public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newState) {
return oldState.getBlock() != newState.getBlock();
}
@Override
public final SPacketUpdateTileEntity getUpdatePacket() {
return new SPacketUpdateTileEntity(getPos(), -999, writeToNBT(new NBTTagCompound()));
}
@Override
public final void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) {
super.onDataPacket(net, pkt);
readFromNBT(pkt.getNbtCompound());
}
@Override
public NBTTagCompound getUpdateTag() {
return writeToNBT(new NBTTagCompound());
}
@Override
public void handleUpdateTag(NBTTagCompound tag) {
readFromNBT(tag);
}
}