First stab at Living Armour reimplementation.

Added a lot of the upgrades, but there's still more testing/upgrades to be done/reimplemented.
This commit is contained in:
WayofTime 2020-11-28 12:04:11 -05:00
parent 06faa916c3
commit 2075fa5be3
42 changed files with 2352 additions and 2 deletions

View file

@ -0,0 +1,182 @@
package wayoftime.bloodmagic.core;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import com.google.common.base.Charsets;
import com.google.common.io.Resources;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.util.ResourceLocation;
import wayoftime.bloodmagic.BloodMagic;
import wayoftime.bloodmagic.common.registration.impl.LivingUpgradeDeferredRegister;
import wayoftime.bloodmagic.common.registration.impl.LivingUpgradeRegistryObject;
import wayoftime.bloodmagic.core.living.LivingUpgrade;
import wayoftime.bloodmagic.gson.Serializers;
public class LivingArmorRegistrar
{
public static final LivingUpgradeDeferredRegister UPGRADES = new LivingUpgradeDeferredRegister(BloodMagic.MODID);
public static final Map<ResourceLocation, LivingUpgrade> UPGRADE_MAP = new HashMap<>();
// public static final DefaultedRegistry<LivingUpgrade> UPGRADES = (DefaultedRegistry<LivingUpgrade>) createRegistry("livingarmor:upgrades", LivingUpgrade.DUMMY.getKey().toString(), () -> LivingUpgrade.DUMMY);
// private static final Map<String, ResourceLocation> DEFINITIONS = ((Supplier<Map<String, ResourceLocation>>) () -> {
// Map<String, ResourceLocation> def = new HashMap<>();
// def.put("arrow_protect", Paths.get(MinecraftForge.getInstance().getConfigDirectory().getAbsolutePath(), "livingarmor", "arrow_protect.json"));
// def.put("arrow_shot", Paths.get(FabricLoader.getInstance().getConfigDirectory().getAbsolutePath(), "livingarmor", "arrow_shot.json"));
// def.put("critical_strike", Paths.get(FabricLoader.getInstance().getConfigDirectory().getAbsolutePath(), "livingarmor", "critical_strike.json"));
// def.put("jump", Paths.get(FabricLoader.getInstance().getConfigDirectory().getAbsolutePath(), "livingarmor", "jump.json"));
// return def;
// }).get();
private static final Map<String, ResourceLocation> DEFINITIONS = ((Supplier<Map<String, ResourceLocation>>) () -> {
Map<String, ResourceLocation> def = new HashMap<>();
def.put("arrow_protect", BloodMagic.rl("arrow_protect"));
def.put("arrow_shot", BloodMagic.rl("arrow_shot"));
def.put("critical_strike", BloodMagic.rl("critical_strike"));
def.put("jump", BloodMagic.rl("jump"));
def.put("health", BloodMagic.rl("health"));
def.put("experience", BloodMagic.rl("experienced"));
def.put("sprint_attack", BloodMagic.rl("sprint_attack"));
def.put("self_sacrifice", BloodMagic.rl("self_sacrifice"));
def.put("speed", BloodMagic.rl("speed"));
return def;
}).get();
// private static final Map<String, Path> DEFINITIONS =
// ResourceUtil.gatherResources("/data", "living_armor", p ->
// FilenameUtils.getExtension(p.toFile().getName()).equals("json"))
// .stream()
// .collect(Collectors.toMap(key -> FilenameUtils.getBaseName(key.toFile().getName()), value -> value));
private static final Gson GSON = new GsonBuilder().serializeNulls().create();
// public static final ItemLivingArmor LIVING_HELMET = new ItemLivingArmor(EquipmentSlotType.HEAD);
// public static final ItemLivingArmor LIVING_CHESTPLATE = new ItemLivingArmor(EquipmentSlotType.CHEST);
// public static final ItemLivingArmor LIVING_LEGGINGS = new ItemLivingArmor(EquipmentSlotType.LEGS);
// public static final ItemLivingArmor LIVING_BOOTS = new ItemLivingArmor(EquipmentSlotType.FEET);
// public static final ItemLivingTrainer TRAINER = new ItemLivingTrainer();
// public static final ItemLivingTome TOME = new ItemLivingTome();
public static final LivingUpgradeRegistryObject<LivingUpgrade> UPGRADE_ARROW_PROTECT = UPGRADES.register("arrow_protect", () -> parseDefinition("arrow_protect").withArmorProvider((player, stats, source, upgrade, level) -> {
if (source.isProjectile())
{
return upgrade.getBonusValue("protection", level).doubleValue();
}
return 0;
}));
public static final LivingUpgradeRegistryObject<LivingUpgrade> UPGRADE_HEALTH = UPGRADES.register("health", () -> parseDefinition("health").withAttributeProvider((stats, attributeMap, uuid, upgrade, level) -> {
attributeMap.put(Attributes.MAX_HEALTH, new AttributeModifier(uuid, "Health Modifier", upgrade.getBonusValue("hp", level).intValue(), AttributeModifier.Operation.ADDITION));
}));
public static final LivingUpgradeRegistryObject<LivingUpgrade> UPGRADE_EXPERIENCE = UPGRADES.register("experienced", () -> parseDefinition("experienced"));
public static final LivingUpgradeRegistryObject<LivingUpgrade> UPGRADE_SPRINT_ATTACK = UPGRADES.register("sprint_attack", () -> parseDefinition("sprint_attack").withDamageProvider((player, weapon, damage, stats, attackedEntity, upgrade, level) -> {
if (player.isSprinting())
{
return damage * upgrade.getBonusValue("damage_boost", level).doubleValue();
}
return 0;
}));
public static final LivingUpgradeRegistryObject<LivingUpgrade> UPGRADE_SELF_SACRIFICE = UPGRADES.register("self_sacrifice", () -> parseDefinition("self_sacrifice"));
public static final LivingUpgradeRegistryObject<LivingUpgrade> UPGRADE_SPEED = UPGRADES.register("speed", () -> parseDefinition("speed"));
// public static final LivingUpgrade UPGRADE_ARROW_PROTECT = parseDefinition("arrow_protect").withArmorProvider((player, stats, source, upgrade, level) -> {
// if (source.isProjectile())
// {
// return upgrade.getBonusValue("protection", level).doubleValue();
// }
// return 0;
// });
// public static final LivingUpgrade UPGRADE_ARROW_SHOT = parseDefinition("arrow_shot");
// public static final LivingUpgrade UPGRADE_CRITICAL_STRIKE = parseDefinition("critical_strike").withAttributeProvider((stats, attributeMap, uuid, upgrade, level) -> {
// attributeMap.put(Attributes.ATTACK_DAMAGE, new AttributeModifier(uuid, "Weapon modifier", upgrade.getBonusValue("damage_boost", level).doubleValue(), AttributeModifier.Operation.ADDITION));
//// attributeMap.put(EntityAttributes.ATTACK_DAMAGE.getId(), AttributeModifiers.create(upgrade, "damage_boost", upgrade.getBonusValue("damage_boost", level).doubleValue(), EntityAttributeModifier.Operation.ADDITION));
//// attributeMap.put(EntityAttributes.ATTACK_DAMAGE.getId(), AttributeModifiers.create(upgrade, "damage_boost", level, EntityAttributeModifier.Operation.ADDITION));
// });
// public static final LivingUpgrade UPGRADE_JUMP = parseDefinition("jump");
public static void register()
{
registerUpgrade(UPGRADE_ARROW_PROTECT.get());
registerUpgrade(UPGRADE_HEALTH.get());
registerUpgrade(UPGRADE_EXPERIENCE.get());
registerUpgrade(UPGRADE_SPRINT_ATTACK.get());
registerUpgrade(UPGRADE_SELF_SACRIFICE.get());
registerUpgrade(UPGRADE_SPEED.get());
// Registry.register(UPGRADES, UPGRADE_ARROW_PROTECT.getKey(), UPGRADE_ARROW_PROTECT);
// Registry.register(UPGRADES, UPGRADE_ARROW_SHOT.getKey(), UPGRADE_ARROW_SHOT);
// Registry.register(UPGRADES, UPGRADE_CRITICAL_STRIKE.getKey(), UPGRADE_CRITICAL_STRIKE);
// Registry.register(UPGRADES, UPGRADE_JUMP.getKey(), UPGRADE_JUMP);
// Registry.register(Registry.ITEM, new ResourceLocation("livingarmor", "living_helmet"), LIVING_HELMET);
// Registry.register(Registry.ITEM, new Identifier("livingarmor", "living_chestplate"), LIVING_CHESTPLATE);
// Registry.register(Registry.ITEM, new Identifier("livingarmor", "living_leggings"), LIVING_LEGGINGS);
// Registry.register(Registry.ITEM, new Identifier("livingarmor", "living_boots"), LIVING_BOOTS);
// Registry.register(Registry.ITEM, new Identifier("livingarmor", "trainer"), TRAINER);
// Registry.register(Registry.ITEM, new Identifier("livingarmor", "tome"), TOME);
}
public static void registerUpgrade(LivingUpgrade upgrade)
{
UPGRADE_MAP.put(upgrade.getKey(), upgrade);
}
public static LivingUpgrade parseDefinition(String fileName)
{
ResourceLocation path = DEFINITIONS.get(fileName);
if (path == null)
return LivingUpgrade.DUMMY;
try
{
URL schematicURL = LivingUpgrade.class.getResource(resLocToResourcePath(path));
System.out.println("Attempting to load Living Armour Upgrade: " + schematicURL + ", path: " + resLocToResourcePath(path));
return Serializers.GSON.fromJson(Resources.toString(schematicURL, Charsets.UTF_8), LivingUpgrade.class);
// return GSON.fromJson(IOUtils.toString(path.toUri(), StandardCharsets.UTF_8), LivingUpgrade.class);
} catch (Exception e)
{
e.printStackTrace();
return LivingUpgrade.DUMMY;
}
// Path path = DEFINITIONS.get(fileName);
// if (path == null)
// return LivingUpgrade.DUMMY;
//
// try
// {
// return GSON.fromJson(IOUtils.toString(path.toUri(), StandardCharsets.UTF_8), LivingUpgrade.class);
// } catch (Exception e)
// {
// e.printStackTrace();
// return LivingUpgrade.DUMMY;
// }
}
public static String resLocToResourcePath(ResourceLocation resourceLocation)
{
return "/data/" + resourceLocation.getNamespace() + "/living_armor/" + resourceLocation.getPath() + ".json";
}
// private static <T> Registry<T> createRegistry(String registryId, String defaultId, Supplier<T> defaultProvider)
// {
// try
// {
// Method _createRegistry = Registry.class.getDeclaredMethod("create", String.class, String.class, Supplier.class); // FIXME
// // yarn
// // name
// _createRegistry.setAccessible(true);
// return (Registry<T>) _createRegistry.invoke(null, registryId, defaultId, defaultProvider);
// } catch (Exception e)
// {
// e.printStackTrace();
// MutableRegistry<T> registry = new DefaultedRegistry(defaultId, null, null);
// registry.add(new ResourceLocation(defaultId), defaultProvider.get());
// return registry;
// }
// }
}

