diff --git a/build.gradle b/build.gradle index 5bf17e3..2f6b2da 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ dependencies { mappings loom.officialMojangMappings() modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" - modImplementation include("net.atlas:atlas-lib:1.0.1") + modImplementation include("net.atlas:atlas-lib:1.0.2") modApi "com.terraformersmc:modmenu:10.0.0-alpha.1" modApi "me.shedaniel.cloth:cloth-config-fabric:14.0.125" diff --git a/libs/atlas-lib.jar b/libs/atlas-lib.jar index b0ea19b..2050530 100644 Binary files a/libs/atlas-lib.jar and b/libs/atlas-lib.jar differ diff --git a/src/main/java/net/atlas/combatify/Combatify.java b/src/main/java/net/atlas/combatify/Combatify.java index 44b4da1..87d4200 100644 --- a/src/main/java/net/atlas/combatify/Combatify.java +++ b/src/main/java/net/atlas/combatify/Combatify.java @@ -7,6 +7,7 @@ import net.atlas.combatify.config.CombatifyBetaConfig; import net.atlas.combatify.config.ItemConfig; import net.atlas.combatify.enchantment.DefendingEnchantment; +import net.atlas.combatify.extensions.ExtendedTier; import net.atlas.combatify.item.CombatifyItemTags; import net.atlas.combatify.item.ItemRegistry; import net.atlas.combatify.item.TieredShieldItem; @@ -20,11 +21,16 @@ import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.item.*; +import net.minecraft.world.item.CreativeModeTabs; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.Tier; import net.minecraft.world.level.block.DispenserBlock; import org.apache.logging.log4j.LogManager; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; import static net.minecraft.world.item.Items.NETHERITE_SWORD; @@ -38,20 +44,22 @@ public class Combatify implements ModInitializer { public static final List unmoddedPlayers = new ArrayListExtensions<>(); public static final List moddedPlayers = new ArrayListExtensions<>(); public static final Map isPlayerAttacking = new HashMap<>(); + public static final Map defaultWeaponTypes = new HashMap<>(); + public static final Map defaultTypes = new HashMap<>(); + public static final BiMap defaultTiers = HashBiMap.create(); public static Map registeredWeaponTypes = new HashMap<>(); public static Map registeredTypes = new HashMap<>(); public static BiMap tiers = HashBiMap.create(); public static final PrefixLogger LOGGER = new PrefixLogger(LogManager.getLogger("Combatify")); - public static final BlockingType SWORD = registerBlockingType(new SwordBlockingType("sword").setToolBlocker(true).setDisablement(false).setCrouchable(false).setBlockHit(true).setRequireFullCharge(false).setSwordBlocking(true).setDelay(false)); - public static final BlockingType SHIELD = registerBlockingType(new ShieldBlockingType("shield")); - public static final BlockingType CURRENT_SHIELD = registerBlockingType(new CurrentShieldBlockingType("current_shield")); - public static final BlockingType NEW_SHIELD = registerBlockingType(new NewShieldBlockingType("new_shield").setKbMechanics(false)); + public static final BlockingType SWORD = defineDefaultBlockingType(new SwordBlockingType("sword").setToolBlocker(true).setDisablement(false).setCrouchable(false).setBlockHit(true).setRequireFullCharge(false).setSwordBlocking(true).setDelay(false)); + public static final BlockingType SHIELD = defineDefaultBlockingType(new ShieldBlockingType("shield")); + public static final BlockingType CURRENT_SHIELD = defineDefaultBlockingType(new CurrentShieldBlockingType("current_shield")); + public static final BlockingType NEW_SHIELD = defineDefaultBlockingType(new NewShieldBlockingType("new_shield").setKbMechanics(false)); public static final BlockingType EMPTY = new EmptyBlockingType("empty").setDisablement(false).setCrouchable(false).setRequireFullCharge(false).setKbMechanics(false); @Override public void onInitialize() { - if (registeredWeaponTypes.isEmpty()) - WeaponType.init(); + WeaponType.init(); networkingHandler = new NetworkingHandler(); LOGGER.info("Init started."); CombatifyItemTags.init(); @@ -84,4 +92,15 @@ public static T registerBlockingType(T blockingType) { public static ResourceLocation id(String path) { return new ResourceLocation(MOD_ID, path); } + public static void defineDefaultWeaponType(WeaponType type) { + defaultWeaponTypes.put(type.name, type); + } + public static T defineDefaultBlockingType(T blockingType) { + defaultTypes.put(blockingType.getName(), blockingType); + return registerBlockingType(blockingType); + } + public static void defineDefaultTier(String name, ExtendedTier tier) { + defaultTiers.put(name, tier); + tiers.put(name, tier); + } } diff --git a/src/main/java/net/atlas/combatify/config/ConfigurableItemData.java b/src/main/java/net/atlas/combatify/config/ConfigurableItemData.java index 5b3e165..e329328 100644 --- a/src/main/java/net/atlas/combatify/config/ConfigurableItemData.java +++ b/src/main/java/net/atlas/combatify/config/ConfigurableItemData.java @@ -1,11 +1,121 @@ package net.atlas.combatify.config; +import net.atlas.combatify.Combatify; import net.atlas.combatify.item.WeaponType; import net.atlas.combatify.util.BlockingType; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.world.item.Tier; import net.minecraft.world.item.crafting.Ingredient; +import static net.atlas.combatify.Combatify.registeredWeaponTypes; +import static net.atlas.combatify.config.ItemConfig.getTier; +import static net.atlas.combatify.config.ItemConfig.getTierName; + public class ConfigurableItemData { + public static final StreamCodec ITEM_DATA_STREAM_CODEC = StreamCodec.of((buf, configurableItemData) -> { + buf.writeDouble(configurableItemData.damage == null ? -10 : configurableItemData.damage); + buf.writeDouble(configurableItemData.speed == null ? -10 : configurableItemData.speed); + buf.writeDouble(configurableItemData.reach == null ? -10 : configurableItemData.reach); + buf.writeDouble(configurableItemData.chargedReach == null ? -10 : configurableItemData.chargedReach); + buf.writeVarInt(configurableItemData.stackSize == null ? -10 : configurableItemData.stackSize); + buf.writeVarInt(configurableItemData.durability == null ? -10 : configurableItemData.durability); + buf.writeInt(configurableItemData.cooldown == null ? -10 : configurableItemData.cooldown); + if(configurableItemData.cooldown != null) + buf.writeBoolean(configurableItemData.cooldownAfter); + buf.writeUtf(configurableItemData.type == null ? "empty" : configurableItemData.type.name); + buf.writeUtf(configurableItemData.blockingType == null ? "blank" : configurableItemData.blockingType.getName()); + buf.writeDouble(configurableItemData.blockStrength == null ? -10 : configurableItemData.blockStrength); + buf.writeDouble(configurableItemData.blockKbRes == null ? -10 : configurableItemData.blockKbRes); + buf.writeInt(configurableItemData.enchantability == null ? -10 : configurableItemData.enchantability); + buf.writeInt(configurableItemData.isEnchantable == null ? -10 : configurableItemData.isEnchantable ? 1 : 0); + buf.writeInt(configurableItemData.hasSwordEnchants == null ? -10 : configurableItemData.hasSwordEnchants ? 1 : 0); + buf.writeInt(configurableItemData.isPrimaryForSwordEnchants == null ? -10 : configurableItemData.isPrimaryForSwordEnchants ? 1 : 0); + buf.writeInt(configurableItemData.useDuration == null ? -10 : configurableItemData.useDuration); + buf.writeDouble(configurableItemData.piercingLevel == null ? -10 : configurableItemData.piercingLevel); + buf.writeInt(configurableItemData.canSweep == null ? -10 : configurableItemData.canSweep ? 1 : 0); + buf.writeUtf(configurableItemData.tier == null ? "empty" : getTierName(configurableItemData.tier)); + buf.writeInt(configurableItemData.defense == null ? -10 : configurableItemData.defense); + buf.writeDouble(configurableItemData.toughness == null ? -10 : configurableItemData.toughness); + buf.writeDouble(configurableItemData.armourKbRes == null ? -10 : configurableItemData.armourKbRes); + buf.writeBoolean(configurableItemData.repairIngredient == null); + if (configurableItemData.repairIngredient != null) + Ingredient.CONTENTS_STREAM_CODEC.encode(buf, configurableItemData.repairIngredient); + }, buf -> { + Double damage = buf.readDouble(); + Double speed = buf.readDouble(); + Double reach = buf.readDouble(); + Double chargedReach = buf.readDouble(); + Integer stackSize = buf.readVarInt(); + Integer durability = buf.readVarInt(); + Integer cooldown = buf.readInt(); + Boolean cooldownAfter = null; + if (cooldown != -10) + cooldownAfter = buf.readBoolean(); + String weaponType = buf.readUtf(); + WeaponType type = null; + String blockingType = buf.readUtf(); + BlockingType bType = Combatify.registeredTypes.get(blockingType); + Double blockStrength = buf.readDouble(); + Double blockKbRes = buf.readDouble(); + Integer enchantlevel = buf.readInt(); + int isEnchantableAsInt = buf.readInt(); + int hasSwordEnchantsAsInt = buf.readInt(); + int isPrimaryForSwordEnchantsAsInt = buf.readInt(); + Boolean isEnchantable = null; + Boolean hasSwordEnchants = null; + Boolean isPrimaryForSwordEnchants = null; + Integer useDuration = buf.readInt(); + Double piercingLevel = buf.readDouble(); + int canSweepAsInt = buf.readInt(); + Boolean canSweep = null; + Tier tier = getTier(buf.readUtf()); + Integer defense = buf.readInt(); + Double toughness = buf.readDouble(); + Double armourKbRes = buf.readDouble(); + Ingredient ingredient = buf.readBoolean() ? null : Ingredient.CONTENTS_STREAM_CODEC.decode(buf); + if (damage == -10) + damage = null; + if (speed == -10) + speed = null; + if (reach == -10) + reach = null; + if (chargedReach == -10) + chargedReach = null; + if (stackSize == -10) + stackSize = null; + if (durability == -10) + durability = null; + if (cooldown == -10) + cooldown = null; + if (blockStrength == -10) + blockStrength = null; + if (blockKbRes == -10) + blockKbRes = null; + if (enchantlevel == -10) + enchantlevel = null; + if (isEnchantableAsInt != -10) + isEnchantable = isEnchantableAsInt == 1; + if (hasSwordEnchantsAsInt != -10) + hasSwordEnchants = hasSwordEnchantsAsInt == 1; + if (isPrimaryForSwordEnchantsAsInt != -10) + isPrimaryForSwordEnchants = isPrimaryForSwordEnchantsAsInt == 1; + if (useDuration == -10) + useDuration = null; + if (piercingLevel == -10) + piercingLevel = null; + if (canSweepAsInt != -10) + canSweep = canSweepAsInt == 1; + if (registeredWeaponTypes.containsKey(weaponType)) + type = WeaponType.fromID(weaponType); + if (defense == -10) + defense = null; + if (toughness == -10) + toughness = null; + if (armourKbRes == -10) + armourKbRes = null; + return new ConfigurableItemData(damage, speed, reach, chargedReach, stackSize, cooldown, cooldownAfter, type, bType, blockStrength, blockKbRes, enchantlevel, isEnchantable, hasSwordEnchants, isPrimaryForSwordEnchants, useDuration, piercingLevel, canSweep, tier, durability, defense, toughness, armourKbRes, ingredient); + }); public final Double damage; public final Double speed; public final Double reach; diff --git a/src/main/java/net/atlas/combatify/config/ConfigurableWeaponData.java b/src/main/java/net/atlas/combatify/config/ConfigurableWeaponData.java index 2548e78..0d9d0a6 100644 --- a/src/main/java/net/atlas/combatify/config/ConfigurableWeaponData.java +++ b/src/main/java/net/atlas/combatify/config/ConfigurableWeaponData.java @@ -1,8 +1,55 @@ package net.atlas.combatify.config; +import net.atlas.combatify.Combatify; import net.atlas.combatify.util.BlockingType; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; public class ConfigurableWeaponData { + public static final StreamCodec WEAPON_DATA_STREAM_CODEC = StreamCodec.of((buf, configurableWeaponData) -> { + buf.writeDouble(configurableWeaponData.damageOffset == null ? -10 : configurableWeaponData.damageOffset); + buf.writeDouble(configurableWeaponData.speed == null ? -10 : configurableWeaponData.speed); + buf.writeDouble(configurableWeaponData.reach == null ? -10 : configurableWeaponData.reach); + buf.writeDouble(configurableWeaponData.chargedReach == null ? -10 : configurableWeaponData.chargedReach); + buf.writeBoolean(configurableWeaponData.tierable); + buf.writeUtf(configurableWeaponData.blockingType == null ? "blank" : configurableWeaponData.blockingType.getName()); + buf.writeInt(configurableWeaponData.hasSwordEnchants == null ? -10 : configurableWeaponData.hasSwordEnchants ? 1 : 0); + buf.writeInt(configurableWeaponData.isPrimaryForSwordEnchants == null ? -10 : configurableWeaponData.isPrimaryForSwordEnchants ? 1 : 0); + buf.writeDouble(configurableWeaponData.piercingLevel == null ? -10 : configurableWeaponData.piercingLevel); + buf.writeInt(configurableWeaponData.canSweep == null ? -10 : configurableWeaponData.canSweep ? 1 : 0); + }, buf -> { + Double damageOffset = buf.readDouble(); + Double speed = buf.readDouble(); + Double reach = buf.readDouble(); + Double chargedReach = buf.readDouble(); + Boolean tierable = buf.readBoolean(); + String blockingType = buf.readUtf(); + BlockingType bType = Combatify.registeredTypes.get(blockingType); + int hasSwordEnchantsAsInt = buf.readInt(); + Boolean hasSwordEnchants = null; + int isPrimaryForSwordEnchantsAsInt = buf.readInt(); + Boolean isPrimaryForSwordEnchants = null; + Double piercingLevel = buf.readDouble(); + int canSweepAsInt = buf.readInt(); + Boolean canSweep = null; + if (damageOffset == -10) + damageOffset = null; + if (speed == -10) + speed = null; + if (reach == -10) + reach = null; + if (chargedReach == -10) + chargedReach = null; + if (hasSwordEnchantsAsInt != -10) + hasSwordEnchants = hasSwordEnchantsAsInt == 1; + if (isPrimaryForSwordEnchantsAsInt != -10) + isPrimaryForSwordEnchants = isPrimaryForSwordEnchantsAsInt == 1; + if (piercingLevel == -10) + piercingLevel = null; + if (canSweepAsInt != -10) + canSweep = canSweepAsInt == 1; + return new ConfigurableWeaponData(damageOffset, speed, reach, chargedReach, tierable, bType, hasSwordEnchants, isPrimaryForSwordEnchants, piercingLevel, canSweep); + }); public final Double damageOffset; public final Double speed; public final Double reach; diff --git a/src/main/java/net/atlas/combatify/config/ItemConfig.java b/src/main/java/net/atlas/combatify/config/ItemConfig.java index 6c87356..d8196d2 100644 --- a/src/main/java/net/atlas/combatify/config/ItemConfig.java +++ b/src/main/java/net/atlas/combatify/config/ItemConfig.java @@ -1,6 +1,7 @@ package net.atlas.combatify.config; import com.google.common.collect.HashBiMap; +import com.google.common.collect.Maps; import com.google.gson.*; import com.google.gson.stream.JsonWriter; import me.shedaniel.clothconfig2.api.ConfigBuilder; @@ -20,31 +21,119 @@ import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.chat.Component; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; import net.minecraft.util.GsonHelper; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.item.*; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.enchantment.EnchantmentHelper; -import org.jetbrains.annotations.NotNull; +import net.minecraft.world.level.block.Block; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; +import java.util.*; +import java.util.function.IntFunction; import static net.atlas.combatify.Combatify.*; +import static net.atlas.combatify.config.ConfigurableItemData.ITEM_DATA_STREAM_CODEC; +import static net.atlas.combatify.config.ConfigurableWeaponData.WEAPON_DATA_STREAM_CODEC; public class ItemConfig extends AtlasConfig { public Map configuredItems; public Map configuredWeapons; + public static final StreamCodec NAME_STREAM_CODEC = StreamCodec.of(RegistryFriendlyByteBuf::writeUtf, RegistryFriendlyByteBuf::readUtf); + public static final StreamCodec TIERS_STREAM_CODEC = StreamCodec.of((buf, tier) -> { + buf.writeVarInt(ExtendedTier.getLevel(tier)); + buf.writeVarInt(tier.getEnchantmentValue()); + buf.writeVarInt(tier.getUses()); + buf.writeFloat(tier.getAttackDamageBonus()); + buf.writeFloat(tier.getSpeed()); + Ingredient.CONTENTS_STREAM_CODEC.encode(buf, tier.getRepairIngredient()); + buf.writeResourceLocation(tier.getIncorrectBlocksForDrops().location()); + buf.writeUtf(tier instanceof ExtendedTier extendedTier ? extendedTier.baseTierName() : getTierName(tier)); + }, (buf) -> { + int level = buf.readVarInt(); + int enchantLevel = buf.readVarInt(); + int uses = buf.readVarInt(); + float damage = buf.readFloat(); + float speed = buf.readFloat(); + Ingredient repairIngredient = Ingredient.CONTENTS_STREAM_CODEC.decode(buf); + TagKey incorrect = TagKey.create(Registries.BLOCK, buf.readResourceLocation()); + String baseTier = buf.readUtf(); + return ExtendedTier.create(level, enchantLevel, uses, damage, speed, repairIngredient, incorrect, baseTier); + }); + public static final StreamCodec REGISTERED_WEAPON_TYPE_STREAM_CODEC = StreamCodec.of((buf, weaponType) -> { + buf.writeUtf(weaponType.name); + buf.writeDouble(weaponType.damageOffset); + buf.writeDouble(weaponType.speed); + buf.writeDouble(weaponType.reach); + buf.writeBoolean(weaponType.useAxeDamage); + buf.writeBoolean(weaponType.useHoeDamage); + buf.writeBoolean(weaponType.useHoeSpeed); + buf.writeBoolean(weaponType.hasSwordEnchants); + buf.writeBoolean(weaponType.tierable); + }, buf -> { + String name = buf.readUtf(); + double damageOffset = buf.readDouble(); + double speed = buf.readDouble(); + double reach = buf.readDouble(); + boolean useAxeDamage = buf.readBoolean(); + boolean useHoeDamage = buf.readBoolean(); + boolean useHoeSpeed = buf.readBoolean(); + boolean hasSwordEnchants = buf.readBoolean(); + boolean tierable = buf.readBoolean(); + return new WeaponType(name, damageOffset, speed, reach, useAxeDamage, useHoeDamage, useHoeSpeed, tierable, hasSwordEnchants, true); + }); + public static final StreamCodec BLOCKING_TYPE_STREAM_CODEC = StreamCodec.of((buf, blockingType) -> { + buf.writeUtf(blockingType.getClass().getName()); + buf.writeUtf(blockingType.getName()); + buf.writeBoolean(blockingType.canBeDisabled()); + buf.writeBoolean(blockingType.canBlockHit()); + buf.writeBoolean(blockingType.canCrouchBlock()); + buf.writeBoolean(blockingType.defaultKbMechanics()); + buf.writeBoolean(blockingType.isToolBlocker()); + buf.writeBoolean(blockingType.requireFullCharge()); + buf.writeBoolean(blockingType.requiresSwordBlocking()); + buf.writeBoolean(blockingType.hasDelay()); + }, buf -> { + try { + Class clazz = BlockingType.class.getClassLoader().loadClass(buf.readUtf()); + Constructor constructor = clazz.getConstructor(String.class); + String name = buf.readUtf(); + Object object = constructor.newInstance(name); + if (object instanceof BlockingType blockingType) { + blockingType.setDisablement(buf.readBoolean()); + blockingType.setBlockHit(buf.readBoolean()); + blockingType.setCrouchable(buf.readBoolean()); + blockingType.setKbMechanics(buf.readBoolean()); + blockingType.setToolBlocker(buf.readBoolean()); + blockingType.setRequireFullCharge(buf.readBoolean()); + blockingType.setSwordBlocking(buf.readBoolean()); + blockingType.setDelay(buf.readBoolean()); + Combatify.registerBlockingType(blockingType); + return blockingType; + } else { + CrashReport report = CrashReport.forThrowable(new IllegalStateException("The specified class is not an instance of BlockingType!"), "Syncing Blocking Types"); + CrashReportCategory crashReportCategory = report.addCategory("Blocking Type being synced"); + crashReportCategory.setDetail("Class", clazz.getName()); + crashReportCategory.setDetail("Type Name", name); + throw new ReportedException(report); + } + } catch (InvocationTargetException | InstantiationException | IllegalAccessException | + ClassNotFoundException | NoSuchMethodException e) { + throw new ReportedException(CrashReport.forThrowable(new RuntimeException(e), "Syncing Blocking Types")); + } + }); + public static final StreamCodec ITEM_STREAM_CODEC = StreamCodec.of((buf, item) -> buf.writeResourceLocation(BuiltInRegistries.ITEM.getKey(item)), buf -> BuiltInRegistries.ITEM.get(buf.readResourceLocation())); public static Formula armourCalcs = null; public ItemConfig() { @@ -74,7 +163,7 @@ protected void loadExtra(JsonObject object) { if (jsonElement instanceof JsonObject jsonObject) { parseTiers(jsonObject); } else - throw new ReportedException(CrashReport.forThrowable(new IllegalStateException("Not a JSON Object: " + jsonElement + " this may be due to an incorrectly written config file."), "Configuring Tiers")); + notJSONObject(jsonElement, "Configuring Tiers"); }); } if (defenders instanceof JsonArray typeArray) { @@ -82,64 +171,25 @@ protected void loadExtra(JsonObject object) { if (jsonElement instanceof JsonObject jsonObject) { parseBlockingType(jsonObject); } else - throw new ReportedException(CrashReport.forThrowable(new IllegalStateException("Not a JSON Object: " + jsonElement + " this may be due to an incorrectly written config file."), "Configuring Blocking Types")); + notJSONObject(jsonElement, "Configuring Blocking Types"); }); } if (weapons instanceof JsonArray typeArray) { typeArray.asList().forEach(jsonElement -> { if (jsonElement instanceof JsonObject jsonObject) { - WeaponType type = typeFromJson(jsonObject); - Double damageOffset = null; - Double speed = null; - Double reach = null; - Double chargedReach = null; - BlockingType blockingType = null; - Boolean tierable; - Boolean hasSwordEnchants = null; - Boolean isPrimaryForSwordEnchants = null; - Double piercingLevel = null; - Boolean canSweep = null; - if (jsonObject.has("tierable")) - tierable = getBoolean(jsonObject, "tierable"); - else - throw new ReportedException(CrashReport.forThrowable(new JsonSyntaxException("The JSON must contain the boolean `tierable` if a weapon type is defined!"), "Configuring Weapon Types")); - if (jsonObject.has("damage_offset")) - damageOffset = getDouble(jsonObject, "damage_offset"); - if (jsonObject.has("speed")) - speed = getDouble(jsonObject, "speed"); - if (jsonObject.has("reach")) - reach = getDouble(jsonObject, "reach"); - if (type == null) { - if (damageOffset == null || speed == null || reach == null) - throw new ReportedException(CrashReport.forThrowable(new JsonSyntaxException("The JSON must contain the weapon type's attributes if a new weapon type is added!"), "Configuring Weapon Types")); - type = tierable ? WeaponType.createBasic(GsonHelper.getAsString(jsonObject, "name").toLowerCase(Locale.ROOT), damageOffset, speed, reach) : WeaponType.createBasicUntierable(GsonHelper.getAsString(jsonObject, "name").toLowerCase(Locale.ROOT), damageOffset, speed, reach); - } - if (jsonObject.has("charged_reach")) - chargedReach = getDouble(jsonObject, "charged_reach"); - if (jsonObject.has("blocking_type")) { - String blocking_type = getString(jsonObject, "blocking_type"); - blocking_type = blocking_type.toLowerCase(Locale.ROOT); - if (!Combatify.registeredTypes.containsKey(blocking_type)) { - CrashReport report = CrashReport.forThrowable(new JsonSyntaxException("The specified blocking type does not exist!"), "Applying Item Blocking Type"); - CrashReportCategory crashReportCategory = report.addCategory("Weapon Type being parsed"); - crashReportCategory.setDetail("Type name", blocking_type); - crashReportCategory.setDetail("Json Object", jsonObject); - throw new ReportedException(report); - } - blockingType = Combatify.registeredTypes.get(blocking_type); + if (jsonObject.get("name") instanceof JsonArray weaponsWithConfig) { + weaponsWithConfig.asList().forEach( + weaponName -> { + WeaponType type = typeFromName(weaponName.getAsString()); + parseWeaponType(type, jsonObject); + } + ); + } else { + WeaponType type = typeFromJson(jsonObject); + parseWeaponType(type, jsonObject); } - if (jsonObject.has("has_sword_enchants")) - hasSwordEnchants = getBoolean(jsonObject, "has_sword_enchants"); - if (jsonObject.has("armor_piercing")) - piercingLevel = getDouble(jsonObject, "armor_piercing"); - if (jsonObject.has("can_sweep")) - canSweep = getBoolean(jsonObject, "can_sweep"); - if (jsonObject.has("sword_enchants_from_enchanting")) - isPrimaryForSwordEnchants = getBoolean(jsonObject, "sword_enchants_from_enchanting"); - ConfigurableWeaponData configurableWeaponData = new ConfigurableWeaponData(damageOffset, speed, reach, chargedReach, tierable, blockingType, hasSwordEnchants, isPrimaryForSwordEnchants, piercingLevel, canSweep); - configuredWeapons.put(type, configurableWeaponData); } else - throw new ReportedException(CrashReport.forThrowable(new IllegalStateException("Not a JSON Object: " + jsonElement + " this may be due to an incorrectly written config file."), "Configuring Weapon Types")); + notJSONObject(jsonElement, "Configuring Weapon Types"); }); } if (items instanceof JsonArray itemArray) { @@ -157,12 +207,85 @@ protected void loadExtra(JsonObject object) { parseItemConfig(item, jsonObject); } } else - throw new ReportedException(CrashReport.forThrowable(new IllegalStateException("Not a JSON Object: " + jsonElement + " this may be due to an incorrectly written config file."), "Configuring Items")); + notJSONObject(jsonElement, "Configuring Items"); }); } if (object.has("armor_calculation")) armourCalcs = new Formula(getString(object, "armor_calculation")); } + public void parseWeaponType(WeaponType type, JsonObject jsonObject) { + Double damageOffset = null; + Double speed = null; + Double reach = null; + Double chargedReach = null; + BlockingType blockingType = null; + Boolean tierable = null; + Boolean hasSwordEnchants = null; + Boolean isPrimaryForSwordEnchants = null; + Double piercingLevel = null; + Boolean canSweep = null; + + if (type != null && configuredWeapons.containsKey(type)) { + ConfigurableWeaponData oldData = configuredWeapons.get(type); + tierable = oldData.tierable; + damageOffset = oldData.damageOffset; + speed = oldData.speed; + reach = oldData.reach; + chargedReach = oldData.chargedReach; + blockingType = oldData.blockingType; + hasSwordEnchants = oldData.hasSwordEnchants; + isPrimaryForSwordEnchants = oldData.isPrimaryForSwordEnchants; + piercingLevel = oldData.piercingLevel; + canSweep = oldData.canSweep; + } + + if (jsonObject.has("tierable")) + tierable = getBoolean(jsonObject, "tierable"); + else if (tierable == null) { + LOGGER.error("The JSON must contain the boolean `tierable` if a weapon type is defined!" + errorStage("Configuring Weapon Types")); + return; + } + if (jsonObject.has("damage_offset")) + damageOffset = getDouble(jsonObject, "damage_offset"); + if (jsonObject.has("speed")) + speed = getDouble(jsonObject, "speed"); + if (jsonObject.has("reach")) + reach = getDouble(jsonObject, "reach"); + if (type == null) { + if (damageOffset == null || speed == null || reach == null) { + LOGGER.error("The JSON must contain the weapon type's attributes if a new weapon type is added!" + errorStage("Configuring Weapon Types")); + return; + } + type = tierable ? WeaponType.createBasic(GsonHelper.getAsString(jsonObject, "name").toLowerCase(Locale.ROOT), damageOffset, speed, reach) : WeaponType.createBasicUntierable(GsonHelper.getAsString(jsonObject, "name").toLowerCase(Locale.ROOT), damageOffset, speed, reach); + damageOffset = null; + speed = null; + reach = null; + } + if (jsonObject.has("charged_reach")) + chargedReach = getDouble(jsonObject, "charged_reach"); + if (jsonObject.has("blocking_type")) { + String blocking_type = getString(jsonObject, "blocking_type"); + blocking_type = blocking_type.toLowerCase(Locale.ROOT); + if (!Combatify.registeredTypes.containsKey(blocking_type)) { + CrashReport report = CrashReport.forThrowable(new JsonSyntaxException("The specified blocking type does not exist!"), "Applying Item Blocking Type"); + CrashReportCategory crashReportCategory = report.addCategory("Weapon Type being parsed"); + crashReportCategory.setDetail("Type name", blocking_type); + crashReportCategory.setDetail("Json Object", jsonObject); + throw new ReportedException(report); + } + blockingType = Combatify.registeredTypes.get(blocking_type); + } + if (jsonObject.has("has_sword_enchants")) + hasSwordEnchants = getBoolean(jsonObject, "has_sword_enchants"); + if (jsonObject.has("armor_piercing")) + piercingLevel = getDouble(jsonObject, "armor_piercing"); + if (jsonObject.has("can_sweep")) + canSweep = getBoolean(jsonObject, "can_sweep"); + if (jsonObject.has("sword_enchants_from_enchanting")) + isPrimaryForSwordEnchants = getBoolean(jsonObject, "sword_enchants_from_enchanting"); + ConfigurableWeaponData configurableWeaponData = new ConfigurableWeaponData(damageOffset, speed, reach, chargedReach, tierable, blockingType, hasSwordEnchants, isPrimaryForSwordEnchants, piercingLevel, canSweep); + configuredWeapons.put(type, configurableWeaponData); + } @Override protected InputStream getDefaultedConfig() { return Thread.currentThread().getContextClassLoader().getResourceAsStream("combatify-items.json"); @@ -177,9 +300,9 @@ public void defineConfigHolders() { @Override public void resetExtraHolders() { defineConfigHolders(); - tiers = HashBiMap.create(); - registeredWeaponTypes = new HashMap<>(); - registeredTypes = new HashMap<>(); + tiers = defaultTiers; + registeredWeaponTypes = defaultWeaponTypes; + registeredTypes = defaultTypes; } @Override @@ -228,9 +351,12 @@ public static Item itemFromName(String string) { public static WeaponType typeFromJson(JsonObject jsonObject) { String weapon_type = GsonHelper.getAsString(jsonObject, "name"); weapon_type = weapon_type.toLowerCase(Locale.ROOT); - if (!registeredWeaponTypes.containsKey(weapon_type)) + return typeFromName(weapon_type); + } + public static WeaponType typeFromName(String name) { + if (!registeredWeaponTypes.containsKey(name)) return null; - return WeaponType.fromID(weapon_type); + return WeaponType.fromID(name); } public static void parseBlockingType(JsonObject jsonObject) { @@ -313,11 +439,15 @@ public static void parseBlockingType(JsonObject jsonObject) { blockingType.setDelay(getBoolean(jsonObject, "has_shield_delay")); } public void parseTiers(JsonObject jsonObject) { - if (!jsonObject.has("name")) - throw new ReportedException(CrashReport.forThrowable(new IllegalStateException("An added tier does not possess a name. This is due to an incorrectly written config file."), "Configuring Tiers")); + if (!jsonObject.has("name")) { + LOGGER.error("An added tier does not possess a name. This is due to an incorrectly written config file." + errorStage("Configuring Tiers")); + return; + } String name = getString(jsonObject, "name"); - if (!jsonObject.has("base_tier")) - throw new ReportedException(CrashReport.forThrowable(new IllegalStateException("An added tier by the name of " + name + " has no tier to base off of. This is required for a tier to function."), "Configuring Tiers")); + if (!jsonObject.has("base_tier")) { + LOGGER.error("An added tier by the name of " + name + " has no tier to base off of. This is required for a tier to function." + errorStage("Configuring Tiers")); + return; + } String baseTierName = getString(jsonObject, "base_tier"); Tier baseTier = getTier(baseTierName); int uses = baseTier.getUses(); @@ -336,256 +466,40 @@ public void parseTiers(JsonObject jsonObject) { if (jsonObject.has("enchant_level")) enchantLevel = getInt(jsonObject, "enchant_level"); Ingredient repairIngredient = baseTier.getRepairIngredient(); - if (jsonObject.has("repair_ingredient")) - repairIngredient = Ingredient.of(itemFromName(getString(jsonObject, "repair_ingredient"))); - int finalUses = uses; - float finalSpeed = speed; - float finalDamage = damage; - int finalLevel = level; - int finalEnchantLevel = enchantLevel; - Ingredient finalRepairIngredient = repairIngredient; - tiers.put(name, new ExtendedTier() { - @Override - public int getLevel() { - return finalLevel; - } - - @Override - public String baseTierName() { - return baseTierName; - } - - @Override - public int getUses() { - return finalUses; - } - - @Override - public float getSpeed() { - return finalSpeed; - } - - @Override - public float getAttackDamageBonus() { - return finalDamage; - } - - @Override - public int getEnchantmentValue() { - return finalEnchantLevel; + if (jsonObject.has("repair_ingredient")) { + JsonElement repair_ingredient = jsonObject.get("repair_ingredient"); + if (repair_ingredient instanceof JsonArray jsonArray) { + List ingredients = new ArrayList<>(); + jsonArray.asList().forEach(jsonElement -> ingredients.add(itemFromName(jsonElement.getAsString()).getDefaultInstance())); + repairIngredient = Ingredient.of(ingredients.stream()); + } else { + String ri = repair_ingredient.getAsString(); + if (ri.startsWith("#")) + repairIngredient = Ingredient.of(TagKey.create(Registries.ITEM, new ResourceLocation(ri.substring(1)))); + else repairIngredient = Ingredient.of(itemFromName(ri)); } + } + TagKey incorrect = baseTier.getIncorrectBlocksForDrops(); + if (jsonObject.has("incorrect_blocks")) + incorrect = TagKey.create(Registries.BLOCK, new ResourceLocation(getString(jsonObject, "incorrect_blocks").substring(1))); - @Override - public @NotNull Ingredient getRepairIngredient() { - return finalRepairIngredient; - } - }); + tiers.put(name, ExtendedTier.create(level, enchantLevel, uses, damage, speed, repairIngredient, incorrect, baseTierName)); } - public ItemConfig loadFromNetwork(FriendlyByteBuf buf) { + public ItemConfig loadFromNetwork(RegistryFriendlyByteBuf buf) { super.loadFromNetwork(buf); - tiers = HashBiMap.create(buf.readMap(FriendlyByteBuf::readUtf, buf1 -> { - int uses = buf1.readVarInt(); - float speed = buf1.readFloat(); - float damage = buf1.readFloat(); - int level = buf1.readVarInt(); - int enchantLevel = buf1.readVarInt(); - Ingredient ingredient = Ingredient.of(BuiltInRegistries.ITEM.get(buf1.readResourceLocation())); - String baseTier = buf1.readUtf(); - return new ExtendedTier() { - @Override - public int getLevel() { - return level; - } - - @Override - public String baseTierName() { - return baseTier; - } - - @Override - public int getUses() { - return uses; - } - - @Override - public float getSpeed() { - return speed; - } - - @Override - public float getAttackDamageBonus() { - return damage; - } - - @Override - public int getEnchantmentValue() { - return enchantLevel; - } - - @Override - public @NotNull Ingredient getRepairIngredient() { - return ingredient; - } - }; - })); - registeredWeaponTypes = buf.readMap(FriendlyByteBuf::readUtf, buf1 -> { - String name = buf1.readUtf(); - double damageOffset = buf1.readDouble(); - double speed = buf1.readDouble(); - double reach = buf1.readDouble(); - boolean useAxeDamage = buf1.readBoolean(); - boolean useHoeDamage = buf1.readBoolean(); - boolean useHoeSpeed = buf1.readBoolean(); - boolean hasSwordEnchants = buf1.readBoolean(); - boolean tierable = buf1.readBoolean(); - return new WeaponType(name, damageOffset, speed, reach, useAxeDamage, useHoeDamage, useHoeSpeed, tierable, hasSwordEnchants, true); - }); - Combatify.registeredTypes = buf.readMap(FriendlyByteBuf::readUtf, buf1 -> { - try { - Class clazz = BlockingType.class.getClassLoader().loadClass(buf1.readUtf()); - Constructor constructor = clazz.getConstructor(String.class); - String name = buf1.readUtf(); - Object object = constructor.newInstance(name); - if (object instanceof BlockingType blockingType) { - blockingType.setDisablement(buf1.readBoolean()); - blockingType.setBlockHit(buf1.readBoolean()); - blockingType.setCrouchable(buf1.readBoolean()); - blockingType.setKbMechanics(buf1.readBoolean()); - blockingType.setToolBlocker(buf1.readBoolean()); - blockingType.setRequireFullCharge(buf1.readBoolean()); - blockingType.setSwordBlocking(buf1.readBoolean()); - blockingType.setDelay(buf1.readBoolean()); - Combatify.registerBlockingType(blockingType); - return blockingType; - } else { - CrashReport report = CrashReport.forThrowable(new IllegalStateException("The specified class is not an instance of BlockingType!"), "Syncing Blocking Types"); - CrashReportCategory crashReportCategory = report.addCategory("Blocking Type being synced"); - crashReportCategory.setDetail("Class", clazz.getName()); - crashReportCategory.setDetail("Type Name", name); - throw new ReportedException(report); - } - } catch (InvocationTargetException | InstantiationException | IllegalAccessException | - ClassNotFoundException | NoSuchMethodException e) { - throw new ReportedException(CrashReport.forThrowable(new RuntimeException(e), "Syncing Blocking Types")); - } - }); - configuredItems = buf.readMap(buf12 -> BuiltInRegistries.ITEM.get(buf12.readResourceLocation()), buf1 -> { - Double damage = buf1.readDouble(); - Double speed = buf1.readDouble(); - Double reach = buf1.readDouble(); - Double chargedReach = buf1.readDouble(); - Integer stackSize = buf1.readVarInt(); - Integer durability = buf1.readVarInt(); - Integer cooldown = buf1.readInt(); - Boolean cooldownAfter = null; - if (cooldown != -10) - cooldownAfter = buf1.readBoolean(); - String weaponType = buf1.readUtf(); - WeaponType type = null; - String blockingType = buf1.readUtf(); - BlockingType bType = Combatify.registeredTypes.get(blockingType); - Double blockStrength = buf1.readDouble(); - Double blockKbRes = buf1.readDouble(); - Integer enchantlevel = buf1.readInt(); - int isEnchantableAsInt = buf1.readInt(); - int hasSwordEnchantsAsInt = buf1.readInt(); - int isPrimaryForSwordEnchantsAsInt = buf1.readInt(); - Boolean isEnchantable = null; - Boolean hasSwordEnchants = null; - Boolean isPrimaryForSwordEnchants = null; - Integer useDuration = buf1.readInt(); - Double piercingLevel = buf1.readDouble(); - int canSweepAsInt = buf1.readInt(); - Boolean canSweep = null; - Tier tier = getTier(buf1.readUtf()); - Integer defense = buf1.readInt(); - Double toughness = buf1.readDouble(); - Double armourKbRes = buf1.readDouble(); - String repairIngredient = buf1.readUtf(); - Ingredient ingredient = Objects.equals(repairIngredient, "empty") ? null : Ingredient.of(BuiltInRegistries.ITEM.get(new ResourceLocation(repairIngredient))); - if (damage == -10) - damage = null; - if (speed == -10) - speed = null; - if (reach == -10) - reach = null; - if (chargedReach == -10) - chargedReach = null; - if (stackSize == -10) - stackSize = null; - if (durability == -10) - durability = null; - if (cooldown == -10) - cooldown = null; - if (blockStrength == -10) - blockStrength = null; - if (blockKbRes == -10) - blockKbRes = null; - if (enchantlevel == -10) - enchantlevel = null; - if (isEnchantableAsInt != -10) - isEnchantable = isEnchantableAsInt == 1; - if (hasSwordEnchantsAsInt != -10) - hasSwordEnchants = hasSwordEnchantsAsInt == 1; - if (isPrimaryForSwordEnchantsAsInt != -10) - isPrimaryForSwordEnchants = isPrimaryForSwordEnchantsAsInt == 1; - if (useDuration == -10) - useDuration = null; - if (piercingLevel == -10) - piercingLevel = null; - if (canSweepAsInt != -10) - canSweep = canSweepAsInt == 1; - if (registeredWeaponTypes.containsKey(weaponType)) - type = WeaponType.fromID(weaponType); - if (defense == -10) - defense = null; - if (toughness == -10) - toughness = null; - if (armourKbRes == -10) - armourKbRes = null; - return new ConfigurableItemData(damage, speed, reach, chargedReach, stackSize, cooldown, cooldownAfter, type, bType, blockStrength, blockKbRes, enchantlevel, isEnchantable, hasSwordEnchants, isPrimaryForSwordEnchants, useDuration, piercingLevel, canSweep, tier, durability, defense, toughness, armourKbRes, ingredient); - }); - configuredWeapons = buf.readMap(buf1 -> WeaponType.fromID(buf1.readUtf()), buf1 -> { - Double damageOffset = buf1.readDouble(); - Double speed = buf1.readDouble(); - Double reach = buf1.readDouble(); - Double chargedReach = buf1.readDouble(); - Boolean tierable = buf1.readBoolean(); - String blockingType = buf1.readUtf(); - BlockingType bType = Combatify.registeredTypes.get(blockingType); - int hasSwordEnchantsAsInt = buf1.readInt(); - Boolean hasSwordEnchants = null; - int isPrimaryForSwordEnchantsAsInt = buf1.readInt(); - Boolean isPrimaryForSwordEnchants = null; - Double piercingLevel = buf1.readDouble(); - int canSweepAsInt = buf1.readInt(); - Boolean canSweep = null; - if (damageOffset == -10) - damageOffset = null; - if (speed == -10) - speed = null; - if (reach == -10) - reach = null; - if (chargedReach == -10) - chargedReach = null; - if (hasSwordEnchantsAsInt != -10) - hasSwordEnchants = hasSwordEnchantsAsInt == 1; - if (isPrimaryForSwordEnchantsAsInt != -10) - isPrimaryForSwordEnchants = isPrimaryForSwordEnchantsAsInt == 1; - if (piercingLevel == -10) - piercingLevel = null; - if (canSweepAsInt != -10) - canSweep = canSweepAsInt == 1; - return new ConfigurableWeaponData(damageOffset, speed, reach, chargedReach, tierable, bType, hasSwordEnchants, isPrimaryForSwordEnchants, piercingLevel, canSweep); - }); + tiers = HashBiMap.create(readMap(buf, NAME_STREAM_CODEC, TIERS_STREAM_CODEC)); + registeredWeaponTypes = readMap(buf, NAME_STREAM_CODEC, REGISTERED_WEAPON_TYPE_STREAM_CODEC); + registeredTypes = readMap(buf, NAME_STREAM_CODEC, BLOCKING_TYPE_STREAM_CODEC); + configuredItems = readMap(buf, ITEM_STREAM_CODEC, ITEM_DATA_STREAM_CODEC); + configuredWeapons = readMap(buf, WeaponType.STREAM_CODEC, WEAPON_DATA_STREAM_CODEC); String formula = buf.readUtf(); if (!formula.equals("empty")) armourCalcs = new Formula(formula); return this; } - public Tier getTier(String s) { + public static Tier getTier(String s) { return switch (s.toLowerCase()) { case "wood" -> Tiers.WOOD; case "stone" -> Tiers.STONE; @@ -596,7 +510,7 @@ public Tier getTier(String s) { default -> getTierRaw(s); }; } - private String getTierName(Tier tier) { + public static String getTierName(Tier tier) { if (tier instanceof Tiers vanilla) { return switch (vanilla) { case WOOD -> "wood"; @@ -609,87 +523,46 @@ private String getTierName(Tier tier) { } return tiers.inverse().get(tier); } - private Tier getTierRaw(String s) { + private static Tier getTierRaw(String s) { if (!tiers.containsKey(s) || Objects.equals(s, "empty")) return null; return tiers.get(s); } - public void saveToNetwork(FriendlyByteBuf buf) { + public void saveToNetwork(RegistryFriendlyByteBuf buf) { super.saveToNetwork(buf); - buf.writeMap(tiers, FriendlyByteBuf::writeUtf, (buf1, tier) -> { - buf1.writeVarInt(tier.getUses()); - buf1.writeFloat(tier.getSpeed()); - buf1.writeFloat(tier.getAttackDamageBonus()); - buf1.writeVarInt(ExtendedTier.getLevel(tier)); - buf1.writeVarInt(tier.getEnchantmentValue()); - buf1.writeResourceLocation(BuiltInRegistries.ITEM.getKey(tier.getRepairIngredient().getItems()[0].getItem())); - buf1.writeUtf(tier instanceof ExtendedTier extendedTier ? extendedTier.baseTierName() : getTierName(tier)); - }); - buf.writeMap(registeredWeaponTypes, FriendlyByteBuf::writeUtf, (buf1, weaponType) -> { - buf1.writeUtf(weaponType.name); - buf1.writeDouble(weaponType.damageOffset); - buf1.writeDouble(weaponType.speed); - buf1.writeDouble(weaponType.reach); - buf1.writeBoolean(weaponType.useAxeDamage); - buf1.writeBoolean(weaponType.useHoeDamage); - buf1.writeBoolean(weaponType.useHoeSpeed); - buf1.writeBoolean(weaponType.hasSwordEnchants); - buf1.writeBoolean(weaponType.tierable); - }); - buf.writeMap(Combatify.registeredTypes, FriendlyByteBuf::writeUtf, (buf1, blockingType) -> { - buf1.writeUtf(blockingType.getClass().getName()); - buf1.writeUtf(blockingType.getName()); - buf1.writeBoolean(blockingType.canBeDisabled()); - buf1.writeBoolean(blockingType.canBlockHit()); - buf1.writeBoolean(blockingType.canCrouchBlock()); - buf1.writeBoolean(blockingType.defaultKbMechanics()); - buf1.writeBoolean(blockingType.isToolBlocker()); - buf1.writeBoolean(blockingType.requireFullCharge()); - buf1.writeBoolean(blockingType.requiresSwordBlocking()); - buf1.writeBoolean(blockingType.hasDelay()); - }); - buf.writeMap(configuredItems, (buf1, item) -> buf1.writeResourceLocation(BuiltInRegistries.ITEM.getKey(item)), (buf12, configurableItemData) -> { - buf12.writeDouble(configurableItemData.damage == null ? -10 : configurableItemData.damage); - buf12.writeDouble(configurableItemData.speed == null ? -10 : configurableItemData.speed); - buf12.writeDouble(configurableItemData.reach == null ? -10 : configurableItemData.reach); - buf12.writeDouble(configurableItemData.chargedReach == null ? -10 : configurableItemData.chargedReach); - buf12.writeVarInt(configurableItemData.stackSize == null ? -10 : configurableItemData.stackSize); - buf12.writeVarInt(configurableItemData.durability == null ? -10 : configurableItemData.durability); - buf12.writeInt(configurableItemData.cooldown == null ? -10 : configurableItemData.cooldown); - if(configurableItemData.cooldown != null) - buf12.writeBoolean(configurableItemData.cooldownAfter); - buf12.writeUtf(configurableItemData.type == null ? "empty" : configurableItemData.type.name); - buf12.writeUtf(configurableItemData.blockingType == null ? "blank" : configurableItemData.blockingType.getName()); - buf12.writeDouble(configurableItemData.blockStrength == null ? -10 : configurableItemData.blockStrength); - buf12.writeDouble(configurableItemData.blockKbRes == null ? -10 : configurableItemData.blockKbRes); - buf12.writeInt(configurableItemData.enchantability == null ? -10 : configurableItemData.enchantability); - buf12.writeInt(configurableItemData.isEnchantable == null ? -10 : configurableItemData.isEnchantable ? 1 : 0); - buf12.writeInt(configurableItemData.hasSwordEnchants == null ? -10 : configurableItemData.hasSwordEnchants ? 1 : 0); - buf12.writeInt(configurableItemData.isPrimaryForSwordEnchants == null ? -10 : configurableItemData.isPrimaryForSwordEnchants ? 1 : 0); - buf12.writeInt(configurableItemData.useDuration == null ? -10 : configurableItemData.useDuration); - buf12.writeDouble(configurableItemData.piercingLevel == null ? -10 : configurableItemData.piercingLevel); - buf12.writeInt(configurableItemData.canSweep == null ? -10 : configurableItemData.canSweep ? 1 : 0); - buf12.writeUtf(configurableItemData.tier == null ? "empty" : getTierName(configurableItemData.tier)); - buf12.writeInt(configurableItemData.defense == null ? -10 : configurableItemData.defense); - buf12.writeDouble(configurableItemData.toughness == null ? -10 : configurableItemData.toughness); - buf12.writeDouble(configurableItemData.armourKbRes == null ? -10 : configurableItemData.armourKbRes); - buf12.writeUtf(configurableItemData.repairIngredient == null ? "empty" : BuiltInRegistries.ITEM.getKey(configurableItemData.repairIngredient.getItems()[0].getItem()).toString()); - }); - buf.writeMap(configuredWeapons, (buf1, type) -> buf1.writeUtf(type.name), (buf12, configurableWeaponData) -> { - buf12.writeDouble(configurableWeaponData.damageOffset == null ? -10 : configurableWeaponData.damageOffset); - buf12.writeDouble(configurableWeaponData.speed == null ? -10 : configurableWeaponData.speed); - buf12.writeDouble(configurableWeaponData.reach == null ? -10 : configurableWeaponData.reach); - buf12.writeDouble(configurableWeaponData.chargedReach == null ? -10 : configurableWeaponData.chargedReach); - buf12.writeBoolean(configurableWeaponData.tierable); - buf12.writeUtf(configurableWeaponData.blockingType == null ? "blank" : configurableWeaponData.blockingType.getName()); - buf12.writeInt(configurableWeaponData.hasSwordEnchants == null ? -10 : configurableWeaponData.hasSwordEnchants ? 1 : 0); - buf12.writeInt(configurableWeaponData.isPrimaryForSwordEnchants == null ? -10 : configurableWeaponData.isPrimaryForSwordEnchants ? 1 : 0); - buf12.writeDouble(configurableWeaponData.piercingLevel == null ? -10 : configurableWeaponData.piercingLevel); - buf12.writeInt(configurableWeaponData.canSweep == null ? -10 : configurableWeaponData.canSweep ? 1 : 0); - }); + writeMap(buf, tiers, NAME_STREAM_CODEC, TIERS_STREAM_CODEC); + writeMap(buf, registeredWeaponTypes, NAME_STREAM_CODEC, REGISTERED_WEAPON_TYPE_STREAM_CODEC); + writeMap(buf, Combatify.registeredTypes, NAME_STREAM_CODEC, BLOCKING_TYPE_STREAM_CODEC); + writeMap(buf, configuredItems, ITEM_STREAM_CODEC, ITEM_DATA_STREAM_CODEC); + writeMap(buf, configuredWeapons, WeaponType.STREAM_CODEC, WEAPON_DATA_STREAM_CODEC); buf.writeUtf(armourCalcs == null ? "empty" : armourCalcs.written); } + public static Map readMap(B buf, StreamCodec keyCodec, StreamCodec valueCodec) { + return readMap(buf, Maps::newHashMapWithExpectedSize, keyCodec, valueCodec); + } + + public static > M readMap(B buf, IntFunction intFunction, StreamCodec keyCodec, StreamCodec valueCodec) { + int size = buf.readVarInt(); + M map = intFunction.apply(size); + + for (int index = 0; index < size; ++index) { + K key = keyCodec.decode(buf); + V value = valueCodec.decode(buf); + map.put(key, value); + } + + return map; + } + + public static void writeMap(B buf, Map map, StreamCodec keyCodec, StreamCodec valueCodec) { + buf.writeVarInt(map.size()); + map.forEach((key, value) -> { + keyCodec.encode(buf, key); + valueCodec.encode(buf, value); + }); + } + @Override public void saveExtra(JsonWriter jsonWriter, PrintWriter printWriter) { @@ -814,8 +687,10 @@ public void parseItemConfig(Item item, JsonObject jsonObject) { blockingType = Combatify.registeredTypes.get(blocking_type); } if (cooldown != null && cooldownAfterUse == null) { - if (!jsonObject.has("cooldown_after")) - throw new ReportedException(CrashReport.forThrowable(new JsonSyntaxException("The JSON must contain the boolean 'cooldown_after' if a cooldown is defined!"), "Applying Item Cooldown")); + if (!jsonObject.has("cooldown_after")) { + LOGGER.error("The JSON must contain the boolean 'cooldown_after' if a cooldown is defined!" + errorStage("Applying Item Cooldown")); + return; + } cooldownAfterUse = getBoolean(jsonObject, "cooldown_after"); } if (jsonObject.has("damage_protection")) @@ -839,8 +714,10 @@ public void parseItemConfig(Item item, JsonObject jsonObject) { if (jsonObject.has("durability")) { JsonElement durabilityE = jsonObject.get("durability"); if (durabilityE instanceof JsonObject durabilityO) { - if (!durabilityO.has("any")) - throw new ReportedException(CrashReport.forThrowable(new JsonSyntaxException("The JSON must contain the integer 'any' when armour is configured!"), "Applying Item Durability")); + if (!durabilityO.has("any")) { + LOGGER.error("The JSON must contain the integer 'any' when armour is configured!" + errorStage("Applying Item Durability")); + return; + } if (item instanceof ArmorItem armorItem) { durability = getIntWithFallback(durabilityO, armorItem.getType().getName(), "any"); } else durability = getInt(durabilityO, "any"); @@ -851,8 +728,10 @@ public void parseItemConfig(Item item, JsonObject jsonObject) { if (jsonObject.has("armor")) { JsonElement defenseE = jsonObject.get("armor"); if (defenseE instanceof JsonObject defenseO) { - if (!defenseO.has("any")) - throw new ReportedException(CrashReport.forThrowable(new JsonSyntaxException("The JSON must contain the integer 'any' when armour is configured!"), "Applying Item Defense")); + if (!defenseO.has("any")) { + LOGGER.error("The JSON must contain the integer 'any' when armour is configured!" + errorStage("Applying Item Defense")); + return; + } if (item instanceof ArmorItem armorItem) { defense = getIntWithFallback(defenseO, armorItem.getType().getName(), "any"); } else defense = getInt(defenseO, "any"); @@ -862,11 +741,28 @@ public void parseItemConfig(Item item, JsonObject jsonObject) { toughness = getDouble(jsonObject, "armor_toughness"); if (jsonObject.has("armor_knockback_resistance")) armourKbRes = getDouble(jsonObject, "armor_knockback_resistance"); - if (jsonObject.has("repair_ingredient")) - ingredient = Ingredient.of(itemFromName(getString(jsonObject, "repair_ingredient"))); + if (jsonObject.has("repair_ingredient")) { + JsonElement repair_ingredient = jsonObject.get("repair_ingredient"); + if (repair_ingredient instanceof JsonArray jsonArray) { + List ingredients = new ArrayList<>(); + jsonArray.asList().forEach(jsonElement -> ingredients.add(itemFromName(jsonElement.getAsString()).getDefaultInstance())); + ingredient = Ingredient.of(ingredients.stream()); + } else { + String ri = repair_ingredient.getAsString(); + if (ri.startsWith("#")) + ingredient = Ingredient.of(TagKey.create(Registries.ITEM, new ResourceLocation(ri.substring(1)))); + else ingredient = Ingredient.of(itemFromName(ri)); + } + } ConfigurableItemData configurableItemData = new ConfigurableItemData(damage, speed, reach, chargedReach, stack_size, cooldown, cooldownAfterUse, type, blockingType, blockStrength, blockKbRes, enchantment_level, isEnchantable, hasSwordEnchants, isPrimaryForSwordEnchants, useDuration, piercingLevel, canSweep, tier, durability, defense, toughness, armourKbRes, ingredient); configuredItems.put(item, configurableItemData); } + public static void notJSONObject(JsonElement invalid, String stage) { + LOGGER.error("Not a JSON Object: " + invalid + " this may be due to an incorrectly written config file. " + errorStage(stage)); + } + public static String errorStage(String stage) { + return "[Config Stage]: " + stage; + } public record Formula(String written) { public float armourCalcs(float amount, DamageSource damageSource, float armour, float armourToughness) { String armourFormula = written.split("enchant:", 2)[0]; diff --git a/src/main/java/net/atlas/combatify/extensions/ExtendedTier.java b/src/main/java/net/atlas/combatify/extensions/ExtendedTier.java index a95e53e..b558839 100644 --- a/src/main/java/net/atlas/combatify/extensions/ExtendedTier.java +++ b/src/main/java/net/atlas/combatify/extensions/ExtendedTier.java @@ -1,31 +1,16 @@ package net.atlas.combatify.extensions; -import net.atlas.combatify.Combatify; -import net.minecraft.tags.BlockTags; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Tier; import net.minecraft.world.item.Tiers; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.block.Block; import org.jetbrains.annotations.NotNull; public interface ExtendedTier extends Tier { int getLevel(); - default Tier baseTier() { - return Combatify.ITEMS.getTier(baseTierName()); - } String baseTierName(); - @Override - default @NotNull TagKey getIncorrectBlocksForDrops() { - return switch (getLevel()) { - case 0 -> BlockTags.INCORRECT_FOR_WOODEN_TOOL; - case 1 -> BlockTags.INCORRECT_FOR_STONE_TOOL; - case 2 -> BlockTags.INCORRECT_FOR_IRON_TOOL; - case 3 -> BlockTags.INCORRECT_FOR_DIAMOND_TOOL; - case 4 -> BlockTags.INCORRECT_FOR_NETHERITE_TOOL; - default -> baseTier().getIncorrectBlocksForDrops(); - }; - } static int getLevelFromDefault(Tier tier) { if (tier instanceof Tiers tiers) { return switch (tiers) { @@ -43,4 +28,47 @@ static int getLevel(Tier tier) { return extendedTier.getLevel(); return getLevelFromDefault(tier); } + static ExtendedTier create(int level, int enchantLevel, int uses, float damage, float speed, Ingredient repairIngredient, TagKey incorrect, String baseTier) { + return new ExtendedTier() { + @Override + public int getLevel() { + return level; + } + + @Override + public String baseTierName() { + return baseTier; + } + + @Override + public @NotNull TagKey getIncorrectBlocksForDrops() { + return incorrect; + } + + @Override + public int getUses() { + return uses; + } + + @Override + public float getSpeed() { + return speed; + } + + @Override + public float getAttackDamageBonus() { + return damage; + } + + @Override + public int getEnchantmentValue() { + return enchantLevel; + } + + @Override + public @NotNull Ingredient getRepairIngredient() { + return repairIngredient; + } + }; + } } diff --git a/src/main/java/net/atlas/combatify/item/WeaponType.java b/src/main/java/net/atlas/combatify/item/WeaponType.java index 2ef1835..c305d7f 100644 --- a/src/main/java/net/atlas/combatify/item/WeaponType.java +++ b/src/main/java/net/atlas/combatify/item/WeaponType.java @@ -3,6 +3,8 @@ import net.atlas.combatify.Combatify; import net.atlas.combatify.config.ConfigurableWeaponData; import net.atlas.combatify.extensions.ExtendedTier; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.world.entity.EquipmentSlotGroup; import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.ai.attributes.Attributes; @@ -16,6 +18,7 @@ import static net.minecraft.world.item.Item.BASE_ATTACK_DAMAGE_UUID; public class WeaponType { + public static final StreamCodec STREAM_CODEC = StreamCodec.of((buf, weaponType) -> buf.writeUtf(weaponType.name), buf -> WeaponType.fromID(buf.readUtf())); public static final WeaponType EMPTY = createBasicUntierable("empty", 0, 0, 0); public static final WeaponType SWORD = createBasic("sword", 2, 0.5, 0.5); public static final WeaponType MACE = createBasic("mace", 2, 0.5, 0); @@ -190,6 +193,14 @@ else if (tier == Tiers.DIAMOND || tier == Tiers.GOLD || tier == Tiers.NETHERITE return speed; } public static void init() { - + Combatify.defineDefaultWeaponType(SWORD); + Combatify.defineDefaultWeaponType(MACE); + Combatify.defineDefaultWeaponType(LONGSWORD); + Combatify.defineDefaultWeaponType(AXE); + Combatify.defineDefaultWeaponType(PICKAXE); + Combatify.defineDefaultWeaponType(HOE); + Combatify.defineDefaultWeaponType(SHOVEL); + Combatify.defineDefaultWeaponType(KNIFE); + Combatify.defineDefaultWeaponType(TRIDENT); } }