feat: projection person AI (incomplete)
This commit is contained in:
parent
24080f0437
commit
89473d2dcc
@ -25,6 +25,7 @@ object Quaedam {
|
||||
val blocks = DeferredRegister.create(ID, Registries.BLOCK)!!
|
||||
val blockEntities = DeferredRegister.create(ID, Registries.BLOCK_ENTITY_TYPE)!!
|
||||
val entities = DeferredRegister.create(ID, Registries.ENTITY_TYPE)!!
|
||||
val schedule = DeferredRegister.create(ID, Registries.SCHEDULE)!!
|
||||
val projectionEffects = DeferredRegister.create(ID, ProjectionEffectType.registryKey)!!
|
||||
|
||||
val creativeModeTab: RegistrySupplier<CreativeModeTab> = creativeModeTabs.register("quaedam") {
|
||||
@ -43,6 +44,7 @@ object Quaedam {
|
||||
blocks.register()
|
||||
blockEntities.register()
|
||||
entities.register()
|
||||
schedule.register()
|
||||
projectionEffects.register()
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,126 @@
|
||||
package quaedam.projection.swarm
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.mojang.datafixers.util.Pair
|
||||
import net.minecraft.world.entity.ai.Brain
|
||||
import net.minecraft.world.entity.ai.behavior.*
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.sensing.SensorType
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
import net.minecraft.world.entity.schedule.Schedule
|
||||
import net.minecraft.world.entity.schedule.ScheduleBuilder
|
||||
import quaedam.Quaedam
|
||||
|
||||
object ProjectedPersonAI {
|
||||
|
||||
private val memoryTypes = listOf(
|
||||
MemoryModuleType.PATH,
|
||||
MemoryModuleType.LOOK_TARGET,
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
MemoryModuleType.ATTACK_TARGET,
|
||||
MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES,
|
||||
MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM,
|
||||
MemoryModuleType.HURT_BY,
|
||||
MemoryModuleType.ATTACK_COOLING_DOWN
|
||||
)
|
||||
|
||||
private val sensorTypes = listOf(
|
||||
SensorType.NEAREST_LIVING_ENTITIES,
|
||||
SensorType.NEAREST_PLAYERS,
|
||||
SensorType.HURT_BY,
|
||||
SensorType.NEAREST_ITEMS
|
||||
)
|
||||
|
||||
val defaultSchedule = Quaedam.schedule.register("projected_person_default") {
|
||||
ScheduleBuilder(Schedule()).changeActivityAt(10, Activity.IDLE)
|
||||
.changeActivityAt(10, Activity.IDLE)
|
||||
.changeActivityAt(2000, Activity.WORK)
|
||||
.changeActivityAt(7300, Activity.IDLE)
|
||||
.changeActivityAt(9000, Activity.WORK)
|
||||
.changeActivityAt(10700, Activity.IDLE)
|
||||
.changeActivityAt(11000, Activity.PLAY)
|
||||
.changeActivityAt(11500, Activity.IDLE)
|
||||
.changeActivityAt(12000, Activity.REST)
|
||||
.build()
|
||||
}
|
||||
|
||||
val babySchedule = Quaedam.schedule.register("projected_person_baby") {
|
||||
ScheduleBuilder(Schedule()).changeActivityAt(10, Activity.IDLE)
|
||||
.changeActivityAt(10, Activity.IDLE)
|
||||
.changeActivityAt(3200, Activity.PLAY)
|
||||
.changeActivityAt(7000, Activity.IDLE)
|
||||
.changeActivityAt(9000, Activity.PLAY)
|
||||
.changeActivityAt(11000, Activity.REST)
|
||||
.build()
|
||||
}
|
||||
|
||||
fun provider(): Brain.Provider<out ProjectedPersonEntity> = Brain.provider(memoryTypes, sensorTypes)
|
||||
|
||||
fun initBrain(entity: ProjectedPersonEntity, brain: Brain<ProjectedPersonEntity>) {
|
||||
if (entity.shape.baby) {
|
||||
brain.schedule = babySchedule.get()
|
||||
} else {
|
||||
brain.schedule = defaultSchedule.get()
|
||||
}
|
||||
|
||||
initCoreActivity(brain)
|
||||
initIdleActivity(brain)
|
||||
initPlayActivity(brain)
|
||||
initWorkActivity(brain)
|
||||
initRestActivity(brain)
|
||||
brain.setCoreActivities(setOf(Activity.CORE))
|
||||
brain.setDefaultActivity(Activity.IDLE)
|
||||
brain.updateActivityFromSchedule(entity.level().dayTime, entity.level().gameTime)
|
||||
}
|
||||
|
||||
private fun initCoreActivity(brain: Brain<ProjectedPersonEntity>) {
|
||||
brain.addActivity(
|
||||
Activity.CORE, 0, ImmutableList.of(
|
||||
Swim(0.8f),
|
||||
InteractWithDoor.create(),
|
||||
LookAtTargetSink(40, 70),
|
||||
MoveToTargetSink(),
|
||||
WakeUp.create(),
|
||||
)
|
||||
)
|
||||
brain.addActivity(
|
||||
Activity.CORE, 3, ImmutableList.of(
|
||||
GoToWantedItem.create(0.7f, false, 7)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun initIdleActivity(brain: Brain<ProjectedPersonEntity>) {
|
||||
brain.addActivity(Activity.IDLE, 99, ImmutableList.of(UpdateActivityFromSchedule.create()))
|
||||
}
|
||||
|
||||
private fun initPlayActivity(brain: Brain<ProjectedPersonEntity>) {
|
||||
brain.addActivity(
|
||||
Activity.PLAY, 3, ImmutableList.of(
|
||||
GoToWantedItem.create(1.75f, true, 32),
|
||||
)
|
||||
)
|
||||
brain.addActivity(
|
||||
Activity.PLAY, 5, ImmutableList.of(
|
||||
JumpOnBed(0.5f),
|
||||
RunOne(
|
||||
listOf(
|
||||
Pair.of(RandomStroll.stroll(0.5f), 2),
|
||||
Pair.of(SetWalkTargetFromLookTarget.create(1.0f, 5), 2),
|
||||
Pair.of(DoNothing(30, 60), 1)
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
brain.addActivity(Activity.PLAY, 99, ImmutableList.of(UpdateActivityFromSchedule.create()))
|
||||
}
|
||||
|
||||
private fun initWorkActivity(brain: Brain<ProjectedPersonEntity>) {
|
||||
brain.addActivity(Activity.WORK, 99, ImmutableList.of(UpdateActivityFromSchedule.create()))
|
||||
}
|
||||
|
||||
private fun initRestActivity(brain: Brain<ProjectedPersonEntity>) {
|
||||
brain.addActivity(Activity.REST, 99, ImmutableList.of(UpdateActivityFromSchedule.create()))
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package quaedam.projection.swarm
|
||||
|
||||
import com.mojang.serialization.Dynamic
|
||||
import dev.architectury.platform.Platform
|
||||
import dev.architectury.registry.client.level.entity.EntityRendererRegistry
|
||||
import dev.architectury.registry.level.entity.EntityAttributeRegistry
|
||||
import net.fabricmc.api.EnvType
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
@ -13,6 +13,7 @@ import net.minecraft.network.syncher.SynchedEntityData
|
||||
import net.minecraft.world.DifficultyInstance
|
||||
import net.minecraft.world.SimpleContainer
|
||||
import net.minecraft.world.entity.*
|
||||
import net.minecraft.world.entity.ai.Brain
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
@ -22,8 +23,8 @@ import net.minecraft.world.level.ServerLevelAccessor
|
||||
import quaedam.Quaedam
|
||||
import quaedam.projector.Projector
|
||||
|
||||
class ProjectedPersonEntity(entityType: EntityType<out PathfinderMob>, level: Level) :
|
||||
PathfinderMob(entityType, level), InventoryCarrier {
|
||||
class ProjectedPersonEntity(entityType: EntityType<out PathfinderMob>, level: Level) : PathfinderMob(entityType, level),
|
||||
InventoryCarrier {
|
||||
|
||||
companion object {
|
||||
|
||||
@ -35,28 +36,24 @@ class ProjectedPersonEntity(entityType: EntityType<out PathfinderMob>, level: Le
|
||||
const val BOUNDING_HEIGHT = 1.8f
|
||||
|
||||
val entity = Quaedam.entities.register(ID) {
|
||||
EntityType.Builder.of(::ProjectedPersonEntity, MobCategory.CREATURE)
|
||||
.canSpawnFarFromPlayer()
|
||||
.sized(BOUNDING_WIDTH, BOUNDING_HEIGHT * 1.2f)
|
||||
.build("quaedam:$ID")
|
||||
EntityType.Builder.of(::ProjectedPersonEntity, MobCategory.CREATURE).canSpawnFarFromPlayer()
|
||||
.sized(BOUNDING_WIDTH, BOUNDING_HEIGHT * 1.2f).build("quaedam:$ID")
|
||||
}!!
|
||||
|
||||
val dataShape =
|
||||
SynchedEntityData.defineId(ProjectedPersonEntity::class.java, EntityDataSerializers.COMPOUND_TAG)
|
||||
|
||||
private fun createAttributes(): AttributeSupplier.Builder = Mob.createMobAttributes()
|
||||
.add(Attributes.ATTACK_DAMAGE, 1.5)
|
||||
.add(Attributes.MOVEMENT_SPEED, 0.11)
|
||||
.add(Attributes.ATTACK_SPEED)
|
||||
|
||||
init {
|
||||
EntityAttributeRegistry.register(entity, ::createAttributes)
|
||||
if (Platform.getEnv() == EnvType.CLIENT) {
|
||||
EntityRendererRegistry.register(entity, ::ProjectedPersonRenderer)
|
||||
}
|
||||
if (Platform.getEnv() == EnvType.CLIENT) ProjectedPersonRenderer
|
||||
ProjectedPersonShape
|
||||
ProjectedPersonAI
|
||||
}
|
||||
|
||||
private fun createAttributes(): AttributeSupplier.Builder =
|
||||
Mob.createMobAttributes().add(Attributes.ATTACK_DAMAGE, 1.5).add(Attributes.MOVEMENT_SPEED, 0.11)
|
||||
.add(Attributes.ATTACK_SPEED)
|
||||
|
||||
}
|
||||
|
||||
override fun finalizeSpawn(
|
||||
@ -106,8 +103,8 @@ class ProjectedPersonEntity(entityType: EntityType<out PathfinderMob>, level: Le
|
||||
|
||||
override fun shouldShowName() = true
|
||||
|
||||
override fun getTypeName(): Component = shape.name.takeIf { it.isNotEmpty() }?.let { Component.literal(it) }
|
||||
?: super.getTypeName()
|
||||
override fun getTypeName(): Component =
|
||||
shape.name.takeIf { it.isNotEmpty() }?.let { Component.literal(it) } ?: super.getTypeName()
|
||||
|
||||
override fun getNameTagOffsetY() = super.getNameTagOffsetY() - (BOUNDING_HEIGHT * (1.2f - shape.scaleY))
|
||||
|
||||
@ -116,8 +113,7 @@ class ProjectedPersonEntity(entityType: EntityType<out PathfinderMob>, level: Le
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
if (tickCount % 20 == 0) {
|
||||
if (!checkProjectionEffect())
|
||||
remove(RemovalReason.KILLED)
|
||||
if (!checkProjectionEffect()) remove(RemovalReason.KILLED)
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,8 +122,7 @@ class ProjectedPersonEntity(entityType: EntityType<out PathfinderMob>, level: Le
|
||||
|
||||
override fun checkDespawn() {
|
||||
super.checkDespawn()
|
||||
if (!checkProjectionEffect())
|
||||
discard()
|
||||
if (!checkProjectionEffect()) discard()
|
||||
}
|
||||
|
||||
private val inventory = SimpleContainer(10)
|
||||
@ -146,4 +141,16 @@ class ProjectedPersonEntity(entityType: EntityType<out PathfinderMob>, level: Le
|
||||
|
||||
override fun removeWhenFarAway(d: Double) = false
|
||||
|
||||
// Type signature referenced from: https://github.com/bbrk24/amurians-mod/blob/7a0f0c3c7a3e84c22e5c631286ad23795207adc0/src/main/kotlin/org/bbrk24/amurians/amurian/AmurianEntity.kt#L220
|
||||
override fun brainProvider() = ProjectedPersonAI.provider()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun makeBrain(dynamic: Dynamic<*>): Brain<out ProjectedPersonEntity> = brainProvider().makeBrain(dynamic)
|
||||
.also { ProjectedPersonAI.initBrain(this, it as Brain<ProjectedPersonEntity>) }
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun getBrain(): Brain<ProjectedPersonEntity> = super.getBrain() as Brain<ProjectedPersonEntity>
|
||||
|
||||
override fun isBaby() = shape.baby
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package quaedam.projection.swarm
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import dev.architectury.registry.client.level.entity.EntityRendererRegistry
|
||||
import net.fabricmc.api.EnvType
|
||||
import net.fabricmc.api.Environment
|
||||
import net.minecraft.client.model.PlayerModel
|
||||
@ -18,6 +19,12 @@ class ProjectedPersonRenderer(context: EntityRendererProvider.Context) :
|
||||
0.4f
|
||||
) {
|
||||
|
||||
companion object {
|
||||
init {
|
||||
EntityRendererRegistry.register(ProjectedPersonEntity.entity, ::ProjectedPersonRenderer)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
addLayer(CustomHeadLayer(this, context.modelSet, context.itemInHandRenderer))
|
||||
addLayer(ItemInHandLayer(this, context.itemInHandRenderer))
|
||||
|
@ -22,6 +22,7 @@ data class ProjectedPersonShape(
|
||||
val scaleZ: Float = 1.0f,
|
||||
val name: String = "",
|
||||
val skin: Int = 0,
|
||||
val baby: Boolean = false,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
@ -31,6 +32,7 @@ data class ProjectedPersonShape(
|
||||
const val KEY_SCALE_Z = "ScaleZ"
|
||||
const val KEY_NAME = "Name"
|
||||
const val KEY_SKIN = "Skin"
|
||||
const val KEY_BABY = "Baby"
|
||||
|
||||
init {
|
||||
Names
|
||||
@ -45,6 +47,7 @@ data class ProjectedPersonShape(
|
||||
scaleZ = rand.nextInt(0..2 * 4) * 0.025f + 0.9f,
|
||||
name = Names.random(rand),
|
||||
skin = Skins.random(rand),
|
||||
baby = rand.nextInt(500) == 1
|
||||
)
|
||||
|
||||
fun fromTag(tag: CompoundTag) = ProjectedPersonShape(
|
||||
@ -53,6 +56,7 @@ data class ProjectedPersonShape(
|
||||
scaleZ = tag.getFloat(KEY_SCALE_Z),
|
||||
name = tag.getString(KEY_NAME),
|
||||
skin = tag.getInt(KEY_SKIN),
|
||||
baby = tag.getBoolean(KEY_BABY)
|
||||
)
|
||||
|
||||
}
|
||||
@ -63,6 +67,7 @@ data class ProjectedPersonShape(
|
||||
putFloat(KEY_SCALE_Z, scaleZ)
|
||||
putString(KEY_NAME, name)
|
||||
putInt(KEY_SKIN, skin)
|
||||
putBoolean(KEY_BABY, baby)
|
||||
}
|
||||
|
||||
object Names {
|
||||
|
Loading…
Reference in New Issue
Block a user