View file

@ -0,0 +1,60 @@
package wayoftime.bloodmagic.core.living;
import java.util.List;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public interface ILivingContainer
{
default LivingStats getLivingStats(ItemStack stack)
{
if (!stack.hasTag() || !stack.getTag().contains("livingStats"))
return null;
return LivingStats.fromNBT(stack.getTag().getCompound("livingStats"));
}
default void updateLivingStats(ItemStack stack, LivingStats stats)
{
if (stats == null)
{
if (stack.hasTag())
stack.getTag().remove("livingStats");
return;
}
if (!stack.hasTag())
stack.setTag(new CompoundNBT());
stack.getTag().put("livingStats", stats.serialize());
}
@OnlyIn(Dist.CLIENT)
static void appendLivingTooltip(LivingStats stats, List<ITextComponent> tooltip, boolean trainable)
{
if (stats != null)
{
if (trainable)
tooltip.add(new TranslationTextComponent("tooltip.bloodmagic.livingarmour.upgrade.points", stats.getUsedPoints(), stats.getMaxPoints()).mergeStyle(TextFormatting.GOLD));
stats.getUpgrades().forEach((k, v) -> {
if (k.getLevel(v.intValue()) <= 0)
return;
boolean sneaking = Screen.hasShiftDown();
// if (!InputUtil.isKeyPressed(MinecraftClient.getInstance().getWindow().getHandle(), 340) || k.getNextRequirement(v) == 0)
if (!sneaking || k.getNextRequirement(v.intValue()) == 0)
tooltip.add(new TranslationTextComponent("%s %s", new TranslationTextComponent(k.getTranslationKey()), new TranslationTextComponent("enchantment.level." + k.getLevel(v.intValue()))));
else
tooltip.add(new TranslationTextComponent("%s %s", new TranslationTextComponent(k.getTranslationKey()), (": " + v.intValue() + "/" + k.getNextRequirement(v.intValue()))));
});
}
}
}

