map viewer
This commit is contained in:
parent
93bc6e7a07
commit
2b1f1a0191
15 changed files with 2355 additions and 40 deletions
110
psx-map-exporter/viewer/vite.config.js
Normal file
110
psx-map-exporter/viewer/vite.config.js
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import { defineConfig } from 'vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs/promises';
|
||||
|
||||
const RENDER_ROOT = path.resolve(__dirname, '..', '.output-render');
|
||||
const CACHE_ROOT = path.resolve(__dirname, '..', '.cache');
|
||||
|
||||
// Tiny dev plugin that exposes the .output-render directory at /render and
|
||||
// serves a /api/index endpoint enumerating maps and variants. Keeps the app
|
||||
// dependency-free of any external server.
|
||||
function renderRootPlugin() {
|
||||
return {
|
||||
name: 'psx-render-root',
|
||||
configureServer(server) {
|
||||
server.middlewares.use('/render', async (req, res, next) => {
|
||||
try {
|
||||
const url = decodeURIComponent(req.url.split('?')[0]);
|
||||
const filePath = path.join(RENDER_ROOT, url);
|
||||
if (!filePath.startsWith(RENDER_ROOT)) {
|
||||
res.statusCode = 403;
|
||||
res.end('Forbidden');
|
||||
return;
|
||||
}
|
||||
const stat = await fs.stat(filePath);
|
||||
if (stat.isDirectory()) {
|
||||
const entries = await fs.readdir(filePath, { withFileTypes: true });
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.end(JSON.stringify(entries.map((e) => ({ name: e.name, isDir: e.isDirectory() }))));
|
||||
return;
|
||||
}
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
const mime = ext === '.png' ? 'image/png'
|
||||
: ext === '.json' ? 'application/json'
|
||||
: ext === '.log' ? 'text/plain'
|
||||
: 'application/octet-stream';
|
||||
res.setHeader('Content-Type', mime);
|
||||
res.setHeader('Cache-Control', 'no-cache');
|
||||
const data = await fs.readFile(filePath);
|
||||
res.end(data);
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
res.statusCode = 404;
|
||||
res.end('Not found');
|
||||
return;
|
||||
}
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
server.middlewares.use('/api/index', async (req, res) => {
|
||||
try {
|
||||
const indexPath = path.join(RENDER_ROOT, 'index.json');
|
||||
const data = await fs.readFile(indexPath, 'utf8');
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.setHeader('Cache-Control', 'no-cache');
|
||||
res.end(data);
|
||||
} catch (error) {
|
||||
res.statusCode = 500;
|
||||
res.end(JSON.stringify({ error: error.message }));
|
||||
}
|
||||
});
|
||||
|
||||
// Serve per-map sprite cache: /sprites/<map>/bundle_<hex>/frame_NNN.png
|
||||
// The exporter writes individual decoded sprite PNGs into
|
||||
// <projectRoot>/.cache/<mapStem>/sprites/, sharing the cache between
|
||||
// both the auto and region01 variants of the same map (bundle decoding
|
||||
// is invariant to the record-set choice).
|
||||
server.middlewares.use('/sprites', async (req, res, next) => {
|
||||
try {
|
||||
const url = decodeURIComponent(req.url.split('?')[0]);
|
||||
// url like "/L2/bundle_00085c40/frame_000.png"
|
||||
// map to "<CACHE_ROOT>/L2/sprites/bundle_00085c40/frame_000.png"
|
||||
const segments = url.split('/').filter(Boolean);
|
||||
if (segments.length < 2) {
|
||||
res.statusCode = 404;
|
||||
res.end('Not found');
|
||||
return;
|
||||
}
|
||||
const [mapStem, ...rest] = segments;
|
||||
const filePath = path.join(CACHE_ROOT, mapStem, 'sprites', ...rest);
|
||||
if (!filePath.startsWith(CACHE_ROOT)) {
|
||||
res.statusCode = 403;
|
||||
res.end('Forbidden');
|
||||
return;
|
||||
}
|
||||
const data = await fs.readFile(filePath);
|
||||
res.setHeader('Content-Type', 'image/png');
|
||||
res.setHeader('Cache-Control', 'no-cache');
|
||||
res.end(data);
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
res.statusCode = 404;
|
||||
res.end('Not found');
|
||||
return;
|
||||
}
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue(), renderRootPlugin()],
|
||||
server: {
|
||||
port: 5180,
|
||||
strictPort: false,
|
||||
},
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue