Kotlin metadata annotation remapping (#573)

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>
dev/0.11
modmuss50 2022-01-16 23:48:36 +00:00 committed by GitHub
parent 421b41ebc7
commit d71af0cfd7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 984 additions and 46 deletions

View File

@ -1,4 +1,4 @@
[*.{gradle,java}]
[*.{gradle,java,kotlin}]
indent_style = tab
ij_continuation_indent_size = 8
ij_java_imports_layout = $*,|,java.**,|,javax.**,|,*,|,net.fabricmc.**

View File

@ -8,6 +8,7 @@ plugins {
id 'checkstyle'
id 'jacoco'
id 'codenarc'
id "org.jetbrains.kotlin.jvm" version "1.5.31" // Must match the version included with gradle.
id "com.diffplug.spotless" version "5.14.1"
}
@ -19,6 +20,11 @@ tasks.withType(JavaCompile).configureEach {
it.options.release = 17
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlinOptions {
jvmTarget = "16" // Change to 17 when updating gradle/kotlin to 1.6.10
}
}
group = 'net.fabricmc'
archivesBaseName = project.name
@ -92,6 +98,11 @@ dependencies {
// source code remapping
implementation ('net.fabricmc:mercury:0.2.4')
// Kotlin
implementation("org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.4.1") {
transitive = false
}
// Kapt integration
compileOnly('org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0')
@ -100,7 +111,10 @@ dependencies {
testImplementation('org.spockframework:spock-core:2.0-groovy-3.0') {
exclude module: 'groovy-all'
}
testImplementation 'io.javalin:javalin:3.13.11'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
testImplementation ('io.javalin:javalin:3.13.11') {
exclude group: 'org.jetbrains.kotlin'
}
testImplementation 'net.fabricmc:fabric-installer:0.9.0'
compileOnly 'org.jetbrains:annotations:23.0.0'
@ -127,6 +141,13 @@ spotless {
groovy {
licenseHeaderFile(rootProject.file("HEADER")).yearSeparator("-")
}
kotlin {
licenseHeaderFile(rootProject.file("HEADER")).yearSeparator("-")
targetExclude("**/build.gradle.kts")
targetExclude("src/test/resources/projects/*/**")
ktlint()
}
}
checkstyle {
@ -172,18 +193,6 @@ import org.w3c.dom.Document
import org.w3c.dom.Element
import org.w3c.dom.Node
def patchPom(groovy.util.Node node) {
node.dependencies.first().each {
def groupId = it.get("groupId").first().value().first()
// Patch all eclipse deps to use a strict version
if (groupId.startsWith("org.eclipse.")) {
def version = it.get("version").first().value().first()
it.get("version").first().value = new groovy.util.NodeList(["[$version]"])
}
}
}
publishing {
publications {
plugin(MavenPublication) { publication ->
@ -192,10 +201,6 @@ publishing {
version project.version
from components.java
pom.withXml {
patchPom(asNode())
}
}
// Also publish a snapshot so people can use the latest version if they wish
@ -205,10 +210,6 @@ publishing {
version baseVersion + '-SNAPSHOT'
from components.java
pom.withXml {
patchPom(asNode())
}
}
// Manually crate the plugin marker for snapshot versions

View File

@ -1,3 +1,5 @@
name = fabric-loom
description = The Gradle plugin for Fabric
url = https://github.com/FabricMC/fabric-loom
url = https://github.com/FabricMC/fabric-loom
kotlin.stdlib.default.dependency = false

View File

@ -46,6 +46,7 @@ import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.RemappedConfigurationEntry;
import net.fabricmc.loom.configuration.processors.dependency.ModDependencyInfo;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
import net.fabricmc.loom.kotlin.remapping.KotlinMetadataTinyRemapperExtension;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.TinyRemapperHelper;
import net.fabricmc.loom.util.ZipUtils;
@ -134,16 +135,22 @@ public class ModProcessor {
private void remapJars(List<ModDependencyInfo> remapList) throws IOException {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
final boolean useKotlinExtension = project.getPluginManager().hasPlugin("org.jetbrains.kotlin.jvm");
Path[] mcDeps = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES).getFiles()
.stream().map(File::toPath).toArray(Path[]::new);
project.getLogger().lifecycle(":remapping " + remapList.size() + " mods (TinyRemapper, " + fromM + " -> " + toM + ")");
final TinyRemapper remapper = TinyRemapper.newRemapper()
TinyRemapper.Builder builder = TinyRemapper.newRemapper()
.withMappings(TinyRemapperHelper.create(mappingsProvider.getMappings(), fromM, toM, false))
.renameInvalidLocals(false)
.build();
.renameInvalidLocals(false);
if (useKotlinExtension) {
builder.extension(KotlinMetadataTinyRemapperExtension.INSTANCE);
}
final TinyRemapper remapper = builder.build();
for (Path minecraftJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
remapper.readClassPathAsync(minecraftJar);

View File

@ -37,6 +37,7 @@ import java.util.Objects;
import org.gradle.api.Project;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.kotlin.remapping.KotlinMetadataTinyRemapperExtension;
import net.fabricmc.loom.task.AbstractRemapJarTask;
import net.fabricmc.loom.util.service.SharedService;
import net.fabricmc.loom.util.service.SharedServiceManager;
@ -52,9 +53,10 @@ public class TinyRemapperService implements SharedService {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final SharedServiceManager sharedServiceManager = SharedServiceManager.get(project);
final boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get();
final boolean useKotlinExtension = project.getPluginManager().hasPlugin("org.jetbrains.kotlin.jvm");
// Generates an id that is used to share the remapper across projects. This tasks in the remap jar task name to handle custom remap jar tasks separately.
final String id = extension.getMappingsProvider().getBuildServiceName("remapJarService", from, to) + ":" + remapJarTask.getName();
final String id = extension.getMappingsProvider().getBuildServiceName("remapJarService", from, to) + ":" + remapJarTask.getName() + (useKotlinExtension ? ":kotlin" : "");
TinyRemapperService service = sharedServiceManager.getOrCreateService(id, () -> {
List<IMappingProvider> mappings = new ArrayList<>();
@ -64,7 +66,7 @@ public class TinyRemapperService implements SharedService {
mappings.add(MixinMappingsService.getService(SharedServiceManager.get(project)).getMappingProvider(from, to));
}
return new TinyRemapperService(mappings, !legacyMixin);
return new TinyRemapperService(mappings, !legacyMixin, useKotlinExtension);
});
service.readClasspath(remapJarTask.getClasspath().getFiles().stream().map(File::toPath).toList());
@ -78,7 +80,7 @@ public class TinyRemapperService implements SharedService {
// Set to true once remapping has started, once set no inputs can be read.
private boolean isRemapping = false;
public TinyRemapperService(List<IMappingProvider> mappings, boolean useMixinExtension) {
public TinyRemapperService(List<IMappingProvider> mappings, boolean useMixinExtension, boolean useKotlinExtension) {
TinyRemapper.Builder builder = TinyRemapper.newRemapper();
for (IMappingProvider provider : mappings) {
@ -89,6 +91,10 @@ public class TinyRemapperService implements SharedService {
builder.extension(new net.fabricmc.tinyremapper.extension.mixin.MixinExtension());
}
if (useKotlinExtension) {
builder.extension(KotlinMetadataTinyRemapperExtension.INSTANCE);
}
tinyRemapper = builder.build();
}

View File

@ -0,0 +1,124 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2022 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.kotlin.remapping
import kotlinx.metadata.jvm.KotlinClassHeader
import kotlinx.metadata.jvm.KotlinClassMetadata
import org.objectweb.asm.AnnotationVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.commons.Remapper
import org.objectweb.asm.tree.AnnotationNode
class KotlinClassMetadataRemappingAnnotationVisitor(private val remapper: Remapper, val next: AnnotationVisitor) :
AnnotationNode(Opcodes.ASM9, KotlinMetadataRemappingClassVisitor.ANNOTATION_DESCRIPTOR) {
private var _name: String? = null
override fun visit(name: String?, value: Any?) {
super.visit(name, value)
this._name = name
}
override fun visitEnd() {
super.visitEnd()
when (val metadata = readMetadata()) {
is KotlinClassMetadata.Class -> {
val klass = metadata.toKmClass()
val writer = KotlinClassMetadata.Class.Writer()
klass.accept(RemappingKmVisitors(remapper).RemappingKmClassVisitor(writer))
writeClassHeader(writer.write().header)
}
is KotlinClassMetadata.SyntheticClass -> {
val klambda = metadata.toKmLambda()
if (klambda != null) {
val writer = KotlinClassMetadata.SyntheticClass.Writer()
klambda.accept(RemappingKmVisitors(remapper).RemappingKmLambdaVisitor(writer))
writeClassHeader(writer.write().header)
} else {
accept(next)
}
}
// Can only be turned into KmPackage which is useless data
is KotlinClassMetadata.FileFacade, is KotlinClassMetadata.MultiFileClassPart,
// Can't be turned into data
is KotlinClassMetadata.MultiFileClassFacade, is KotlinClassMetadata.Unknown, null -> {
// do nothing
accept(next)
}
}
}
@Suppress("UNCHECKED_CAST")
private fun readMetadata(): KotlinClassMetadata? {
var kind: Int? = null
var metadataVersion: IntArray? = null
var data1: Array<String>? = null
var data2: Array<String>? = null
var extraString: String? = null
var packageName: String? = null
var extraInt: Int? = null
if (values == null) {
return null
}
values.chunked(2).forEach { (name, value) ->
when (name) {
"k" -> kind = value as Int
"mv" -> metadataVersion = (value as List<Int>).toIntArray()
"d1" -> data1 = (value as List<String>).toTypedArray()
"d2" -> data2 = (value as List<String>).toTypedArray()
"xs" -> extraString = value as String
"pn" -> packageName = value as String
"xi" -> extraInt = value as Int
}
}
val header = KotlinClassHeader(kind, metadataVersion, data1, data2, extraString, packageName, extraInt)
return KotlinClassMetadata.read(header)
}
private fun writeClassHeader(header: KotlinClassHeader) {
val newNode = AnnotationNode(api, desc)
newNode.values = this.values.toMutableList()
newNode.run {
for (i in values.indices step 2) {
when (values[i]) {
"k" -> values[i + 1] = header.kind
"mv" -> values[i + 1] = header.metadataVersion.toList()
"d1" -> values[i + 1] = header.data1.toList()
"d2" -> values[i + 1] = header.data2.toList()
"xs" -> values[i + 1] = header.extraString
"pn" -> values[i + 1] = header.packageName
"xi" -> values[i + 1] = header.extraInt
}
}
}
newNode.accept(next)
}
}

View File

@ -0,0 +1,47 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2022 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.kotlin.remapping
import org.objectweb.asm.AnnotationVisitor
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import org.objectweb.asm.commons.Remapper
class KotlinMetadataRemappingClassVisitor(private val remapper: Remapper, next: ClassVisitor?) : ClassVisitor(Opcodes.ASM9, next) {
companion object {
val ANNOTATION_DESCRIPTOR: String = Type.getDescriptor(Metadata::class.java)
}
override fun visitAnnotation(descriptor: String, visible: Boolean): AnnotationVisitor? {
var result: AnnotationVisitor? = super.visitAnnotation(descriptor, visible)
if (descriptor == ANNOTATION_DESCRIPTOR && result != null) {
result = KotlinClassMetadataRemappingAnnotationVisitor(remapper, result)
}
return result
}
}

View File

@ -0,0 +1,39 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2022 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.kotlin.remapping
import net.fabricmc.tinyremapper.TinyRemapper
import net.fabricmc.tinyremapper.api.TrClass
import org.objectweb.asm.ClassVisitor
object KotlinMetadataTinyRemapperExtension : TinyRemapper.ApplyVisitorProvider, TinyRemapper.Extension {
override fun insertApplyVisitor(cls: TrClass, next: ClassVisitor): ClassVisitor {
return KotlinMetadataRemappingClassVisitor(cls.environment.remapper, next)
}
override fun attach(builder: TinyRemapper.Builder) {
builder.extraPreApplyVisitor(this)
}
}

View File

@ -0,0 +1,359 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2022 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.kotlin.remapping
import kotlinx.metadata.ClassName
import kotlinx.metadata.Flags
import kotlinx.metadata.KmAnnotation
import kotlinx.metadata.KmClassExtensionVisitor
import kotlinx.metadata.KmClassVisitor
import kotlinx.metadata.KmConstructorExtensionVisitor
import kotlinx.metadata.KmConstructorVisitor
import kotlinx.metadata.KmContractVisitor
import kotlinx.metadata.KmEffectExpressionVisitor
import kotlinx.metadata.KmEffectInvocationKind
import kotlinx.metadata.KmEffectType
import kotlinx.metadata.KmEffectVisitor
import kotlinx.metadata.KmExtensionType
import kotlinx.metadata.KmFunctionExtensionVisitor
import kotlinx.metadata.KmFunctionVisitor
import kotlinx.metadata.KmLambdaVisitor
import kotlinx.metadata.KmPropertyExtensionVisitor
import kotlinx.metadata.KmPropertyVisitor
import kotlinx.metadata.KmTypeAliasVisitor
import kotlinx.metadata.KmTypeExtensionVisitor
import kotlinx.metadata.KmTypeParameterExtensionVisitor
import kotlinx.metadata.KmTypeParameterVisitor
import kotlinx.metadata.KmTypeVisitor
import kotlinx.metadata.KmValueParameterVisitor
import kotlinx.metadata.KmVariance
import kotlinx.metadata.jvm.JvmClassExtensionVisitor
import kotlinx.metadata.jvm.JvmConstructorExtensionVisitor
import kotlinx.metadata.jvm.JvmFieldSignature
import kotlinx.metadata.jvm.JvmFunctionExtensionVisitor
import kotlinx.metadata.jvm.JvmMethodSignature
import kotlinx.metadata.jvm.JvmPropertyExtensionVisitor
import kotlinx.metadata.jvm.JvmTypeExtensionVisitor
import kotlinx.metadata.jvm.JvmTypeParameterExtensionVisitor
import org.objectweb.asm.commons.Remapper
class RemappingKmVisitors(private val remapper: Remapper) {
private fun remapJvmMethodSignature(signature: JvmMethodSignature?): JvmMethodSignature? {
if (signature != null) {
return JvmMethodSignature(signature.name, remapper.mapMethodDesc(signature.desc))
}
return null
}
private fun remapJvmFieldSignature(signature: JvmFieldSignature?): JvmFieldSignature? {
if (signature != null) {
return JvmFieldSignature(signature.name, remapper.mapDesc(signature.desc))
}
return null
}
inner class RemappingKmClassVisitor(delegate: KmClassVisitor?) : KmClassVisitor(delegate) {
override fun visit(flags: Flags, name: ClassName) {
super.visit(flags, remapper.map(name))
}
override fun visitNestedClass(name: String) {
super.visitNestedClass(remapper.map(name))
}
override fun visitSealedSubclass(name: ClassName) {
super.visitSealedSubclass(remapper.map(name))
}
override fun visitSupertype(flags: Flags): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitSupertype(flags))
}
override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor {
return RemappingKmFunctionVisitor(super.visitFunction(flags, name))
}
override fun visitInlineClassUnderlyingType(flags: Flags): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitInlineClassUnderlyingType(flags))
}
override fun visitProperty(flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags): KmPropertyVisitor {
return RemappingKmPropertyVisitor(super.visitProperty(flags, name, getterFlags, setterFlags))
}
override fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor {
return RemappingKmTypeAliasVisitor(super.visitTypeAlias(flags, name))
}
override fun visitConstructor(flags: Flags): KmConstructorVisitor {
return RemappingKmConstructorVisitor(super.visitConstructor(flags))
}
override fun visitExtensions(type: KmExtensionType): KmClassExtensionVisitor {
return RemappingJvmClassExtensionVisitor(super.visitExtensions(type) as JvmClassExtensionVisitor?)
}
override fun visitTypeParameter(
flags: Flags,
name: String,
id: Int,
variance: KmVariance
): KmTypeParameterVisitor {
return RemappingKmTypeParameterVisitor(super.visitTypeParameter(flags, name, id, variance))
}
}
inner class RemappingKmLambdaVisitor(delegate: KmLambdaVisitor?) : KmLambdaVisitor(delegate) {
override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor {
return RemappingKmFunctionVisitor(super.visitFunction(flags, name))
}
}
inner class RemappingKmTypeVisitor(delegate: KmTypeVisitor?) : KmTypeVisitor(delegate) {
override fun visitClass(name: ClassName) {
super.visitClass(remapper.map(name))
}
override fun visitTypeAlias(name: ClassName) {
super.visitTypeAlias(remapper.map(name))
}
override fun visitAbbreviatedType(flags: Flags): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitAbbreviatedType(flags))
}
override fun visitArgument(flags: Flags, variance: KmVariance): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitArgument(flags, variance))
}
override fun visitOuterType(flags: Flags): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitOuterType(flags))
}
override fun visitFlexibleTypeUpperBound(flags: Flags, typeFlexibilityId: String?): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitFlexibleTypeUpperBound(flags, typeFlexibilityId))
}
override fun visitExtensions(type: KmExtensionType): KmTypeExtensionVisitor {
return RemappingJvmTypeExtensionVisitor(super.visitExtensions(type) as JvmTypeExtensionVisitor?)
}
}
inner class RemappingJvmTypeExtensionVisitor(delegate: JvmTypeExtensionVisitor?) : JvmTypeExtensionVisitor(delegate) {
override fun visitAnnotation(annotation: KmAnnotation) {
super.visitAnnotation(KmAnnotation(remapper.map(annotation.className), annotation.arguments))
}
}
inner class RemappingKmFunctionVisitor(delegate: KmFunctionVisitor?) : KmFunctionVisitor(delegate) {
override fun visitReceiverParameterType(flags: Flags): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitReceiverParameterType(flags))
}
override fun visitReturnType(flags: Flags): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitReturnType(flags))
}
override fun visitValueParameter(flags: Flags, name: String): KmValueParameterVisitor {
return RemappingKmValueParameterVisitor(super.visitValueParameter(flags, name))
}
override fun visitExtensions(type: KmExtensionType): KmFunctionExtensionVisitor {
return RemappingJvmFunctionExtensionVisitor(super.visitExtensions(type) as JvmFunctionExtensionVisitor)
}
override fun visitContract(): KmContractVisitor {
return RemappingKmContractVisitor(super.visitContract())
}
}
inner class RemappingKmContractVisitor(delegate: KmContractVisitor?) : KmContractVisitor(delegate) {
override fun visitEffect(type: KmEffectType, invocationKind: KmEffectInvocationKind?): KmEffectVisitor {
return RemappingKmEffectVisitor(super.visitEffect(type, invocationKind))
}
}
inner class RemappingKmEffectVisitor(delegate: KmEffectVisitor?) : KmEffectVisitor(delegate) {
override fun visitConclusionOfConditionalEffect(): KmEffectExpressionVisitor {
return RemappingKmEffectExpressionVisitor(super.visitConclusionOfConditionalEffect())
}
override fun visitConstructorArgument(): KmEffectExpressionVisitor {
return RemappingKmEffectExpressionVisitor(super.visitConclusionOfConditionalEffect())
}
}
inner class RemappingKmEffectExpressionVisitor(delegate: KmEffectExpressionVisitor?) : KmEffectExpressionVisitor(delegate) {
override fun visitAndArgument(): KmEffectExpressionVisitor {
return RemappingKmEffectExpressionVisitor(super.visitAndArgument())
}
override fun visitIsInstanceType(flags: Flags): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitIsInstanceType(flags))
}
override fun visitOrArgument(): KmEffectExpressionVisitor {
return RemappingKmEffectExpressionVisitor(super.visitOrArgument())
}
}
inner class RemappingKmPropertyVisitor(delegate: KmPropertyVisitor?) : KmPropertyVisitor(delegate) {
override fun visitReceiverParameterType(flags: Flags): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitReceiverParameterType(flags))
}
override fun visitReturnType(flags: Flags): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitReturnType(flags))
}
override fun visitSetterParameter(flags: Flags, name: String): KmValueParameterVisitor {
return RemappingKmValueParameterVisitor(super.visitSetterParameter(flags, name))
}
override fun visitExtensions(type: KmExtensionType): KmPropertyExtensionVisitor {
return RemappingJvmPropertyExtensionVisitor(super.visitExtensions(type) as JvmPropertyExtensionVisitor?)
}
override fun visitTypeParameter(
flags: Flags,
name: String,
id: Int,
variance: KmVariance
): KmTypeParameterVisitor {
return RemappingKmTypeParameterVisitor(super.visitTypeParameter(flags, name, id, variance))
}
}
inner class RemappingJvmPropertyExtensionVisitor(delegate: JvmPropertyExtensionVisitor?) : JvmPropertyExtensionVisitor(delegate) {
override fun visit(
jvmFlags: Flags,
fieldSignature: JvmFieldSignature?,
getterSignature: JvmMethodSignature?,
setterSignature: JvmMethodSignature?
) {
super.visit(jvmFlags, remapJvmFieldSignature(fieldSignature), remapJvmMethodSignature(getterSignature), remapJvmMethodSignature(setterSignature))
}
override fun visitSyntheticMethodForAnnotations(signature: JvmMethodSignature?) {
super.visitSyntheticMethodForAnnotations(remapJvmMethodSignature(signature))
}
override fun visitSyntheticMethodForDelegate(signature: JvmMethodSignature?) {
super.visitSyntheticMethodForDelegate(remapJvmMethodSignature(signature))
}
}
inner class RemappingKmTypeParameterVisitor(delegate: KmTypeParameterVisitor?) : KmTypeParameterVisitor(delegate) {
override fun visitExtensions(type: KmExtensionType): KmTypeParameterExtensionVisitor {
return RemappingJvmTypeParameterExtensionVisitor(super.visitExtensions(type) as JvmTypeParameterExtensionVisitor?)
}
override fun visitUpperBound(flags: Flags): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitUpperBound(flags))
}
}
inner class RemappingJvmTypeParameterExtensionVisitor(delegate: JvmTypeParameterExtensionVisitor?) : JvmTypeParameterExtensionVisitor(delegate) {
override fun visitAnnotation(annotation: KmAnnotation) {
super.visitAnnotation(KmAnnotation(remapper.map(annotation.className), annotation.arguments))
}
}
inner class RemappingKmValueParameterVisitor(delegate: KmValueParameterVisitor?) : KmValueParameterVisitor(delegate) {
override fun visitType(flags: Flags): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitType(flags))
}
override fun visitVarargElementType(flags: Flags): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitVarargElementType(flags))
}
}
inner class RemappingKmTypeAliasVisitor(delegate: KmTypeAliasVisitor?) : KmTypeAliasVisitor(delegate) {
override fun visitExpandedType(flags: Flags): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitExpandedType(flags))
}
override fun visitTypeParameter(
flags: Flags,
name: String,
id: Int,
variance: KmVariance
): KmTypeParameterVisitor {
return RemappingKmTypeParameterVisitor(super.visitTypeParameter(flags, name, id, variance))
}
override fun visitUnderlyingType(flags: Flags): KmTypeVisitor {
return RemappingKmTypeVisitor(super.visitUnderlyingType(flags))
}
override fun visitAnnotation(annotation: KmAnnotation) {
super.visitAnnotation(KmAnnotation(remapper.map(annotation.className), annotation.arguments))
}
}
inner class RemappingJvmFunctionExtensionVisitor(delegate: JvmFunctionExtensionVisitor?) : JvmFunctionExtensionVisitor(delegate) {
override fun visit(signature: JvmMethodSignature?) {
super.visit(remapJvmMethodSignature(signature))
}
override fun visitLambdaClassOriginName(internalName: String) {
super.visitLambdaClassOriginName(remapper.map(internalName))
}
}
inner class RemappingJvmClassExtensionVisitor(delegate: JvmClassExtensionVisitor?) : JvmClassExtensionVisitor(delegate) {
override fun visitAnonymousObjectOriginName(internalName: String) {
super.visitAnonymousObjectOriginName(remapper.map(internalName))
}
override fun visitLocalDelegatedProperty(
flags: Flags,
name: String,
getterFlags: Flags,
setterFlags: Flags
): KmPropertyVisitor {
return RemappingKmPropertyVisitor(super.visitLocalDelegatedProperty(flags, name, getterFlags, setterFlags))
}
}
inner class RemappingKmConstructorVisitor(delegate: KmConstructorVisitor?) : KmConstructorVisitor(delegate) {
override fun visitExtensions(type: KmExtensionType): KmConstructorExtensionVisitor {
return RemappingJvmConstructorExtensionVisitor(super.visitExtensions(type) as JvmConstructorExtensionVisitor?)
}
override fun visitValueParameter(flags: Flags, name: String): KmValueParameterVisitor {
return RemappingKmValueParameterVisitor(super.visitValueParameter(flags, name))
}
}
inner class RemappingJvmConstructorExtensionVisitor(delegate: JvmConstructorExtensionVisitor?) : JvmConstructorExtensionVisitor(delegate) {
override fun visit(signature: JvmMethodSignature?) {
super.visit(remapJvmMethodSignature(signature))
}
}
}

