refactor: block entity based projection block

This commit is contained in:
xtex 2023-07-19 21:34:25 +08:00
parent 82de489963
commit c80859d643
Signed by: xtex
GPG Key ID: B918086ED8045B91
11 changed files with 115 additions and 95 deletions

View File

@ -9,7 +9,8 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.CreativeModeTab import net.minecraft.world.item.CreativeModeTab
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import quaedam.projection.* import quaedam.projection.ProjectionCommand
import quaedam.projection.ProjectionEffectType
import quaedam.projection.misc.NoiseProjection import quaedam.projection.misc.NoiseProjection
import quaedam.projection.misc.SkylightProjection import quaedam.projection.misc.SkylightProjection
import quaedam.projection.misc.SoundProjection import quaedam.projection.misc.SoundProjection

View File

@ -1,59 +1,32 @@
package quaedam.projection package quaedam.projection
import dev.architectury.registry.registries.DeferredSupplier
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.world.entity.LivingEntity import net.minecraft.server.level.ServerLevel
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.LevelAccessor import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.material.MapColor
import net.minecraft.world.level.storage.loot.LootParams
import quaedam.projector.ProjectorBlockEntity
import quaedam.utils.getChunksNearby
abstract class EntityProjectionBlock<P : ProjectionEffect>(properties: Properties = createProperties()) : Block(properties), abstract class EntityProjectionBlock<P : ProjectionEffect>(properties: Properties = createProperties()) :
ProjectionProvider<P> { ProjectionBlock<P>(properties), EntityBlock {
companion object { companion object {
fun createProperties(): Properties = Properties.of() fun createProperties(): Properties = ProjectionBlock.createProperties()
.strength(3.5f)
.requiresCorrectToolForDrops()
.mapColor(MapColor.COLOR_GRAY)
fun findNearbyProjectors(level: Level, pos: BlockPos) = level.getChunksNearby(pos, 1)
.flatMap {
it.blockEntities.filter { (_, v) -> v is ProjectorBlockEntity }
.keys
.filterNotNull()
}
.toSet()
} }
@Suppress("OVERRIDE_DEPRECATION") abstract val blockEntity: DeferredSupplier<BlockEntityType<SimpleProjectionEntity<P>>>
override fun getDrops(blockState: BlockState, builder: LootParams.Builder) = listOf(ItemStack(asItem()))
override fun setPlacedBy( override fun newBlockEntity(pos: BlockPos, state: BlockState) = blockEntity.get().create(pos, state)
level: Level,
pos: BlockPos,
state: BlockState,
placer: LivingEntity?,
itemStack: ItemStack
) {
super.setPlacedBy(level, pos, state, placer, itemStack)
if (!level.isClientSide) {
findNearbyProjectors(level, pos)
.forEach { (level.getBlockEntity(it) as ProjectorBlockEntity).checkUpdate() }
}
}
override fun destroy(level: LevelAccessor, pos: BlockPos, state: BlockState) { @Suppress("UNCHECKED_CAST")
super.destroy(level, pos, state) fun getProjection(level: Level, pos: BlockPos) = (level.getBlockEntity(pos) as SimpleProjectionEntity<P>).projection
if (level is Level && !level.isClientSide) {
findNearbyProjectors(level, pos) override fun applyProjectionEffect(level: ServerLevel, state: BlockState, pos: BlockPos) = getProjection(level, pos)
.forEach { (level.getBlockEntity(it) as ProjectorBlockEntity).checkUpdate() }
} inline fun applyChange(level: Level, pos: BlockPos, func: P.() -> Unit) {
getProjection(level, pos).apply(func)
sendUpdateToProjectors(level, pos)
} }
} }

View File

@ -42,18 +42,21 @@ abstract class ProjectionBlock<P : ProjectionEffect>(properties: Properties = cr
itemStack: ItemStack itemStack: ItemStack
) { ) {
super.setPlacedBy(level, pos, state, placer, itemStack) super.setPlacedBy(level, pos, state, placer, itemStack)
sendUpdateToProjectors(level, pos)
}
override fun destroy(level: LevelAccessor, pos: BlockPos, state: BlockState) {
super.destroy(level, pos, state)
if (level is Level) {
sendUpdateToProjectors(level, pos)
}
}
fun sendUpdateToProjectors(level: Level, pos: BlockPos) {
if (!level.isClientSide) { if (!level.isClientSide) {
findNearbyProjectors(level, pos) findNearbyProjectors(level, pos)
.forEach { (level.getBlockEntity(it) as ProjectorBlockEntity).checkUpdate() } .forEach { (level.getBlockEntity(it) as ProjectorBlockEntity).checkUpdate() }
} }
} }
override fun destroy(level: LevelAccessor, pos: BlockPos, state: BlockState) {
super.destroy(level, pos, state)
if (level is Level && !level.isClientSide) {
findNearbyProjectors(level, pos)
.forEach { (level.getBlockEntity(it) as ProjectorBlockEntity).checkUpdate() }
}
}
} }

