[Editor] Put MapObjectsCodeGenerator to work
This commit is contained in:
@@ -2,8 +2,7 @@ package com.bartlomiejpluta.base.internal.map;
|
||||
|
||||
import com.bartlomiejpluta.base.api.context.Context;
|
||||
import com.bartlomiejpluta.base.api.map.handler.MapHandler;
|
||||
import com.bartlomiejpluta.base.api.runner.GameRunner;
|
||||
|
||||
public interface MapInitializer {
|
||||
void run(final Context context, final GameRunner runner, final MapHandler handler);
|
||||
void run(final Context context, final MapHandler handler);
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ import com.bartlomiejpluta.base.editor.file.model.FileSystemNode
|
||||
import java.io.File
|
||||
|
||||
interface Compiler {
|
||||
fun compile(sourceDirectory: FileSystemNode, targetDirectory: File, classPath: Array<File> = emptyArray())
|
||||
fun compile(sourceDirectories: Array<FileSystemNode>, targetDirectory: File, classPath: Array<File> = emptyArray())
|
||||
}
|
||||
@@ -20,14 +20,14 @@ import javax.tools.ToolProvider
|
||||
class JDKCompiler : Compiler {
|
||||
private val compiler = ToolProvider.getSystemJavaCompiler()
|
||||
|
||||
override fun compile(sourceDirectory: FileSystemNode, targetDirectory: File, classPath: Array<File>) {
|
||||
override fun compile(sourceDirectories: Array<FileSystemNode>, targetDirectory: File, classPath: Array<File>) {
|
||||
val classpath = classPath.joinToString(";") { it.absolutePath }
|
||||
val options = listOf("-g", "-d", targetDirectory.absolutePath, "-classpath", classpath)
|
||||
|
||||
val collector = DiagnosticCollector<JavaFileObject>()
|
||||
|
||||
val manager = compiler.getStandardFileManager(collector, null, null)
|
||||
val sources = sourceDirectory.allChildren
|
||||
val sources = sourceDirectories.flatMap(FileSystemNode::allChildren)
|
||||
.filter { it.type == FileType.FILE }
|
||||
.mapNotNull { it as? FileSystemNode }
|
||||
.map { it.file }
|
||||
|
||||
@@ -17,8 +17,8 @@ import java.io.File
|
||||
class JaninoCompiler : Compiler {
|
||||
private val compilerFactory = CompilerFactory()
|
||||
|
||||
override fun compile(sourceDirectory: FileSystemNode, targetDirectory: File, classPath: Array<File>) = try {
|
||||
tryToCompile(sourceDirectory, targetDirectory, classPath)
|
||||
override fun compile(sourceDirectories: Array<FileSystemNode>, targetDirectory: File, classPath: Array<File>) = try {
|
||||
tryToCompile(sourceDirectories, targetDirectory, classPath)
|
||||
|
||||
/* Because Janino parser does not provide error handler for parsers:
|
||||
*
|
||||
@@ -38,8 +38,8 @@ class JaninoCompiler : Compiler {
|
||||
throw BuildException(Severity.ERROR, TAG, location, message, e)
|
||||
}
|
||||
|
||||
private fun tryToCompile(sourceDirectory: FileSystemNode, targetDirectory: File, classPath: Array<File>) {
|
||||
val compilationUnits = sourceDirectory.allChildren
|
||||
private fun tryToCompile(sourceDirectories: Array<FileSystemNode>, targetDirectory: File, classPath: Array<File>) {
|
||||
val compilationUnits = sourceDirectories.flatMap(FileSystemNode::allChildren)
|
||||
.filter { it.type == FileType.FILE }
|
||||
.map(::FileNodeResourceAdapter)
|
||||
.toTypedArray()
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.bartlomiejpluta.base.editor.code.build.generator
|
||||
|
||||
interface CodeGenerator {
|
||||
fun generate()
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.bartlomiejpluta.base.editor.code.build.generator
|
||||
|
||||
import com.bartlomiejpluta.base.api.context.Context
|
||||
import com.bartlomiejpluta.base.api.map.handler.MapHandler
|
||||
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.ObjectLayer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
import com.bartlomiejpluta.base.editor.project.context.ProjectContext
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
import com.bartlomiejpluta.base.internal.map.MapInitializer
|
||||
import com.squareup.javapoet.*
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Component
|
||||
import java.lang.String.format
|
||||
import java.time.Instant
|
||||
import java.time.format.DateTimeFormatter
|
||||
import javax.annotation.processing.Generated
|
||||
import javax.lang.model.element.Modifier
|
||||
|
||||
@Component
|
||||
class MapObjectsCodeGenerator : CodeGenerator {
|
||||
|
||||
@Autowired
|
||||
private lateinit var projectContext: ProjectContext
|
||||
|
||||
override fun generate() {
|
||||
projectContext.project?.let { project ->
|
||||
project.maps
|
||||
.map { it to projectContext.loadMap(it.uid) }
|
||||
.forEach { generateMapObjects(it.first, it.second, project) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateMapObjects(asset: GameMapAsset, map: GameMap, project: Project) {
|
||||
val runner = className(project.runner)
|
||||
|
||||
map.layers
|
||||
.mapNotNull { it as? ObjectLayer }
|
||||
.map { generateLayerClass(asset, map, it, runner) }
|
||||
.forEach { it.writeTo(project.buildGeneratedCodeDirectory) }
|
||||
}
|
||||
|
||||
private fun generateLayerClass(asset: GameMapAsset, map: GameMap, layer: ObjectLayer, runner: ClassName): JavaFile {
|
||||
val packageName = "com.bartlomiejpluta.base.generated.map"
|
||||
val className = ClassName.get(
|
||||
packageName,
|
||||
format("MapInitializer_%s\$\$Layer%d", map.uid.replace("-", "_"), map.layers.indexOf(layer))
|
||||
)
|
||||
|
||||
val annotation = AnnotationSpec.builder(Generated::class.java)
|
||||
.addMember("value", "\$S", GENERATOR_NAME)
|
||||
.addMember("date", "\$S", DateTimeFormatter.ISO_INSTANT.format(Instant.now()))
|
||||
.addMember("comments", "\$S", "Initializer for map '${asset.name}' (UID: ${asset.uid})")
|
||||
.build()
|
||||
|
||||
val handler = className(map.handler)
|
||||
val generatedClass = TypeSpec.classBuilder(className)
|
||||
.addSuperinterface(MapInitializer::class.java)
|
||||
.addModifiers(Modifier.FINAL, Modifier.PUBLIC)
|
||||
.addAnnotation(annotation)
|
||||
|
||||
layer.objects.forEach {
|
||||
MethodSpec.methodBuilder("_${it.x}x${it.y}")
|
||||
.addModifiers(Modifier.PRIVATE, Modifier.FINAL)
|
||||
.addParameter(Context::class.java, "context", Modifier.FINAL)
|
||||
.addParameter(runner, "runner", Modifier.FINAL)
|
||||
.addParameter(handler, "handler", Modifier.FINAL)
|
||||
.addParameter(TypeName.INT, "x", Modifier.FINAL)
|
||||
.addParameter(TypeName.INT, "y", Modifier.FINAL)
|
||||
.addCode(it.code)
|
||||
.build()
|
||||
.let(generatedClass::addMethod)
|
||||
}
|
||||
|
||||
val runMethod = MethodSpec.methodBuilder("run")
|
||||
.addAnnotation(Override::class.java)
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
|
||||
.addParameter(Context::class.java, "context", Modifier.FINAL)
|
||||
.addParameter(MapHandler::class.java, "handler", Modifier.FINAL)
|
||||
.addStatement("var customRunner = (\$T) context.getGameRunner()", runner)
|
||||
.addStatement("var customHandler = (\$T) handler", handler)
|
||||
|
||||
layer.objects.forEach {
|
||||
runMethod.addStatement("_${it.x}x${it.y}(context, customRunner, customHandler, ${it.x}, ${it.y})")
|
||||
}
|
||||
|
||||
generatedClass
|
||||
.addMethod(runMethod.build())
|
||||
|
||||
return JavaFile
|
||||
.builder(packageName, generatedClass.build())
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun className(canonical: String) = ClassName.get(
|
||||
canonical.substringBeforeLast("."),
|
||||
canonical.substringAfterLast(".")
|
||||
)
|
||||
|
||||
companion object {
|
||||
private val GENERATOR_NAME = MapObjectsCodeGenerator::class.java.canonicalName
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,14 @@ import com.bartlomiejpluta.base.editor.code.build.compiler.Compiler
|
||||
import com.bartlomiejpluta.base.editor.code.build.database.DatabaseAssembler
|
||||
import com.bartlomiejpluta.base.editor.code.build.exception.BuildException
|
||||
import com.bartlomiejpluta.base.editor.code.build.game.GameEngineProvider
|
||||
import com.bartlomiejpluta.base.editor.code.build.generator.CodeGenerator
|
||||
import com.bartlomiejpluta.base.editor.code.build.packager.JarPackager
|
||||
import com.bartlomiejpluta.base.editor.code.build.project.ProjectAssembler
|
||||
import com.bartlomiejpluta.base.editor.code.dependency.DependenciesProvider
|
||||
import com.bartlomiejpluta.base.editor.common.logs.enumeration.Severity
|
||||
import com.bartlomiejpluta.base.editor.event.AppendBuildLogsEvent
|
||||
import com.bartlomiejpluta.base.editor.event.ClearBuildLogsEvent
|
||||
import com.bartlomiejpluta.base.editor.file.model.FileSystemNode
|
||||
import com.bartlomiejpluta.base.editor.project.context.ProjectContext
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
@@ -24,6 +26,9 @@ class DefaultBuildPipelineService : BuildPipelineService {
|
||||
@Autowired
|
||||
private lateinit var dependenciesProvider: DependenciesProvider
|
||||
|
||||
@Autowired
|
||||
private lateinit var generators: List<CodeGenerator>
|
||||
|
||||
@Autowired
|
||||
private lateinit var compiler: Compiler
|
||||
|
||||
@@ -92,8 +97,15 @@ class DefaultBuildPipelineService : BuildPipelineService {
|
||||
eventbus.fire(AppendBuildLogsEvent(Severity.INFO, "Providing compile-time dependencies...", tag = TAG))
|
||||
val dependencies = dependenciesProvider.provideDependenciesTo(project.buildDependenciesDirectory)
|
||||
|
||||
eventbus.fire(AppendBuildLogsEvent(Severity.INFO, "Generating sources...", tag = TAG))
|
||||
generators.forEach(CodeGenerator::generate)
|
||||
|
||||
eventbus.fire(AppendBuildLogsEvent(Severity.INFO, "Compiling sources...", tag = TAG))
|
||||
compiler.compile(project.codeFSNode, project.buildClassesDirectory, dependencies.toTypedArray())
|
||||
compiler.compile(
|
||||
arrayOf(project.codeFSNode, FileSystemNode(project.buildGeneratedCodeDirectory)),
|
||||
project.buildClassesDirectory,
|
||||
dependencies.toTypedArray()
|
||||
)
|
||||
|
||||
eventbus.fire(AppendBuildLogsEvent(Severity.INFO, "Assembling game engine...", tag = TAG))
|
||||
engineProvider.provideBaseGameEngine(outputFile)
|
||||
|
||||
@@ -104,6 +104,10 @@ class Project {
|
||||
var buildOutDirectory by buildOutDirectoryProperty
|
||||
private set
|
||||
|
||||
val buildGeneratedCodeDirectoryProperty = SimpleObjectProperty<File>()
|
||||
var buildGeneratedCodeDirectory by buildGeneratedCodeDirectoryProperty
|
||||
private set
|
||||
|
||||
val buildDatabaseDumpFileProperty =
|
||||
createObjectBinding({ File(buildDatabaseDumpDirectory, DATABASE_DUMP_FILE) }, buildDatabaseDumpDirectoryProperty)
|
||||
val buildDatabaseDumpFile by buildDatabaseDumpFileProperty
|
||||
@@ -129,6 +133,7 @@ class Project {
|
||||
buildDirectory = File(it, BUILD_DIR)
|
||||
buildClassesDirectory = File(it, BUILD_CLASSES_DIR)
|
||||
buildDependenciesDirectory = File(it, BUILD_DEPENDENCIES_DIR)
|
||||
buildGeneratedCodeDirectory = File(it, BUILD_GENERATED_DIR)
|
||||
buildDatabaseDumpDirectory = File(it, BUILD_DATABASE_DUMP_DIR)
|
||||
buildOutDirectory = File(it, BUILD_OUT_DIR)
|
||||
}
|
||||
@@ -176,6 +181,7 @@ class Project {
|
||||
const val BUILD_CLASSES_DIR = "$BUILD_DIR/classes"
|
||||
const val BUILD_OUT_DIR = "$BUILD_DIR/out"
|
||||
const val BUILD_DEPENDENCIES_DIR = "$BUILD_DIR/dependencies"
|
||||
const val BUILD_GENERATED_DIR = "$BUILD_DIR/generated"
|
||||
const val BUILD_DATABASE_DUMP_DIR = "$BUILD_DIR/db"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user