feat: item exchange
This commit is contained in:
parent
f2ceaf176c
commit
e13d5ff178
@ -26,6 +26,7 @@ object Quaedam {
|
|||||||
val blockEntities = DeferredRegister.create(ID, Registries.BLOCK_ENTITY_TYPE)!!
|
val blockEntities = DeferredRegister.create(ID, Registries.BLOCK_ENTITY_TYPE)!!
|
||||||
val entities = DeferredRegister.create(ID, Registries.ENTITY_TYPE)!!
|
val entities = DeferredRegister.create(ID, Registries.ENTITY_TYPE)!!
|
||||||
val schedules = DeferredRegister.create(ID, Registries.SCHEDULE)!!
|
val schedules = DeferredRegister.create(ID, Registries.SCHEDULE)!!
|
||||||
|
val memoryTypes = DeferredRegister.create(ID, Registries.MEMORY_MODULE_TYPE)!!
|
||||||
val sensors = DeferredRegister.create(ID, Registries.SENSOR_TYPE)!!
|
val sensors = DeferredRegister.create(ID, Registries.SENSOR_TYPE)!!
|
||||||
val projectionEffects = DeferredRegister.create(ID, ProjectionEffectType.registryKey)!!
|
val projectionEffects = DeferredRegister.create(ID, ProjectionEffectType.registryKey)!!
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ object Quaedam {
|
|||||||
blockEntities.register()
|
blockEntities.register()
|
||||||
entities.register()
|
entities.register()
|
||||||
schedules.register()
|
schedules.register()
|
||||||
|
memoryTypes.register()
|
||||||
sensors.register()
|
sensors.register()
|
||||||
projectionEffects.register()
|
projectionEffects.register()
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package quaedam.projection.swarm.ai
|
|||||||
|
|
||||||
import net.minecraft.core.GlobalPos
|
import net.minecraft.core.GlobalPos
|
||||||
import net.minecraft.server.level.ServerLevel
|
import net.minecraft.server.level.ServerLevel
|
||||||
import net.minecraft.world.entity.Mob
|
import net.minecraft.world.entity.LivingEntity
|
||||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||||
import net.minecraft.world.entity.ai.sensing.Sensor
|
import net.minecraft.world.entity.ai.sensing.Sensor
|
||||||
@ -12,11 +12,13 @@ import net.minecraft.world.level.block.entity.BedBlockEntity
|
|||||||
import net.minecraft.world.level.block.state.properties.BedPart
|
import net.minecraft.world.level.block.state.properties.BedPart
|
||||||
import quaedam.Quaedam
|
import quaedam.Quaedam
|
||||||
|
|
||||||
class BedInChunkSensor : Sensor<Mob>() {
|
class BedInChunkSensor : Sensor<LivingEntity>() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val sensor = Quaedam.sensors.register("bed_in_chunk") {
|
const val ID = "bed_in_chunk"
|
||||||
|
|
||||||
|
val sensor = Quaedam.sensors.register(ID) {
|
||||||
SensorType(::BedInChunkSensor)
|
SensorType(::BedInChunkSensor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +26,7 @@ class BedInChunkSensor : Sensor<Mob>() {
|
|||||||
|
|
||||||
override fun requires() = setOf(MemoryModuleType.NEAREST_BED)
|
override fun requires() = setOf(MemoryModuleType.NEAREST_BED)
|
||||||
|
|
||||||
override fun doTick(level: ServerLevel, entity: Mob) {
|
override fun doTick(level: ServerLevel, entity: LivingEntity) {
|
||||||
if (entity.tickCount and 0b11111 == 0 && !entity.isSleeping) { // 32gt
|
if (entity.tickCount and 0b11111 == 0 && !entity.isSleeping) { // 32gt
|
||||||
level.getChunkAt(entity.blockPosition()).blockEntities
|
level.getChunkAt(entity.blockPosition()).blockEntities
|
||||||
.filterValues { it is BedBlockEntity }
|
.filterValues { it is BedBlockEntity }
|
||||||
|
@ -0,0 +1,126 @@
|
|||||||
|
package quaedam.projection.swarm.ai
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.server.level.ServerLevel
|
||||||
|
import net.minecraft.sounds.SoundEvents
|
||||||
|
import net.minecraft.world.Container
|
||||||
|
import net.minecraft.world.entity.Mob
|
||||||
|
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||||
|
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||||
|
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||||
|
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||||
|
import net.minecraft.world.entity.npc.InventoryCarrier
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity
|
||||||
|
import net.minecraft.world.level.block.entity.ChestBlockEntity
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
class ExchangeItem<E> : Behavior<E>(
|
||||||
|
mapOf(
|
||||||
|
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
|
||||||
|
NearestVisibleContainer.memory.get() to MemoryStatus.VALUE_PRESENT,
|
||||||
|
), 5 * 20, 12 * 20
|
||||||
|
) where E : Mob, E : InventoryCarrier {
|
||||||
|
|
||||||
|
private var target: BlockPos? = null
|
||||||
|
private var closeAt: Long? = null
|
||||||
|
|
||||||
|
override fun start(level: ServerLevel, entity: E, l: Long) {
|
||||||
|
target = entity.brain.getMemory(NearestVisibleContainer.memory.get()).get()
|
||||||
|
closeAt = null
|
||||||
|
entity.brain.setMemory(MemoryModuleType.WALK_TARGET, WalkTarget(target!!, 1.0f, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canStillUse(level: ServerLevel, entity: E, l: Long) =
|
||||||
|
entity.brain.getMemory(MemoryModuleType.WALK_TARGET).isPresent || entity.brain.getMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE).isEmpty || (closeAt != null && closeAt!! < l)
|
||||||
|
|
||||||
|
override fun tick(level: ServerLevel, entity: E, l: Long) {
|
||||||
|
if (closeAt == null) {
|
||||||
|
if (entity.brain.getMemory(MemoryModuleType.WALK_TARGET).isEmpty) {
|
||||||
|
// reached
|
||||||
|
val chest = level.getBlockEntity(target!!) as BaseContainerBlockEntity
|
||||||
|
if (chest is ChestBlockEntity) {
|
||||||
|
ChestBlockEntity.playSound(level, target!!, level.getBlockState(target!!), SoundEvents.CHEST_OPEN)
|
||||||
|
}
|
||||||
|
if (chest.isEmpty) {
|
||||||
|
closeAt = l + 7
|
||||||
|
} else {
|
||||||
|
closeAt = l + 10 + level.random.nextInt(100)
|
||||||
|
exchangeItems(level, entity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stop(level: ServerLevel, entity: E, l: Long) {
|
||||||
|
entity.brain.eraseMemory(MemoryModuleType.WALK_TARGET)
|
||||||
|
if (closeAt != null) {
|
||||||
|
// opened
|
||||||
|
val chest = level.getBlockEntity(target!!)!!
|
||||||
|
if (chest is ChestBlockEntity) {
|
||||||
|
ChestBlockEntity.playSound(level, target!!, level.getBlockState(target!!), SoundEvents.CHEST_CLOSE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun exchangeItems(level: ServerLevel, entity: E) {
|
||||||
|
val container = level.getBlockEntity(target!!) as Container
|
||||||
|
val inventory = entity.inventory
|
||||||
|
for (i in 1..6) {
|
||||||
|
val maxCount = level.random.nextInt(16)
|
||||||
|
if (level.random.nextBoolean()) {
|
||||||
|
// take
|
||||||
|
val slot = level.random.nextInt(container.containerSize)
|
||||||
|
val item = container.getItem(slot)
|
||||||
|
if (!item.isEmpty) {
|
||||||
|
val takeCount = min(item.count, maxCount)
|
||||||
|
val takeItem = item.copyWithCount(takeCount)
|
||||||
|
if (inventory.canTakeItem(container, slot, takeItem) && entity.canHoldItem(takeItem)) {
|
||||||
|
val remaining = entity.inventory.addItem(entity.equipItemIfPossible(takeItem))
|
||||||
|
val actualCount = takeCount - remaining.count
|
||||||
|
item.shrink(actualCount)
|
||||||
|
container.setItem(slot, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// put
|
||||||
|
val slot = level.random.nextInt(inventory.containerSize)
|
||||||
|
val item = inventory.getItem(slot)
|
||||||
|
if (!item.isEmpty) {
|
||||||
|
val takeCount = min(item.count, maxCount)
|
||||||
|
val takeItem = item.copyWithCount(takeCount)
|
||||||
|
if (container.canTakeItem(inventory, slot, takeItem)) {
|
||||||
|
for (target in 0 until container.containerSize) {
|
||||||
|
val targetItem = container.getItem(target)
|
||||||
|
if (ItemStack.isSameItemSameTags(targetItem, takeItem)) {
|
||||||
|
val resultCount = min(targetItem.count + takeItem.count, item.maxStackSize)
|
||||||
|
val putCount = resultCount - targetItem.count
|
||||||
|
if (putCount != 0) {
|
||||||
|
targetItem.grow(putCount)
|
||||||
|
container.setItem(target, targetItem)
|
||||||
|
takeItem.shrink(putCount)
|
||||||
|
if (takeItem.isEmpty) break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!takeItem.isEmpty) {
|
||||||
|
for (target in 0 until container.containerSize) {
|
||||||
|
val targetItem = container.getItem(target)
|
||||||
|
if (targetItem.isEmpty) {
|
||||||
|
container.setItem(target, takeItem.copyAndClear())
|
||||||
|
println("put all at $target")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val putCount = takeCount - takeItem.count
|
||||||
|
println("put $putCount")
|
||||||
|
item.shrink(putCount)
|
||||||
|
container.setItem(slot, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package quaedam.projection.swarm.ai
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.server.level.ServerLevel
|
||||||
|
import net.minecraft.world.entity.LivingEntity
|
||||||
|
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||||
|
import net.minecraft.world.entity.ai.sensing.Sensor
|
||||||
|
import net.minecraft.world.entity.ai.sensing.SensorType
|
||||||
|
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity
|
||||||
|
import quaedam.Quaedam
|
||||||
|
import quaedam.utils.getChunksNearby
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class NearestVisibleContainer : Sensor<LivingEntity>() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
const val ID = "nearest_visible_container"
|
||||||
|
|
||||||
|
val sensor = Quaedam.sensors.register(ID) {
|
||||||
|
SensorType(::NearestVisibleContainer)
|
||||||
|
}!!
|
||||||
|
|
||||||
|
val memory = Quaedam.memoryTypes.register(ID) {
|
||||||
|
MemoryModuleType(Optional.of(BlockPos.CODEC))
|
||||||
|
}!!
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun requires() = setOf(memory.get())
|
||||||
|
|
||||||
|
override fun doTick(level: ServerLevel, entity: LivingEntity) {
|
||||||
|
if (entity.tickCount and 0b11111 == 0) { // 32gt
|
||||||
|
val pos = level.getChunksNearby(entity.blockPosition(), 1)
|
||||||
|
.flatMap { it.blockEntities.filterValues { be -> be is BaseContainerBlockEntity }.keys }
|
||||||
|
.minByOrNull { it.distManhattan(entity.blockPosition()) }
|
||||||
|
entity.brain.setMemory(memory.get(), pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -52,6 +52,7 @@ object ProjectedPersonAI {
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
BedInChunkSensor
|
BedInChunkSensor
|
||||||
|
NearestVisibleContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
private val memoryTypes by lazy {
|
private val memoryTypes by lazy {
|
||||||
@ -67,6 +68,7 @@ object ProjectedPersonAI {
|
|||||||
MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE,
|
MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE,
|
||||||
MemoryModuleType.HOME,
|
MemoryModuleType.HOME,
|
||||||
MemoryModuleType.LAST_WOKEN,
|
MemoryModuleType.LAST_WOKEN,
|
||||||
|
NearestVisibleContainer.memory.get(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,6 +79,7 @@ object ProjectedPersonAI {
|
|||||||
SensorType.HURT_BY,
|
SensorType.HURT_BY,
|
||||||
SensorType.NEAREST_ITEMS,
|
SensorType.NEAREST_ITEMS,
|
||||||
BedInChunkSensor.sensor.get(),
|
BedInChunkSensor.sensor.get(),
|
||||||
|
NearestVisibleContainer.sensor.get(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,6 +149,7 @@ object ProjectedPersonAI {
|
|||||||
private fun initWorkActivity(brain: Brain<ProjectedPersonEntity>) {
|
private fun initWorkActivity(brain: Brain<ProjectedPersonEntity>) {
|
||||||
brain.addActivity(
|
brain.addActivity(
|
||||||
Activity.WORK, ImmutableList.of(
|
Activity.WORK, ImmutableList.of(
|
||||||
|
7 weight ExchangeItem(),
|
||||||
10 weight createStrollBehavior(),
|
10 weight createStrollBehavior(),
|
||||||
99 weight UpdateActivityFromSchedule.create(),
|
99 weight UpdateActivityFromSchedule.create(),
|
||||||
)
|
)
|
||||||
|
@ -4,3 +4,5 @@ accessible method net/minecraft/core/registries/BuiltInRegistries registerSimple
|
|||||||
accessible class net/minecraft/core/registries/BuiltInRegistries$RegistryBootstrap
|
accessible class net/minecraft/core/registries/BuiltInRegistries$RegistryBootstrap
|
||||||
# Entity Brain AI
|
# Entity Brain AI
|
||||||
accessible method net/minecraft/world/entity/ai/sensing/SensorType <init> (Ljava/util/function/Supplier;)V
|
accessible method net/minecraft/world/entity/ai/sensing/SensorType <init> (Ljava/util/function/Supplier;)V
|
||||||
|
# ExchangeItem behaviour
|
||||||
|
accessible method net/minecraft/world/level/block/entity/ChestBlockEntity playSound (Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/sounds/SoundEvent;)V
|
||||||
|
Loading…
Reference in New Issue
Block a user