View File

@ -28,7 +28,7 @@ import org.gradle.util.GradleVersion
class LoomTestConstants {
public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion()
public final static String PRE_RELEASE_GRADLE = "7.5-20220110230252+0000"
public final static String PRE_RELEASE_GRADLE = "7.5-20220116010338+0000"
public final static String[] STANDARD_TEST_VERSIONS = [DEFAULT_GRADLE, PRE_RELEASE_GRADLE]
}

View File

@ -25,6 +25,7 @@
package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.GradleProjectTestTrait
import net.fabricmc.loom.test.util.ServerRunner
import spock.lang.Specification
import spock.lang.Unroll
@ -36,12 +37,17 @@ class KotlinTest extends Specification implements GradleProjectTestTrait {
def "kotlin build (gradle #version)"() {
setup:
def gradle = gradleProject(project: "kotlin", version: version)
def server = ServerRunner.create(gradle.projectDir, "1.16.5")
.withMod(gradle.getOutputFile("fabric-example-mod-0.0.1.jar"))
.downloadMod(ServerRunner.FABRIC_LANG_KOTLIN, "fabric-language-kotlin-1.7.1+kotlin.1.6.10.jar")
when:
def result = gradle.run(task: "build")
def serverResult = server.run()
then:
result.task(":build").outcome == SUCCESS
serverResult.successful()
where:
version << STANDARD_TEST_VERSIONS

View File

@ -34,6 +34,7 @@ class ServerRunner {
"1.16.5": "https://github.com/FabricMC/fabric/releases/download/0.37.1%2B1.16/fabric-api-0.37.1+1.16.jar",
"1.17.1": "https://github.com/FabricMC/fabric/releases/download/0.37.1%2B1.17/fabric-api-0.37.1+1.17.jar"
]
static final String FABRIC_LANG_KOTLIN = "https://maven.fabricmc.net/net/fabricmc/fabric-language-kotlin/1.7.1%2Bkotlin.1.6.10/fabric-language-kotlin-1.7.1%2Bkotlin.1.6.10.jar"
final File serverDir
final String minecraftVersion

View File

@ -0,0 +1,82 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2022 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.test.kotlin
import java.io.File
import java.io.PrintWriter
import java.io.StringWriter
import java.nio.file.Paths
import net.fabricmc.loom.kotlin.remapping.KotlinMetadataRemappingClassVisitor
import net.fabricmc.loom.util.TinyRemapperHelper
import net.fabricmc.mappingio.MappingReader
import net.fabricmc.mappingio.tree.MemoryMappingTree
import net.fabricmc.tinyremapper.IMappingProvider
import net.fabricmc.tinyremapper.TinyRemapper
import org.junit.jupiter.api.Test
import org.objectweb.asm.ClassReader
import org.objectweb.asm.Opcodes
import org.objectweb.asm.util.Textifier
import org.objectweb.asm.util.TraceClassVisitor
// See: https://github.com/JetBrains/kotlin/blob/master/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/MetadataSmokeTest.kt#L67
class KotlinClassMetadataRemappingAnnotationVisitorTest {
/*
val test = KmClass()
klass.accept(RemappingKmClassVisitor(remapper, test))
println(GsonBuilder().setPrettyPrinting().create().toJson(test))
*/
@Test
fun simpleTest() {
val inputPosInChunk = getClassBytes("PosInChunk")
val classReader = ClassReader(inputPosInChunk)
val tinyRemapper = TinyRemapper.newRemapper()
.withMappings(readMappings("PosInChunk"))
.build()
val stringWriter = StringWriter()
val traceClassVisitor = TraceClassVisitor(null, TextifierImpl(), PrintWriter(stringWriter))
classReader.accept(KotlinMetadataRemappingClassVisitor(tinyRemapper.environment.remapper, traceClassVisitor), 0)
val d2Regex = Regex("(d2=)(.*)")
val asm = stringWriter.toString()
println(d2Regex.find(asm)?.value)
}
private fun getClassBytes(name: String): ByteArray {
return File("src/test/resources/classes/$name.class").readBytes()
}
private fun readMappings(name: String): IMappingProvider {
val mappingTree = MemoryMappingTree()
MappingReader.read(Paths.get("src/test/resources/mappings/$name.mappings"), mappingTree)
return TinyRemapperHelper.create(mappingTree, "named", "intermediary", false)
}
private class TextifierImpl : Textifier(Opcodes.ASM9)
}

Binary file not shown.

View File

@ -0,0 +1,220 @@
tiny 2 0 intermediary named
c net/minecraft/class_2338 net/minecraft/util/math/BlockPos
c Represents the position of a block in a three-dimensional volume.\n\n<p>The position is integer-valued.\n\n<p>A block position may be mutable; hence, when using block positions\nobtained from other places as map keys, etc., you should call {@link\n#toImmutable()} to obtain an immutable block position.
f J field_10976 BITS_X
f Lcom/mojang/serialization/Codec; field_25064 CODEC
f Lorg/apache/logging/log4j/Logger; field_18789 LOGGER
f Lnet/minecraft/class_2338; field_10980 ORIGIN
c The block position which x, y, and z values are all zero.
f I field_10983 BIT_SHIFT_Z
f I field_10975 SIZE_BITS_Y
f J field_10974 BITS_Y
f I field_10978 SIZE_BITS_X
f I field_10981 BIT_SHIFT_X
f J field_10973 BITS_Z
f I field_10977 SIZE_BITS_Z
m ([I)Lnet/minecraft/class_2338; method_29095 method_29095
p 0 values
m (Ljava/util/Random;IIIIIII)Ljava/lang/Iterable; method_27156 iterateRandomly
c Iterates through {@code count} random block positions in the given area.\n\n<p>The iterator yields positions in no specific order. The same position\nmay be returned multiple times by the iterator.
p 6 maxY
c the maximum y value for returned positions
p 7 maxZ
c the maximum z value for returned positions
p 4 minZ
c the minimum z value for returned positions
p 5 maxX
c the maximum x value for returned positions
p 2 minX
c the minimum x value for returned positions
p 3 minY
c the minimum y value for returned positions
p 0 random
c the {@link Random} object used to compute new positions
p 1 count
c the number of positions to iterate
m (JIII)J method_10096 add
p 0 value
p 3 y
p 2 x
p 4 z
m ()Lnet/minecraft/class_2338$class_2339; method_25503 mutableCopy
c Returns a mutable copy of this block position.\n\n<p>If this block position is a mutable one, mutation to this block\nposition won't affect the returned position.
m (I)Lnet/minecraft/class_2338; method_10088 west
p 1 distance
m (I)Lnet/minecraft/class_2338; method_10076 north
p 1 distance
m ()J method_10063 asLong
m ()Lnet/minecraft/class_2338; method_10084 up
m (Lnet/minecraft/class_2382;)V <init> <init>
p 1 pos
m (Lnet/minecraft/class_2338;III)Ljava/util/stream/Stream; method_25998 streamOutwards
p 0 center
p 3 maxZ
p 1 maxX
p 2 maxY
m (Lnet/minecraft/class_2374;)V <init> <init>
p 1 pos
m (Lnet/minecraft/class_2382;)Lnet/minecraft/class_2338; method_10081 add
m (Lnet/minecraft/class_238;)Ljava/util/stream/Stream; method_29715 stream
p 0 box
m ()Lnet/minecraft/class_2338; method_10072 south
m (III)Lnet/minecraft/class_2338; method_10069 add
m (I)Lnet/minecraft/class_2338; method_35830 multiply
m (Ljava/util/Random;ILnet/minecraft/class_2338;I)Ljava/lang/Iterable; method_34848 iterateRandomly
c Iterates through {@code count} random block positions in a given range around the given position.\n\n<p>The iterator yields positions in no specific order. The same position\nmay be returned multiple times by the iterator.
p 0 random
c the {@link Random} object used to compute new positions
p 1 count
c the number of positions to iterate
p 2 around
c the {@link BlockPos} to iterate around
p 3 range
c the maximum distance from the given pos in any axis
m (I)Lnet/minecraft/class_2338; method_10077 south
p 1 distance
m (I)Lnet/minecraft/class_2338; method_10089 east
p 1 distance
m (J)J method_10091 removeChunkSectionLocalY
p 0 y
m (J)I method_10071 unpackLongY
p 0 packedPos
m (Lnet/minecraft/class_2338;ILnet/minecraft/class_2350;Lnet/minecraft/class_2350;)Ljava/lang/Iterable; method_30512 iterateInSquare
c Iterates block positions around the {@code center} in a square of\n({@code 2 * radius + 1}) by ({@code 2 * radius + 1}). The blocks\nare iterated in a (square) spiral around the center.\n\n<p>The first block returned is the center, then the iterator moves\na block towards the first direction, followed by moving along\nthe second direction.\n\n@throws IllegalStateException when the 2 directions lie on the same axis
p 2 firstDirection
c the direction the iterator moves first
p 3 secondDirection
c the direction the iterator moves after the first
p 0 center
c the center of iteration
p 1 radius
c the maximum chebychev distance
m (J)I method_10083 unpackLongZ
p 0 packedPos
m (J)Lnet/minecraft/class_2338; method_10092 fromLong
p 0 packedPos
m (I)Lnet/minecraft/class_2338; method_33096 withY
p 1 y
m (Ljava/util/stream/IntStream;)Lcom/mojang/serialization/DataResult; method_29094 method_29094
p 0 stream
m (Lnet/minecraft/class_2338;Lnet/minecraft/class_2338;)Ljava/util/stream/Stream; method_20437 stream
p 1 end
p 0 start
m (Lnet/minecraft/class_2350;)Lnet/minecraft/class_2338; method_10093 offset
m (I)Lnet/minecraft/class_2338; method_10086 up
p 1 distance
m (III)J method_10064 asLong
p 0 x
p 1 y
p 2 z
m ()Lnet/minecraft/class_2338; method_10074 down
m (IIIIII)Ljava/lang/Iterable; method_10094 iterate
p 1 startY
p 0 startX
p 3 endX
p 2 startZ
p 5 endZ
p 4 endY
m ()Lnet/minecraft/class_2338; method_10062 toImmutable
c Returns an immutable block position with the same x, y, and z as this\nposition.\n\n<p>This method should be called when a block position is used as map\nkeys as to prevent side effects of mutations of mutable block positions.
m ()Lnet/minecraft/class_2338; method_10078 east
m (Lnet/minecraft/class_3341;)Ljava/util/stream/Stream; method_23627 stream
p 0 box
m (Lnet/minecraft/class_2350;I)Lnet/minecraft/class_2338; method_10079 offset
m (Lnet/minecraft/class_2338;III)Ljava/lang/Iterable; method_25996 iterateOutwards
c Iterates block positions around the {@code center}. The iteration order\nis mainly based on the manhattan distance of the position from the\ncenter.\n\n<p>For the same manhattan distance, the positions are iterated by y\noffset, from negative to positive. For the same y offset, the positions\nare iterated by x offset, from negative to positive. For the two\npositions with the same x and y offsets and the same manhattan distance,\nthe one with a positive z offset is visited first before the one with a\nnegative z offset.
p 2 rangeY
c the maximum y difference from the center
p 3 rangeZ
c the maximum z difference from the center
p 0 center
c the center of iteration
p 1 rangeX
c the maximum x difference from the center
m (Lnet/minecraft/class_2338;)Ljava/util/stream/IntStream; method_29093 method_29093
p 0 pos
m (Lnet/minecraft/class_2382;)Lnet/minecraft/class_2338; method_10059 subtract
m (Lnet/minecraft/class_2382;)Lnet/minecraft/class_2338; method_10075 crossProduct
p 1 pos
m (IIIIII)Ljava/util/stream/Stream; method_17962 stream
p 1 startY
p 0 startX
p 3 endX
p 2 startZ
p 5 endZ
p 4 endY
m (Lnet/minecraft/class_2350$class_2351;I)Lnet/minecraft/class_2338; method_30513 offset
m (Lnet/minecraft/class_2338;IILjava/util/function/Predicate;)Ljava/util/Optional; method_25997 findClosest
p 3 condition
p 1 horizontalRange
p 2 verticalRange
p 0 pos
m (I)Lnet/minecraft/class_2338; method_10087 down
m (DDD)Lnet/minecraft/class_2338; method_10080 add
m (Lnet/minecraft/class_2338;Lnet/minecraft/class_2338;)Ljava/lang/Iterable; method_10097 iterate
p 1 end
p 0 start
m ()Lnet/minecraft/class_2338; method_10095 north
m ()Lnet/minecraft/class_2338; method_10067 west
m (J)I method_10061 unpackLongX
p 0 packedPos
m (Lnet/minecraft/class_243;)V <init> <init>
p 1 pos
m (JLnet/minecraft/class_2350;)J method_10060 offset
p 2 direction
p 0 value
m (Lnet/minecraft/class_2470;)Lnet/minecraft/class_2338; method_10070 rotate
p 1 rotationrotate
c net/minecraft/class_1923 net/minecraft/util/math/ChunkPos
f I field_9180 z
f I field_9181 x
f Lnet/minecraft/class_1923; field_35107 ORIGIN
f J field_17348 MARKER
m ()Lnet/minecraft/class_2338; method_8323 getStartPos
m (Lnet/minecraft/class_1923;)I method_24022 getChebyshevDistance
p 1 pos
m ()J method_8324 toLong
m (II)J method_8331 toLong
p 1 chunkZ
p 0 chunkX
m ()I method_17887 getRegionRelativeX
m ()I method_17885 getRegionX
m (J)V <init> <init>
p 1 pos
m ()I method_33940 getCenterX
m (J)I method_8325 getPackedX
p 0 pos
m (Lnet/minecraft/class_2338;)V <init> <init>
p 1 pos
m ()I method_33942 getCenterZ
m ()I method_8326 getStartX
m ()I method_8328 getStartZ
m (III)Lnet/minecraft/class_2338; method_35231 getBlockPos
p 2 y
p 1 offsetX
p 3 offsetZ
m (I)I method_33939 getOffsetX
p 1 offset
m (Lnet/minecraft/class_1923;Lnet/minecraft/class_1923;)Ljava/util/stream/Stream; method_19281 stream
p 0 pos1
p 1 pos2
m (Lnet/minecraft/class_2338;)J method_37232 toLong
p 0 pos
m (I)I method_33941 getOffsetZ
p 1 offset
m ()I method_17888 getRegionRelativeZ
m (I)Lnet/minecraft/class_2338; method_33943 getCenterAtY
p 1 y
m ()I method_17886 getRegionZ
m ()I method_8327 getEndX
m (II)V <init> <init>
p 2 z
p 1 x
m ()I method_8329 getEndZ
m (J)I method_8332 getPackedZ
p 0 pos
m (Lnet/minecraft/class_1923;I)Ljava/util/stream/Stream; method_19280 stream
p 0 center
p 1 radius
m (Ljava/lang/Object;)Z equals equals
p 1 o

View File

@ -1,7 +1,8 @@
import java.util.Properties
plugins {
kotlin("jvm") version "1.5.21"
kotlin("jvm") version "1.6.10"
kotlin("plugin.serialization") version "1.6.10"
id("fabric-loom")
}
@ -15,6 +16,6 @@ version = "0.0.1"
dependencies {
minecraft(group = "com.mojang", name = "minecraft", version = "1.16.5")
mappings(group = "net.fabricmc", name = "yarn", version = "1.16.5+build.5", classifier = "v2")
modImplementation("net.fabricmc:fabric-loader:0.11.2")
modImplementation(group = "net.fabricmc", name = "fabric-language-kotlin", version = "1.6.3+kotlin.1.5.21")
modImplementation("net.fabricmc:fabric-loader:0.12.12")
modImplementation(group = "net.fabricmc", name = "fabric-language-kotlin", version = "1.7.1+kotlin.1.6.10")
}

View File

@ -0,0 +1,9 @@
package net.fabricmc.language.kotlin
import kotlinx.serialization.Serializable
import net.minecraft.util.Identifier
@Serializable
data class ExampleSerializable(@Serializable(with = IdentifierSerializer::class) val identifier: Identifier, val test: Double) {
}

View File

@ -0,0 +1,24 @@
package net.fabricmc.language.kotlin
import kotlinx.serialization.KSerializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import net.minecraft.util.Identifier
// Based on https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.descriptors/-primitive-serial-descriptor.html
class IdentifierSerializer : KSerializer<Identifier> {
override val descriptor =
PrimitiveSerialDescriptor("net.fabricmc.language.kotlin.IdentifierSerializer", PrimitiveKind.STRING)
override fun deserialize(decoder: Decoder): Identifier {
val split = decoder.decodeString().split(':')
return Identifier(split[0], split[1])
}
override fun serialize(encoder: Encoder, value: Identifier) {
encoder.encodeString("${value.namespace}:${value.path}")
}
}

View File

@ -0,0 +1,10 @@
package net.fabricmc.language.kotlin
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.ChunkPos
data class PosInChunk(val x: Int, val y: Int, val z: Int) {
constructor(blockPos: BlockPos) : this(blockPos.x and 15, blockPos.y, blockPos.z and 15)
fun getBlockPos(chunkPos: ChunkPos) = BlockPos(chunkPos.startX + x, y, chunkPos.startZ + z)
}

View File

@ -2,14 +2,22 @@ package net.fabricmc.language.kotlin
import net.fabricmc.api.ModInitializer
import org.apache.logging.log4j.LogManager
import kotlinx.serialization.*
import kotlinx.serialization.json.*
import net.minecraft.util.Identifier
class TestModClass : ModInitializer {
val logger = LogManager.getFormatterLogger("KotlinLanguageTest")
override fun onInitialize() {
val json = Json.encodeToString(ExampleSerializable(Identifier("kotlin:hello"), 12.0))
val obj = Json.decodeFromString<ExampleSerializable>(json)
logger.info("**************************")
logger.info("Hello from Kotlin TestModClass")
logger.info(json)
logger.info(obj)
logger.info("**************************")
}
}

View File

@ -2,32 +2,24 @@
"schemaVersion": 1,
"id": "modid",
"version": "${version}",
"name": "Example Mod",
"description": "This is an example description! Tell everyone what your mod is about!",
"authors": [
"Me!"
],
"contact": {
"homepage": "https://fabricmc.net/",
"sources": "https://github.com/FabricMC/fabric-example-mod"
},
"license": "CC0-1.0",
"environment": "*",
"entrypoints": {
"main": [
"net.fabricmc.language.kotlin.TestModClass"
{
"adapter": "kotlin",
"value": "net.fabricmc.language.kotlin.TestModClass"
}
]
},
"depends": {
"fabricloader": ">=0.7.4",
"fabric": "*",
"minecraft": "1.16.x"
},
"suggests": {
"another-mod": "*"
}
}