added ender armour, need to polish thing and give the ingot an item model - disabled at eagerLoad for now

This commit is contained in:
2026-07-12 00:04:56 +01:00
parent fe04526040
commit e58470c0cc
23 changed files with 291 additions and 153 deletions
@@ -0,0 +1,32 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_addition": {
"conditions": {
"items": [
{
"items": "minecraft:wither_skeleton_skull"
}
]
},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {
"conditions": {
"recipe": "fantasysmp:witherite_shield"
},
"trigger": "minecraft:recipe_unlocked"
}
},
"requirements": [
[
"has_the_recipe",
"has_addition"
]
],
"rewards": {
"recipes": [
"fantasysmp:witherite_shield"
]
}
}
@@ -0,0 +1,37 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_ingredient": {
"conditions": {
"items": [
{
"items": [
"minecraft:shulker_shell",
"fantasysmp:dragon_scale",
"minecraft:dragon_breath",
"minecraft:chorus_fruit"
]
}
]
},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {
"conditions": {
"recipe": "fantasysmp:dragonite_ingot"
},
"trigger": "minecraft:recipe_unlocked"
}
},
"requirements": [
[
"has_the_recipe",
"has_ingredient"
]
],
"rewards": {
"recipes": [
"fantasysmp:dragonite_ingot"
]
}
}
@@ -0,0 +1,18 @@
{
"type": "minecraft:crafting_shaped",
"category": "misc",
"key": {
"B": "minecraft:dragon_breath",
"C": "minecraft:chorus_fruit",
"S": "minecraft:shulker_shell",
"X": "fantasysmp:dragon_scale"
},
"pattern": [
"SBS",
"CXC",
"SBS"
],
"result": {
"id": "fantasysmp:dragonite_ingot"
}
}
@@ -1,9 +1,9 @@
{
"type": "minecraft:smithing_transform",
"template": "minecraft:netherite_upgrade_smithing_template",
"base": "minecraft:shield",
"addition": "minecraft:wither_skeleton_skull",
"base": "minecraft:shield",
"result": {
"id": "fantasysmp:witherite_shield"
}
}
},
"template": "minecraft:netherite_upgrade_smithing_template"
}
-16
View File
@@ -3,17 +3,13 @@ package dev.zxq5
import dev.zxq5.items.template.GenericItemSet
import dev.zxq5.items.template.ItemTagAdder
import dev.zxq5.items.ModItems
import dev.zxq5.items.sets.Witherite
//import dev.zxq5.items.sets.Witherite
import net.fabricmc.api.ModInitializer
import net.fabricmc.fabric.api.datagen.v1.FabricPackOutput
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagsProvider
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents
import net.minecraft.core.HolderLookup
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.RecipeProvider
import net.minecraft.world.effect.MobEffects
import org.slf4j.LoggerFactory
import java.util.concurrent.CompletableFuture
@@ -25,18 +21,6 @@ object Fantasysmp : ModInitializer {
override fun onInitialize() {
logger.info("Hello Fabric world!")
ModItems.onLoad();
// Register the group.
registerItemEffects()
}
private fun registerItemEffects() {
ServerTickEvents.END_SERVER_TICK.register { server ->
for (player in server.playerList.players) {
if (Witherite.fullSetEquippedBy(player)) {
player.removeEffect(MobEffects.WITHER)
}
}
}
}
}
@@ -3,6 +3,7 @@ package dev.zxq5.items
import dev.zxq5.Fantasysmp
import dev.zxq5.items.template.GenericItemSet
import dev.zxq5.items.sets.Dragonite
import dev.zxq5.items.sets.Ender
import dev.zxq5.items.sets.Witherite
import net.fabricmc.fabric.api.creativetab.v1.FabricCreativeModeTab
import net.minecraft.core.Registry
@@ -44,6 +45,7 @@ object ModItems {
private val eagerLoad = listOf<GenericItemSet>(
Witherite,
Dragonite,
// Ender // TODO: Enable for content drop #1
)
fun onLoad() {
@@ -5,6 +5,7 @@ import dev.zxq5.items.template.GenericGearSet
import dev.zxq5.items.ModItems.register
import dev.zxq5.items.template.registerItem
import dev.zxq5.items.template.provideDelegate
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents
import net.minecraft.core.component.DataComponents
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.core.particles.PowerParticleOption
@@ -15,6 +16,8 @@ import net.minecraft.util.Unit
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResult
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.damagesource.DamageSources
import net.minecraft.world.damagesource.DamageTypes
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
@@ -32,7 +35,7 @@ object Dragonite: GenericGearSet() {
get() = super.materialDefinition.copy(assetId = materialKey)
val SCALE by registerItem("dragon_scale", ::Item)
val INGOT by registerItem("dragonite_ingot", ::Item) {
shapedRecipe("SBS", "CXC", "SBS", key=mapOf<Char, Item>(
'S' to Items.SHULKER_SHELL,
@@ -83,7 +86,35 @@ object Dragonite: GenericGearSet() {
override val armorSet: ArmorSet = ArmorSet(HELMET, CHESTPLATE, LEGGINGS, BOOTS)
override val items = listOf(SWORD, HELMET, CHESTPLATE, LEGGINGS, BOOTS, SCALE, INGOT)
override fun onLoad() {}
private var reducingCollision: Boolean = false
private const val FALL_DAMAGE_REDUCTION = 0.5f
private const val COLLISION_DAMAGE_REDUCTION = 0.75f // 75% reduction; tune to taste
override fun onLoad() {
ServerLivingEntityEvents.ALLOW_DAMAGE.register { entity, damageSource, amount ->
if (reducingCollision) return@register true // let our own re-applied hit through untouched
if (entity !is Player) return@register true
if (!fullSetEquippedBy(entity)) return@register true
val reduced = when {
damageSource.`is`(DamageTypes.FLY_INTO_WALL) -> amount * (1f - COLLISION_DAMAGE_REDUCTION)
damageSource.`is`(DamageTypes.FALL) -> amount * (1f - COLLISION_DAMAGE_REDUCTION)
else -> return@register false
}
if (reduced > 0f) {
reducingCollision = true
try {
entity.hurtServer(entity.level() as ServerLevel, damageSource, reduced)
return@register false
} finally {
reducingCollision = false
}
}
false
}
}
}
class DragoniteSword(properties: Properties) : Item(properties) {
@@ -111,7 +142,7 @@ class DragoniteSword(properties: Properties) : Item(properties) {
override fun getAttackDamageBonus(victim: Entity, damage: Float, damageSource: DamageSource): Float {
val superBonus = super.getAttackDamageBonus(victim, damage, damageSource) // 0f from vanilla, but respect it anyway
val attacker = damageSource.entity as? Player ?: return superBonus
if (Dragonite.fullSetEquippedBy(attacker)) return superBonus
if (!Dragonite.fullSetEquippedBy(attacker)) return superBonus
if (attacker.level().isClientSide) return superBonus
if (!attacker.isFallFlying) return superBonus
@@ -0,0 +1,145 @@
package dev.zxq5.items.sets
import dev.zxq5.items.template.ArmorSet
import dev.zxq5.items.template.GearMaterialDef
import dev.zxq5.items.template.GenericGearSet
import dev.zxq5.items.template.provideDelegate
import dev.zxq5.items.template.registerItem
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents
import net.minecraft.core.BlockPos
import net.minecraft.core.component.DataComponents
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.server.level.ServerLevel
import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResult
import net.minecraft.world.damagesource.DamageTypes
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
import net.minecraft.world.item.Items
import net.minecraft.world.item.ToolMaterial
import net.minecraft.world.item.component.UseCooldown
import net.minecraft.world.item.equipment.ArmorType
import net.minecraft.world.level.ClipContext
import net.minecraft.world.level.Level
import net.minecraft.world.phys.BlockHitResult
import net.minecraft.world.phys.HitResult
import net.minecraft.world.phys.Vec3
object Ender: GenericGearSet() {
override val materialName = "ender"
override val materialDefinition
get() = GearMaterialDef.DIAMOND.copy(assetId = materialKey)
val ENDER_INGOT by registerItem("ender_ingot", ::Item) {
shapedRecipe("EDE", "DED", "EDE", key=mapOf(
'E' to Items.ENDER_EYE,
'D' to Items.DIAMOND,
))
}
val SWORD by registerItem("ender_sword", ::EnderSword) {
properties {
enchantable(armorMaterial.enchantmentValue)
.component(DataComponents.USE_COOLDOWN, UseCooldown(3f))
.sword(ToolMaterial.DIAMOND, 3F, -2.4F)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.DIAMOND_SWORD, ENDER_INGOT)
}
val HELMET by registerItem("ender_helmet", ::Item) {
properties {
humanoidArmor(armorMaterial, ArmorType.HELMET)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.DIAMOND_HELMET, ENDER_INGOT)
}
val CHESTPLATE by registerItem("ender_chestplate", ::Item) {
properties {
humanoidArmor(armorMaterial, ArmorType.CHESTPLATE)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.DIAMOND_CHESTPLATE, ENDER_INGOT)
}
val LEGGINGS by registerItem("ender_leggings", ::Item) {
properties {
humanoidArmor(armorMaterial, ArmorType.LEGGINGS)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.DIAMOND_LEGGINGS, ENDER_INGOT)
}
val BOOTS by registerItem("ender_boots", ::Item) {
properties {
humanoidArmor(armorMaterial, ArmorType.BOOTS)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.DIAMOND_BOOTS, ENDER_INGOT)
}
override val armorSet: ArmorSet = ArmorSet(HELMET, CHESTPLATE, LEGGINGS, BOOTS)
override val items = listOf(SWORD, HELMET, CHESTPLATE, LEGGINGS, BOOTS)
override fun onLoad() {
ServerLivingEntityEvents.ALLOW_DAMAGE.register { entity, damageSource, _ ->
if (entity !is Player) return@register true
if (!fullSetEquippedBy(entity)) return@register true
if (damageSource.`is`(DamageTypes.ENDER_PEARL)) return@register false
return@register true
}
}
}
class EnderSword(properties: Properties) : Item(properties) {
override fun use(level: Level, user: Player, hand: InteractionHand): InteractionResult {
if (level.isClientSide || !Ender.fullSetEquippedBy(user)) return InteractionResult.PASS
val serverLevel = level as ServerLevel
val hit = getTargetedBlock(user, 64.0)
if (hit.type != HitResult.Type.BLOCK) return InteractionResult.PASS
val state = serverLevel.getBlockState(hit.blockPos)
if (state.isAir) return InteractionResult.PASS
val landingPos = findSafeLanding(serverLevel, hit) ?: return InteractionResult.PASS // no clearance — cancel silently
val oldPos = user.position()
serverLevel.playSound(null, oldPos.x, oldPos.y, oldPos.z, SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 1.0f, 1.0f)
serverLevel.sendParticles(ParticleTypes.PORTAL, oldPos.x, oldPos.y, oldPos.z, 100, 0.5, 1.0, 0.5, 0.0)
val destination = Vec3.atBottomCenterOf(landingPos)
user.setDeltaMovement(user.deltaMovement.x, 0.0, user.deltaMovement.z)
user.teleportTo(destination.x, destination.y, destination.z)
serverLevel.playSound(null, destination.x, destination.y, destination.z, SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 1.0f, 1.0f)
serverLevel.sendParticles(ParticleTypes.PORTAL, destination.x, destination.y, destination.z, 100, 0.5, 1.0, 0.5, 0.0)
return InteractionResult.SUCCESS
}
}
fun getTargetedBlock(player: Player, maxDistance: Double): BlockHitResult {
val start = player.eyePosition
val end = start.add(player.lookAngle.scale(maxDistance))
return player.level().clip(ClipContext(start, end,
ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player))
}
private const val MAX_UPWARD_SEARCH = 256
fun findSafeLanding(level: Level, hit: BlockHitResult): BlockPos? {
var pos = hit.blockPos.above()
repeat(MAX_UPWARD_SEARCH) {
if (isPassable(level, pos) && isPassable(level, pos.above())) {
return pos
}
pos = pos.above()
}
return null // no safe gap found within range — caller should cancel the teleport
}
private fun isPassable(level: Level, pos: BlockPos): Boolean {
val state = level.getBlockState(pos)
return state.getCollisionShape(level, pos).isEmpty
}
@@ -4,6 +4,7 @@ import dev.zxq5.items.template.ArmorSet
import dev.zxq5.items.template.GenericGearSet
import dev.zxq5.items.template.registerItem
import dev.zxq5.items.template.provideDelegate
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents
import net.minecraft.core.component.DataComponents
import net.minecraft.sounds.SoundEvents
import net.minecraft.world.InteractionHand
@@ -49,7 +50,7 @@ object Witherite: GenericGearSet() {
Optional.empty() // default disable sound
))
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.NETHERITE_SWORD, Items.WITHER_SKELETON_SKULL)
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.SHIELD, Items.WITHER_SKELETON_SKULL)
}
val SWORD by registerItem("witherite_sword", ::WitheriteSword) {
@@ -102,7 +103,13 @@ object Witherite: GenericGearSet() {
override val items = listOf(SWORD, AXE, SHIELD, HELMET, CHESTPLATE, LEGGINGS, BOOTS)
override fun onLoad() {
// empty function - this must be called to initialise the above properties ^
ServerTickEvents.END_SERVER_TICK.register { server ->
for (player in server.playerList.players) {
if (fullSetEquippedBy(player)) {
player.removeEffect(MobEffects.WITHER)
}
}
}
}
}
@@ -8,6 +8,7 @@ import net.minecraft.tags.TagKey
import net.minecraft.world.entity.EquipmentSlot
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
import net.minecraft.world.item.ToolMaterial
import net.minecraft.world.item.equipment.ArmorMaterial
import net.minecraft.world.item.equipment.ArmorMaterials
import net.minecraft.world.item.equipment.ArmorType
@@ -24,6 +25,10 @@ abstract class GenericGearSet: GenericItemSet() {
open val materialDefinition: GearMaterialDef
get() = GearMaterialDef.NETHERITE
val toolMaterial: ToolMaterial by lazy {
materialDefinition.toToolMaterial()
}
val armorMaterial: ArmorMaterial by lazy {
materialDefinition.toArmorMaterial()
}
@@ -89,3 +94,6 @@ fun GearMaterialDef.toArmorMaterial(): ArmorMaterial {
)
}
fun GearMaterialDef.toToolMaterial(): ToolMaterial {
TODO()
}
@@ -24,7 +24,7 @@ abstract class GenericItemSet {
// list of all items part of the class
abstract val items: List<Item>
abstract fun onLoad()
open fun onLoad() {}
private val itemRecipes = mutableMapOf<Item, List<RecipeSpec>>()
private val itemTags = mutableMapOf<Item, List<TagKey<Item>>>()
@@ -81,6 +81,7 @@ abstract class GenericItemSet {
fun register(impl: GenericItemSet) = _all.add(impl)
}
}
class CustomItemBuilder<T : Item>(
-10
View File
@@ -1,10 +0,0 @@
{
"type": "minecraft:smithing_transform",
"template": "minecraft:crying_obsidian",
"base": "minecraft:netherite_boots",
"addition": "fantasysmp:dragonite_ingot",
"result": {
"id": "fantasysmp:dragonite_boots"
}
}
@@ -1,9 +0,0 @@
{
"type": "minecraft:smithing_transform",
"template": "minecraft:elytra",
"base": "minecraft:netherite_chestplate",
"addition": "fantasysmp:dragonite_ingot",
"result": {
"id": "fantasysmp:dragonite_chestplate"
}
}
-9
View File
@@ -1,9 +0,0 @@
{
"type": "minecraft:smithing_transform",
"template": "minecraft:dragon_head",
"base": "minecraft:netherite_helmet",
"addition": "fantasysmp:dragonite_ingot",
"result": {
"id": "fantasysmp:dragonite_helmet"
}
}
-27
View File
@@ -1,27 +0,0 @@
{
"type": "minecraft:crafting_shaped",
"ingredients": [
"minecraft:dragon_breath",
"fantasysmp:dragon_scale"
],
"pattern": [
"SBS",
"CXC",
"SBS"
],
"key": {
"S": [
"minecraft:shulker_shell"
],
"B": [
"minecraft:dragon_breath"
],
"C": [
"minecraft:chorus_fruit"
],
"X": [
"fantasysmp:dragon_scale"
]
},
"result": "fantasysmp:dragonite_ingot"
}
@@ -1,9 +0,0 @@
{
"type": "minecraft:smithing_transform",
"template": "minecraft:crying_obsidian",
"base": "minecraft:netherite_leggings",
"addition": "fantasysmp:dragonite_ingot",
"result": {
"id": "fantasysmp:dragonite_leggings"
}
}
-9
View File
@@ -1,9 +0,0 @@
{
"type": "minecraft:smithing_transform",
"template": "minecraft:end_crystal",
"base": "minecraft:netherite_sword",
"addition": "fantasysmp:dragonite_ingot",
"result": {
"id": "fantasysmp:dragonite_sword"
}
}
-9
View File
@@ -1,9 +0,0 @@
{
"type": "minecraft:smithing_transform",
"template": "minecraft:netherite_upgrade_smithing_template",
"base": "minecraft:netherite_axe",
"addition": "minecraft:wither_skeleton_skull",
"result": {
"id": "fantasysmp:witherite_axe"
}
}
-9
View File
@@ -1,9 +0,0 @@
{
"type": "minecraft:smithing_transform",
"template": "minecraft:netherite_upgrade_smithing_template",
"base": "minecraft:netherite_boots",
"addition": "minecraft:wither_skeleton_skull",
"result": {
"id": "fantasysmp:witherite_boots"
}
}
@@ -1,9 +0,0 @@
{
"type": "minecraft:smithing_transform",
"template": "minecraft:netherite_upgrade_smithing_template",
"base": "minecraft:netherite_chestplate",
"addition": "minecraft:wither_skeleton_skull",
"result": {
"id": "fantasysmp:witherite_chestplate"
}
}
-9
View File
@@ -1,9 +0,0 @@
{
"type": "minecraft:smithing_transform",
"template": "minecraft:netherite_upgrade_smithing_template",
"base": "minecraft:netherite_helmet",
"addition": "minecraft:wither_skeleton_skull",
"result": {
"id": "fantasysmp:witherite_helmet"
}
}
@@ -1,9 +0,0 @@
{
"type": "minecraft:smithing_transform",
"template": "minecraft:netherite_upgrade_smithing_template",
"base": "minecraft:netherite_leggings",
"addition": "minecraft:wither_skeleton_skull",
"result": {
"id": "fantasysmp:witherite_leggings"
}
}
-9
View File
@@ -1,9 +0,0 @@
{
"type": "minecraft:smithing_transform",
"template": "minecraft:netherite_upgrade_smithing_template",
"base": "minecraft:netherite_sword",
"addition": "minecraft:wither_skeleton_skull",
"result": {
"id": "fantasysmp:witherite_sword"
}
}