JSON-based living upgrade definitions
Since they're just data, it's okay for them to be data driven. Also makes it easier for outside sources (ie: a wiki) to parse the data to keep it up to date.
This commit is contained in:
parent
2ca458aaea
commit
59142c2a9c
|
@ -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<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 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));
|
||||
});
|
||||
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<Item> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<ResourceLocation> incompatible;
|
||||
private final TreeMap<Integer, Integer> experienceToLevel;
|
||||
private final Map<Integer, Integer> levelToCost;
|
||||
private final boolean isNegative;
|
||||
private final Map<String, Bonus> bonuses;
|
||||
private 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) {
|
||||
public LivingUpgrade(ResourceLocation key, Consumer<List<Level>> experienceMapper) {
|
||||
this.key = key;
|
||||
this.incompatible = Sets.newHashSet();
|
||||
this.experienceToLevel = Maps.newTreeMap();
|
||||
this.levelToCost = Maps.newHashMap();
|
||||
this.isNegative = isNegative;
|
||||
this.bonuses = Maps.newHashMap();
|
||||
|
||||
List<UpgradeLevel> levels = Lists.newArrayList();
|
||||
List<Level> 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<List<UpgradeLevel>> experienceMapper /* xp needed -> level */) {
|
||||
this(key, experienceMapper, false);
|
||||
public LivingUpgrade withBonusSet(String id, Consumer<List<Number>> modifiers) {
|
||||
List<Number> 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<Number> modifiers;
|
||||
|
||||
public Bonus(String id, List<Number> modifiers) {
|
||||
this.id = id;
|
||||
this.modifiers = modifiers;
|
||||
}
|
||||
}
|
||||
|
||||
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<LivingUpgrade.Level> levels = context.deserialize(json.getAsJsonArray("levels"), new TypeToken<List<Level>>(){}.getType());
|
||||
|
||||
LivingUpgrade upgrade = new LivingUpgrade(id, upgradeLevels -> upgradeLevels.addAll(levels));
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<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")) {
|
||||
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<Path> 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<IResourcePack> defaultResourcePacks = (List<IResourcePack>) _defaultResourcePacks.get(Minecraft.getMinecraft());
|
||||
defaultResourcePacks.add(resourcePack);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
29
src/main/resources/data/living_armor/arrow_protect.json
Normal file
29
src/main/resources/data/living_armor/arrow_protect.json
Normal file
|
@ -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
|
||||
]
|
||||
}
|
||||
}
|
10
src/main/resources/data/living_armor/arrow_shot.json
Normal file
10
src/main/resources/data/living_armor/arrow_shot.json
Normal file
|
@ -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 }
|
||||
]
|
||||
}
|
19
src/main/resources/data/living_armor/critical_strike.json
Normal file
19
src/main/resources/data/living_armor/critical_strike.json
Normal file
|
@ -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
|
||||
]
|
||||
}
|
||||
}
|
9
src/main/resources/data/living_armor/jump.json
Normal file
9
src/main/resources/data/living_armor/jump.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"id": "bloodmagic:jump",
|
||||
"levels": [
|
||||
{ "xp": 10, "cost": 1 },
|
||||
{ "xp": 20, "cost": 5 },
|
||||
{ "xp": 30, "cost": 25 },
|
||||
{ "xp": 40, "cost": 125 }
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue