From eb1a6383a61ac0b2f397fb4b598737152af6b55c Mon Sep 17 00:00:00 2001 From: MysticKoko <132279944+MysticKoko@users.noreply.github.com> Date: Mon, 15 Jul 2024 10:08:52 +0300 Subject: [PATCH] Started implementing the new variant system to crustaceans --- .../crustacean/FiddlerCrabEntityModel.kt | 12 +- .../entity/crustacean/GhostCrabEntityModel.kt | 12 +- .../HybridAquaticCrustaceanEntityModel.kt | 15 +- .../entity/crustacean/LobsterEntityModel.kt | 12 +- .../entity/crustacean/ShrimpEntityModel.kt | 12 +- .../entity/critter/NudibranchEntity.kt | 4 +- .../entity/crustacean/CoconutCrabEntity.kt | 2 +- .../entity/crustacean/CrayfishEntity.kt | 2 +- .../entity/crustacean/DungenessCrabEntity.kt | 2 +- .../entity/crustacean/FiddlerCrabEntity.kt | 2 +- .../entity/crustacean/FlowerCrabEntity.kt | 2 +- .../entity/crustacean/GhostCrabEntity.kt | 2 +- .../entity/crustacean/GiantIsopodEntity.kt | 2 +- .../entity/crustacean/HermitCrabEntity.kt | 2 +- .../entity/crustacean/HorseshoeCrabEntity.kt | 2 +- .../HybridAquaticCrustaceanEntity.kt | 179 ++++++++++++++++-- .../entity/crustacean/KarkinosEntity.kt | 2 +- .../entity/crustacean/LightfootCrabEntity.kt | 2 +- .../entity/crustacean/LobsterEntity.kt | 2 +- .../aquatic/entity/crustacean/ShrimpEntity.kt | 2 +- .../entity/crustacean/SpiderCrabEntity.kt | 2 +- .../entity/crustacean/VampireCrabEntity.kt | 2 +- .../entity/crustacean/YetiCrabEntity.kt | 2 +- 23 files changed, 198 insertions(+), 80 deletions(-) diff --git a/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/FiddlerCrabEntityModel.kt b/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/FiddlerCrabEntityModel.kt index b9e96548d..184b8d864 100644 --- a/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/FiddlerCrabEntityModel.kt +++ b/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/FiddlerCrabEntityModel.kt @@ -1,15 +1,5 @@ package dev.hybridlabs.aquatic.client.model.entity.crustacean import dev.hybridlabs.aquatic.entity.crustacean.HybridAquaticCrustaceanEntity -import net.minecraft.util.Identifier -class FiddlerCrabEntityModel : HybridAquaticCrustaceanEntityModel("fiddler_crab") { - override fun getTextureResource(animatable: HybridAquaticCrustaceanEntity?): Identifier { - if (animatable != null) return getVariantTexture(allVariants[animatable.variant]) - return super.getTextureResource(animatable) - } - - companion object { - val allVariants: Array = arrayOf("blue", "red", "purple", "palestine") - } -} +class FiddlerCrabEntityModel : HybridAquaticCrustaceanEntityModel("fiddler_crab") \ No newline at end of file diff --git a/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/GhostCrabEntityModel.kt b/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/GhostCrabEntityModel.kt index 07b890016..9d25fd9fa 100644 --- a/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/GhostCrabEntityModel.kt +++ b/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/GhostCrabEntityModel.kt @@ -1,15 +1,5 @@ package dev.hybridlabs.aquatic.client.model.entity.crustacean import dev.hybridlabs.aquatic.entity.crustacean.HybridAquaticCrustaceanEntity -import net.minecraft.util.Identifier -class GhostCrabEntityModel : HybridAquaticCrustaceanEntityModel("ghost_crab") { - override fun getTextureResource(animatable: HybridAquaticCrustaceanEntity?): Identifier { - if (animatable != null) return getVariantTexture(allVariants[animatable.variant]) - return super.getTextureResource(animatable) - } - - companion object { - val allVariants: Array = arrayOf("white", "yellow", "red", "brown", "palestine") - } -} +class GhostCrabEntityModel : HybridAquaticCrustaceanEntityModel("ghost_crab") \ No newline at end of file diff --git a/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/HybridAquaticCrustaceanEntityModel.kt b/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/HybridAquaticCrustaceanEntityModel.kt index 937bba1f0..d67324545 100644 --- a/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/HybridAquaticCrustaceanEntityModel.kt +++ b/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/HybridAquaticCrustaceanEntityModel.kt @@ -7,18 +7,23 @@ import software.bernie.geckolib.model.GeoModel abstract class HybridAquaticCrustaceanEntityModel (private val id: String) : GeoModel() { override fun getModelResource(animatable: T?): Identifier { + val variant = animatable?.variant + if (variant != null && !variant.ignore.contains(HybridAquaticCrustaceanEntity.CrustaceanVariant.Ignore.MODEL)) + return Identifier(HybridAquatic.MOD_ID, "geo/${id}_${variant.getProvidedVariant(animatable)}.geo.json") return Identifier(HybridAquatic.MOD_ID, "geo/$id.geo.json") } override fun getTextureResource(animatable: T?): Identifier { - return Identifier(HybridAquatic.MOD_ID, "textures/entity/crustacean/$id/$id.png") - } - - fun getVariantTexture(variant: String): Identifier { - return Identifier(HybridAquatic.MOD_ID, "textures/entity/crustacean/$id/${id}_$variant.png") + val variant = animatable?.variant + if (variant != null && !variant.ignore.contains(HybridAquaticCrustaceanEntity.CrustaceanVariant.Ignore.TEXTURE)) + return Identifier(HybridAquatic.MOD_ID, "textures/entity/crustacean/${id}/${id}_${variant.getProvidedVariant(animatable)}.png") + return Identifier(HybridAquatic.MOD_ID, "textures/entity/crustacean/${id}/$id.png") } override fun getAnimationResource(animatable: T?): Identifier { + val variant = animatable?.variant + if (variant != null && !variant.ignore.contains(HybridAquaticCrustaceanEntity.CrustaceanVariant.Ignore.ANIMATION)) + return Identifier(HybridAquatic.MOD_ID, "animations/${id}_${variant.getProvidedVariant(animatable)}.animation.json") return Identifier(HybridAquatic.MOD_ID, "animations/$id.animation.json") } } \ No newline at end of file diff --git a/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/LobsterEntityModel.kt b/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/LobsterEntityModel.kt index 9a2e51332..b4ace87e8 100644 --- a/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/LobsterEntityModel.kt +++ b/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/LobsterEntityModel.kt @@ -1,15 +1,5 @@ package dev.hybridlabs.aquatic.client.model.entity.crustacean import dev.hybridlabs.aquatic.entity.crustacean.HybridAquaticCrustaceanEntity -import net.minecraft.util.Identifier -class LobsterEntityModel : HybridAquaticCrustaceanEntityModel("lobster") { - override fun getTextureResource(animatable: HybridAquaticCrustaceanEntity?): Identifier { - if (animatable != null) return getVariantTexture(allVariants[animatable.variant]) - return super.getTextureResource(animatable) - } - - companion object { - val allVariants: Array = arrayOf("ornate_spiny", "california_spiny", "american") - } -} \ No newline at end of file +class LobsterEntityModel : HybridAquaticCrustaceanEntityModel("lobster") \ No newline at end of file diff --git a/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/ShrimpEntityModel.kt b/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/ShrimpEntityModel.kt index 9f5a5177f..b22a9c040 100644 --- a/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/ShrimpEntityModel.kt +++ b/src/client/kotlin/dev/hybridlabs/aquatic/client/model/entity/crustacean/ShrimpEntityModel.kt @@ -1,15 +1,5 @@ package dev.hybridlabs.aquatic.client.model.entity.crustacean import dev.hybridlabs.aquatic.entity.crustacean.HybridAquaticCrustaceanEntity -import net.minecraft.util.Identifier -class ShrimpEntityModel : HybridAquaticCrustaceanEntityModel("shrimp") { - override fun getTextureResource(animatable: HybridAquaticCrustaceanEntity?): Identifier { - if (animatable != null) return getVariantTexture(allVariants[animatable.variant]) - return super.getTextureResource(animatable) - } - - companion object { - val allVariants: Array = arrayOf("blue", "blue_white", "black", "black_white", "red", "red_white", "green", "green_white", "brown", "brown_white", "lime", "lime_white", "yellow", "yellow_white", "pink", "pink_white", "white", "orange", "orange_white", "palestine") - } -} +class ShrimpEntityModel : HybridAquaticCrustaceanEntityModel("shrimp") \ No newline at end of file diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/critter/NudibranchEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/critter/NudibranchEntity.kt index c302a0e02..033f237f4 100644 --- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/critter/NudibranchEntity.kt +++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/critter/NudibranchEntity.kt @@ -12,9 +12,7 @@ import software.bernie.geckolib.core.`object`.PlayState class NudibranchEntity(entityType: EntityType, world: World) : HybridAquaticCritterEntity(entityType, world, variants = hashMapOf( - "pyjama" to CritterVariant.biomeVariant( - "pyjama", - HybridAquaticBiomeTags.NUDIBRANCH_SPAWN_BIOMES, + "pyjama" to CritterVariant.biomeVariant("pyjama", HybridAquaticBiomeTags.NUDIBRANCH_SPAWN_BIOMES, ignore = listOf(CritterVariant.Ignore.MODEL, CritterVariant.Ignore.ANIMATION)), "bullock" to CritterVariant.biomeVariant("bullock", HybridAquaticBiomeTags.NUDIBRANCH_SPAWN_BIOMES, ignore = listOf(CritterVariant.Ignore.MODEL, CritterVariant.Ignore.ANIMATION)), diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/CoconutCrabEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/CoconutCrabEntity.kt index 2fcf0a12e..f12bfb1ed 100644 --- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/CoconutCrabEntity.kt +++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/CoconutCrabEntity.kt @@ -7,7 +7,7 @@ import net.minecraft.entity.mob.WaterCreatureEntity import net.minecraft.world.World class CoconutCrabEntity(entityType: EntityType, world: World) : - HybridAquaticCrustaceanEntity(entityType, world, 1, false, true) { + HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false) { companion object { fun createMobAttributes(): DefaultAttributeContainer.Builder { return WaterCreatureEntity.createMobAttributes() diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/CrayfishEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/CrayfishEntity.kt index b2424f1ce..3c052d09d 100644 --- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/CrayfishEntity.kt +++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/CrayfishEntity.kt @@ -7,7 +7,7 @@ import net.minecraft.entity.mob.WaterCreatureEntity import net.minecraft.world.World class CrayfishEntity(entityType: EntityType, world: World) : - HybridAquaticCrustaceanEntity(entityType, world, 1, false, false) { + HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false) { companion object { fun createMobAttributes(): DefaultAttributeContainer.Builder { return WaterCreatureEntity.createMobAttributes() diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/DungenessCrabEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/DungenessCrabEntity.kt index 85e23a870..8de7fb3a4 100644 --- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/DungenessCrabEntity.kt +++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/DungenessCrabEntity.kt @@ -7,7 +7,7 @@ import net.minecraft.entity.mob.WaterCreatureEntity import net.minecraft.world.World class DungenessCrabEntity(entityType: EntityType, world: World) : - HybridAquaticCrustaceanEntity(entityType, world, 1, false, true) { + HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false) { companion object { fun createMobAttributes(): DefaultAttributeContainer.Builder { return WaterCreatureEntity.createMobAttributes() diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/FiddlerCrabEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/FiddlerCrabEntity.kt index 95ab9109c..59ffb5a4c 100644 --- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/FiddlerCrabEntity.kt +++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/FiddlerCrabEntity.kt @@ -7,7 +7,7 @@ import net.minecraft.entity.mob.WaterCreatureEntity import net.minecraft.world.World class FiddlerCrabEntity(entityType: EntityType, world: World) : - HybridAquaticCrustaceanEntity(entityType, world, 3, false, true) { + HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false) { companion object { fun createMobAttributes(): DefaultAttributeContainer.Builder { return WaterCreatureEntity.createMobAttributes() diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/FlowerCrabEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/FlowerCrabEntity.kt index 6cabaff0f..5237a79bd 100644 --- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/FlowerCrabEntity.kt +++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/FlowerCrabEntity.kt @@ -7,7 +7,7 @@ import net.minecraft.entity.mob.WaterCreatureEntity import net.minecraft.world.World class FlowerCrabEntity(entityType: EntityType, world: World) : - HybridAquaticCrustaceanEntity(entityType, world, 1, false, true) { + HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false) { companion object { fun createMobAttributes(): DefaultAttributeContainer.Builder { return WaterCreatureEntity.createMobAttributes() diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/GhostCrabEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/GhostCrabEntity.kt index 19ec2505c..1769b9971 100644 --- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/GhostCrabEntity.kt +++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/GhostCrabEntity.kt @@ -7,7 +7,7 @@ import net.minecraft.entity.mob.WaterCreatureEntity import net.minecraft.world.World class GhostCrabEntity(entityType: EntityType, world: World) : - HybridAquaticCrustaceanEntity(entityType, world, 4, false, true) { + HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false) { companion object { fun createMobAttributes(): DefaultAttributeContainer.Builder { return WaterCreatureEntity.createMobAttributes() diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/GiantIsopodEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/GiantIsopodEntity.kt index 4a18bbba1..6be0ee632 100644 --- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/GiantIsopodEntity.kt +++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/GiantIsopodEntity.kt @@ -7,7 +7,7 @@ import net.minecraft.entity.mob.WaterCreatureEntity import net.minecraft.world.World class GiantIsopodEntity(entityType: EntityType, world: World) : - HybridAquaticCrustaceanEntity(entityType, world, 1, false, false) { + HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false) { companion object { fun createMobAttributes(): DefaultAttributeContainer.Builder { return WaterCreatureEntity.createMobAttributes() diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/HermitCrabEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/HermitCrabEntity.kt index 6e7413693..1b5dd5dec 100644 --- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/HermitCrabEntity.kt +++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/HermitCrabEntity.kt @@ -11,7 +11,7 @@ import software.bernie.geckolib.core.animation.AnimationState import software.bernie.geckolib.core.`object`.PlayState class HermitCrabEntity(entityType: EntityType, world: World) : - HybridAquaticCrustaceanEntity(entityType, world, 1, true, false) { + HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), true, false) { private var isHiding: Boolean = false private var hidingTimer: Int = 0 diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/HorseshoeCrabEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/HorseshoeCrabEntity.kt index 59864e1ea..73e3a1194 100644 --- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/HorseshoeCrabEntity.kt +++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/HorseshoeCrabEntity.kt @@ -7,7 +7,7 @@ import net.minecraft.entity.mob.WaterCreatureEntity import net.minecraft.world.World class HorseshoeCrabEntity(entityType: EntityType, world: World) : - HybridAquaticCrustaceanEntity(entityType, world, 1, false, false) { + HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false) { companion object { fun createMobAttributes(): DefaultAttributeContainer.Builder { return WaterCreatureEntity.createMobAttributes() diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/HybridAquaticCrustaceanEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/HybridAquaticCrustaceanEntity.kt index c85ce9f63..c35fcd515 100644 --- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/HybridAquaticCrustaceanEntity.kt +++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/HybridAquaticCrustaceanEntity.kt @@ -1,5 +1,6 @@ package dev.hybridlabs.aquatic.entity.crustacean +import dev.hybridlabs.aquatic.entity.fish.HybridAquaticFishEntity import dev.hybridlabs.aquatic.tag.HybridAquaticBlockTags import dev.hybridlabs.aquatic.tag.HybridAquaticItemTags import net.minecraft.block.Blocks @@ -17,11 +18,13 @@ import net.minecraft.entity.mob.WaterCreatureEntity import net.minecraft.entity.player.PlayerEntity import net.minecraft.nbt.NbtCompound import net.minecraft.recipe.Ingredient +import net.minecraft.registry.tag.TagKey import net.minecraft.sound.SoundEvent import net.minecraft.sound.SoundEvents import net.minecraft.util.math.BlockPos import net.minecraft.util.math.random.Random import net.minecraft.world.* +import net.minecraft.world.biome.Biome import software.bernie.geckolib.animatable.GeoEntity import software.bernie.geckolib.core.animatable.GeoAnimatable import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache @@ -34,9 +37,11 @@ import software.bernie.geckolib.util.GeckoLibUtil open class HybridAquaticCrustaceanEntity( type: EntityType, world: World, - private val variantCount: Int = 1, + private val variants: Map = mutableMapOf(), open val canDig: Boolean, open val canDance: Boolean, + open val assumeDefault: Boolean = false, + open val collisionRules: List = listOf(), ) : WaterCreatureEntity(type, world), GeoEntity { private val factory = GeckoLibUtil.createInstanceCache(this) private var landNavigation: EntityNavigation = createNavigation(world) @@ -50,12 +55,6 @@ open class HybridAquaticCrustaceanEntity( dataTracker.set(IS_DIGGING, bool) } - var variant: Int - get() = dataTracker.get(VARIANT).coerceAtLeast(0).coerceAtMost(variantCount-1) - set(int) { - dataTracker.set(VARIANT, int) - } - var size: Int get() = dataTracker.get(CRUSTACEAN_SIZE) set(size) { @@ -68,13 +67,36 @@ private var attemptAttack: Boolean dataTracker.set(ATTEMPT_ATTACK, attemptAttack) } + private var variantData: NbtCompound + get() = dataTracker.get(VARIANT_DATA) + set(value) { + dataTracker.set(VARIANT_DATA, value) + } + + private var variantKey: String + get() = dataTracker.get(VARIANT).ifBlank { + if (!assumeDefault && variants.isNotEmpty()) { + variants.isNotEmpty() + } + dataTracker.get(VARIANT) + } + private set(value) { + dataTracker.set(VARIANT, value) + } + + @Suppress("UNUSED_PARAMETER") + var variant: CrustaceanVariant? + get() = variants[variantKey] + private set(value) {} + override fun initDataTracker() { super.initDataTracker() dataTracker.startTracking(MOISTNESS, getMaxMoistness()) dataTracker.startTracking(IS_DIGGING, false) - dataTracker.startTracking(VARIANT, 0) dataTracker.startTracking(CRUSTACEAN_SIZE, 0) dataTracker.startTracking(ATTEMPT_ATTACK, false) + dataTracker.startTracking(VARIANT, "") + dataTracker.startTracking(VARIANT_DATA, NbtCompound()) } override fun initGoals() { @@ -93,8 +115,45 @@ private var attemptAttack: Boolean entityNbt: NbtCompound? ): EntityData? { this.air = getMaxMoistness() - this.variant = this.random.nextInt(variantCount) this.size = this.random.nextBetween(getMinSize(),getMaxSize()) + + if (variants.isNotEmpty()) { + if (spawnReason == SpawnReason.SPAWN_EGG) { + variantKey = variants.keys.elementAt(random.nextBetween(0, variants.size - 1)) + } else { + // Handle collisions + val validKeys = variants.filter { it.value.spawnCondition(world, spawnReason, blockPos, random) }.map { it.key } + + if (validKeys.isEmpty()) { + variantKey = variants.keys.random() + } else if (collisionRules.isNotEmpty()) { + for (rule in collisionRules) { + val variantSet = rule.variants.toSet() + if ((rule.exclusionStatus == HybridAquaticFishEntity.VariantCollisionRules.ExclusionStatus.EXCLUSIVE && validKeys.toSet() == variantSet) || + (rule.exclusionStatus == HybridAquaticFishEntity.VariantCollisionRules.ExclusionStatus.INCLUSIVE && validKeys.containsAll(variantSet))) { + variantKey = rule.collisionHandler(validKeys.toSet(), random, world) + break + } + } + } else { + // Default to a priority based system + val validityFilter = variants.filter { validKeys.contains(it.key) } + variantKey = if (validityFilter.isNotEmpty()) { + val maxPriority = validityFilter.values.maxOf { it.priority } + val filteredMap = validityFilter.filter { it.value.priority == maxPriority } + if (filteredMap.isNotEmpty()) { + filteredMap.keys.random() + } else { + validKeys.random() + } + } else { + validKeys.random() + } + } + } + } + + this.size = this.random.nextBetween(getMinSize(), getMaxSize()) return super.initialize(world, difficulty, spawnReason, entityData, entityNbt) } @@ -158,7 +217,8 @@ private var attemptAttack: Boolean super.writeCustomDataToNbt(nbt) nbt.putInt(MOISTNESS_KEY, moistness) nbt.putInt(DIGGING_COOLDOWN_KEY, diggingCooldown) - nbt.putInt(VARIANT_KEY, variant) + nbt.putString(VARIANT_KEY, variantKey) + nbt.put(VARIANT_DATA_KEY, variantData) nbt.putInt(CRUSTACEAN_SIZE_KEY, size) } @@ -166,7 +226,8 @@ private var attemptAttack: Boolean super.readCustomDataFromNbt(nbt) moistness = nbt.getInt(MOISTNESS_KEY) diggingCooldown = nbt.getInt(DIGGING_COOLDOWN_KEY) - variant = nbt.getInt(VARIANT_KEY).coerceAtLeast(0).coerceAtMost(variantCount-1) + variantKey = nbt.getString(VARIANT_KEY) + variantData = nbt.getCompound(VARIANT_DATA_KEY) size = nbt.getInt(CRUSTACEAN_SIZE_KEY) } @@ -306,9 +367,10 @@ private var attemptAttack: Boolean companion object { val MOISTNESS: TrackedData = DataTracker.registerData(HybridAquaticCrustaceanEntity::class.java, TrackedDataHandlerRegistry.INTEGER) - val VARIANT: TrackedData = DataTracker.registerData(HybridAquaticCrustaceanEntity::class.java, TrackedDataHandlerRegistry.INTEGER) val CRUSTACEAN_SIZE: TrackedData = DataTracker.registerData(HybridAquaticCrustaceanEntity::class.java, TrackedDataHandlerRegistry.INTEGER) val ATTEMPT_ATTACK: TrackedData = DataTracker.registerData(HybridAquaticCrustaceanEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN) + val VARIANT: TrackedData = DataTracker.registerData(HybridAquaticCrustaceanEntity::class.java, TrackedDataHandlerRegistry.STRING) + var VARIANT_DATA: TrackedData = DataTracker.registerData(HybridAquaticCrustaceanEntity::class.java, TrackedDataHandlerRegistry.NBT_COMPOUND) val DANCE_ANIMATION: RawAnimation = RawAnimation.begin().then("dance", Animation.LoopType.LOOP) val DIG_ANIMATION: RawAnimation = RawAnimation.begin().then("dig", Animation.LoopType.LOOP) @@ -354,10 +416,103 @@ private var attemptAttack: Boolean const val MOISTNESS_KEY = "Moistness" const val VARIANT_KEY = "Variant" + const val VARIANT_DATA_KEY = "VariantData" const val CRUSTACEAN_SIZE_KEY = "CrustaceanSize" val IS_DIGGING: TrackedData = DataTracker.registerData(HybridAquaticCrustaceanEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN) const val DIGGING_COOLDOWN_KEY = "DiggingCooldown" } + + @Suppress("UNUSED") + data class CrustaceanVariant( + val variantName : String, + val spawnCondition: (WorldAccess, SpawnReason, BlockPos, Random ) -> Boolean, + val ignore: List = emptyList(), + val priority: Int = 0, + var providedVariant: (World, BlockPos, Random, HybridAquaticCrustaceanEntity) -> String = { _, _, _, _ -> + variantName + } + ) { + + fun getProvidedVariant(crustacean: HybridAquaticCrustaceanEntity) : String { + return providedVariant(crustacean.world, crustacean.blockPos, crustacean.random, crustacean) + } + + companion object { + /** + * Creates a biome variant of a fish + */ + fun biomeVariant(variantName: String, biomes : TagKey, ignore : List = emptyList()): CrustaceanVariant { + return CrustaceanVariant(variantName, { world, _, pos, _ -> + world.getBiome(pos).isIn(biomes) + }, ignore) + } + } + + enum class Ignore { + TEXTURE, + MODEL, + ANIMATION + } + } + + @Suppress("UNUSED") + data class VariantCollisionRules(val variants : Set, val collisionHandler: (Set, Random, ServerWorldAccess) -> String, val exclusionStatus: ExclusionStatus = ExclusionStatus.INCLUSIVE) { + + /** + * INCLUSIVE - all other variants can exist within this selection swath + *
 
+ * EXCLUSIVE - all other variants are excluded from this selection swath + */ + enum class ExclusionStatus { + INCLUSIVE, + EXCLUSIVE + } + + /** + *

+         * Example:
+         * ```kotlin
+         * // returns a bluefin or a yellowfin tuna variant
+         * equalDistribution(setOf("bluefin", "yellowfin"))
+         * ```
+         * @return a random variant within the set
+         */
+        fun equalDistribution(variants: Set, status : ExclusionStatus = ExclusionStatus.INCLUSIVE) : VariantCollisionRules {
+            return VariantCollisionRules(variants, { possibleVariants, _, _ ->
+                possibleVariants.random()
+            }, status)
+        }
+
+        /**
+         * Example
+         * ```
+         * weightedDistribution(setOf(
+         *  Pair("bluefin", 0.80),
+         *  Pair("yellowfin", 0.20)
+         * ))
+         * ```
+         * @return a premade variant collision rule which allows weighted distribution of variants.
+         */
+        fun weightedDistribution(weights: Set>, status: ExclusionStatus = ExclusionStatus.EXCLUSIVE) : VariantCollisionRules {
+            return VariantCollisionRules(weights.map { pair -> pair.first }.toSet(), { _, random, _ ->
+                // sum up weights
+                val weightTotal = weights.sumOf { pair -> pair.second }
+                val randomVal = random.nextFloat() * weightTotal
+                var accumulatedWeight = 0.0
+                var result = ""
+
+                for (pair in weights) {
+                    accumulatedWeight += pair.second
+                    if (randomVal < accumulatedWeight) {
+                        result = pair.first
+                        break
+                    }
+                }
+
+                result
+            }, status)
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/KarkinosEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/KarkinosEntity.kt
index bc22a96ac..89f71a4ee 100644
--- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/KarkinosEntity.kt
+++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/KarkinosEntity.kt
@@ -29,7 +29,7 @@ import software.bernie.geckolib.core.`object`.PlayState
 import java.util.*
 
 class KarkinosEntity(entityType: EntityType, world: World) :
-    HybridAquaticCrustaceanEntity(entityType, world, 1, false, false), Angerable {
+    HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false), Angerable {
 
     init {
         stepHeight = 2.0F
diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/LightfootCrabEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/LightfootCrabEntity.kt
index df897eb72..6adf0cbec 100644
--- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/LightfootCrabEntity.kt
+++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/LightfootCrabEntity.kt
@@ -7,7 +7,7 @@ import net.minecraft.entity.mob.WaterCreatureEntity
 import net.minecraft.world.World
 
 class LightfootCrabEntity(entityType: EntityType, world: World) :
-    HybridAquaticCrustaceanEntity(entityType, world, 1, false, true) {
+    HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false) {
     companion object {
         fun createMobAttributes(): DefaultAttributeContainer.Builder {
             return WaterCreatureEntity.createMobAttributes()
diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/LobsterEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/LobsterEntity.kt
index a4d47196d..9a081505d 100644
--- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/LobsterEntity.kt
+++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/LobsterEntity.kt
@@ -7,7 +7,7 @@ import net.minecraft.entity.mob.WaterCreatureEntity
 import net.minecraft.world.World
 
 class LobsterEntity(entityType: EntityType, world: World) :
-    HybridAquaticCrustaceanEntity(entityType, world, 3, false, false) {
+    HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false) {
 
     companion object {
         fun createMobAttributes(): DefaultAttributeContainer.Builder {
diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/ShrimpEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/ShrimpEntity.kt
index c3e20317b..db30740d8 100644
--- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/ShrimpEntity.kt
+++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/ShrimpEntity.kt
@@ -7,7 +7,7 @@ import net.minecraft.entity.mob.WaterCreatureEntity
 import net.minecraft.world.World
 
 class ShrimpEntity(entityType: EntityType, world: World) :
-    HybridAquaticCrustaceanEntity(entityType, world, 20, false, false) {
+    HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false) {
     companion object {
         fun createMobAttributes(): DefaultAttributeContainer.Builder {
             return WaterCreatureEntity.createMobAttributes()
diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/SpiderCrabEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/SpiderCrabEntity.kt
index d14487189..f7ac26945 100644
--- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/SpiderCrabEntity.kt
+++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/SpiderCrabEntity.kt
@@ -7,7 +7,7 @@ import net.minecraft.entity.mob.WaterCreatureEntity
 import net.minecraft.world.World
 
 class SpiderCrabEntity(entityType: EntityType, world: World) :
-    HybridAquaticCrustaceanEntity(entityType, world, 1, false, true) {
+    HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false) {
     companion object {
         fun createMobAttributes(): DefaultAttributeContainer.Builder {
             return WaterCreatureEntity.createMobAttributes()
diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/VampireCrabEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/VampireCrabEntity.kt
index d75688bec..ba11d98ea 100644
--- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/VampireCrabEntity.kt
+++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/VampireCrabEntity.kt
@@ -7,7 +7,7 @@ import net.minecraft.entity.mob.WaterCreatureEntity
 import net.minecraft.world.World
 
 class VampireCrabEntity(entityType: EntityType, world: World) :
-    HybridAquaticCrustaceanEntity(entityType, world, 1, false, true) {
+    HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false) {
     companion object {
         fun createMobAttributes(): DefaultAttributeContainer.Builder {
             return WaterCreatureEntity.createMobAttributes()
diff --git a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/YetiCrabEntity.kt b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/YetiCrabEntity.kt
index 47035a1f7..4797f7e34 100644
--- a/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/YetiCrabEntity.kt
+++ b/src/main/kotlin/dev/hybridlabs/aquatic/entity/crustacean/YetiCrabEntity.kt
@@ -9,7 +9,7 @@ import net.minecraft.util.math.BlockPos
 import net.minecraft.world.World
 
 class YetiCrabEntity(entityType: EntityType, world: World) :
-    HybridAquaticCrustaceanEntity(entityType, world, 1, false, true) {
+    HybridAquaticCrustaceanEntity(entityType, world, emptyMap(), false, false) {
 
     private var targetVentPos: BlockPos? = null