diff --git a/src/main/java/com/wayoftime/bloodmagic/core/RegistrarBloodMagicLivingArmor.java b/src/main/java/com/wayoftime/bloodmagic/core/RegistrarBloodMagicLivingArmor.java index 7959ef67..0f0d9bae 100644 --- a/src/main/java/com/wayoftime/bloodmagic/core/RegistrarBloodMagicLivingArmor.java +++ b/src/main/java/com/wayoftime/bloodmagic/core/RegistrarBloodMagicLivingArmor.java @@ -1,22 +1,31 @@ package com.wayoftime.bloodmagic.core; import com.google.common.collect.Maps; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.wayoftime.bloodmagic.BloodMagic; import com.wayoftime.bloodmagic.core.living.LivingUpgrade; +import com.wayoftime.bloodmagic.core.util.ResourceUtil; 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 org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import javax.annotation.Nonnull; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; import java.util.Map; +import java.util.stream.Collectors; /* * TODO - See checklist * - [-] Upgrades (Names pulled from 2.0 class names) - * - [ ] Arrow Protect - * - [ ] Arrow Shot - * - [ ] Critical Strike + * - [-] 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. @@ -63,20 +72,37 @@ import java.util.Map; @Mod.EventBusSubscriber(modid = BloodMagic.MODID) public class RegistrarBloodMagicLivingArmor { + private static final Map 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 Map 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)); - }); + public static final LivingUpgrade UPGRADE_ARROW_PROTECT = parseDefinition("arrow_protect"); + public static final LivingUpgrade UPGRADE_ARROW_SHOT = parseDefinition("arrow_shot"); + public static final LivingUpgrade UPGRADE_CRITICAL_STRIKE = parseDefinition("critical_strike"); + public static final LivingUpgrade UPGRADE_JUMP = parseDefinition("jump"); @SubscribeEvent public static void registerUpgrades(RegistryEvent.Register event) { - addUpgrade(JUMP); + addUpgrade(UPGRADE_ARROW_PROTECT); + addUpgrade(UPGRADE_ARROW_SHOT); + addUpgrade(UPGRADE_CRITICAL_STRIKE); + addUpgrade(UPGRADE_JUMP); } private static void addUpgrade(LivingUpgrade upgrade) { UPGRADES.put(upgrade.getKey(), upgrade); } + + @Nonnull + public static LivingUpgrade parseDefinition(String fileName) { + 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; + } + } } diff --git a/src/main/java/com/wayoftime/bloodmagic/core/living/LivingStatusWatcher.java b/src/main/java/com/wayoftime/bloodmagic/core/living/LivingStatusWatcher.java index bf564d03..ea70b694 100644 --- a/src/main/java/com/wayoftime/bloodmagic/core/living/LivingStatusWatcher.java +++ b/src/main/java/com/wayoftime/bloodmagic/core/living/LivingStatusWatcher.java @@ -17,11 +17,11 @@ public class LivingStatusWatcher { return; EntityPlayer player = (EntityPlayer) event.getEntity(); - LivingStats stats = LivingUtil.applyNewExperience(player, RegistrarBloodMagicLivingArmor.JUMP, 1); + LivingStats stats = LivingUtil.applyNewExperience(player, RegistrarBloodMagicLivingArmor.UPGRADE_JUMP, 1); if (stats == null) return; - int level = stats.getLevel(RegistrarBloodMagicLivingArmor.JUMP.getKey()); + int level = stats.getLevel(RegistrarBloodMagicLivingArmor.UPGRADE_JUMP.getKey()); player.motionY += 0.05 * level; if (level >= 3) { diff --git a/src/main/java/com/wayoftime/bloodmagic/core/living/LivingUpgrade.java b/src/main/java/com/wayoftime/bloodmagic/core/living/LivingUpgrade.java index f308109e..75b6dc5f 100644 --- a/src/main/java/com/wayoftime/bloodmagic/core/living/LivingUpgrade.java +++ b/src/main/java/com/wayoftime/bloodmagic/core/living/LivingUpgrade.java @@ -4,45 +4,67 @@ 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.gson.*; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.DamageSource; +import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; +import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.lang.reflect.Type; import java.util.*; import java.util.function.Consumer; +@JsonAdapter(LivingUpgrade.Deserializer.class) public class 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 incompatible; private final TreeMap experienceToLevel; private final Map levelToCost; - private final boolean isNegative; + private final Map bonuses; + private boolean isNegative; private String unlocalizedName = null; private IAttributeProvider attributeProvider; private IArmorProvider armorProvider; - public LivingUpgrade(ResourceLocation key, Consumer> experienceMapper /* xp needed -> level */, boolean isNegative) { + public LivingUpgrade(ResourceLocation key, Consumer> experienceMapper) { this.key = key; this.incompatible = Sets.newHashSet(); this.experienceToLevel = Maps.newTreeMap(); this.levelToCost = Maps.newHashMap(); - this.isNegative = isNegative; + this.bonuses = Maps.newHashMap(); - List levels = Lists.newArrayList(); + List levels = Lists.newArrayList(); experienceMapper.accept(levels); for (int i = 0; i < levels.size(); i++) { - UpgradeLevel level = levels.get(i); + Level level = levels.get(i); experienceToLevel.put(level.experienceNeeded, i + 1); levelToCost.put(i + 1, level.upgradeCost); } } - public LivingUpgrade(ResourceLocation key, Consumer> experienceMapper /* xp needed -> level */) { - this(key, experienceMapper, false); + public LivingUpgrade withBonusSet(String id, Consumer> modifiers) { + List values = NonNullList.create(); + 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; + } + + @Nonnull + public Number getBonusValue(String id, int level) { + return bonuses.getOrDefault(id, Bonus.DEFAULT).modifiers.get(level); } public LivingUpgrade withAttributeProvider(IAttributeProvider attributeProvider) { @@ -100,6 +122,11 @@ public class LivingUpgrade { return key; } + public LivingUpgrade asDowngrade() { + this.isNegative = true; + return this; + } + @Override public String toString() { return key.toString(); @@ -113,13 +140,45 @@ public class LivingUpgrade { double getProtection(EntityPlayer player, DamageSource source, int level); } - public static class UpgradeLevel { + public static class Level { + @SerializedName("xp") private final int experienceNeeded; + @SerializedName("cost") private final int upgradeCost; - public UpgradeLevel(int experienceNeeded, 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 modifiers; + + public Bonus(String id, List modifiers) { + this.id = id; + this.modifiers = modifiers; + } + } + + public static class Deserializer implements JsonDeserializer { + @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 levels = context.deserialize(json.getAsJsonArray("levels"), new TypeToken>(){}.getType()); + + LivingUpgrade upgrade = new LivingUpgrade(id, upgradeLevels -> upgradeLevels.addAll(levels)); + if (json.has("bonuses")) { + Map bonuses = context.deserialize(json.getAsJsonObject("bonuses"), new TypeToken>(){}.getType()); + bonuses.forEach((k, v) -> upgrade.withBonusSet(k, numbers -> Collections.addAll(numbers, v))); + } + + return upgrade; + } + } } diff --git a/src/main/java/com/wayoftime/bloodmagic/core/util/ResourceUtil.java b/src/main/java/com/wayoftime/bloodmagic/core/util/ResourceUtil.java new file mode 100644 index 00000000..39254fd2 --- /dev/null +++ b/src/main/java/com/wayoftime/bloodmagic/core/util/ResourceUtil.java @@ -0,0 +1,85 @@ +package com.wayoftime.bloodmagic.core.util; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.FolderResourcePack; +import net.minecraft.client.resources.IResourcePack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.ReflectionHelper; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.apache.commons.io.IOUtils; + +import javax.annotation.Nonnull; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.*; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +public class ResourceUtil { + + @Nonnull + public static Set gatherResources(String home, String following, Predicate 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")) { + BMLog.DEFAULT.error("Unsupported URI scheme {}", uri.getScheme()); + return Collections.emptySet(); + } + + fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap()); + 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(); + } + + @Nonnull + public static Set gatherResources(String home, String following) { + return gatherResources(home, following, p -> true); + } + + @Nonnull + public static ResourceLocation addContext(ResourceLocation rl, String context) { + return new ResourceLocation(rl.getNamespace(), context + rl.getPath()); + } + + @SideOnly(Side.CLIENT) + public static void injectDirectoryAsResource(File resourceDir) { + if (!resourceDir.exists() || !resourceDir.isDirectory()) + return; + + FolderResourcePack resourcePack = new FolderResourcePack(resourceDir); + Field _defaultResourcePacks = ReflectionHelper.findField(Minecraft.class, "field_110449_ao", "defaultResourcePacks"); + try { + _defaultResourcePacks.setAccessible(true); + // noinspection unchecked + List defaultResourcePacks = (List) _defaultResourcePacks.get(Minecraft.getMinecraft()); + defaultResourcePacks.add(resourcePack); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/resources/data/living_armor/arrow_protect.json b/src/main/resources/data/living_armor/arrow_protect.json new file mode 100644 index 00000000..ae1ea715 --- /dev/null +++ b/src/main/resources/data/living_armor/arrow_protect.json @@ -0,0 +1,29 @@ +{ + "id": "bloodmagic:arrow_protect", + "levels": [ + { "xp": 30, "cost": 4 }, + { "xp": 200, "cost": 9 }, + { "xp": 400, "cost": 16 }, + { "xp": 800, "cost": 30 }, + { "xp": 1500, "cost": 60 }, + { "xp": 2500, "cost": 90 }, + { "xp": 3500, "cost": 125 }, + { "xp": 5000, "cost": 165 }, + { "xp": 7000, "cost": 210 }, + { "xp": 15000, "cost": 250 } + ], + "bonuses": { + "protection": [ + 0.1, + 0.3, + 0.4, + 0.6, + 0.7, + 0.75, + 0.77, + 0.8, + 0.83, + 0.85 + ] + } +} \ No newline at end of file diff --git a/src/main/resources/data/living_armor/arrow_shot.json b/src/main/resources/data/living_armor/arrow_shot.json new file mode 100644 index 00000000..009585b7 --- /dev/null +++ b/src/main/resources/data/living_armor/arrow_shot.json @@ -0,0 +1,10 @@ +{ + "id": "bloodmagic:arrow_shot", + "levels": [ + { "xp": 50, "cost": 20 }, + { "xp": 200, "cost": 50 }, + { "xp": 700, "cost": 90 }, + { "xp": 1500, "cost": 160 }, + { "xp": 3000, "cost": 290 } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/living_armor/critical_strike.json b/src/main/resources/data/living_armor/critical_strike.json new file mode 100644 index 00000000..6089c9be --- /dev/null +++ b/src/main/resources/data/living_armor/critical_strike.json @@ -0,0 +1,19 @@ +{ + "id": "bloodmagic:critical_strike", + "levels": [ + { "xp": 200, "cost": 5 }, + { "xp": 800, "cost": 12 }, + { "xp": 1300, "cost": 22 }, + { "xp": 2500, "cost": 35 }, + { "xp": 3000, "cost": 49 } + ], + "bonuses": { + "damage_boost": [ + 0.1, + 0.2, + 0.3, + 0.4, + 0.5 + ] + } +} \ No newline at end of file diff --git a/src/main/resources/data/living_armor/jump.json b/src/main/resources/data/living_armor/jump.json new file mode 100644 index 00000000..be8a516b --- /dev/null +++ b/src/main/resources/data/living_armor/jump.json @@ -0,0 +1,9 @@ +{ + "id": "bloodmagic:jump", + "levels": [ + { "xp": 10, "cost": 1 }, + { "xp": 20, "cost": 5 }, + { "xp": 30, "cost": 25 }, + { "xp": 40, "cost": 125 } + ] +} \ No newline at end of file