Compare commits

..

35 Commits

Author SHA1 Message Date
b40a33f69a feat(swarm): walk farther 2023-08-23 21:35:56 +08:00
22b1450a72 feat: adjust swarm time table 2023-08-23 14:28:06 +08:00
abb5646959 fix: game crash when no container available 2023-08-21 09:10:13 +08:00
1ee1c7215d fix: container focus again 2023-08-18 09:34:07 +08:00
d45f8d2a57 fix: signed 32-bits integer overflowed
Use in the wild: Mojang
2023-08-18 09:28:00 +08:00
cd40ba58da fix: WorkPoiAI not initialized early 2023-08-16 10:22:17 +08:00
d110d688c6 fix: only stroll in near positions 2023-08-11 16:00:14 +08:00
6cc16233fa fix: work poi missing 2023-08-11 15:55:17 +08:00
00ce17cb21 fix: disable despawn for swarm 2023-08-11 15:44:22 +08:00
3a4ad875e2 fix: missing bed memory for swarm 2023-08-11 15:33:25 +08:00
e25f23f40b chore: trigger longjing build 2023-08-11 09:51:19 +08:00
f794f9848b fix: remove debug log 2023-08-10 22:22:40 +08:00
f2b60ca6b0 fix(i18n): json syntax 2023-08-10 22:11:25 +08:00
a68b68a0e3 fix: remove duplicated key 2023-08-10 22:09:21 +08:00
33604db8a0 feat(i18n): add translations 2023-08-10 22:07:56 +08:00
a31321e662 feat: volume scaler 2023-08-10 22:03:32 +08:00
db74d07155 fix: mitigation for container tracker 2023-08-10 11:48:16 +08:00
d578db6fb2 fix: crash 2023-08-10 11:45:21 +08:00
296fe1efc2 fix: crash when trying to interact with destoryed container 2023-08-10 11:41:33 +08:00
2c95dfa660 fix: fix unable to bootstrap registry warning 2023-08-01 17:53:34 +08:00
fa1aefe425 feat: remove 3.0 base factor for music 2023-08-01 17:51:53 +08:00
dca1482526 feat: add quilt support
It is not working at all
2023-08-01 16:56:38 +08:00
9aa248e7f2 build: add fabric support 2023-08-01 15:45:21 +08:00
2b62599485 feat: use sided success for SmartInstrument 2023-08-01 14:57:31 +08:00
f588d3bc72 feat: right-click to cycle projection effect radius 2023-08-01 14:55:35 +08:00
c6edaac2e1 feat: custom projection radius 2023-08-01 14:44:11 +08:00
e18b4d78fb style: format code 2023-07-30 21:19:41 +08:00
68c90c8f8a fix: empty containers are always skipped 2023-07-30 21:15:03 +08:00
f3be1aae48 fix: incorrect usage of canTakeItem 2023-07-30 21:05:38 +08:00
40ed66d76e feat: more configurations 2023-07-30 20:52:46 +08:00
07455f2091 feat: dynamic config push 2023-07-30 20:39:46 +08:00
3ac5f3c9ec feat: add advancements 2023-07-30 20:17:33 +08:00
bf3d1ba574 feat(i18n): add zh_meme support 2023-07-30 17:18:37 +08:00
9aa47128c7 feat: idle activities 2023-07-30 16:09:16 +08:00
0fceb397d1 feat: add more sounds 2023-07-30 15:29:01 +08:00
48 changed files with 1044 additions and 116 deletions

2
.gitignore vendored
View File

@@ -1,4 +1,4 @@
build
.gradle
forge/run
*/run
.idea

View File