View File

@ -57,5 +57,5 @@ data class ProjectionEffectType<T : ProjectionEffect>(val constructor: () -> T)
} }
interface ProjectionProvider<P : ProjectionEffect> { interface ProjectionProvider<P : ProjectionEffect> {
fun createProjectionEffect(level: ServerLevel, state: BlockState, pos: BlockPos): P? fun applyProjectionEffect(level: ServerLevel, state: BlockState, pos: BlockPos): P?
} }

View File

@ -0,0 +1,51 @@
package quaedam.projection
import dev.architectury.registry.registries.RegistrySupplier
import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.protocol.Packet
import net.minecraft.network.protocol.game.ClientGamePacketListener
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
class SimpleProjectionEntity<P : ProjectionEffect>(
type: BlockEntityType<SimpleProjectionEntity<P>>,
pos: BlockPos,
state: BlockState,
val projection: P
) : BlockEntity(type, pos, state) {
companion object {
const val TAG_PROJECTION_EFFECT = "ProjectionEffect"
fun <P : ProjectionEffect, B: ProjectionBlock<P>> createBlockEntityType(
block: RegistrySupplier<B>,
default: () -> P,
): BlockEntityType<SimpleProjectionEntity<P>> {
val type = ValueContainer<BlockEntityType<SimpleProjectionEntity<P>>>()
type.inner = BlockEntityType.Builder.of({ pos, state ->
SimpleProjectionEntity(type.inner!!, pos, state, default())
}, block.get()).build(null)
return type.inner!!
}
}
data class ValueContainer<E>(var inner: E? = null)
override fun saveAdditional(tag: CompoundTag) {
super.saveAdditional(tag)
tag.put(TAG_PROJECTION_EFFECT, projection.toNbt())
}
override fun load(tag: CompoundTag) {
super.load(tag)
projection.fromNbt(tag.getCompound(TAG_PROJECTION_EFFECT))
}
override fun getUpdateTag(): CompoundTag = saveWithoutMetadata()
override fun getUpdatePacket(): Packet<ClientGamePacketListener> = ClientboundBlockEntityDataPacket.create(this)
}

View File

@ -1,15 +1,13 @@
package quaedam.projection.misc package quaedam.projection.misc
import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.item.BlockItem import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.level.block.state.BlockState
import quaedam.Quaedam import quaedam.Quaedam
import quaedam.projection.ProjectionBlock import quaedam.projection.EntityProjectionBlock
import quaedam.projection.ProjectionEffect import quaedam.projection.ProjectionEffect
import quaedam.projection.ProjectionEffectType import quaedam.projection.ProjectionEffectType
import quaedam.projection.SimpleProjectionEntity
object NoiseProjection { object NoiseProjection {
@ -29,15 +27,15 @@ object NoiseProjection {
ProjectionEffectType { NoiseProjectionEffect() } ProjectionEffectType { NoiseProjectionEffect() }
}!! }!!
val blockEntity = Quaedam.blockEntities.register(ID) {
SimpleProjectionEntity.createBlockEntityType(block, ::NoiseProjectionEffect)
}!!
} }
object NoiseProjectionBlock : ProjectionBlock<NoiseProjectionEffect>(createProperties().lightLevel { 3 }) { object NoiseProjectionBlock : EntityProjectionBlock<NoiseProjectionEffect>(createProperties().lightLevel { 3 }) {
override fun createProjectionEffect( override val blockEntity = NoiseProjection.blockEntity
level: ServerLevel,
state: BlockState,
pos: BlockPos
) = NoiseProjectionEffect()
} }

View File