View file

@ -0,0 +1,150 @@
package wayoftime.bloodmagic.core.living;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.ResourceLocation;
import wayoftime.bloodmagic.core.LivingArmorRegistrar;
public class LivingStats
{
public static final int DEFAULT_UPGRADE_POINTS = 100;
private final Map<LivingUpgrade, Double> upgrades;
private int maxPoints = DEFAULT_UPGRADE_POINTS;
public LivingStats(Map<LivingUpgrade, Double> upgrades)
{
this.upgrades = upgrades;
}
public LivingStats()
{
this(Maps.newHashMap());
}
public Map<LivingUpgrade, Double> getUpgrades()
{
return ImmutableMap.copyOf(upgrades);
}
public LivingStats addExperience(ResourceLocation key, double experience)
{
// LivingUpgrade upgrade = LivingArmorRegistrar.UPGRADES.getOrDefault(key);
LivingUpgrade upgrade = LivingArmorRegistrar.UPGRADE_MAP.getOrDefault(key, LivingUpgrade.DUMMY);
double current = upgrades.getOrDefault(upgrade, 0d);
System.out.println("Upgrade: " + upgrade);
if (upgrade.getNextRequirement((int) current) == 0)
return this;
upgrades.put(upgrade, current + experience);
return this;
}
public int getLevel(ResourceLocation key)
{
LivingUpgrade upgrade = LivingArmorRegistrar.UPGRADE_MAP.getOrDefault(key, LivingUpgrade.DUMMY);
// LivingUpgrade upgrade = LivingArmorRegistrar.UPGRADES.getOrDefault(key);
return upgrade.getLevel(upgrades.getOrDefault(upgrade, 0d).intValue());
}
public int getUsedPoints()
{
int total = 0;
for (Map.Entry<LivingUpgrade, Double> applied : upgrades.entrySet())
{
double experience = applied.getValue();
int level = applied.getKey().getLevel((int) 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;
}
public CompoundNBT serialize()
{
CompoundNBT compound = new CompoundNBT();
ListNBT statList = new ListNBT();
upgrades.forEach((k, v) -> {
CompoundNBT upgrade = new CompoundNBT();
upgrade.putString("key", k.getKey().toString());
upgrade.putDouble("exp", v);
statList.add(upgrade);
});
compound.put("upgrades", statList);
compound.putInt("maxPoints", maxPoints);
return compound;
}
public void deserialize(CompoundNBT nbt)
{
ListNBT statList = nbt.getList("upgrades", 10);
statList.forEach(tag -> {
if (!(tag instanceof CompoundNBT))
return;
LivingUpgrade upgrade = LivingArmorRegistrar.UPGRADE_MAP.getOrDefault(new ResourceLocation(((CompoundNBT) tag).getString("key")), LivingUpgrade.DUMMY);
if (upgrade == LivingUpgrade.DUMMY)
return;
double experience = ((CompoundNBT) tag).getDouble("exp");
upgrades.put(upgrade, experience);
});
maxPoints = nbt.getInt("maxPoints");
}
public static LivingStats fromNBT(CompoundNBT statTag)
{
LivingStats stats = new LivingStats();
stats.deserialize(statTag);
return stats;
}
public static LivingStats fromPlayer(PlayerEntity player)
{
return fromPlayer(player, false);
}
public static LivingStats fromPlayer(PlayerEntity player, boolean createNew)
{
if (!LivingUtil.hasFullSet(player))
return null;
ItemStack chest = player.getItemStackFromSlot(EquipmentSlotType.CHEST);
LivingStats stats = ((ILivingContainer) chest.getItem()).getLivingStats(chest);
return stats == null && createNew ? new LivingStats() : stats;
}
public static void toPlayer(PlayerEntity player, LivingStats stats)
{
if (!LivingUtil.hasFullSet(player))
return;
ItemStack chest = player.getItemStackFromSlot(EquipmentSlotType.CHEST);
((ILivingContainer) chest.getItem()).updateLivingStats(chest, stats);
}
}

View file

@ -0,0 +1,267 @@
package wayoftime.bloodmagic.core.living;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import java.util.function.Consumer;
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 com.google.common.reflect.TypeToken;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.attributes.Attribute;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.DamageSource;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.Util;
import net.minecraftforge.registries.ForgeRegistryEntry;
@JsonAdapter(LivingUpgrade.Deserializer.class)
public class LivingUpgrade extends ForgeRegistryEntry<LivingUpgrade>
{
public static final LivingUpgrade DUMMY = new LivingUpgrade(new ResourceLocation("dummy"), levels -> levels.add(new Level(0, 0)));
private final ResourceLocation key;
private final Set<ResourceLocation> incompatible;
private final TreeMap<Integer, Integer> experienceToLevel;
private final Map<Integer, Integer> levelToCost;
private final Map<String, Bonus> bonuses;
private boolean isNegative;
private String translationKey = null;
private IAttributeProvider attributeProvider;
private IArmorProvider armorProvider;
private IDamageProvider damageProvider;
public LivingUpgrade(ResourceLocation key, Consumer<List<Level>> experienceMapper)
{
this.key = key;
this.incompatible = Sets.newHashSet();
this.experienceToLevel = Maps.newTreeMap();
this.levelToCost = Maps.newHashMap();
this.bonuses = Maps.newHashMap();
List<Level> levels = Lists.newArrayList();
experienceMapper.accept(levels);
for (int i = 0; i < levels.size(); i++)
{
Level level = levels.get(i);
experienceToLevel.put(level.experienceNeeded, i + 1);
levelToCost.put(i + 1, level.upgradeCost);
}
}
public LivingUpgrade withBonusSet(String id, Consumer<List<Number>> modifiers)
{
// List<Number> values = DefaultedList.of();
List<Number> values = new ArrayList<Number>();
modifiers.accept(values);
if (values.size() != levelToCost.size())
throw new RuntimeException("Bonus size and level size must be the same.");
bonuses.put(id, new Bonus(id, values));
return this;
}
public Number getBonusValue(String id, int level)
{
List<Number> modifiers = bonuses.getOrDefault(id, Bonus.DEFAULT).modifiers;
if (modifiers.isEmpty() || level == 0)
return 0;
return modifiers.get(level - 1);
}
public LivingUpgrade withAttributeProvider(IAttributeProvider attributeProvider)
{
this.attributeProvider = attributeProvider;
return this;
}
public IAttributeProvider getAttributeProvider()
{
return attributeProvider;
}
public LivingUpgrade withArmorProvider(IArmorProvider armorProvider)
{
this.armorProvider = armorProvider;
return this;
}
public IArmorProvider getArmorProvider()
{
return armorProvider;
}
public LivingUpgrade withDamageProvider(IDamageProvider damageProvider)
{
this.damageProvider = damageProvider;
return this;
}
public IDamageProvider getDamageProvider()
{
return damageProvider;
}
public String getTranslationKey()
{
return translationKey == null ? translationKey = Util.makeTranslationKey("living_upgrade", key)
: translationKey;
}
public boolean isNegative()
{
return isNegative;
}
public boolean isCompatible(ResourceLocation otherUpgrade)
{
return !incompatible.contains(otherUpgrade);
}
public LivingUpgrade addIncompatibility(ResourceLocation key, ResourceLocation... otherKeys)
{
incompatible.add(key);
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;
}
public LivingUpgrade asDowngrade()
{
this.isNegative = true;
return this;
}
@Override
public String toString()
{
return key.toString();
}
public interface IAttributeProvider
{
void handleAttributes(LivingStats stats, Multimap<Attribute, AttributeModifier> modifiers, UUID uuid, LivingUpgrade upgrade, int level);
}
public interface IArmorProvider
{
double getProtection(PlayerEntity player, LivingStats stats, DamageSource source, LivingUpgrade upgrade, int level);
}
public interface IDamageProvider
{
double getAdditionalDamage(PlayerEntity player, ItemStack weapon, double damage, LivingStats stats, LivingEntity attacked, LivingUpgrade upgrade, int level);
}
public static class Level
{
@SerializedName("xp")
private final int experienceNeeded;
@SerializedName("cost")
private final int upgradeCost;
public Level(int experienceNeeded, int upgradeCost)
{
this.experienceNeeded = experienceNeeded;
this.upgradeCost = upgradeCost;
}
}
public static class Bonus
{
private static final Bonus DEFAULT = new Bonus("null", Collections.emptyList());
private final String id;
private final List<Number> modifiers;
public Bonus(String id, List<Number> modifiers)
{
this.id = id;
this.modifiers = modifiers;
}
public String getId()
{
return id;
}
}
public static class Deserializer implements JsonDeserializer<LivingUpgrade>
{
@Override
public LivingUpgrade deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException
{
JsonObject json = element.getAsJsonObject();
ResourceLocation id = new ResourceLocation(json.getAsJsonPrimitive("id").getAsString());
List<Level> levels = context.deserialize(json.getAsJsonArray("levels"), new TypeToken<List<Level>>()
{
}.getType());
boolean negative = json.has("negative") && json.getAsJsonPrimitive("negative").getAsBoolean();
LivingUpgrade upgrade = new LivingUpgrade(id, upgradeLevels -> upgradeLevels.addAll(levels));
if (negative)
upgrade.asDowngrade();
if (json.has("incompatibilities"))
{
String[] incompatibilities = context.deserialize(json.getAsJsonArray("incompatibilities"), String[].class);
for (String incompatible : incompatibilities)
upgrade.addIncompatibility(new ResourceLocation(incompatible));
}
if (json.has("bonuses"))
{
Map<String, Number[]> bonuses = context.deserialize(json.getAsJsonObject("bonuses"), new TypeToken<Map<String, Number[]>>()
{
}.getType());
bonuses.forEach((k, v) -> upgrade.withBonusSet(k, numbers -> Collections.addAll(numbers, v)));
}
return upgrade;
}
}
}

View file

@ -0,0 +1,176 @@
package wayoftime.bloodmagic.core.living;
import java.util.Map;
import java.util.Map.Entry;
import com.google.common.collect.Multimap;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.attributes.Attribute;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.ItemStack;
import net.minecraft.util.DamageSource;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraftforge.common.MinecraftForge;
import wayoftime.bloodmagic.common.item.ItemLivingTrainer;
import wayoftime.bloodmagic.core.util.PlayerUtil;
import wayoftime.bloodmagic.event.LivingEquipmentEvent;
public class LivingUtil
{
public static LivingStats applyNewExperience(PlayerEntity player, LivingUpgrade upgrade, double experience)
{
LivingStats stats = LivingStats.fromPlayer(player, true);
if (stats == null)
return null;
if (!canTrain(player, upgrade, upgrade.getLevel((int) experience)))
return stats;
LivingEquipmentEvent.GainExperience event = new LivingEquipmentEvent.GainExperience(player, stats, upgrade, experience);
// EventResult result = LivingEquipmentEvent.EXPERIENCE_GAIN.invoker().gainExperience(event);
MinecraftForge.EVENT_BUS.post(event);
if (event.isCanceled())
return stats;
experience = event.getExperience();
double currentExperience = stats.getUpgrades().getOrDefault(upgrade, 0d);
double requiredForLevel = upgrade.getNextRequirement((int) 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((int) 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((int) (currentExperience + experience));
if (upgrade.getLevel((int) currentExperience) != newLevel)
{
LivingEquipmentEvent.LevelUp levelUpEvent = new LivingEquipmentEvent.LevelUp(player, stats, upgrade);
// LivingEquipmentEvent.LEVEL_UP.invoker().levelUp(levelUpEvent);
MinecraftForge.EVENT_BUS.post(levelUpEvent);
player.sendStatusMessage(new TranslationTextComponent("chat.bloodmagic.living_upgrade_level_increase", new TranslationTextComponent(upgrade.getTranslationKey()), newLevel), true);
}
System.out.println("Adding experience!");
stats.addExperience(upgrade.getKey(), experience);
LivingStats.toPlayer(player, stats);
return stats;
}
public static double getDamageReceivedForArmour(PlayerEntity player, DamageSource source, double damage)
{
// System.out.println("Initial damage from " + source + ": " + damage);
LivingStats stats = LivingStats.fromPlayer(player, true);
if (stats == null)
return damage;
Map<LivingUpgrade, Double> upgrades = stats.getUpgrades();
for (Entry<LivingUpgrade, Double> entry : upgrades.entrySet())
{
LivingUpgrade upgrade = entry.getKey();
if (upgrade.getArmorProvider() == null)
{
continue;
}
int level = upgrade.getLevel(entry.getValue().intValue());
damage *= 1 - upgrade.getArmorProvider().getProtection(player, stats, source, upgrade, level);
}
// System.out.println("Final damage: " + damage);
return damage;
}
public static double getAdditionalDamage(PlayerEntity player, ItemStack weapon, LivingEntity attackedEntity, double damage)
{
// System.out.println("Initial damage from " + source + ": " + damage);
LivingStats stats = LivingStats.fromPlayer(player, true);
if (stats == null)
return 0;
double additionalDamage = 0;
Map<LivingUpgrade, Double> upgrades = stats.getUpgrades();
for (Entry<LivingUpgrade, Double> entry : upgrades.entrySet())
{
LivingUpgrade upgrade = entry.getKey();
if (upgrade.getArmorProvider() == null)
{
continue;
}
int level = upgrade.getLevel(entry.getValue().intValue());
if (upgrade.getDamageProvider() == null)
{
continue;
}
additionalDamage += upgrade.getDamageProvider().getAdditionalDamage(player, weapon, damage, stats, attackedEntity, upgrade, level);
}
// System.out.println("Final damage: " + damage);
return additionalDamage;
}
public static boolean canTrain(PlayerEntity player, LivingUpgrade upgrade, int currentLevel)
{
ItemStack trainer = PlayerUtil.findItem(player, stack -> stack.getItem() instanceof ItemLivingTrainer && stack.hasTag() && stack.getTag().contains("livingStats"));
if (trainer.isEmpty())
return true;
String mode = trainer.getTag().getString("livingLock");
LivingStats stats = ((ILivingContainer) trainer.getItem()).getLivingStats(trainer);
int levelLimit = stats.getLevel(upgrade.getKey());
if (mode.equalsIgnoreCase("whitelist"))
{
return levelLimit != 0 && levelLimit > currentLevel;
} else if (mode.equalsIgnoreCase("blacklist"))
{
return levelLimit == 0;
}
return true;
}
public static boolean hasFullSet(PlayerEntity player)
{
for (ItemStack stack : player.inventory.armorInventory)
if (stack.isEmpty() || !(stack.getItem() instanceof ILivingContainer))
return false;
return true;
}
public static void applyAttributes(Multimap<Attribute, AttributeModifier> attributes, ItemStack stack, PlayerEntity player, EquipmentSlotType slot)
{
if (player == null || !hasFullSet(player))
return;
Multimap<Attribute, AttributeModifier> newAttributes = ((ArmorItem) stack.getItem()).getAttributeModifiers(slot, stack);
// newAttributes.values().forEach(e -> e.setSerialize(false));
attributes.putAll(newAttributes);
}
}

View file

@ -0,0 +1,15 @@
package wayoftime.bloodmagic.core.living;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.DamageSource;
public class ProjectileArmorProvider implements LivingUpgrade.IArmorProvider
{
@Override
public double getProtection(PlayerEntity player, LivingStats stats, DamageSource source, LivingUpgrade upgrade, int level)
{
// TODO Auto-generated method stub
return 0;
}
}

View file

@ -0,0 +1,57 @@
package wayoftime.bloodmagic.core.util;
import java.util.function.Predicate;
import com.google.common.collect.Multimap;
import net.minecraft.entity.ai.attributes.Attribute;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.ItemStack;
import wayoftime.bloodmagic.common.item.ExpandedArmor;
import wayoftime.bloodmagic.core.living.LivingUtil;
public class PlayerUtil
{
public static ItemStack findItem(PlayerEntity player, Predicate<ItemStack> requirements)
{
// Check offhand first
ItemStack offHand = player.getHeldItemOffhand();
if (requirements.test(offHand))
return offHand;
// Check inventory next
for (int slot = 0; slot < player.inventory.getSizeInventory(); slot++)
{
ItemStack foundStack = player.inventory.getStackInSlot(slot);
if (!foundStack.isEmpty() && requirements.test(foundStack))
return foundStack;
}
return ItemStack.EMPTY;
}
public static Multimap<Attribute, AttributeModifier> handle(PlayerEntity player, Multimap<Attribute, AttributeModifier> existing)
{
ItemStack chest = player.getItemStackFromSlot(EquipmentSlotType.CHEST);
boolean hasFullSet = LivingUtil.hasFullSet(player);
if (hasFullSet && existing == null)
{
existing = ((ExpandedArmor) chest.getItem()).getAttributeModifiers(EquipmentSlotType.CHEST, chest);
player.getAttributeManager().reapplyModifiers(existing);
}
if (!hasFullSet && existing != null)
{
player.getAttributeManager().removeModifiers(existing);
existing = null;
}
return existing;
}
}

View file

@ -0,0 +1,78 @@
package wayoftime.bloodmagic.core.util;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.FileSystem;
import java.nio.file.FileSystemAlreadyExistsException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.commons.io.IOUtils;
import net.minecraft.util.ResourceLocation;
import wayoftime.bloodmagic.BloodMagic;
public class ResourceUtil
{
public static Set<Path> gatherResources(String home, String following, Predicate<Path> predicate)
{
FileSystem fileSystem = null;
try
{
URL url = ResourceUtil.class.getResource(home);
if (url != null)
{
URI uri = url.toURI();
Path path;
if (uri.getScheme().equals("file"))
{
path = Paths.get(ResourceUtil.class.getResource(home + "/" + following).toURI());
} else
{
if (!uri.getScheme().equals("jar"))
{
BloodMagic.LOGGER.error("Unsupported URI scheme {}", uri.getScheme());
return Collections.emptySet();
}
try
{
fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap());
} catch (FileSystemAlreadyExistsException e)
{
fileSystem = FileSystems.getFileSystem(uri);
}
path = fileSystem.getPath(home + "/" + following);
}
return Files.walk(path).filter(predicate).collect(Collectors.toSet());
}
} catch (IOException | URISyntaxException e)
{
e.printStackTrace();
} finally
{
IOUtils.closeQuietly(fileSystem);
}
return Collections.emptySet();
}
public static Set<Path> gatherResources(String home, String following)
{
return gatherResources(home, following, p -> true);
}
public static ResourceLocation addContext(ResourceLocation rl, String context)
{
return new ResourceLocation(rl.getNamespace(), context + rl.getPath());
}
}

View file

@ -0,0 +1,27 @@
package wayoftime.bloodmagic.core.util;
public final class Value<T>
{
private T value;
private Value(T t)
{
this.value = t;
}
public T get()
{
return value;
}
public Value<T> set(T t)
{
this.value = t;
return this;
}
public static <T> Value<T> of(T t)
{
return new Value<>(t);
}
}