chore(scripts): include anim, missiles, overlays, entities, and world-graph in publish-packs
This commit is contained in:
parent
bdb3b4145a
commit
cccc6ff527
|
|
@ -163,55 +163,66 @@ npm run publish:packs # orphan 提交 + force push 覆盖本仓库
|
||||||
* loses everything on the first reset. Batching at ~10 MB keeps each push to a
|
* loses everything on the first reset. Batching at ~10 MB keeps each push to a
|
||||||
* few minutes and makes a retry cheap.
|
* few minutes and makes a retry cheap.
|
||||||
*/
|
*/
|
||||||
const MAX_BATCH_BYTES = 10 * 1024 * 1024
|
const MAX_BATCH_BYTES = 25 * 1024 * 1024
|
||||||
|
|
||||||
/** How many times to retry one push before giving up. */
|
/** How many times to retry one push before giving up. */
|
||||||
const PUSH_ATTEMPTS = 5
|
const PUSH_ATTEMPTS = 5
|
||||||
|
|
||||||
/** The order acts are published in, smallest first so the remote is usable early. */
|
/** The order pack directories are published in, smallest first so the remote is usable early. */
|
||||||
const ACT_ORDER = ['act4', 'act3', 'act5', 'act2', 'act1'] as const
|
const PACK_CATEGORIES = [
|
||||||
|
'anim',
|
||||||
|
'missiles',
|
||||||
|
'overlays',
|
||||||
|
'act4',
|
||||||
|
'act3',
|
||||||
|
'act5',
|
||||||
|
'act2',
|
||||||
|
'act1',
|
||||||
|
'entities',
|
||||||
|
] as const
|
||||||
|
|
||||||
/** One push batch: a set of map directories inside one act. */
|
/** One push batch: a set of relative paths inside one top-level pack directory. */
|
||||||
interface Batch {
|
interface Batch {
|
||||||
readonly act: string
|
readonly act: string
|
||||||
/** Paths relative to {@link PACKS_DIR}, e.g. `act1/1-act-1-town-townn1`. */
|
/** Paths relative to {@link PACKS_DIR}, e.g. `act1/1-act-1-town-townn1` or `entities/char-so.r8`. */
|
||||||
readonly paths: readonly string[]
|
readonly paths: readonly string[]
|
||||||
readonly bytes: number
|
readonly bytes: number
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Total size of a directory tree, in bytes.
|
* Total size of a file or directory tree, in bytes.
|
||||||
*
|
*
|
||||||
* @param dir - absolute path.
|
* @param target - absolute path.
|
||||||
* @returns bytes, `.git` excluded.
|
* @returns bytes, `.git` excluded.
|
||||||
*/
|
*/
|
||||||
function dirSize(dir: string): number {
|
function entrySize(target: string): number {
|
||||||
|
const st = statSync(target)
|
||||||
|
if (!st.isDirectory()) return st.size
|
||||||
let bytes = 0
|
let bytes = 0
|
||||||
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
for (const entry of readdirSync(target, { withFileTypes: true })) {
|
||||||
if (entry.name === '.git') continue
|
if (entry.name === '.git') continue
|
||||||
const path = join(dir, entry.name)
|
bytes += entrySize(join(target, entry.name))
|
||||||
if (entry.isDirectory()) bytes += dirSize(path)
|
|
||||||
else bytes += statSync(path).size
|
|
||||||
}
|
}
|
||||||
return bytes
|
return bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Split every act into batches of at most {@link MAX_BATCH_BYTES}.
|
* Split every top-level pack directory into batches of at most {@link MAX_BATCH_BYTES}.
|
||||||
*
|
*
|
||||||
* Map directories are never split, so a single oversized map becomes a batch of
|
* Direct child entries (map directories, overlay subdirectories, or individual asset files)
|
||||||
* its own. The order within an act is the directory listing order, sorted, so
|
* are never split, so a single oversized entry becomes a batch of its own. The order within
|
||||||
* the plan is stable across runs — which is what makes resuming safe.
|
* a category is the sorted directory listing order, so the plan is stable across runs —
|
||||||
|
* which is what makes resuming safe.
|
||||||
*
|
*
|
||||||
* @returns the batches, act by act in {@link ACT_ORDER}.
|
* @returns the batches, category by category in {@link PACK_CATEGORIES}.
|
||||||
*/
|
*/
|
||||||
function planBatches(): Batch[] {
|
function planBatches(): Batch[] {
|
||||||
const batches: Batch[] = []
|
const batches: Batch[] = []
|
||||||
for (const act of ACT_ORDER) {
|
for (const category of PACK_CATEGORIES) {
|
||||||
const actDir = join(PACKS_DIR, act)
|
const categoryDir = join(PACKS_DIR, category)
|
||||||
if (!existsSync(actDir)) continue
|
if (!existsSync(categoryDir)) continue
|
||||||
const maps = readdirSync(actDir, { withFileTypes: true })
|
const entries = readdirSync(categoryDir, { withFileTypes: true })
|
||||||
.filter(entry => entry.isDirectory())
|
.filter(entry => entry.name !== '.git')
|
||||||
.map(entry => entry.name)
|
.map(entry => entry.name)
|
||||||
.sort()
|
.sort()
|
||||||
|
|
||||||
|
|
@ -219,21 +230,16 @@ function planBatches(): Batch[] {
|
||||||
let currentBytes = 0
|
let currentBytes = 0
|
||||||
const flush = (): void => {
|
const flush = (): void => {
|
||||||
if (current.length === 0) return
|
if (current.length === 0) return
|
||||||
batches.push({ act, paths: current, bytes: currentBytes })
|
batches.push({ act: category, paths: current, bytes: currentBytes })
|
||||||
current = []
|
current = []
|
||||||
currentBytes = 0
|
currentBytes = 0
|
||||||
}
|
}
|
||||||
for (const map of maps) {
|
for (const name of entries) {
|
||||||
const bytes = dirSize(join(actDir, map))
|
const bytes = entrySize(join(categoryDir, name))
|
||||||
if (currentBytes > 0 && currentBytes + bytes > MAX_BATCH_BYTES) flush()
|
if (currentBytes > 0 && currentBytes + bytes > MAX_BATCH_BYTES) flush()
|
||||||
current.push(`${act}/${map}`)
|
current.push(`${category}/${name}`)
|
||||||
currentBytes += bytes
|
currentBytes += bytes
|
||||||
}
|
}
|
||||||
// Loose files directly under the act directory ride along in the last batch.
|
|
||||||
const loose = readdirSync(actDir, { withFileTypes: true })
|
|
||||||
.filter(entry => !entry.isDirectory())
|
|
||||||
.map(entry => `${act}/${entry.name}`)
|
|
||||||
for (const file of loose) current.push(file)
|
|
||||||
flush()
|
flush()
|
||||||
}
|
}
|
||||||
return batches
|
return batches
|
||||||
|
|
@ -350,8 +356,11 @@ try {
|
||||||
// Step 0: metadata and index.
|
// Step 0: metadata and index.
|
||||||
if (!committed('index.json', work)) {
|
if (!committed('index.json', work)) {
|
||||||
writeFileSync(join(work, 'README.md'), readme(stats, stamp))
|
writeFileSync(join(work, 'README.md'), readme(stats, stamp))
|
||||||
writeFileSync(join(work, '.gitattributes'), '*.png binary -diff\n*.json text eol=lf\n')
|
writeFileSync(join(work, '.gitattributes'), '*.png binary -diff\n*.r8 binary -diff\n*.json text eol=lf\n')
|
||||||
cpSync(join(PACKS_DIR, 'index.json'), join(work, 'index.json'))
|
cpSync(join(PACKS_DIR, 'index.json'), join(work, 'index.json'))
|
||||||
|
if (existsSync(join(PACKS_DIR, 'world-graph.json'))) {
|
||||||
|
cpSync(join(PACKS_DIR, 'world-graph.json'), join(work, 'world-graph.json'))
|
||||||
|
}
|
||||||
git(['add', '-A'], work)
|
git(['add', '-A'], work)
|
||||||
git([
|
git([
|
||||||
'-c', `user.name=${process.env['GIT_AUTHOR_NAME'] ?? 'Dao Tao'}`,
|
'-c', `user.name=${process.env['GIT_AUTHOR_NAME'] ?? 'Dao Tao'}`,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue