Skip to content

Commit 5fe85b8

Browse files
committed
feat: release 0.8.6
1 parent dbca093 commit 5fe85b8

18 files changed

Lines changed: 110 additions & 69 deletions

File tree

about/DESCRIPTION.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
A Kotlin Symbol Processor for Sponge Mixins. Generates boilerplate with compile-time safety and automatically handles Mixin/AW/AT configurations.
1+
A Kotlin Symbol Processor (KSP) for Sponge Mixins. Built exclusively for Minecraft modding, Lapis focuses on intent-based injections and compile-time safety. It provides a Kotlin-first frontend with a type-safe DSL, leverages a MixinExtras-based backend, and automates the generation of Mixin and AW/AT configurations.

about/DETAILS.md

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,58 @@
1-
Soon...
1+
## Problem
2+
3+
[Mixin](https://github.com/spongepowered/Mixin) is a powerful tool that enables on-the-fly code modification at runtime;
4+
however, it was designed for the broader Java ecosystem, **not just** Minecraft modding. As a result, it provides a
5+
fairly low-level interface that relies on imperative logic and implementation-heavy annotations.
6+
7+
**Redundancy & Maintenance Hell**: Modding for years with standard Mixins reveals a pattern of constant duplication. A
8+
single logic change often requires updating method descriptors in multiple places: the injection point, the parameter
9+
list, Shadow methods, Accessors, and AW/AT configurations. This manual synchronization is fragile; missing a single
10+
descriptor during a version migration or mapping update leads to a broken mod.
11+
12+
**The "Descriptor" Nightmare**: Relying on long, cryptic strings (like `Lnet/minecraft/class_...;()V`) makes code
13+
unreadable and error-prone. While IDE plugins help generate these, they only provide "coding-time" assistance. They
14+
don't prevent the project from building successfully even if a descriptor is wrong, leading to frustrating runtime
15+
crashes that only appear after the mod is deployed.
16+
17+
**Decision Fatigue**: There is too much "freedom of choice" in how to achieve the same result. Whether it's choosing
18+
between an Accessor or an AW, or implementing a common pattern like Interface Injection to expose Mixin logic,
19+
developers often end up copy-pasting the same boilerplate or "reinventing the wheel".
20+
21+
## Inspiration
22+
23+
[MixinExtras](https://github.com/LlamaLad7/MixinExtras) revolutionized the ecosystem by bringing Minecraft-specific
24+
modding realities into the Mixin world. It introduced conflict-safe injections while maintaining strict compatibility
25+
with the original Mixin framework.
26+
27+
Seeing the elegance of MixinExtras was my primary inspiration; it revealed the true potential of what modern injections
28+
could look like. Lapis wouldn't exist without it. To honor this foundation, I chose MixinExtras as the primary backend
29+
for my code generation, aiming to provide a high-level, intent-based layer on top of its robust architecture.
30+
31+
## Solution
32+
33+
Lapis is the result of moving the complexity from the developer's head to the compiler. It bridges the gap between
34+
low-level Mixins and expressive Kotlin.
35+
36+
### Key Features
37+
38+
- **Compile-time Safety**: No more runtime crashes due to typos in descriptors. If it builds, it works.
39+
- **Intent-Based DSL**: Write what you want to change, not how to find the bytecode instruction.
40+
- **Automatic Boilerplate**: Lapis handles Interface Injections, Extension properties, and AW/AT generation for you.
41+
- **Built-in Best Practices**: Optimized for conflict-free injections using MixinExtras by default.
42+
43+
| Feature | Standard Mixin | Lapis |
44+
|:-----------------|:---------------------|:------------------------|
45+
| **Descriptors** | Strings | Type-safe references |
46+
| **Maintenance** | Update in 2-5 places | Update in one place |
47+
| **Safety** | Runtime crashes | Compile-time errors |
48+
| **Kotlin-first** | No | Native DSL & Extensions |
49+
50+
---
51+
52+
## Quick Start
53+
54+
> [!NOTE]
55+
> A brief guide on connecting the KSP plugin will be added here shortly. The full documentation and comprehensive Wiki
56+
> will be available with the **1.0.0** release.
57+
>
58+
> You can find the current documentation in our [Wiki →](https://github.com/recrafter/lapis/wiki).

settings.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ dependencyResolutionManagement {
2222
}
2323

2424
projekt {
25-
version = "0.8.5"
25+
version = "0.8.6"
2626
license = MIT
2727
publish = setOf(MAVEN_CENTRAL)
2828

src/main/kotlin/io/github/recrafter/lapis/LapisProcessor.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ class LapisProcessor(
2626
private val mixins: MutableMap<String, IrMixin> = mutableMapOf()
2727

2828
override fun process(resolver: KSPResolver): List<KSAnnotated> {
29-
logger.setPhase(LapisPhase.BUILTINS)
3029
val parser = SymbolParser(resolver, logger)
3130
if (!builtins.isGenerated) {
31+
logger.setPhase(LapisPhase.BUILTINS)
3232
builtins.generate()
3333
return parser.prepare().run { schemaClassDecls + patchClassDecls }
3434
}

src/main/kotlin/io/github/recrafter/lapis/extensions/jp/JPMethodBuilderExt.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ package io.github.recrafter.lapis.extensions.jp
33
import io.github.recrafter.lapis.extensions.common.lapisError
44
import io.github.recrafter.lapis.extensions.quoted
55
import io.github.recrafter.lapis.layers.generator.builders.Builder
6-
import io.github.recrafter.lapis.layers.generator.builders.IrJavaCodeBlock
76
import io.github.recrafter.lapis.layers.generator.builders.IrJavaMethodBody
87
import io.github.recrafter.lapis.layers.lowering.IrModifier
98
import io.github.recrafter.lapis.layers.lowering.models.IrParameter
10-
import io.github.recrafter.lapis.layers.lowering.types.IrClassName
119
import io.github.recrafter.lapis.layers.lowering.types.IrTypeName
1210

1311
inline fun <reified A : Annotation> JPMethodBuilder.addAnnotation(builder: Builder<JPAnnotationBuilder> = {}) {

src/main/kotlin/io/github/recrafter/lapis/extensions/jp/JPTypeNameExt.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package io.github.recrafter.lapis.extensions.jp
22

3-
val JPTypeName.defaultValue: String
3+
val JPTypeName.primitiveDefaultValue: String?
44
get() = when (this) {
55
JPBoolean -> "false"
66
JPByte, JPShort, JPInt -> "0"
77
JPLong -> "0L"
88
JPChar -> "'\\0'"
99
JPFloat -> "0f"
1010
JPDouble -> "0d"
11-
else -> "null"
11+
else -> null
1212
}
1313

1414
fun JPTypeName?.orVoid(): JPTypeName =

src/main/kotlin/io/github/recrafter/lapis/extensions/kp/KPFunctionBuilderExt.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import com.squareup.kotlinpoet.ExperimentalKotlinPoetApi
66
import io.github.recrafter.lapis.extensions.common.lapisError
77
import io.github.recrafter.lapis.extensions.quoted
88
import io.github.recrafter.lapis.layers.generator.builders.Builder
9-
import io.github.recrafter.lapis.layers.generator.builders.IrKotlinCodeBlock
109
import io.github.recrafter.lapis.layers.generator.builders.IrKotlinFunctionBody
1110
import io.github.recrafter.lapis.layers.lowering.IrModifier
1211
import io.github.recrafter.lapis.layers.lowering.models.IrParameter

src/main/kotlin/io/github/recrafter/lapis/extensions/ks/KSAnnotationExt.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ inline fun <reified A : Annotation> KSAnnotation.getMemberTypeClassDecl(
1919
findArgument(property)?.getTypeClassDecl()
2020

2121
fun KSAnnotation.getArgumentType(name: String): KSType? =
22-
annotationType.resolve().getClassDecl()?.propertyDeclarations.orEmpty()
23-
.find { it.name == name }?.type?.resolve()
22+
annotationType.resolve().getClassDecl()
23+
?.propertyDeclarations.orEmpty().find { it.name == name }
24+
?.type?.resolve()

src/main/kotlin/io/github/recrafter/lapis/extensions/ks/KSTypeExt.kt

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,7 @@
11
package io.github.recrafter.lapis.extensions.ks
22

33
import io.github.recrafter.lapis.extensions.common.castOrNull
4-
import io.github.recrafter.lapis.extensions.kp.KPArray
5-
import io.github.recrafter.lapis.extensions.kp.KPBooleanArray
6-
import io.github.recrafter.lapis.extensions.kp.KPByteArray
7-
import io.github.recrafter.lapis.extensions.kp.KPCharArray
8-
import io.github.recrafter.lapis.extensions.kp.KPDoubleArray
9-
import io.github.recrafter.lapis.extensions.kp.KPFloatArray
10-
import io.github.recrafter.lapis.extensions.kp.KPIntArray
11-
import io.github.recrafter.lapis.extensions.kp.KPLongArray
12-
import io.github.recrafter.lapis.extensions.kp.KPShortArray
13-
import io.github.recrafter.lapis.extensions.kp.qualifiedName
4+
import io.github.recrafter.lapis.extensions.kp.*
145
import io.github.recrafter.lapis.extensions.ksp.KSPResolver
156
import kotlin.reflect.KClass
167

src/main/kotlin/io/github/recrafter/lapis/extensions/ks/KSValueArgumentExt.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ fun KSValueArgument.getKClassType(): KSType? =
66
value?.castOrNull<KSType>()
77

88
fun KSValueArgument.getTypeClassDecl(): KSClassDecl? =
9-
getKClassType()?.getClassDecl()
9+
getKClassType()?.getClassDecl()?.takeNotNothing()

0 commit comments

Comments
 (0)