Skip to content

Commit

Permalink
feat: 1.2.0 (#46)
Browse files Browse the repository at this point in the history
* build: switch version, run workflow for upcoming version snapshots

* feat(generator-web-cli): namespace configuration

* perf: intern strings

* fix(generator-web-cli): add missing CB version replacement call

* feat: support for Quilt mappings (#33)

* feat: support for Quilt Mappings

* refactor(core): remove Fabric-only code from Quilt implementation

* fix(core): log "quilt mappings" instead of just "quilt"

* fix(core): fix missing license header

* fix(generator-accessor-plugin): fix Quilt being missing from namespaceFriendlinessIndex

* refactor(core): remove Fabric remnants from QuiltMetadataProvider and QuiltMappingResolver
chore(core): lowercase Quilt mappings, fix typo

* feat: support for Quilt Hashed mappings

* fix: remove Hashed from default ancestry namespace list
fix: add Hashed to namespace friendliness index

* fix(accessor-generator-plugin): remove edit remnant

---------

Co-authored-by: Matouš Kučera <[email protected]>

* feat(core): validate SHA1 hashes of Yarn and Quilt cached metadata (#35)

* fix(generator-web-cli): mismatching joined output cache

* refactor: improve concurrency model

* chore: update license headers

* refactor: misc

* feat(generator-accessor): add `@since` and `@version` tags to generated javadocs (#38)

* feat(generator-accessor): naming strategy (#39)

* feat(generator-accessor): introduction of naming strategy

* style(generator-accessor): this todo is useless since it has been fixed elsewhere

Probably not the best way to fix that tho

* feat(generator-accessor): additional naming strategies + licenses

* fix(generator-accessor): fix generation

* build: updated gradle, kotlin-conventions and -Xjvm-default flag

* feat(generator-accessor): specifying custom package containing generator-accessor-runtime module

* fix(generator-accessor): groovy dsl compatibility with StandardNamingStrategies enum

* refactor: improve API, untested

* fix: de-parallelize `AccessorGenerator`

Fixes non-deterministic behavior of name conflict resolution, I don't think parallelization makes that much of a difference anyway.

* deps: Kotlin, ASM, Jackson, KotlinPoet, SLF4J, Shadow

* build: release 1.1.2

* refactor: re-add missing strategies, make them serializable

* fix: pass correct input into `generateLookupClass`

* feat(generator-accessor-plugin): add naming strategy shortcuts

---------

Co-authored-by: Matouš Kučera <[email protected]>

* feat(generator-accessor-plugin): namespace configuration

* [ci skip] fix: deprecated usage in example

* fix(generator-accessor): prevent KotlinPoet from wrapping references

* refactor(generator-accessor-plugin): `versions` -> `version`

* chore(generator-web): bump Java API doc version

* fix(generator-accessor-plugin): wrong source type

* fix(generator-accessor): prevent KotlinPoet from wrapping references

* fix(generator-accessor): escape Kotlin names in lookup class

* feat(generator-accessor): merge chained accessors into single accessor field (#40)

* feat(generator-accessor): merge chained accessors into single accessor field

* fix(generator-accessor): fix javadoc format

* fix(generator-accessor): squash mappings as well, standalone counter for put mappings and accessor fields

* feat(generator-accessor): kotlin support

* style(generator-accessor): use filter and mutableListOf

* refactor(generator-accessor): extract some common code from Java and Kotlin generation context

* fix(generator-accessor): Kdoc generation for *Mapping classes

* refactor(generator-accessor): improve chain resolving logic

Co-authored-by: Matouš Kučera <[email protected]>

* fix(generator-accessor): fucking whitespace

* refactor: simplify

---------

Co-authored-by: Matouš Kučera <[email protected]>

* refactor: prepare to make Jackson an implementation detail

* deps: update `kotlin-logging-jvm`

* deps: bump Kotlin Coroutines and KotlinPoet

* [ci skip] fix: doc mistakes

* fix(generator-accessor): improve chain tracing

* fix(generator-accessor): group method descriptors exactly when tracing

* fix(generator-accessor): this logic was needed

* feat(generator-accessor): add mapping website link to accessors *doc (#45)

* feat(generator-accessor): add mapping website link to accessors *doc

* chore(generator-accessor): use toInternalName extension function

---------

Co-authored-by: Florentin Schleuß <[email protected]>
Co-authored-by: Misat11 <[email protected]>
  • Loading branch information
3 people authored Aug 8, 2024
1 parent 302a0e2 commit 5f17c0c
Show file tree
Hide file tree
Showing 68 changed files with 2,993 additions and 1,078 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
branches:
- main
- 'ver/**'

jobs:
build:
Expand Down
33 changes: 28 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ The goal of this project is to improve the maintainability and performance of th
- [x] Searge (Forge) mappings
- [x] Spigot mappings
- [x] Yarn (FabricMC) mappings
- [ ] Hashed (QuiltMC) mappings (PRs welcome!)
- [ ] QuiltMC mappings (PRs welcome!)
- [x] Hashed (QuiltMC) mappings
- [x] QuiltMC mappings

## Usage

Expand Down Expand Up @@ -83,7 +83,7 @@ accessors {
// if you don't, you will get accessors mapped for everything that the bundle offers, i.e. 1.8.8 to 1.20.6

basePackage("org.example.myplugin.accessors") // this is the base package of the generated output, probably somewhere in your plugin/library's namespace
accessedNamespaces("spigot", "mojang") // these are the "namespaces" that can be queried on runtime, i.e. "spigot" (for Spigot/CraftBukkit/Paper), "searge" (for Forge), "mojang" (for Mojang-mapped Paper - >1.20.4), "yarn" (not useful on runtime) or "intermediary" (for Fabric)
namespaces("spigot", "mojang") // these are the "namespaces" that can be queried on runtime, i.e. "spigot" (for Spigot/CraftBukkit/Paper), "searge" (for Forge), "mojang" (for Mojang-mapped Paper - >1.20.4), "yarn" (not useful on runtime), "intermediary" (for Fabric), "quilt" or "hashed" (for Quilt)
accessorType("reflection") // this is the generated accessor type, can be "none" (no accessor breakout classes are generated, only a mapping class that can be queried), "reflection" or "method_handles" (self-explanatory, java.lang.reflect or java.lang.invoke accessors)

// there are many more options, like mapping for clients, IntelliJ's source JAR view and auto-complete are your friends (Ctrl+Click)
Expand Down Expand Up @@ -126,6 +126,8 @@ Usage: web-cli options_list
Options:
--output, -o [output] -> Output directory { String }
--version, -v -> Target Minecraft version, can be specified multiple times (always required) { String }
--namespace, -n -> Target namespace, can be specified multiple times, order matters { String }
--ancestryNamespace, -a -> Target ancestry namespace, can be specified multiple times, has to be a subset of --namespace { String }
--cache, -c [cache] -> Caching directory for mappings and other resources { String }
--server [false] -> Include server mappings in the documentation
--client [false] -> Include client mappings in the documentation
Expand All @@ -141,15 +143,36 @@ Options:
```

The command-line to build a [mappings.dev](https://mappings.dev) clone would look something like this:
`java -jar generator-web-cli-<latest version here>.jar --client --server -v 1.20.2 -v 1.20.1 ... (more versions follow)`
`java -jar generator-web-cli-<latest version here>.jar --client --server -n mojang -n spigot -n yarn -n searge -n intermediary -v 1.20.2 -v 1.20.1 ... (more versions follow)`

#### `--namespace` option

This option allows you to specify a custom namespace subset and preference ordering.
Useful if you want to build an instance for only modding mappings for example.

For the Fabric toolchain, you would specify something along the lines of `-n yarn -n intermediary`,
that resolves only the Yarn and Intermediary mappings, with Yarn names used for the links/overview pages/...
and Intermediary being a fallback that is used if a Yarn name is not present.
Both namespaces will still be shown as usual on class detail pages.

*The `source` (obfuscated) namespace is always implicitly appended last.*

By default, all available namespaces are used (`mojang, spigot, yarn, quilt, searge, intermediary, hashed`).

#### `--ancestryNamespace` option

This option allows you to select a subset of defined namespaces (`--namespace` choices or its default), which will be
used for ancestry computation. This option is more advanced and most users won't need to use it, the default suffices for most cases.

By default, the `mojang, spigot, searge, intermediary` namespaces are used, minus ones that haven't been defined (`--namespace` choices or its default).

#### `--javadoc` option

The expected value can be:
- a plus-sign delimited pair of a supported package and a link to the Javadoc root (Javadoc sites _with no modules_): `org.slf4j+https://www.slf4j.org/api`
- a link to the Javadoc root (Javadoc sites _with modules_): `https://docs.oracle.com/en/java/javase/17/docs/api`

**Java 17 API is included automatically for indexing.**
**Java 21 API is included automatically for indexing.**

## Acknowledgements

Expand Down
1 change: 1 addition & 0 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ repositories {
dependencies {
implementation(libs.build.licenser)
implementation(libs.build.gradle.versions)
implementation(libs.build.kotlin.jvm)
}

dependencies {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

apply(plugin = "org.jetbrains.kotlin.jvm")

tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjvm-default=all-compatibility")
}
}
3 changes: 1 addition & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
plugins {
id("takenaka.base-conventions")
alias(libs.plugins.kotlin.jvm) apply false
}

allprojects {
group = "me.kcra.takenaka"
version = "1.1.4"
version = "1.2.0-SNAPSHOT"
description = "A Kotlin library for reconciling multiple obfuscation mapping files from multiple versions of Minecraft: JE."
}
3 changes: 1 addition & 2 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
plugins {
id("takenaka.base-conventions")
id("takenaka.kotlin-conventions")
id("takenaka.publish-conventions")
}

apply(plugin = "org.jetbrains.kotlin.jvm")

dependencies {
api(libs.bundles.asm)
api(libs.bundles.jackson)
Expand Down
67 changes: 67 additions & 0 deletions core/src/main/kotlin/me/kcra/takenaka/core/VersionManifest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import java.nio.file.Path
import java.time.Instant
import kotlin.io.path.createDirectories
import kotlin.io.path.fileSize
import kotlin.io.path.getLastModifiedTime
import kotlin.io.path.isRegularFile

/**
Expand All @@ -42,15 +43,63 @@ const val VERSION_MANIFEST_V2 = "https://piston-meta.mojang.com/mc/game/version_
*
* @return the version manifest
*/
@Deprecated(
"Jackson will be an implementation detail in the future.",
ReplaceWith("versionManifestOf()", "me.kcra.takenaka.core.versionManifestOf")
)
fun ObjectMapper.versionManifest(): VersionManifest = readValue(URL(VERSION_MANIFEST_V2))

/**
* Fetches and deserializes the version manifest from Mojang's API.
*
* @param url the version manifest url, defaults to [VERSION_MANIFEST_V2]
* @return the version manifest
*/
fun versionManifestOf(url: String = VERSION_MANIFEST_V2): VersionManifest = MAPPER.readValue(URL(url))

/**
* Retrieves the version manifest from Mojang's API or a cache file,
* fetching it again if the cache missed, or it could not be deserialized.
*
* @param cacheFile the cache file, does not need to exist
* @param url the version manifest url, defaults to [VERSION_MANIFEST_V2]
* @return the version manifest
*/
fun versionManifestFrom(cacheFile: Path, url: String = VERSION_MANIFEST_V2): VersionManifest {
val url0 = URL(url)
if (cacheFile.isRegularFile()) {
if (url0.lastModified > cacheFile.getLastModifiedTime().toMillis()) {
try {
return MAPPER.readValue(cacheFile)
} catch (_: JacksonException) {
// failed to read cached file, corrupted? fetch it again
}
}
}

url0.httpRequest {
if (it.ok) {
cacheFile.parent.createDirectories()
it.copyTo(cacheFile)

return MAPPER.readValue(cacheFile)
}

throw IOException("Failed to fetch v2 Mojang manifest, received ${it.responseCode}")
}
}

/**
* Retrieves the version manifest from Mojang's API or a cache file,
* fetching it if it could not be deserialized or the content length changed.
*
* @param cacheFile the cache file, does not need to exist
* @return the version manifest
*/
@Deprecated(
"Jackson will be an implementation detail in the future.",
ReplaceWith("versionManifestFrom(cacheFile)", "me.kcra.takenaka.core.versionManifestFrom")
)
fun ObjectMapper.cachedVersionManifest(cacheFile: Path): VersionManifest {
val url = URL(VERSION_MANIFEST_V2)

Expand Down Expand Up @@ -179,6 +228,24 @@ data class Version(
}
}

/**
* Fetches and deserializes version attributes from Mojang's API.
*
* @param url the version attributes url
* @return the version attributes
*/
fun versionAttributesOf(url: String): VersionAttributes {
return MAPPER.readValue(URL(url))
}

/**
* Fetches and deserializes version attributes from Mojang's API.
*
* @param version the version
* @return the version attributes
*/
fun versionAttributesOf(version: Version): VersionAttributes = versionAttributesOf(version.url)

/**
* The version attributes from Mojang's v2 version manifest.
*/
Expand Down
1 change: 1 addition & 0 deletions core/src/main/kotlin/me/kcra/takenaka/core/Workspace.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ open class WorkspaceBuilder {
/**
* The resolver options.
*/
@Deprecated("Unused.")
var options = 0

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

package me.kcra.takenaka.core.mapping.adapter

import mu.KotlinLogging
import io.github.oshai.kotlinlogging.KotlinLogging
import net.fabricmc.mappingio.MappingVisitor
import net.fabricmc.mappingio.adapter.ForwardingMappingVisitor

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* This file is part of takenaka, licensed under the Apache License, Version 2.0 (the "License").
*
* Copyright (c) 2023-2024 Matous Kucera
*
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package me.kcra.takenaka.core.mapping.adapter

import net.fabricmc.mappingio.MappedElementKind
import net.fabricmc.mappingio.MappingVisitor
import net.fabricmc.mappingio.adapter.ForwardingMappingVisitor

/**
* Pools element name and descriptor strings (using [String.intern]).
*
* @param next the visitor to delegate to
* @author Matouš Kučera
*/
class StringPoolingAdapter(next: MappingVisitor) : ForwardingMappingVisitor(next) {
override fun visitClass(srcName: String?): Boolean {
return super.visitClass(srcName?.intern())
}

override fun visitField(srcName: String?, srcDesc: String?): Boolean {
return super.visitField(srcName?.intern(), srcDesc?.intern())
}

override fun visitMethod(srcName: String?, srcDesc: String?): Boolean {
return super.visitMethod(srcName?.intern(), srcDesc?.intern())
}

override fun visitDstName(targetKind: MappedElementKind?, namespace: Int, name: String?) {
super.visitDstName(targetKind, namespace, name?.intern())
}

override fun visitDstDesc(targetKind: MappedElementKind?, namespace: Int, desc: String?) {
super.visitDstDesc(targetKind, namespace, desc?.intern())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import me.kcra.takenaka.core.mapping.analysis.MappingAnalyzer
import me.kcra.takenaka.core.mapping.analysis.Problem
import me.kcra.takenaka.core.mapping.analysis.ProblemKind
import me.kcra.takenaka.core.mapping.analysis.ProblemResolution
import mu.KotlinLogging
import io.github.oshai.kotlinlogging.KotlinLogging
import net.fabricmc.mappingio.tree.MappingTree
import java.util.*
import kotlin.system.measureTimeMillis
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,36 @@ class AncestryTree<T : MappingTreeView, E : ElementMappingView>(
if (keys.isEmpty()) return null // return early, we're not searching for anything

return if (keys.size == 1) {
val key = keys[0]
val key = keys.first()

find { key in it.lastNames }
} else {
find { keys.all(it.lastNames::contains) }
}
}
}

/**
* Creates a merged node.
*
* Respects existing ordering in case of conflicts - only latest entries are kept, older are discarded.
*
* @param nodes the nodes to merge
* @return the merged node
*/
fun <T : MappingTreeView, E : ElementMappingView> nodeOf(vararg nodes: AncestryTree.Node<T, E>): AncestryTree.Node<T, E> {
require(nodes.isNotEmpty()) {
"No nodes provided"
}

if (nodes.size == 1) return nodes.first()

// create merged node
val lastNode = nodes.last()
return AncestryTree.Node(
lastNode.tree,
nodes.flatMap { it.entries }
.associate { it.key to it.value },
last = lastNode.last
)
}
Loading

0 comments on commit 5f17c0c

Please sign in to comment.