From 8cd36fad170d9c63d6b0ca5b97ae0ef5f3d0220b Mon Sep 17 00:00:00 2001 From: Martin Haye Date: Fri, 11 Aug 2017 11:17:38 -0700 Subject: [PATCH] Added version stamp (encoded engine time, plus scenario differential) --- .../src/org/badvision/A2PackPartitions.groovy | 52 +++++++++++++++++-- .../Apple/virtual/src/plasma/gameloop.pla | 40 ++++++++++++-- 2 files changed, 85 insertions(+), 7 deletions(-) diff --git a/Platform/Apple/tools/PackPartitions/src/org/badvision/A2PackPartitions.groovy b/Platform/Apple/tools/PackPartitions/src/org/badvision/A2PackPartitions.groovy index 95e21027..f59e3ecc 100644 --- a/Platform/Apple/tools/PackPartitions/src/org/badvision/A2PackPartitions.groovy +++ b/Platform/Apple/tools/PackPartitions/src/org/badvision/A2PackPartitions.groovy @@ -19,6 +19,7 @@ import java.nio.ByteBuffer import java.nio.channels.Channels import java.nio.charset.StandardCharsets import java.nio.file.Files +import java.util.Calendar import java.util.zip.GZIPInputStream import java.util.LinkedHashMap import java.security.MessageDigest @@ -773,6 +774,12 @@ class A2PackPartitions cache[key] = [hash:hash, data:buf] } + def updateEngineStamp(name, hash) + { + if (!cache.containsKey("engineStamp") || cache["engineStamp"].hash < hash) + cache["engineStamp"] = [hash:hash] + } + def grabEntireFromCache(kind, addTo, hash) { if (cache.containsKey(kind) && cache[kind].hash == hash) { @@ -1559,6 +1566,30 @@ class A2PackPartitions } } + /** + * Make a compact representation of a timestamp, useful as a version number + */ + def timestampToVersionNum(engineStamp, scenarioStamp) + { + Calendar cal = Calendar.getInstance() + cal.setTimeInMillis(engineStamp) + def year = cal.get(Calendar.YEAR) + def month = cal.get(Calendar.MONTH) + def day = cal.get(Calendar.DAY_OF_MONTH) + def hour = cal.get(Calendar.HOUR_OF_DAY) + + def yearCode = year % 10 + def monthCode = (month < 9) ? (char) (48+month+1) : + month == 9 ? 'o' : + month == 10 ? 'n' : + 'd' + def hourCode = (char) (65 + hour) + def engineCode = String.format("%d%c%02d%c", yearCode, monthCode, day, hourCode) + + def offset = (int) ((scenarioStamp - engineStamp) / (1000 * 60 * 60)) + return String.format("%s%s%d", engineCode, offset < 0 ? "-" : ".", Math.abs(offset)) + } + /** * Make an index listing the partition number wherein each map and portrait can be found. */ @@ -1566,6 +1597,12 @@ class A2PackPartitions { def tmp = ByteBuffer.allocate(5000) + // Start with the version number + def combinedVersion = timestampToVersionNum(cache["engineStamp"].hash, cache["scenarioStamp"].hash) + tmp.put((byte)(combinedVersion.length())) + combinedVersion.getBytes().each { b -> tmp.put((byte)b) } + + // Then output 2D maps, 3d maps, and portraits tmp.put((byte) maps2D.size()) maps2D.each { k, v -> tmp.put((byte) ((parseOrder(v.order) < 0) ? 255 : v.buf.partNum)) @@ -1859,6 +1896,7 @@ class A2PackPartitions def uncompData = readBinary(inDir + "build/" + codeName + ".b") addToCache("code", code, codeName, hash, compress(uncompData)) + updateEngineStamp(codeName, hash) } def assembleCore(inDir) @@ -1878,8 +1916,10 @@ class A2PackPartitions def file = jitCopy( new File("build/tools/${name=="PRORWTS" ? "ProRWTS/PRORWTS2" : "PLASMA/src/PLVM02"}#4000")) hash = file.lastModified() - if (!grabFromCache("sysCode", sysCode, name, hash)) + if (!grabFromCache("sysCode", sysCode, name, hash)) { addToCache("sysCode", sysCode, name, hash, compress(readBinary(file.toString()))) + updateEngineStamp(name, hash) + } } else { hash = getLastDep(new File(inDir, "${name}.s")) @@ -1892,6 +1932,7 @@ class A2PackPartitions addToCache("sysCode", sysCode, name, hash, (name ==~ /loader|decomp/) ? [data:uncompData, len:uncompData.length, compressed:false] : compress(uncompData)) + updateEngineStamp(name, hash) } } @@ -1952,6 +1993,8 @@ class A2PackPartitions addToCache("modules", modules, moduleName, hash, module) addToCache("bytecodes", bytecodes, moduleName, hash, bytecode) addToCache("fixups", fixups, moduleName, hash, fixup) + if (!(moduleName ==~ /.*(gs|gen)_.*/ || codeDir ==~ /.*mapScript.*/)) + updateEngineStamp(moduleName, hash) } def readAllCode() @@ -2127,11 +2170,14 @@ class A2PackPartitions addResourceDep("map", curMapName, toType, toName) } - def pack(xmlPath, dataIn) + def pack(xmlFile, dataIn) { // Save time by using cache of previous run readCache() + // Record scenario timestamp + cache["scenarioStamp"] = [hash: xmlFile.lastModified()] + // Record global script names recordGlobalScripts(dataIn) @@ -3088,7 +3134,7 @@ end return [name.trim(), animFrameNum, animFlags] } - def dataGen(xmlPath, dataIn) + def dataGen(xmlFile, dataIn) { // When generating code, we need to use Unix linebreaks since that's what // the PLASMA compiler expects to see. diff --git a/Platform/Apple/virtual/src/plasma/gameloop.pla b/Platform/Apple/virtual/src/plasma/gameloop.pla index 173acaaf..ab627af5 100644 --- a/Platform/Apple/virtual/src/plasma/gameloop.pla +++ b/Platform/Apple/virtual/src/plasma/gameloop.pla @@ -1365,9 +1365,9 @@ def lookupResourcePart(sectionNum, resourceNum)#1 word ptr byte n - // Skip to the requested section + // Skip to the requested section (starting just after version num) ptr = pResourceIndex - while sectionNum > 1 + while sectionNum > 0 ptr = ptr + readAuxByte(ptr) + 1 sectionNum-- loop @@ -1405,6 +1405,36 @@ export def setGround(num)#0 needRender = TRUE end +/////////////////////////////////////////////////////////////////////////////////////////////////// +def printVersion()#0 + word p, len, cv, ch + if !pResourceIndex; return; fin + cv = ^$25 + ^$23 = 24 // full height window + ^$25 = 22 + crout() + ^$24 = 25 + puts("V ") + setWindow(183, 192, 168, 254) + clearWindow() + setWindow(183, 192, 175, 245) + rawDisplayStr("^YV ") + p = pResourceIndex + len = readAuxByte(p) + while len + p++ + ch = readAuxByte(p) + printChar(ch) + displayChar(ch) + len-- + loop + rawDisplayStr("^N") + ^$23 = 23 // shrink window to protect version num + ^$25 = cv-1 + crout() + setWindow2() +end + /////////////////////////////////////////////////////////////////////////////////////////////////// // Load the Frame Image, and lock it. export def loadFrameImg(img)#0 @@ -1435,6 +1465,9 @@ export def loadFrameImg(img)#0 // And show the first frame of the screen image showAnimFrame() + + // Brand the image with the version number + printVersion() else curFullscreenImg = NULL anyAnims = FALSE @@ -1847,7 +1880,7 @@ end def moveForward()#1 byte dir dir = getDir() - moveInternal(dir, dir, TRUE) + return moveInternal(dir, dir, TRUE) end /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -3091,7 +3124,6 @@ end /////////////////////////////////////////////////////////////////////////////////////////////////// // Main code. // -^$25 = 23 loadTitle() startGame(TRUE) // ask whether new or load kbdLoop()