repo for my hex addons :3
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

networking & gradle refactor

+584 -293
+3 -1
.envrc
··· 10 10 11 11 . <(comm -13 <(env | sort) <(nixGL env | sort)) 12 12 export LD_LIBRARY_PATH="$extraLibs/lib/apulse:$extraLibs/lib:$LD_LIBRARY_PATH" 13 - export ALSOFT_LOGLEVEL=3 ALSOFT_LOGFILE=$PWD/run/alsoft.log 13 + export ALSOFT_LOGLEVEL=3 ALSOFT_LOGFILE=$PWD/run/alsoft.log 14 + 15 + export KOTLIN_OPTS=-Xcontext-receivers
+49 -250
build.gradle.kts
··· 1 - import com.google.gson.Gson 2 - import com.google.gson.JsonObject 3 - import com.google.gson.JsonArray 4 1 import de.undercouch.gradle.tasks.download.Download 5 2 import net.fabricmc.loom.task.prod.ClientProductionRunTask 3 + import org.eu.net.pool.mc_plugin.Environment 4 + import org.eu.net.pool.mc_plugin.JsonDsl 6 5 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 7 6 import kotlin.text.replace 8 7 ··· 13 12 id("maven-publish") 14 13 id("idea") 15 14 id("de.undercouch.download") version "5.6.0" 15 + id("org.eu.net.pool.mc") 16 16 } 17 17 18 18 version = project.property("mod_version") as String 19 19 group = project.property("maven_group") as String 20 - val minecraft_version: String by project.properties 21 20 val cca_version by lazy { project.property("cca_version") as String } 22 21 23 - val serialVersion = minecraft_version.let { 24 - val (maj, min, pat) = it.toString().split('.') 25 - min.toInt() * 100 + pat.toInt() 26 - } 27 - 28 - project.buildDir = file("build$serialVersion") 29 - 30 22 fun <T> List<T>.uncons() = first() to drop(1) 31 23 run { 32 24 val (headers, versions) = file("versions.csv").readText().lines().map { it.split(',').uncons() }.uncons() ··· 41 33 overwrite(true) 42 34 onlyIf { !dest.exists() } 43 35 } 44 - val soundsDir by tasks.register<Sync>("assets") { 36 + val assetsDir by tasks.register<Sync>("assets") { 45 37 dependsOn(assetsArchive) 46 38 inputs.file(assetsArchive.dest) 47 39 val interest = "minecraft-assets-$minecraft_version/assets/minecraft/sounds" ··· 61 53 } 62 54 } 63 55 val synthSounds by tasks.register("synthSounds") { 64 - dependsOn(soundsDir) 56 + dependsOn(assetsDir) 65 57 val inDir = "$buildDir/mcSounds" 66 58 val outDir = "$buildDir/generatedSounds" 67 59 inputs.dir(inDir) ··· 177 169 } 178 170 } 179 171 180 - val mergedDeps by configurations.creating 181 - 182 172 tasks.register<ClientProductionRunTask>("prodClient") 183 173 184 174 dependencies { ··· 207 197 //include(modApi("dev.onyxstudios.cardinal-components-api:cardinal-components-item:$cca_version")!!) 208 198 } 209 199 210 - object Statics { 211 - val File.wslPath 212 - get() = path.replace('\\', '/').replace(Regex("^([A-Z]):")) { g -> "/mnt/${g.groupValues[1].lowercase()}" } 213 - } 214 - 215 - @DslMarker 216 - annotation class JsonDsl { 217 - sealed interface Element 218 - @JsonDsl 219 - class Object(val element: JsonObject = JsonObject()): Element { 220 - fun put(key: String, value: String) { 221 - element.addProperty(key, value) 222 - } 223 - fun put(key: String, value: Number) { 224 - element.addProperty(key, value) 225 - } 226 - fun put(key: String, value: Boolean) { 227 - element.addProperty(key, value) 228 - } 229 - fun array(key: String, action: JsonDsl.Array.() -> Unit) { 230 - element.add(key, JsonArray().also { Array(it).action() }) 231 - } 232 - fun map(key: String, action: Object.() -> Unit) { 233 - element.add(key, JsonObject().also { Object(it).action() }) 234 - } 235 - 236 - override fun toString(): String = Gson().toJson(element) 237 - } 238 - @JsonDsl 239 - class Array(val element: JsonArray = JsonArray()): Element { 240 - fun put(value: String) { 241 - element.add(value) 242 - } 243 - fun put(value: Number) { 244 - element.add(value) 245 - } 246 - fun put(value: Boolean) { 247 - element.add(value) 248 - } 249 - fun array(action: JsonDsl.Array.() -> Unit) { 250 - element.add(JsonArray().also { Array(it).action() }) 251 - } 252 - fun map(action: Object.() -> Unit) { 253 - element.add(JsonObject().also { Object(it).action() }) 254 - } 255 - 256 - override fun toString(): String = Gson().toJson(element) 257 - } 258 - } 259 - 260 200 loom { 261 201 runs["client"].apply { 262 202 vmArg("-XX:+FlightRecorder") 263 203 programArgs("--username", "PoolloverNathan") 264 204 } 265 - } 266 - 267 - tasks.named<Jar>("jar") { 268 - from(mergedDeps.resolve()) 269 205 } 270 206 271 207 tasks.withType<ProcessResources> { ··· 279 215 filteringCharset = "UTF-8" 280 216 } 281 217 218 + preprocessor { 219 + sourceSets.all { 220 + processTask<JavaCompile>("java") 221 + processTask<KotlinCompile>("kotlin") 222 + processTask<ScalaCompile>("scala") 223 + } 224 + } 225 + 282 226 tasks.processResources { 283 - from(resources.text.fromString( 284 - JsonDsl.Object().apply { 285 - put("schemaVersion", 1) 286 - put("id", "mica") 287 - put("version", version.toString()) 288 - put("name", "Mica") 289 - put("description", 290 - file("README.md").readText().split("<!-- summary -->")[1].lineSequence().first().replace("\\", "\\\\") 291 - .replace("\"", "\\\"").trim() 292 - ) 293 - array("authors") { 294 - map { 295 - put("name", "PoolloverNathan") 296 - map("contact") { 297 - put("discord", "https://discord.com/users/402104961812660226") 298 - put("github", "https://github.com/PoolloverNathan") 299 - put("codeberg", "https://github.com/PoolloverNathan") 300 - } 301 - } 227 + preprocessor { 228 + fabricMod("mica", version.toString()) { 229 + name = "Mica" 230 + description = file("README.md").readText().split("<!-- summary -->")[1].lineSequence().first().replace("\\", "\\\\").replace("\"", "\\\"").trim() 231 + icon = "assets/mica/icon.png" 232 + author("PoolloverNathan") { 233 + put("discord", "https://discord.com/users/402104961812660226") 234 + put("github", "https://github.com/PoolloverNathan") 235 + put("codeberg", "https://github.com/PoolloverNathan") 302 236 } 303 - array("contributors") { 304 - map { 305 - put("name", "dinosore_rs") 306 - put("role", "textures") 307 - map("contact") { 308 - put("discord", "https://discord.com/users/219925949309779970") 309 - put("github", "https://github.com/dinosore-rs") 310 - } 311 - } 312 - map { 313 - put("name", "afamiliarquiet") 314 - put("role", "stole your fops code") // she stole it first 315 - map("contact") { 316 - put("discord", "https://discord.com/users/813502272355958844") 317 - put("github", "https://github.com/afamiliarquiet") 318 - } 319 - } 237 + contributor("dinosore_rs", "textures") { 238 + put("discord", "https://discord.com/users/219925949309779970") 239 + put("github", "https://github.com/dinosore-rs") 320 240 } 321 - map("contact") { 322 - put("issues", "https://codeberg.org/poollovernathan/mica/issues") 323 - put("homepage", "https://codeberg.org/poollovernathan/mica") 324 - put("sources", "git+https://codeberg.org/poollovernathan/mica") 241 + contributor("afamiliarquiet", "stole your fops code" /* it stole it first */) { 242 + put("discord", "https://discord.com/users/813502272355958844") 243 + put("github", "https://github.com/afamiliarquiet") 325 244 } 326 - put("license", "GPL-3.0") 327 - put("icon", "assets.mica/icon.png") 328 - put("environment", "*") 329 - map("entrypoints") { 330 - array("fabric-datagen") { 331 - put("org.net.eu.pool.mica.client.MicaClient\$package::datagen") 332 - } 333 - array("client") { 334 - put("org.net.eu.pool.mica.client.MicaClient\$package::init") 335 - } 336 - array("main") { 337 - put("org.net.eu.pool.mica.Mica\$package::init") 338 - } 339 - array("cardinal-components") { 340 - put("org.net.eu.pool.mica.ComponentInitializer") 341 - } 342 - } 343 - array("mixins") { 344 - put("mica.mixins.json") 345 - map { 346 - put("config", "mica.client.mixins.json") 347 - put("environment", "client") 348 - } 349 - } 350 - map("depends") { 351 - put("fabricloader", ">=${project.properties["loader_version"]}") 352 - put("krysztal-language-scala", "3.3.0+scala.3.7.1") 353 - put("fabric", "*") 354 - put("minecraft", minecraft_version) 355 - // put("cardinal-components-item", ">=$cca_version") 356 - put("cardinal-components-world", ">=$cca_version") 357 - } 358 - map("custom") { 245 + contact("issues", "https://codeberg.org/poollovernathan/mica/issues") 246 + contact("homepage", "https://codeberg.org/poollovernathan/mica") 247 + contact("sources", "git+https://codeberg.org/poollovernathan/mica") 248 + 249 + entrypoint("org.net.eu.pool.mica.Mica\$package::init") 250 + entrypoint("org.net.eu.pool.mica.client.MicaClient\$package::init", Environment.Client) 251 + entrypoint("fabric-datagen", "org.net.eu.pool.mica.client.MicaClient\$package::datagen") 252 + entrypoint("cardinal-components", "org.net.eu.pool.mica.ComponentInitializer") 253 + mixins("mica.mixins.json") 254 + mixins("mica.client.mixins.json", Environment.Client) 255 + 256 + depends("fabricloader", ">=${project.properties["loader_version"]}") 257 + depends("krysztal-language-scala", "3.3.0+scala.3.7.1") 258 + depends("fabric", "*") 259 + depends("minecraft", minecraft_version) 260 + //depends("cardinal-components-item", ">=$cca_version") 261 + depends("cardinal-components-world", ">=$cca_version") 262 + 263 + custom { 359 264 array("cardinal-components") { 360 265 for (i in 0..767) { 361 266 put("mica:runes$i") 362 267 } 363 268 } 364 269 } 365 - }.toString() 366 - )) { 367 - rename { "fabric.mod.json" } 270 + } 368 271 } 369 - 370 272 duplicatesStrategy = DuplicatesStrategy.INCLUDE 371 - 372 273 exclude("**/.cache/**") 373 274 } 374 275 ··· 380 281 } 381 282 382 283 tasks.named("ideaSyncTask") { 383 - dependsOn("runDatagen") 384 - } 385 - 386 - abstract class FrozenFile: DefaultTask() { 387 - @get:InputFiles val macroFiles: ListProperty<RegularFile> = project.objects.listProperty() 388 - @get:OutputFile val frozenFile: Property<RegularFile> = project.objects.fileProperty() 389 - @get:Input val globals: MapProperty<String, String> = project.objects.mapProperty() 390 - init { 391 - inputs.files(macroFiles) 392 - inputs.property("globals", globals) 393 - outputs.file(frozenFile) 394 - } 395 - @TaskAction 396 - fun run() { 397 - project.exec { 398 - Statics.run { 399 - val args = mutableListOf("m4", "-F", frozenFile.get().asFile.wslPath) 400 - globals.get().forEach { k, v -> 401 - args.add("-D$k=$v") 402 - } 403 - macroFiles.get().forEach { 404 - args.add(it.asFile.wslPath) 405 - } 406 - commandLine = args 407 - } 408 - } 409 - } 410 - } 411 - 412 - private val makeFrozen = { 413 - open class Task @Inject constructor() : FrozenFile() { 414 - @Input 415 - @Option(description = "Run the build in seed mode. This compiles only the portion of source needed to bootstrap actual compilation (e.g. macros).") 416 - var seed: Boolean = false 417 - } 418 - tasks.register<Task>("freezeMacros", Task::class.java) { 419 - macroFiles.add(project.layout.projectDirectory.file("macros.m4")) 420 - frozenFile = project.layout.buildDirectory.file("macros.m4f") 421 - globals.put("minecraft_version", serialVersion.toString()) 422 - globals.put("SEED", provider { if (seed) "1" else "0" }) 423 - } 424 - }() 425 - 426 - sourceSets.all { 427 - fun processTask(lang: String, body: Pair<String, Task>.(Provider<Directory>) -> Unit) { 428 - val inDir = project.layout.projectDirectory.dir("src/${this@all.name}/$lang") 429 - val outDir = project.layout.buildDirectory.dir(getTaskName("generated", lang)) 430 - val frozen = project.layout.buildDirectory.file("macros.m4f") 431 - val task by tasks.register(getTaskName("process", lang)) { 432 - inputs.dir(inDir).optional() 433 - inputs.file(frozen) 434 - dependsOn(makeFrozen) 435 - outputs.dir(outDir) 436 - onlyIf { file(inDir).exists() } 437 - doLast { 438 - fileTree(inDir).files.forEach { 439 - file("${outDir.get()}/${it.relativeTo(inDir.asFile)}").parentFile.mkdirs() 440 - Statics.run { 441 - exec { 442 - commandLine("bash", "-c", "m4 -R ${frozen.get().asFile.wslPath} ${it.wslPath}") 443 - standardOutput = file("${outDir.get()}/${it.relativeTo(inDir.asFile)}").outputStream() 444 - } 445 - } 446 - } 447 - } 448 - } 449 - idea { 450 - module { 451 - generatedSourceDirs.add(outDir.get().asFile) 452 - } 453 - } 454 - (getCompileTaskName(lang) to task).body(outDir) 455 - } 456 - processTask("java") { 457 - tasks.named<JavaCompile>(first) { 458 - inputs.property("minecraft_version", serialVersion) 459 - inputs.property("seed", project.properties["seed"]) 460 - dependsOn(second) 461 - doFirst { 462 - setSource(it) 463 - } 464 - } 465 - } 466 - processTask("kotlin") { 467 - tasks.named<KotlinCompile>(first) { 468 - inputs.property("minecraft_version", serialVersion) 469 - inputs.property("seed", project.properties["seed"]) 470 - dependsOn(second) 471 - doFirst { 472 - setSource(it) 473 - } 474 - } 475 - } 476 - processTask("scala") { 477 - tasks.named<ScalaCompile>(first) { 478 - inputs.property("minecraft_version", serialVersion) 479 - inputs.property("seed", project.properties["seed"]) 480 - dependsOn(second) 481 - doFirst { 482 - setSource(it) 483 - } 484 - } 485 - } 284 + // dependsOn("runDatagen") 486 285 } 487 286 488 287 tasks.withType<JavaCompile>().configureEach {
+35
plugin/build.gradle.kts
··· 1 + import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 + 3 + /* 4 + * This file was generated by the Gradle 'init' task. 5 + * 6 + * This generated file contains a sample Gradle plugin project to get you started. 7 + * For more details on writing Custom Plugins, please refer to https://docs.gradle.org/8.14/userguide/custom_plugins.html in the Gradle documentation. 8 + * This project uses @Incubating APIs which are subject to change. 9 + */ 10 + 11 + plugins { 12 + `java-gradle-plugin` 13 + `kotlin-dsl` 14 + kotlin("jvm") version "2.0.21" 15 + } 16 + 17 + repositories { 18 + mavenCentral() 19 + gradlePluginPortal() 20 + } 21 + 22 + dependencies { 23 + implementation("com.google.code.gson:gson:2.13.1") 24 + } 25 + 26 + tasks.withType<KotlinCompile> { 27 + compilerOptions.freeCompilerArgs.add("-Xcontext-receivers") 28 + } 29 + 30 + gradlePlugin { 31 + val plugin by plugins.creating { 32 + id = "org.eu.net.pool.mc" 33 + implementationClass = "org.eu.net.pool.mc_plugin.Plugin" 34 + } 35 + }
plugin/settings.gradle.kts

This is a binary file and will not be displayed.

+111
plugin/src/main/kotlin/org/eu/net/pool/mc_plugin/FabricModBuilder.kt
··· 1 + package org.eu.net.pool.mc_plugin 2 + 3 + import com.google.gson.JsonArray 4 + import com.google.gson.JsonObject 5 + import org.gradle.api.Project 6 + import org.gradle.api.tasks.AbstractCopyTask 7 + import java.util.function.Consumer 8 + import java.util.function.Supplier 9 + 10 + class FabricMod(val id: String, val version: String): Consumer<JsonDsl.Object> { 11 + var name = id 12 + var description = "" 13 + var license = "GPL-3.0" 14 + var icon = "assets.mica/icon.png" 15 + var environment: Environment? = null 16 + @PublishedApi internal val authors = JsonDsl.Array() 17 + @PublishedApi internal val contributors = JsonDsl.Array() 18 + @PublishedApi internal val entrypoints = JsonDsl.Object() 19 + @PublishedApi internal val mixins = JsonDsl.Array() 20 + @PublishedApi internal val contact = JsonDsl.Object() 21 + @PublishedApi internal val custom = JsonDsl.Object() 22 + @PublishedApi internal val depends = JsonDsl.Object() 23 + @PublishedApi internal val recommends = JsonDsl.Object() 24 + @PublishedApi internal val suggests = JsonDsl.Object() 25 + @PublishedApi internal val conflicts = JsonDsl.Object() 26 + @PublishedApi internal val breaks = JsonDsl.Object() 27 + fun entrypoint(key: String, path: String) { 28 + entrypoints.array(key) { 29 + put(path) 30 + } 31 + } 32 + fun entrypoint(path: String) = entrypoint("main", path) 33 + fun entrypoint(path: String, environment: Environment) = entrypoint(environment.id, path) 34 + fun mixins(path: String) { 35 + mixins.put(path) 36 + } 37 + fun mixins(path: String, environment: Environment) { 38 + mixins.map { 39 + put("config", path) 40 + put("environment", environment.id) 41 + } 42 + } 43 + inline fun contact(action: JsonDsl.Object.() -> Unit) = contact.run(action) 44 + inline fun contact(name: String, url: String) = contact { put(name, url) } 45 + inline fun custom(action: JsonDsl.Object.() -> Unit) = custom.run(action) 46 + fun author(name: String) { 47 + authors.put(name) 48 + } 49 + inline fun author(name: String, contact: JsonDsl.Object.() -> Unit) { 50 + authors.map { 51 + put("name", name) 52 + map("contact") { 53 + contact() 54 + } 55 + } 56 + } 57 + fun contributor(name: String) { 58 + contributors.put(name) 59 + } 60 + inline fun contributor(name: String, role: String? = "", contact: JsonDsl.Object.() -> Unit = {}) { 61 + contributors.map { 62 + put("name", name) 63 + if (role != null) put("role", role) 64 + map("contact") { 65 + contact() 66 + } 67 + } 68 + } 69 + fun depends(mod: String, version: String = "*") { 70 + depends.put(mod, version) 71 + } 72 + fun recommends(mod: String, version: String = "*") { 73 + recommends.put(mod, version) 74 + } 75 + fun suggests(mod: String, version: String = "*") { 76 + suggests.put(mod, version) 77 + } 78 + fun conflicts(mod: String, version: String = "*") { 79 + conflicts.put(mod, version) 80 + } 81 + fun breaks(mod: String, version: String = "*") { 82 + breaks.put(mod, version) 83 + } 84 + 85 + fun JsonDsl.Object.merge() { 86 + put("schemaVersion", 1) 87 + put("id", id) 88 + put("version", version) 89 + put("name", name) 90 + put("description", description) 91 + environment?.let { put("environment", it.id) } 92 + put("authors", authors) 93 + put("contributors", contributors) 94 + put("entrypoints", entrypoints) 95 + put("mixins", mixins) 96 + put("custom", custom) 97 + put("depends", depends) 98 + put("recommends", recommends) 99 + put("suggests", suggests) 100 + put("conflicts", conflicts) 101 + put("breaks", breaks) 102 + } 103 + 104 + override fun accept(t: JsonDsl.Object) = t.merge() 105 + override fun toString(): String = JsonDsl.Object().run { merge(); toString() } 106 + } 107 + 108 + enum class Environment(val id: String) { 109 + Server("server"), 110 + Client("client"), 111 + }
+76
plugin/src/main/kotlin/org/eu/net/pool/mc_plugin/JsonDsl.kt
··· 1 + package org.eu.net.pool.mc_plugin 2 + 3 + import com.google.gson.Gson 4 + import com.google.gson.JsonArray 5 + import com.google.gson.JsonElement 6 + import com.google.gson.JsonObject 7 + 8 + internal val gson = Gson() 9 + 10 + @DslMarker 11 + annotation class JsonDsl { 12 + sealed interface Element { 13 + val element: JsonElement 14 + } 15 + @JsonDsl 16 + class Object(override val element: JsonObject = JsonObject()): Element { 17 + internal fun check(key: String) { 18 + if (element.has(key)) 19 + throw IllegalArgumentException("Duplicate key $key") 20 + } 21 + fun put(key: String, value: String) { 22 + check(key) 23 + element.addProperty(key, value) 24 + } 25 + fun put(key: String, value: Number) { 26 + check(key) 27 + element.addProperty(key, value) 28 + } 29 + fun put(key: String, value: Boolean) { 30 + check(key) 31 + element.addProperty(key, value) 32 + } 33 + fun put(key: String, value: JsonElement) { 34 + check(key) 35 + element.add(key, value) 36 + } 37 + fun put(key: String, value: Element) { 38 + check(key) 39 + element.add(key, value.element) 40 + } 41 + inline fun array(key: String, action: Array.() -> Unit) { 42 + element.add(key, (element.get(key)?.asJsonArray ?: JsonArray()).also { Array(it).action() }) 43 + } 44 + inline fun map(key: String, action: Object.() -> Unit) { 45 + element.add(key, (element.get(key)?.asJsonObject ?: JsonObject()).also { Object(it).action() }) 46 + } 47 + 48 + override fun toString(): String = gson.toJson(element) 49 + } 50 + @JsonDsl 51 + class Array(override val element: JsonArray = JsonArray()): Element { 52 + fun put(value: String) { 53 + element.add(value) 54 + } 55 + fun put(value: Number) { 56 + element.add(value) 57 + } 58 + fun put(value: Boolean) { 59 + element.add(value) 60 + } 61 + fun put(value: JsonElement) { 62 + element.add(value) 63 + } 64 + fun put(value: Element) { 65 + element.add(value.element) 66 + } 67 + inline fun array(action: Array.() -> Unit) { 68 + element.add(JsonArray().also { Array(it).action() }) 69 + } 70 + inline fun map(action: Object.() -> Unit) { 71 + element.add(JsonObject().also { Object(it).action() }) 72 + } 73 + 74 + override fun toString(): String = gson.toJson(element) 75 + } 76 + }
+106
plugin/src/main/kotlin/org/eu/net/pool/mc_plugin/Plugin.kt
··· 1 + /* 2 + * This source file was generated by the Gradle 'init' task 3 + */ 4 + package org.eu.net.pool.mc_plugin 5 + 6 + import org.gradle.api.DefaultTask 7 + import org.gradle.api.Project 8 + import org.gradle.api.Plugin 9 + import org.gradle.api.Task 10 + import org.gradle.api.file.Directory 11 + import org.gradle.api.file.RegularFile 12 + import org.gradle.api.provider.ListProperty 13 + import org.gradle.api.provider.MapProperty 14 + import org.gradle.api.provider.Property 15 + import org.gradle.api.provider.Provider 16 + import org.gradle.api.tasks.AbstractCopyTask 17 + import org.gradle.api.tasks.Input 18 + import org.gradle.api.tasks.InputFiles 19 + import org.gradle.api.tasks.OutputFile 20 + import org.gradle.api.tasks.SourceSet 21 + import org.gradle.api.tasks.TaskAction 22 + import org.gradle.kotlin.dsl.get 23 + import org.gradle.language.jvm.tasks.ProcessResources 24 + 25 + typealias PT = context(Project) SourceSet.(String, Pair<String, Task>.(Provider<Directory>) -> Unit) -> Unit 26 + 27 + class Plugin: Plugin<Project> { 28 + override fun apply(project: Project) { 29 + val minecraft_version: String by project.properties 30 + val serialVersion = minecraft_version.let { 31 + val (maj, min, pat) = it.toString().split('.') 32 + min.toInt() * 100 + pat.toInt() 33 + } 34 + project.buildDir = project.file("build$serialVersion") 35 + project.extensions.add("minecraft_version", minecraft_version) 36 + project.extensions.add("serialVersion", serialVersion) 37 + project.extensions.add("preprocessor", PreprocessorExtension(project, minecraft_version, serialVersion)) 38 + } 39 + } 40 + 41 + class PreprocessorExtension(val project: Project, val minecraft_version: String, val serialVersion: Int) { 42 + val freezeMacrosTask = project.tasks.register<FrozenFile>("freezeMacros", FrozenFile::class.java) { 43 + macroFiles.add(project.layout.projectDirectory.file("macros.m4")) 44 + frozenFile.set(project.layout.buildDirectory.file("macros.m4f")) 45 + globals.put("minecraft_version", serialVersion.toString()) 46 + }.get() 47 + inline fun <reified T: Task> SourceSet.processTask(lang: String) { 48 + val inDir = project.layout.projectDirectory.dir("src/$name/$lang") 49 + val outDir = project.layout.buildDirectory.dir(getTaskName("generated", lang)) 50 + val frozen = project.layout.buildDirectory.file("macros.m4f") 51 + val task = project.tasks.register(getTaskName("process", lang)) { 52 + inputs.dir(inDir).optional() 53 + inputs.file(frozen) 54 + dependsOn(project.tasks.named("freezeMacros")) 55 + outputs.dir(outDir) 56 + onlyIf { project.file(inDir).exists() } 57 + doLast { 58 + project.fileTree(inDir).files.forEach { 59 + project.file("${outDir.get()}/${it.relativeTo(inDir.asFile)}").parentFile.mkdirs() 60 + project.exec { 61 + commandLine("m4", "-R", frozen.get().asFile.path, it.path) 62 + standardOutput = project.file("${outDir.get()}/${it.relativeTo(inDir.asFile)}").outputStream() 63 + } 64 + } 65 + } 66 + }.get() 67 + project.tasks.named<T>(getCompileTaskName(lang), T::class.java) { 68 + inputs.property("minecraft_version", project.extensions["serialVersion"]) 69 + dependsOn(task) 70 + doFirst { 71 + try { 72 + T::class.java.getMethod("setSource", Object::class.java).invoke(this@named, outDir) 73 + } catch (e: NoSuchMethodException) { 74 + T::class.java.getMethod("setSource", Array<Object>::class.java).invoke(this@named, arrayOf(outDir)) 75 + } 76 + } 77 + } 78 + } 79 + 80 + fun AbstractCopyTask.fabricMod(id: String, version: String, action: FabricMod.() -> Unit) { 81 + val mod = FabricMod(id, version) 82 + mod.action() 83 + from(project.resources.text.fromString(mod.toString())) { rename { "fabric.mod.json" } } 84 + } 85 + } 86 + 87 + abstract class FrozenFile: DefaultTask() { 88 + @get:InputFiles val macroFiles: ListProperty<RegularFile> = project.objects.listProperty(RegularFile::class.java) 89 + @get:OutputFile val frozenFile: Property<RegularFile> = project.objects.fileProperty() 90 + @get:Input val globals: MapProperty<String, String> = project.objects.mapProperty(String::class.java, String::class.java) 91 + init { 92 + inputs.files(macroFiles) 93 + inputs.property("globals", globals) 94 + outputs.file(frozenFile) 95 + } 96 + @TaskAction 97 + fun run() { 98 + project.exec { 99 + val args = mutableListOf("m4", "-F", frozenFile.get().asFile.path) 100 + globals.get().forEach { k, v -> args.add("-D$k=$v") } 101 + macroFiles.get().forEach { args.add(it.asFile.path) } 102 + commandLine = args 103 + } 104 + } 105 + } 106 +
+2
settings.gradle.kts
··· 4 4 gradlePluginPortal() 5 5 } 6 6 } 7 + 8 + includeBuild("plugin")
+12 -2
src/client/scala/org/net/eu/pool/mica/client/MicaClient.scala
··· 3 3 import com.google.gson.{JsonArray, JsonElement, JsonObject} 4 4 import com.mojang.blaze3d.systems.RenderSystem 5 5 import net.fabricmc.fabric.api.client.datagen.v1.provider.FabricModelProvider 6 + import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking 6 7 import net.fabricmc.fabric.api.client.rendering.v1.{WorldRenderContext, WorldRenderEvents} 7 8 import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator 8 9 import net.fabricmc.fabric.api.datagen.v1.provider.FabricAdvancementProvider 10 + import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking 9 11 import net.fabricmc.fabric.api.renderer.v1.render.RenderLayerHelper 10 12 import net.minecraft.advancement.criterion.{Criteria, ImpossibleCriterion} 11 13 import net.minecraft.advancement.{Advancement, AdvancementCriterion, AdvancementDisplay, AdvancementDisplays, AdvancementEntry, AdvancementFrame, AdvancementRequirements, AdvancementRewards} ··· 16 18 import net.minecraft.client.util.math.MatrixStack 17 19 import net.minecraft.util.{AssetInfo, Identifier} 18 20 import net.minecraft.util.math.{BlockPos, Direction, MathHelper} 19 - import org.net.eu.pool.mica.{AbstractRuneStorage, EmptyRune, EndQuoteRune, HasRegistry, QuoteRune, Rune, RuneShift, registryFor, given} 21 + import org.net.eu.pool.mica.{AbstractRuneStorage, ClientExecutor, EmptyRune, EndQuoteRune, HasRegistry, QuoteRune, Rune, RuneShift, ServerExecutor, SidedExecutePacket, registryFor, given} 20 22 import net.minecraft.client.data.{BlockStateModelGenerator, ItemModelGenerator, ItemModels, Model, ModelIds, ModelSupplier} 21 23 import net.minecraft.client.render.item.model.ItemModel 22 24 import net.minecraft.item.{ItemStack, Items} 25 + import net.minecraft.network.packet.CustomPayload 23 26 import net.minecraft.registry.RegistryWrapper 27 + import net.minecraft.server.network.ServerPlayerEntity 24 28 import net.minecraft.text.Text 25 29 import net.minecraft.util.math.Direction.Axis 26 30 ··· 252 256 val textureFile = Path.of(s"$projectRoot/src/client/resources/assets/${texture.getNamespace}/textures/${texture.getPath}.png") 253 257 if !Files.exists(textureFile) then Files.createFile(textureFile) 254 258 259 + given ServerExecutor: 260 + override def run(body: ClientExecutor ?=> Unit): Unit = 261 + val packet = SidedExecutePacket[ClientExecutor](body(using _)) 262 + ClientPlayNetworking.send(packet) 263 + 255 264 def datagen(using gen: FabricDataGenerator): Unit = 256 265 given pack: FabricDataGenerator#Pack = gen.createPack() 257 266 registryFor[Rune].forEach(datagenRune(_)) ··· 282 291 } 283 292 ) 284 293 285 - def init() = println("new dummy client init") 294 + def init() = 295 + ClientPlayNetworking.registerGlobalReceiver[SidedExecutePacket[ServerExecutor]](SidedExecutePacket.id, (p, ctx) => p.payload(summon))
+3 -1
src/main/resources/mica.mixins.json
··· 6 6 "mixins": [ 7 7 "BrainMixin", 8 8 "FlintAndSteelItemMixin", 9 - "ItemMixin" 9 + "ItemMixin", 10 + "SerializableMixin", 11 + "ServerPlayNetworkingContextMixin" 10 12 ], 11 13 "plugin": "org.net.eu.pool.mica.Plugin", 12 14 "injectors": {
+18 -9
src/main/scala/org/net/eu/pool/mica/Defs.scala
··· 310 310 println("nah") 311 311 ActionResult.PASS 312 312 313 - def computeNeighbors(using r: RuneRef): Set[RuneRef] = Set(r.north.north, r.east.east, r.south.south, r.west.west) 313 + def computeNeighbors(using r: RuneRef): Set[RuneRef] = r.adjacent 314 314 def ignite(using r: RuneRef, ci: CallbackInfoReturnable[ActionResult])(ctx: ItemUsageContext): Unit = () 315 315 def fillHeap(using RuneRef, PlayerEntity, World)(): Unit = () 316 316 ··· 402 402 heap2 = 0 403 403 heap3 = 0 404 404 shift.storage(pos) = r 405 - def isEmpty(using World) = rune == null || rune == EmptyRune 405 + def isEmpty(using World): Boolean = rune == null || rune == EmptyRune 406 406 def heap0(using World): Int = shift.storage.heap0.get(pos.asLong) 407 407 def heap0_=(r: Int)(using World): Unit = shift.storage.heap0.put(pos.asLong, r) 408 408 def heap1(using World): Int = shift.storage.heap1.get(pos.asLong) ··· 412 412 def heap3(using World): Int = shift.storage.heap3.get(pos.asLong) 413 413 def heap3_=(r: Int)(using World): Unit = shift.storage.heap3.put(pos.asLong, r) 414 414 415 - def north = offset(Direction.NORTH) 416 - def south = offset(Direction.SOUTH) 417 - def east = offset(Direction.EAST) 418 - def west = offset(Direction.WEST) 415 + def north: RuneRef = offset(Direction.NORTH) 416 + def south: RuneRef = offset(Direction.SOUTH) 417 + def east: RuneRef = offset(Direction.EAST) 418 + def west: RuneRef = offset(Direction.WEST) 419 419 420 - def neighbors = Set(north, east, south, west, north.east, north.west, south.east, south.west) 421 - def adjacent = Set(north.north, east.east, south.south, west.west) 420 + lazy val neighbors: Set[RuneRef] = Set( 421 + north, east, south, west, 422 + north.east, north.west, south.east, south.west 423 + ) 424 + lazy val adjacent: Set[RuneRef] = Set( 425 + north.north, east.east, south.south, west.west, 426 + north.north.east, east.east.north, south.south.east, west.west.north, 427 + north.north.west, east.east.south, south.south.west, west.west.south, 428 + ) 422 429 423 430 private[mica] trait AbstractRuneStorage extends Component, AutoSyncedComponent: 424 431 type Concrete <: AbstractRuneStorage ··· 442 449 private[mica] val keys: Array[ComponentKey[? <: AbstractRuneStorage]] = Array.fill(768)(null) 443 450 def get(world: World, shift: RuneShift): AbstractRuneStorage = keys(shift.value).get(world) 444 451 def sync(world: World, shift: RuneShift): Unit = keys(shift.value).sync(world) 445 - 446 452 trait ValueType[T: Codec]: 447 453 def eq[U: ValueType](x: T, y: U): Boolean 448 454 def cast[R: ClassTag](x: T): Option[R] = ··· 451 457 case _ => None 452 458 def show(x: T): Text 453 459 def codec: Codec[T] = summon 460 + def present(x: T): Boolean = true 461 + def typeof(x: T): ValueType[?] = this 462 + trait UntypedValue 454 463 object ValueType: 455 464 given HasRegistry[ValueType[?]] = HasRegistry.derived
+149 -30
src/main/scala/org/net/eu/pool/mica/Mica.scala
··· 5 5 import com.mojang.serialization 6 6 import com.mojang.serialization.codecs.RecordCodecBuilder 7 7 import com.mojang.serialization.{Codec, DataResult, Decoder, DynamicOps, Encoder, Lifecycle, MapCodec} 8 + import io.github.afamiliarquiet.be_a_doll.item.DollcraftItem 9 + import io.github.afamiliarquiet.be_a_doll.mixin.shoulder_riding.OopsDollDeletedYouPlayerManagerMixin 8 10 import io.github.afamiliarquiet.be_a_doll.{BeADoll, BeAMaid} 11 + import io.netty.buffer.ByteBuf 9 12 import it.unimi.dsi.fastutil.longs.{Long2FloatMap, Long2IntMap, Long2IntMaps, Long2IntOpenHashMap, Long2LongMap} 13 + import net.fabricmc.fabric.api.networking.v1.{PayloadTypeRegistry, ServerPlayNetworking} 10 14 import net.fabricmc.loader.api.{FabricLoader, Version} 11 15 import net.minecraft.Bootstrap 12 16 import net.minecraft.component.`type`.ProfileComponent ··· 20 24 import net.minecraft.entity.player.PlayerEntity 21 25 import net.minecraft.item.ItemStack 22 26 import net.minecraft.loot.entry.ItemEntry 23 - import net.minecraft.network.codec.PacketCodecs 24 - import net.minecraft.server.network.ServerPlayerEntity 27 + import net.minecraft.network.PacketByteBuf 28 + import net.minecraft.network.codec.{PacketCodec, PacketCodecs} 29 + import net.minecraft.network.packet.CustomPayload 30 + import net.minecraft.server.network.{ServerPlayNetworkHandler, ServerPlayerEntity} 25 31 import net.minecraft.server.world.ServerWorld 26 32 import net.minecraft.sound.{SoundCategory, SoundEvent, SoundEvents} 27 33 import net.minecraft.state.property.Property 28 - import net.minecraft.text.{TextCodecs, TextColor, Texts} 34 + import net.minecraft.text.{MutableText, TextCodecs, TextColor, Texts} 29 35 import net.minecraft.util.{Hand, Rarity, Uuids} 30 36 import net.minecraft.util.shape.VoxelShapes 31 37 import net.minecraft.world.World.ExplosionSourceType ··· 34 40 import org.slf4j.{Logger, LoggerFactory} 35 41 import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable 36 42 43 + import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream} 37 44 import java.nio.file.{Files, Path} 38 45 import java.util.{Optional, UUID} 39 46 import java.util.stream.LongStream ··· 41 48 import scala.NamedTuple.{AnyNamedTuple, NamedTuple} 42 49 import scala.Tuple.:* 43 50 import scala.annotation.targetName 51 + import scala.beans.BeanProperty 44 52 import scala.collection.immutable.{AbstractSet, SortedSet} 45 53 import scala.compiletime.constValue 46 54 import scala.runtime.ObjectRef ··· 86 94 import scala.util.chaining.scalaUtilChainingOps 87 95 88 96 private given ModID = ModID("mica") 97 + given (m: ModID) => Logger = LoggerFactory.getLogger(m.name) 89 98 90 99 /** 91 100 * Current serial Minecraft version. This is solely provided for IDE completion; it is expanded before compile-time by m4. ··· 230 239 val layers: Array[Option[MultipartLayer]] = Array.fill(16)(None) 231 240 232 241 // divert 242 + 243 + extension [T: ValueType as v] (x: T) def castValue[R: ClassTag]: Option[R] = v.cast(x) 244 + 245 + extension (ctx: StringContext) def t(args: AnyRef*): MutableText = Text.translatable(ctx.parts.map(_.replace("%", "%%")).mkString("%s"), args*) 246 + 247 + given Codec[BeADoll.Variant] = BeADoll.Variant.CODEC 248 + given ValueType[BeADoll.Variant]: 249 + override def eq[U: ValueType](x: BeADoll.Variant, y: U): Boolean = y.castValue[BeADoll.Variant] contains x 250 + override def show(x: BeADoll.Variant): Text = x match 251 + case BeADoll.Variant.REPRESSED => t"Repressed".withColor(0x7a7a7a) 252 + case BeADoll.Variant.WOODEN => t"Wooden".withColor(0xc2a166) 253 + case BeADoll.Variant.CLAY => t"Clay".withColor(0x934833) 254 + case BeADoll.Variant.CLOTH => t"Cloth".withColor(0xdbdbdb) 255 + 256 + given Codec[Boolean] = Codec.BOOL.xmap(_.booleanValue, boolean2Boolean) 257 + 258 + // divert 233 259 class immutable extends Annotation 234 260 235 261 /** ··· 293 319 294 320 def translationFields(data: Data): Seq[AnyRef] = Seq() 295 321 322 + given seqCodec: [T: Codec as c] => Codec[Seq[T]] = c.listOf().xmap(_.toSeq, locally(_)) 323 + given unitCodec: Codec[Unit] = Codec.unit(()) 324 + given nothingCodec: Codec[Nothing] = Codec.of(new Encoder[Nothing]: 325 + override def encode[T](input: Nothing, ops: DynamicOps[T], prefix: T): DataResult[T] = input, Decoder.error("Nothing codec")) 326 + 296 327 @register("noop") 297 328 object NoopEffect extends SideEffect: 298 329 override type Data = Unit ··· 307 338 override def eq[U: ValueType as v](x: Unit, y: U): Boolean = v eq unitValueType 308 339 override def show(x: Unit): Text = Text.literal("Unit").styled(_.withColor(0x7a7a7a)) 309 340 341 + @register("drop") 342 + object DropRune extends SimpleRune: 343 + override def execute(frame: BoxedThunk) = BoxedThunk(Frame, frame) 344 + @register("drop/0") 345 + object Frame extends ThunkFrame: 346 + type Data = BoxedThunk 347 + override def accept[T: ValueType](data: BoxedThunk, value: T): BoxedThunk = data 348 + 349 + @register("copy") 350 + object CopyRune extends SimpleRune: 351 + override def execute(frame: BoxedThunk) = BoxedThunk(Frame, frame) 352 + @register("copy/0") 353 + object Frame extends ThunkFrame: 354 + type Data = BoxedThunk 355 + override def accept[T: ValueType](data: BoxedThunk, value: T): BoxedThunk = data accept value accept value 356 + 357 + extension [T: Registry as r] (x: T) def registryId: Identifier = r.getId(x) 358 + 359 + trait Display[T]: 360 + def display(x: T): Text 361 + 362 + given ValueType[BoxedRune]: 363 + override def eq[T: ValueType as v](x: BoxedRune, y: T): Boolean = v.cast[BoxedRune](y).contains(x) 364 + override def show(x: BoxedRune): Text = Text translatable x.rune.registryId.toTranslationKey("mica.rune") withColor 0xbd9146 365 + 366 + @register("join") 367 + object JoinRune extends Rune: 368 + override type Data = (BoxedRune, BoxedRune) 369 + override def read(rhs: List[(Rune, RuneRef)])(using ref: RuneRef, world: World): ((BoxedRune, BoxedRune), List[(Rune, RuneRef)]) = 370 + rhs match 371 + case Nil => throw RuneError(Text.literal("Can't join nothing")) 372 + case (rune, given RuneRef)::next => 373 + val (boxed, rhs) = rune.read(next) 374 + rhs match 375 + case Nil => throw RuneError(Text.literal("Can't join nothing")) 376 + case (rune2, given RuneRef)::next => 377 + val (boxed2, rhs) = rune2.read(next) 378 + ((BoxedRune(rune, boxed), BoxedRune(rune2, boxed2)), rhs) 379 + 380 + override def execute(data: (BoxedRune, BoxedRune), frame: BoxedThunk): BoxedThunk = 381 + val frame2 = data._1.rune.execute(data._1.data, frame) 382 + data._2.rune.execute(data._2.data, frame2) 383 + 384 + @register("box") 385 + object BoxRune extends Rune: 386 + override type Data = BoxedRune 387 + override def read(rhs: List[(Rune, RuneRef)])(using ref: RuneRef, world: World): (BoxedRune, List[(Rune, RuneRef)]) = 388 + rhs match 389 + case Nil => throw RuneError(Text.literal("Can't box nothing")) 390 + case (head, given RuneRef)::next => 391 + val (data, rhs) = head.read(next) 392 + (BoxedRune(head, data), rhs) 393 + override def execute(data: BoxedRune, frame: BoxedThunk): BoxedThunk = frame accept data 394 + 395 + class unsafe extends Annotation 396 + 397 + case class ByteRepr[+T] private[ByteRepr](bytes: IArray[Byte]) extends AnyVal 398 + object ByteRepr: 399 + def fromBytes(bytes: IArray[Byte]): ByteRepr[?] = bytes.asInstanceOf[Array[Byte]] 400 + given [T] => Conversion[T, ByteRepr[T]] = x => ByteRepr(ByteArrayOutputStream().tap(ObjectOutputStream(_).writeObject(x)).toByteArray.assumeImmutable) 401 + given [T] => Conversion[ByteRepr[T], T] = x => ObjectInputStream(ByteArrayInputStream(x.bytes.assumeWillNotMutate)).readObject().asInstanceOf[T] 402 + import ByteRepr.given 403 + 404 + class SidedExecutePacket[T](val payload: T => Unit) extends CustomPayload: 405 + override def getId: CustomPayload.Id[SidedExecutePacket[T]] = summon 406 + object SidedExecutePacket: 407 + given id: [T] => CustomPayload.Id[SidedExecutePacket[T]] = CustomPayload.Id(Identifier.of("mica", "run_sided")) 408 + given codec: [T] => PacketCodec[PacketByteBuf, SidedExecutePacket[T]] = new PacketCodec[PacketByteBuf, SidedExecutePacket[T]]: 409 + override def encode(buf: PacketByteBuf, value: SidedExecutePacket[T]): Unit = buf.writeByteArray((value.payload: ByteRepr[T => Unit]).bytes.assumeWillNotMutate) 410 + override def decode(buf: PacketByteBuf): SidedExecutePacket[T] = SidedExecutePacket(ByteRepr.fromBytes(buf.readByteArray().assumeImmutable).asInstanceOf[ByteRepr[T => Unit]]) 411 + 412 + trait ServerExecutor private[mica](): 413 + def run(body: ClientExecutor ?=> Unit): Unit 414 + trait ClientExecutor private[mica](val player: ServerPlayerEntity): 415 + def run(body: ServerExecutor ?=> Unit): Unit 416 + 417 + def toPlayer[R](player: ServerPlayerEntity)(body: ClientExecutor ?=> R): R = 418 + given ClientExecutor(player): 419 + override def run(body: => Unit): Unit = 420 + ServerPlayNetworking.send(this.player, SidedExecutePacket[Unit](_ => body)) 421 + body 422 + 423 + def runOnServer(body: ClientExecutor ?=> Unit)(using e: ServerExecutor): Unit = e.run(body) 424 + def runOnClient(body: ServerExecutor ?=> Unit)(using e: ClientExecutor): Unit = e.run(body) 425 + def runOnClient(who: ServerPlayerEntity)(body: ServerExecutor ?=> Unit): Unit = 426 + toPlayer(who): 427 + runOnClient(_ ?=> body) 428 + 310 429 // divert(-1) 311 430 trait ByteCodec[T]: 312 431 def read(r: DataInput): T ··· 318 437 val topMask = r.read() 319 438 val section = MultipartSection() 320 439 for n <- 0 to 7 do 321 - /*dnl*/if bottomMask & (1 << n) != 0 then 440 + /*dnl*/if (bottomMask & (1 << n)) != 0 then 322 441 section.layers(n) = r.get() 323 - /*dnl*/if topMask & (1 << n) != 0 then 442 + /*dnl*/if (topMask & (1 << n)) != 0 then 324 443 section.layers(n+8) = r.get() 325 444 section 326 445 override def write(w: OutputStream, x: MultipartSection): Unit = ··· 346 465 // divert 347 466 348 467 def assumed[T, U]: T =:= U = summon[Int =:= Int].asInstanceOf[T =:= U] 468 + extension [T](x: Array[T]) @unsafe def assumeImmutable: IArray[T] = x.asInstanceOf 469 + extension [T](x: IArray[T]) @unsafe def assumeWillNotMutate: Array[T] = x.asInstanceOf 349 470 350 - inline given tupleCodec: [T <: Tuple] => Codec[T] = compiletime.summonFrom: 471 + inline given tupleCodec: [T <: NonEmptyTuple] => Codec[T] = tupleCodecImpl[T] 472 + inline def tupleCodecImpl[T <: Tuple]: Codec[T] = compiletime.summonFrom: 351 473 case ev: (T =:= EmptyTuple) => ev.substituteContra(Codec.unit(EmptyTuple)) 352 - case ev: (T =:= (h *: t)) => ev.substituteContra(Codec.pair(summonInline[Codec[h]], tupleCodec[t]).xmap(p => p.getFirst *: p.getSecond, { case h *: t => Pair(h, t) })) 474 + case ev: (T =:= Tuple1[t]) => ev.substituteContra(summonInline[Codec[t]].xmap(Tuple1(_), _._1)) 475 + case ev: (T =:= (h *: t)) => ev.substituteContra(Codec.pair(summonInline[Codec[h]], tupleCodecImpl[t]).xmap(p => p.getFirst *: p.getSecond, { case h *: t => Pair(h, t) })) 353 476 354 477 // divert(-1) 355 478 ··· 398 521 override def accept[T: ValueType](data: BoxedSideEffect, value: T): BoxedThunk = 399 522 //throw RuneError(Text.literal("Too many side effects in one cast")) 400 523 ??? 401 - def findRunes(start: RuneRef, prev: Option[RuneRef])(using World): Option[List[(Rune, RuneRef)]] = 524 + def findRunes(start: RuneRef, prev: Set[RuneRef] = Set.empty)(using World): Option[List[(Rune, RuneRef)]] = 402 525 logger.debug(s"findRunes ${start} ${prev}") 403 526 if start.isEmpty then 404 527 None 405 528 else 406 - val neigh = (start.rune.computeNeighbors(using start) -- prev).flatMap(findRunes(_, Some(start))).toSeq 529 + val neigh = (start.rune.computeNeighbors(using start) -- prev).flatMap(findRunes(_, prev + start)).toSeq 407 530 neigh match 408 531 case Seq() => 409 532 logger.debug(s"\tfindRunes ${start} ${prev}, neigh = ${neigh} | no more neighbors; stop here.") ··· 744 867 None 745 868 case _ => None 746 869 870 + override def present(x: Double): Boolean = x =~ 0.0 747 871 override def show(x: Double): Text = Text.literal(s"$x").styled(_.withColor(0xab3900)) 748 872 749 873 class RuneBeStartinShit private(val direction: Direction) extends Rune: ··· 901 1025 given Registry[StatusEffect] = Registries.STATUS_EFFECT 902 1026 903 1027 extension (ent: LivingEntity) 904 - def isOrganic = ent match 1028 + def isOrganic: Boolean = ent match 905 1029 case _: (GolemEntity | ArmorStandEntity) => false 906 1030 case p: PlayerEntity => 907 1031 lazy val isDoll = BeAMaid.isDoll(p) ··· 951 1075 override def show(x: BoxedValue): Text = 952 1076 import x.given 953 1077 summon[ValueType[x.T]].show(x.value) 1078 + override def present(x: BoxedValue): Boolean = x.given_ValueType_T.present(x.value) 1079 + override def typeof(x: BoxedValue): ValueType[?] = x.given_ValueType_T 954 1080 955 1081 @register("defer") 956 1082 object DeferEffectRune extends SimpleRune: ··· 1173 1299 ref.rune match 1174 1300 case RuneBeStartinShit(d) => 1175 1301 boundary: 1176 - val runes = findRunes(ref, None).getOrElse: 1302 + val runes = findRunes(ref).getOrElse: 1177 1303 ci.setReturnValue(ActionResult.FAIL) 1178 1304 given_World.playSound(ctx.getPlayer, p.x, p.y, p.z, SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.PLAYERS) 1179 1305 ctx.getPlayer.sendMessage(Text.literal("The spark fizzles out."), true) ··· 1212 1338 cursedRegister(Identifier.of("mica", "rune_probe"), Item.Settings()): 1213 1339 new Item(_): 1214 1340 override def useOnBlock(ctx: ItemUsageContext): ActionResult = 1341 + Exception("Rune stuff").printStackTrace() 1215 1342 val p = ctx.getHitPos 1216 1343 val q = BlockPos.Mutable((p.x * 4).round.toInt, (p.y * 8).round.toInt, (p.z * 4).round.toInt) 1217 1344 val b = BlockPos.Mutable(p.x, p.y, p.z) ··· 1367 1494 override type Arg0 = Double 1368 1495 override type Arg1 = Double 1369 1496 override type Return = Double 1370 - 1371 1497 override def run(x: Double, y: Double): Double = x / y 1372 - 1373 1498 register: 1374 1499 registerFrames() 1375 1500 DivitionRune.item.register() 1376 1501 1377 - extension (x: Double) @targetName("~=") def =~(y: Double): Boolean = Math.abs(x - y) < 0.0001 1502 + extension (x: Double) 1503 + @targetName("=~") def =~(y: Double): Boolean = Math.abs(x - y) < 0.0001 1504 + @targetName("!~") def !~(y: Double): Boolean = !(x =~ y) 1378 1505 1379 1506 given Codec[Vec3d] = Vec3d.CODEC 1380 1507 given ValueType[Vec3d]: ··· 1382 1509 v.cast[Vec3d](y).exists: y => 1383 1510 x.x =~ y.x && x.y =~ y.y && x.z =~ y.z 1384 1511 override def cast[R: ClassTag](x: Vec3d): Option[R] = super.cast(x) 1385 - 1386 1512 override def show(x: Vec3d): Text = Text.literal(s"{${x.x}, ${x.y}, ${x.z}}").styled(_.withColor(0xad8d1a)) 1387 1513 1388 1514 inline def codec[T: Codec as c] = c ··· 1399 1525 case _ => None 1400 1526 def attributeInstance(using World): Option[EntityAttributeInstance] = entity.map(_.getAttributeInstance(Registries.ATTRIBUTE.getEntry(attribute))) 1401 1527 given `codec for entity attributes using the registry`: Codec[EntityAttribute] = Registries.ATTRIBUTE.getCodec 1402 - given `codec for references to entity attributes`: Codec[AttributeReference] = 1403 - RecordCodecBuilder.create: i => 1404 - i.group( 1405 - Uuids.INT_STREAM_CODEC.fieldOf("entity").forGetter(_.uuid), 1406 - codec[EntityAttribute].fieldOf("attribute").forGetter(_.attribute), 1407 - ).apply(i, AttributeReference(_, _)) 1528 + given `codec for references to entity attributes`: Codec[AttributeReference] = RecordCodecBuilder.create: i => 1529 + i.group(Uuids.INT_STREAM_CODEC.fieldOf("entity").forGetter(_.uuid), codec[EntityAttribute].fieldOf("attribute").forGetter(_.attribute)).apply(i, AttributeReference(_, _)) 1408 1530 given `hey did you know attributes are values`: ValueType[AttributeReference]: 1409 1531 override def eq[U: ValueType as v](x: AttributeReference, y: U): Boolean = v.cast[AttributeReference](y).exists(y => (x.uuid == y.uuid) && (x.attribute eq y.target)) 1410 1532 override def show(x: AttributeReference): Text = Text.translatable(x.attribute.getTranslationKey).styled(_.withColor(0x07b891)) ··· 1475 1597 EndQuoteRune.item.register() 1476 1598 // divert 1477 1599 1478 - given seqCodec: [T: Codec as c] => Codec[Seq[T]] = c.listOf().xmap(_.toSeq, locally(_)) 1479 - given unitCodec: Codec[Unit] = Codec.unit(()) 1480 - given nothingCodec: Codec[Nothing] = Codec.of(new Encoder[Nothing]: 1481 - override def encode[T](input: Nothing, ops: DynamicOps[T], prefix: T): DataResult[T] = input, Decoder.error("Nothing codec")) 1482 - 1483 1600 extension [T] (x: T) 1484 1601 /** 1485 1602 * Tries to cast the value to the given type. ··· 1489 1606 def cast[R: ClassTag]: Option[R] = x match 1490 1607 case r: R => Some(r) 1491 1608 case _ => None 1492 - 1493 - //@register("find_people") 1494 - 1495 1609 1496 1610 @tailrec 1497 1611 def panic(reason: String): Nothing = ··· 1518 1632 val config = Path.of("config/mica:extra_classes.txt") 1519 1633 if Files.exists(config) then 1520 1634 logger.warn("Ignoring config/mica:extra_classes.txt as it is deprecated. Remove the file to silence this warning.") 1521 - catch case e => () 1635 + catch case e => () 1636 + PayloadTypeRegistry.playC2S.register(SidedExecutePacket.id, SidedExecutePacket.codec) 1637 + PayloadTypeRegistry.playS2C.register(SidedExecutePacket.id, SidedExecutePacket.codec) 1638 + ServerPlayNetworking.registerGlobalReceiver[SidedExecutePacket[ClientExecutor]](SidedExecutePacket.id, (p, ctx) => p.payload(toPlayer(ctx.player))) 1639 + 1640 + def println(msg: Any): Unit = logger.info(msg.toString)
+11
src/main/scala/org/net/eu/pool/mica/mixin/SerializableMixin.java
··· 1 + package org.net.eu.pool.mica.mixin; 2 + 3 + import net.minecraft.util.Identifier; 4 + import org.spongepowered.asm.mixin.Mixin; 5 + import scala.Product; 6 + import scala.runtime.FunctionXXL; 7 + 8 + import java.io.Serializable; 9 + 10 + @Mixin({forloop(n,1,22,<[[<[[scala.Function]]>n<[[.class, ]]>]]>)FunctionXXL.class, Product.class, Identifier.class}) 11 + public class SerializableMixin implements Serializable {}
+9
src/main/scala/org/net/eu/pool/mica/mixin/ServerPlayNetworkingContextMixin.java
··· 1 + package org.net.eu.pool.mica.mixin; 2 + 3 + import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 4 + import org.net.eu.pool.mica.ClientExecutor; 5 + import org.spongepowered.asm.mixin.Mixin; 6 + 7 + @Mixin(ServerPlayNetworking.Context.class) 8 + public class ServerPlayNetworkingContextMixin implements ClientExecutor { 9 + }