diff --git a/ansible/build.gradle.kts b/ansible/build.gradle.kts index 6dac5bdf4..6c06ec8ef 100644 --- a/ansible/build.gradle.kts +++ b/ansible/build.gradle.kts @@ -26,6 +26,7 @@ dependencies { paperPlugin(project(path = ":plugins:randomspawn-paper")) paperPlugin(project(path = ":plugins:realisticbiomes-paper")) paperPlugin(project(path = ":plugins:simpleadminhacks-paper")) + paperPlugin(project(path = ":plugins:heliodor-paper")) pvpPlugin(project(path = ":plugins:banstick-paper", configuration = "shadow")) pvpPlugin(project(path = ":plugins:civduties-paper")) @@ -35,6 +36,7 @@ dependencies { pvpPlugin(project(path = ":plugins:simpleadminhacks-paper")) pvpPlugin(project(path = ":plugins:kitpvp-paper")) pvpPlugin(project(path = ":plugins:voidworld-paper")) + pvpPlugin(project(path = ":plugins:heliodor-paper")) } val copyPaperPlugins = tasks.register("copyPaperPlugins") { diff --git a/ansible/files/paper-config/plugins/FactoryMod/config.yml b/ansible/files/paper-config/plugins/FactoryMod/config.yml index ac8e691aa..2b9ec1430 100644 --- a/ansible/files/paper-config/plugins/FactoryMod/config.yml +++ b/ansible/files/paper-config/plugins/FactoryMod/config.yml @@ -14,8 +14,75 @@ disable_nether: false use_recipe_yamlidentifiers: true log_inventories: true force_include_default: true +can_upgrade: true factories: + meteoric_iron_sword: + type: FCC + name: Meteoric Iron Sword Smith + citadelBreakReduction: 1.0 + setupcost: + meteoric_iron_ingot: + custom-key: meteoric_iron_ingot + amount: 7 + essence: + v: 3839 + ==: org.bukkit.inventory.ItemStack + type: ENDER_EYE + amount: 49 + meta: + meta-type: UNSPECIFIC + ==: ItemMeta + display-name: Player Essence + lore: + - Activity reward used to fuel pearls + recipes: + - make_meteoric_iron_sword + - repair_meteoric_iron_sword_factory + meteoric_iron_pickaxe: + type: FCC + name: Meteoric Iron Pickaxe Smith + citadelBreakReduction: 1.0 + setupcost: + meteoric_iron_ingot: + custom-key: meteoric_iron_ingot + amount: 11 + essence: + v: 3839 + ==: org.bukkit.inventory.ItemStack + type: ENDER_EYE + amount: 77 + meta: + meta-type: UNSPECIFIC + ==: ItemMeta + display-name: Player Essence + lore: + - Activity reward used to fuel pearls + recipes: + - make_meteoric_iron_pickaxe + - repair_meteoric_iron_pickaxe_factory + meteoric_iron_axe: + type: FCC + name: Meteoric Iron Axe Smith + citadelBreakReduction: 1.0 + setupcost: + meteoric_iron_ingot: + custom-key: meteoric_iron_ingot + amount: 10 + essence: + v: 3839 + ==: org.bukkit.inventory.ItemStack + type: ENDER_EYE + amount: 70 + meta: + meta-type: UNSPECIFIC + ==: ItemMeta + display-name: Player Essence + lore: + - Activity reward used to fuel pearls + recipes: + - make_meteoric_iron_axe + - repair_meteoric_iron_axe_factory stone_smelter: type: FCC name: Basic Smelter @@ -1445,14 +1512,14 @@ factories: type: HONEYCOMB amount: 32 recipes: - - wax_copper_block - - wax_exposed_copper - - wax_weathered_copper - - wax_oxidized_copper - - weather_copper_block - - weather_exposed_copper - - weather_weathered_copper - - repair_copper_workshop + - wax_copper_block + - wax_exposed_copper + - wax_weathered_copper + - wax_oxidized_copper + - weather_copper_block + - weather_exposed_copper + - weather_weathered_copper + - repair_copper_workshop #RECIPES recipes: smelt_stone: @@ -7686,10 +7753,10 @@ recipes: type: PRODUCTION input: iron_ingot: - v: 3839 - ==: org.bukkit.inventory.ItemStack - type: IRON_INGOT - amount: 6 + v: 3839 + ==: org.bukkit.inventory.ItemStack + type: IRON_INGOT + amount: 6 lava_bucket: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -9581,7 +9648,7 @@ recipes: ==: ItemMeta display-name: Plains Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -9618,7 +9685,7 @@ recipes: ==: ItemMeta display-name: Plains Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -9655,7 +9722,7 @@ recipes: ==: ItemMeta display-name: Plains Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -9692,7 +9759,7 @@ recipes: ==: ItemMeta display-name: Relic Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -9729,7 +9796,7 @@ recipes: ==: ItemMeta display-name: Arid Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -9766,7 +9833,7 @@ recipes: ==: ItemMeta display-name: Forest Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -9803,7 +9870,7 @@ recipes: ==: ItemMeta display-name: Forest Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -9840,7 +9907,7 @@ recipes: ==: ItemMeta display-name: Forest Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -9877,7 +9944,7 @@ recipes: ==: ItemMeta display-name: Forest Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -9914,7 +9981,7 @@ recipes: ==: ItemMeta display-name: Relic Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -9951,7 +10018,7 @@ recipes: ==: ItemMeta display-name: Relic Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -9988,7 +10055,7 @@ recipes: ==: ItemMeta display-name: Barren Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -10025,7 +10092,7 @@ recipes: ==: ItemMeta display-name: Arid Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -10062,7 +10129,7 @@ recipes: ==: ItemMeta display-name: Arid Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -10099,7 +10166,7 @@ recipes: ==: ItemMeta display-name: Barren Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -10136,7 +10203,7 @@ recipes: ==: ItemMeta display-name: Barren Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -10173,7 +10240,7 @@ recipes: ==: ItemMeta display-name: Tricky Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -10210,7 +10277,7 @@ recipes: ==: ItemMeta display-name: Tricky Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station diamond: v: 3839 ==: org.bukkit.inventory.ItemStack @@ -10292,7 +10359,7 @@ recipes: lore: - Crack it open for a surprise! outputs: - #Food--- 60% + #Food--- 60% egg: chance: 0.15 egg: @@ -10321,7 +10388,7 @@ recipes: ==: org.bukkit.inventory.ItemStack type: BREAD amount: 8 - #Good Loot--- 30% + #Good Loot--- 30% ironingot: chance: 0.0375 ironingot: @@ -10378,7 +10445,7 @@ recipes: ==: org.bukkit.inventory.ItemStack type: GOLDEN_APPLE amount: 4 - #Unique--- 10% + #Unique--- 10% recipe1: chance: 0.01 recipe1: @@ -13809,7 +13876,7 @@ recipes: ==: ItemMeta display-name: Plains Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_cat: production_time: 4s fuel_consumption_intervall: 1s @@ -13832,7 +13899,7 @@ recipes: ==: ItemMeta display-name: Plains Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_blocks: production_time: 4s fuel_consumption_intervall: 1s @@ -13855,7 +13922,7 @@ recipes: ==: ItemMeta display-name: Plains Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_chirp: production_time: 4s fuel_consumption_intervall: 1s @@ -13878,7 +13945,7 @@ recipes: ==: ItemMeta display-name: Relic Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_far: production_time: 4s fuel_consumption_intervall: 1s @@ -13901,7 +13968,7 @@ recipes: ==: ItemMeta display-name: Relic Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_relic: production_time: 4s fuel_consumption_intervall: 1s @@ -13924,7 +13991,7 @@ recipes: ==: ItemMeta display-name: Relic Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_stal: production_time: 4s fuel_consumption_intervall: 1s @@ -13947,7 +14014,7 @@ recipes: ==: ItemMeta display-name: Arid Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_strad: production_time: 4s fuel_consumption_intervall: 1s @@ -13970,7 +14037,7 @@ recipes: ==: ItemMeta display-name: Arid Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_pigstep: production_time: 4s fuel_consumption_intervall: 1s @@ -13993,7 +14060,7 @@ recipes: ==: ItemMeta display-name: Arid Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_ward: production_time: 4s fuel_consumption_intervall: 1s @@ -14016,7 +14083,7 @@ recipes: ==: ItemMeta display-name: Barren Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_wait: production_time: 4s fuel_consumption_intervall: 1s @@ -14039,7 +14106,7 @@ recipes: ==: ItemMeta display-name: Barren Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_otherside: production_time: 4s fuel_consumption_intervall: 1s @@ -14062,7 +14129,7 @@ recipes: ==: ItemMeta display-name: Barren Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_mall: production_time: 4s fuel_consumption_intervall: 1s @@ -14085,7 +14152,7 @@ recipes: ==: ItemMeta display-name: Forest Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_5: production_time: 4s fuel_consumption_intervall: 1s @@ -14108,7 +14175,7 @@ recipes: ==: ItemMeta display-name: Forest Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_11: production_time: 4s fuel_consumption_intervall: 1s @@ -14131,7 +14198,7 @@ recipes: ==: ItemMeta display-name: Forest Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_mellohi: production_time: 4s fuel_consumption_intervall: 1s @@ -14154,7 +14221,7 @@ recipes: ==: ItemMeta display-name: Forest Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_precipice: production_time: 4s fuel_consumption_intervall: 1s @@ -14177,7 +14244,7 @@ recipes: ==: ItemMeta display-name: Tricky Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_creator: production_time: 4s fuel_consumption_intervall: 1s @@ -14200,7 +14267,7 @@ recipes: ==: ItemMeta display-name: Tricky Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station crush_disc_creator_music_box: production_time: 4s fuel_consumption_intervall: 1s @@ -14223,4 +14290,100 @@ recipes: ==: ItemMeta display-name: Tricky Trim Fragment lore: - - Used to produce trims in the Research Station + - Used to produce trims in the Research Station + make_meteoric_iron_sword: + production_time: 4s + name: Make Meteoric Iron Sword + type: PRODUCTION + input: + meteoric_iron_ingot: + custom-key: meteoric_iron_ingot + amount: 6 + output: + meteoric_iron_sword: + custom-key: meteoric_iron_sword + amount: 5 + repair_meteoric_iron_sword_factory: + production_time: 4s + name: Repair Factory + type: REPAIR + input: + meteoric_iron_ingot: + custom-key: meteoric_iron_ingot + amount: 1 + essence: + v: 3839 + ==: org.bukkit.inventory.ItemStack + type: ENDER_EYE + amount: 7 + meta: + meta-type: UNSPECIFIC + ==: ItemMeta + display-name: Player Essence + lore: + - Activity reward used to fuel pearls + health_gained: 10000 + make_meteoric_iron_pickaxe: + production_time: 4s + name: Make Meteoric Iron Pickaxe + type: PRODUCTION + input: + meteoric_iron_ingot: + custom-key: meteoric_iron_ingot + amount: 10 + output: + meteoric_iron_pickaxe: + custom-key: meteoric_iron_pickaxe + amount: 5 + repair_meteoric_iron_pickaxe_factory: + production_time: 4s + name: Repair Factory + type: REPAIR + input: + meteoric_iron_ingot: + custom-key: meteoric_iron_ingot + amount: 1 + essence: + v: 3839 + ==: org.bukkit.inventory.ItemStack + type: ENDER_EYE + amount: 11 + meta: + meta-type: UNSPECIFIC + ==: ItemMeta + display-name: Player Essence + lore: + - Activity reward used to fuel pearls + health_gained: 10000 + make_meteoric_iron_axe: + production_time: 4s + name: Make Meteoric Iron Axe + type: PRODUCTION + input: + meteoric_iron_ingot: + custom-key: meteoric_iron_ingot + amount: 9 + output: + meteoric_iron_axe: + custom-key: meteoric_iron_axe + amount: 5 + repair_meteoric_iron_axe_factory: + production_time: 4s + name: Repair Factory + type: REPAIR + input: + meteoric_iron_ingot: + custom-key: meteoric_iron_ingot + amount: 1 + essence: + v: 3839 + ==: org.bukkit.inventory.ItemStack + type: ENDER_EYE + amount: 10 + meta: + meta-type: UNSPECIFIC + ==: ItemMeta + display-name: Player Essence + lore: + - Activity reward used to fuel pearls + health_gained: 10000 diff --git a/ansible/files/paper-config/plugins/Finale/config.yml b/ansible/files/paper-config/plugins/Finale/config.yml index 5d5c9de62..a258e2709 100644 --- a/ansible/files/paper-config/plugins/Finale/config.yml +++ b/ansible/files/paper-config/plugins/Finale/config.yml @@ -4,7 +4,7 @@ alterAttack: speed: 1024 #CombatTag player on login? ctpOnLogin: true - + cleanerCombat: maxReach: 6.0 cps: @@ -65,7 +65,7 @@ cleanerCombat: x: 10.0 y: 10.0 z: 10.0 - + # gives full control over health / regen, default is full reversion to 1.8 mechanics foodHealthRegen: enabled: true @@ -87,20 +87,21 @@ pearls: useActionBar: true #Combat tag using CTP when pearling? combatTag: true -#Whether to set the vanilla cooldown (gray overlay) for players upon pearling. This will keep them from pearling client side, +#Whether to set the vanilla cooldown (gray overlay) for players upon pearling. This will keep them from pearling client side, #but they wont be able to see a cooldown in chat anymore and sometimes it's a bit laggy setVanillaCooldown: false - + #Config same as above, except with only enabled and cooldown as options gappleCooldown: enabled: true cooldown: 16s - + #allows adjusting the attack damage of any item by its spigot material identifier weaponModification: netheriteAxe: material: NETHERITE_AXE damage: 6 + armourDamageMultiplier: 2 diamondAxe: material: DIAMOND_AXE damage: 5 @@ -134,7 +135,11 @@ weaponModification: woodSword: material: WOODEN_SWORD damage: 3 - + meteoricIronSword: + key: meteoric_iron_sword + damage: 7 + bonusDamagePerNetheritePiece: 0.75 + armourModification: diamondHelmet: material: DIAMOND_HELMET @@ -180,6 +185,26 @@ armourModification: toughness: 3 extraDurabilityHits: 1 knockbackResistance: 0 + meteoricIronHelmet: + key: meteoric_iron_helmet + armour: 3 + toughness: 2 + extraDurabilityHits: 1 + meteoricIronChestplate: + key: meteoric_iron_chestplate + armour: 8 + toughness: 2 + extraDurabilityHits: 1 + meteoricIronLeggings: + key: meteoric_iron_leggings + armour: 6 + toughness: 2 + extraDurabilityHits: 1 + meteoricIronBoots: + key: meteoric_iron_boots + armour: 3 + toughness: 2 + extraDurabilityHits: 1 #allows disabling enchantments. Use official spigot identifiers from https://hub.spigotmc.org/javadocs/spigot/org/bukkit/enchantments/Enchantment.html #This will not remove them from enchanting, but simply remove the enchant as soon as the item is touched @@ -187,19 +212,19 @@ disabledEnchantments: - MENDING - FROST_WALKER - RIPTIDE - + potions: -#Allows applying a multiplier to the intensity of potions. Intensities <= 1.0 will always work fine, but intensities > 1 +#Allows applying a multiplier to the intensity of potions. Intensities <= 1.0 will always work fine, but intensities > 1 #may lead to unintended results for instant effects like INSTANT_HEALTH. #All entries may have the following entries: # type: # A potion type (https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/potion/PotionType.html) # upgraded: -# Boolean to specify whether the pot is upgraded (tier 2) +# Boolean to specify whether the pot is upgraded (tier 2) # extended: # Boolean to specify whether the pot is extended # splash: -# Boolean to specify whether the pot is splash +# Boolean to specify whether the pot is splash # multiplier: # Double value, the multiplier applied to the duration. May not be negative and defaults to 1.0 @@ -230,10 +255,10 @@ potions: healthMultiplier: 1.5 minIntensityCutOff: 0.3 # minimum intensity for non-thrower to steal some health effect. minIntensityImpact: 0.5 # minimum intensity for thrower to get full health effect. - + velocity: -#In newer Minecraft versions when a player launches a projectile the players velocity will be added to the projectiles base velocity. This can lead to -#weird behavior sometimes and reverted with this setting. Add entity types (https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/EntityType.html) +#In newer Minecraft versions when a player launches a projectile the players velocity will be added to the projectiles base velocity. This can lead to +#weird behavior sometimes and reverted with this setting. Add entity types (https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/EntityType.html) #of projectiles to the list to revert their behavior regarding initial velocity to 1.7 ENDER_PEARL: type: REVERTED @@ -244,7 +269,7 @@ velocity: vertical: 0.4 horizontal: 0.4 pitchOffset: -20 - + #This option allows modifying the damage dealt by/to players based on certain properties. All entries look like this: # SWORD: @@ -259,8 +284,8 @@ velocity: #The order in which modifiers are applied is: ALL, ARROW, POWER_ENCHANT, STRENGTH_EFFECT, SWORD, SHARPNESS_ENCHANT, CRIT #Note that these effects are applied after vanilla damage additions and before vanilla damage reductions -damageModifiers: -#Decrease all damage by 20 % +damageModifiers: +#Decrease all damage by 20 % ALL: multiplier: 0.8 mode: DIRECT @@ -277,7 +302,7 @@ damageModifiers: STRENGTH_EFFECT: mode: DIRECT multiplier: 1.0 - + invulTicksEnabled: false #disabled because currently it messes up invulnerability with other damage types invulnerableTicks: FIRE: 10 @@ -286,3 +311,5 @@ invulnerableTicks: PROJECTILE: 1 DROWNING: 1 ENTITY_ATTACK: 9 + +netheriteFireResistance: true diff --git a/ansible/files/paper-config/plugins/Heliodor/config.yml b/ansible/files/paper-config/plugins/Heliodor/config.yml new file mode 100644 index 000000000..f915fe151 --- /dev/null +++ b/ansible/files/paper-config/plugins/Heliodor/config.yml @@ -0,0 +1,11 @@ +database: + ==: vg.civcraft.mc.civmodcore.dao.DatabaseCredentials + user: ${CIV_MYSQL_USERNAME} + password: ${CIV_MYSQL_PASSWORD} + host: ${CIV_MYSQL_HOST} + port: 3306 + database: heliodor + poolsize: 5 + connection_timeout: 10000 + idle_timeout: 600000 + max_lifetime: 7200000 diff --git a/ansible/files/paper-config/plugins/SimpleAdminHacks/config.yml b/ansible/files/paper-config/plugins/SimpleAdminHacks/config.yml index f6410731e..6c8fccd31 100644 --- a/ansible/files/paper-config/plugins/SimpleAdminHacks/config.yml +++ b/ansible/files/paper-config/plugins/SimpleAdminHacks/config.yml @@ -19,6 +19,10 @@ hacks: ArmourBound: enabled: true whitelist: + - IRON_HELMET + - IRON_CHESTPLATE + - IRON_LEGGINGS + - IRON_BOOTS - DIAMOND_HELMET - DIAMOND_CHESTPLATE - DIAMOND_LEGGINGS @@ -372,7 +376,7 @@ hacks: patrolSpawning: true phantomSpawning: false enderChestPlacement: true - enderChestUse: false + enderChestUse: true grindstoneUse: false shulkerBoxUse: false totemPower: true diff --git a/ansible/src/paper-plugins/worldedit-bukkit-7.3.6.jar b/ansible/src/paper-plugins/worldedit-bukkit-7.3.8.jar similarity index 83% rename from ansible/src/paper-plugins/worldedit-bukkit-7.3.6.jar rename to ansible/src/paper-plugins/worldedit-bukkit-7.3.8.jar index fc3ce8568..be4f345c6 100644 Binary files a/ansible/src/paper-plugins/worldedit-bukkit-7.3.6.jar and b/ansible/src/paper-plugins/worldedit-bukkit-7.3.8.jar differ diff --git a/plugins/civmodcore-paper/src/main/java/vg/civcraft/mc/civmodcore/config/ConfigHelper.java b/plugins/civmodcore-paper/src/main/java/vg/civcraft/mc/civmodcore/config/ConfigHelper.java index 3ddefd85c..32d77a60b 100644 --- a/plugins/civmodcore-paper/src/main/java/vg/civcraft/mc/civmodcore/config/ConfigHelper.java +++ b/plugins/civmodcore-paper/src/main/java/vg/civcraft/mc/civmodcore/config/ConfigHelper.java @@ -19,6 +19,8 @@ import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import vg.civcraft.mc.civmodcore.CivModCorePlugin; +import vg.civcraft.mc.civmodcore.inventory.CustomItem; import vg.civcraft.mc.civmodcore.inventory.items.EnchantUtils; import vg.civcraft.mc.civmodcore.inventory.items.ItemMap; import vg.civcraft.mc.civmodcore.inventory.items.MaterialUtils; @@ -122,7 +124,19 @@ public final class ConfigHelper { } for (final String key : config.getKeys(false)) { ItemMap partMap = new ItemMap(); - partMap.addItemStack(config.getItemStack(key, ItemStack.empty())); + ConfigurationSection section = config.getConfigurationSection(key); + String custom = section == null ? null : section.getString("custom-key"); + if (custom != null) { + ItemStack item = CustomItem.getCustomItem(custom); + if (item == null) { + throw new IllegalArgumentException("Unknown custom item key " + custom); + } else { + int amount = section.getInt("amount", 1); + partMap.addItemAmount(item, amount); + } + } else { + partMap.addItemStack(config.getItemStack(key, ItemStack.empty())); + } result.merge(partMap); } return result; diff --git a/plugins/civmodcore-paper/src/main/java/vg/civcraft/mc/civmodcore/inventory/CustomItem.java b/plugins/civmodcore-paper/src/main/java/vg/civcraft/mc/civmodcore/inventory/CustomItem.java new file mode 100644 index 000000000..1cd3fff6b --- /dev/null +++ b/plugins/civmodcore-paper/src/main/java/vg/civcraft/mc/civmodcore/inventory/CustomItem.java @@ -0,0 +1,50 @@ +package vg.civcraft.mc.civmodcore.inventory; + +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.java.JavaPlugin; +import vg.civcraft.mc.civmodcore.CivModCorePlugin; +import java.util.HashMap; +import java.util.Map; + +public class CustomItem { + + public static NamespacedKey CUSTOM_ITEM = new NamespacedKey(JavaPlugin.getPlugin(CivModCorePlugin.class), "custom_item"); + + private static final Map customItems = new HashMap<>(); + + public static void registerCustomItem(String key, ItemStack item) { + if (item == null || item.isEmpty()) { + return; + } + ItemMeta meta = item.getItemMeta(); + meta.getPersistentDataContainer().set(CUSTOM_ITEM, PersistentDataType.STRING, key); + item.setItemMeta(meta); + if (!customItems.containsKey(key)) { + customItems.put(key, item.clone()); + } + } + + public static ItemStack getCustomItem(String key) { + ItemStack itemStack = customItems.get(key); + return itemStack == null ? null : itemStack.clone(); + } + + public static boolean isCustomItem(ItemStack item) { + return item != null && !item.isEmpty() && item.getPersistentDataContainer().has(CUSTOM_ITEM); + } + + public static boolean isCustomItem(ItemStack item, String key) { + return item != null && !item.isEmpty() && key.equals(item.getPersistentDataContainer().get(CUSTOM_ITEM, PersistentDataType.STRING)); + } + + public static String getCustomItemKey(ItemStack item) { + if (isCustomItem(item)) { + return item.getPersistentDataContainer().get(CUSTOM_ITEM, PersistentDataType.STRING); + } else { + return null; + } + } +} diff --git a/plugins/civmodcore-paper/src/main/java/vg/civcraft/mc/civmodcore/inventory/items/ItemMap.java b/plugins/civmodcore-paper/src/main/java/vg/civcraft/mc/civmodcore/inventory/items/ItemMap.java index 85ee1d87f..fc9589929 100644 --- a/plugins/civmodcore-paper/src/main/java/vg/civcraft/mc/civmodcore/inventory/items/ItemMap.java +++ b/plugins/civmodcore-paper/src/main/java/vg/civcraft/mc/civmodcore/inventory/items/ItemMap.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.inventory.items; +import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import java.util.ArrayList; @@ -10,13 +11,18 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; +import java.util.function.BiFunction; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import it.unimi.dsi.fastutil.objects.ObjectSet; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.keyvalue.UnmodifiableMapEntry; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import vg.civcraft.mc.civmodcore.inventory.CustomItem; /** * Allows the storage and comparison of item stacks while ignoring their maximum possible stack sizes. This offers @@ -37,6 +43,7 @@ import org.bukkit.inventory.PlayerInventory; public class ItemMap { private final Object2IntMap items; + private final Object2IntOpenHashMap customItems; private int totalItems; /** @@ -45,6 +52,8 @@ public class ItemMap { public ItemMap() { this.items = new Object2IntOpenHashMap<>(0); this.items.defaultReturnValue(0); + this.customItems = new Object2IntOpenHashMap<>(); + this.customItems.defaultReturnValue(0); this.totalItems = 0; } @@ -56,6 +65,8 @@ public class ItemMap { public ItemMap(final ItemStack item) { this.items = new Object2IntOpenHashMap<>(1); this.items.defaultReturnValue(0); + this.customItems = new Object2IntOpenHashMap<>(); + this.customItems.defaultReturnValue(0); this.totalItems = 0; addItemStack(item); } @@ -68,6 +79,8 @@ public class ItemMap { public ItemMap(final Collection stacks) { this.items = new Object2IntOpenHashMap<>(stacks.size()); this.items.defaultReturnValue(0); + this.customItems = new Object2IntOpenHashMap<>(); + this.customItems.defaultReturnValue(0); addAll(stacks); } @@ -80,6 +93,8 @@ public class ItemMap { public ItemMap(final Inventory inventory) { this.items = new Object2IntOpenHashMap<>(inventory.getSize()); this.items.defaultReturnValue(0); + this.customItems = new Object2IntOpenHashMap<>(); + this.customItems.defaultReturnValue(0); this.totalItems = 0; update(inventory); } @@ -99,8 +114,14 @@ public class ItemMap { if (!ItemUtils.isValidItemIgnoringAmount(input)) { return; } - this.items.computeInt(INTERNAL_createKey(input), (key, amount) -> - amount == null ? input.getAmount() : amount + input.getAmount()); + BiFunction addFn = (key, amount) -> + amount == null ? input.getAmount() : amount + input.getAmount(); + String customItemKey = CustomItem.getCustomItemKey(input); + if (customItemKey != null) { + this.customItems.computeInt(customItemKey, addFn); + } else { + this.items.computeInt(INTERNAL_createKey(input), addFn); + } this.totalItems += input.getAmount(); } @@ -130,7 +151,13 @@ public class ItemMap { if (key == null) { return; } - this.items.computeIntIfPresent(key, (_key, amount) -> (amount -= input.getAmount()) <= 0 ? null : amount); + BiFunction subFun = (_key, amount) -> (amount -= input.getAmount()) <= 0 ? null : amount; + String customItemKey = CustomItem.getCustomItemKey(input); + if (customItemKey != null) { + this.customItems.computeIntIfPresent(customItemKey, subFun); + } else { + this.items.computeIntIfPresent(key, subFun); + } } /** @@ -147,7 +174,7 @@ public class ItemMap { @Override public int hashCode() { - return this.items.hashCode(); + return Objects.hash(this.items.hashCode(), this.customItems.hashCode()); } /** @@ -169,13 +196,17 @@ public class ItemMap { * @param im ItemMap to merge */ public void merge(ItemMap im) { - for (Entry entry : im.getEntrySet()) { + for (Entry entry : im.items.object2IntEntrySet()) { addItemAmount(entry.getKey(), entry.getValue()); } + for (Entry entry : im.customItems.object2IntEntrySet()) { + addItemAmount(CustomItem.getCustomItem(entry.getKey()), entry.getValue()); + } } public void update(final Inventory inventory) { this.items.clear(); + this.customItems.clear(); this.totalItems = 0; for (int i = 0; i < inventory.getSize(); i++) { final ItemStack item = inventory.getItem(i); @@ -185,12 +216,6 @@ public class ItemMap { } } - public void addEntrySet(Set> entries) { - for (Entry entry : entries) { - addItemAmount(entry.getKey(), entry.getValue()); - } - } - /** * Utility method, which has the amount of items to add as parameter. * @@ -221,6 +246,12 @@ public class ItemMap { result.addItemAmount(is.clone(), items.get(is)); } } + for (String is : customItems.keySet()) { + ItemStack item = CustomItem.getCustomItem(is); + if (item.getType() == m) { + result.addItemAmount(item, customItems.get(is)); + } + } return result; } @@ -229,58 +260,6 @@ public class ItemMap { } /** - * Gets a submap of this instance which contains all stacks with the same material and enchants as the given one - * and their respective amounts. - * - * @param m Material to search for - * @param enchants Enchants to search for - * @return New ItemMap with all ItemStack and their amount whose material and enchants matches the given one - */ - public ItemMap getStacksByMaterialEnchants(Material m, Map enchants) { - ItemMap result = new ItemMap(); - for (ItemStack is : items.keySet()) { - if (is.getType() == m && is.getItemMeta() != null && is.getItemMeta().getEnchants().equals(enchants)) { - result.addItemAmount(is.clone(), items.get(is)); - } - } - return result; - } - - public ItemMap getStacksByMaterialEnchants(ItemStack is) { - if (is.getItemMeta() != null) { - return getStacksByMaterialEnchants(is.getType(), is.getItemMeta().getEnchants()); - } else { - return getStacksByMaterialEnchants(is.getType(), new HashMap<>()); - } - } - - /** - * Gets a submap of this instance which contains all stacks with the same lore as the given and their respective - * amount. - * - * @param lore Lore to search for - * @return New ItemMap with all ItemStacks and their amount whose lore matches the given one - */ - public ItemMap getStacksByLore(final List lore) { - final boolean gaveLore = CollectionUtils.isNotEmpty(lore); - final ItemMap result = new ItemMap(); - for (final ItemStack key : this.items.keySet()) { - if (!key.hasItemMeta()) { - continue; - } - final var keyMeta = key.getItemMeta(); - if (gaveLore != keyMeta.hasLore()) { - continue; - } - final var keyLore = keyMeta.getLore(); - if (!Objects.equals(lore, keyLore)) { - continue; - } - result.addItemAmount(key.clone(), this.items.getInt(key)); - } - return result; - } - /** * Gets how many items of the given stack are in this map. Be aware that if a stack doesnt equal with the given one, * for example because of mismatched NBT tags, it wont be included in the result @@ -291,12 +270,17 @@ public class ItemMap { public int getAmount(ItemStack is) { ItemMap matSubMap = getStacksByMaterial(is); int amount = 0; - for (Entry entry : matSubMap.getEntrySet()) { + for (Entry entry : matSubMap.items.object2IntEntrySet()) { ItemStack current = entry.getKey(); if (MetaUtils.areMetasEqual(is.getItemMeta(), current.getItemMeta())) { amount += entry.getValue(); } } + for (Entry entry : matSubMap.customItems.object2IntEntrySet()) { + if (entry.getKey().equals(CustomItem.getCustomItemKey(is))) { + amount += entry.getValue(); + } + } return amount; } @@ -311,12 +295,23 @@ public class ItemMap { * @return How many unique items are stored in this map */ public int getTotalUniqueItemAmount() { - return items.keySet().size(); + return items.keySet().size() + customItems.keySet().size(); } - @SuppressWarnings("deprecation") - public Set> getEntrySet() { - return this.items.entrySet(); + public Map getAllItems() { + Object2IntOpenHashMap map = new Object2IntOpenHashMap<>(this.items); + for (Object2IntMap.Entry entry : this.customItems.object2IntEntrySet()) { + map.put(CustomItem.getCustomItem(entry.getKey()), entry.getIntValue()); + } + return map; + } + + public Object2IntMap getItems() { + return items; + } + + public Object2IntOpenHashMap getCustomItems() { + return customItems; } /** @@ -327,7 +322,7 @@ public class ItemMap { */ public boolean containedExactlyIn(Inventory i) { ItemMap invMap = new ItemMap(i); - for (Entry entry : getEntrySet()) { + for (Entry entry : getAllItems().entrySet()) { if (!entry.getValue().equals(invMap.getAmount(entry.getKey()))) { return false; } @@ -353,7 +348,7 @@ public class ItemMap { */ public boolean isContainedIn(Inventory i) { ItemMap invMap = new ItemMap(i); - for (Entry entry : getEntrySet()) { + for (Entry entry : getAllItems().entrySet()) { if (entry.getValue() > invMap.getAmount(entry.getKey())) { return false; } @@ -380,7 +375,7 @@ public class ItemMap { public int getMultiplesContainedIn(Inventory i) { ItemMap invMap = new ItemMap(i); int res = Integer.MAX_VALUE; - for (Entry entry : getEntrySet()) { + for (Entry entry : getAllItems().entrySet()) { int pulledAmount = invMap.getAmount(entry.getKey()); int multiples = pulledAmount / entry.getValue(); res = Math.min(res, multiples); @@ -395,10 +390,14 @@ public class ItemMap { */ public void multiplyContent(double multiplier) { totalItems = 0; - for (Entry entry : getEntrySet()) { + for (Entry entry : this.items.object2IntEntrySet()) { items.put(entry.getKey(), (int) (entry.getValue() * multiplier)); totalItems += (int) (entry.getValue() * multiplier); } + for (Entry entry : this.customItems.object2IntEntrySet()) { + customItems.put(entry.getKey(), (int) (entry.getValue() * multiplier)); + totalItems += (int) (entry.getValue() * multiplier); + } } /** @@ -409,7 +408,7 @@ public class ItemMap { */ public List getItemStackRepresentation() { List result = new ArrayList<>(); - for (Entry entry : getEntrySet()) { + for (Entry entry : getAllItems().entrySet()) { ItemStack is = entry.getKey(); Integer amount = entry.getValue(); while (amount != 0) { @@ -429,7 +428,7 @@ public class ItemMap { @Override public ItemMap clone() { ItemMap clone = new ItemMap(); - for (Entry entry : getEntrySet()) { + for (Entry entry : this.getAllItems().entrySet()) { clone.addItemAmount(entry.getKey(), entry.getValue()); } return clone; @@ -465,7 +464,7 @@ public class ItemMap { * @return UI representation of large ItemMap */ public List getLoredItemCountRepresentation() { - Set> entrySet = getEntrySet(); + Set> entrySet = getAllItems().entrySet(); List items = new ArrayList<>(entrySet.size()); for (Entry entry : entrySet) { ItemStack is = entry.getKey().clone(); @@ -496,7 +495,7 @@ public class ItemMap { * @return True if everything was successfully removed, false if not */ public boolean removeSafelyFrom(Inventory i) { - for (Entry entry : getEntrySet()) { + for (Entry entry : getAllItems().entrySet()) { int amountToRemove = entry.getValue(); ItemStack is = entry.getKey(); for (ItemStack inventoryStack : i.getStorageContents()) { @@ -551,7 +550,7 @@ public class ItemMap { public boolean equals(Object o) { if (o instanceof ItemMap im) { if (im.getTotalItemAmount() == getTotalItemAmount()) { - return im.getEntrySet().equals(getEntrySet()); + return im.items.equals(items) && im.customItems.equals(customItems); } } return false; diff --git a/plugins/donum-paper/src/main/java/com/github/civcraft/donum/DonumManager.java b/plugins/donum-paper/src/main/java/com/github/civcraft/donum/DonumManager.java index 57fbd129b..28448024a 100644 --- a/plugins/donum-paper/src/main/java/com/github/civcraft/donum/DonumManager.java +++ b/plugins/donum-paper/src/main/java/com/github/civcraft/donum/DonumManager.java @@ -131,7 +131,7 @@ public class DonumManager { Donum.getInstance().debug("Old inventory: " + oldInventory.toString()); Donum.getInstance().debug("New inventory: " + newInventory.toString()); ItemMap diff = new ItemMap(); - for (Entry entry : oldInventory.getEntrySet()) { + for (Entry entry : oldInventory.getAllItems().entrySet()) { ItemStack is = entry.getKey(); int oldAmount = entry.getValue(); int newAmount = newInventory.getAmount(is); diff --git a/plugins/donum-paper/src/main/java/com/github/civcraft/donum/misc/ItemMapBlobHandling.java b/plugins/donum-paper/src/main/java/com/github/civcraft/donum/misc/ItemMapBlobHandling.java index 872ec4061..0e54a17c3 100644 --- a/plugins/donum-paper/src/main/java/com/github/civcraft/donum/misc/ItemMapBlobHandling.java +++ b/plugins/donum-paper/src/main/java/com/github/civcraft/donum/misc/ItemMapBlobHandling.java @@ -34,7 +34,7 @@ public class ItemMapBlobHandling { public static byte[] turnItemMapIntoBlob(ItemMap im) { YamlConfiguration yaml = new YamlConfiguration(); int count = 0; - for (Entry entry : im.getEntrySet()) { + for (Entry entry : im.getAllItems().entrySet()) { ItemStack is = entry.getKey().clone(); is.setAmount(entry.getValue()); //yaml doesnt allow int as keys, so we have to add a string diff --git a/plugins/exilepearl-paper/src/main/java/com/devotedmc/ExilePearl/storage/MySqlStorage.java b/plugins/exilepearl-paper/src/main/java/com/devotedmc/ExilePearl/storage/MySqlStorage.java index fb1fec286..bfbd16013 100644 --- a/plugins/exilepearl-paper/src/main/java/com/devotedmc/ExilePearl/storage/MySqlStorage.java +++ b/plugins/exilepearl-paper/src/main/java/com/devotedmc/ExilePearl/storage/MySqlStorage.java @@ -100,10 +100,7 @@ class MySqlStorage implements PluginStorage { @Override public void disconnect() { isConnected = false; - try { - db.close(); - } catch (SQLException e) { - } + db.close(); } @Override diff --git a/plugins/factorymod-paper/build.gradle.kts b/plugins/factorymod-paper/build.gradle.kts index a3ef69638..cb1e119ae 100644 --- a/plugins/factorymod-paper/build.gradle.kts +++ b/plugins/factorymod-paper/build.gradle.kts @@ -12,4 +12,5 @@ dependencies { compileOnly(project(":plugins:civmodcore-paper")) compileOnly(project(":plugins:namelayer-paper")) compileOnly(project(":plugins:citadel-paper")) + compileOnly(project(":plugins:heliodor-paper")) } diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/ConfigParser.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/ConfigParser.java index ab01eef7f..b87e34425 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/ConfigParser.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/ConfigParser.java @@ -27,12 +27,16 @@ import com.github.igotyou.FactoryMod.recipes.RepairRecipe; import com.github.igotyou.FactoryMod.recipes.Upgraderecipe; import com.github.igotyou.FactoryMod.recipes.WordBankRecipe; import com.github.igotyou.FactoryMod.recipes.scaling.ProductionRecipeModifier; +import com.github.igotyou.FactoryMod.recipes.upgrade.CharcoalConsumptionUpgradeRecipe; +import com.github.igotyou.FactoryMod.recipes.upgrade.ResetUpgradesRecipe; +import com.github.igotyou.FactoryMod.recipes.upgrade.SpeedUpgradeRecipe; import com.github.igotyou.FactoryMod.structures.BlockFurnaceStructure; import com.github.igotyou.FactoryMod.structures.FurnCraftChestStructure; import com.github.igotyou.FactoryMod.structures.PipeStructure; import com.github.igotyou.FactoryMod.utility.FactoryGarbageCollector; import com.github.igotyou.FactoryMod.utility.FactoryModGUI; import org.apache.commons.lang.WordUtils; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.NamespacedKey; @@ -42,6 +46,7 @@ import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.scheduler.BukkitRunnable; import vg.civcraft.mc.civmodcore.config.ConfigHelper; +import vg.civcraft.mc.civmodcore.inventory.CustomItem; import vg.civcraft.mc.civmodcore.inventory.items.ItemMap; import java.io.File; @@ -148,10 +153,11 @@ public class ConfigParser { int maxOutputChests = config.getInt("max_output_chests", 10); int maxFuelChests = config.getInt("max_fuel_chests", 10); int maxTotalIOFChests = config.getInt("max_iof_chests", 15); + boolean canUpgrade = config.getBoolean("can_upgrade", false); manager = new FactoryModManager(plugin, factoryInteractionMaterial, citadelEnabled, nameLayerEnabled, redstonePowerOn, redstoneRecipeChange, logInventories, maxInputChests, maxOutputChests, maxFuelChests, - maxTotalIOFChests, factoryRenames); + maxTotalIOFChests, factoryRenames, canUpgrade); upgradeEggs = new HashMap<>(); recipeLists = new HashMap<>(); recipeScalingUpgradeMapping = new HashMap<>(); @@ -254,6 +260,11 @@ public class ConfigParser { } } } + if (manager.canUpgrade()) { + manager.registerRecipe(new ResetUpgradesRecipe()); + manager.registerRecipe(new CharcoalConsumptionUpgradeRecipe()); + manager.registerRecipe(new SpeedUpgradeRecipe()); + } } /** @@ -904,7 +915,24 @@ public class ConfigParser { } private static ItemStack parseFirstItem(ConfigurationSection config) { - return config == null ? null : config.getItemStack(config.getKeys(false).iterator().next()); + if (config == null) { + return null; + } + String key = config.getKeys(false).iterator().next(); + ConfigurationSection section = config.getConfigurationSection(key); + String custom = section == null ? null : section.getString("custom-key"); + if (custom != null) { + ItemStack item = CustomItem.getCustomItem(custom); + if (item == null) { + throw new IllegalArgumentException("Unknown custom item key " + custom); + } else { + int amount = section.getInt("amount", 1); + item.setAmount(amount); + return item; + } + } else { + return config.getItemStack(key); + } } private Map parseRenames(ConfigurationSection config) { diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/FactoryModManager.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/FactoryModManager.java index 9eb708593..363f67664 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/FactoryModManager.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/FactoryModManager.java @@ -59,11 +59,12 @@ public class FactoryModManager { private Set compactLore; private Set forceInclude; private FactoryModPlayerSettings playerSettings; + private boolean canUpgrade; public FactoryModManager(FactoryMod plugin, Material factoryInteractionMaterial, boolean citadelEnabled, boolean nameLayerEnabled, int redstonePowerOn, int redstoneRecipeChange, boolean logInventories, int maxInputChests, int maxOutputChests, int maxFuelChests, int maxTotalIOFChests, - Map factoryRenames) { + Map factoryRenames, boolean canUpgrade) { this.plugin = plugin; this.factoryInteractionMaterial = factoryInteractionMaterial; this.citadelEnabled = citadelEnabled; @@ -74,6 +75,7 @@ public class FactoryModManager { this.maxFuelChests = maxFuelChests; this.maxTotalIOFChests = maxTotalIOFChests; this.fileHandler = new FileHandler(this, factoryRenames); + this.canUpgrade = canUpgrade; factoryCreationRecipes = new HashMap<>(); locations = new HashMap<>(); @@ -186,6 +188,10 @@ public class FactoryModManager { return factoryInteractionMaterial; } + public boolean canUpgrade() { + return canUpgrade; + } + /** * Removes a factory from the manager * diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/eggs/FurnCraftChestEgg.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/eggs/FurnCraftChestEgg.java index df80ac7ec..ba7e3fa88 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/eggs/FurnCraftChestEgg.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/eggs/FurnCraftChestEgg.java @@ -54,7 +54,7 @@ public class FurnCraftChestEgg implements IFactoryEgg { FurnCraftChestInteractionManager fccim = new FurnCraftChestInteractionManager(); PercentageHealthRepairManager phrm = new PercentageHealthRepairManager(maximumHealth, maximumHealth, 0, healthPerDamagePeriod, breakGracePeriod); FurnCraftChestFactory fccf = new FurnCraftChestFactory(fccim, phrm, - fpm, fccs, updateTime, name, recipes, citadelBreakReduction); + fpm, fccs, updateTime, name, recipes, citadelBreakReduction, 0, 0, 0); fccim.setFactory(fccf); phrm.setFactory(fccf); if (!recipes.isEmpty()) { @@ -106,7 +106,8 @@ public class FurnCraftChestEgg implements IFactoryEgg { } public Factory revive(List blocks, int health, - String selectedRecipe, int productionTimer, long breakTime, List recipeStrings) { + String selectedRecipe, int productionTimer, long breakTime, List recipeStrings, + int charcoalLevel, int speedLevel, int charcoalAbsorbed) { FurnCraftChestStructure fccs = new FurnCraftChestStructure(blocks); FurnacePowerManager fpm = new FurnacePowerManager(fccs.getFurnace(), fuel, fuelConsumptionIntervall); @@ -131,7 +132,7 @@ public class FurnCraftChestEgg implements IFactoryEgg { } } FurnCraftChestFactory fccf = new FurnCraftChestFactory(fccim, phrm, - fpm, fccs, updateTime, name, currRecipes, citadelBreakReduction); + fpm, fccs, updateTime, name, currRecipes, citadelBreakReduction, charcoalLevel, speedLevel, charcoalAbsorbed); fccim.setFactory(fccf); phrm.setFactory(fccf); for (IRecipe recipe : currRecipes) { diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/factories/Factory.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/factories/Factory.java index d5a369bde..cce829c66 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/factories/Factory.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/factories/Factory.java @@ -115,7 +115,7 @@ public abstract class Factory implements Runnable { public void scheduleUpdate() { threadId = FactoryMod.getInstance().getServer().getScheduler() - .scheduleSyncDelayedTask(FactoryMod.getInstance(), this, (long) updateTime); + .scheduleSyncDelayedTask(FactoryMod.getInstance(), this, getUpdateTime()); } public void turnFurnaceOn(Block f) { diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/factories/FurnCraftChestFactory.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/factories/FurnCraftChestFactory.java index 0aaf7c81d..f2e6955dd 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/factories/FurnCraftChestFactory.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/factories/FurnCraftChestFactory.java @@ -64,12 +64,15 @@ public class FurnCraftChestFactory extends Factory implements IIOFInventoryProvi private @Nullable IOSelector furnaceIoSelector; private @Nullable IOSelector tableIoSelector; private UiMenuMode uiMenuMode; + private int charcoalLevel; + private int speedLevel; + private int charcoalAbsorbed; private static HashSet pylonFactories; public FurnCraftChestFactory(IInteractionManager im, IRepairManager rm, IPowerManager ipm, FurnCraftChestStructure mbs, int updateTime, String name, List recipes, - double citadelBreakReduction) { + double citadelBreakReduction, int charcoalLevel, int speedLevel, int charcoalAbsorbed) { super(im, rm, ipm, mbs, updateTime, name); if (ipm instanceof FurnacePowerManager) { ((FurnacePowerManager) ipm).setIofProvider(this); @@ -81,6 +84,9 @@ public class FurnCraftChestFactory extends Factory implements IIOFInventoryProvi this.citadelBreakReduction = citadelBreakReduction; this.autoSelect = false; this.uiMenuMode = UiMenuMode.SIMPLE; + this.charcoalLevel = charcoalLevel; + this.speedLevel = speedLevel; + this.charcoalAbsorbed = charcoalAbsorbed; for (IRecipe rec : recipes) { addRecipe(rec); } @@ -363,11 +369,13 @@ public class FurnCraftChestFactory extends Factory implements IIOFInventoryProvi return; } if (p != null) { - int consumptionIntervall = ((InputRecipe) currentRecipe).getFuelConsumptionIntervall() > 0 ? ((InputRecipe) currentRecipe) - .getFuelConsumptionIntervall() : pm.getPowerConsumptionIntervall(); - if (((FurnacePowerManager) pm).getFuelAmountAvailable() < (currentRecipe.getProductionTime() / consumptionIntervall)) { - p.sendMessage(ChatColor.RED - + "You don't have enough fuel, the factory will run out of it before completing"); + if (currentRecipe instanceof InputRecipe) { + int consumptionIntervall = ((InputRecipe) currentRecipe).getFuelConsumptionIntervall() > 0 ? ((InputRecipe) currentRecipe) + .getFuelConsumptionIntervall() : pm.getPowerConsumptionIntervall(); + if (((FurnacePowerManager) pm).getFuelAmountAvailable() < (currentRecipe.getProductionTime() / consumptionIntervall)) { + p.sendMessage(ChatColor.RED + + "You don't have enough fuel, the factory will run out of it before completing"); + } } p.sendMessage(ChatColor.GREEN + "Activated " + name + " with recipe: " + currentRecipe.getName()); activator = p.getUniqueId(); @@ -472,9 +480,14 @@ public class FurnCraftChestFactory extends Factory implements IIOFInventoryProvi // if the factory has been working for less than the required // time for the recipe if (currentProductionTimer < currentRecipe.getProductionTime()) { - int consumptionIntervall = ((InputRecipe) currentRecipe).getFuelConsumptionIntervall() > 0 - ? ((InputRecipe) currentRecipe).getFuelConsumptionIntervall() - : pm.getPowerConsumptionIntervall(); + int consumptionIntervall; + if (currentRecipe instanceof InputRecipe) { + consumptionIntervall = ((InputRecipe) currentRecipe).getFuelConsumptionIntervall() > 0 + ? ((InputRecipe) currentRecipe).getFuelConsumptionIntervall() + : pm.getPowerConsumptionIntervall(); + } else { + consumptionIntervall = Integer.MAX_VALUE; + } int powerCounter = pm.getPowerCounter() + updateTime; int fuelCount = powerCounter / consumptionIntervall; @@ -488,7 +501,20 @@ public class FurnCraftChestFactory extends Factory implements IIOFInventoryProvi // if we need to consume fuel - then do it if (fuelCount >= 1) { // remove fuel. - pm.consumePower(fuelCount); + int maxCharcoalAbsorbed = (((FurnacePowerManager) getPowerManager()).getFuel().getType() != Material.CHARCOAL) ? 1 : switch (charcoalLevel) { + case 0 -> 1; + case 1 -> 4; + case 2 -> 8; + case 3 -> 12; + case 4 -> 16; + default -> throw new IllegalStateException("charcoalLevel " + charcoalLevel); + }; + if (charcoalAbsorbed + 1 >= maxCharcoalAbsorbed) { + pm.consumePower(fuelCount); + charcoalAbsorbed = 0; + } else { + charcoalAbsorbed++; + } // update power counter to remained time pm.setPowerCounter(powerCounter % consumptionIntervall); } @@ -513,16 +539,18 @@ public class FurnCraftChestFactory extends Factory implements IIOFInventoryProvi // time remove input from chest, and add output material else { LoggingUtils.log("Executing recipe " + currentRecipe.getName() + " for " + getLogData()); - RecipeExecuteEvent ree = new RecipeExecuteEvent(this, (InputRecipe) currentRecipe); - Bukkit.getPluginManager().callEvent(ree); - if (ree.isCancelled()) { - LoggingUtils.log("Executing recipe " + currentRecipe.getName() + " for " + getLogData() - + " was cancelled over the event"); - deactivate(); - return; + if (currentRecipe instanceof InputRecipe) { + RecipeExecuteEvent ree = new RecipeExecuteEvent(this, (InputRecipe) currentRecipe); + Bukkit.getPluginManager().callEvent(ree); + if (ree.isCancelled()) { + LoggingUtils.log("Executing recipe " + currentRecipe.getName() + " for " + getLogData() + + " was cancelled over the event"); + deactivate(); + return; + } } sendActivatorMessage(ChatColor.GOLD + currentRecipe.getName() + " in " + name + " completed"); - if (currentRecipe instanceof Upgraderecipe || currentRecipe instanceof RecipeScalingUpgradeRecipe) { + if (currentRecipe instanceof Upgraderecipe || currentRecipe instanceof RecipeScalingUpgradeRecipe || !(currentRecipe instanceof InputRecipe)) { // this if else might look a bit weird, but because // upgrading changes the current recipe and a lot of // other stuff, this is needed @@ -619,6 +647,10 @@ public class FurnCraftChestFactory extends Factory implements IIOFInventoryProvi } } + public void setRecipeForce(IRecipe pr) { + currentRecipe = pr; + } + public int getRunCount(IRecipe r) { return runCount.get(r); } @@ -752,6 +784,38 @@ public class FurnCraftChestFactory extends Factory implements IIOFInventoryProvi return citadelBreakReduction; } + public void setCharcoalLevel(int charcoalLevel) { + this.charcoalLevel = charcoalLevel; + } + + public int getCharcoalLevel() { + return charcoalLevel; + } + + public int getSpeedLevel() { + return speedLevel; + } + + public void setSpeedLevel(int speedLevel) { + this.speedLevel = speedLevel; + } + + @Override + public int getUpdateTime() { + return switch (speedLevel) { + case 0 -> updateTime; + case 1 -> Math.ceilDiv(updateTime, 2); + case 2 -> Math.ceilDiv(updateTime, 3); + case 3 -> Math.ceilDiv(updateTime, 4); + case 4 -> Math.ceilDiv(updateTime, 5); + default -> throw new IllegalStateException("speedLevel " + speedLevel); + }; + } + + public int getCharcoalAbsorbed() { + return charcoalAbsorbed; + } + public enum UiMenuMode { SIMPLE(Material.PAPER, "Show simple menu"), IOCONFIG(Material.HOPPER, "Show IO config menu"); diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/interactionManager/FurnCraftChestInteractionManager.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/interactionManager/FurnCraftChestInteractionManager.java index b08df90cc..cacd8c84a 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/interactionManager/FurnCraftChestInteractionManager.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/interactionManager/FurnCraftChestInteractionManager.java @@ -3,9 +3,13 @@ package com.github.igotyou.FactoryMod.interactionManager; import com.github.igotyou.FactoryMod.FactoryMod; import com.github.igotyou.FactoryMod.eggs.FurnCraftChestEgg; import com.github.igotyou.FactoryMod.factories.FurnCraftChestFactory; +import com.github.igotyou.FactoryMod.powerManager.FurnacePowerManager; import com.github.igotyou.FactoryMod.recipes.IRecipe; import com.github.igotyou.FactoryMod.recipes.InputRecipe; import com.github.igotyou.FactoryMod.recipes.ProductionRecipe; +import com.github.igotyou.FactoryMod.recipes.upgrade.CharcoalConsumptionUpgradeRecipe; +import com.github.igotyou.FactoryMod.recipes.upgrade.ResetUpgradesRecipe; +import com.github.igotyou.FactoryMod.recipes.upgrade.SpeedUpgradeRecipe; import com.github.igotyou.FactoryMod.repairManager.PercentageHealthRepairManager; import com.github.igotyou.FactoryMod.structures.FurnCraftChestStructure; import com.github.igotyou.FactoryMod.structures.MultiBlockStructure; @@ -15,6 +19,8 @@ import java.text.DecimalFormat; import java.util.ArrayList; import java.util.List; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.block.Block; @@ -23,6 +29,7 @@ import org.bukkit.block.Furnace; import org.bukkit.entity.Player; import org.bukkit.event.block.BlockRedstoneEvent; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; import vg.civcraft.mc.citadel.ReinforcementLogic; import vg.civcraft.mc.citadel.model.Reinforcement; import vg.civcraft.mc.civmodcore.inventory.gui.Clickable; @@ -103,7 +110,7 @@ public class FurnCraftChestInteractionManager implements IInteractionManager { } } if (b.equals(((FurnCraftChestStructure) fccf.getMultiBlockStructure()).getChest())) { // chest interaction - if (p.isSneaking()) { // sneaking, so showing detailed recipe stuff + if (p.isSneaking() && fccf.getCurrentRecipe() instanceof InputRecipe) { // sneaking, so showing detailed recipe stuff ClickableInventory ci = new ClickableInventory(54, fccf.getCurrentRecipe().getName()); int index = 4; List inp = ((InputRecipe) fccf.getCurrentRecipe()) @@ -214,10 +221,14 @@ public class FurnCraftChestInteractionManager implements IInteractionManager { private ComponableInventory buildRecipeInventory(Player p) { ComponableInventory compInv = new ComponableInventory("Select a recipe", 6, p); + boolean upgrades = FactoryMod.getInstance().getManager().canUpgrade(); + Clickable resetUpgrades = upgrades ? buildResetUpgrades() : null; + Clickable upgradeSpeed = upgrades ? buildUpgradeSpeed() : null; + Clickable upgradeCharcoalConsumption = upgrades ? buildUpgradeCharcoalConsumption() : null; Clickable autoClick = buildAutoSelectToggle(); Clickable menuC = buildMenuClickable(); Clickable menuModeButton = buildMenuModeCycleButton(p); - Clickable[] buddons = new Clickable[]{autoClick, menuC, menuModeButton}; + Clickable[] buddons = new Clickable[]{resetUpgrades, upgradeSpeed, upgradeCharcoalConsumption, autoClick, menuC, menuModeButton}; StaticDisplaySection lowerSection = new StaticDisplaySection(buddons); Block fblock = fccf.getFurnace(); @@ -252,7 +263,7 @@ public class FurnCraftChestInteractionManager implements IInteractionManager { default: { Scrollbar recipeScroller = buildRecipeScrollbar(5); compInv.addComponent(recipeScroller, SlotPredicates.offsetRectangle(5, 9, 0, 0)); - compInv.addComponent(lowerSection, SlotPredicates.offsetRectangle(1, 3, 5, 6)); + compInv.addComponent(lowerSection, SlotPredicates.offsetRectangle(1, 6, 5, 3)); } } return compInv; @@ -299,6 +310,125 @@ public class FurnCraftChestInteractionManager implements IInteractionManager { return recipeScroller; } + private static final String[] CHARCOAL_STAGES = new String[] { "1", "1/4", "1/8", "1/12", "1/16"}; + + private Clickable buildUpgradeCharcoalConsumption() { + ItemStack upgradeCharcoal = new ItemStack(Material.REDSTONE_TORCH); + ItemMeta meta = upgradeCharcoal.getItemMeta(); + meta.displayName(Component.text("Upgrade charcoal consumption")); + if (fccf.getSpeedLevel() > 0) { + meta.lore(List.of(Component.text("Cannot be upgraded", NamedTextColor.RED).decoration(TextDecoration.ITALIC, false))); + } else if (fccf.getCharcoalLevel() == CHARCOAL_STAGES.length - 1) { + meta.lore(List.of(Component.empty().decoration(TextDecoration.ITALIC, false) + .append(Component.text(CHARCOAL_STAGES[fccf.getCharcoalLevel()], NamedTextColor.YELLOW)) + .append(Component.text(" Max level!", NamedTextColor.GOLD)))); + } else if (((FurnacePowerManager) fccf.getPowerManager()).getFuel().getType() != Material.CHARCOAL) { + meta.lore(List.of(Component.text("This factory does not use charcoal", NamedTextColor.GOLD).decoration(TextDecoration.ITALIC, false))); + } else { + meta.lore(List.of( + Component.empty().decoration(TextDecoration.ITALIC, false) + .append(Component.text(CHARCOAL_STAGES[fccf.getCharcoalLevel()], NamedTextColor.YELLOW)) + .append(Component.text(" -> ", NamedTextColor.GOLD)) + .append(Component.text(CHARCOAL_STAGES[fccf.getCharcoalLevel() + 1], NamedTextColor.YELLOW)), + Component.text("Requires 1 Factory Upgrade", NamedTextColor.AQUA).decoration(TextDecoration.ITALIC, false), + Component.text("Mutually exclusive with speed upgrade", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC, false), + Component.text("Not refundable", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC, false) + )); + } + meta.setEnchantmentGlintOverride(true); + upgradeCharcoal.setItemMeta(meta); + + return new Clickable(upgradeCharcoal) { + @Override + protected void clicked(Player p) { + if (fccf.getCharcoalLevel() == CHARCOAL_STAGES.length - 1 || fccf.getSpeedLevel() > 0 || ((FurnacePowerManager) fccf.getPowerManager()).getFuel().getType() != Material.CHARCOAL) { + return; + } + + if (fccf.isActive()) { + p.sendMessage(Component.text("You can't switch recipes while the factory is running", NamedTextColor.RED)); + } else { + fccf.setRecipeForce(FactoryMod.getInstance().getManager().getRecipe(CharcoalConsumptionUpgradeRecipe.IDENTIFIER)); + p.sendMessage(ChatColor.GREEN + "Switched recipe to " + fccf.getCurrentRecipe().getName()); + } + } + }; + } + + private static final String[] SPEED_STAGES = new String[] { "x1", "x2", "x3", "x4", "x5"}; + + private Clickable buildUpgradeSpeed() { + ItemStack upgradeSpeed = new ItemStack(Material.SOUL_TORCH); + ItemMeta meta = upgradeSpeed.getItemMeta(); + meta.displayName(Component.text("Upgrade speed")); + if (fccf.getCharcoalLevel() > 0) { + meta.lore(List.of(Component.text("Cannot be upgraded", NamedTextColor.RED).decoration(TextDecoration.ITALIC, false))); + } else if (fccf.getSpeedLevel() == SPEED_STAGES.length - 1) { + meta.lore(List.of(Component.empty().decoration(TextDecoration.ITALIC, false) + .append(Component.text(SPEED_STAGES[fccf.getSpeedLevel()], NamedTextColor.YELLOW)) + .append(Component.text(" Max level!", NamedTextColor.GOLD)))); + } else { + meta.lore(List.of( + Component.empty().decoration(TextDecoration.ITALIC, false) + .append(Component.text(SPEED_STAGES[fccf.getSpeedLevel()], NamedTextColor.YELLOW)) + .append(Component.text(" -> ", NamedTextColor.GOLD)) + .append(Component.text(SPEED_STAGES[fccf.getSpeedLevel() + 1], NamedTextColor.YELLOW)), + Component.text("Requires 1 Factory Upgrade", NamedTextColor.AQUA).decoration(TextDecoration.ITALIC, false), + Component.text("Mutually exclusive with charcoal upgrade", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC, false), + Component.text("Not refundable", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC, false) + )); + } + meta.setEnchantmentGlintOverride(true); + upgradeSpeed.setItemMeta(meta); + + return new Clickable(upgradeSpeed) { + @Override + protected void clicked(Player p) { + if (fccf.getSpeedLevel() == SPEED_STAGES.length - 1 || fccf.getCharcoalLevel() > 0) { + return; + } + + if (fccf.isActive()) { + p.sendMessage(Component.text("You can't switch recipes while the factory is running", NamedTextColor.RED)); + } else { + fccf.setRecipeForce(FactoryMod.getInstance().getManager().getRecipe(SpeedUpgradeRecipe.IDENTIFIER)); + p.sendMessage(ChatColor.GREEN + "Switched recipe to " + fccf.getCurrentRecipe().getName()); + } + } + }; + } + + private Clickable buildResetUpgrades() { + ItemStack upgradeSpeed = new ItemStack(Material.LEVER); + ItemMeta meta = upgradeSpeed.getItemMeta(); + meta.displayName(Component.text("Reset upgrades")); + if (fccf.getCharcoalLevel() == 0 && fccf.getSpeedLevel() == 0) { + meta.lore(List.of(Component.text("You do not have any upgrades", NamedTextColor.RED).decoration(TextDecoration.ITALIC, false))); + } else { + meta.lore(List.of( + Component.text("Permanently deletes all upgrades for this factory", NamedTextColor.GOLD).decoration(TextDecoration.ITALIC, false) + )); + } + meta.setEnchantmentGlintOverride(true); + upgradeSpeed.setItemMeta(meta); + + return new Clickable(upgradeSpeed) { + @Override + protected void clicked(Player p) { + if (fccf.getCharcoalLevel() == 0 && fccf.getSpeedLevel() == 0) { + return; + } + + if (fccf.isActive()) { + p.sendMessage(Component.text("You can't switch recipes while the factory is running", NamedTextColor.RED)); + } else { + fccf.setRecipeForce(FactoryMod.getInstance().getManager().getRecipe(ResetUpgradesRecipe.IDENTIFIER)); + p.sendMessage(ChatColor.GREEN + "Switched recipe to " + fccf.getCurrentRecipe().getName()); + } + } + }; + } + private Clickable buildAutoSelectToggle() { ItemStack autoSelectStack = new ItemStack(Material.REDSTONE_BLOCK); ItemUtils.setDisplayName(autoSelectStack, "Toggle auto select"); diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/FactoryMaterialReturnRecipe.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/FactoryMaterialReturnRecipe.java index b82239f1c..763a307d4 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/FactoryMaterialReturnRecipe.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/FactoryMaterialReturnRecipe.java @@ -82,7 +82,7 @@ public class FactoryMaterialReturnRecipe extends InputRecipe { .getCenter(); for (Entry items : FactoryMod.getInstance(). getManager().getTotalSetupCost(fccf) - .getEntrySet()) { + .getAllItems().entrySet()) { int returnAmount = (int) (items.getValue() * factor); ItemMap im = new ItemMap(); im.addItemAmount(items.getKey(), returnAmount); diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/InputRecipe.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/InputRecipe.java index 8b68d80ec..569a1039d 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/InputRecipe.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/InputRecipe.java @@ -3,6 +3,7 @@ package com.github.igotyou.FactoryMod.recipes; import com.github.igotyou.FactoryMod.factories.Factory; import com.github.igotyou.FactoryMod.factories.FurnCraftChestFactory; import com.github.igotyou.FactoryMod.utility.LoggingUtils; +import java.awt.*; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -14,6 +15,8 @@ import org.bukkit.Material; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import vg.civcraft.mc.civmodcore.chat.ChatUtils; +import vg.civcraft.mc.civmodcore.inventory.CustomItem; import vg.civcraft.mc.civmodcore.inventory.items.ItemMap; import vg.civcraft.mc.civmodcore.inventory.items.ItemUtils; import vg.civcraft.mc.civmodcore.utilities.TextUtil; @@ -183,7 +186,7 @@ public abstract class InputRecipe implements IRecipe { LinkedList result = new LinkedList<>(); ItemMap inventoryMap = new ItemMap(i); ItemMap possibleRuns = new ItemMap(); - for (Entry entry : input.getEntrySet()) { + for (Entry entry : input.getAllItems().entrySet()) { if (inventoryMap.getAmount(entry.getKey()) != 0) { possibleRuns.addItemAmount(entry.getKey(), inventoryMap.getAmount(entry.getKey()) / entry.getValue()); } else { @@ -213,14 +216,33 @@ public abstract class InputRecipe implements IRecipe { protected List formatLore(ItemMap ingredients) { List result = new ArrayList<>(); - for (Entry entry : ingredients.getEntrySet()) { + for (Entry entry : ingredients.getItems().entrySet()) { if (entry.getValue() > 0) { if (!entry.getKey().hasItemMeta()) { result.add(entry.getValue() + " " + ItemUtils.getItemName(entry.getKey())); } else { String lore = String.format("%s %s%s", entry.getValue(), ChatColor.ITALIC, ItemUtils.getItemName(entry.getKey())); if (entry.getKey().getItemMeta().hasDisplayName()) { - lore += String.format("%s [%s]", ChatColor.DARK_AQUA, StringUtils.abbreviate(entry.getKey().getItemMeta().getDisplayName(), 20)); + lore += String.format("%s [%s%1$s]", ChatColor.DARK_AQUA, StringUtils.abbreviate(entry.getKey().getItemMeta().getDisplayName(), 20)); + } + result.add(lore); + } + } + } + // Custom items should have their custom name displayed more prominently, their actual item type is irrelevant + for (Entry entry : ingredients.getCustomItems().entrySet()) { + if (entry.getValue() > 0) { + ItemStack item = CustomItem.getCustomItem(entry.getKey()); + if (!item.hasItemMeta()) { + result.add(entry.getValue() + " " + ItemUtils.getItemName(item)); + } else { + String lore; + if (item.getItemMeta().hasDisplayName()) { + lore = String.format("%s %s", entry.getValue(), StringUtils.abbreviate(item.getItemMeta().getDisplayName(), 35)); + } else if (item.getItemMeta().hasItemName()) { + lore = String.format("%s %s", entry.getValue(), StringUtils.abbreviate(item.getItemMeta().getItemName(), 35)); + } else { + lore = String.format("%s %s%s", entry.getValue(), ChatColor.ITALIC, ItemUtils.getItemName(item)); } result.add(lore); } diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/ProductionRecipe.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/ProductionRecipe.java index cf3c22a27..2298f9ff0 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/ProductionRecipe.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/ProductionRecipe.java @@ -63,7 +63,7 @@ public class ProductionRecipe extends InputRecipe { } ItemMap adjusted = new ItemMap(); double factor = modifier.getFactor(rank, runs); - for (Entry entry : output.getEntrySet()) { + for (Entry entry : output.getAllItems().entrySet()) { adjusted.addItemAmount(entry.getKey(), (int) (Math.floor(entry.getValue() * factor))); } return adjusted; @@ -81,7 +81,7 @@ public class ProductionRecipe extends InputRecipe { ItemMap currentOut = getGuaranteedOutput(fccf.getRecipeLevel(this), fccf.getRunCount(this)); List stacks = currentOut.getItemStackRepresentation(); double factor = (modifier != null) ? (modifier.getFactor(fccf.getRecipeLevel(this), fccf.getRunCount(this))) : 1.0; - for (Entry entry : output.getEntrySet()) { + for (Entry entry : output.getAllItems().entrySet()) { double additionalChance = (((double) entry.getValue()) * factor) - currentOut.getAmount(entry.getKey()); if (Math.abs(additionalChance) > 0.00000001) { ItemStack is = entry.getKey().clone(); @@ -132,7 +132,7 @@ public class ProductionRecipe extends InputRecipe { } else { toAdd = getGuaranteedOutput(fccf.getRecipeLevel(this), fccf.getRunCount(this)); double factor = modifier.getFactor(fccf.getRecipeLevel(this), fccf.getRunCount(this)); - for (Entry entry : output.getEntrySet()) { + for (Entry entry : output.getAllItems().entrySet()) { double additionalChance = (((double) entry.getValue()) * factor) - toAdd.getAmount(entry.getKey()); if (rng.nextDouble() <= additionalChance) { toAdd.addItemAmount(entry.getKey(), 1); diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/PylonRecipe.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/PylonRecipe.java index aa19f8219..ff60c68d9 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/PylonRecipe.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/PylonRecipe.java @@ -115,7 +115,7 @@ public class PylonRecipe extends InputRecipe { / (float) globalLimit); double multiplier = 1.0 / overload; ItemMap actualOutput = new ItemMap(); - for (Entry entry : output.getEntrySet()) { + for (Entry entry : output.getAllItems().entrySet()) { actualOutput.addItemAmount(entry.getKey(), (int) (entry.getValue() * multiplier)); } @@ -142,7 +142,7 @@ public class PylonRecipe extends InputRecipe { @Override public List getTextualOutputRepresentation(Inventory i, FurnCraftChestFactory fccf) { List result = new ArrayList<>(); - for (Entry entry : output.getEntrySet()) { + for (Entry entry : output.getAllItems().entrySet()) { if (entry.getValue() > 0) { result.add(entry.getValue() + " " + ItemUtils.getItemName(entry.getKey())); } diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/Upgraderecipe.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/Upgraderecipe.java index 965031cb9..c92fcdd93 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/Upgraderecipe.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/Upgraderecipe.java @@ -70,7 +70,7 @@ public class Upgraderecipe extends InputRecipe { LinkedList result = new LinkedList<>(); ItemMap inventoryMap = new ItemMap(i); ItemMap possibleRuns = new ItemMap(); - for (Entry entry : input.getEntrySet()) { + for (Entry entry : input.getAllItems().entrySet()) { if (inventoryMap.getAmount(entry.getKey()) != 0) { possibleRuns.addItemAmount( entry.getKey(), diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/WordBankRecipe.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/WordBankRecipe.java index c7cc9302c..a816116b0 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/WordBankRecipe.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/WordBankRecipe.java @@ -9,6 +9,7 @@ import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.inventory.CustomItem; import vg.civcraft.mc.civmodcore.inventory.items.ItemMap; import vg.civcraft.mc.civmodcore.inventory.items.ItemUtils; @@ -64,6 +65,9 @@ public class WordBankRecipe extends InputRecipe { if (!ItemUtils.isValidItem(is)) { continue; } + if (CustomItem.isCustomItem(is)) { + continue; + } input.addItemStack(is); inputInv.setItem(i, null); } @@ -71,7 +75,7 @@ public class WordBankRecipe extends InputRecipe { StringBuilder sb = new StringBuilder(); sb.append(ChatColor.GOLD); sb.append("Wordbank recipe complete and turned "); - for (Entry entry : input.getEntrySet()) { + for (Entry entry : input.getItems().entrySet()) { sb.append(entry.getValue()); sb.append(" "); sb.append(ItemUtils.getItemName(entry.getKey())); @@ -137,6 +141,9 @@ public class WordBankRecipe extends InputRecipe { if (!ItemUtils.isValidItem(is)) { continue; } + if (!CustomItem.isCustomItem(is)) { + continue; + } return true; } return false; @@ -144,7 +151,7 @@ public class WordBankRecipe extends InputRecipe { private synchronized String getHash(ItemMap items) { digest.update(key.getBytes()); - List> entries = new ArrayList<>(items.getEntrySet()); + List> entries = new ArrayList<>(items.getItems().object2IntEntrySet()); //sort because hashmaps dont guarantee iteration order Collections.sort(entries, (a, b) -> a.getKey().getType().getKey().getKey().compareTo(b.getKey().getType().getKey().getKey())); diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/upgrade/CharcoalConsumptionUpgradeRecipe.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/upgrade/CharcoalConsumptionUpgradeRecipe.java new file mode 100644 index 000000000..dc8a8e37f --- /dev/null +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/upgrade/CharcoalConsumptionUpgradeRecipe.java @@ -0,0 +1,50 @@ +package com.github.igotyou.FactoryMod.recipes.upgrade; + +import com.github.igotyou.FactoryMod.factories.FurnCraftChestFactory; +import com.github.igotyou.FactoryMod.powerManager.FurnacePowerManager; +import com.github.igotyou.FactoryMod.recipes.IRecipe; +import org.bukkit.Material; +import org.bukkit.inventory.Inventory; + +public class CharcoalConsumptionUpgradeRecipe implements IRecipe { + + public static final String IDENTIFIER = "upgrade_charcoal_consumption"; + + @Override + public String getName() { + return "Upgrade Charcoal Consumption"; + } + + @Override + public String getIdentifier() { + return IDENTIFIER; + } + + @Override + public int getProductionTime() { + return 80; + } + + @Override + public boolean enoughMaterialAvailable(Inventory inputInv) { + return Upgrade.hasUpgrade(inputInv.getStorageContents()); + } + + @Override + public boolean applyEffect(Inventory inputInv, Inventory outputInv, FurnCraftChestFactory fccf) { + if (fccf.getCharcoalLevel() == 4 || fccf.getSpeedLevel() > 0 || ((FurnacePowerManager) fccf.getPowerManager()).getFuel().getType() != Material.CHARCOAL) { + return false; + } + if (Upgrade.removeUpgrade(inputInv)) { + fccf.setCharcoalLevel(fccf.getCharcoalLevel() + 1); + return true; + } else { + return false; + } + } + + @Override + public String getTypeIdentifier() { + return "UPGRADE_CHARCOAL_CONSUMPTION"; + } +} diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/upgrade/ResetUpgradesRecipe.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/upgrade/ResetUpgradesRecipe.java new file mode 100644 index 000000000..fdb0ffaae --- /dev/null +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/upgrade/ResetUpgradesRecipe.java @@ -0,0 +1,45 @@ +package com.github.igotyou.FactoryMod.recipes.upgrade; + +import com.github.igotyou.FactoryMod.factories.FurnCraftChestFactory; +import com.github.igotyou.FactoryMod.recipes.IRecipe; +import org.bukkit.inventory.Inventory; + +public class ResetUpgradesRecipe implements IRecipe { + + public static String IDENTIFIER = "reset_upgrades"; + + @Override + public String getName() { + return "Reset Upgrades"; + } + + @Override + public String getIdentifier() { + return IDENTIFIER; + } + + @Override + public int getProductionTime() { + return 80; + } + + @Override + public boolean enoughMaterialAvailable(Inventory inputInv) { + return true; + } + + @Override + public boolean applyEffect(Inventory inputInv, Inventory outputInv, FurnCraftChestFactory fccf) { + if (fccf.getSpeedLevel() == 0 && fccf.getCharcoalLevel() == 0) { + return false; + } + fccf.setSpeedLevel(0); + fccf.setCharcoalLevel(0); + return false; + } + + @Override + public String getTypeIdentifier() { + return "RESET_UPGRADES"; + } +} diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/upgrade/SpeedUpgradeRecipe.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/upgrade/SpeedUpgradeRecipe.java new file mode 100644 index 000000000..deb4518e4 --- /dev/null +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/upgrade/SpeedUpgradeRecipe.java @@ -0,0 +1,48 @@ +package com.github.igotyou.FactoryMod.recipes.upgrade; + +import com.github.igotyou.FactoryMod.factories.FurnCraftChestFactory; +import com.github.igotyou.FactoryMod.recipes.IRecipe; +import org.bukkit.inventory.Inventory; + +public class SpeedUpgradeRecipe implements IRecipe { + + public static String IDENTIFIER = "upgrade_speed"; + + @Override + public String getName() { + return "Upgrade Speed"; + } + + @Override + public String getIdentifier() { + return IDENTIFIER; + } + + @Override + public int getProductionTime() { + return 80; + } + + @Override + public boolean enoughMaterialAvailable(Inventory inputInv) { + return Upgrade.hasUpgrade(inputInv.getStorageContents()); + } + + @Override + public boolean applyEffect(Inventory inputInv, Inventory outputInv, FurnCraftChestFactory fccf) { + if (fccf.getSpeedLevel() == 4 || fccf.getCharcoalLevel() > 0) { + return false; + } + if (Upgrade.removeUpgrade(inputInv)) { + fccf.setSpeedLevel(fccf.getSpeedLevel() + 1); + return true; + } else { + return false; + } + } + + @Override + public String getTypeIdentifier() { + return "UPGRADE_SPEED"; + } +} diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/upgrade/Upgrade.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/upgrade/Upgrade.java new file mode 100644 index 000000000..a80ef5c96 --- /dev/null +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/recipes/upgrade/Upgrade.java @@ -0,0 +1,35 @@ +package com.github.igotyou.FactoryMod.recipes.upgrade; + +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.inventory.CustomItem; + +public interface Upgrade { + + static boolean hasUpgrade(ItemStack[] items) { + for (ItemStack item : items) { + if (CustomItem.isCustomItem(item, "factory_upgrade")) { + return true; + } + } + return false; + } + + static boolean removeUpgrade(Inventory inventory) { + ItemStack[] storageContents = inventory.getStorageContents(); + for (int i = 0; i < storageContents.length; i++) { + ItemStack item = storageContents[i]; + if (CustomItem.isCustomItem(item, "factory_upgrade")) { + if (item.getAmount() == 1) { + inventory.removeItem(item); + } else { + item.setAmount(item.getAmount() - 1); + } + return true; + } + } + return false; + } + + +} diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/repairManager/PercentageHealthRepairManager.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/repairManager/PercentageHealthRepairManager.java index 247607932..b8ea2e5b0 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/repairManager/PercentageHealthRepairManager.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/repairManager/PercentageHealthRepairManager.java @@ -85,7 +85,7 @@ public class PercentageHealthRepairManager implements IRepairManager { if (rate == 0.0) { return; } - for (Entry items : FactoryMod.getInstance().getManager().getTotalSetupCost(factory).getEntrySet()) { + for (Entry items : FactoryMod.getInstance().getManager().getTotalSetupCost(factory).getAllItems().entrySet()) { int returnAmount = (int) (items.getValue() * rate); ItemMap im = new ItemMap(); im.addItemAmount(items.getKey(), returnAmount); diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/utility/FactoryModGUI.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/utility/FactoryModGUI.java index f317e1849..0e018e479 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/utility/FactoryModGUI.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/utility/FactoryModGUI.java @@ -146,7 +146,7 @@ public class FactoryModGUI { ItemUtils.addLore(is, ChatColor.GREEN + factory.getName() + " can be created directly"); List lore = new ArrayList<>(); lore.add(ChatColor.GOLD + "Required materials:"); - for (Entry entry : factory.getSetupCost().getEntrySet()) { + for (Entry entry : factory.getSetupCost().getAllItems().entrySet()) { lore.add(ChatColor.GRAY + " - " + ChatColor.AQUA + entry.getValue() + " " + ItemUtils.getItemName(entry.getKey())); } @@ -159,7 +159,7 @@ public class FactoryModGUI { if (upRec != null) { List lore = new ArrayList<>(); lore.add(ChatColor.GOLD + "Required materials for the upgrade:"); - for (Entry entry : upRec.getInput().getEntrySet()) { + for (Entry entry : upRec.getInput().getAllItems().entrySet()) { lore.add(ChatColor.GRAY + " - " + ChatColor.AQUA + entry.getValue() + " " + ItemUtils.getItemName(entry.getKey())); } diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/utility/FileHandler.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/utility/FileHandler.java index 40fd7b804..76cc4cfdd 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/utility/FileHandler.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/utility/FileHandler.java @@ -102,6 +102,9 @@ public class FileHandler { config.set(current + ".furnace-io", fccf.getFurnaceIOSelector().toConfigSection()); config.set(current + ".table-io", fccf.getTableIOSelector().toConfigSection()); config.set(current + ".ui-menu-mode", fccf.getUiMenuMode().name()); + config.set(current + ".charcoal-level", fccf.getCharcoalLevel()); + config.set(current + ".speed-level", fccf.getSpeedLevel()); + config.set(current + ".charcoal-absorbed", fccf.getCharcoalAbsorbed()); } else if (f instanceof Pipe) { Pipe p = (Pipe) f; config.set(current + ".type", "PIPE"); @@ -258,8 +261,11 @@ public class FileHandler { } boolean autoSelect = current.getBoolean("autoSelect", false); + int charcoalLevel = current.getInt("charcoal-level", 0); + int speedLevel = current.getInt("speed-level", 0); + int charcoalAbsorbed = current.getInt("charcoal-absorbed", 0); FurnCraftChestFactory fac = (FurnCraftChestFactory) egg.revive(blocks, health, selectedRecipe, - runtime, breakTime, recipes); + runtime, breakTime, recipes, charcoalLevel, speedLevel, charcoalAbsorbed); String activator = current.getString("activator", "null"); UUID acti; if (activator.equals("null")) { diff --git a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/utility/ItemUseGUI.java b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/utility/ItemUseGUI.java index 4a12ad963..b17d18865 100644 --- a/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/utility/ItemUseGUI.java +++ b/plugins/factorymod-paper/src/main/java/com/github/igotyou/FactoryMod/utility/ItemUseGUI.java @@ -167,7 +167,7 @@ public class ItemUseGUI { ItemUtils.setDisplayName(is, ChatColor.DARK_GREEN + fccEgg.getName()); List lore = new ArrayList<>(); lore.add(ChatColor.GOLD + "Setup cost:"); - for (Map.Entry entry : fccEgg.getSetupCost().getEntrySet()) { + for (Map.Entry entry : fccEgg.getSetupCost().getAllItems().entrySet()) { String recipeRepresentation = entry.getValue() + " " + ItemUtils.getItemName(entry.getKey()); lore.add(formatIngredient(recipeRepresentation, item)); } diff --git a/plugins/factorymod-paper/src/main/resources/plugin.yml b/plugins/factorymod-paper/src/main/resources/plugin.yml index 134361ffd..5e655c64b 100644 --- a/plugins/factorymod-paper/src/main/resources/plugin.yml +++ b/plugins/factorymod-paper/src/main/resources/plugin.yml @@ -3,7 +3,7 @@ main: com.github.igotyou.FactoryMod.FactoryMod author: Maxopoly, igotyou version: ${version} depend: [ CivModCore ] -softdepend: [ CivMenu, NameLayer, Citadel ] +softdepend: [ CivMenu, NameLayer, Citadel, Heliodor ] permissions: fm.public: default: true diff --git a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/ConfigParser.java b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/ConfigParser.java index eaec28640..5c8455b3c 100644 --- a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/ConfigParser.java +++ b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/ConfigParser.java @@ -49,6 +49,7 @@ public class ConfigParser { private boolean pearlEnabled; private long pearlCooldown; private boolean combatTagOnPearl; + private boolean netheriteFireResistanceEnabled; private PotionHandler potionHandler; private Collection disabledEnchants; private VelocityHandler velocityHandler; @@ -91,6 +92,10 @@ public class ConfigParser { return combatConfig; } + public boolean isNetheriteFireResistanceEnabled() { + return netheriteFireResistanceEnabled; + } + public FinaleManager parse() { plugin.info("Parsing Finale config..."); plugin.saveDefaultConfig(); @@ -156,6 +161,8 @@ public class ConfigParser { } WarpFruitTracker warpFruitTracker = new WarpFruitTracker(warpFruitLogSize, warpFruitLogInterval, warpFruitCooldown, warpFruitMaxDistance, warpFruitSpectralWhileChanneling, afterEffects); + netheriteFireResistanceEnabled = config.getBoolean("netheriteFireResistance"); + // Initialize the manager manager = new FinaleManager(debug, attackEnabled, attackSpeed, invulTicksEnabled, invulnerableTicks, regenEnabled, ctpOnLogin, regenhandler, weapMod, armourMod, allyHandler, arrowHandler, tridentHandler, shieldHandler, crossbowHandler, gappleHandler, potionHandler, tippedArrowMod, blockRestrictionHandler, combatConfig, warpFruitTracker); @@ -556,24 +563,31 @@ public class ConfigParser { plugin.warning("Found invalid value " + key + " at " + config + " only mapping values allowed here"); continue; } - String matString = current.getString("material"); - if (matString == null) { - plugin.warning("Found no material specified at " + current + ". Skipping attack damage adjustment"); - continue; - } - Material mat; - try { - - mat = Material.valueOf(matString); - } catch (IllegalArgumentException e) { - plugin.warning("Found invalid material " + matString + " specified at " + current - + ". Skipping attack damage adjustment for it"); - continue; - } int damage = current.getInt("damage", -1); double attackSpeed = current.getDouble("attackSpeed", -1.0); - plugin.info("Modifying " + matString + ": attackSpeed: " + attackSpeed + ", damage: " + damage); - wm.addWeapon(mat, damage, attackSpeed); + double bonusDamagePerNetheritePiece = current.getDouble("bonusDamagePerNetheritePiece", 0.0); + double armourDamageMultiplier = current.getDouble("armourDamageMultiplier", 1.0); + String customKey = current.getString("key"); + if (customKey != null) { + plugin.info("Modifying custom " + customKey + ": attackSpeed: " + attackSpeed + ", damage: " + damage + ", bonusDamagePerNetheritePiece: " + bonusDamagePerNetheritePiece + ", armourDamageMultiplier: " + armourDamageMultiplier); + wm.addCustomWeapon(customKey, damage, attackSpeed, bonusDamagePerNetheritePiece, armourDamageMultiplier); + } else { + String matString = current.getString("material"); + if (matString == null) { + plugin.warning("Found no material specified at " + current + ". Skipping attack damage adjustment"); + continue; + } + Material mat; + try { + mat = Material.valueOf(matString); + } catch (IllegalArgumentException e) { + plugin.warning("Found invalid material " + matString + " specified at " + current + + ". Skipping attack damage adjustment for it"); + continue; + } + plugin.info("Modifying " + matString + ": attackSpeed: " + attackSpeed + ", damage: " + damage + ", bonusDamagePerNetheritePiece: " + bonusDamagePerNetheritePiece + ", armourDamageMultiplier: " + armourDamageMultiplier); + wm.addWeapon(mat, damage, attackSpeed, bonusDamagePerNetheritePiece, armourDamageMultiplier); + } } return wm; } @@ -589,26 +603,34 @@ public class ConfigParser { plugin.warning("Found invalid value " + key + " at " + config + " only mapping values allowed here"); continue; } - String matString = current.getString("material"); - if (matString == null) { - plugin.warning("Found no material specified at " + current + ". Skipping attack damage adjustment"); - continue; - } - Material mat; - try { - mat = Material.valueOf(matString); - } catch (IllegalArgumentException e) { - plugin.warning("Found invalid material " + matString + " specified at " + current - + ". Skipping attack damage adjustment for it"); - continue; - } double toughness = current.getDouble("toughness", -1); double armour = current.getDouble("armour", -1); double knockbackResistance = current.getDouble("knockbackResistance", -1); int extraDurabilityHits = current.getInt("extraDurabilityHits", 0); - plugin.info("Modifying " + matString + ": toughness: " + toughness + ", armour: " + armour - + ", knockbackResistance: " + knockbackResistance, ", extraDurabilityHits: " + extraDurabilityHits); - am.addArmour(mat, toughness, armour, knockbackResistance, extraDurabilityHits); + + String customKey = current.getString("key"); + if (customKey != null) { + plugin.info("Modifying custom " + customKey + ": toughness: " + toughness + ", armour: " + armour + + ", knockbackResistance: " + knockbackResistance, ", extraDurabilityHits: " + extraDurabilityHits); + am.addCustomArmour(customKey, toughness, armour, knockbackResistance, extraDurabilityHits); + } else { + String matString = current.getString("material"); + if (matString == null) { + plugin.warning("Found no material specified at " + current + ". Skipping attack damage adjustment"); + continue; + } + Material mat; + try { + mat = Material.valueOf(matString); + } catch (IllegalArgumentException e) { + plugin.warning("Found invalid material " + matString + " specified at " + current + + ". Skipping attack damage adjustment for it"); + continue; + } + plugin.info("Modifying " + matString + ": toughness: " + toughness + ", armour: " + armour + + ", knockbackResistance: " + knockbackResistance, ", extraDurabilityHits: " + extraDurabilityHits); + am.addArmour(mat, toughness, armour, knockbackResistance, extraDurabilityHits); + } } return am; } diff --git a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/Finale.java b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/Finale.java index 89065bdbf..c4777b1ac 100644 --- a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/Finale.java +++ b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/Finale.java @@ -16,6 +16,7 @@ import com.github.maxopoly.finale.listeners.DamageListener; import com.github.maxopoly.finale.listeners.EnchantmentDisableListener; import com.github.maxopoly.finale.listeners.ExtraDurabilityListener; import com.github.maxopoly.finale.listeners.GappleListener; +import com.github.maxopoly.finale.listeners.NetheriteFireResistanceListener; import com.github.maxopoly.finale.listeners.PearlCoolDownListener; import com.github.maxopoly.finale.listeners.PlayerListener; import com.github.maxopoly.finale.listeners.PotionListener; @@ -112,6 +113,9 @@ public class Finale extends ACivMod { Bukkit.getPluginManager().registerEvents(new DamageListener(config.getDamageModifiers()), this); Bukkit.getPluginManager().registerEvents(new ScoreboardHUD(settingsManager), this); Bukkit.getPluginManager().registerEvents(new ToolProtectionListener(settingsManager), this); + if (config.isNetheriteFireResistanceEnabled()) { + new NetheriteFireResistanceListener(this).start(); + } Bukkit.getPluginManager().registerEvents(new WarpFruitListener(), this); Bukkit.getPluginManager().registerEvents(new TridentListener(), this); Bukkit.getPluginManager().registerEvents(new ShieldListener(), this); diff --git a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/combat/CombatUtil.java b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/combat/CombatUtil.java index ca70873da..6ebf13ccc 100644 --- a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/combat/CombatUtil.java +++ b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/combat/CombatUtil.java @@ -44,6 +44,8 @@ import org.bukkit.util.Vector; public class CombatUtil { + public static org.bukkit.inventory.ItemStack DAMAGING_ITEM = null; + private static void sendSoundEffect(net.minecraft.world.entity.player.Player fromEntity, double x, double y, double z, SoundEvent soundEffect, SoundSource soundCategory, float volume, float pitch) { fromEntity.playSound(soundEffect, volume, pitch); // This will not send the effect to the entity himself if (fromEntity instanceof ServerPlayer) { @@ -119,7 +121,13 @@ public class CombatUtil { Vec3 victimMot = victim.getDeltaMovement(); if (shouldDamage) { - boolean damagedVictim = victim.hurt(damagesource, damage); + boolean damagedVictim; + try { + DAMAGING_ITEM = attacker.getBukkitEntity().getInventory().getItemInMainHand(); + damagedVictim = victim.hurt(damagesource, damage); + } finally { + DAMAGING_ITEM = null; + } if (damagedVictim) { if (knockbackLevel > 0 || dealtExtraKnockback) { if (victim instanceof LivingEntity) { diff --git a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/ExtraDurabilityListener.java b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/ExtraDurabilityListener.java index ba65fa315..c1006f0c7 100644 --- a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/ExtraDurabilityListener.java +++ b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/ExtraDurabilityListener.java @@ -1,21 +1,36 @@ package com.github.maxopoly.finale.listeners; import com.github.maxopoly.finale.Finale; +import com.github.maxopoly.finale.combat.CombatUtil; import com.github.maxopoly.finale.misc.ArmourModifier; import com.github.maxopoly.finale.misc.ExtraDurabilityTracker; +import com.github.maxopoly.finale.misc.WeaponModifier; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerItemDamageEvent; import org.bukkit.inventory.ItemStack; +import java.util.concurrent.ThreadLocalRandom; public class ExtraDurabilityListener implements Listener { @EventHandler public void onDurabilityChange(PlayerItemDamageEvent e) { + ItemStack item = CombatUtil.DAMAGING_ITEM; + if (item == null || item.isEmpty()) { + return; + } + + WeaponModifier weaponMod = Finale.getPlugin().getManager().getWeaponModifer(); + double multi = weaponMod.getArmourDamageMultiplier(item); + if (multi > 1 && multi <= 2 && ThreadLocalRandom.current().nextDouble() < multi - 1) { + return; + } + + ItemStack is = e.getItem(); ArmourModifier armourModifier = Finale.getPlugin().getManager().getArmourModifier(); ExtraDurabilityTracker extraDurabilityTracker = armourModifier.getExtraDurabilityTracker(); - boolean reduce = extraDurabilityTracker.reduceDurability(e.getPlayer(), is.getType()); + boolean reduce = extraDurabilityTracker.reduceDurability(e.getPlayer(), is); e.setCancelled(!reduce); } diff --git a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/NetheriteFireResistanceListener.java b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/NetheriteFireResistanceListener.java new file mode 100644 index 000000000..162d8ff21 --- /dev/null +++ b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/NetheriteFireResistanceListener.java @@ -0,0 +1,59 @@ +package com.github.maxopoly.finale.listeners; + +import java.util.logging.Level; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +public class NetheriteFireResistanceListener implements Listener { + + private final Plugin plugin; + + public NetheriteFireResistanceListener(Plugin plugin) { + this.plugin = plugin; + } + + public void start() { + Bukkit.getScheduler().runTaskTimer(plugin, () -> { + try { + this.applyFireResistance(); + } catch (RuntimeException ex) { + plugin.getLogger().log(Level.WARNING, "Applying fire resistance to netherite armour", ex); + } + }, 20, 20); + } + + public void applyFireResistance() { + for (Player player : Bukkit.getOnlinePlayers()) { + int pieces = 0; + for (ItemStack armour : player.getInventory().getArmorContents()) { + if (armour == null) { + continue; + } + Material type = armour.getType(); + switch (type) { + case NETHERITE_BOOTS, NETHERITE_HELMET, NETHERITE_CHESTPLATE, NETHERITE_LEGGINGS -> pieces++; + } + } + if (pieces == 4) { + PotionEffect currentEffect = player.getPotionEffect(PotionEffectType.FIRE_RESISTANCE); + if (currentEffect == null || currentEffect.getDuration() < 5 * 20 + 19) { + player.addPotionEffect(new PotionEffect( + PotionEffectType.FIRE_RESISTANCE, + 8 * 20 + 19, + 0, + true, + false, + true + )); + } + } + } + } + +} diff --git a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/ToolProtectionListener.java b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/ToolProtectionListener.java index aae13f171..82694b4d1 100644 --- a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/ToolProtectionListener.java +++ b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/ToolProtectionListener.java @@ -33,7 +33,8 @@ public class ToolProtectionListener implements Listener { if (meta == null) { return; } - int health = is.getType().getMaxDurability() - meta.getDamage(); + int maxDura = meta.hasMaxDamage() ? meta.getMaxDamage() : is.getType().getMaxDurability(); + int health = maxDura - meta.getDamage(); if (health <= settingMan.getToolProtectionThreshhold(e.getPlayer().getUniqueId())) { for (int i = 0; i < 5; i++) { e.getPlayer().sendMessage(ChatColor.RED.toString() + ChatColor.BOLD + "Your tool is almost broken"); diff --git a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/WeaponModificationListener.java b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/WeaponModificationListener.java index 35a587007..86ba58ea8 100644 --- a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/WeaponModificationListener.java +++ b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/listeners/WeaponModificationListener.java @@ -5,12 +5,15 @@ import com.github.maxopoly.finale.misc.ArmourModifier; import com.github.maxopoly.finale.misc.ItemUtil; import com.github.maxopoly.finale.misc.TippedArrowModifier; import com.github.maxopoly.finale.misc.WeaponModifier; +import java.util.Map; import net.kyori.adventure.text.Component; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.EquipmentSlotGroup; import org.bukkit.inventory.ItemStack; @@ -21,8 +24,6 @@ import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionType; -import java.util.Map; - public class WeaponModificationListener implements Listener { private final NamespacedKey KEY_ATTACK_SPEED; @@ -48,9 +49,9 @@ public class WeaponModificationListener implements Listener { ArmourModifier armourMod = Finale.getPlugin().getManager().getArmourModifier(); - double toughness = armourMod.getToughness(is.getType()); - double armour = armourMod.getArmour(is.getType()); - double knockbackResistance = armourMod.getKnockbackResistance(is.getType()); + double toughness = armourMod.getToughness(is); + double armour = armourMod.getArmour(is); + double knockbackResistance = armourMod.getKnockbackResistance(is); if (toughness != -1 || armour != -1 || knockbackResistance != -1) { if (toughness == -1) { @@ -93,8 +94,8 @@ public class WeaponModificationListener implements Listener { WeaponModifier weaponMod = Finale.getPlugin().getManager().getWeaponModifer(); - double adjustedDamage = weaponMod.getDamage(is.getType()); - double adjustedAttackSpeed = weaponMod.getAttackSpeed(is.getType()); + double adjustedDamage = weaponMod.getDamage(is); + double adjustedAttackSpeed = weaponMod.getAttackSpeed(is); if (adjustedAttackSpeed != -1.0 || adjustedDamage != -1) { im.removeAttributeModifier(Attribute.GENERIC_ATTACK_SPEED); @@ -162,4 +163,25 @@ public class WeaponModificationListener implements Listener { is.setItemMeta(im); } + @EventHandler + public void damageEntity(EntityDamageByEntityEvent e) { + if (!(e.getEntity() instanceof Player victim) || !(e.getDamager() instanceof Player attacker)) { + return; + } + WeaponModifier weaponMod = Finale.getPlugin().getManager().getWeaponModifer(); + ItemStack item = attacker.getInventory().getItemInMainHand(); + + int pieces = 0; + for (ItemStack armour : victim.getInventory().getArmorContents()) { + if (armour == null) { + continue; + } + Material type = armour.getType(); + switch (type) { + case NETHERITE_BOOTS, NETHERITE_HELMET, NETHERITE_CHESTPLATE, NETHERITE_LEGGINGS -> pieces++; + } + } + + e.setDamage(e.getDamage() + pieces * weaponMod.getBonusDamagePerNetheritePiece(item)); + } } diff --git a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/misc/ArmourModifier.java b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/misc/ArmourModifier.java index f6a5c2113..ec2ee494f 100644 --- a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/misc/ArmourModifier.java +++ b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/misc/ArmourModifier.java @@ -4,6 +4,10 @@ import java.util.HashMap; import java.util.Map; import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; +import vg.civcraft.mc.civmodcore.inventory.CustomItem; public class ArmourModifier { @@ -50,42 +54,60 @@ public class ArmourModifier { private ExtraDurabilityTracker extraDurabilityTracker; private Map armour; + private Map customArmour; public ArmourModifier() { this.extraDurabilityTracker = new ExtraDurabilityTracker(this); - this.armour = new HashMap(); + this.armour = new HashMap<>(); + this.customArmour = new HashMap<>(); } public void addArmour(Material m, double toughness, double armour, double knockbackResistance, int extraDurabilityHits) { this.armour.put(m, new ArmourConfig(toughness, armour, knockbackResistance, extraDurabilityHits)); } - public double getToughness(Material m) { - ArmourConfig config = armour.get(m); + public void addCustomArmour(String k, double toughness, double armour, double knockbackResistance, int extraDurabilityHits) { + this.customArmour.put(k, new ArmourConfig(toughness, armour, knockbackResistance, extraDurabilityHits)); + } + + private ArmourConfig getArmourConfig(ItemStack item) { + if (item == null || item.isEmpty()) { + return null; + } + String key = CustomItem.getCustomItemKey(item); + if (key != null && customArmour.containsKey(key)) { + return customArmour.get(key); + } else { + return armour.get(item.getType()); + } + } + + public double getToughness(ItemStack m) { + ArmourConfig config = getArmourConfig(m); if (config == null) { return -1; } return config.getToughness(); } - public double getArmour(Material m) { - ArmourConfig config = armour.get(m); + public double getArmour(ItemStack m) { + ArmourConfig config = getArmourConfig(m); if (config == null) { return -1; } return config.getArmour(); } - public double getKnockbackResistance(Material m) { - ArmourConfig config = armour.get(m); + public double getKnockbackResistance(ItemStack m) { + ArmourConfig config = getArmourConfig(m); if (config == null) { return -1; } return config.getKnockbackResistance(); } - public int getExtraDurabilityHits(Material m) { - ArmourConfig config = armour.get(m); + public int getExtraDurabilityHits(ItemStack m) { + ArmourConfig config = getArmourConfig(m); if (config == null) { return -1; } diff --git a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/misc/ExtraDurabilityTracker.java b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/misc/ExtraDurabilityTracker.java index 5f394f136..547a4308f 100644 --- a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/misc/ExtraDurabilityTracker.java +++ b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/misc/ExtraDurabilityTracker.java @@ -2,6 +2,7 @@ package com.github.maxopoly.finale.misc; import org.bukkit.Material; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import java.util.HashMap; import java.util.Map; @@ -17,14 +18,14 @@ public class ExtraDurabilityTracker { } // returns true if durability should reduce, false if durability shouldn't reduce. - public boolean reduceDurability(Player player, Material material) { + public boolean reduceDurability(Player player, ItemStack item) { Map materialExtraHits = playerExtraHits.getOrDefault(player.getUniqueId(), new HashMap<>()); - int extraHits = materialExtraHits.containsKey(material) ? materialExtraHits.get(material) : armourModifier.getExtraDurabilityHits(material); + int extraHits = materialExtraHits.containsKey(item.getType()) ? materialExtraHits.get(item.getType()) : armourModifier.getExtraDurabilityHits(item); boolean reduce = extraHits <= 0; if (reduce) { - materialExtraHits.put(material, armourModifier.getExtraDurabilityHits(material)); + materialExtraHits.put(item.getType(), armourModifier.getExtraDurabilityHits(item)); } else { - materialExtraHits.put(material, extraHits - 1); + materialExtraHits.put(item.getType(), extraHits - 1); } playerExtraHits.put(player.getUniqueId(), materialExtraHits); return reduce; diff --git a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/misc/WeaponModifier.java b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/misc/WeaponModifier.java index 87d3a2809..9807c0e49 100644 --- a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/misc/WeaponModifier.java +++ b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/misc/WeaponModifier.java @@ -1,8 +1,10 @@ package com.github.maxopoly.finale.misc; -import java.util.EnumMap; +import java.util.HashMap; import java.util.Map; import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.inventory.CustomItem; public class WeaponModifier { @@ -11,14 +13,16 @@ public class WeaponModifier { private static final class WeaponConfig { - private Material mat; private double damage; private double attackSpeed; + private double bonusDamagePerNetheritePiece; + private double armourDamageMultiplier; - private WeaponConfig(Material mat, double damage, double attackSpeed) { - this.mat = mat; + private WeaponConfig(double damage, double attackSpeed, double bonusDamagePerNetheritePiece, double armourDamageMultiplier) { this.damage = damage; this.attackSpeed = attackSpeed; + this.bonusDamagePerNetheritePiece = bonusDamagePerNetheritePiece; + this.armourDamageMultiplier = armourDamageMultiplier; } public double getAttackSpeed() { @@ -29,35 +33,74 @@ public class WeaponModifier { return damage; } - public Material getMaterial() { - return mat; + public double getBonusDamagePerNetheritePiece() { + return bonusDamagePerNetheritePiece; + } + + public double getArmourDamageMultiplier() { + return armourDamageMultiplier; } } - private Map weapons; + private final Map weapons; + private final Map customWeapons; public WeaponModifier() { - this.weapons = new EnumMap<>(Material.class); + this.weapons = new HashMap<>(); + this.customWeapons = new HashMap<>(); } - public void addWeapon(Material m, int damage, double attackSpeed) { - weapons.put(m, new WeaponConfig(m, damage, attackSpeed)); + public void addWeapon(Material m, int damage, double attackSpeed, double bonusDamagePerNetheritePiece, double armourDamageMultiplier) { + weapons.put(m, new WeaponConfig(damage, attackSpeed, bonusDamagePerNetheritePiece, armourDamageMultiplier)); } - public double getAttackSpeed(Material m) { - WeaponConfig config = weapons.get(m); + + public void addCustomWeapon(String s, int damage, double attackSpeed, double bonusDamagePerNetheritePiece, double armourDamageMultiplier) { + customWeapons.put(s, new WeaponConfig(damage, attackSpeed, bonusDamagePerNetheritePiece, armourDamageMultiplier)); + } + + private WeaponConfig getWeaponConfig(ItemStack item) { + if (item == null || item.getType().isEmpty()) { + return null; + } + String key = CustomItem.getCustomItemKey(item); + if (key != null && customWeapons.containsKey(key)) { + return customWeapons.get(key); + } else { + return weapons.get(item.getType()); + } + } + + + public double getAttackSpeed(ItemStack m) { + WeaponConfig config = getWeaponConfig(m); if (config == null) { return DAMAGE_NON_ADJUSTED; } return config.getAttackSpeed(); } - public double getDamage(Material m) { - WeaponConfig config = weapons.get(m); + public double getDamage(ItemStack m) { + WeaponConfig config = getWeaponConfig(m); if (config == null) { return ATTACK_SPEED_NON_ADJUSTED; } return config.getDamage(); } + public double getBonusDamagePerNetheritePiece(ItemStack m) { + WeaponConfig config = getWeaponConfig(m); + if (config == null) { + return 0; + } + return config.getBonusDamagePerNetheritePiece(); + } + + public double getArmourDamageMultiplier(ItemStack m) { + WeaponConfig config = getWeaponConfig(m); + if (config == null) { + return 1; + } + return config.getArmourDamageMultiplier(); + } } diff --git a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/overlay/ScoreboardHUD.java b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/overlay/ScoreboardHUD.java index 1333982e9..7555617c7 100644 --- a/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/overlay/ScoreboardHUD.java +++ b/plugins/finale-paper/src/main/java/com/github/maxopoly/finale/overlay/ScoreboardHUD.java @@ -222,7 +222,7 @@ public class ScoreboardHUD implements Listener { if (damageable == null) { return null; } - int maxDura = is.getType().getMaxDurability(); + int maxDura = damageable.hasMaxDamage() ? damageable.getMaxDamage() : is.getType().getMaxDurability(); int damage = damageable.getDamage(); int remainingHealth = maxDura - damage; float damagedRatio = ((float) remainingHealth) / maxDura; diff --git a/plugins/finale-paper/src/main/resources/config.yml b/plugins/finale-paper/src/main/resources/config.yml index ad1659324..f6bfb438f 100644 --- a/plugins/finale-paper/src/main/resources/config.yml +++ b/plugins/finale-paper/src/main/resources/config.yml @@ -298,6 +298,8 @@ invulnerableTicks: PROJECTILE: 1 ENTITY_ATTACK: 10 +netheriteFireResistance: false + # the warp fruit will roll back to 7 seconds ago warpFruit: # logSize * logInterval = how far back in time you go logSize: 35 # log queue size diff --git a/plugins/heliodor-paper/build.gradle.kts b/plugins/heliodor-paper/build.gradle.kts new file mode 100644 index 000000000..e46f3ee20 --- /dev/null +++ b/plugins/heliodor-paper/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + id("io.papermc.paperweight.userdev") +} + +version = "1.0.0" + +dependencies { + paperweight { + paperDevBundle("1.21.1-R0.1-SNAPSHOT") + } + + compileOnly(project(":plugins:civmodcore-paper")) +} diff --git a/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/AnvilRepairListener.java b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/AnvilRepairListener.java new file mode 100644 index 000000000..27f23b4f0 --- /dev/null +++ b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/AnvilRepairListener.java @@ -0,0 +1,37 @@ +package net.civmc.heliodor; + +import com.destroystokyo.paper.event.inventory.PrepareResultEvent; +import org.bukkit.NamespacedKey; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.inventory.AnvilInventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.java.JavaPlugin; + +public class AnvilRepairListener implements Listener { + + private static final NamespacedKey NO_COMBINE = new NamespacedKey(JavaPlugin.getPlugin(HeliodorPlugin.class), "no_combine"); + + @EventHandler + public void on(PrepareResultEvent event) { + if (!(event.getInventory() instanceof AnvilInventory inventory)) { + return; + } + + ItemStack firstItem = inventory.getFirstItem(); + ItemStack secondItem = inventory.getSecondItem(); + if (firstItem != null && firstItem.getPersistentDataContainer().has(NO_COMBINE)) { + if (secondItem != null && !secondItem.isEmpty()) { + event.setResult(null); + } + } else if (secondItem != null && secondItem.getPersistentDataContainer().has(NO_COMBINE)) { + event.setResult(null); + } + } + + public static void setNoCombine(ItemMeta meta) { + meta.getPersistentDataContainer().set(NO_COMBINE, PersistentDataType.BOOLEAN, true); + } +} diff --git a/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/ChunkPos.java b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/ChunkPos.java new file mode 100644 index 000000000..95ebcd5f4 --- /dev/null +++ b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/ChunkPos.java @@ -0,0 +1,5 @@ +package net.civmc.heliodor; + +public record ChunkPos(int x, int z) { + +} diff --git a/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/HeliodorPlugin.java b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/HeliodorPlugin.java new file mode 100644 index 000000000..39bed4307 --- /dev/null +++ b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/HeliodorPlugin.java @@ -0,0 +1,41 @@ +package net.civmc.heliodor; + +import net.civmc.heliodor.backpack.BackpackListener; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import vg.civcraft.mc.civmodcore.ACivMod; +import vg.civcraft.mc.civmodcore.dao.ManagedDatasource; + +public class HeliodorPlugin extends ACivMod { + + private ManagedDatasource database; + private HeliodorRecipeGiver recipes; + private NamespacedKey oreLocationsKey; + + @Override + public void onLoad() { + this.recipes = new HeliodorRecipeGiver(this); + } + + @Override + public void onEnable() { + super.onEnable(); + + saveDefaultConfig(); + + Bukkit.getScheduler().runTaskTimer(this, this.recipes, 15 * 20, 15 * 20); + + getServer().getPluginManager().registerEvents(new AnvilRepairListener(), this); + + getServer().getPluginManager().registerEvents(new BackpackListener(), this); + } + + public HeliodorRecipeGiver getRecipes() { + return recipes; + } + + @Override + public void onDisable() { + super.onDisable(); + } +} diff --git a/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/HeliodorRecipeGiver.java b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/HeliodorRecipeGiver.java new file mode 100644 index 000000000..c2e49343a --- /dev/null +++ b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/HeliodorRecipeGiver.java @@ -0,0 +1,61 @@ +package net.civmc.heliodor; + +import net.civmc.heliodor.backpack.Backpack; +import net.civmc.heliodor.meteoriciron.FactoryUpgrade; +import net.civmc.heliodor.meteoriciron.MeteoricIron; +import net.civmc.heliodor.meteoriciron.MeteoricIronArmour; +import net.civmc.heliodor.meteoriciron.MeteoricIronTools; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.logging.Level; + +public class HeliodorRecipeGiver implements Runnable { + + private final List heliodorRecipes = new ArrayList<>(); + + public HeliodorRecipeGiver(Plugin plugin) { + register(MeteoricIronTools.getRecipes(plugin)); + register(MeteoricIron.getRecipes(plugin)); + register(MeteoricIronArmour.getRecipes(plugin)); + register(Backpack.getRecipes(plugin)); + register(FactoryUpgrade.getRecipes(plugin)); + } + + @Override + public void run() { + try { + if (heliodorRecipes.isEmpty()) { + return; + } + NamespacedKey first = heliodorRecipes.get(ThreadLocalRandom.current().nextInt(heliodorRecipes.size())); + for (Player player : Bukkit.getOnlinePlayers()) { + if (!player.hasDiscoveredRecipe(first)) { + for (ItemStack item : player.getInventory().getStorageContents()) { + if ((item != null && !item.isEmpty()) && (MeteoricIron.isNugget(item) + || MeteoricIron.isIngot(item))) { + player.discoverRecipes(heliodorRecipes); + break; + } + } + } + } + } catch (RuntimeException ex) { + JavaPlugin.getPlugin(HeliodorPlugin.class).getLogger().log(Level.WARNING, "Iterating inventories for heliodor", ex); + } + } + + private void register(List recipes) { + for (ShapedRecipe recipe : recipes) { + Bukkit.getServer().addRecipe(recipe); + this.heliodorRecipes.add(recipe.getKey()); + } + } +} diff --git a/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/backpack/Backpack.java b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/backpack/Backpack.java new file mode 100644 index 000000000..dbe80a0ec --- /dev/null +++ b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/backpack/Backpack.java @@ -0,0 +1,51 @@ +package net.civmc.heliodor.backpack; + +import net.civmc.heliodor.HeliodorPlugin; +import net.civmc.heliodor.meteoriciron.MeteoricIron; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.recipe.CraftingBookCategory; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; +import java.util.List; + +public interface Backpack { + + NamespacedKey BACKPACK_KEY = new NamespacedKey(JavaPlugin.getPlugin(HeliodorPlugin.class), "backpack"); + + static ItemStack createBackpack() { + ItemStack item = new ItemStack(Material.ENDER_CHEST); + ItemMeta meta = item.getItemMeta(); + meta.itemName(Component.text("Backpack", NamedTextColor.YELLOW)); + meta.lore(List.of(Component.text("Can be placed and used like an ender chest,", NamedTextColor.WHITE), + Component.text("but drops its items when you die", NamedTextColor.WHITE), + Component.text("Cannot contain certain PvP items", NamedTextColor.WHITE))); + meta.setFireResistant(true); + meta.getPersistentDataContainer().set(BACKPACK_KEY, PersistentDataType.BOOLEAN, true); + item.setItemMeta(meta); + + return item; + } + + static boolean isBackpack(ItemStack item) { + if (item == null || item.getType() != Material.ENDER_CHEST) { + return false; + } + return item.getItemMeta().getPersistentDataContainer().has(BACKPACK_KEY); + } + + static List getRecipes(Plugin plugin) { + ShapedRecipe recipe = new ShapedRecipe(new NamespacedKey(plugin, "backpack"), Backpack.createBackpack()) + .shape("xxx", "xex", "xxx") + .setIngredient('x', MeteoricIron.createIngot()) + .setIngredient('e', Material.ENDER_CHEST); + recipe.setCategory(CraftingBookCategory.MISC); + return List.of(recipe); + } +} diff --git a/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/backpack/BackpackListener.java b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/backpack/BackpackListener.java new file mode 100644 index 000000000..e43e7d3dc --- /dev/null +++ b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/backpack/BackpackListener.java @@ -0,0 +1,181 @@ +package net.civmc.heliodor.backpack; + +import net.civmc.heliodor.HeliodorPlugin; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; +import org.bukkit.block.EnderChest; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.event.inventory.InventoryOpenEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.java.JavaPlugin; +import java.util.List; + +public class BackpackListener implements Listener { + + public static final NamespacedKey BACKPACK_ENDER_CHEST_KEY = new NamespacedKey(JavaPlugin.getPlugin(HeliodorPlugin.class), "backpack"); + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void on(BlockPlaceEvent event) { + ItemStack item = event.getItemInHand(); + if (!Backpack.isBackpack(item)) { + return; + } + + Block block = event.getBlock(); + EnderChest type = (EnderChest) block.getState(false); + + type.getPersistentDataContainer().set(BACKPACK_ENDER_CHEST_KEY, PersistentDataType.BOOLEAN, true); + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void on(BlockBreakEvent event) { + Block block = event.getBlock(); + if (block.getType() != Material.ENDER_CHEST) { + return; + } + + EnderChest state = (EnderChest) block.getState(false); + + if (!state.getPersistentDataContainer().has(BACKPACK_ENDER_CHEST_KEY)) { + return; + } + + event.setDropItems(false); + block.getWorld().dropItemNaturally(block.getLocation(), Backpack.createBackpack()); + } + + @EventHandler + public void on(PlayerInteractEvent event) { + Action action = event.getAction(); + Block block = event.getClickedBlock(); + if (block == null || block.getType() != Material.ENDER_CHEST || action != Action.RIGHT_CLICK_BLOCK) { + return; + } + + EnderChest state = (EnderChest) block.getState(false); + + if (!state.getPersistentDataContainer().has(BACKPACK_ENDER_CHEST_KEY)) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void on(InventoryOpenEvent event) { + if (!isBackpackInventory(event.getInventory())) { + return; + } + + event.titleOverride(Component.text("Backpack")); + } + + @EventHandler + public void on(InventoryClickEvent event) { + if (!isBackpackInventory(event.getInventory())) { + return; + } + + switch (event.getAction()) { + case PLACE_ALL, PLACE_ONE, PLACE_SOME, SWAP_WITH_CURSOR, DROP_ALL_CURSOR, DROP_ONE_CURSOR -> { + if (event.getInventory() == event.getClickedInventory() && isIllegalItem(event.getCursor())) { + event.setCancelled(true); + } + } + case MOVE_TO_OTHER_INVENTORY -> { + if (event.getInventory() != event.getClickedInventory() && isIllegalItem(event.getCurrentItem())) { + event.setCancelled(true); + } + } + case HOTBAR_SWAP -> { + if (isIllegalItem(event.getWhoClicked().getInventory().getStorageContents()[event.getHotbarButton()])) { + event.setCancelled(true); + } + } + } + } + + @EventHandler + public void on(InventoryDragEvent event) { + if (!isBackpackInventory(event.getInventory())) { + return; + } + + if (isIllegalItem(event.getOldCursor())) { + for (int slot : event.getRawSlots()) { + if (slot < 27) { + event.setCancelled(true); + break; + } + } + } + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void on(PlayerDeathEvent event) { + Inventory enderChest = event.getPlayer().getEnderChest(); + for (ItemStack item : enderChest.getStorageContents()) { + if (item != null && !item.isEmpty()) { + event.getDrops().add(item); + } + } + enderChest.clear(); + } + + private boolean isBackpackInventory(Inventory inventory) { + if (inventory.getLocation() == null) { + return false; + } + + Block block = inventory.getLocation().getBlock(); + if (block.getType() != Material.ENDER_CHEST) { + return false; + } + + if (!((EnderChest) block.getState(false)).getPersistentDataContainer().has(BACKPACK_ENDER_CHEST_KEY)) { + return false; + } + return true; + } + + private boolean isIllegalItem(ItemStack item) { + if (item == null || item.isEmpty()) { + return false; + } + List lore = item.lore(); + if (lore != null && !lore.isEmpty()) { + if (PlainTextComponentSerializer.plainText().serialize(lore.getFirst()).equals("Compacted Item")) { + return true; + } + } + switch (item.getType()) { + case OBSIDIAN, + CRYING_OBSIDIAN, + RESPAWN_ANCHOR, + ENDER_PEARL, + NETHERITE_BLOCK, + ENDER_CHEST, + GOLDEN_APPLE, + ENCHANTED_GOLDEN_APPLE, + ANCIENT_DEBRIS, + CHORUS_FRUIT: + return true; + } + if (item.getMaxStackSize() == 1) { + return true; + } + return false; + } +} diff --git a/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/meteoriciron/FactoryUpgrade.java b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/meteoriciron/FactoryUpgrade.java new file mode 100644 index 000000000..42aff0bcd --- /dev/null +++ b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/meteoriciron/FactoryUpgrade.java @@ -0,0 +1,54 @@ +package net.civmc.heliodor.meteoriciron; + +import net.civmc.heliodor.AnvilRepairListener; +import net.civmc.heliodor.HeliodorPlugin; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.ItemRarity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.inventory.meta.Damageable; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; +import vg.civcraft.mc.civmodcore.inventory.CustomItem; +import java.util.List; + +public interface FactoryUpgrade { + + static ItemStack createUpgrade() { + ItemStack upgrade = new ItemStack(Material.REDSTONE_TORCH); + Damageable meta = (Damageable) upgrade.getItemMeta(); + + meta.displayName(Component.text("Factory Upgrade", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC, false)); + meta.setRarity(ItemRarity.EPIC); + meta.lore(List.of( + Component.text("Factories can be upgraded with one of two paths", NamedTextColor.AQUA).decoration(TextDecoration.ITALIC, false), + Component.text("Charcoal consumption: ", NamedTextColor.GOLD).append(Component.text("1/4 -> 1/8 -> 1/12 -> 1/16", NamedTextColor.YELLOW)).decoration(TextDecoration.ITALIC, false), + Component.text("Factory speed: ", NamedTextColor.GOLD).append(Component.text("x2 -> x3 -> x4 -> x5", NamedTextColor.YELLOW)).decoration(TextDecoration.ITALIC, false) + )); + meta.setFireResistant(true); + meta.setEnchantmentGlintOverride(true); + AnvilRepairListener.setNoCombine(meta); + upgrade.setItemMeta(meta); + CustomItem.registerCustomItem("factory_upgrade", upgrade); + return upgrade; + } + + + static List getRecipes(Plugin plugin) { + ItemStack upgrade = FactoryUpgrade.createUpgrade(); + upgrade.setAmount(3); + return List.of( + new ShapedRecipe(new NamespacedKey(plugin, "factory_upgrade"), upgrade) + .shape("#c#", "#r#", "#f#") + .setIngredient('#', MeteoricIron.createIngot()) + .setIngredient('c', Material.CHEST) + .setIngredient('r', Material.CRAFTING_TABLE) + .setIngredient('f', Material.FURNACE) + ); + } +} diff --git a/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/meteoriciron/MeteoricIron.java b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/meteoriciron/MeteoricIron.java new file mode 100644 index 000000000..08299a48b --- /dev/null +++ b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/meteoriciron/MeteoricIron.java @@ -0,0 +1,65 @@ +package net.civmc.heliodor.meteoriciron; + +import net.civmc.heliodor.HeliodorPlugin; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.recipe.CraftingBookCategory; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; +import vg.civcraft.mc.civmodcore.inventory.CustomItem; + +import java.util.List; + +public interface MeteoricIron { + + static ItemStack createMeteoricIronNugget() { + ItemStack item = new ItemStack(Material.IRON_NUGGET); + ItemMeta meta = item.getItemMeta(); + meta.itemName(Component.text("Meteoric Iron Nugget", NamedTextColor.AQUA)); + meta.lore(List.of(Component.text("A buried fragment from another world", NamedTextColor.WHITE), + Component.text("Used for its unique magical properties", NamedTextColor.WHITE))); + meta.setEnchantmentGlintOverride(true); + meta.setFireResistant(true); + item.setItemMeta(meta); + CustomItem.registerCustomItem("meteoric_iron_nugget", item); + + return item; + } + + static ItemStack createIngot() { + ItemStack item = new ItemStack(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); + ItemMeta meta = item.getItemMeta(); + meta.itemName(Component.text("Meteoric Iron Ingot", NamedTextColor.LIGHT_PURPLE)); + meta.lore(List.of(Component.text("A buried fragment from another world", NamedTextColor.WHITE), + Component.text("Used for its unique magical properties", NamedTextColor.WHITE))); + meta.setEnchantmentGlintOverride(true); + meta.setFireResistant(true); + item.setItemMeta(meta); + CustomItem.registerCustomItem("meteoric_iron_ingot", item); + + return item; + } + + + static boolean isNugget(ItemStack item) { + return CustomItem.isCustomItem(item, "meteoric_iron_nugget"); + } + + static boolean isIngot(ItemStack item) { + return CustomItem.isCustomItem(item, "meteoric_iron_ingot"); + } + + static List getRecipes(Plugin plugin) { + ShapedRecipe recipe = new ShapedRecipe(new NamespacedKey(plugin, "meteoric_iron_ingot"), MeteoricIron.createIngot()) + .shape("xxx", "xxx", "xxx") + .setIngredient('x', MeteoricIron.createMeteoricIronNugget()); + recipe.setCategory(CraftingBookCategory.MISC); + return List.of(recipe); + } +} diff --git a/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/meteoriciron/MeteoricIronArmour.java b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/meteoriciron/MeteoricIronArmour.java new file mode 100644 index 000000000..1d2653a6a --- /dev/null +++ b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/meteoriciron/MeteoricIronArmour.java @@ -0,0 +1,142 @@ +package net.civmc.heliodor.meteoriciron; + +import java.util.List; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import net.civmc.heliodor.AnvilRepairListener; +import net.civmc.heliodor.HeliodorPlugin; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.EquipmentSlotGroup; +import org.bukkit.inventory.ItemRarity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.inventory.meta.Damageable; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.recipe.CraftingBookCategory; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; +import vg.civcraft.mc.civmodcore.inventory.CustomItem; + +@SuppressWarnings("UnstableApiUsage") +public interface MeteoricIronArmour { + + int CHESPLATE_DURABILITY = 9648; + + static ItemStack createHelmet() { + ItemStack item = new ItemStack(Material.IRON_HELMET); + Damageable meta = (Damageable) item.getItemMeta(); + + meta.displayName(Component.text("Meteoric Iron Helmet", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC, false)); + meta.setRarity(ItemRarity.EPIC); + meta.setMaxDamage(CHESPLATE_DURABILITY * 11 / 16); + meta.addEnchant(Enchantment.UNBREAKING, 5, false); + meta.addEnchant(Enchantment.RESPIRATION, 3, false); + meta.addEnchant(Enchantment.AQUA_AFFINITY, 1, false); + meta.addEnchant(Enchantment.PROTECTION, 4, false); + meta.addEnchant(Enchantment.BLAST_PROTECTION, 4, false); + meta.setFireResistant(true); + setAttributes(meta, 3, 2, 0.03, "helmet", EquipmentSlotGroup.HEAD); + AnvilRepairListener.setNoCombine(meta); + item.setItemMeta(meta); + CustomItem.registerCustomItem("meteoric_iron_helmet", item); + return item; + } + + static ItemStack createChestplate() { + ItemStack item = new ItemStack(Material.IRON_CHESTPLATE); + Damageable meta = (Damageable) item.getItemMeta(); + + meta.displayName(Component.text("Meteoric Iron Chestplate", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC, false)); + meta.setRarity(ItemRarity.EPIC); + meta.setMaxDamage(CHESPLATE_DURABILITY); + meta.addEnchant(Enchantment.UNBREAKING, 5, false); + meta.addEnchant(Enchantment.PROTECTION, 4, false); + meta.addEnchant(Enchantment.BLAST_PROTECTION, 4, false); + meta.setFireResistant(true); + setAttributes(meta, 8, 2, 0.03, "chestplate", EquipmentSlotGroup.CHEST); + AnvilRepairListener.setNoCombine(meta); + item.setItemMeta(meta); + CustomItem.registerCustomItem("meteoric_iron_chestplate", item); + return item; + } + + static ItemStack createLeggings() { + ItemStack item = new ItemStack(Material.IRON_LEGGINGS); + Damageable meta = (Damageable) item.getItemMeta(); + + meta.displayName(Component.text("Meteoric Iron Leggings", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC, false)); + meta.setRarity(ItemRarity.EPIC); + meta.setMaxDamage(CHESPLATE_DURABILITY * 15 / 16); + meta.addEnchant(Enchantment.UNBREAKING, 5, false); + meta.addEnchant(Enchantment.SWIFT_SNEAK, 3, false); + meta.addEnchant(Enchantment.PROTECTION, 4, false); + meta.addEnchant(Enchantment.BLAST_PROTECTION, 4, false); + meta.setFireResistant(true); + setAttributes(meta, 6, 2, 0.03, "leggings", EquipmentSlotGroup.LEGS); + AnvilRepairListener.setNoCombine(meta); + item.setItemMeta(meta); + CustomItem.registerCustomItem("meteoric_iron_leggings", item); + return item; + } + + static ItemStack createBoots() { + ItemStack item = new ItemStack(Material.IRON_BOOTS); + Damageable meta = (Damageable) item.getItemMeta(); + + meta.displayName(Component.text("Meteoric Iron Boots", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC, false)); + meta.setRarity(ItemRarity.EPIC); + meta.setMaxDamage(CHESPLATE_DURABILITY * 13 / 16); + meta.addEnchant(Enchantment.UNBREAKING, 5, false); + meta.addEnchant(Enchantment.FEATHER_FALLING, 5, false); + meta.addEnchant(Enchantment.DEPTH_STRIDER, 5, false); + meta.addEnchant(Enchantment.PROTECTION, 4, false); + meta.addEnchant(Enchantment.BLAST_PROTECTION, 4, false); + meta.setFireResistant(true); + setAttributes(meta, 3, 2, 0.03, "boots", EquipmentSlotGroup.FEET); + AnvilRepairListener.setNoCombine(meta); + item.setItemMeta(meta); + CustomItem.registerCustomItem("meteoric_iron_boots", item); + return item; + } + + private static void setAttributes(ItemMeta meta, int armour, int toughness, double speed, String name, EquipmentSlotGroup group) { + String prefix = "meteoric_iron_" + name; + Multimap ams = HashMultimap.create(); + HeliodorPlugin plugin = JavaPlugin.getPlugin(HeliodorPlugin.class); + ams.put(Attribute.GENERIC_ARMOR, new AttributeModifier(new NamespacedKey(plugin, prefix + "_armour"), armour, AttributeModifier.Operation.ADD_NUMBER, group)); + ams.put(Attribute.GENERIC_ARMOR_TOUGHNESS, new AttributeModifier(new NamespacedKey(plugin, prefix + "_toughness"), toughness, AttributeModifier.Operation.ADD_NUMBER, group)); + ams.put(Attribute.GENERIC_MOVEMENT_SPEED, new AttributeModifier(new NamespacedKey(plugin, prefix + "_speed"), speed, AttributeModifier.Operation.MULTIPLY_SCALAR_1, group)); + meta.setAttributeModifiers(ams); + + meta.getPersistentDataContainer().set(new NamespacedKey("finale", "custom_armour"), PersistentDataType.STRING, prefix); + } + + static List getRecipes(Plugin plugin) { + return List.of( + categoryEquipment(new ShapedRecipe(new NamespacedKey(plugin, "meteoric_iron_helmet"), MeteoricIronArmour.createHelmet()) + .shape("xxx", "x x") + .setIngredient('x', MeteoricIron.createIngot())), + categoryEquipment(new ShapedRecipe(new NamespacedKey(plugin, "meteoric_iron_chestplate"), MeteoricIronArmour.createChestplate()) + .shape("x x", "xxx", "xxx") + .setIngredient('x', MeteoricIron.createIngot())), + categoryEquipment(new ShapedRecipe(new NamespacedKey(plugin, "meteoric_iron_leggings"), MeteoricIronArmour.createLeggings()) + .shape("xxx", "x x", "x x") + .setIngredient('x', MeteoricIron.createIngot())), + categoryEquipment(new ShapedRecipe(new NamespacedKey(plugin, "meteoric_iron_boots"), MeteoricIronArmour.createBoots()) + .shape("x x", "x x") + .setIngredient('x', MeteoricIron.createIngot()))); + } + + private static ShapedRecipe categoryEquipment(ShapedRecipe recipe) { + recipe.setCategory(CraftingBookCategory.EQUIPMENT); + return recipe; + } +} diff --git a/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/meteoriciron/MeteoricIronTools.java b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/meteoriciron/MeteoricIronTools.java new file mode 100644 index 000000000..1b2703838 --- /dev/null +++ b/plugins/heliodor-paper/src/main/java/net/civmc/heliodor/meteoriciron/MeteoricIronTools.java @@ -0,0 +1,168 @@ +package net.civmc.heliodor.meteoriciron; + +import net.civmc.heliodor.AnvilRepairListener; +import net.civmc.heliodor.HeliodorPlugin; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.EquipmentSlotGroup; +import org.bukkit.inventory.ItemRarity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.inventory.meta.Damageable; +import org.bukkit.inventory.meta.components.ToolComponent; +import org.bukkit.inventory.recipe.CraftingBookCategory; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; +import vg.civcraft.mc.civmodcore.inventory.CustomItem; +import java.util.List; + +@SuppressWarnings("UnstableApiUsage") +public interface MeteoricIronTools { + + int DURABILITY = 48_600; + + static ItemStack createPickaxe(boolean silk) { + ItemStack pickaxe = new ItemStack(Material.IRON_PICKAXE); + Damageable meta = (Damageable) pickaxe.getItemMeta(); + + meta.displayName(Component.text("Meteoric Iron Pickaxe", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC, false)); + meta.setRarity(ItemRarity.EPIC); + meta.lore(List.of( + Component.text("Instantly breaks deepslate and stone,", NamedTextColor.WHITE), + Component.text("and otherwise equivalent to diamond", NamedTextColor.WHITE))); + ToolComponent tool = meta.getTool(); + tool.setDamagePerBlock(1); + tool.addRule(Tag.BASE_STONE_OVERWORLD, 1000f, true); + tool.addRule(Tag.MINEABLE_PICKAXE, 8f, true); + meta.setTool(tool); + meta.setMaxDamage(DURABILITY); + meta.addEnchant(Enchantment.EFFICIENCY, 5, false); + if (silk) { + meta.addEnchant(Enchantment.SILK_TOUCH, 1, false); + } else { + meta.addEnchant(Enchantment.FORTUNE, 3, false); + } + meta.setFireResistant(true); + AnvilRepairListener.setNoCombine(meta); + pickaxe.setItemMeta(meta); + CustomItem.registerCustomItem("meteoric_iron_pickaxe", pickaxe); + return pickaxe; + } + + static ItemStack createAxe(boolean silk) { + ItemStack axe = new ItemStack(Material.IRON_AXE); + Damageable meta = (Damageable) axe.getItemMeta(); + + meta.displayName(Component.text("Meteoric Iron Axe", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC, false)); + meta.setRarity(ItemRarity.EPIC); + meta.lore(List.of( + Component.text("Instantly breaks many wood products,", NamedTextColor.WHITE), + Component.text("and can break some iron ones too", NamedTextColor.WHITE))); + ToolComponent tool = meta.getTool(); + tool.setDamagePerBlock(1); + tool.addRule(Material.CHEST, 1000f, true); + tool.addRule(Material.TRAPPED_CHEST, 1000f, true); + tool.addRule(Tag.FENCE_GATES, 1000f, true); + tool.addRule(Tag.WOODEN_PRESSURE_PLATES, 1000f, true); + tool.addRule(Tag.LOGS, 1000f, true); + tool.addRule(Material.JUKEBOX, 1000f, true); + tool.addRule(Material.BARREL, 1000f, true); + tool.addRule(Tag.WOODEN_TRAPDOORS, 1000f, true); + tool.addRule(Tag.WOODEN_FENCES, 1000f, true); + tool.addRule(Tag.WOODEN_DOORS, 1000f, true); + // 2 ticks for iron stuff + tool.addRule(Material.IRON_DOOR, 50f, true); + tool.addRule(Material.IRON_TRAPDOOR, 50f, true); + tool.addRule(Material.IRON_BARS, 50f, true); + tool.addRule(Material.DISPENSER, 50f, true); + tool.addRule(Material.DROPPER, 50f, true); + tool.addRule(Material.HOPPER, 50f, true); + tool.addRule(Tag.MINEABLE_AXE, 8f, true); + meta.setTool(tool); + meta.setMaxDamage(DURABILITY); + meta.addEnchant(Enchantment.EFFICIENCY, 5, false); + if (silk) { + meta.addEnchant(Enchantment.SILK_TOUCH, 1, false); + } else { + meta.addEnchant(Enchantment.FORTUNE, 3, false); + } + meta.setFireResistant(true); + AnvilRepairListener.setNoCombine(meta); + axe.setItemMeta(meta); + CustomItem.registerCustomItem("meteoric_iron_axe", axe); + return axe; + } + + static ItemStack createSword(boolean knocback) { + ItemStack sword = new ItemStack(Material.IRON_SWORD); + Damageable meta = (Damageable) sword.getItemMeta(); + + meta.displayName(Component.text("Meteoric Iron Sword", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC, false)); + meta.setRarity(ItemRarity.EPIC); + meta.lore(List.of( + Component.text("+0.75 damage for each piece of netherite", NamedTextColor.WHITE), + Component.text("armour the opponent is wearing", NamedTextColor.WHITE), + Component.text("Instantly breaks cobwebs", NamedTextColor.WHITE))); + ToolComponent tool = meta.getTool(); + tool.setDamagePerBlock(1); + tool.addRule(Material.COBWEB, 200f, true); + meta.setTool(tool); + meta.setMaxDamage(DURABILITY); + meta.addEnchant(Enchantment.FIRE_ASPECT, 2, false); + if (knocback) { + meta.addEnchant(Enchantment.KNOCKBACK, 2, false); + } else { + meta.addEnchant(Enchantment.SHARPNESS, 5, false); + } + meta.setFireResistant(true); + AnvilRepairListener.setNoCombine(meta); + sword.setItemMeta(meta); + CustomItem.registerCustomItem("meteoric_iron_sword", sword); + return sword; + } + + static List getRecipes(Plugin plugin) { + return List.of( + categoryEquipment(new ShapedRecipe(new NamespacedKey(plugin, "meteoric_iron_pickaxe_silk_touch"), MeteoricIronTools.createPickaxe(true)) + .shape("xxx", "asa", "asa") + .setIngredient('x', MeteoricIron.createIngot()) + .setIngredient('a', Material.AMETHYST_SHARD) + .setIngredient('s', Material.STICK)), + categoryEquipment(new ShapedRecipe(new NamespacedKey(plugin, "meteoric_iron_pickaxe_fortune"), MeteoricIronTools.createPickaxe(false)) + .shape("xxx", " s ", " s ") + .setIngredient('x', MeteoricIron.createIngot()) + .setIngredient('s', Material.STICK)), + categoryEquipment(new ShapedRecipe(new NamespacedKey(plugin, "meteoric_iron_axe_silk_touch"), MeteoricIronTools.createAxe(true)) + .shape("xxa", "xs ", "as ") + .setIngredient('x', MeteoricIron.createIngot()) + .setIngredient('a', Material.AMETHYST_SHARD) + .setIngredient('s', Material.STICK)), + categoryEquipment(new ShapedRecipe(new NamespacedKey(plugin, "meteoric_iron_axe_fortune"), MeteoricIronTools.createAxe(false)) + .shape("xx ", "xs ", " s ") + .setIngredient('x', MeteoricIron.createIngot()) + .setIngredient('s', Material.STICK)), + categoryEquipment(new ShapedRecipe(new NamespacedKey(plugin, "meteoric_iron_sword_knockback"), MeteoricIronTools.createSword(true)) + .shape("axa", " x ", " s ") + .setIngredient('x', MeteoricIron.createIngot()) + .setIngredient('a', Material.AMETHYST_SHARD) + .setIngredient('s', Material.STICK)), + categoryEquipment(new ShapedRecipe(new NamespacedKey(plugin, "meteoric_iron_sword_sharpness"), MeteoricIronTools.createSword(false)) + .shape(" x ", " x ", " s ") + .setIngredient('x', MeteoricIron.createIngot()) + .setIngredient('s', Material.STICK)) + ); + } + + private static ShapedRecipe categoryEquipment(ShapedRecipe recipe) { + recipe.setCategory(CraftingBookCategory.EQUIPMENT); + return recipe; + } +} diff --git a/plugins/heliodor-paper/src/main/resources/plugin.yml b/plugins/heliodor-paper/src/main/resources/plugin.yml new file mode 100644 index 000000000..d921e34bb --- /dev/null +++ b/plugins/heliodor-paper/src/main/resources/plugin.yml @@ -0,0 +1,7 @@ +name: Heliodor +version: ${version} +main: net.civmc.heliodor.HeliodorPlugin +author: Okx +api-version: 1.21 +description: Implements various mechanics relating to custom ores, separately from HiddenOre +depend: [CivModCore] diff --git a/settings.gradle.kts b/settings.gradle.kts index f9fa3ac47..5d28f0a9b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -32,3 +32,4 @@ include(":plugins:namecolors-paper") include(":plugins:kirabukkitgateway-paper") include(":plugins:kitpvp-paper") include(":plugins:voidworld-paper") +include(":plugins:heliodor-paper")