feat: projection person AI (incomplete)

This commit is contained in:
xtex 2023-07-02 17:34:30 +08:00
parent 24080f0437
commit 89473d2dcc
Signed by: xtex
GPG Key ID: B918086ED8045B91
5 changed files with 168 additions and 21 deletions

View File

@ -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()
}

View File

@ -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()))
}
}

View File

@ -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
}

View File

@ -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))

View File

@ -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 {