@ -1,15 +1,13 @@
package quaedam.projection.misc package quaedam.projection.misc
import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.item.BlockItem import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.level.block.state.BlockState
import quaedam.Quaedam import quaedam.Quaedam
import quaedam.projection.ProjectionBlock import quaedam.projection.EntityProjectionBlock
import quaedam.projection.ProjectionEffect import quaedam.projection.ProjectionEffect
import quaedam.projection.ProjectionEffectType import quaedam.projection.ProjectionEffectType
import quaedam.projection.SimpleProjectionEntity
object SkylightProjection { object SkylightProjection {
@ -29,15 +27,15 @@ object SkylightProjection {
ProjectionEffectType { SkylightProjectionEffect() } ProjectionEffectType { SkylightProjectionEffect() }
}!! }!!
val blockEntity = Quaedam.blockEntities.register(ID) {
SimpleProjectionEntity.createBlockEntityType(block, ::SkylightProjectionEffect)
}!!
} }
object SkylightProjectionBlock : ProjectionBlock<SkylightProjectionEffect>(createProperties().lightLevel { 3 }) { object SkylightProjectionBlock : EntityProjectionBlock<SkylightProjectionEffect>(createProperties().lightLevel { 3 }) {
override fun createProjectionEffect( override val blockEntity = SkylightProjection.blockEntity
level: ServerLevel,
state: BlockState,
pos: BlockPos
) = SkylightProjectionEffect()
} }

View File

@ -1,15 +1,13 @@
package quaedam.projection.misc package quaedam.projection.misc
import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.item.BlockItem import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.level.block.state.BlockState
import quaedam.Quaedam import quaedam.Quaedam
import quaedam.projection.ProjectionBlock import quaedam.projection.EntityProjectionBlock
import quaedam.projection.ProjectionEffect import quaedam.projection.ProjectionEffect
import quaedam.projection.ProjectionEffectType import quaedam.projection.ProjectionEffectType
import quaedam.projection.SimpleProjectionEntity
object SoundProjection { object SoundProjection {
@ -29,15 +27,15 @@ object SoundProjection {
ProjectionEffectType { SoundProjectionEffect } ProjectionEffectType { SoundProjectionEffect }
}!! }!!
val blockEntity = Quaedam.blockEntities.register(ID) {
SimpleProjectionEntity.createBlockEntityType(block) { SoundProjectionEffect }
}!!
} }
object SoundProjectionBlock : ProjectionBlock<SoundProjectionEffect>(createProperties().lightLevel { 3 }) { object SoundProjectionBlock : EntityProjectionBlock<SoundProjectionEffect>(createProperties().lightLevel { 3 }) {
override fun createProjectionEffect( override val blockEntity = SoundProjection.blockEntity
level: ServerLevel,
state: BlockState,
pos: BlockPos
) = SoundProjectionEffect
} }

View File

@ -4,6 +4,7 @@ import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import quaedam.Quaedam import quaedam.Quaedam
import quaedam.projection.ProjectionEffectType import quaedam.projection.ProjectionEffectType
import quaedam.projection.SimpleProjectionEntity
object SwarmProjection { object SwarmProjection {
@ -23,6 +24,10 @@ object SwarmProjection {
ProjectionEffectType { SwarmProjectionEffect() } ProjectionEffectType { SwarmProjectionEffect() }
}!! }!!
val blockEntity = Quaedam.blockEntities.register(ID) {
SimpleProjectionEntity.createBlockEntityType(block, ::SwarmProjectionEffect)
}!!
init { init {
ProjectedPersonEntity ProjectedPersonEntity
} }

View File

@ -1,16 +1,9 @@
package quaedam.projection.swarm package quaedam.projection.swarm
import net.minecraft.core.BlockPos import quaedam.projection.EntityProjectionBlock
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.block.state.BlockState
import quaedam.projection.ProjectionBlock
object SwarmProjectionBlock : ProjectionBlock<SwarmProjectionEffect>() { object SwarmProjectionBlock : EntityProjectionBlock<SwarmProjectionEffect>() {
override fun createProjectionEffect( override val blockEntity = SwarmProjection.blockEntity
level: ServerLevel,
state: BlockState,
pos: BlockPos
) = SwarmProjectionEffect()
} }

View File

@ -132,7 +132,7 @@ class ProjectorBlockEntity(pos: BlockPos, state: BlockState) :
val blockState = level.getBlockState(pos) val blockState = level.getBlockState(pos)
val block = blockState.block val block = blockState.block
if (block is ProjectionProvider<*>) { if (block is ProjectionProvider<*>) {
val projection = block.createProjectionEffect(level, blockState, pos) val projection = block.applyProjectionEffect(level, blockState, pos)
if (projection != null) { if (projection != null) {
effects[projection.type] = projection effects[projection.type] = projection
} }