feat: simple projection updater

This commit is contained in:
xtex 2023-07-20 17:42:50 +08:00
parent 7308a478b8
commit e7aa4f4c30
Signed by: xtex
GPG Key ID: B918086ED8045B91
11 changed files with 142 additions and 22 deletions

View File

@ -21,7 +21,10 @@ subprojects {
dependencies {
"minecraft"("com.mojang:minecraft:${project.property("minecraft_version")}")
"mappings"(loom.officialMojangMappings())
"mappings"(loom.layered {
officialMojangMappings()
parchment("org.parchmentmc.data:parchment-${project.property("minecraft_version")}:${project.property("parchment_version")}@zip")
})
}
}
@ -35,6 +38,13 @@ allprojects {
version = "1.0.0"
group = "quaedam"
repositories {
maven {
name = "ParchmentMC"
setUrl("https://maven.parchmentmc.org")
}
}
dependencies {
compileOnly("org.jetbrains.kotlin:kotlin-stdlib")
}

View File

@ -11,6 +11,7 @@ import net.minecraft.world.item.ItemStack
import org.slf4j.LoggerFactory
import quaedam.projection.ProjectionCommand
import quaedam.projection.ProjectionEffectType
import quaedam.projection.SimpleProjectionUpdate
import quaedam.projection.misc.NoiseProjection
import quaedam.projection.misc.SkylightProjection
import quaedam.projection.misc.SoundProjection
@ -48,6 +49,7 @@ object Quaedam {
SoundProjection
NoiseProjection
ProjectionCommand
SimpleProjectionUpdate
creativeModeTabs.register()
items.register()

View File

@ -1,12 +1,14 @@
package quaedam.projection
import dev.architectury.registry.registries.DeferredSupplier
import net.minecraft.client.Minecraft
import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import quaedam.utils.sendBlockUpdated
abstract class EntityProjectionBlock<P : ProjectionEffect>(properties: Properties = createProperties()) :
ProjectionBlock<P>(properties), EntityBlock {
@ -17,16 +19,25 @@ abstract class EntityProjectionBlock<P : ProjectionEffect>(properties: Propertie
abstract val blockEntity: DeferredSupplier<BlockEntityType<SimpleProjectionEntity<P>>>
override fun newBlockEntity(pos: BlockPos, state: BlockState) = blockEntity.get().create(pos, state)
override fun newBlockEntity(pos: BlockPos, state: BlockState) = blockEntity.get().create(pos, state)!!
@Suppress("UNCHECKED_CAST")
fun getProjection(level: Level, pos: BlockPos) = (level.getBlockEntity(pos) as SimpleProjectionEntity<P>).projection
fun getBlockEntity(level: Level, pos: BlockPos) = (level.getBlockEntity(pos) as SimpleProjectionEntity<P>)
override fun applyProjectionEffect(level: ServerLevel, state: BlockState, pos: BlockPos) = getProjection(level, pos)
override fun applyProjectionEffect(level: ServerLevel, state: BlockState, pos: BlockPos) =
getBlockEntity(level, pos).cloneProjection()
inline fun applyChange(level: Level, pos: BlockPos, func: P.() -> Unit) {
getProjection(level, pos).apply(func)
fun applyChange(level: Level, pos: BlockPos, func: P.() -> Unit) {
val entity = getBlockEntity(level, pos)
val projection = entity.projection
projection.apply(func)
if (level.isClientSide) {
check(level == Minecraft.getInstance().player!!.level())
SimpleProjectionUpdate.send(pos, projection.toNbt())
} else {
getBlockEntity(level, pos).sendBlockUpdated()
sendUpdateToProjectors(level, pos)
}
}
}

View File

@ -29,6 +29,13 @@ abstract class ProjectionBlock<P : ProjectionEffect>(properties: Properties = cr
}
.toSet()
fun sendUpdateToProjectors(level: Level, pos: BlockPos) {
if (!level.isClientSide) {
findNearbyProjectors(level, pos)
.forEach { (level.getBlockEntity(it) as ProjectorBlockEntity).checkUpdate() }
}
}
}
@Suppress("OVERRIDE_DEPRECATION")
@ -52,11 +59,4 @@ abstract class ProjectionBlock<P : ProjectionEffect>(properties: Properties = cr
}
}
fun sendUpdateToProjectors(level: Level, pos: BlockPos) {
if (!level.isClientSide) {
findNearbyProjectors(level, pos)
.forEach { (level.getBlockEntity(it) as ProjectorBlockEntity).checkUpdate() }
}
}
}

View File

@ -10,17 +10,17 @@ import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
abstract class ProjectionEffect {
abstract class ProjectionEffect : Cloneable {
abstract val type: ProjectionEffectType<*>
abstract fun toNbt(tag: CompoundTag)
abstract fun fromNbt(tag: CompoundTag, trusted: Boolean)
abstract fun fromNbt(tag: CompoundTag, trusted: Boolean = true)
fun toNbt() = CompoundTag().apply { toNbt(this) }
override fun equals(other: Any?) = other === this
override fun equals(other: Any?): Boolean = other === this
override fun hashCode() = type.hashCode()

View File

@ -14,19 +14,20 @@ class SimpleProjectionEntity<P : ProjectionEffect>(
type: BlockEntityType<SimpleProjectionEntity<P>>,
pos: BlockPos,
state: BlockState,
val projection: P
var projection: P,
val default: () -> P,
) : BlockEntity(type, pos, state) {
companion object {
const val TAG_PROJECTION_EFFECT = "ProjectionEffect"
fun <P : ProjectionEffect, B: ProjectionBlock<P>> createBlockEntityType(
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())
SimpleProjectionEntity(type.inner!!, pos, state, default(), default)
}, block.get()).build(null)
return type.inner!!
}
@ -41,11 +42,15 @@ class SimpleProjectionEntity<P : ProjectionEffect>(
override fun load(tag: CompoundTag) {
super.load(tag)
projection.fromNbt(tag.getCompound(TAG_PROJECTION_EFFECT), true)
if (TAG_PROJECTION_EFFECT in tag) {
projection.fromNbt(tag.getCompound(TAG_PROJECTION_EFFECT))
}
}
override fun getUpdateTag(): CompoundTag = saveWithoutMetadata()
override fun getUpdatePacket(): Packet<ClientGamePacketListener> = ClientboundBlockEntityDataPacket.create(this)
fun cloneProjection() = default().apply { fromNbt(projection.toNbt()) }
}

View File

@ -0,0 +1,63 @@
package quaedam.projection
import dev.architectury.networking.NetworkManager
import dev.architectury.networking.NetworkManager.PacketContext
import io.netty.buffer.Unpooled
import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import quaedam.Quaedam
import quaedam.utils.sendBlockUpdated
object SimpleProjectionUpdate {
val id = ResourceLocation("quaedam", "simple_projection_update")
init {
NetworkManager.registerReceiver(NetworkManager.Side.C2S, id, ::handle)
}
private fun handle(buf: FriendlyByteBuf, ctx: PacketContext) {
val player = ctx.player!! as ServerPlayer
val level = player.level()
val pos = buf.readBlockPos()
val data = buf.readNbt()!!
if (player.blockPosition().distSqr(pos) > 10 * 10) {
Quaedam.logger.info("Player ${player.name} tried to update a projection block far away")
if (player.blockPosition().distSqr(pos) > 50 * 50) {
player.connection.disconnect(Component.literal("[Quaedam] wth r u doing? why not waiting for server?"))
}
return
}
level.server!!.execute {
val entity = level.getBlockEntity(pos) ?: return@execute
val blockEntity = entity as SimpleProjectionEntity<*>
try {
blockEntity.projection.fromNbt(data, trusted = false)
} catch (e: Throwable) {
Quaedam.logger.error(
"Player ${player.name} tried to update projection " +
"at $pos but caused error: $data", e
)
player.connection.disconnect(Component.literal("[Quaedam] ? wait what did you send to the server?"))
return@execute
}
blockEntity.sendBlockUpdated()
ProjectionBlock.sendUpdateToProjectors(level, pos)
}
}
fun send(pos: BlockPos, data: CompoundTag) {
val buf = FriendlyByteBuf(Unpooled.buffer())
buf.writeBlockPos(pos)
buf.writeNbt(data)
NetworkManager.sendToServer(id, buf)
}
}

View File

@ -1,8 +1,15 @@
package quaedam.projection.misc
import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResult
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.Item
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.BlockHitResult
import quaedam.Quaedam
import quaedam.projection.EntityProjectionBlock
import quaedam.projection.ProjectionEffect
@ -38,6 +45,26 @@ object SkylightProjectionBlock : EntityProjectionBlock<SkylightProjectionEffect>
override val blockEntity = SkylightProjection.blockEntity
override fun use(
blockState: BlockState,
level: Level,
blockPos: BlockPos,
player: Player,
interactionHand: InteractionHand,
blockHitResult: BlockHitResult
): InteractionResult {
if (level.isClientSide) {
println("update")
applyChange(level, blockPos) {
factor -= 0.5
if (factor < 0.5) factor = 2.0
println("new factor: $factor")
}
return InteractionResult.CONSUME
}
return super.use(blockState, level, blockPos, player, interactionHand, blockHitResult)
}
}
data class SkylightProjectionEffect(var factor: Double = 2.0) : ProjectionEffect() {

View File

@ -26,7 +26,7 @@ data class SwarmProjectionEffect(
override fun fromNbt(tag: CompoundTag, trusted: Boolean) {
maxCount = tag.getInt(TAG_MAX_COUNT)
if (!trusted){
if (!trusted) {
maxCount = min(maxCount, 250)
}
}

View File

@ -39,6 +39,7 @@ object ProjectorBlock : Block(Properties.of()
blockHitResult: BlockHitResult
): InteractionResult {
checkUpdate(level, blockPos)
println(level.getBlockEntity(blockPos)!!.saveWithoutMetadata())
return InteractionResult.SUCCESS
}

View File

@ -2,6 +2,7 @@ org.gradle.parallel=true
org.gradle.caching=true
org.gradle.jvmargs=-Xmx2048M
minecraft_version=1.20.1
parchment_version=2023.07.16
# https://www.curseforge.com/minecraft/mc-mods/architectury-api
architectury_version=9.1.10
# https://files.minecraftforge.net/net/minecraftforge/forge/