···77/** Target configuration for Diorama package. */
88data class DioramaConfig(
99 val assetsArchiveRomStart: Int,
1010- val engineSha: String
1110) {
1212- companion object {
1313- /** Standard ROM address for AssetsArchive in papermario-dx builds. */
1414- const val DEFAULT_ROM_START = 0x1E40000
1515- }
1611 /**
1712 * Generates target.json content.
1813 */
1914 fun toJson(): String {
2015 val json = Json { prettyPrint = false }
2116 val target = TargetJson(
1717+ version = 1,
2218 engine = PapermarioDxConfig(
2323- sha = engineSha,
2419 assets_archive_ROM_START = assetsArchiveRomStart
2520 )
2621 )
···29243025 @Serializable
3126 internal data class TargetJson(
2727+ val version: Int,
3228 val engine: PapermarioDxConfig
3329 )
34303531 @Serializable
3632 internal data class PapermarioDxConfig(
3737- val sha: String,
3833 val assets_archive_ROM_START: Int
3934 )
4035}
+5-32
src/main/java/project/Build.kt
···77import assets.archive.AssetsArchiveCompressor
88import assets.archive.DioramaArchiver
99import assets.archive.DioramaConfig
1010+import assets.archive.readMapfsRomStart
1011import kotlinx.coroutines.*
1112import kotlinx.coroutines.channels.Channel
1213import kotlinx.coroutines.future.future
···127128 headersDir.createDirectories()
128129129130 val stateFile = project.directory.toPath() / ".starrod" / "build-state" / "state.json"
130130- val engineSha = getEngineSha()
131131132132 // Load or create build state
133133- var buildState = BuildState.load(stateFile, engineSha)
133133+ var buildState = BuildState.load(stateFile)
134134 if (buildState == null) {
135135 Logger.log("Build state invalidated or missing, rebuilding all assets")
136136- buildState = BuildState.create(engineSha)
136136+ buildState = BuildState.create()
137137 }
138138139139 // Discover all assets
···171171 val ctx = BuildCtx(
172172 buildDir = buildDir,
173173 project = project,
174174- engineSha = engineSha,
175175- buildStateVersion = BuildState.CURRENT_VERSION,
176174 headersDir = headersDir
177175 )
178176···278276 }
279277280278 /**
281281- * Gets the current engine git SHA for cache invalidation.
282282- * Returns "unknown" if not in a git repository.
283283- */
284284- private fun getEngineSha(): String {
285285- return try {
286286- val process = ProcessBuilder("git", "rev-parse", "HEAD")
287287- .directory(project.directory)
288288- .redirectErrorStream(true)
289289- .start()
290290-291291- val sha = process.inputStream.bufferedReader().readText().trim()
292292- process.waitFor()
293293-294294- if (process.exitValue() == 0) sha else "unknown"
295295- } catch (e: Exception) {
296296- "unknown"
297297- }
298298- }
299299-300300- /**
301279 * Generates an AssetsArchive binary from built artifacts.
302280 * @return Path to the generated assets.bin
303281 */
···335313 Logger.log("Packaging Diorama...")
336314337315 val projectManifest = project.directory.toPath() / Manifest.FILENAME
338338- val engineSha = getEngineSha()
339339- val config = DioramaConfig(
340340- assetsArchiveRomStart = DioramaConfig.DEFAULT_ROM_START,
341341- engineSha = engineSha
342342- )
316316+ val start = readMapfsRomStart(project.engine.directory.resolve("ver/us/build/syms.ld"));
317317+ val config = DioramaConfig(start)
343318 val modId = project.manifest.id ?: "unknown"
344319 val outputPath = project.directory.toPath() / ".starrod" / "build" / "$modId.diorama"
345320346321 val archiver = DioramaArchiver(projectManifest, config, archivePath)
347322 archiver.createArchive(outputPath)
348348-349349- Logger.log("Diorama engine SHA: $engineSha")
350323 }
351324 }
352325}
-4
src/main/java/project/Project.kt
···4242 val engineAssetsDir: AssetsDir.Engine
4343 get() = assetDirectories.last() as AssetsDir.Engine
44444545- fun build() {
4646- // TODO
4747- }
4848-4945 companion object {
5046 /** Creates a new project from a template. */
5147 @JvmStatic
-6
src/main/java/project/build/BuildCtx.kt
···1616 /** Current project being built. */
1717 val project: Project,
18181919- /** Engine SHA for cache invalidation. */
2020- val engineSha: String,
2121-2222- /** Build state format version for migration. */
2323- val buildStateVersion: Int,
2424-2519 /** Directory containing generated headers. */
2620 val headersDir: Path
2721) {
+5-7
src/main/java/project/build/BuildState.kt
···1414 */
1515@Serializable
1616data class BuildState(
1717- val engineSha: String,
1817 val version: Int,
1918 val assetTimestamps: MutableMap<String, Long> = mutableMapOf(),
2019 val assetClassTimestamps: MutableMap<String, Long> = mutableMapOf()
···129128130129 /**
131130 * Load build state from disk, or create a fresh state if the file doesn't exist.
132132- * Returns null if the state is invalid (wrong engine SHA or version).
131131+ * Returns null if the state is invalid.
133132 */
134134- fun load(stateFile: Path, currentEngineSha: String): BuildState? {
133133+ fun load(stateFile: Path): BuildState? {
135134 if (!stateFile.exists())
136135 return null
137136138137 return try {
139138 val state = json.decodeFromString<BuildState>(stateFile.readText())
140140- // Invalidate if engine changed or version mismatch
141141- if (state.engineSha != currentEngineSha || state.version != CURRENT_VERSION) {
139139+ if (state.version != CURRENT_VERSION) {
142140 null
143141 } else {
144142 state
···152150 /**
153151 * Create a fresh build state.
154152 */
155155- fun create(engineSha: String): BuildState {
156156- return BuildState(engineSha, CURRENT_VERSION)
153153+ fun create(): BuildState {
154154+ return BuildState(CURRENT_VERSION)
157155 }
158156 }
159157}