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.ItemStack
import org.slf4j.LoggerFactory
import quaedam.projection.*
import quaedam.projection.ProjectionCommand
import quaedam.projection.ProjectionEffectType
import quaedam.projection.misc.NoiseProjection
import quaedam.projection.misc.SkylightProjection
import quaedam.projection.misc.SoundProjection

View File

@ -1,59 +1,32 @@
package quaedam.projection
import dev.architectury.registry.registries.DeferredSupplier
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.item.ItemStack
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.Level
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntityType
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),
ProjectionProvider<P> {
abstract class EntityProjectionBlock<P : ProjectionEffect>(properties: Properties = createProperties()) :
ProjectionBlock<P>(properties), EntityBlock {
companion object {
fun createProperties(): Properties = Properties.of()
.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()
fun createProperties(): Properties = ProjectionBlock.createProperties()
}
@Suppress("OVERRIDE_DEPRECATION")
override fun getDrops(blockState: BlockState, builder: LootParams.Builder) = listOf(ItemStack(asItem()))
abstract val blockEntity: DeferredSupplier<BlockEntityType<SimpleProjectionEntity<P>>>
override fun setPlacedBy(
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 newBlockEntity(pos: BlockPos, state: BlockState) = blockEntity.get().create(pos, state)
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() }
}
@Suppress("UNCHECKED_CAST")
fun getProjection(level: Level, pos: BlockPos) = (level.getBlockEntity(pos) as SimpleProjectionEntity<P>).projection
override fun applyProjectionEffect(level: ServerLevel, state: BlockState, pos: BlockPos) = getProjection(level, pos)
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
) {
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) {
findNearbyProjectors(level, pos)
.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> {
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
import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.Item
import net.minecraft.world.level.block.state.BlockState
import quaedam.Quaedam
import quaedam.projection.ProjectionBlock
import quaedam.projection.EntityProjectionBlock
import quaedam.projection.ProjectionEffect
import quaedam.projection.ProjectionEffectType
import quaedam.projection.SimpleProjectionEntity
object NoiseProjection {
@ -29,15 +27,15 @@ object NoiseProjection {
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(
level: ServerLevel,
state: BlockState,
pos: BlockPos
) = NoiseProjectionEffect()
override val blockEntity = NoiseProjection.blockEntity
}

View File

@ -1,15 +1,13 @@
package quaedam.projection.misc
import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.Item
import net.minecraft.world.level.block.state.BlockState
import quaedam.Quaedam
import quaedam.projection.ProjectionBlock
import quaedam.projection.EntityProjectionBlock
import quaedam.projection.ProjectionEffect
import quaedam.projection.ProjectionEffectType
import quaedam.projection.SimpleProjectionEntity
object SkylightProjection {
@ -29,15 +27,15 @@ object SkylightProjection {
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(
level: ServerLevel,
state: BlockState,
pos: BlockPos
) = SkylightProjectionEffect()
override val blockEntity = SkylightProjection.blockEntity
}

View File

@ -1,15 +1,13 @@
package quaedam.projection.misc
import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.Item
import net.minecraft.world.level.block.state.BlockState
import quaedam.Quaedam
import quaedam.projection.ProjectionBlock
import quaedam.projection.EntityProjectionBlock
import quaedam.projection.ProjectionEffect
import quaedam.projection.ProjectionEffectType
import quaedam.projection.SimpleProjectionEntity
object SoundProjection {
@ -29,15 +27,15 @@ object SoundProjection {
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(
level: ServerLevel,
state: BlockState,
pos: BlockPos
) = SoundProjectionEffect
override val blockEntity = SoundProjection.blockEntity
}

View File

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

View File

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

View File

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