diff --git a/build.gradle.kts b/build.gradle.kts index 8e4582f..356df65 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,6 @@ allprojects { group = "com.lehaine" - version = "0.8.1-b4" + version = "0.8.1-b5" } diff --git a/ldtk-api/src/commonMain/kotlin/com/lehaine/ldtk/Annotations.kt b/ldtk-api/src/commonMain/kotlin/com/lehaine/ldtk/Annotations.kt index 185bc15..f629f87 100644 --- a/ldtk-api/src/commonMain/kotlin/com/lehaine/ldtk/Annotations.kt +++ b/ldtk-api/src/commonMain/kotlin/com/lehaine/ldtk/Annotations.kt @@ -1,4 +1,11 @@ package com.lehaine.ldtk +import kotlin.reflect.KClass + @Target(AnnotationTarget.CLASS) -annotation class LDtkProject(val ldtkFileLocation: String, val name: String = "") \ No newline at end of file +@Retention(AnnotationRetention.RUNTIME) +annotation class LDtkProject( + val ldtkFileLocation: String, + val name: String = "", + val extendClass: KClass = Project::class +) \ No newline at end of file diff --git a/ldtk-api/src/commonMain/kotlin/com/lehaine/ldtk/Project.kt b/ldtk-api/src/commonMain/kotlin/com/lehaine/ldtk/Project.kt index 419c757..6331877 100644 --- a/ldtk-api/src/commonMain/kotlin/com/lehaine/ldtk/Project.kt +++ b/ldtk-api/src/commonMain/kotlin/com/lehaine/ldtk/Project.kt @@ -5,10 +5,14 @@ import com.soywiz.korio.file.std.resourcesVfs open class Project(val projectFilePath: String) { - val bgColorInt: Int - val bgColorHex: String - val worldLayout: WorldLayout - val defs: Definitions + var bgColorInt: Int = 0 + protected set + var bgColorHex: String = "#000000" + protected set + var worldLayout: WorldLayout? = null + protected set + var defs: Definitions? = null + protected set val tilesets = mutableMapOf() private val assetCache = mutableMapOf() @@ -31,16 +35,18 @@ open class Project(val projectFilePath: String) { } } - init { - val jsonString = runBlockingNoSuspensions { - resourcesVfs[projectFilePath].readString() + fun load() { + val jsonString = loadLDtkJson() + + if (jsonString.isEmpty()) { + error("An empty file was passed in.") } val json = LDtkApi.parseLDtkFile(jsonString) ?: error("Unable to parse LDtk file content!") defs = json.defs json.levelDefinitions.forEach { levelJson -> - val level = instantiateLevel(this, levelJson) + val level = instantiateLevel(levelJson) level?.let { _allUntypedLevels.add(it) } @@ -55,17 +61,23 @@ open class Project(val projectFilePath: String) { bgColorInt = hexToInt(json.bgColor) } - open fun instantiateLevel(project: Project, json: LevelDefinition): Level? { - return Level(project, json) + open fun instantiateLevel(json: LevelDefinition): Level? { + return Level(this, json) + } + + protected open fun loadLDtkJson(): String { + return runBlockingNoSuspensions { + resourcesVfs[projectFilePath].readString() + } } - fun getAsset(relativePath: String): ByteArray { - if (assetCache.contains(relativePath)) { - return assetCache[relativePath] ?: error("Unable to load asset from asset cache!") + open fun getAsset(assetPath: String): ByteArray { + if (assetCache.contains(assetPath)) { + return assetCache[assetPath] ?: error("Unable to load asset from asset cache!") } return runBlockingNoSuspensions { - resourcesVfs[relativePath].readBytes() + resourcesVfs[assetPath].readBytes() } } @@ -73,13 +85,13 @@ open class Project(val projectFilePath: String) { if (uid == null && identifier == null) { return null } - return defs.layers.find { it.uid == uid || it.identifier == identifier } + return defs?.layers?.find { it.uid == uid || it.identifier == identifier } } fun getTilesetDef(uid: Int?, identifier: String? = ""): TilesetDefinition? { if (uid == null && identifier == null) { return null } - return defs.tilesets.find { it.uid == uid || it.identifier == identifier } + return defs?.tilesets?.find { it.uid == uid || it.identifier == identifier } } } \ No newline at end of file diff --git a/ldtk-processor/build.gradle.kts b/ldtk-processor/build.gradle.kts index 51a77c2..3fc79e3 100644 --- a/ldtk-processor/build.gradle.kts +++ b/ldtk-processor/build.gradle.kts @@ -13,6 +13,7 @@ publishing { publications { create("ldtk-processor") { artifactId = "ldtk-processor" + from(components["java"]) } } } @@ -20,7 +21,10 @@ publishing { dependencies { implementation(kotlin("stdlib")) implementation(project(":ldtk-api")) + // implementation("com.lehaine:ldtk-api:$version") implementation("com.squareup:kotlinpoet:1.7.2") + implementation("com.squareup:kotlinpoet-metadata:1.7.2") + implementation("com.squareup:kotlinpoet-metadata-specs:1.7.2") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") implementation("com.google.auto.service:auto-service:1.0-rc7") kapt("com.google.auto.service:auto-service:1.0-rc7") diff --git a/ldtk-processor/src/main/kotlin/com/lehaine/ldtk/processor/ProjectProcessor.kt b/ldtk-processor/src/main/kotlin/com/lehaine/ldtk/processor/ProjectProcessor.kt index 95fd978..a54ebba 100644 --- a/ldtk-processor/src/main/kotlin/com/lehaine/ldtk/processor/ProjectProcessor.kt +++ b/ldtk-processor/src/main/kotlin/com/lehaine/ldtk/processor/ProjectProcessor.kt @@ -7,6 +7,7 @@ import com.lehaine.ldtk.LDtkApi.LAYER_PREFIX import com.lehaine.ldtk.LDtkApi.LEVEL_SUFFIX import com.squareup.kotlinpoet.* import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy +import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview import java.io.File import java.nio.file.Files import java.nio.file.Path @@ -16,6 +17,7 @@ import javax.annotation.processing.Processor import javax.annotation.processing.RoundEnvironment import javax.lang.model.SourceVersion import javax.lang.model.element.TypeElement +import javax.lang.model.type.MirroredTypeException import javax.tools.StandardLocation import kotlin.reflect.KClass @@ -50,10 +52,18 @@ open class ProjectProcessor : AbstractProcessor() { return SourceVersion.latest() } + @KotlinPoetMetadataPreview override fun process(annotations: MutableSet, roundEnv: RoundEnvironment): Boolean { roundEnv.getElementsAnnotatedWith(LDtkProject::class.java) .forEach { val ldtkProject = it.getAnnotation(LDtkProject::class.java) + var extendClass: TypeName? = null + try { + ldtkProject.extendClass + } catch (ex: MirroredTypeException) { + extendClass = ex.typeMirror.asTypeName() + } + val ldtkFileLocation = ldtkProject.ldtkFileLocation val className = if (ldtkProject.name.isBlank()) { "${it.simpleName}_" @@ -61,12 +71,12 @@ open class ProjectProcessor : AbstractProcessor() { ldtkProject.name } val pkg = processingEnv.elementUtils.getPackageOf(it).toString() - generateProject(className, pkg, ldtkFileLocation) + generateProject(className, pkg, ldtkFileLocation, extendClass!!) } return true } - private fun generateProject(className: String, pkg: String, ldtkFileLocation: String) { + private fun generateProject(className: String, pkg: String, ldtkFileLocation: String, extendClass: TypeName) { try { val resource = processingEnv.filer.createResource(StandardLocation.SOURCE_OUTPUT, "", "tmp_${className}", null) @@ -80,15 +90,14 @@ open class ProjectProcessor : AbstractProcessor() { val fileSpec = FileSpec.builder(pkg, className).indent(FILE_INDENT) val projectClassSpec = TypeSpec.classBuilder(className).apply { - superclass(Project::class) + superclass(extendClass) addSuperclassConstructorParameter("%S", ldtkFileLocation) addFunction( FunSpec.builder("instantiateLevel") .addModifiers(KModifier.OVERRIDE) - .addParameter("project", Project::class) .addParameter("json", LevelDefinition::class) .returns(Level::class) - .addStatement("return %L$LEVEL_SUFFIX(project, json)", className) + .addStatement("return %L$LEVEL_SUFFIX(this, json)", className) .build() ) } @@ -113,12 +122,15 @@ open class ProjectProcessor : AbstractProcessor() { PropertySpec.builder( "allLevels", List::class.asTypeName().parameterizedBy(levelClassType) - ).initializer( - CodeBlock.builder() - .beginControlFlow("allUntypedLevels.map") - .addStatement("it as %T", levelClassType) - .endControlFlow() - .build() + ).getter( + FunSpec.getterBuilder().addCode( + CodeBlock.builder() +// .beginControlFlow("allUntypedLevels.map") +// .addStatement("it as %T", levelClassType) +// .endControlFlow() + .addStatement("return allUntypedLevels as List<%T>", levelClassType) + .build() + ).build() ).build() ) diff --git a/libgdx-backend/build.gradle.kts b/libgdx-backend/build.gradle.kts index ec7c3fa..62d06b9 100644 --- a/libgdx-backend/build.gradle.kts +++ b/libgdx-backend/build.gradle.kts @@ -1,6 +1,6 @@ - repositories { mavenCentral() + mavenLocal() } tasks.named("jar") { @@ -13,6 +13,7 @@ publishing { publications { create("libgdx-backend") { artifactId = "libgdx-backend" + from(components["java"]) } } } @@ -20,6 +21,7 @@ publishing { dependencies { implementation(kotlin("stdlib")) implementation(project(":ldtk-api")) + // implementation("com.lehaine:ldtk-api:$version") implementation("com.badlogicgames.gdx:gdx-backend-lwjgl3:1.9.12") implementation("com.badlogicgames.gdx:gdx-platform:1.9.12") } \ No newline at end of file diff --git a/libgdx-ldtk-processor/build.gradle.kts b/libgdx-ldtk-processor/build.gradle.kts index 68be2c3..70ab12c 100644 --- a/libgdx-ldtk-processor/build.gradle.kts +++ b/libgdx-ldtk-processor/build.gradle.kts @@ -1,6 +1,7 @@ repositories { mavenCentral() + mavenLocal() } tasks.named("jar") { @@ -13,6 +14,7 @@ publishing { publications { create("libgdx-ldtk-processor") { artifactId = "libgdx-ldtk-processor" + from(components["java"]) } } } @@ -22,6 +24,9 @@ dependencies { implementation(project(":ldtk-api")) implementation(project(":libgdx-backend")) implementation(project(":ldtk-processor")) +// implementation("com.lehaine:ldtk-api-jvm:$version") +// implementation("com.lehaine:libgdx-backend:$version") +// implementation("com.lehaine:ldtk-processor:$version") implementation("com.google.auto.service:auto-service:1.0-rc7") kapt("com.google.auto.service:auto-service:1.0-rc7") } \ No newline at end of file diff --git a/samples/build.gradle.kts b/samples/build.gradle.kts index 336c525..e11e56a 100644 --- a/samples/build.gradle.kts +++ b/samples/build.gradle.kts @@ -3,6 +3,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType repositories { maven(url = "https://jitpack.io") mavenCentral() + mavenLocal() } configurations.all { @@ -23,6 +24,9 @@ dependencies { // implementation("com.lehaine.kt-ldtk-api:ldtk-api:-SNAPSHOT") // implementation("com.lehaine.kt-ldtk-api:libgdx-backend:-SNAPSHOT") // kapt("com.lehaine.kt-ldtk-api:libgdx-ldtk-processor:-SNAPSHOT") +// implementation("com.lehaine:ldtk-api:$version") +// implementation("com.lehaine:libgdx-backend:$version") +// kapt("com.lehaine:libgdx-ldtk-processor:$version") implementation("com.badlogicgames.gdx:gdx-backend-lwjgl3:1.9.12") implementation("com.badlogicgames.gdx:gdx-platform:1.9.12:natives-desktop") implementation("com.badlogicgames.gdx:gdx:1.9.12") diff --git a/samples/src/main/java/com/lehaine/samples/SampleJava.java b/samples/src/main/java/com/lehaine/samples/SampleJava.java index ebba52b..de61a61 100644 --- a/samples/src/main/java/com/lehaine/samples/SampleJava.java +++ b/samples/src/main/java/com/lehaine/samples/SampleJava.java @@ -11,30 +11,30 @@ public class SampleJava { public static void main(String[] args) { // create new LDtk world - JavaWorld world = new JavaWorld(); - - // get a level - JavaWorld.JavaWorldLevel level = world.getAllLevels().get(0); - - // iterate over a layers tiles - for (LayerAutoLayer.AutoTile tile : level.getLayerCavern_background().getAutoTiles()) { - // logic for handling the tile - int x = tile.getRenderX(); - } - - // iterate over entities - for (JavaWorld.EntityMob mob : level.getLayerEntities().getAllMob()) { - JavaWorld.MobType type = mob.type; - // field arrays / lists - List patrolPoint = mob.getPatrol(); - int health = mob.getHealth(); - } - - for (JavaWorld.EntityItem item : level.getLayerEntities().getAllItem()) { - if (item.type == JavaWorld.Items.Pickaxe) { - // spawn pickaxe - } - } +// JavaWorld world = new JavaWorld(); +// +// // get a level +// JavaWorld.JavaWorldLevel level = world.getAllLevels().get(0); +// +// // iterate over a layers tiles +// for (LayerAutoLayer.AutoTile tile : level.getLayerCavern_background().getAutoTiles()) { +// // logic for handling the tile +// int x = tile.getRenderX(); +// } +// +// // iterate over entities +// for (JavaWorld.EntityMob mob : level.getLayerEntities().getAllMob()) { +// JavaWorld.MobType type = mob.type; +// // field arrays / lists +// List patrolPoint = mob.getPatrol(); +// int health = mob.getHealth(); +// } +// +// for (JavaWorld.EntityItem item : level.getLayerEntities().getAllItem()) { +// if (item.type == JavaWorld.Items.Pickaxe) { +// // spawn pickaxe +// } +// } } } diff --git a/samples/src/main/kotlin/com/lehaine/samples/GdxTest.kt b/samples/src/main/kotlin/com/lehaine/samples/GdxTest.kt index 34faf78..2fa5740 100644 --- a/samples/src/main/kotlin/com/lehaine/samples/GdxTest.kt +++ b/samples/src/main/kotlin/com/lehaine/samples/GdxTest.kt @@ -27,7 +27,7 @@ class GdxApp : ApplicationListener { private lateinit var unitTestWorldTiles: Texture private lateinit var camera: OrthographicCamera private lateinit var viewport: FitViewport - private val world = World() + private val world = World().apply { load() } private var currentWorldIdx = 0 private var worldBgImage: TextureRegion? = null diff --git a/samples/src/main/kotlin/com/lehaine/samples/Sample.kt b/samples/src/main/kotlin/com/lehaine/samples/Sample.kt index de4597d..7e8a146 100644 --- a/samples/src/main/kotlin/com/lehaine/samples/Sample.kt +++ b/samples/src/main/kotlin/com/lehaine/samples/Sample.kt @@ -2,10 +2,14 @@ package com.lehaine.samples import com.lehaine.ldtk.LDtkProject import com.lehaine.ldtk.Point +import com.lehaine.ldtk.Project +import java.io.BufferedReader +import java.io.InputStream +import java.io.InputStreamReader // designate class for loading and attaching LDtk file to @LDtkProject(ldtkFileLocation = "sample.ldtk", name = "World") -class _World +open class _World(projectFilePath: String) @LDtkProject(ldtkFileLocation = "unitTest.ldtk", name = "UnitTestWorld") class _UnitTestWorld @@ -13,6 +17,8 @@ class _UnitTestWorld fun main(args: Array) { // create new LDtk world val world = World() + world.load() + // get a level val level: World.WorldLevel = world.allLevels[0] @@ -27,7 +33,7 @@ fun main(args: Array) { // access entity fields val type: World.MobType = mob.type // generated enum class // field arrays / lists - val patrolPoints: List? = mob.patrol // points + val patrolPoints: List = mob.patrol // points val health: Int = mob.health }