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
build / build (push) Has been cancelled
This commit is contained in:
@@ -1,11 +1,29 @@
|
|||||||
package dev.zxq5.client
|
package dev.zxq5.client
|
||||||
|
|
||||||
|
import dev.zxq5.ModItemTagProvider
|
||||||
|
import dev.zxq5.ModRecipeProvider
|
||||||
|
import dev.zxq5.items.ItemImplementation
|
||||||
|
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
|
||||||
|
|
||||||
object FantasysmpDataGenerator : DataGeneratorEntrypoint {
|
object FantasysmpDataGenerator : DataGeneratorEntrypoint {
|
||||||
override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) {
|
override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) {
|
||||||
|
val pack = fabricDataGenerator.createPack()
|
||||||
|
pack.addProvider(::ModRecipeProvider) // main-safe, can live in either sourceSet
|
||||||
|
pack.addProvider(::ModItemTagProvider) // main-safe
|
||||||
|
pack.addProvider(::ModModelProvider) // needs client, since ItemModelGenerators is client-only
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// client sourceSet
|
||||||
|
class ModModelProvider(output: FabricPackOutput) : FabricModelProvider(output) {
|
||||||
|
override fun generateBlockStateModels(blockModels: BlockModelGenerators) {}
|
||||||
|
|
||||||
|
override fun generateItemModels(itemModels: ItemModelGenerators) {
|
||||||
|
ItemImplementation.all.forEach { it.generateItemModels(itemModels) }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,30 +1,29 @@
|
|||||||
package dev.zxq5
|
package dev.zxq5
|
||||||
|
|
||||||
|
import dev.zxq5.items.ItemImplementation
|
||||||
|
import dev.zxq5.items.ItemTagAdder
|
||||||
import dev.zxq5.items.ModItems
|
import dev.zxq5.items.ModItems
|
||||||
import dev.zxq5.items.Witherite
|
import dev.zxq5.items.Witherite
|
||||||
import dev.zxq5.items.isWearingFullSet
|
|
||||||
import net.fabricmc.api.ModInitializer
|
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.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents
|
||||||
import net.fabricmc.fabric.api.event.player.AttackEntityCallback
|
import net.minecraft.core.HolderLookup
|
||||||
import net.minecraft.world.InteractionHand
|
import net.minecraft.data.recipes.RecipeOutput
|
||||||
import net.minecraft.world.InteractionResult
|
import net.minecraft.data.recipes.RecipeProvider
|
||||||
import net.minecraft.world.effect.MobEffectInstance
|
|
||||||
import net.minecraft.world.effect.MobEffects
|
import net.minecraft.world.effect.MobEffects
|
||||||
import net.minecraft.world.entity.LivingEntity
|
|
||||||
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.
|
// Register the group.
|
||||||
registerItemEffects()
|
registerItemEffects()
|
||||||
}
|
}
|
||||||
@@ -32,32 +31,36 @@ object Fantasysmp : ModInitializer {
|
|||||||
private fun registerItemEffects() {
|
private fun registerItemEffects() {
|
||||||
ServerTickEvents.END_SERVER_TICK.register { server ->
|
ServerTickEvents.END_SERVER_TICK.register { server ->
|
||||||
for (player in server.playerList.players) {
|
for (player in server.playerList.players) {
|
||||||
if (player.isWearingFullSet(Witherite.ARMOUR_SET)) {
|
if (Witherite.fullSetEquippedBy(player)) {
|
||||||
player.removeEffect(MobEffects.WITHER)
|
player.removeEffect(MobEffects.WITHER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
AttackEntityCallback.EVENT.register { player, world, hand, entity, _ ->
|
}
|
||||||
if (world.isClientSide) return@register InteractionResult.PASS
|
|
||||||
if (hand != InteractionHand.MAIN_HAND) return@register InteractionResult.PASS
|
class ModRecipeProvider(
|
||||||
if (player.getItemInHand(hand).item != Witherite.SWORD) return@register InteractionResult.PASS
|
output: FabricPackOutput,
|
||||||
if (entity is LivingEntity) {
|
registriesFuture: CompletableFuture<HolderLookup.Provider>
|
||||||
entity.addEffect(MobEffectInstance(MobEffects.WITHER, 60, 1), player)
|
) : FabricRecipeProvider(output, registriesFuture) {
|
||||||
}
|
override fun createRecipeProvider(
|
||||||
|
registries: HolderLookup.Provider,
|
||||||
InteractionResult.PASS
|
exporter: RecipeOutput
|
||||||
}
|
): RecipeProvider {
|
||||||
|
return object : RecipeProvider(registries, exporter) {
|
||||||
AttackEntityCallback.EVENT.register { player, world, hand, entity, _ ->
|
override fun buildRecipes() {
|
||||||
if (world.isClientSide) return@register InteractionResult.PASS
|
ItemImplementation.all.forEach { it.generateRecipes(registries, exporter) }
|
||||||
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)
|
|
||||||
}
|
override fun getName(): String = "Fantasysmp Recipes"
|
||||||
|
}
|
||||||
InteractionResult.PASS
|
|
||||||
}
|
class ModItemTagProvider(output: FabricPackOutput, registriesFuture: CompletableFuture<HolderLookup.Provider>) :
|
||||||
|
FabricTagsProvider.ItemTagsProvider(output, registriesFuture) {
|
||||||
|
override fun addTags(provider: HolderLookup.Provider) {
|
||||||
|
val adder = ItemTagAdder(this)
|
||||||
|
ItemImplementation.all.forEach { it.generateItemTags(adder) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ object Dragonite {
|
|||||||
val SWORD = register("dragonite_sword", ::DragoniteSword,
|
val SWORD = register("dragonite_sword", ::DragoniteSword,
|
||||||
Item.Properties()
|
Item.Properties()
|
||||||
.enchantable(armorMaterial.enchantmentValue)
|
.enchantable(armorMaterial.enchantmentValue)
|
||||||
.component(DataComponents.USE_COOLDOWN, UseCooldown(0.0f))
|
.component(DataComponents.USE_COOLDOWN, UseCooldown(2f))
|
||||||
.sword(ToolMaterial.NETHERITE, 3.0F, -2.4F)
|
.sword(ToolMaterial.NETHERITE, 3.0F, -2.4F)
|
||||||
)
|
)
|
||||||
val HELMET = register(
|
val HELMET = register(
|
||||||
@@ -109,26 +109,21 @@ object Dragonite {
|
|||||||
|
|
||||||
class DragoniteSword(properties: Properties) : Item(properties) {
|
class DragoniteSword(properties: Properties) : Item(properties) {
|
||||||
override fun use(level: Level, user: Player, hand: InteractionHand): InteractionResult {
|
override fun use(level: Level, user: Player, hand: InteractionHand): InteractionResult {
|
||||||
if (level.isClientSide) return InteractionResult.PASS
|
// if (level.isClientSide || !user.isWearingFullSet(Dragonite.ARMOUR_SET)) return InteractionResult.PASS
|
||||||
if (!user.isWearingFullSet(Dragonite.ARMOUR_SET)) return InteractionResult.PASS
|
|
||||||
|
|
||||||
val stack = user.getItemInHand(hand)
|
val direction = user.lookAngle
|
||||||
if (user.cooldowns.isOnCooldown(stack)) return InteractionResult.PASS
|
user.deltaMovement = direction.scale(2.0)
|
||||||
|
|
||||||
val dir = user.lookAngle
|
|
||||||
user.deltaMovement = dir.scale(2.0)
|
|
||||||
user.hurtMarked = true
|
user.hurtMarked = true
|
||||||
|
|
||||||
level.playSound(null, user.x, user.y, user.z,
|
level.playSound(null, user.x, user.y, user.z,
|
||||||
SoundEvents.ENDER_DRAGON_FLAP, SoundSource.PLAYERS, 1.0f, 1.0f)
|
SoundEvents.ENDER_DRAGON_FLAP, SoundSource.PLAYERS, 1.0f, 1.0f)
|
||||||
|
|
||||||
(level as? ServerLevel)?.sendParticles(
|
// TODO("fix this broken ahh code. WHY TF DOES FABRIC HAVE NO DOCUMENTATION FOR BASICALLY ANYTHING.")
|
||||||
ParticleTypes.DRAGON_BREATH as ParticleOptions,
|
// (level as? ServerLevel)?.sendParticles(
|
||||||
user.x, user.y, user.z,
|
// ParticleTypes.DRAGON_BREATH as ParticleOptions,
|
||||||
100, 0.5, 0.5, 0.5, 0.5
|
// user.x, user.y, user.z,
|
||||||
)
|
// 100, 0.5, 0.5, 0.5, 0.5
|
||||||
|
// )
|
||||||
user.cooldowns.addCooldown(stack, 25)
|
|
||||||
|
|
||||||
return InteractionResult.SUCCESS
|
return InteractionResult.SUCCESS
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,126 @@
|
|||||||
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.util.id
|
||||||
|
import dev.zxq5.util.resourceKey
|
||||||
import net.fabricmc.fabric.api.creativetab.v1.FabricCreativeModeTab
|
import net.fabricmc.fabric.api.creativetab.v1.FabricCreativeModeTab
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagsProvider
|
||||||
|
import net.minecraft.advancements.criterion.InventoryChangeTrigger
|
||||||
|
import net.minecraft.advancements.criterion.ItemPredicate
|
||||||
|
import net.minecraft.client.data.models.ItemModelGenerators
|
||||||
|
import net.minecraft.core.Holder
|
||||||
|
import net.minecraft.core.HolderGetter
|
||||||
|
import net.minecraft.core.HolderLookup
|
||||||
import net.minecraft.core.Registry
|
import net.minecraft.core.Registry
|
||||||
import net.minecraft.core.registries.BuiltInRegistries
|
import net.minecraft.core.registries.BuiltInRegistries
|
||||||
import net.minecraft.core.registries.Registries
|
import net.minecraft.core.registries.Registries
|
||||||
|
import net.minecraft.data.recipes.RecipeCategory
|
||||||
|
import net.minecraft.data.recipes.RecipeOutput
|
||||||
|
import net.minecraft.data.recipes.RecipeProvider
|
||||||
|
import net.minecraft.data.recipes.ShapedRecipeBuilder
|
||||||
|
import net.minecraft.data.recipes.SmithingTransformRecipeBuilder
|
||||||
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.sounds.SoundEvent
|
||||||
|
import net.minecraft.tags.TagKey
|
||||||
import net.minecraft.world.entity.EquipmentSlot
|
import net.minecraft.world.entity.EquipmentSlot
|
||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
import net.minecraft.world.item.*
|
import net.minecraft.world.item.*
|
||||||
import net.minecraft.world.item.CreativeModeTab.DisplayItemsGenerator
|
import net.minecraft.world.item.crafting.Ingredient
|
||||||
import net.minecraft.world.item.CreativeModeTab.ItemDisplayParameters
|
import net.minecraft.world.item.equipment.ArmorMaterial
|
||||||
import java.util.function.Supplier
|
import net.minecraft.world.item.equipment.ArmorMaterials
|
||||||
|
import net.minecraft.world.item.equipment.ArmorType
|
||||||
|
import net.minecraft.world.item.equipment.EquipmentAsset
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
abstract class ItemImplementation {
|
||||||
|
// list of all items part of the class
|
||||||
|
abstract val items: List<Item>
|
||||||
|
|
||||||
|
abstract fun onLoad()
|
||||||
|
|
||||||
|
open fun generateRecipes(registries: HolderLookup.Provider, exporter: RecipeOutput) {}
|
||||||
|
open fun generateItemTags(tags: ItemTagAdder) {}
|
||||||
|
open fun generateItemModels(models: ItemModelGenerators) {}
|
||||||
|
|
||||||
|
init {
|
||||||
|
register(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val _all = mutableListOf<ItemImplementation>()
|
||||||
|
val all: List<ItemImplementation> get() = _all
|
||||||
|
fun register(impl: ItemImplementation) = _all.add(impl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class GenericGearSet: ItemImplementation() {
|
||||||
|
abstract val materialName: String
|
||||||
|
abstract val armorSet: ArmorSet
|
||||||
|
|
||||||
|
open val materialKey: ResourceKey<EquipmentAsset> = materialName.resourceKey()
|
||||||
|
|
||||||
|
open val materialDefinition: GearMaterialDef = GearMaterialDef()
|
||||||
|
val armorMaterial: ArmorMaterial by lazy {
|
||||||
|
materialDefinition.toArmorMaterial()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val itemRecipes = mutableMapOf<Item, List<RecipeSpec>>()
|
||||||
|
private val itemTags = mutableMapOf<Item, List<TagKey<Item>>>()
|
||||||
|
|
||||||
|
internal fun registerDatagen(item: Item, recipes: List<RecipeSpec>, tags: List<TagKey<Item>>) {
|
||||||
|
itemRecipes[item] = recipes
|
||||||
|
itemTags[item] = tags
|
||||||
|
}
|
||||||
|
|
||||||
|
override 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateItemTags(tags: ItemTagAdder) {
|
||||||
|
itemTags.forEach { (item, tagList) -> tagList.forEach { tags.add(it, item) } }
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
|
||||||
object ModItems {
|
object ModItems {
|
||||||
fun <T : Item> register(
|
fun <T : Item> register(
|
||||||
@@ -29,36 +134,106 @@ 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) }
|
ItemImplementation.all.forEach {
|
||||||
Dragonite.ITEMS.forEach { output.accept(it) }
|
it.items.forEach(output::accept)
|
||||||
})
|
}
|
||||||
|
}
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
fun init() {
|
private val eagerLoad = listOf(Witherite, Dragonite)
|
||||||
Witherite.init();
|
|
||||||
Dragonite.init();
|
fun onLoad() {
|
||||||
|
// ensure that implementations such as creative tab are loaded and initialised
|
||||||
|
eagerLoad
|
||||||
|
ItemImplementation.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(
|
data class GearMaterialDef(
|
||||||
val helmet: Item,
|
val durability: Int = ArmorMaterials.NETHERITE.durability,
|
||||||
val chestplate: Item,
|
val defence: Map<ArmorType, Int> = ArmorMaterials.NETHERITE.defense,
|
||||||
val leggings: Item,
|
val enchantability: Int = ArmorMaterials.NETHERITE.enchantmentValue,
|
||||||
val boots: Item,
|
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,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun Player.isWearingFullSet(set: ArmorSet): Boolean {
|
fun GearMaterialDef.toArmorMaterial(): ArmorMaterial {
|
||||||
return getItemBySlot(EquipmentSlot.HEAD).item == set.helmet &&
|
return ArmorMaterial(
|
||||||
getItemBySlot(EquipmentSlot.CHEST).item == set.chestplate &&
|
durability,
|
||||||
getItemBySlot(EquipmentSlot.LEGS).item == set.leggings &&
|
defence,
|
||||||
getItemBySlot(EquipmentSlot.FEET).item == set.boots
|
enchantability,
|
||||||
|
equipSound,
|
||||||
|
toughness,
|
||||||
|
knockbackResistance,
|
||||||
|
repairIngredient,
|
||||||
|
assetId,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ItemTagAdder(private val provider: FabricTagsProvider.ItemTagsProvider) {
|
||||||
|
fun add(tag: TagKey<Item>, vararg items: Item) {
|
||||||
|
provider.apply { items.forEach { add(tag, it) } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
class GearItemBuilder<T : Item>(
|
||||||
|
private val owner: GenericGearSet,
|
||||||
|
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>>()
|
||||||
|
|
||||||
|
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: TagKey<Item>) {
|
||||||
|
tags += tag
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun build(): T {
|
||||||
|
val item = ModItems.register(name, itemFactory, properties)
|
||||||
|
owner.registerDatagen(item, recipes, tags)
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Item> GenericGearSet.gearItem(
|
||||||
|
name: String,
|
||||||
|
itemFactory: (Item.Properties) -> T,
|
||||||
|
block: GearItemBuilder<T>.() -> Unit = {},
|
||||||
|
): GearItemBuilder<T> = GearItemBuilder(this, name, itemFactory).apply(block)
|
||||||
|
|
||||||
|
operator fun <T : Item> GearItemBuilder<T>.provideDelegate(
|
||||||
|
thisRef: Any?, property: KProperty<*>
|
||||||
|
): Lazy<T> = lazy { build() }
|
||||||
|
|
||||||
|
operator fun <T : Item> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
|
||||||
@@ -1,78 +1,56 @@
|
|||||||
package dev.zxq5.items
|
package dev.zxq5.items
|
||||||
|
|
||||||
import dev.zxq5.Fantasysmp
|
|
||||||
import dev.zxq5.items.ModItems.register
|
import dev.zxq5.items.ModItems.register
|
||||||
import net.minecraft.core.component.DataComponents
|
import net.minecraft.core.component.DataComponents
|
||||||
import net.minecraft.resources.Identifier
|
|
||||||
import net.minecraft.resources.ResourceKey
|
|
||||||
import net.minecraft.sounds.SoundEvents
|
import net.minecraft.sounds.SoundEvents
|
||||||
import net.minecraft.tags.ItemTags
|
|
||||||
import net.minecraft.util.Unit
|
|
||||||
import net.minecraft.world.InteractionHand
|
import net.minecraft.world.InteractionHand
|
||||||
import net.minecraft.world.InteractionResult
|
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.EntityType
|
||||||
|
import net.minecraft.world.entity.LivingEntity
|
||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
import net.minecraft.world.entity.projectile.hurtingprojectile.WitherSkull
|
import net.minecraft.world.entity.projectile.hurtingprojectile.WitherSkull
|
||||||
import net.minecraft.world.item.Item
|
import net.minecraft.world.item.Item
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.item.ToolMaterial
|
import net.minecraft.world.item.ToolMaterial
|
||||||
import net.minecraft.world.item.component.BlocksAttacks
|
import net.minecraft.world.item.component.BlocksAttacks
|
||||||
import net.minecraft.world.item.component.UseCooldown
|
import net.minecraft.world.item.component.UseCooldown
|
||||||
import net.minecraft.world.item.equipment.*
|
import net.minecraft.world.item.equipment.ArmorMaterial
|
||||||
|
import net.minecraft.world.item.equipment.ArmorType
|
||||||
import net.minecraft.world.level.Level
|
import net.minecraft.world.level.Level
|
||||||
import java.util.Optional
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
object Witherite {
|
object Witherite: GenericGearSet() {
|
||||||
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,
|
val SHIELD = register("witherite_shield", ::Item,
|
||||||
Item.Properties().component(DataComponents.BLOCKS_ATTACKS, BlocksAttacks(
|
Item.Properties()
|
||||||
0.25f, // 5 tick warmup
|
.component(DataComponents.BLOCKS_ATTACKS, BlocksAttacks(
|
||||||
1.0f, // standard disable cooldown
|
0.25f, // 5 tick warmup
|
||||||
listOf(
|
1.0f, // standard disable cooldown
|
||||||
BlocksAttacks.DamageReduction(
|
listOf(
|
||||||
90.0f, // horizontalBlockingAngle — 90° arc each side (180° total, same as vanilla)
|
BlocksAttacks.DamageReduction(
|
||||||
Optional.empty(), // type — empty = blocks all damage types
|
90.0f, // horizontalBlockingAngle — 90° arc each side (180° total, same as vanilla)
|
||||||
0.0f, // base — flat damage reduction
|
Optional.empty(), // type — empty = blocks all damage types
|
||||||
1.0f // factor — multiplier (1.0 = block 100% of damage)
|
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
|
), // full block — check if this constant exists, else build the list manually
|
||||||
Optional.empty(), // no bypass
|
BlocksAttacks.ItemDamageFunction.DEFAULT, // check for this constant too
|
||||||
Optional.empty(), // default block sound
|
Optional.empty(), // no bypass
|
||||||
Optional.empty() // default disable sound
|
Optional.empty(), // default block sound
|
||||||
))
|
Optional.empty() // default disable sound
|
||||||
|
))
|
||||||
)
|
)
|
||||||
|
|
||||||
val SWORD = register("witherite_sword", ::WitheriteSword,
|
val SWORD = register("witherite_sword", ::WitheriteSword,
|
||||||
Item.Properties()
|
Item.Properties()
|
||||||
.enchantable(armorMaterial.enchantmentValue)
|
.enchantable(armorMaterial.enchantmentValue)
|
||||||
.component(DataComponents.USE_COOLDOWN, UseCooldown(0.0f))
|
.component(DataComponents.USE_COOLDOWN, UseCooldown(2f))
|
||||||
.sword(ToolMaterial.NETHERITE, 3F, -2.4F)
|
.sword(ToolMaterial.NETHERITE, 3F, -2.4F)
|
||||||
)
|
)
|
||||||
|
|
||||||
val AXE = register("witherite_axe", ::Item,
|
val AXE = register("witherite_axe", ::WitheriteWeapon,
|
||||||
Item.Properties()
|
Item.Properties()
|
||||||
.enchantable(armorMaterial.enchantmentValue)
|
.enchantable(armorMaterial.enchantmentValue)
|
||||||
.axe(ToolMaterial.NETHERITE, 5F, -3F))
|
.axe(ToolMaterial.NETHERITE, 5F, -3F))
|
||||||
@@ -114,21 +92,33 @@ object Witherite {
|
|||||||
.durability(ArmorType.BOOTS.getDurability(armorMaterial.durability))
|
.durability(ArmorType.BOOTS.getDurability(armorMaterial.durability))
|
||||||
)
|
)
|
||||||
|
|
||||||
val ITEMS = listOf(SWORD, AXE, SHIELD, HELMET, CHESTPLATE, LEGGINGS, BOOTS)
|
override val materialName = "witherite"
|
||||||
val ARMOUR_SET = ArmorSet(HELMET, CHESTPLATE, LEGGINGS, BOOTS)
|
override val materialDefinition = super.materialDefinition.copy(assetId = materialKey)
|
||||||
|
override val armorSet: ArmorSet = ArmorSet(HELMET, CHESTPLATE, LEGGINGS, BOOTS)
|
||||||
|
override val items = listOf(SWORD, AXE, SHIELD, HELMET, CHESTPLATE, LEGGINGS, BOOTS)
|
||||||
|
|
||||||
fun init() {}
|
override fun onLoad() {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WitheriteSword(properties: Properties) : Item(properties) {
|
open class WitheriteWeapon(properties: Properties): Item(properties) {
|
||||||
override fun use(level: Level, user: Player, hand: InteractionHand): InteractionResult {
|
override fun hurtEnemy(itemStack: ItemStack, mob: LivingEntity, attacker: LivingEntity) {
|
||||||
if (level.isClientSide) {
|
super.hurtEnemy(itemStack, mob, attacker)
|
||||||
return InteractionResult.PASS;
|
|
||||||
}
|
|
||||||
if (!user.isCrouching) return InteractionResult.PASS
|
|
||||||
|
|
||||||
val stack = user.getItemInHand(hand)
|
if (attacker.level().isClientSide) return
|
||||||
if (user.cooldowns.isOnCooldown(stack)) return InteractionResult.PASS
|
|
||||||
|
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)
|
val skull = WitherSkull(EntityType.WITHER_SKULL, level)
|
||||||
skull.setPos(user.eyePosition)
|
skull.setPos(user.eyePosition)
|
||||||
@@ -136,8 +126,6 @@ class WitheriteSword(properties: Properties) : Item(properties) {
|
|||||||
level.addFreshEntity(skull)
|
level.addFreshEntity(skull)
|
||||||
skull.playSound(SoundEvents.WITHER_SHOOT)
|
skull.playSound(SoundEvents.WITHER_SHOOT)
|
||||||
|
|
||||||
user.cooldowns.addCooldown(stack, 25)
|
|
||||||
|
|
||||||
return InteractionResult.SUCCESS;
|
return InteractionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package dev.zxq5.util
|
||||||
|
import dev.zxq5.Fantasysmp
|
||||||
|
import net.minecraft.resources.Identifier
|
||||||
|
import net.minecraft.resources.ResourceKey
|
||||||
|
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),
|
||||||
|
)
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 589 B After Width: | Height: | Size: 607 B |
Binary file not shown.
|
After Width: | Height: | Size: 589 B |
Binary file not shown.
|
Before Width: | Height: | Size: 451 B After Width: | Height: | Size: 552 B |
Binary file not shown.
|
After Width: | Height: | Size: 552 B |
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"values": [
|
||||||
|
"fantasysmp:witherite_helmet",
|
||||||
|
"fantasysmp:witherite_chestplate",
|
||||||
|
"fantasysmp:witherite_leggings",
|
||||||
|
"fantasysmp:witherite_boots",
|
||||||
|
"fantasysmp:dragonite_helmet",
|
||||||
|
"fantasysmp:dragonite_chestplate",
|
||||||
|
"fantasysmp:dragonite_leggings",
|
||||||
|
"fantasysmp:dragonite_boots"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"values": [
|
||||||
|
"fantasysmp:witherite_helmet",
|
||||||
|
"fantasysmp:witherite_chestplate",
|
||||||
|
"fantasysmp:witherite_leggings",
|
||||||
|
"fantasysmp:witherite_boots",
|
||||||
|
"fantasysmp:dragonite_helmet",
|
||||||
|
"fantasysmp:dragonite_chestplate",
|
||||||
|
"fantasysmp:dragonite_leggings",
|
||||||
|
"fantasysmp:dragonite_boots"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user