@@ -3,6 +3,7 @@ import net.fabricmc.loom.api.LoomGradleExtensionAPI
plugins {
java
kotlin("jvm") version "1.9.0"
kotlin("plugin.serialization") version "1.9.0"
id("architectury-plugin") version "3.4-SNAPSHOT"
id("dev.architectury.loom") version "1.3-SNAPSHOT" apply false
id("com.github.johnrengelman.shadow") version "8.1.1" apply false
@@ -31,6 +32,7 @@ subprojects {
allprojects {
apply(plugin = "java")
apply(plugin = "kotlin")
apply(plugin = "kotlinx-serialization")
apply(plugin = "architectury-plugin")
apply(plugin = "maven-publish")
@@ -43,10 +45,15 @@ allprojects {
name = "ParchmentMC"
setUrl("https://maven.parchmentmc.org")
}
maven {
name = "QuiltMC"
setUrl("https://maven.quiltmc.org/repository/release/")
}
}
dependencies {
compileOnly("org.jetbrains.kotlin:kotlin-stdlib")
compileOnly("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
}
tasks.withType<JavaCompile> {

View File

@@ -1,5 +1,5 @@
architectury {
common("forge")
common("forge", "fabric", "quilt")
}
loom {

View File

@@ -20,6 +20,7 @@ import quaedam.projection.misc.NoiseProjection
import quaedam.projection.misc.SkylightProjection
import quaedam.projection.misc.SoundProjection
import quaedam.projection.music.MusicProjection
import quaedam.projection.swarm.ProjectedPersonEntity
import quaedam.projection.swarm.SwarmProjection
import quaedam.projector.Projector
import quaedam.shell.ProjectionShell
@@ -39,6 +40,7 @@ object Quaedam {
val memoryTypes = DeferredRegister.create(ID, Registries.MEMORY_MODULE_TYPE)!!
val sensors = DeferredRegister.create(ID, Registries.SENSOR_TYPE)!!
val soundEvents = DeferredRegister.create(ID, Registries.SOUND_EVENT)!!
val poiTypes = DeferredRegister.create(ID, Registries.POINT_OF_INTEREST_TYPE)!!
val projectionEffects by lazy { DeferredRegister.create(ID, ProjectionEffectType.registryKey)!! }
val creativeModeTab: RegistrySupplier<CreativeModeTab> = creativeModeTabs.register("quaedam") {
@@ -47,6 +49,8 @@ object Quaedam {
}
}
val lateinit = mutableListOf<() -> Unit>()
fun init() {
QuaedamConfig
Projector
@@ -72,7 +76,11 @@ object Quaedam {
memoryTypes.register()
sensors.register()
soundEvents.register()
poiTypes.register()
projectionEffects.register()
lateinit.forEach { it() }
lateinit.clear()
}
fun resource(path: String) = ResourceLocation(ID, path)

View File

@@ -1,12 +1,13 @@
package quaedam.config
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import dev.architectury.event.events.client.ClientPlayerEvent
import dev.architectury.platform.Platform
import dev.architectury.utils.GameInstance
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import net.fabricmc.api.EnvType
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.*
import quaedam.Quaedam
import java.nio.file.Path
import kotlin.io.path.exists
@@ -14,12 +15,27 @@ import kotlin.io.path.notExists
import kotlin.io.path.readText
import kotlin.io.path.writeText
@Serializable
data class QuaedamConfig(
val projectorEffectRadius: Int = 4
val valuesInt: Map<String, Int> = mapOf(),
val valuesFloat: Map<String, Float> = mapOf(),
val valuesDouble: Map<String, Double> = mapOf(),
val valuesBoolean: Map<String, Boolean> = mapOf(),
) {
companion object {
const val TAG_PROJECTOR_EFFECT_RADIUS = "ProjectorEffectRadius"
private val localJson = Json {
isLenient = true
prettyPrint = true
encodeDefaults = true
ignoreUnknownKeys = true
}
private val pushJson = Json {
encodeDefaults = true
ignoreUnknownKeys = true
}
private val localFile: Path = Platform.getConfigFolder().resolve("quaedam.json")
private var local0 = loadLocalConfig()
@@ -29,7 +45,7 @@ data class QuaedamConfig(
local0 = value
writeLocalConfig()
}
var remote: QuaedamConfig? = null
private var remote: QuaedamConfig? = null
val current get() = remote ?: local0
init {
@@ -48,13 +64,13 @@ data class QuaedamConfig(
}
private fun loadLocalConfig(): QuaedamConfig = if (localFile.exists()) {
Gson().fromJson(localFile.readText(), QuaedamConfig::class.java)
localJson.decodeFromString(localFile.readText())
} else {
QuaedamConfig()
}
private fun writeLocalConfig() {
localFile.writeText(GsonBuilder().serializeNulls().setPrettyPrinting().create().toJson(local0))
localFile.writeText(localJson.encodeToString(local0))
}
fun applyRemoteConfig(config: QuaedamConfig?) {
@@ -62,15 +78,28 @@ data class QuaedamConfig(
remote = config
}
fun fromPushNbt(tag: CompoundTag) = QuaedamConfig(
projectorEffectRadius = tag.getInt(TAG_PROJECTOR_EFFECT_RADIUS)
)
const val TAG_VALUES_INT = "ValuesInt"
const val TAG_VALUES_FLOAT = "ValuesFloat"
const val TAG_VALUES_DOUBLE = "ValuesDouble"
const val TAG_VALUES_BOOLEAN = "ValuesBoolean"
fun fromPushNbt(tag: CompoundTag): QuaedamConfig {
return QuaedamConfig(
valuesInt = pushJson.decodeFromString(tag.getString(TAG_VALUES_INT)),
valuesFloat = pushJson.decodeFromString(tag.getString(TAG_VALUES_FLOAT)),
valuesDouble = pushJson.decodeFromString(tag.getString(TAG_VALUES_DOUBLE)),
valuesBoolean = pushJson.decodeFromString(tag.getString(TAG_VALUES_BOOLEAN)),
)
}
}
fun toPushNbt(tag: CompoundTag) {
tag.putInt(TAG_PROJECTOR_EFFECT_RADIUS, projectorEffectRadius)
tag.putString(TAG_VALUES_INT, pushJson.encodeToString(valuesInt))
tag.putString(TAG_VALUES_FLOAT, pushJson.encodeToString(valuesFloat))
tag.putString(TAG_VALUES_DOUBLE, pushJson.encodeToString(valuesDouble))
tag.putString(TAG_VALUES_BOOLEAN, pushJson.encodeToString(valuesBoolean))
}
fun toPushNbt(forPush: Boolean) = CompoundTag().also { toPushNbt(it) }
fun toPushNbt() = CompoundTag().also { toPushNbt(it) }
}

View File

@@ -27,7 +27,7 @@ object SimpleQuaedamConfigPush {
fun sendCurrent(player: ServerPlayer) = send(player, QuaedamConfig.current)
fun send(player: ServerPlayer, config: QuaedamConfig) = send(player, config.toPushNbt(forPush = true))
fun send(player: ServerPlayer, config: QuaedamConfig) = send(player, config.toPushNbt())
private fun send(player: ServerPlayer, data: CompoundTag) {
val buf = FriendlyByteBuf(Unpooled.buffer())

View File

@@ -39,7 +39,7 @@ data class ProjectionEffectType<T : ProjectionEffect>(val constructor: () -> T)
val registryKey: ResourceKey<Registry<ProjectionEffectType<*>>> =
ResourceKey.createRegistryKey(Quaedam.resource("projection_effect"))
val registry: Registry<ProjectionEffectType<*>> = BuiltInRegistries.registerSimple(registryKey) { null }
val registry: Registry<ProjectionEffectType<*>> = BuiltInRegistries.registerSimple(registryKey) { nopEffect }
val nopEffect: ProjectionEffectType<NopEffect> =
Registry.register(registry, Quaedam.resource("nop"), ProjectionEffectType { NopEffect })

View File

@@ -13,6 +13,7 @@ import net.minecraft.util.RandomSource
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.Item
import quaedam.Quaedam
import quaedam.config.QuaedamConfig
import quaedam.projection.EntityProjectionBlock
import quaedam.projection.ProjectionEffect
import quaedam.projection.ProjectionEffectType
@@ -58,10 +59,11 @@ object NoiseProjection {
if (projections.isNotEmpty()) {
val rate = projections.maxOf { it.rate }
val amount = min(projections.sumOf { it.amount }, 12)
val volume = projections.fold(1.0f) { v, p -> v * p.volume }
if (amount != 0 && random.nextInt(1000 / rate) == 1) {
for (i in 0 until random.nextInt(amount)) {
// play random noise
playRandomNoise(random, game)
playRandomNoise(random, game, volume)
}
}
}
@@ -69,7 +71,7 @@ object NoiseProjection {
}
}
private fun playRandomNoise(random: RandomSource, game: Minecraft) {
private fun playRandomNoise(random: RandomSource, game: Minecraft, volume: Float) {
val volumeFactor = random.nextInt(100)
val sound = SimpleSoundInstance(
soundEvent.get().location,
@@ -79,7 +81,7 @@ object NoiseProjection {
in 10..15 -> random.nextFloat() * 0.5f + 0.5f
in 21..50 -> random.nextFloat() * 0.3f
else -> random.nextFloat() * 0.2f
},
} * volume,
random.nextFloat() + 0.4f,
RandomSource.create(random.nextLong()),
false,
@@ -101,12 +103,17 @@ object NoiseProjectionBlock : EntityProjectionBlock<NoiseProjectionEffect>(creat
}
data class NoiseProjectionEffect(var rate: Int = 250, var amount: Int = 3) : ProjectionEffect(),
data class NoiseProjectionEffect(var rate: Int = 250, var amount: Int = 3, var volume: Float = 1.0f) :
ProjectionEffect(),
ProjectionEffectShell.Provider {
companion object {
const val TAG_RATE = "Rate"
const val TAG_AMOUNT = "Amount"
const val TAG_VOLUME = "Volume"
val maxAmount get() = QuaedamConfig.current.valuesInt["projection.noise.max_amount"] ?: 8
val maxRate get() = QuaedamConfig.current.valuesInt["projection.noise.max_rate"] ?: 300
}
override val type
@@ -115,20 +122,23 @@ data class NoiseProjectionEffect(var rate: Int = 250, var amount: Int = 3) : Pro
override fun toNbt(tag: CompoundTag) {
tag.putInt(TAG_RATE, rate)
tag.putInt(TAG_AMOUNT, amount)
tag.putFloat(TAG_VOLUME, volume)
}
override fun fromNbt(tag: CompoundTag, trusted: Boolean) {
rate = tag.getInt(TAG_RATE)
amount = tag.getInt(TAG_AMOUNT)
volume = tag.getFloat(TAG_VOLUME)
if (!trusted) {
amount = min(amount, 8)
rate = min(rate, 500)
amount = min(amount, maxAmount)
rate = min(rate, maxRate)
}
}
override fun createShell() = buildProjectionEffectShell(this) {
intSlider("quaedam.shell.noise.rate", ::rate, 0..300 step 5)
intSlider("quaedam.shell.noise.amount", ::amount, 0..8)
intSlider("quaedam.shell.noise.rate", ::rate, 0..maxRate step 5)
intSlider("quaedam.shell.noise.amount", ::amount, 0..maxAmount)
floatSlider("quaedam.shell.noise.volume", ::volume, 0.0f..1.0f, 0.1f)
}
}

View File

@@ -4,6 +4,7 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.Item
import quaedam.Quaedam
import quaedam.config.QuaedamConfig
import quaedam.projection.EntityProjectionBlock
import quaedam.projection.ProjectionEffect
import quaedam.projection.ProjectionEffectType
@@ -46,6 +47,8 @@ data class SkylightProjectionEffect(var factor: Double = 2.0) : ProjectionEffect
companion object {
const val TAG_FACTOR = "Factor"
val maxFactor get() = QuaedamConfig.current.valuesDouble["projection.skylight.max_factor"] ?: 5.0
}
override val type
@@ -58,12 +61,12 @@ data class SkylightProjectionEffect(var factor: Double = 2.0) : ProjectionEffect
override fun fromNbt(tag: CompoundTag, trusted: Boolean) {
factor = tag.getDouble(TAG_FACTOR)
if (!trusted) {
factor = min(factor, 5.0)
factor = min(factor, maxFactor)
}
}
override fun createShell() = buildProjectionEffectShell(this) {
doubleSlider("quaedam.shell.skylight.factor", ::factor, 0.0..5.0, 0.1)
doubleSlider("quaedam.shell.skylight.factor", ::factor, 0.0..maxFactor, 0.1)
}
}

View File

@@ -4,6 +4,7 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.Item
import quaedam.Quaedam
import quaedam.config.QuaedamConfig
import quaedam.projection.EntityProjectionBlock
import quaedam.projection.ProjectionEffect
import quaedam.projection.ProjectionEffectType
@@ -42,10 +43,14 @@ object SoundProjectionBlock : EntityProjectionBlock<SoundProjectionEffect>(creat
}
data class SoundProjectionEffect(var rate: Int = 60) : ProjectionEffect(), ProjectionEffectShell.Provider {
data class SoundProjectionEffect(var rate: Int = 60, var volume: Float = 1.0f) : ProjectionEffect(),
ProjectionEffectShell.Provider {
companion object {
const val TAG_RATE = "Rate"
const val TAG_VOLUME = "Volume"
val maxRate get() = QuaedamConfig.current.valuesInt["projection.sound.max_rate"] ?: 210
}
override val type
@@ -53,17 +58,20 @@ data class SoundProjectionEffect(var rate: Int = 60) : ProjectionEffect(), Proje
override fun toNbt(tag: CompoundTag) {
tag.putInt(TAG_RATE, rate)
tag.putFloat(TAG_VOLUME, volume)
}
override fun fromNbt(tag: CompoundTag, trusted: Boolean) {
rate = tag.getInt(TAG_RATE)
volume = tag.getFloat(TAG_VOLUME)
if (!trusted) {
rate = min(rate, 210)
rate = min(rate, maxRate)
}
}
override fun createShell() = buildProjectionEffectShell(this) {
intSlider("quaedam.shell.sound.rate", ::rate, 0..210)
intSlider("quaedam.shell.sound.rate", ::rate, 0..maxRate)
floatSlider("quaedam.shell.sound.volume", ::volume, 0.0f..1.0f, 0.1f)
}
}

View File

@@ -71,7 +71,7 @@ class MusicPlayer(
// play note
val projections = Projector.findNearbyProjections(level, pos, MusicProjection.effect.get())
.takeIf { it.isNotEmpty() } ?: listOf(MusicProjectionEffect())
val volume = 3.0f * projections.maxOf { it.volumeFactor } * note.volume
val volume = projections.maxOf { it.volumeFactor } * note.volume
val particle = projections.any { it.particle }
val instrument = level.getBlockState(pos).getValue(BlockStateProperties.NOTEBLOCK_INSTRUMENT)
val pitch = if (instrument.isTunable) {

View File

@@ -4,6 +4,7 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.Item
import quaedam.Quaedam
import quaedam.config.QuaedamConfig
import quaedam.projection.EntityProjectionBlock
import quaedam.projection.ProjectionEffect
import quaedam.projection.ProjectionEffectType
@@ -52,6 +53,9 @@ data class MusicProjectionEffect(var volumeFactor: Float = 1.0f, var particle: B
companion object {
const val TAG_VOLUME_FACTOR = "VolumeFactor"
const val TAG_PARTICLE = "Particle"
val maxVolumeFactor get() = QuaedamConfig.current.valuesFloat["projection.music.max_volume_factor"] ?: 5.0f
val enforceParticle get() = QuaedamConfig.current.valuesBoolean["projection.music.enforce_particle"]
}
override val type
@@ -66,13 +70,16 @@ data class MusicProjectionEffect(var volumeFactor: Float = 1.0f, var particle: B
volumeFactor = tag.getFloat(TAG_VOLUME_FACTOR)
particle = tag.getBoolean(TAG_PARTICLE)
if (!trusted) {
volumeFactor = min(volumeFactor, 5.0f)
volumeFactor = min(volumeFactor, maxVolumeFactor)
particle = enforceParticle ?: particle
}
}
override fun createShell() = buildProjectionEffectShell(this) {
floatSlider("quaedam.shell.music.volume_factor", ::volumeFactor, 0.0f..5.0f, 0.1f)
boolean("quaedam.shell.music.particle", ::particle)
floatSlider("quaedam.shell.music.volume_factor", ::volumeFactor, 0.0f..maxVolumeFactor, 0.1f)
if (enforceParticle == null) {
boolean("quaedam.shell.music.particle", ::particle)
}
}
}

View File

@@ -126,10 +126,10 @@ object SmartInstrumentBlock : Block(
|| CausalityAnchor.checkEffect(level, pos)
) {
val entity = level.getBlockEntity(pos) as SmartInstrumentBlockEntity
if (entity.player == null) {
if (entity.player == null && !level.isClientSide) {
entity.startMusic()
}
return InteractionResult.SUCCESS
return InteractionResult.sidedSuccess(level.isClientSide)
}
return super.use(state, level, pos, player, hand, hit)
}

View File

@@ -60,7 +60,7 @@ class ProjectedPersonEntity(entityType: EntityType<out PathfinderMob>, level: Le
}!!
init {
EntityAttributeRegistry.register(entity, ::createAttributes)
Quaedam.lateinit += { EntityAttributeRegistry.register(entity, ::createAttributes) }
if (Platform.getEnv() == EnvType.CLIENT) ProjectedPersonRenderer
ProjectedPersonShape
ProjectedPersonAI
@@ -177,7 +177,8 @@ class ProjectedPersonEntity(entityType: EntityType<out PathfinderMob>, level: Le
Projector.findNearbyProjections(level(), blockPosition(), SwarmProjection.effect.get()).isNotEmpty()
override fun checkDespawn() {
super.checkDespawn()
// no despawn
// super.checkDespawn()
if (!checkProjectionEffect() && !CausalityAnchor.checkEffect(level(), blockPosition())) {
dropEquipment()
remove(RemovalReason.KILLED)
@@ -237,24 +238,27 @@ class ProjectedPersonEntity(entityType: EntityType<out PathfinderMob>, level: Le
}
fun findNearbySoundProjection() =
Projector.findNearbyProjections(level(), blockPosition(), SoundProjection.effect.get()).firstOrNull()
Projector.findNearbyProjections(level(), blockPosition(), SoundProjection.effect.get())
override fun isSilent() =
super.isSilent() && findNearbySoundProjection() != null
super.isSilent() && findNearbySoundProjection().isEmpty()
override fun getAmbientSound(): SoundEvent? {
if (findNearbySoundProjection() != null) {
if (findNearbySoundProjection().isNotEmpty()) {
// sound projection available
return soundNoise.get()
}
return null
}
override fun getSoundVolume() = super.getSoundVolume() * (random.nextFloat() * 1.1f + 0.4f)
override fun getSoundVolume() =
super.getSoundVolume() * (random.nextFloat() * 1.1f + 0.4f) *
findNearbySoundProjection().fold(1.0f) { v, p -> v * p.volume }
override fun getVoicePitch() = super.getVoicePitch() * (random.nextFloat() * 0.55f + 0.7f)
override fun getAmbientSoundInterval() = 80 - random.nextInt((findNearbySoundProjection()?.rate ?: 1) * 5)
override fun getAmbientSoundInterval() =
80 - random.nextInt((findNearbySoundProjection().firstOrNull()?.rate ?: 1) * 5)
override fun isEffectiveAi() = super.isEffectiveAi() && checkProjectionEffect()

View File

@@ -10,6 +10,7 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider
import net.minecraft.client.renderer.entity.MobRenderer
import net.minecraft.client.renderer.entity.layers.CustomHeadLayer
import net.minecraft.client.renderer.entity.layers.ItemInHandLayer
import quaedam.Quaedam
@Environment(EnvType.CLIENT)
class ProjectedPersonRenderer(context: EntityRendererProvider.Context) :
@@ -21,7 +22,12 @@ class ProjectedPersonRenderer(context: EntityRendererProvider.Context) :
companion object {
init {
EntityRendererRegistry.register(ProjectedPersonEntity.entity, ::ProjectedPersonRenderer)
Quaedam.lateinit += {
EntityRendererRegistry.register(
ProjectedPersonEntity.entity,
::ProjectedPersonRenderer
)
}
}
}

View File

@@ -5,6 +5,7 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.MobSpawnType
import net.minecraft.world.level.levelgen.Heightmap
import quaedam.config.QuaedamConfig
import quaedam.projection.ProjectionEffect
import quaedam.projector.Projector
import quaedam.projector.ProjectorBlockEntity
@@ -18,6 +19,8 @@ data class SwarmProjectionEffect(
companion object {
const val TAG_MAX_COUNT = "MaxCount"
val maxMaxCount get() = QuaedamConfig.current.valuesInt["projection.swarm.max_max_count"] ?: 250
}
override val type
@@ -30,7 +33,7 @@ data class SwarmProjectionEffect(
override fun fromNbt(tag: CompoundTag, trusted: Boolean) {
maxCount = tag.getInt(TAG_MAX_COUNT)
if (!trusted) {
maxCount = min(maxCount, 250)
maxCount = min(maxCount, maxMaxCount)
}
}
@@ -60,7 +63,7 @@ data class SwarmProjectionEffect(
}
override fun createShell() = buildProjectionEffectShell(this) {
intSlider("quaedam.shell.swarm.max_count", ::maxCount, 0..250 step 5)
intSlider("quaedam.shell.swarm.max_count", ::maxCount, 0..maxMaxCount step 5)
}
}

View File

@@ -0,0 +1,58 @@
package quaedam.projection.swarm.ai
import net.minecraft.core.GlobalPos
import net.minecraft.world.entity.ai.behavior.AcquirePoi
import net.minecraft.world.entity.ai.behavior.StrollAroundPoi
import net.minecraft.world.entity.ai.behavior.StrollToPoi
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.village.poi.PoiType
import net.minecraft.world.entity.ai.village.poi.PoiTypes
import net.minecraft.world.level.block.Blocks
import quaedam.Quaedam
import quaedam.projection.music.SmartInstrumentBlock
import java.util.*
object AmusementAI {
const val ID = "amusement"
val poiType = Quaedam.poiTypes.register(ID) {
PoiType(
setOf(
Blocks.NOTE_BLOCK,
SmartInstrumentBlock,
Blocks.HONEY_BLOCK,
Blocks.TARGET,
).flatMap { it.stateDefinition.possibleStates }.toSet(),
16, 10
)
}!!
val poiTypes by lazy {
setOf(
poiType.key,
PoiTypes.LIBRARIAN,
PoiTypes.MEETING,
)
}
val memory = Quaedam.memoryTypes.register(ID) {
MemoryModuleType(Optional.of(GlobalPos.CODEC))
}!!
fun createAcquirePoi() =
AcquirePoi.create({ it.`is` { key -> key in poiTypes } }, memory.get(), false, Optional.empty())
fun createStrollToPoi() =
StrollToPoi.create(memory.get(), 0.4f, 7, 15)
fun createStrollToPoiBaby() =
StrollToPoi.create(memory.get(), 0.7f, 5, 10)
fun createStrollAroundPoi() =
StrollAroundPoi.create(memory.get(), 0.4f, 10)
fun createStrollAroundPoiBaby() =
StrollAroundPoi.create(memory.get(), 0.55f, 8)
}

View File

@@ -32,33 +32,37 @@ class ExchangeItem<E> : Behavior<E>(
entity.brain.eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE)
}
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 canStillUse(level: ServerLevel, owner: E, gameTime: Long) =
owner.brain.getMemory(MemoryModuleType.WALK_TARGET).isPresent
|| owner.brain.getMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE).isEmpty
|| (closeAt != null && closeAt!! < gameTime)
override fun tick(level: ServerLevel, entity: E, l: Long) {
override fun tick(level: ServerLevel, owner: E, gameTime: Long) {
if (closeAt == null) {
if (entity.brain.getMemory(MemoryModuleType.WALK_TARGET).isEmpty) {
if (owner.brain.getMemory(MemoryModuleType.WALK_TARGET).isEmpty) {
// reached
val chest = level.getBlockEntity(target!!) as BaseContainerBlockEntity
val chest = level.getBlockEntity(target!!) ?: return
if (chest !is BaseContainerBlockEntity)
return
if (chest is ChestBlockEntity) {
ChestBlockEntity.playSound(level, target!!, level.getBlockState(target!!), SoundEvents.CHEST_OPEN)
}
if (chest.isEmpty) {
closeAt = l + 7
if (chest.isEmpty && level.random.nextBoolean()) {
closeAt = gameTime + 7
} else {
closeAt = l + 10 + level.random.nextInt(100)
exchangeItems(level, entity)
closeAt = gameTime + 10 + level.random.nextInt(100)
exchangeItems(level, owner)
}
}
}
}
override fun stop(level: ServerLevel, entity: E, l: Long) {
entity.brain.eraseMemory(MemoryModuleType.WALK_TARGET)
entity.brain.eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE)
override fun stop(level: ServerLevel, owner: E, gameTime: Long) {
owner.brain.eraseMemory(MemoryModuleType.WALK_TARGET)
owner.brain.eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE)
if (closeAt != null) {
// opened
val chest = level.getBlockEntity(target!!)!!
val chest = level.getBlockEntity(target!!) ?: return
if (chest is ChestBlockEntity) {
ChestBlockEntity.playSound(level, target!!, level.getBlockState(target!!), SoundEvents.CHEST_CLOSE)
}
@@ -66,9 +70,11 @@ class ExchangeItem<E> : Behavior<E>(
}
private fun exchangeItems(level: ServerLevel, entity: E) {
val container = level.getBlockEntity(target!!) as Container
val container = level.getBlockEntity(target!!) ?: return
if (container !is Container)
return
val inventory = entity.inventory
for (i in 1..6) {
for (i in 1..10) {
val maxCount = 1 + level.random.nextInt(16)
if (level.random.nextBoolean()) {
// take
@@ -77,7 +83,7 @@ class ExchangeItem<E> : Behavior<E>(
if (!item.isEmpty) {
val takeCount = min(item.count, maxCount)
val takeItem = item.copyWithCount(takeCount)
if (inventory.canTakeItem(container, slot, takeItem) && entity.canHoldItem(takeItem)) {
if (entity.canHoldItem(takeItem)) {
val remaining = inventory.addItem(/*entity.equipItemIfPossible(takeItem)*/ takeItem)
val actualCount = takeCount - remaining.count
item.shrink(actualCount)
@@ -91,33 +97,31 @@ class ExchangeItem<E> : Behavior<E>(
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 (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 (targetItem.isEmpty) {
container.setItem(target, takeItem.copyAndClear())
break
}
}
if (!takeItem.isEmpty) {
for (target in 0 until container.containerSize) {
val targetItem = container.getItem(target)
if (targetItem.isEmpty) {
container.setItem(target, takeItem.copyAndClear())
break
}
}
}
val putCount = takeCount - takeItem.count
item.shrink(putCount)
inventory.setItem(slot, item)
}
val putCount = takeCount - takeItem.count
item.shrink(putCount)
inventory.setItem(slot, item)
}
}
}

View File

@@ -10,6 +10,7 @@ import net.minecraft.world.level.block.entity.BaseContainerBlockEntity
import quaedam.Quaedam
import quaedam.utils.getChunksNearby
import java.util.*
import kotlin.random.Random
class NearestVisibleContainer : Sensor<LivingEntity>() {
@@ -33,7 +34,9 @@ class NearestVisibleContainer : Sensor<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()) }
.sortedBy { it.distManhattan(entity.blockPosition()) / 5 }
.shuffled(Random(System.currentTimeMillis() / 10000))
.firstOrNull()
entity.brain.setMemory(memory.get(), pos)
}
}

View File

@@ -29,8 +29,8 @@ object ProjectedPersonAI {
val defaultSchedule = Quaedam.schedules.register("projected_person_default") {
ScheduleBuilder(Schedule()).changeActivityAt(10, Activity.IDLE)
.changeActivityAt(10, Activity.IDLE)
.changeActivityAt(2000, Activity.WORK)
.changeActivityAt(7300, Activity.IDLE)
.changeActivityAt(900, Activity.WORK)
.changeActivityAt(6300, Activity.IDLE)
.changeActivityAt(9000, Activity.WORK)
.changeActivityAt(10700, Activity.IDLE)
.changeActivityAt(11000, Activity.PLAY)
@@ -51,6 +51,8 @@ object ProjectedPersonAI {
init {
BedInChunkSensor
AmusementAI
WorkPoiAI
NearestVisibleContainer
}
@@ -67,6 +69,7 @@ object ProjectedPersonAI {
MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE,
MemoryModuleType.HOME,
MemoryModuleType.LAST_WOKEN,
MemoryModuleType.NEAREST_BED,
NearestVisibleContainer.memory.get(),
)
}
@@ -129,6 +132,9 @@ object ProjectedPersonAI {
private fun initIdleActivity(brain: Brain<ProjectedPersonEntity>) {
brain.addActivity(
Activity.IDLE, ImmutableList.of(
5 weight AmusementAI.createStrollAroundPoi(),
7 weight AmusementAI.createStrollToPoi(),
9 weight AmusementAI.createAcquirePoi(),
10 weight createStrollBehavior(),
)
)
@@ -137,7 +143,10 @@ object ProjectedPersonAI {
private fun initPlayActivity(brain: Brain<ProjectedPersonEntity>) {
brain.addActivity(
Activity.PLAY, ImmutableList.of(
7 weight GoToWantedItem.create(1.75f, true, 32),
3 weight GoToWantedItem.create(1.75f, true, 32),
5 weight AmusementAI.createStrollAroundPoiBaby(),
7 weight AmusementAI.createStrollToPoiBaby(),
9 weight AmusementAI.createAcquirePoi(),
10 weight JumpOnBed(1.0f),
10 weight createStrollBehavior(),
)
@@ -148,7 +157,15 @@ object ProjectedPersonAI {
brain.addActivity(
Activity.WORK, ImmutableList.of(
5 weight ExchangeItem(),
10 weight createStrollBehavior(),
7 weight WorkPoiAI.createStrollAroundPoi(),
7 weight WorkPoiAI.createStrollToPoi(),
10 weight RunOne(
mapOf(),
listOf(
1 weightR createStrollBehavior(),
1 weightR WorkPoiAI.createAcquirePoi(),
)
),
)
)
}
@@ -172,7 +189,7 @@ object ProjectedPersonAI {
private fun createStrollBehavior() = RunOne(
listOf(
2 weightR RandomStroll.stroll(1.0f),
2 weightR RandomStroll.stroll(1.0f, 42, 12),
2 weightR SetWalkTargetFromLookTarget.create(1.0f, 5),
1 weightR DoNothing(30, 60)
)

View File

@@ -0,0 +1,49 @@
package quaedam.projection.swarm.ai
import net.minecraft.core.GlobalPos
import net.minecraft.world.entity.ai.behavior.AcquirePoi
import net.minecraft.world.entity.ai.behavior.StrollAroundPoi
import net.minecraft.world.entity.ai.behavior.StrollToPoi
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.village.poi.PoiTypes
import quaedam.Quaedam
import java.util.*
object WorkPoiAI {
const val ID = "work"
val poiTypes by lazy {
setOf(
PoiTypes.ARMORER,
PoiTypes.BUTCHER,
PoiTypes.CARTOGRAPHER,
PoiTypes.CLERIC,
PoiTypes.FARMER,
PoiTypes.FISHERMAN,
PoiTypes.FLETCHER,
PoiTypes.LEATHERWORKER,
PoiTypes.LIBRARIAN,
PoiTypes.MASON,
PoiTypes.SHEPHERD,
PoiTypes.TOOLSMITH,
PoiTypes.WEAPONSMITH,
PoiTypes.LODESTONE,
PoiTypes.LIGHTNING_ROD,
)
}
val memory = Quaedam.memoryTypes.register(ID) {
MemoryModuleType(Optional.of(GlobalPos.CODEC))
}!!
fun createAcquirePoi() =
AcquirePoi.create({ it.`is` { key -> key in poiTypes } }, memory.get(), false, Optional.empty())
fun createStrollToPoi() =
StrollToPoi.create(memory.get(), 0.4f, 7, 4)
fun createStrollAroundPoi() =
StrollAroundPoi.create(memory.get(), 0.4f, 5)
}

View File

@@ -30,11 +30,11 @@ object Projector {
BlockEntityType.Builder.of(::ProjectorBlockEntity, block.get()).build(null)
}!!
val currentEffectRadius get() = QuaedamConfig.current.projectorEffectRadius
val currentEffectRadius get() = QuaedamConfig.current.valuesInt["projector.effect_radius"] ?: 4
fun findNearbyProjectors(level: Level, pos: BlockPos) = level.getChunksNearby(pos, currentEffectRadius)
.flatMap {
it.blockEntities.filter { (_, v) -> v is ProjectorBlockEntity }
it.blockEntities.filter { (_, v) -> v is ProjectorBlockEntity && pos in v }
.keys
.filterNotNull()
}

View File

@@ -1,6 +1,7 @@
package quaedam.projector
import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerLevel
import net.minecraft.util.RandomSource
import net.minecraft.world.InteractionHand
@@ -15,6 +16,8 @@ import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.material.MapColor
import net.minecraft.world.level.material.PushReaction
import net.minecraft.world.phys.BlockHitResult
import quaedam.shell.ProjectionShellItem
import quaedam.utils.sendBlockUpdated
object ProjectorBlock : Block(Properties.of()
.jumpFactor(0.8f)
@@ -41,6 +44,21 @@ object ProjectorBlock : Block(Properties.of()
interactionHand: InteractionHand,
blockHitResult: BlockHitResult
): InteractionResult {
if (player.getItemInHand(interactionHand).item == ProjectionShellItem) {
if (!level.isClientSide) {
val entity = level.getBlockEntity(blockPos) as ProjectorBlockEntity
var newRadius = entity.effectRadius + 1
if (newRadius > Projector.currentEffectRadius) {
newRadius = 0
}
entity.updateEffectArea(newRadius)
entity.setChanged()
entity.sendBlockUpdated()
checkUpdate(level, blockPos)
player.sendSystemMessage(Component.translatable("quaedam.projector.radius_updated", newRadius))
}
return InteractionResult.sidedSuccess(level.isClientSide)
}
checkUpdate(level, blockPos)
return InteractionResult.PASS
}

View File

@@ -1,6 +1,7 @@
package quaedam.projector
import net.minecraft.core.BlockPos
import net.minecraft.core.SectionPos
import net.minecraft.core.Vec3i
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.protocol.Packet
@@ -17,32 +18,23 @@ import quaedam.projection.ProjectionEffect
import quaedam.projection.ProjectionEffectType
import quaedam.projection.ProjectionProvider
import quaedam.utils.sendBlockUpdated
import kotlin.math.max
import kotlin.math.min
class ProjectorBlockEntity(pos: BlockPos, state: BlockState) :
BlockEntity(Projector.blockEntity.get(), pos, state) {
companion object {
const val TAG_EFFECT_RADIUS = "EffectRadius"
const val TAG_PROJECTION_EFFECTS = "ProjectionEffects"
}
val effectAreaChunk by lazy {
val chunk = level!!.getChunk(pos).pos
ChunkPos(chunk.x - Projector.currentEffectRadius, chunk.z - Projector.currentEffectRadius) to
ChunkPos(chunk.x + Projector.currentEffectRadius, chunk.z + Projector.currentEffectRadius)
}
var effectRadius: Int = 0
lateinit var effectArea: BoundingBox
lateinit var effectAreaAABB: AABB
val effectArea: BoundingBox by lazy {
val (minChunk, maxChunk) = effectAreaChunk
val minBlock = BlockPos(minChunk.minBlockX, level!!.minBuildHeight, minChunk.minBlockZ)
val maxBlock = BlockPos(maxChunk.maxBlockX, level!!.maxBuildHeight, maxChunk.maxBlockZ)
BoundingBox.fromCorners(minBlock, maxBlock)
}
val effectAreaAABB by lazy {
val (minChunk, maxChunk) = effectAreaChunk
val minBlock = BlockPos(minChunk.minBlockX, level!!.minBuildHeight, minChunk.minBlockZ)
val maxBlock = BlockPos(maxChunk.maxBlockX, level!!.maxBuildHeight, maxChunk.maxBlockZ)
AABB(minBlock, maxBlock)
init {
updateEffectArea(Projector.currentEffectRadius)
}
val checkArea: BoundingBox by lazy {
@@ -57,11 +49,13 @@ class ProjectorBlockEntity(pos: BlockPos, state: BlockState) :
effects.map { (type, effect) ->
effectsTag.put(type.id.toString(), effect.toNbt())
}
tag.putInt(TAG_EFFECT_RADIUS, effectRadius)
tag.put(TAG_PROJECTION_EFFECTS, effectsTag)
}
override fun load(tag: CompoundTag) {
super.load(tag)
updateEffectArea(max(min(tag.getInt(TAG_EFFECT_RADIUS), Projector.currentEffectRadius), 0))
val effectsTag = tag[TAG_PROJECTION_EFFECTS]
val effects = mutableMapOf<ProjectionEffectType<*>, ProjectionEffect>()
if (effectsTag != null && effectsTag is CompoundTag) {
@@ -76,6 +70,20 @@ class ProjectorBlockEntity(pos: BlockPos, state: BlockState) :
updateEffects(effects, notify = false)
}
fun updateEffectArea(radius: Int) {
effectRadius = radius
val chunk = ChunkPos(SectionPos.blockToSectionCoord(blockPos.x), SectionPos.blockToSectionCoord(blockPos.z))
val minChunk = ChunkPos(chunk.x - radius, chunk.z - radius)
val maxChunk = ChunkPos(chunk.x + radius, chunk.z + radius)
// Y is not the limit value of Int because at
// Lnet/minecraft/world/level/entity/EntitySectionStorage;forEachAccessibleNonEmptySection(Lnet/minecraft/world/phys/AABB;Lnet/minecraft/util/AbortableIterationConsumer;)V
// it may get overflow
val minBlock = BlockPos(minChunk.minBlockX, Short.MIN_VALUE.toInt(), minChunk.minBlockZ)
val maxBlock = BlockPos(maxChunk.maxBlockX, Short.MAX_VALUE.toInt(), maxChunk.maxBlockZ)
effectArea = BoundingBox.fromCorners(minBlock, maxBlock)
effectAreaAABB = AABB(minBlock, maxBlock)
}
override fun getUpdateTag(): CompoundTag = saveWithoutMetadata()
override fun getUpdatePacket(): Packet<ClientGamePacketListener> = ClientboundBlockEntityDataPacket.create(this)

View File

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -13,6 +13,7 @@
"item.quaedam.projection_shell": "Projection Shell",
"item.quaedam.iron_copper_metal": "Copper-iron Alloy",
"item.quaedam.projection_metal": "Projection Metal",
"quaedam.projector.radius_updated": "Current effect radius: %s",
"quaedam.screen.projection_shell": "Projection Shell",
"quaedam.screen.projection_shell.lock_revoked": "Timeout! Connection Lost",
"quaedam.screen.projection_shell.lock_failed": "Permission denied!",
@@ -22,10 +23,26 @@
"quaedam.shell.skylight.factor": "Factor",
"quaedam.shell.noise.rate": "Rate",
"quaedam.shell.noise.amount": "Amount",
"quaedam.shell.noise.volume": "Volume",
"quaedam.shell.swarm.max_count": "Max Count",
"quaedam.shell.sound.rate": "Rate",
"quaedam.shell.sound.volume": "Volume",
"quaedam.shell.music.volume_factor": "Volume Factor",
"quaedam.shell.music.particle": "Particle",
"quaedam.shell.music.particle.true": "Display",
"quaedam.shell.music.particle.false": "Hidden"
"quaedam.shell.music.particle.false": "Hidden",
"advancements.quaedam.causality_anchor.title": "Causality",
"advancements.quaedam.causality_anchor.description": "Is there any reason for this?",
"advancements.quaedam.projector.title": "Quaedam",
"advancements.quaedam.projector.description": "Use projectors to project",
"advancements.quaedam.reality_stabler.title": "More Stable",
"advancements.quaedam.reality_stabler.description": "Use reality stabler to stable the reality",
"advancements.quaedam.smart_instrument.title": "Better than Note Block",
"advancements.quaedam.smart_instrument.description": "Use smart instrument",
"advancements.quaedam.sound_projection.title": "Get Noisier",
"advancements.quaedam.sound_projection.description": "Make a sound projection",
"advancements.quaedam.swarm_projection.title": "Too many people",
"advancements.quaedam.swarm_projection.description": "Make a swarm projection",
"advancements.quaedam.kill_projected_person.title": "Go away",
"advancements.quaedam.kill_projected_person.description": "Kill a projection person\n\nWhy are you doing this?\nThis is bad."
}

View File

@@ -4,7 +4,7 @@
"block.quaedam.skylight_projection": "天光投影",
"block.quaedam.swarm_projection": "人群投影",
"block.quaedam.sound_projection": "声音投影",
"block.quaedam.noise_projection": "噪投影",
"block.quaedam.noise_projection": "噪投影",
"block.quaedam.music_projection": "音乐投影",
"block.quaedam.causality_anchor": "因果锚",
"block.quaedam.reality_stabler": "现实稳定器",
@@ -13,6 +13,7 @@
"item.quaedam.projection_shell": "投影操作面板",
"item.quaedam.iron_copper_metal": "铜铁合金",
"item.quaedam.projection_metal": "投影金属",
"quaedam.projector.radius_updated": "当前效果半径:%s",
"quaedam.screen.projection_shell": "投影操作",
"quaedam.screen.projection_shell.lock_revoked": "超时!连接丢失",
"quaedam.screen.projection_shell.lock_failed": "正被使用",
@@ -22,10 +23,26 @@
"quaedam.shell.skylight.factor": "因子",
"quaedam.shell.noise.rate": "速率",
"quaedam.shell.noise.amount": "数量",
"quaedam.shell.noise.volume": "响度因子",
"quaedam.shell.swarm.max_count": "最大数量",
"quaedam.shell.sound.rate": "速率",
"quaedam.shell.sound.volume": "响度因子",
"quaedam.shell.music.volume_factor": "响度因子",
"quaedam.shell.music.particle": "粒子效果",
"quaedam.shell.music.particle.true": "显示",
"quaedam.shell.music.particle.false": "隐藏"
"quaedam.shell.music.particle.false": "隐藏",
"advancements.quaedam.causality_anchor.title": "因果律",
"advancements.quaedam.causality_anchor.description": "这不合理",
"advancements.quaedam.projector.title": "Quaedam",
"advancements.quaedam.projector.description": "使用投影仪进行投影",
"advancements.quaedam.reality_stabler.title": "更加稳定",
"advancements.quaedam.reality_stabler.description": "使用现实稳定器稳定现实",
"advancements.quaedam.smart_instrument.title": "比音符盒更好",
"advancements.quaedam.smart_instrument.description": "使用智能乐器",
"advancements.quaedam.sound_projection.title": "更加吵闹",
"advancements.quaedam.sound_projection.description": "制作声音投影",
"advancements.quaedam.swarm_projection.title": "太多人了",
"advancements.quaedam.swarm_projection.description": "制作人群投影",
"advancements.quaedam.kill_projected_person.title": "走开",
"advancements.quaedam.kill_projected_person.description": "杀死一个投影人\n\n你为什么要这样做呢\n这是不好的。"
}

View File

@@ -0,0 +1,48 @@
{
"category.quaedam": "有些事",
"block.quaedam.projector": "不会发光的投影仪",
"block.quaedam.skylight_projection": "天窗发射",
"block.quaedam.swarm_projection": "群体发射",
"block.quaedam.sound_projection": "生活上的噪声发射",
"block.quaedam.noise_projection": "物理上的噪声发射",
"block.quaedam.music_projection": "音乐发射",
"block.quaedam.causality_anchor": "宇宙万法的那个源头————如",
"block.quaedam.reality_stabler": "投影?退,退,退",
"block.quaedam.smart_instrument": "SMART消歧义笔记方块",
"entity.quaedam.projected_person": "没用的废物",
"item.quaedam.projection_shell": "投射滥权终端",
"item.quaedam.iron_copper_metal": "有点生锈的铁锭",
"item.quaedam.projection_metal": "投影Metal©",
"quaedam.projector.radius_updated": "现在乱七八糟的效果能碰到的范围:%s",
"quaedam.screen.projection_shell": "控制面板",
"quaedam.screen.projection_shell.lock_revoked": "土豆熟了",
"quaedam.screen.projection_shell.lock_failed": "宁配吗?",
"quaedam.screen.projection_shell.save": "我好了",
"quaedam.screen.projection_shell.empty": "空",
"quaedam.screen.projection_shell.close": "怒退",
"quaedam.shell.skylight.factor": "防晒系数",
"quaedam.shell.noise.rate": "急急急等级",
"quaedam.shell.noise.amount": "声卡压榨等级",
"quaedam.shell.noise.volume": "振幅大小",
"quaedam.shell.swarm.max_count": "显卡和处理器迫害等级",
"quaedam.shell.sound.rate": "急急急等级",
"quaedam.shell.sound.volume": "振幅大小",
"quaedam.shell.music.volume_factor": "振幅大小",
"quaedam.shell.music.particle": "会变色的颗粒buff",
"quaedam.shell.music.particle.true": "打开",
"quaedam.shell.music.particle.false": "关掉,关掉,一定要关掉",
"advancements.quaedam.causality_anchor.title": "因果律",
"advancements.quaedam.causality_anchor.description": "这不合理",
"advancements.quaedam.projector.title": "有些事",
"advancements.quaedam.projector.description": "你是黑魔法(指着 JVMTI师吗",
"advancements.quaedam.reality_stabler.title": "水滴",
"advancements.quaedam.reality_stabler.description": "tql这是强互作用力做的吗",
"advancements.quaedam.smart_instrument.title": "SMART消歧义",
"advancements.quaedam.smart_instrument.description": "音乐盘?不需要的",
"advancements.quaedam.sound_projection.title": "不要偷偷摸摸",
"advancements.quaedam.sound_projection.description": "又没有幽yóu匿分贝仪、幽yóu匿尖叫体或大聪明怕什么",
"advancements.quaedam.swarm_projection.title": "多来点,爱看",
"advancements.quaedam.swarm_projection.description": "",
"advancements.quaedam.kill_projected_person.title": "失败",
"advancements.quaedam.kill_projected_person.description": "投影人这么可爱,为什么要失败投影人\n\n你干嘛\n坏太坏了你不能这样。"
}

View File

@@ -152,6 +152,26 @@
{
"name": "entity.villager.work_weaponsmith",
"type": "event"
},
{
"name": "block.anvil.use",
"type": "event"
},
{
"name": "block.furnace.fire_crackle",
"type": "event"
},
{
"name": "block.blastfurnace.fire_crackle",
"type": "event"
},
{
"name": "block.metal.break",
"type": "event"
},
{
"name": "block.wood.break",
"type": "event"
}
]
}

View File

@@ -0,0 +1,37 @@
{
"display": {
"icon": {
"item": "quaedam:causality_anchor"
},
"title": {
"translate": "advancements.quaedam.causality_anchor.title"
},
"description": {
"translate": "advancements.quaedam.causality_anchor.description"
},
"frame": "goal"
},
"parent": "quaedam:projector",
"criteria": {
"causality_anchor": {
"trigger": "minecraft:placed_block",
"conditions": {
"location": [
{
"condition": "minecraft:block_state_property",
"block": "quaedam:causality_anchor",
"properties": {}
}
]
}
}
},
"requirements": [
[
"causality_anchor"
]
],
"rewards": {
"experience": 30
}
}

View File

@@ -0,0 +1,37 @@
{
"display": {
"icon": {
"item": "quaedam:swarm_projection"
},
"title": {
"translate": "advancements.quaedam.kill_projected_person.title"
},
"description": {
"translate": "advancements.quaedam.kill_projected_person.description"
},
"hidden": true
},
"parent": "quaedam:swarm_projection",
"criteria": {
"kill_projected_person": {
"trigger": "minecraft:player_killed_entity",
"conditions": {
"entity": [
{
"condition": "minecraft:entity_properties",
"entity": "this",
"predicate": {
"type": "quaedam:projected_person"
}
}
]
}
}
},
"requirements": [
[
"kill_projected_person"
]
],
"rewards": {}
}

View File

@@ -0,0 +1,37 @@
{
"display": {
"icon": {
"item": "quaedam:projector"
},
"title": {
"translate": "advancements.quaedam.projector.title"
},
"description": {
"translate": "advancements.quaedam.projector.description"
},
"background": "minecraft:textures/gui/advancements/backgrounds/husbandry.png",
"frame": "task"
},
"criteria": {
"projector": {
"trigger": "minecraft:placed_block",
"conditions": {
"location": [
{
"condition": "minecraft:block_state_property",
"block": "quaedam:projector",
"properties": {}
}
]
}
}
},
"requirements": [
[
"projector"
]
],
"rewards": {
"experience": 15
}
}

View File

@@ -0,0 +1,37 @@
{
"display": {
"icon": {
"item": "quaedam:reality_stabler"
},
"title": {
"translate": "advancements.quaedam.reality_stabler.title"
},
"description": {
"translate": "advancements.quaedam.reality_stabler.description"
},
"frame": "goal"
},
"parent": "quaedam:projector",
"criteria": {
"reality_stabler": {
"trigger": "minecraft:placed_block",
"conditions": {
"location": [
{
"condition": "minecraft:block_state_property",
"block": "quaedam:reality_stabler",
"properties": {}
}
]
}
}
},
"requirements": [
[
"reality_stabler"
]
],
"rewards": {
"experience": 30
}
}

View File

@@ -0,0 +1,36 @@
{
"display": {
"icon": {
"item": "quaedam:smart_instrument"
},
"title": {
"translate": "advancements.quaedam.smart_instrument.title"
},
"description": {
"translate": "advancements.quaedam.smart_instrument.description"
}
},
"parent": "quaedam:projector",
"criteria": {
"smart_instrument": {
"trigger": "minecraft:placed_block",
"conditions": {
"location": [
{
"condition": "minecraft:block_state_property",
"block": "quaedam:smart_instrument",
"properties": {}
}
]
}
}
},
"requirements": [
[
"smart_instrument"
]
],
"rewards": {
"experience": 15
}
}

View File

@@ -0,0 +1,36 @@
{
"display": {
"icon": {
"item": "quaedam:sound_projection"
},
"title": {
"translate": "advancements.quaedam.sound_projection.title"
},
"description": {
"translate": "advancements.quaedam.sound_projection.description"
}
},
"parent": "quaedam:swarm_projection",
"criteria": {
"sound_projection": {
"trigger": "minecraft:placed_block",
"conditions": {
"location": [
{
"condition": "minecraft:block_state_property",
"block": "quaedam:sound_projection",
"properties": {}
}
]
}
}
},
"requirements": [
[
"sound_projection"
]
],
"rewards": {
"experience": 15
}
}

View File

@@ -0,0 +1,37 @@
{
"display": {
"icon": {
"item": "quaedam:swarm_projection"
},
"title": {
"translate": "advancements.quaedam.swarm_projection.title"
},
"description": {
"translate": "advancements.quaedam.swarm_projection.description"
},
"frame": "goal"
},
"parent": "quaedam:projector",
"criteria": {
"swarm_projection": {
"trigger": "minecraft:placed_block",
"conditions": {
"location": [
{
"condition": "minecraft:block_state_property",
"block": "quaedam:swarm_projection",
"properties": {}
}
]
}
}
},
"requirements": [
[
"swarm_projection"
]
],
"rewards": {
"experience": 30
}
}

82
fabric/build.gradle.kts Normal file
View File

@@ -0,0 +1,82 @@
plugins {
id("com.github.johnrengelman.shadow")
}
architectury {
platformSetupLoomIde()
fabric()
}
loom {
accessWidenerPath.set(project(":common").loom.accessWidenerPath)
}
val common: Configuration by configurations.creating
val shadowCommon: Configuration by configurations.creating
val developmentFabric: Configuration by configurations.getting
configurations {
compileOnly.configure { extendsFrom(common) }
runtimeOnly.configure { extendsFrom(common) }
developmentFabric.extendsFrom(common)
}
dependencies {
modImplementation("net.fabricmc:fabric-loader:${rootProject.property("fabric_loader_version")}")
modApi("net.fabricmc.fabric-api:fabric-api:${rootProject.property("fabric_version")}")
modApi("dev.architectury:architectury-fabric:${rootProject.property("architectury_version")}")
modImplementation("net.fabricmc:fabric-language-kotlin:${rootProject.property("fabric_kotlin_version")}")
common(project(":common", "namedElements")) {
isTransitive = false
}
shadowCommon(project(":common", "transformProductionFabric")){
isTransitive = false
}
}
tasks.processResources {
inputs.property("version", project.version)
filesMatching("fabric.mod.json") {
expand(
mapOf(
"version" to project.version,
"minecraft_version" to rootProject.property("minecraft_version"),
"architectury_version" to rootProject.property("architectury_version"),
"fabric_kotlin_version" to rootProject.property("fabric_kotlin_version")
)
)
}
}
tasks.shadowJar {
exclude("architectury.common.json")
configurations = listOf(shadowCommon)
archiveClassifier.set("dev-shadow")
}
tasks.remapJar {
injectAccessWidener.set(true)
inputFile.set(tasks.shadowJar.get().archiveFile)
dependsOn(tasks.shadowJar)
archiveClassifier.set(null as String?)
}
tasks.jar {
archiveClassifier.set("dev")
}
tasks.sourcesJar {
val commonSources = project(":common").tasks.getByName<Jar>("sourcesJar")
dependsOn(commonSources)
from(commonSources.archiveFile.map { zipTree(it) })
}
components.getByName("java") {
this as AdhocComponentWithVariants
this.withVariantsFromConfiguration(project.configurations["shadowRuntimeElements"]) {
skip()
}
}

View File

@@ -0,0 +1,12 @@
package quaedam.fabric
import net.fabricmc.api.ModInitializer
import quaedam.Quaedam
object QuaedamFabric: ModInitializer {
override fun onInitialize() {
Quaedam.init()
}
}

View File

@@ -0,0 +1,34 @@
{
"schemaVersion": 1,
"id": "quaedam",
"version": "${version}",
"name": "Quaedam",
"description": "Hot hot hot!",
"authors": [
"xtex"
],
"contact": {
"homepage": "https://codeberg.org/xtex/quaedam",
"sources": "https://codeberg.org/xtex/quaedam"
},
"license": "Apache-2.0",
"icon": "assets/quaedam/icon.png",
"environment": "*",
"entrypoints": {
"main": [
{
"adapter": "kotlin",
"value": "quaedam.fabric.QuaedamFabric"
}
]
},
"mixins": [
"quaedam-common.mixins.json"
],
"depends": {
"fabric": "*",
"minecraft": ">=${minecraft_version}",
"architectury": ">=${architectury_version}",
"fabric-language-kotlin": ">=${fabric_kotlin_version}"
}
}

View File

@@ -0,0 +1,13 @@
{
"required": true,
"package": "quaedam.fabric.mixin",
"compatibilityLevel": "JAVA_17",
"minVersion": "0.8",
"client": [
],
"mixins": [
],
"injectors": {
"defaultRequire": 1
}
}

View File

@@ -11,7 +11,7 @@ authors = "xtex"
description = '''
Hot hot hot!
'''
logoFile = "icon.png"
logoFile = "assets/quaedam/icon.png"
[[dependencies.quaedam]]
modId = "forge"

View File

@@ -1,13 +1,27 @@
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
parchment_version=2023.07.30
# https://modrinth.com/mod/architectury-api
architectury_version=9.1.12
# https://files.minecraftforge.net/net/minecraftforge/forge/
forge_version=1.20.1-47.1.43
# https://www.curseforge.com/minecraft/mc-mods/kotlin-for-forge/files
# https://modrinth.com/mod/kotlin-for-forge
kotlin_for_forge_version=4.4.0
# https://fabricmc.net/develop/
fabric_loader_version=0.14.21
fabric_version=0.86.1+1.20.1
# https://modrinth.com/mod/fabric-language-kotlin
fabric_kotlin_version=1.10.8+kotlin.1.9.0
# https://github.com/QuiltMC/quilt-loader/tags
quilt_loader_version=0.20.0-beta.5
# https://modrinth.com/mod/qsl
quilt_fabric_version=7.0.3+0.83.1-1.20.1
quilt_standard_library_version=6.0.4+1.20.1
# https://modrinth.com/mod/qkl
quilt_kotlin_libraries_version=2.1.1+kt.1.9.0+flk.1.9.6

86
quilt/build.gradle.kts Normal file
View File

@@ -0,0 +1,86 @@
plugins {
id("com.github.johnrengelman.shadow")
}
architectury {
platformSetupLoomIde()
loader("quilt")
}
loom {
accessWidenerPath.set(project(":common").loom.accessWidenerPath)
}
val common: Configuration by configurations.creating
val shadowCommon: Configuration by configurations.creating
val developmentQuilt: Configuration by configurations.getting
configurations {
compileOnly.configure { extendsFrom(common) }
runtimeOnly.configure { extendsFrom(common) }
developmentQuilt.extendsFrom(common)
}
dependencies {
modImplementation("org.quiltmc:quilt-loader:${rootProject.property("quilt_loader_version")}")
modApi("org.quiltmc.quilted-fabric-api:quilted-fabric-api:${rootProject.property("quilt_fabric_version")}")
modApi("dev.architectury:architectury-fabric:${rootProject.property("architectury_version")}") {
exclude("net.fabricmc")
exclude("net.fabricmc.fabric-api")
}
modApi("org.quiltmc:qsl:${rootProject.property("quilt_standard_library_version")}")
modApi("org.quiltmc.quilt-kotlin-libraries:quilt-kotlin-libraries:${rootProject.property("quilt_kotlin_libraries_version")}")
common(project(":common", "namedElements")) {
isTransitive = false
}
shadowCommon(project(":common", "transformProductionQuilt")) {
isTransitive = false
}
}
tasks.processResources {
inputs.property("version", project.version)
filesMatching("quilt.mod.json") {
expand(
mapOf(
"version" to project.version,
"minecraft_version" to rootProject.property("minecraft_version"),
"architectury_version" to rootProject.property("architectury_version"),
"quilt_kotlin_libraries_version" to rootProject.property("quilt_kotlin_libraries_version"),
)
)
}
}
tasks.shadowJar {
exclude("architectury.common.json")
configurations = listOf(shadowCommon)
archiveClassifier.set("dev-shadow")
}
tasks.remapJar {
injectAccessWidener.set(true)
inputFile.set(tasks.shadowJar.get().archiveFile)
dependsOn(tasks.shadowJar)
archiveClassifier.set(null as String?)
}
tasks.jar {
archiveClassifier.set("dev")
}
tasks.sourcesJar {
val commonSources = project(":common").tasks.getByName<Jar>("sourcesJar")
dependsOn(commonSources)
from(commonSources.archiveFile.map { zipTree(it) })
}
components.getByName("java") {
this as AdhocComponentWithVariants
this.withVariantsFromConfiguration(project.configurations["shadowRuntimeElements"]) {
skip()
}
}

1
quilt/gradle.properties Normal file
View File

@@ -0,0 +1 @@
loom.platform=quilt

View File

@@ -0,0 +1,12 @@
package quaedam.quilt
import net.fabricmc.api.ModInitializer
import quaedam.Quaedam
object QuaedamQuilt: ModInitializer {
override fun onInitialize() {
Quaedam.init()
}
}

View File

@@ -0,0 +1,13 @@
{
"required": true,
"package": "quaedam.fabric.mixin",
"compatibilityLevel": "JAVA_17",
"minVersion": "0.8",
"client": [
],
"mixins": [
],
"injectors": {
"defaultRequire": 1
}
}

View File

@@ -0,0 +1,59 @@
{
"_comment": "https://github.com/QuiltMC/rfcs/blob/main/specification/0002-quilt.mod.json.md",
"schema_version": 1,
"mixin": [
"quaedam-common.mixins.json"
],
"quilt_loader": {
"metadata": {
"name": "Quaedam",
"description": "Hot hot hot!",
"license": "Apache-2.0",
"authors": [
"xtex"
],
"contact": {
"homepage": "https://codeberg.org/xtex/quaedam",
"sources": "https://codeberg.org/xtex/quaedam"
},
"icon": "assets/quaedam/icon.png"
},
"group": "quaedam",
"id": "quaedam",
"version": "${version}",
"intermediate_mappings": "net.fabricmc:intermediary",
"entrypoints": {
"init": [
{
"adapter": "kotlin",
"value": "quaedam.quilt.QuaedamQuilt"
}
]
},
"depends": [
{
"id": "quilt_loader",
"version": "*"
},
{
"id": "quilt_base",
"version": "*"
},
{
"id": "minecraft",
"version": ">=${minecraft_version}"
},
{
"id": "architectury",
"version": ">=${architectury_version}"
},
{
"id": "qkl",
"version": ">=${quilt_kotlin_libraries_version}"
}
]
},
"minecraft": {
"environment": "*"
}
}

View File

@@ -10,5 +10,6 @@ pluginManagement {
include("common")
include("forge")
include("fabric", "quilt")
rootProject.name = "quaedam"