Move public assets to stable paths
This commit is contained in:
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Preserve downloadable files exactly and keep the Unix wrapper runnable on macOS.
|
||||||
|
*.jar binary
|
||||||
|
*.webp binary
|
||||||
|
minecraft/gradlew text eol=lf
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,5 +10,7 @@ artifacts/
|
|||||||
**/build/
|
**/build/
|
||||||
playwright-report/
|
playwright-report/
|
||||||
test-results/
|
test-results/
|
||||||
|
# Local renderer outputs and legacy build copies. The site's example image in
|
||||||
|
# public/images/ and distributable JARs in public/tools/ are committed to Git.
|
||||||
public/generated/
|
public/generated/
|
||||||
public/downloads/*.jar
|
public/downloads/*.jar
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { existsSync } from "node:fs";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
export default function Downloads() {
|
export default function Downloads() {
|
||||||
const fabric = existsSync("public/downloads/minegeo-fabric-1.21.11.jar"),
|
const fabric = existsSync("public/tools/mod/minegeo-fabric-1.21.11.jar"),
|
||||||
plugin = existsSync("public/downloads/minegeo-plugin-1.21.11.jar");
|
plugin = existsSync("public/tools/plugin/minegeo-plugin-1.21.11.jar");
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Header />
|
<Header />
|
||||||
@@ -37,7 +37,7 @@ export default function Downloads() {
|
|||||||
{fabric ? (
|
{fabric ? (
|
||||||
<a
|
<a
|
||||||
className="button primary"
|
className="button primary"
|
||||||
href="/downloads/minegeo-fabric-1.21.11.jar"
|
href="/tools/mod/minegeo-fabric-1.21.11.jar"
|
||||||
download
|
download
|
||||||
>
|
>
|
||||||
<Download size={16} /> Download Fabric mod
|
<Download size={16} /> Download Fabric mod
|
||||||
@@ -68,7 +68,7 @@ export default function Downloads() {
|
|||||||
{plugin ? (
|
{plugin ? (
|
||||||
<a
|
<a
|
||||||
className="button primary"
|
className="button primary"
|
||||||
href="/downloads/minegeo-plugin-1.21.11.jar"
|
href="/tools/plugin/minegeo-plugin-1.21.11.jar"
|
||||||
download
|
download
|
||||||
>
|
>
|
||||||
<Download size={16} /> Download server plugin
|
<Download size={16} /> Download server plugin
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export default async function Home() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="map-art-frame">
|
<div className="map-art-frame">
|
||||||
<Image
|
<Image
|
||||||
src="/generated/paper-proof/map.webp"
|
src="/images/example-map.webp"
|
||||||
alt="Top-down map of the real Paper renderer test world"
|
alt="Top-down map of the real Paper renderer test world"
|
||||||
width={1024}
|
width={1024}
|
||||||
height={1024}
|
height={1024}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export function MapCard({ map, index = 0 }: { map: CardMap; index?: number }) {
|
|||||||
<Link className="map-card" href={`/servers/${map.id}`}>
|
<Link className="map-card" href={`/servers/${map.id}`}>
|
||||||
<div className="card-image">
|
<div className="card-image">
|
||||||
<Image
|
<Image
|
||||||
src={map.image || "/generated/paper-proof/map.webp"}
|
src={map.image || "/images/example-map.webp"}
|
||||||
alt={`${map.name} terrain`}
|
alt={`${map.name} terrain`}
|
||||||
fill
|
fill
|
||||||
unoptimized
|
unoptimized
|
||||||
|
|||||||
22
docs/shared-assets.md
Normal file
22
docs/shared-assets.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Files shared between development machines
|
||||||
|
|
||||||
|
Commit these website assets together with the source code:
|
||||||
|
|
||||||
|
- `public/images/example-map.webp` — homepage illustration and map-card fallback.
|
||||||
|
- `public/tools/mod/minegeo-fabric-1.21.11.jar` — Fabric mod download.
|
||||||
|
- `public/tools/plugin/minegeo-plugin-1.21.11.jar` — server plugin download.
|
||||||
|
|
||||||
|
Next.js serves these directly at `/images/example-map.webp`,
|
||||||
|
`/tools/mod/minegeo-fabric-1.21.11.jar`, and
|
||||||
|
`/tools/plugin/minegeo-plugin-1.21.11.jar`. They are deliberately tracked, so a
|
||||||
|
fresh checkout on macOS has the homepage image and both download buttons without
|
||||||
|
building Minecraft tools or running the renderer proof.
|
||||||
|
|
||||||
|
After changing the Java source, run `npm run java:build` with Java 21 installed.
|
||||||
|
The build copies the new JARs into `public/tools/`; commit those updated files too.
|
||||||
|
Gradle caches, intermediate build output, and generated test panoramas remain
|
||||||
|
ignored. The JARs contain Java bytecode and work across Windows, macOS, and Linux.
|
||||||
|
|
||||||
|
On the Mac, pull the commit, run `npm install`, and restart the development
|
||||||
|
server. For a production server, run `npm run build` and then `npm start`.
|
||||||
|
Keep that machine's Supabase credentials in its own `.env.local`.
|
||||||
BIN
public/images/example-map.webp
Normal file
BIN
public/images/example-map.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 396 KiB |
BIN
public/tools/mod/minegeo-fabric-1.21.11.jar
Normal file
BIN
public/tools/mod/minegeo-fabric-1.21.11.jar
Normal file
Binary file not shown.
BIN
public/tools/plugin/minegeo-plugin-1.21.11.jar
Normal file
BIN
public/tools/plugin/minegeo-plugin-1.21.11.jar
Normal file
Binary file not shown.
@@ -2,11 +2,11 @@ import { spawn } from "node:child_process";
|
|||||||
import { existsSync } from "node:fs";
|
import { existsSync } from "node:fs";
|
||||||
import { mkdir, copyFile } from "node:fs/promises";
|
import { mkdir, copyFile } from "node:fs/promises";
|
||||||
const windows = process.platform === "win32";
|
const windows = process.platform === "win32";
|
||||||
const command = windows ? "gradlew.bat" : "./gradlew";
|
const command = windows ? "gradlew.bat" : "sh";
|
||||||
const targets = process.argv.slice(2);
|
const targets = process.argv.slice(2);
|
||||||
if (!targets.length) targets.push(":plugin:build", ":fabric:build");
|
if (!targets.length) targets.push(":plugin:build", ":fabric:build");
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const child = spawn(command, targets, {
|
const child = spawn(command, windows ? targets : ["./gradlew", ...targets], {
|
||||||
cwd: "minecraft",
|
cwd: "minecraft",
|
||||||
stdio: "inherit",
|
stdio: "inherit",
|
||||||
shell: windows,
|
shell: windows,
|
||||||
@@ -16,9 +16,15 @@ await new Promise((resolve, reject) => {
|
|||||||
code === 0 ? resolve() : reject(new Error(`Gradle exited ${code}`)),
|
code === 0 ? resolve() : reject(new Error(`Gradle exited ${code}`)),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
await mkdir("public/downloads", { recursive: true });
|
|
||||||
for (const name of ["plugin", "fabric"]) {
|
for (const name of ["plugin", "fabric"]) {
|
||||||
|
const directory = `public/tools/${name === "fabric" ? "mod" : "plugin"}`;
|
||||||
const file = `minegeo-${name}-1.21.11.jar`,
|
const file = `minegeo-${name}-1.21.11.jar`,
|
||||||
path = `minecraft/${name}/build/libs/${file}`;
|
path = `minecraft/${name}/build/libs/${file}`;
|
||||||
if (existsSync(path)) await copyFile(path, `public/downloads/${file}`);
|
if (existsSync(path)) {
|
||||||
|
await mkdir(directory, { recursive: true });
|
||||||
|
await copyFile(path, `${directory}/${file}`);
|
||||||
|
console.log(
|
||||||
|
`Updated ${directory}/${file}. Include this JAR in your next commit.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,73 @@
|
|||||||
import {createClient} from '@supabase/supabase-js';
|
import { createClient } from "@supabase/supabase-js";
|
||||||
import {createHash,randomBytes} from 'node:crypto';
|
import { createHash, randomBytes } from "node:crypto";
|
||||||
import {mkdir,readFile,writeFile} from 'node:fs/promises';
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
||||||
import {existsSync} from 'node:fs';
|
import { existsSync } from "node:fs";
|
||||||
process.loadEnvFile('.env.local');
|
process.loadEnvFile(".env.local");
|
||||||
const client=createClient(process.env.NEXT_PUBLIC_SUPABASE_URL!,process.env.SUPABASE_SECRET_KEY!,{auth:{persistSession:false}});
|
const client = createClient(
|
||||||
function check<T>(r:{data:T,error:{message:string}|null}):NonNullable<T>{if(r.error)throw new Error(r.error.message);return r.data!;}
|
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||||
await mkdir('.data',{recursive:true});
|
process.env.SUPABASE_SECRET_KEY!,
|
||||||
if(!existsSync('.data/test-account.json')){
|
{ auth: { persistSession: false } },
|
||||||
const password=randomBytes(32).toString('hex'),token='mg_'+randomBytes(32).toString('hex'),email='minegeo-fixture-'+randomBytes(4).toString('hex')+'@example.com';
|
);
|
||||||
const {user}=check(await client.auth.admin.createUser({email,password,email_confirm:true}));if(!user)throw new Error('No fixture account returned');
|
function check<T>(r: {
|
||||||
check(await client.from('profiles').insert({id:user.id,display_name:'MineGeo test world',role:'moderator'}));
|
data: T;
|
||||||
check(await client.from('contributor_tokens').insert({owner_id:user.id,token_hash:createHash('sha256').update(token).digest('hex'),label:'Local integration fixture'}));
|
error: { message: string } | null;
|
||||||
await writeFile('.data/test-account.json',JSON.stringify({id:user.id,email,password,token}));
|
}): NonNullable<T> {
|
||||||
|
if (r.error) throw new Error(r.error.message);
|
||||||
|
return r.data!;
|
||||||
}
|
}
|
||||||
const manifest=JSON.parse(await readFile('.cache/paper-proof/plugins/MineGeo/export/manifest.json','utf8'));
|
await mkdir(".data", { recursive: true });
|
||||||
manifest.name='The First Expedition';manifest.serverName='MineGeo Test World';manifest.description='A real Paper 1.21.11 renderer test world: terrain, water and a builder’s outpost. Exported with no connected capture player. This small map is for trying MineGeo.';
|
if (!existsSync(".data/test-account.json")) {
|
||||||
await mkdir('.data/proof-upload',{recursive:true});
|
const password = randomBytes(32).toString("hex"),
|
||||||
await writeFile('.data/proof-upload/manifest.json',JSON.stringify(manifest));
|
token = "mg_" + randomBytes(32).toString("hex"),
|
||||||
await writeFile('.data/proof-upload/terrain.json.gz',await readFile('.cache/paper-proof/plugins/MineGeo/export/terrain.json.gz'));
|
email =
|
||||||
console.log('Fixture contributor and real Paper upload are ready. Credentials remain in ignored local files.');
|
"minegeo-fixture-" + randomBytes(4).toString("hex") + "@example.com";
|
||||||
|
const created = await client.auth.admin.createUser({
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
email_confirm: true,
|
||||||
|
});
|
||||||
|
if (created.error) throw new Error(created.error.message);
|
||||||
|
const user = created.data.user;
|
||||||
|
if (!user) throw new Error("No fixture account returned");
|
||||||
|
check(
|
||||||
|
await client
|
||||||
|
.from("profiles")
|
||||||
|
.insert({
|
||||||
|
id: user.id,
|
||||||
|
display_name: "MineGeo test world",
|
||||||
|
role: "moderator",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
await client
|
||||||
|
.from("contributor_tokens")
|
||||||
|
.insert({
|
||||||
|
owner_id: user.id,
|
||||||
|
token_hash: createHash("sha256").update(token).digest("hex"),
|
||||||
|
label: "Local integration fixture",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
await writeFile(
|
||||||
|
".data/test-account.json",
|
||||||
|
JSON.stringify({ id: user.id, email, password, token }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const manifest = JSON.parse(
|
||||||
|
await readFile(
|
||||||
|
".cache/paper-proof/plugins/MineGeo/export/manifest.json",
|
||||||
|
"utf8",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
manifest.name = "The First Expedition";
|
||||||
|
manifest.serverName = "MineGeo Test World";
|
||||||
|
manifest.description =
|
||||||
|
"A real Paper 1.21.11 renderer test world: terrain, water and a builder’s outpost. Exported with no connected capture player. This small map is for trying MineGeo.";
|
||||||
|
await mkdir(".data/proof-upload", { recursive: true });
|
||||||
|
await writeFile(".data/proof-upload/manifest.json", JSON.stringify(manifest));
|
||||||
|
await writeFile(
|
||||||
|
".data/proof-upload/terrain.json.gz",
|
||||||
|
await readFile(".cache/paper-proof/plugins/MineGeo/export/terrain.json.gz"),
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
"Fixture contributor and real Paper upload are ready. Credentials remain in ignored local files.",
|
||||||
|
);
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import { prepareAssets } from "./assets.mjs";
|
|||||||
if (!existsSync(".env.local")) await copyFile(".env.example", ".env.local");
|
if (!existsSync(".env.local")) await copyFile(".env.example", ".env.local");
|
||||||
await mkdir(".data", { recursive: true });
|
await mkdir(".data", { recursive: true });
|
||||||
await mkdir("public/generated", { recursive: true });
|
await mkdir("public/generated", { recursive: true });
|
||||||
await mkdir("public/downloads", { recursive: true });
|
await mkdir("public/tools/mod", { recursive: true });
|
||||||
|
await mkdir("public/tools/plugin", { recursive: true });
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const p = spawn(
|
const p = spawn(
|
||||||
process.execPath,
|
process.execPath,
|
||||||
|
|||||||
Reference in New Issue
Block a user