11 Commits

Author SHA1 Message Date
zxq5 3dc064fab6 fixed build
build / build (push) Failing after 3m36s
2026-07-13 23:38:19 +01:00
zxq5 cad49095b4 README
build / build (push) Has been cancelled
2026-07-13 23:33:37 +01:00
zxq5 a1c4fe3edf removed build files 2026-07-13 23:30:37 +01:00
zxq5 e7af04418b basically done with data generation now. model generation is pretty much fully working/automated
build / build (push) Failing after 3m31s
2026-07-13 23:28:54 +01:00
zxq5 e58470c0cc added ender armour, need to polish thing and give the ingot an item model - disabled at eagerLoad for now 2026-07-12 00:04:56 +01:00
zxq5 fe04526040 item builder DSL framework completed and seems to work. custom tag and model generation don't work yet. don't uncomment the tag generation code as it causes a stack overflow crash ⚠️ 2026-07-11 22:21:17 +01:00
zxq5 5b57baafb1 custom items now use new builder DSL syntax, implementing first new set begins tmr
build / build (push) Failing after 3m16s
2026-07-08 00:58:10 +01:00
zxq5 5f6350943e new item builder kinda works. making sure everything is moved across, then i gotta start on the new set
build / build (push) Failing after 3m33s
2026-07-08 00:34:10 +01:00
zxq5 08c1800cac maybe fixed CI, not sure if these actions work on gitea tho
build / build (push) Failing after 7m33s
2026-07-06 07:21:03 +01:00
zxq5 db1f6cc5ae slightly broken but very refactored. TODO: make the code that should run on the clientside run on the clientside
build / build (push) Has been cancelled
2026-07-06 07:14:36 +01:00
zxq5 d392be38c5 1.0.0 beta ready to deploy
build / build (push) Has been cancelled
2026-07-01 22:32:27 +01:00
135 changed files with 1032 additions and 1174 deletions
@@ -8,7 +8,7 @@ on: [pull_request, push]
jobs: jobs:
build: build:
runs-on: ubuntu-24.04 runs-on: zqsrv-builder
steps: steps:
- name: checkout repository - name: checkout repository
uses: actions/checkout@v6 uses: actions/checkout@v6
+1
View File
@@ -38,3 +38,4 @@ hs_err_*.log
replay_*.log replay_*.log
*.hprof *.hprof
*.jfr *.jfr
/src/main/generated/
+5 -8
View File
@@ -1,9 +1,6 @@
# fantasysmp # FantasySMP
## Setup custom items mod.
as of writing this readme, includes:
For setup instructions, please see the [Fabric Documentation page](https://docs.fabricmc.net/develop/getting-started/creating-a-project#setting-up) related to the IDE that you are using. - Witherite Gear
- Dragonite Gear
## License
This template is available under the CC0 license. Feel free to learn from it and incorporate it in your own projects.
+5 -2
View File
@@ -49,6 +49,7 @@ tasks.processResources {
val version = version val version = version
inputs.property("version", version) inputs.property("version", version)
duplicatesStrategy = DuplicatesStrategy.INCLUDE
filesMatching("fabric.mod.json") { filesMatching("fabric.mod.json") {
expand("version" to version) expand("version" to version)
} }
@@ -78,13 +79,15 @@ tasks.jar {
val projectName = project.name val projectName = project.name
inputs.property("projectName", projectName) inputs.property("projectName", projectName)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE duplicatesStrategy = DuplicatesStrategy.INCLUDE
from("LICENSE") { from("LICENSE") {
rename { "${it}_$projectName" } rename { "${it}_$projectName" }
} }
} }
tasks.named<Jar>("sourcesJar") {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
// configure the maven publication // configure the maven publication
publishing { publishing {
@@ -10,6 +10,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class ExampleClientMixin { public class ExampleClientMixin {
@Inject(at = @At("HEAD"), method = "run") @Inject(at = @At("HEAD"), method = "run")
private void init(CallbackInfo info) { private void init(CallbackInfo info) {
// This code is injected into the start of Minecraft.run()V // This code is injected into the start of Minecraft.run()
} }
} }
@@ -1,9 +1,92 @@
package dev.zxq5.client package dev.zxq5.client
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import dev.zxq5.Fantasysmp
import dev.zxq5.ModItemTagProvider
import dev.zxq5.ModLanguageProvider
import dev.zxq5.ModRecipeProvider
import dev.zxq5.items.template.CustomItemBuilder
import dev.zxq5.items.template.GenericGearSet
import dev.zxq5.items.template.GenericItemSet
import dev.zxq5.items.template.ModelSpec
import net.fabricmc.fabric.api.client.datagen.v1.provider.FabricModelProvider
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator
import net.fabricmc.fabric.api.datagen.v1.FabricPackOutput
import net.minecraft.client.data.models.BlockModelGenerators
import net.minecraft.client.data.models.ItemModelGenerators
import net.minecraft.client.data.models.model.ModelTemplates
import net.minecraft.data.CachedOutput
import net.minecraft.data.DataProvider
import net.minecraft.data.PackOutput
import java.util.concurrent.CompletableFuture
object FantasysmpDataGenerator : DataGeneratorEntrypoint { object FantasysmpDataGenerator : DataGeneratorEntrypoint {
override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) { override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) {
val pack = fabricDataGenerator.createPack()
pack.addProvider(::ModRecipeProvider)
pack.addProvider(::ModItemTagProvider) // TODO! fix impl.
pack.addProvider(::ModLanguageProvider)
// runs only in the client as it requires client only libs!
pack.addProvider(::ModModelProvider)
pack.addProvider(::ModEquipmentAssetProvider)
}
}
// client sourceSet
class ModModelProvider(output: FabricPackOutput) : FabricModelProvider(output) {
override fun generateBlockStateModels(blockModels: BlockModelGenerators) {}
override fun generateItemModels(itemModels: ItemModelGenerators) {
println("Generating item models")
GenericItemSet.all.forEach {
println("doing $it")
it.generateModels(itemModels)
}
}
}
class ModEquipmentAssetProvider(private val output: FabricPackOutput) : DataProvider {
override fun run(writer: CachedOutput): CompletableFuture<*> {
val futures = GenericItemSet.all
.filterIsInstance<GenericGearSet>()
.map { set -> writeAsset(writer, set) }
return CompletableFuture.allOf(*futures.toTypedArray())
}
private fun writeAsset(writer: CachedOutput, set: GenericGearSet): CompletableFuture<*> {
val json = JsonObject()
val layersJson = JsonObject()
set.equipmentAssetSpec.layers.forEach { (layerType, layers) ->
val arr = JsonArray()
layers.forEach { layer ->
val entry = JsonObject()
entry.addProperty("texture", layer.texture)
if (!layer.usePlayerTexture) entry.addProperty("use_player_texture", false)
arr.add(entry)
}
layersJson.add(layerType, arr)
}
json.add("layers", layersJson)
val path = output.outputFolder
.resolve("assets/${Fantasysmp.MOD_ID}/equipment/${set.materialName}.json")
return DataProvider.saveStable(writer, json, path)
}
override fun getName() = "Fantasysmp Equipment Assets"
}
// client sourceSet
fun GenericItemSet.generateModels(itemModels: ItemModelGenerators) {
modelSpecs.forEach { (item, spec) ->
when (spec) {
ModelSpec.Generated -> itemModels.generateFlatItem(item, ModelTemplates.FLAT_ITEM)
ModelSpec.Handheld -> itemModels.generateFlatItem(item, ModelTemplates.FLAT_HANDHELD_ITEM)
ModelSpec.None -> {} // nothing to do — hand-authored JSON covers it
}
} }
} }
+49 -38
View File
@@ -1,63 +1,74 @@
package dev.zxq5 package dev.zxq5
import dev.zxq5.items.ModItems import dev.zxq5.items.ModItems
import dev.zxq5.items.Witherite import dev.zxq5.items.template.GenericItemSet
import dev.zxq5.items.isWearingFullSet
import net.fabricmc.api.ModInitializer import net.fabricmc.api.ModInitializer
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents import net.fabricmc.fabric.api.datagen.v1.FabricPackOutput
import net.fabricmc.fabric.api.event.player.AttackEntityCallback import net.fabricmc.fabric.api.datagen.v1.provider.FabricLanguageProvider
import net.minecraft.world.InteractionHand import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider
import net.minecraft.world.InteractionResult import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagsProvider
import net.minecraft.world.effect.MobEffectInstance import net.minecraft.core.HolderLookup
import net.minecraft.world.effect.MobEffects import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.world.entity.LivingEntity import net.minecraft.core.registries.Registries
import net.minecraft.data.recipes.RecipeOutput
import net.minecraft.data.recipes.RecipeProvider
import net.minecraft.resources.ResourceKey
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.util.concurrent.CompletableFuture
object Fantasysmp : ModInitializer { object Fantasysmp : ModInitializer {
const val MOD_ID = "fantasysmp" const val MOD_ID = "fantasysmp"
private val logger = LoggerFactory.getLogger("fantasysmp") private val logger = LoggerFactory.getLogger("fantasysmp")
override fun onInitialize() { override fun onInitialize() {
// This code runs as soon as Minecraft is in a mod-load-ready state.
// However, some things (like resources) may still be uninitialized.
// Proceed with mild caution.
logger.info("Hello Fabric world!") logger.info("Hello Fabric world!")
ModItems.init(); ModItems.onLoad();
// Register the group.
registerItemEffects()
} }
}
private fun registerItemEffects() { class ModRecipeProvider(
ServerTickEvents.END_SERVER_TICK.register { server -> output: FabricPackOutput,
for (player in server.playerList.players) { registriesFuture: CompletableFuture<HolderLookup.Provider>
if (player.isWearingFullSet(Witherite.ARMOUR_SET)) { ) : FabricRecipeProvider(output, registriesFuture) {
player.removeEffect(MobEffects.WITHER) override fun createRecipeProvider(
registries: HolderLookup.Provider,
exporter: RecipeOutput
): RecipeProvider {
return object : RecipeProvider(registries, exporter) {
override fun buildRecipes() {
GenericItemSet.all.forEach {
it.generateRecipes(registries, exporter)
}
} }
} }
} }
AttackEntityCallback.EVENT.register { player, world, hand, entity, _ -> override fun getName(): String = "Fantasysmp Recipes"
if (world.isClientSide) return@register InteractionResult.PASS }
if (hand != InteractionHand.MAIN_HAND) return@register InteractionResult.PASS
if (player.getItemInHand(hand).item != Witherite.SWORD) return@register InteractionResult.PASS
if (entity is LivingEntity) {
entity.addEffect(MobEffectInstance(MobEffects.WITHER, 60, 1), player)
}
InteractionResult.PASS class ModItemTagProvider(output: FabricPackOutput, registriesFuture: CompletableFuture<HolderLookup.Provider>) :
FabricTagsProvider.ItemTagsProvider(output, registriesFuture) {
override fun addTags(provider: HolderLookup.Provider) {
GenericItemSet.all.forEach {
it.generateItemTags(provider).forEach { (item, keys) ->
keys.forEach { key ->
builder(key)
.add(ResourceKey.create(Registries.ITEM, BuiltInRegistries.ITEM.getKey(item)))
} }
AttackEntityCallback.EVENT.register { player, world, hand, entity, _ ->
if (world.isClientSide) return@register InteractionResult.PASS
if (hand != InteractionHand.MAIN_HAND) return@register InteractionResult.PASS
if (player.getItemInHand(hand).item != Witherite.AXE) return@register InteractionResult.PASS
if (entity is LivingEntity) {
entity.addEffect(MobEffectInstance(MobEffects.WITHER, 60, 1), player)
} }
InteractionResult.PASS
} }
} }
} }
class ModLanguageProvider(
output: FabricPackOutput, registriesFuture: CompletableFuture<HolderLookup.Provider>) :
FabricLanguageProvider(output, registriesFuture) {
override fun generateTranslations(
registryLookup: HolderLookup.Provider,
translationBuilder: TranslationBuilder
) {
GenericItemSet.all.forEach { it.generateTranslations(translationBuilder) }
}
}
-126
View File
@@ -1,126 +0,0 @@
package dev.zxq5.items
import dev.zxq5.Fantasysmp
import dev.zxq5.items.ModItems.register
import net.minecraft.core.component.DataComponents
import net.minecraft.core.particles.ParticleOptions
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.resources.Identifier
import net.minecraft.resources.ResourceKey
import net.minecraft.server.level.ServerLevel
import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource
import net.minecraft.tags.ItemTags
import net.minecraft.util.Unit
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResult
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
import net.minecraft.world.item.ToolMaterial
import net.minecraft.world.item.component.BlocksAttacks
import net.minecraft.world.item.equipment.*
import net.minecraft.world.level.Level
import java.util.Optional
object Dragonite {
const val BASE_DURABILITY = 40;
val witherite_material_key: ResourceKey<EquipmentAsset> = ResourceKey.create<EquipmentAsset>(
EquipmentAssets.ROOT_ID,
Identifier.fromNamespaceAndPath(Fantasysmp.MOD_ID, "dragon")
)
val armorMaterial = ArmorMaterial(
BASE_DURABILITY,
mapOf(
ArmorType.HELMET to 3,
ArmorType.CHESTPLATE to 8,
ArmorType.LEGGINGS to 6,
ArmorType.BOOTS to 3,
ArmorType.BODY to 19,
),
5,
SoundEvents.ARMOR_EQUIP_NETHERITE,
3.0f,
0.1f,
ItemTags.REPAIRS_NETHERITE_ARMOR,
witherite_material_key,
)
val SWORD = register("dragon_sword", ::DragoniteSword,
Item.Properties()
.sword(ToolMaterial.NETHERITE, 3.0F, -2.4F)
)
val HELMET = register(
"dragon_helmet",
::Item,
Item.Properties().humanoidArmor(armorMaterial , ArmorType.HELMET)
.durability(ArmorType.HELMET.getDurability(armorMaterial.durability))
)
val CHESTPLATE = register(
"dragon_chestplate",
::Item,
Item.Properties().humanoidArmor(armorMaterial , ArmorType.CHESTPLATE)
.component(DataComponents.GLIDER, Unit.INSTANCE)
.durability(ArmorType.CHESTPLATE.getDurability(armorMaterial.durability))
)
val LEGGINGS = register(
"dragon_leggings",
::Item,
Item.Properties().humanoidArmor(armorMaterial , ArmorType.LEGGINGS)
.durability(ArmorType.LEGGINGS.getDurability(armorMaterial.durability))
)
val BOOTS = register(
"dragon_boots",
::Item,
Item.Properties().humanoidArmor(armorMaterial , ArmorType.BOOTS)
.durability(ArmorType.BOOTS.getDurability(armorMaterial.durability))
)
val INGOT = register(
"dragonite_ingot",
::Item,
Item.Properties()
)
val SCALE = register(
"dragon_scale",
::Item,
Item.Properties()
)
val ITEMS = listOf(SWORD, HELMET, CHESTPLATE, LEGGINGS, BOOTS, INGOT, SCALE)
val ARMOUR_SET = ArmorSet(HELMET, CHESTPLATE, LEGGINGS, BOOTS)
fun init() {}
}
class DragoniteSword(properties: Properties) : Item(properties) {
override fun use(level: Level, user: Player, hand: InteractionHand): InteractionResult {
if (level.isClientSide) return InteractionResult.PASS
if (!user.isWearingFullSet(Dragonite.ARMOUR_SET)) return InteractionResult.PASS
val stack = user.getItemInHand(hand)
if (user.cooldowns.isOnCooldown(stack)) return InteractionResult.PASS
val dir = user.lookAngle
user.deltaMovement = dir.scale(2.0)
user.hurtMarked = true
level.playSound(null, user.x, user.y, user.z,
SoundEvents.ENDER_DRAGON_FLAP, SoundSource.PLAYERS, 1.0f, 1.0f)
(level as? ServerLevel)?.sendParticles(
ParticleTypes.DRAGON_BREATH as ParticleOptions,
user.x, user.y, user.z,
100, 0.5, 0.5, 0.5, 0.5
)
user.cooldowns.addCooldown(stack, 25)
return InteractionResult.SUCCESS
}
}
@@ -1,7 +1,10 @@
package dev.zxq5.items package dev.zxq5.items
import dev.zxq5.Fantasysmp import dev.zxq5.Fantasysmp
import dev.zxq5.items.Witherite.SWORD import dev.zxq5.items.sets.Dragonite
import dev.zxq5.items.sets.Ender
import dev.zxq5.items.sets.Witherite
import dev.zxq5.items.template.GenericItemSet
import net.fabricmc.fabric.api.creativetab.v1.FabricCreativeModeTab import net.fabricmc.fabric.api.creativetab.v1.FabricCreativeModeTab
import net.minecraft.core.Registry import net.minecraft.core.Registry
import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.core.registries.BuiltInRegistries
@@ -9,19 +12,15 @@ import net.minecraft.core.registries.Registries
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.resources.Identifier import net.minecraft.resources.Identifier
import net.minecraft.resources.ResourceKey import net.minecraft.resources.ResourceKey
import net.minecraft.world.entity.EquipmentSlot import net.minecraft.world.item.CreativeModeTab
import net.minecraft.world.entity.player.Player import net.minecraft.world.item.Item
import net.minecraft.world.item.* import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.CreativeModeTab.DisplayItemsGenerator
import net.minecraft.world.item.CreativeModeTab.ItemDisplayParameters
import java.util.function.Supplier
object ModItems { object ModItems {
fun <T : Item> register( fun <T : Item> register(
name: String, name: String,
itemFactory: (Item.Properties) -> T, itemFactory: (Item.Properties) -> T,
settings: Item.Properties settings: Item.Properties = Item.Properties(),
): T { ): T {
val itemKey = ResourceKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath(Fantasysmp.MOD_ID, name)) val itemKey = ResourceKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath(Fantasysmp.MOD_ID, name))
val item = itemFactory(settings.setId(itemKey)) val item = itemFactory(settings.setId(itemKey))
@@ -29,36 +28,30 @@ object ModItems {
return item return item
} }
val CUSTOM_CREATIVE_TAB_KEY: ResourceKey<CreativeModeTab> = ResourceKey.create<CreativeModeTab>( val CUSTOM_CREATIVE_TAB_KEY: ResourceKey<CreativeModeTab> = ResourceKey.create(
BuiltInRegistries.CREATIVE_MODE_TAB.key(), Identifier.fromNamespaceAndPath(Fantasysmp.MOD_ID, "creative_tab") BuiltInRegistries.CREATIVE_MODE_TAB.key(), Identifier.fromNamespaceAndPath(Fantasysmp.MOD_ID, "creative_tab")
) )
val CUSTOM_CREATIVE_TAB: CreativeModeTab = FabricCreativeModeTab.builder() val CUSTOM_CREATIVE_TAB: CreativeModeTab = FabricCreativeModeTab.builder()
.icon(Supplier { ItemStack(SWORD) }) .icon { ItemStack(Witherite.SWORD) }
.title(Component.translatable("Fantasysmp")) .title(Component.translatable("Fantasysmp"))
.displayItems(DisplayItemsGenerator { params: ItemDisplayParameters, output: CreativeModeTab.Output -> .displayItems { _, output ->
Witherite.ITEMS.forEach { output.accept(it) } GenericItemSet.all.forEach {
Dragonite.ITEMS.forEach { output.accept(it) } it.items.forEach(output::accept)
}) }
}
.build() .build()
fun init() { private val eagerLoad = listOf<GenericItemSet>(
Witherite.init(); Witherite,
Dragonite.init(); Dragonite,
// Ender // TODO: Enable for content drop #1
)
fun onLoad() {
// ensure that implementations such as creative tab are loaded and initialised
eagerLoad
GenericItemSet.all.forEach { it.onLoad() }
Registry.register(BuiltInRegistries.CREATIVE_MODE_TAB, CUSTOM_CREATIVE_TAB_KEY, CUSTOM_CREATIVE_TAB); Registry.register(BuiltInRegistries.CREATIVE_MODE_TAB, CUSTOM_CREATIVE_TAB_KEY, CUSTOM_CREATIVE_TAB);
} }
} }
data class ArmorSet(
val helmet: Item,
val chestplate: Item,
val leggings: Item,
val boots: Item,
)
fun Player.isWearingFullSet(set: ArmorSet): Boolean {
return getItemBySlot(EquipmentSlot.HEAD).item == set.helmet &&
getItemBySlot(EquipmentSlot.CHEST).item == set.chestplate &&
getItemBySlot(EquipmentSlot.LEGS).item == set.leggings &&
getItemBySlot(EquipmentSlot.FEET).item == set.boots
}
-123
View File
@@ -1,123 +0,0 @@
package dev.zxq5.items
import dev.zxq5.Fantasysmp
import dev.zxq5.items.ModItems.register
import net.minecraft.core.component.DataComponents
import net.minecraft.resources.Identifier
import net.minecraft.resources.ResourceKey
import net.minecraft.sounds.SoundEvents
import net.minecraft.tags.ItemTags
import net.minecraft.util.Unit
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResult
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.player.Player
import net.minecraft.world.entity.projectile.hurtingprojectile.WitherSkull
import net.minecraft.world.item.Item
import net.minecraft.world.item.ToolMaterial
import net.minecraft.world.item.component.BlocksAttacks
import net.minecraft.world.item.equipment.*
import net.minecraft.world.level.Level
import java.util.Optional
object Witherite {
val base_durability = 40;
val witherite_material_key: ResourceKey<EquipmentAsset> = ResourceKey.create<EquipmentAsset>(
EquipmentAssets.ROOT_ID,
Identifier.fromNamespaceAndPath(Fantasysmp.MOD_ID, "witherite")
)
val armorMaterial = ArmorMaterial(
base_durability,
mapOf(
ArmorType.HELMET to 3,
ArmorType.CHESTPLATE to 8,
ArmorType.LEGGINGS to 6,
ArmorType.BOOTS to 3,
ArmorType.BODY to 19,
),
5,
SoundEvents.ARMOR_EQUIP_NETHERITE,
3.0f,
0.1f,
ItemTags.REPAIRS_NETHERITE_ARMOR,
witherite_material_key,
)
val SHIELD = register("witherite_shield", ::Item,
Item.Properties().component(DataComponents.BLOCKS_ATTACKS, BlocksAttacks(
0.25f, // 5 tick warmup
1.0f, // standard disable cooldown
listOf(
BlocksAttacks.DamageReduction(
90.0f, // horizontalBlockingAngle — 90° arc each side (180° total, same as vanilla)
Optional.empty(), // type — empty = blocks all damage types
0.0f, // base — flat damage reduction
1.0f // factor — multiplier (1.0 = block 100% of damage)
)
), // full block — check if this constant exists, else build the list manually
BlocksAttacks.ItemDamageFunction.DEFAULT, // check for this constant too
Optional.empty(), // no bypass
Optional.empty(), // default block sound
Optional.empty() // default disable sound
))
)
val SWORD = register("witherite_sword", ::WitheriteSword,
Item.Properties().sword(ToolMaterial.NETHERITE, 3F, -2.4F)
)
val AXE = register("witherite_axe", ::Item,
Item.Properties().axe(ToolMaterial.NETHERITE, 5F, -3F))
val HELMET = register(
"witherite_helmet",
::Item,
Item.Properties().humanoidArmor(armorMaterial , ArmorType.HELMET)
.durability(ArmorType.HELMET.getDurability(armorMaterial.durability))
)
val CHESTPLATE = register(
"witherite_chestplate",
::Item,
Item.Properties().humanoidArmor(armorMaterial , ArmorType.CHESTPLATE)
.durability(ArmorType.CHESTPLATE.getDurability(armorMaterial.durability))
)
val LEGGINGS = register(
"witherite_leggings",
::Item,
Item.Properties().humanoidArmor(armorMaterial , ArmorType.LEGGINGS)
.durability(ArmorType.LEGGINGS.getDurability(armorMaterial.durability))
)
val BOOTS = register(
"witherite_boots",
::Item,
Item.Properties().humanoidArmor(armorMaterial , ArmorType.BOOTS)
.durability(ArmorType.BOOTS.getDurability(armorMaterial.durability))
)
val ITEMS = listOf(SWORD, AXE, SHIELD, HELMET, CHESTPLATE, LEGGINGS, BOOTS)
val ARMOUR_SET = ArmorSet(HELMET, CHESTPLATE, LEGGINGS, BOOTS)
fun init() {}
}
class WitheriteSword(properties: Properties) : Item(properties) {
override fun use(level: Level, user: Player, hand: InteractionHand): InteractionResult {
if (level.isClientSide) {
return InteractionResult.PASS;
}
if (!user.isCrouching) return InteractionResult.PASS
val skull = WitherSkull(EntityType.WITHER_SKULL, level)
skull.setPos(user.eyePosition)
skull.deltaMovement = user.lookAngle
level.addFreshEntity(skull)
skull.playSound(SoundEvents.WITHER_SHOOT)
return InteractionResult.SUCCESS;
}
}
@@ -0,0 +1,200 @@
package dev.zxq5.items.sets
import dev.zxq5.Fantasysmp
import dev.zxq5.items.template.ArmorSet
import dev.zxq5.items.template.EquipmentLayer
import dev.zxq5.items.template.GenericGearSet
import dev.zxq5.items.template.ModelSpec
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents
import net.minecraft.ChatFormatting
import net.minecraft.core.component.DataComponents
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.core.particles.PowerParticleOption
import net.minecraft.server.level.ServerLevel
import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource
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.DamageTypes
import net.minecraft.world.entity.Entity
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.Level
object Dragonite: GenericGearSet() {
override val materialName = "dragonite"
override val materialDefinition
get() = super.materialDefinition.copy(assetId = materialKey)
override val equipmentAssetSpec = super.equipmentAssetSpec.copy(
layers = super.equipmentAssetSpec.layers + ("wings" to listOf(
EquipmentLayer(
"${Fantasysmp.MOD_ID}:dragonite",
usePlayerTexture = false
)
))
)
const val LORE = " forged from the essence of dragons"
override val lore_style = ChatFormatting.DARK_PURPLE
val SCALE by registerItem("dragon_scale", ::Item) {
name("Dragon Scale")
}
val INGOT by registerItem("dragonite_ingot", ::Item) {
name("Dragonite Ingot")
shapedRecipe("SBS", "CXC", "SBS", key=mapOf<Char, Item>(
'S' to Items.SHULKER_SHELL,
'X' to SCALE,
'B' to Items.DRAGON_BREATH,
'C' to Items.CHORUS_FRUIT
))
}
val SWORD by registerItem("dragonite_sword", ::DragoniteSword) {
name("Dragonite Sword")
lore("A sword$LORE")
model(ModelSpec.Handheld)
properties {
enchantable(armorMaterial.enchantmentValue)
.component(DataComponents.USE_COOLDOWN, UseCooldown(2f))
.sword(ToolMaterial.NETHERITE, 3F, -2.4F)
}
smithingUpgrade(Items.END_CRYSTAL, Items.NETHERITE_SWORD, INGOT)
tags("swords")
}
val HELMET by registerItem("dragonite_helmet", ::Item) {
name("Dragonite Helmet")
lore("A helmet$LORE")
properties {
humanoidArmor(armorMaterial, ArmorType.HELMET)
}
smithingUpgrade(Items.DRAGON_HEAD, Items.NETHERITE_HELMET, INGOT)
tags("head_armor")
}
val CHESTPLATE by registerItem("dragonite_chestplate", ::Item) {
name("Dragonite Chestplate")
lore("A chestplate$LORE")
properties {
humanoidArmor(armorMaterial, ArmorType.CHESTPLATE)
.component(DataComponents.GLIDER, Unit.INSTANCE)
.component(DataComponents.UNBREAKABLE, Unit.INSTANCE)
}
smithingUpgrade(Items.ELYTRA, Items.NETHERITE_CHESTPLATE, INGOT)
tags("chest_armor")
}
val LEGGINGS by registerItem("dragonite_leggings", ::Item) {
name("Dragonite Leggings")
lore("Leggings$LORE")
properties {
humanoidArmor(armorMaterial, ArmorType.LEGGINGS)
}
smithingUpgrade(Items.CRYING_OBSIDIAN, Items.NETHERITE_LEGGINGS, INGOT)
tags("leg_armor")
}
val BOOTS by registerItem("dragonite_boots", ::Item) {
name("Dragonite Boots")
lore("Boots$LORE")
properties {
humanoidArmor(armorMaterial, ArmorType.BOOTS)
}
smithingUpgrade(Items.CRYING_OBSIDIAN, Items.NETHERITE_BOOTS, INGOT)
tags("foot_armor")
}
override val armorSet: ArmorSet = ArmorSet(HELMET, CHESTPLATE, LEGGINGS, BOOTS)
override val items = listOf(SWORD, HELMET, CHESTPLATE, LEGGINGS, BOOTS, SCALE, INGOT)
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) {
override fun use(level: Level, user: Player, hand: InteractionHand): InteractionResult {
if (level.isClientSide || !Dragonite.fullSetEquippedBy(user)) return InteractionResult.PASS
val direction = user.lookAngle
val scale = if (user.isFallFlying) { 4.0 } else { 1.5 }
user.deltaMovement = direction.scale(scale)
user.hurtMarked = true
level.playSound(null, user.x, user.y, user.z,
SoundEvents.ENDER_DRAGON_FLAP, SoundSource.PLAYERS, 1.0f, 1.0f)
(level as? ServerLevel)?.sendParticles(
PowerParticleOption.create(ParticleTypes.DRAGON_BREATH, 1.0f),
user.x, user.y, user.z,
100, 0.5, 0.5, 0.5, 0.5
)
return InteractionResult.SUCCESS
}
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 (attacker.level().isClientSide) return superBonus
if (!attacker.isFallFlying) return superBonus
val speed = attacker.deltaMovement.length()
if (speed < MIN_DIVE_SPEED) return superBonus
val clampedSpeed = speed.coerceAtMost(MAX_DIVE_SPEED)
val t = (clampedSpeed - MIN_DIVE_SPEED) / (MAX_DIVE_SPEED - MIN_DIVE_SPEED)
val multiplier = 1.0f + (t * MAX_BONUS_MULTIPLIER).toFloat()
// damage is the current total (base + crit + whatever ran before this hook).
// We want final = damage * multiplier, and this method adds its return value on top of damage,
// so the bonus we need to return is exactly (damage * multiplier) - damage.
val extraBonus = damage * (multiplier - 1f)
println("base: $damage bonus: ${superBonus + extraBonus}")
return superBonus + extraBonus
}
companion object {
const val MIN_DIVE_SPEED = 0.3
const val MAX_DIVE_SPEED = 1.1
const val MAX_BONUS_MULTIPLIER = 2.0f
}
}
@@ -0,0 +1,165 @@
package dev.zxq5.items.sets
import dev.zxq5.items.template.ArmorSet
import dev.zxq5.items.template.GearMaterialDef
import dev.zxq5.items.template.GenericGearSet
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents
import net.minecraft.ChatFormatting
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)
const val LORE = "Crafted from the essence of endermen"
override val lore_style: ChatFormatting
get() = ChatFormatting.AQUA
val ENDER_INGOT by registerItem("ender_ingot", ::Item) {
name("Ender Ingot")
lore(LORE)
shapedRecipe("EDE", "DED", "EDE", key=mapOf(
'E' to Items.ENDER_EYE,
'D' to Items.DIAMOND,
))
}
val SWORD by registerItem("ender_sword", ::EnderSword) {
name("Ender Sword")
lore(LORE)
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)
tags("swords")
}
val HELMET by registerItem("ender_helmet", ::Item) {
name("Ender Helmet")
lore(LORE)
properties {
humanoidArmor(armorMaterial, ArmorType.HELMET)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.DIAMOND_HELMET, ENDER_INGOT)
tags("head_armor")
}
val CHESTPLATE by registerItem("ender_chestplate", ::Item) {
name("Ender Chestplate")
lore(LORE)
properties {
humanoidArmor(armorMaterial, ArmorType.CHESTPLATE)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.DIAMOND_CHESTPLATE, ENDER_INGOT)
tags("chest_armor")
}
val LEGGINGS by registerItem("ender_leggings", ::Item) {
name("Ender Leggings")
lore(LORE)
properties {
humanoidArmor(armorMaterial, ArmorType.LEGGINGS)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.DIAMOND_LEGGINGS, ENDER_INGOT)
tags("leg_armor")
}
val BOOTS by registerItem("ender_boots", ::Item) {
name("Ender Boots")
lore(LORE)
properties {
humanoidArmor(armorMaterial, ArmorType.BOOTS)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.DIAMOND_BOOTS, ENDER_INGOT)
tags("foot_armor")
}
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
}
@@ -0,0 +1,169 @@
package dev.zxq5.items.sets
import dev.zxq5.items.template.ArmorSet
import dev.zxq5.items.template.GenericGearSet
import dev.zxq5.items.template.ModelSpec
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents
import net.minecraft.ChatFormatting
import net.minecraft.core.component.DataComponents
import net.minecraft.sounds.SoundEvents
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResult
import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.entity.projectile.hurtingprojectile.WitherSkull
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.item.ToolMaterial
import net.minecraft.world.item.component.BlocksAttacks
import net.minecraft.world.item.component.UseCooldown
import net.minecraft.world.item.equipment.ArmorType
import net.minecraft.world.level.Level
import java.util.*
object Witherite: GenericGearSet() {
override val materialName = "witherite"
override val materialDefinition
get() = super.materialDefinition.copy(assetId = materialKey)
const val LORE = " forged with the skulls of wither skeletons."
override val lore_style
get() = ChatFormatting.BLACK
val SHIELD by registerItem("witherite_shield", ::Item) {
name("Witherite Shield")
lore("A shield$LORE")
properties {
component(DataComponents.BLOCKS_ATTACKS, BlocksAttacks(
0.25f, // 5 tick warmup
1.0f, // standard disable cooldown
listOf(
BlocksAttacks.DamageReduction(
90.0f, // horizontalBlockingAngle — 90° arc each side (180° total, same as vanilla)
Optional.empty(), // type — empty = blocks all damage types
0.0f, // base — flat damage reduction
1.0f // factor — multiplier (1.0 = block 100% of damage)
)
), // full block — check if this constant exists, else build the list manually
BlocksAttacks.ItemDamageFunction.DEFAULT, // check for this constant too
Optional.empty(), // no bypass
Optional.empty(), // default block sound
Optional.empty() // default disable sound
))
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.SHIELD, Items.WITHER_SKELETON_SKULL)
}
val SWORD by registerItem("witherite_sword", ::WitheriteSword) {
name("Witherite Sword")
lore("A sword$LORE")
model(ModelSpec.Handheld)
properties {
enchantable(armorMaterial.enchantmentValue)
.component(DataComponents.USE_COOLDOWN, UseCooldown(2f))
.sword(ToolMaterial.NETHERITE, 3F, -2.4F)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.NETHERITE_SWORD, Items.WITHER_SKELETON_SKULL)
tags("swords")
}
val AXE by registerItem("witherite_axe", ::WitheriteWeapon) {
name("Witherite Axe")
lore("An axe$LORE")
model(ModelSpec.Handheld)
properties {
enchantable(armorMaterial.enchantmentValue)
.component(DataComponents.USE_COOLDOWN, UseCooldown(2f))
.axe(ToolMaterial.NETHERITE, 3F, -3F)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.NETHERITE_AXE, Items.WITHER_SKELETON_SKULL)
tags("axes")
}
val HELMET by registerItem("witherite_helmet", ::Item) {
name("Witherite Helmet")
lore("A helmet$LORE")
properties {
humanoidArmor(armorMaterial, ArmorType.HELMET)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.NETHERITE_HELMET, Items.WITHER_SKELETON_SKULL)
tags("head_armor")
}
val CHESTPLATE by registerItem("witherite_chestplate", ::Item) {
name("Witherite Chestplate")
lore("A chestplate$LORE")
properties {
humanoidArmor(armorMaterial, ArmorType.CHESTPLATE)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.NETHERITE_CHESTPLATE, Items.WITHER_SKELETON_SKULL)
tags("chest_armor")
}
val LEGGINGS by registerItem("witherite_leggings", ::Item) {
name("Witherite Leggings")
lore("Leggings$LORE")
properties {
humanoidArmor(armorMaterial, ArmorType.LEGGINGS)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.NETHERITE_LEGGINGS, Items.WITHER_SKELETON_SKULL)
tags("leg_armor")
}
val BOOTS by registerItem("witherite_boots", ::Item) {
name("Witherite Boots")
lore("Boots$LORE")
properties {
humanoidArmor(armorMaterial, ArmorType.BOOTS)
}
smithingUpgrade(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items.NETHERITE_BOOTS, Items.WITHER_SKELETON_SKULL)
tags("foot_armor")
}
override val armorSet: ArmorSet = ArmorSet(HELMET, CHESTPLATE, LEGGINGS, BOOTS)
override val items = listOf(SWORD, AXE, SHIELD, HELMET, CHESTPLATE, LEGGINGS, BOOTS)
override fun onLoad() {
ServerTickEvents.END_SERVER_TICK.register { server ->
for (player in server.playerList.players) {
if (fullSetEquippedBy(player)) {
player.removeEffect(MobEffects.WITHER)
}
}
}
}
}
open class WitheriteWeapon(properties: Properties): Item(properties) {
override fun hurtEnemy(itemStack: ItemStack, mob: LivingEntity, attacker: LivingEntity) {
super.hurtEnemy(itemStack, mob, attacker)
if (attacker.level().isClientSide) return
val amplifier = if (attacker is Player) { 0 } else { 2 }
mob.addEffect(MobEffectInstance(MobEffects.WITHER, 60, amplifier), attacker)
}
}
class WitheriteSword(properties: Properties) : WitheriteWeapon(properties) {
override fun use(level: Level, user: Player, hand: InteractionHand): InteractionResult {
if (level.isClientSide
|| !user.isCrouching
|| !Witherite.fullSetEquippedBy(user)
) return InteractionResult.PASS;
val skull = WitherSkull(EntityType.WITHER_SKULL, level)
skull.setPos(user.eyePosition)
skull.deltaMovement = user.lookAngle
level.addFreshEntity(skull)
skull.playSound(SoundEvents.WITHER_SHOOT)
return InteractionResult.SUCCESS;
}
}
@@ -0,0 +1,108 @@
package dev.zxq5.items.template
import dev.zxq5.Fantasysmp
import dev.zxq5.util.resourceKey
import net.minecraft.core.Holder
import net.minecraft.resources.ResourceKey
import net.minecraft.sounds.SoundEvent
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
import net.minecraft.world.item.equipment.EquipmentAsset
abstract class GenericGearSet: GenericItemSet() {
abstract val materialName: String
abstract val armorSet: ArmorSet
open val equipmentAssetSpec: EquipmentAssetSpec
get() = EquipmentAssetSpec(
layers = mapOf(
"humanoid" to listOf(EquipmentLayer("${Fantasysmp.MOD_ID}:$materialName")),
"humanoid_leggings" to listOf(EquipmentLayer("${Fantasysmp.MOD_ID}:$materialName")),
)
)
open val materialKey: ResourceKey<EquipmentAsset>
get() = materialName.resourceKey()
open val materialDefinition: GearMaterialDef
get() = GearMaterialDef.NETHERITE
val toolMaterial: ToolMaterial by lazy {
materialDefinition.toToolMaterial()
}
val armorMaterial: ArmorMaterial by lazy {
materialDefinition.toArmorMaterial()
}
open fun fullSetEquippedBy(p: Player) =
p.getItemBySlot(EquipmentSlot.HEAD).item == armorSet.helmet &&
p.getItemBySlot(EquipmentSlot.CHEST).item == armorSet.chestplate &&
p.getItemBySlot(EquipmentSlot.LEGS).item == armorSet.leggings &&
p.getItemBySlot(EquipmentSlot.FEET).item == armorSet.boots
}
data class ArmorSet(
val helmet: Item,
val chestplate: Item,
val leggings: Item,
val boots: Item,
)
data class GearMaterialDef(
val durability: Int = ArmorMaterials.NETHERITE.durability,
val defence: Map<ArmorType, Int> = ArmorMaterials.NETHERITE.defense,
val enchantability: Int = ArmorMaterials.NETHERITE.enchantmentValue,
val equipSound: Holder<SoundEvent> = ArmorMaterials.NETHERITE.equipSound,
val toughness: Float = ArmorMaterials.NETHERITE.toughness,
val knockbackResistance: Float = ArmorMaterials.NETHERITE.knockbackResistance,
val repairIngredient: TagKey<Item> = ArmorMaterials.NETHERITE.repairIngredient,
val assetId: ResourceKey<EquipmentAsset> = ArmorMaterials.NETHERITE.assetId,
) {
companion object {
val NETHERITE = GearMaterialDef(
durability = ArmorMaterials.NETHERITE.durability,
defence = ArmorMaterials.NETHERITE.defense,
enchantability = ArmorMaterials.NETHERITE.enchantmentValue,
equipSound = ArmorMaterials.NETHERITE.equipSound,
toughness = ArmorMaterials.NETHERITE.toughness,
knockbackResistance = ArmorMaterials.NETHERITE.knockbackResistance,
repairIngredient = ArmorMaterials.NETHERITE.repairIngredient,
assetId = ArmorMaterials.NETHERITE.assetId,
)
val DIAMOND = GearMaterialDef(
durability = ArmorMaterials.DIAMOND.durability,
defence = ArmorMaterials.DIAMOND.defense,
enchantability = ArmorMaterials.DIAMOND.enchantmentValue,
equipSound = ArmorMaterials.DIAMOND.equipSound,
toughness = ArmorMaterials.DIAMOND.toughness,
knockbackResistance = ArmorMaterials.DIAMOND.knockbackResistance,
repairIngredient = ArmorMaterials.DIAMOND.repairIngredient,
assetId = ArmorMaterials.DIAMOND.assetId,
)
}
}
fun GearMaterialDef.toArmorMaterial(): ArmorMaterial {
return ArmorMaterial(
durability,
defence,
enchantability,
equipSound,
toughness,
knockbackResistance,
repairIngredient,
assetId,
)
}
fun GearMaterialDef.toToolMaterial(): ToolMaterial {
TODO()
}
@@ -0,0 +1,198 @@
package dev.zxq5.items.template
import dev.zxq5.Fantasysmp
import dev.zxq5.items.ModItems
import dev.zxq5.util.mcItemTag
import net.fabricmc.fabric.api.datagen.v1.provider.FabricLanguageProvider
import net.minecraft.ChatFormatting
import net.minecraft.advancements.criterion.InventoryChangeTrigger
import net.minecraft.advancements.criterion.ItemPredicate
import net.minecraft.core.HolderGetter
import net.minecraft.core.HolderLookup
import net.minecraft.core.component.DataComponents
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.data.recipes.*
import net.minecraft.network.chat.Component
import net.minecraft.tags.TagKey
import net.minecraft.world.item.Item
import net.minecraft.world.item.component.ItemLore
import net.minecraft.world.item.crafting.Ingredient
import kotlin.reflect.KProperty
abstract class GenericItemSet {
// list of all items part of the class
open val lore_style = ChatFormatting.GRAY
abstract val items: List<Item>
open fun onLoad() {}
private val itemRecipes = mutableMapOf<Item, List<RecipeSpec>>()
private val itemTags = mutableMapOf<Item, List<TagKey<Item>>>()
private val itemModels = mutableMapOf<Item, ModelSpec>()
private val itemTranslations = mutableMapOf<String, String>()
val modelSpecs: Map<Item, ModelSpec> get() = itemModels
internal fun registerDatagen(
item: Item,
recipes: List<RecipeSpec>,
tags: List<TagKey<Item>>,
model: ModelSpec,
translations: Map<String, String>
) {
itemRecipes[item] = recipes
itemTags[item] = tags
itemModels[item] = model
itemTranslations.putAll(translations)
}
open fun generateItemTags(provider: HolderLookup.Provider): Map<Item, List<TagKey<Item>>> {
return itemTags
}
open fun generateTranslations(builder: FabricLanguageProvider.TranslationBuilder) {
itemTranslations.forEach { (key, value) -> builder.add(key, value) }
}
open fun generateRecipes(registries: HolderLookup.Provider, exporter: RecipeOutput) {
val itemLookup: HolderGetter<Item> = registries.lookupOrThrow(Registries.ITEM)
itemRecipes.forEach { (item, specs) ->
specs.forEach { spec ->
when (spec) {
is RecipeSpec.Smithing -> SmithingTransformRecipeBuilder.smithing(
Ingredient.of(spec.template), Ingredient.of(spec.base), Ingredient.of(spec.addition),
RecipeCategory.COMBAT, item
).unlocks("has_addition", InventoryChangeTrigger.TriggerInstance.hasItems(spec.addition))
.save(exporter, BuiltInRegistries.ITEM.getKey(item).path)
is RecipeSpec.Shaped -> {
val builder = ShapedRecipeBuilder.shaped(itemLookup, RecipeCategory.MISC, item)
spec.pattern.forEach { builder.pattern(it) }
spec.key.forEach { (char, ingredientItem) ->
builder.define(char, ingredientItem)
}
builder
.unlockedBy("has_ingredient", RecipeProvider.inventoryTrigger(
ItemPredicate.Builder().of(itemLookup, *spec.key.values.toTypedArray() )
))
.save(exporter)
}
}
}
}
};
init {
register(this)
}
fun <T : Item> registerItem(
name: String,
itemFactory: (Item.Properties) -> T,
block: CustomItemBuilder<T>.() -> Unit = {},
): CustomItemBuilder<T> {
return CustomItemBuilder(this, name, itemFactory).apply(block)
}
companion object {
private val _all = mutableListOf<GenericItemSet>()
val all: List<GenericItemSet> get() = _all
fun register(impl: GenericItemSet) = _all.add(impl)
}
}
data class EquipmentLayer(val texture: String, val usePlayerTexture: Boolean = true)
data class EquipmentAssetSpec(
val layers: Map<String, List<EquipmentLayer>> // "humanoid", "humanoid_leggings", "wings", etc.
)
class CustomItemBuilder<T : Item>(
private val owner: GenericItemSet,
val name: String,
private val itemFactory: (Item.Properties) -> T,
) {
private var properties = Item.Properties()
private val recipes = mutableListOf<RecipeSpec>()
private val tags = mutableListOf<TagKey<Item>>()
private val translations = mutableMapOf<String, String>()
private var modelSpec: ModelSpec = ModelSpec.Generated
fun model(spec: ModelSpec) {
modelSpec = spec
}
fun name(displayName: String) {
translations["item.${Fantasysmp.MOD_ID}.$name"] = displayName
}
fun lore(vararg lines: String, style: ChatFormatting = owner.lore_style) {
val components = lines.mapIndexed { index, line ->
val key = "item.${Fantasysmp.MOD_ID}.$name.lore.line${index + 1}"
translations[key] = line
Component.translatable(key).withStyle(style)
}
properties = properties.component(DataComponents.LORE, ItemLore(components))
}
fun lore(vararg lines: Pair<String, ChatFormatting>) {
val components = lines.mapIndexed { index, (line, style) ->
val key = "item.${Fantasysmp.MOD_ID}.$name.lore.line${index + 1}"
translations[key] = line
Component.translatable(key).withStyle(style)
}
properties = properties.component(DataComponents.LORE, ItemLore(components))
}
fun properties(block: Item.Properties.() -> Item.Properties) {
properties = properties.block()
}
fun smithingUpgrade(template: Item, base: Item, addition: Item) {
recipes += RecipeSpec.Smithing(template, base, addition)
}
fun shapedRecipe(vararg pattern: String, key: Map<Char, Item>) {
recipes += RecipeSpec.Shaped(pattern.toList(), key)
}
fun tags(vararg tag: String) {
tag.forEach {
tags += mcItemTag(it)
}
}
fun tags(vararg tag: TagKey<Item>) {
tags += tag
}
internal fun build(): T {
val item = ModItems.register(name, itemFactory, properties)
owner.registerDatagen(item, recipes, tags, modelSpec, translations)
return item
}
operator fun provideDelegate(
thisRef: Any?, property: KProperty<*>
): Lazy<T> = lazy { build() }
}
sealed interface RecipeSpec {
data class Smithing(val template: Item, val base: Item, val addition: Item) : RecipeSpec
data class Shaped(val pattern: List<String>, val key: Map<Char, Item>) : RecipeSpec
}
sealed interface ModelSpec {
data object Generated : ModelSpec // plain flat 2D item icon
data object Handheld : ModelSpec // flat icon, held like a tool
data object None : ModelSpec // handwritten JSON already exists, skip auto-gen
}
operator fun <T : Item> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
+20
View File
@@ -0,0 +1,20 @@
package dev.zxq5.util
import dev.zxq5.Fantasysmp
import net.minecraft.core.registries.Registries
import net.minecraft.resources.Identifier
import net.minecraft.resources.ResourceKey
import net.minecraft.tags.TagKey
import net.minecraft.world.item.Item
import net.minecraft.world.item.equipment.EquipmentAsset
import net.minecraft.world.item.equipment.EquipmentAssets
fun id(path: String): Identifier = Identifier.fromNamespaceAndPath(Fantasysmp.MOD_ID, path)
fun String.resourceKey(): ResourceKey<EquipmentAsset> = ResourceKey.create(
EquipmentAssets.ROOT_ID,
Identifier.fromNamespaceAndPath(Fantasysmp.MOD_ID, this),
)
fun mcItemTag(path: String): TagKey<Item> = TagKey.create(
Registries.ITEM,
Identifier.withDefaultNamespace(path)
)
@@ -1,14 +0,0 @@
{
"layers": {
"humanoid": [
{
"texture": "fantasysmp:alchemist"
}
],
"humanoid_leggings": [
{
"texture": "fantasysmp:alchemist"
}
]
}
}
@@ -1,14 +0,0 @@
{
"layers": {
"humanoid": [
{
"texture": "fantasysmp:blazing"
}
],
"humanoid_leggings": [
{
"texture": "fantasysmp:blazing"
}
]
}
}
@@ -1,14 +0,0 @@
{
"layers": {
"humanoid": [
{
"texture": "fantasysmp:crimson"
}
],
"humanoid_leggings": [
{
"texture": "fantasysmp:crimson"
}
]
}
}
@@ -1,20 +0,0 @@
{
"layers": {
"humanoid": [
{
"texture": "fantasysmp:dragon"
}
],
"humanoid_leggings": [
{
"texture": "fantasysmp:dragon"
}
],
"wings": [
{
"texture": "fantasysmp:dragon",
"use_player_texture": false
}
]
}
}
@@ -1,14 +0,0 @@
{
"layers": {
"humanoid": [
{
"texture": "fantasysmp:ender"
}
],
"humanoid_leggings": [
{
"texture": "fantasysmp:ender"
}
]
}
}
@@ -1,14 +0,0 @@
{
"layers": {
"humanoid": [
{
"texture": "fantasysmp:mechanist"
}
],
"humanoid_leggings": [
{
"texture": "fantasysmp:mechanist"
}
]
}
}
@@ -1,14 +0,0 @@
{
"layers": {
"humanoid": [
{
"texture": "fantasysmp:poseidon"
}
],
"humanoid_leggings": [
{
"texture": "fantasysmp:poseidon"
}
]
}
}
@@ -1,14 +0,0 @@
{
"layers": {
"humanoid": [
{
"texture": "fantasysmp:true_netherite"
}
],
"humanoid_leggings": [
{
"texture": "fantasysmp:true_netherite"
}
]
}
}
@@ -1,14 +0,0 @@
{
"layers": {
"humanoid": [
{
"texture": "fantasysmp:witherite"
}
],
"humanoid_leggings": [
{
"texture": "fantasysmp:witherite"
}
]
}
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 113 KiB

@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/alchemist_boots"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/alchemist_chestplate"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/alchemist_helmet"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/alchemist_leggings"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/alchemist_sword"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/blazing_boots"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/blazing_chestplate"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/blazing_helmet"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/blazing_leggings"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/blazing_sword"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/crimson_sword"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/dragon_boots"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/dragon_chestplate"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/dragon_helmet"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/dragon_leggings"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/dragon_scale"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/dragon_sword"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/dragonite_ingot"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/ender_boots"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/ender_chestplate"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/ender_helmet"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/ender_leggings"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/ender_sword"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/lightning_sword"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/poseidons_boots"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/poseidons_chestplate"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/poseidons_helmet"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/poseidons_leggings"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/poseidons_trident"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/stevens_wrath"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/true_netherite_boots"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/true_netherite_chestplate"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/true_netherite_helmet"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/true_netherite_leggings"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/true_netherite_sword"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/witherite_axe"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/witherite_boots"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/witherite_chestplate"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/witherite_helmet"
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/witherite_leggings"
}
}
@@ -1,44 +0,0 @@
{
"model": {
"type": "minecraft:condition",
"on_false": {
"type": "minecraft:special",
"base": "minecraft:item/shield",
"model": {
"type": "fantasysmp:witherite_shield"
}
},
"on_true": {
"type": "minecraft:special",
"base": "minecraft:item/shield_blocking",
"model": {
"type": "fantasysmp:witherite_shield"
}
},
"property": "minecraft:using_item",
"transformation": {
"left_rotation": [
0.0,
0.0,
0.0,
1.0
],
"right_rotation": [
0.0,
0.0,
0.0,
1.0
],
"scale": [
1.0,
-1.0,
-1.0
],
"translation": [
0.0,
0.0,
0.0
]
}
}
}
@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "fantasysmp:item/witherite_sword"
}
}
@@ -1,14 +0,0 @@
{
"item.fantasysmp.witherite_sword": "Witherite Sword",
"item.fantasysmp.witherite_helmet": "Witherite Helmet",
"item.fantasysmp.witherite_chestplate": "Witherite Chestplate",
"item.fantasysmp.witherite_leggings": "Witherite Leggings",
"item.fantasysmp.witherite_boots": "Witherite Boots",
"item.fantasysmp.witherite_axe": "Witherite Axe",
"item.fantasysmp.witherite_shield": "Witherite Shield",
"item.fantasysmp.dragon_sword": "Dragon Sword",
"item.fantasysmp.dragon_helmet": "Dragon Helmet",
"item.fantasysmp.dragon_chestplate": "Dragon Chestplate",
"item.fantasysmp.dragon_leggings": "Dragon Leggings",
"item.fantasysmp.dragon_boots": "Dragon Boots"
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_boots",
"textures": {
"layer0": "fantasysmp:item/alchemist_boots"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_chestplate",
"textures": {
"layer0": "fantasysmp:item/alchemist_chestplate"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_helmet",
"textures": {
"layer0": "fantasysmp:item/alchemist_helmet"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_leggings",
"textures": {
"layer0": "fantasysmp:item/alchemist_leggings"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_sword",
"textures": {
"layer0": "fantasysmp:item/alchemist_sword"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_boots",
"textures": {
"layer0": "fantasysmp:item/blazing_boots"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_chestplate",
"textures": {
"layer0": "fantasysmp:item/blazing_chestplate"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_helmet",
"textures": {
"layer0": "fantasysmp:item/blazing_helmet"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_leggings",
"textures": {
"layer0": "fantasysmp:item/blazing_leggings"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_sword",
"textures": {
"layer0": "fantasysmp:item/blazing_sword"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/netherite_sword",
"textures": {
"layer0": "fantasysmp:item/crimson_sword"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/netherite_boots",
"textures": {
"layer0": "fantasysmp:item/dragon_boots"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/netherite_chestplate",
"textures": {
"layer0": "fantasysmp:item/dragon_chestplate"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/netherite_helmet",
"textures": {
"layer0": "fantasysmp:item/dragon_helmet"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/netherite_leggings",
"textures": {
"layer0": "fantasysmp:item/dragon_leggings"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/netherite_ingot",
"textures": {
"layer0": "fantasysmp:item/dragon_scale"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/netherite_sword",
"textures": {
"layer0": "fantasysmp:item/dragon_sword"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/netherite_ingot",
"textures": {
"layer0": "fantasysmp:item/dragonite_ingot"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_boots",
"textures": {
"layer0": "fantasysmp:item/ender_boots"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_chestplate",
"textures": {
"layer0": "fantasysmp:item/ender_chestplate"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_helmet",
"textures": {
"layer0": "fantasysmp:item/ender_helmet"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_leggings",
"textures": {
"layer0": "fantasysmp:item/ender_leggings"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/diamond_sword",
"textures": {
"layer0": "fantasysmp:item/ender_sword"
}
}
@@ -1,7 +0,0 @@
{
"parent": "item/netherite_sword",
"textures": {
"layer0": "fantasysmp:item/lightning_sword"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/netherite_boots",
"textures": {
"layer0": "fantasysmp:item/poseidons_boots"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/netherite_chestplate",
"textures": {
"layer0": "fantasysmp:item/poseidons_chestplate"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/netherite_helmet",
"textures": {
"layer0": "fantasysmp:item/poseidons_helmet"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/netherite_leggings",
"textures": {
"layer0": "fantasysmp:item/poseidons_leggings"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/trident",
"textures": {
"layer0": "fantasysmp:item/poseidons_trident"
}
}
@@ -1,28 +0,0 @@
{
"parent": "item/netherite_sword",
"display": {
"thirdperson_righthand": {
"rotation": [ 0, -90, 55 ],
"translation": [ 0, 12, -1 ],
"scale": [ 2.0, 2.0, 1.25 ]
},
"thirdperson_lefthand": {
"rotation": [ 0, 90, -55 ],
"translation": [ 0, 12, -1 ],
"scale": [ 2.0, 2.0, 1.25 ]
},
"firstperson_righthand": {
"rotation": [ 0, -90, 40 ],
"translation": [ 1.13, 3.2, 1.13 ],
"scale": [ 1.5, 1.5, 1.5 ]
},
"firstperson_lefthand": {
"rotation": [ 0, 90, -40 ],
"translation": [ 1.13, 3.2, 1.13 ],
"scale": [ 1.5, 1.5, 1.5 ]
}
},
"textures": {
"layer0": "fantasysmp:item/stevens_wrath"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/netherite_boots",
"textures": {
"layer0": "fantasysmp:item/true_netherite_boots"
}
}

Some files were not shown because too many files have changed in this diff Show More