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 { dependencies {
"minecraft"("com.mojang:minecraft:${project.property("minecraft_version")}") "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" version = "1.0.0"
group = "quaedam" group = "quaedam"
repositories {
maven {
name = "ParchmentMC"
setUrl("https://maven.parchmentmc.org")
}
}
dependencies { dependencies {
compileOnly("org.jetbrains.kotlin:kotlin-stdlib") compileOnly("org.jetbrains.kotlin:kotlin-stdlib")
} }

View File

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

View File

@ -1,12 +1,14 @@
package quaedam.projection package quaedam.projection
import dev.architectury.registry.registries.DeferredSupplier import dev.architectury.registry.registries.DeferredSupplier
import net.minecraft.client.Minecraft
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.EntityBlock import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntityType 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 quaedam.utils.sendBlockUpdated
abstract class EntityProjectionBlock<P : ProjectionEffect>(properties: Properties = createProperties()) : abstract class EntityProjectionBlock<P : ProjectionEffect>(properties: Properties = createProperties()) :
ProjectionBlock<P>(properties), EntityBlock { ProjectionBlock<P>(properties), EntityBlock {
@ -17,16 +19,25 @@ abstract class EntityProjectionBlock<P : ProjectionEffect>(properties: Propertie
abstract val blockEntity: DeferredSupplier<BlockEntityType<SimpleProjectionEntity<P>>> 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") @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) { fun applyChange(level: Level, pos: BlockPos, func: P.() -> Unit) {
getProjection(level, pos).apply(func) val entity = getBlockEntity(level, pos)
sendUpdateToProjectors(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() .toSet()
fun sendUpdateToProjectors(level: Level, pos: BlockPos) {
if (!level.isClientSide) {
findNearbyProjectors(level, pos)
.forEach { (level.getBlockEntity(it) as ProjectorBlockEntity).checkUpdate() }
}
}
} }
@Suppress("OVERRIDE_DEPRECATION") @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.Level
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
abstract class ProjectionEffect { abstract class ProjectionEffect : Cloneable {
abstract val type: ProjectionEffectType<*> abstract val type: ProjectionEffectType<*>
abstract fun toNbt(tag: CompoundTag) 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) } 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() override fun hashCode() = type.hashCode()

View File

@ -14,19 +14,20 @@ class SimpleProjectionEntity<P : ProjectionEffect>(
type: BlockEntityType<SimpleProjectionEntity<P>>, type: BlockEntityType<SimpleProjectionEntity<P>>,
pos: BlockPos, pos: BlockPos,
state: BlockState, state: BlockState,
val projection: P var projection: P,
val default: () -> P,
) : BlockEntity(type, pos, state) { ) : BlockEntity(type, pos, state) {
companion object { companion object {
const val TAG_PROJECTION_EFFECT = "ProjectionEffect" const val TAG_PROJECTION_EFFECT = "ProjectionEffect"
fun <P : ProjectionEffect, B: ProjectionBlock<P>> createBlockEntityType( fun <P : ProjectionEffect, B : ProjectionBlock<P>> createBlockEntityType(
block: RegistrySupplier<B>, block: RegistrySupplier<B>,
default: () -> P, default: () -> P,
): BlockEntityType<SimpleProjectionEntity<P>> { ): BlockEntityType<SimpleProjectionEntity<P>> {
val type = ValueContainer<BlockEntityType<SimpleProjectionEntity<P>>>() val type = ValueContainer<BlockEntityType<SimpleProjectionEntity<P>>>()
type.inner = BlockEntityType.Builder.of({ pos, state -> type.inner = BlockEntityType.Builder.of({ pos, state ->
SimpleProjectionEntity(type.inner!!, pos, state, default()) SimpleProjectionEntity(type.inner!!, pos, state, default(), default)
}, block.get()).build(null) }, block.get()).build(null)
return type.inner!! return type.inner!!
} }
@ -41,11 +42,15 @@ class SimpleProjectionEntity<P : ProjectionEffect>(
override fun load(tag: CompoundTag) { override fun load(tag: CompoundTag) {
super.load(tag) 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 getUpdateTag(): CompoundTag = saveWithoutMetadata()
override fun getUpdatePacket(): Packet<ClientGamePacketListener> = ClientboundBlockEntityDataPacket.create(this) 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 package quaedam.projection.misc
import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag 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.BlockItem
import net.minecraft.world.item.Item 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.Quaedam
import quaedam.projection.EntityProjectionBlock import quaedam.projection.EntityProjectionBlock
import quaedam.projection.ProjectionEffect import quaedam.projection.ProjectionEffect
@ -38,6 +45,26 @@ object SkylightProjectionBlock : EntityProjectionBlock<SkylightProjectionEffect>
override val blockEntity = SkylightProjection.blockEntity 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() { 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) { override fun fromNbt(tag: CompoundTag, trusted: Boolean) {
maxCount = tag.getInt(TAG_MAX_COUNT) maxCount = tag.getInt(TAG_MAX_COUNT)
if (!trusted){ if (!trusted) {
maxCount = min(maxCount, 250) maxCount = min(maxCount, 250)
} }
} }

View File

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

View File

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