mirror of
https://github.com/exogen/t2-mapper.git
synced 2026-03-12 08:51:45 +00:00
Initial commit
This commit is contained in:
commit
2211ed7650
10117 changed files with 735995 additions and 0 deletions
133
.gitignore
vendored
Normal file
133
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
.DS_Store
|
||||
.tshy
|
||||
18
app/layout.tsx
Normal file
18
app/layout.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import "./style.css";
|
||||
|
||||
export const metadata = {
|
||||
title: "Next.js",
|
||||
description: "Generated by Next.js",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
353
app/page.tsx
Normal file
353
app/page.tsx
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
"use client";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import * as THREE from "three";
|
||||
import {
|
||||
getActualResourcePath,
|
||||
getResourceList,
|
||||
getSource,
|
||||
} from "@/src/manifest";
|
||||
import { parseTerrainBuffer } from "@/src/terrain";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
||||
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
||||
import { getTerrainFile, parseMissionScript } from "@/src/mission";
|
||||
|
||||
const BASE_URL = "/t2-mapper";
|
||||
const RESOURCE_ROOT_URL = `${BASE_URL}/base/`;
|
||||
|
||||
function getUrlForPath(resourcePath: string) {
|
||||
resourcePath = getActualResourcePath(resourcePath);
|
||||
const sourcePath = getSource(resourcePath);
|
||||
if (!sourcePath) {
|
||||
return `${RESOURCE_ROOT_URL}${resourcePath}`;
|
||||
} else {
|
||||
return `${RESOURCE_ROOT_URL}@vl2/${sourcePath}/${resourcePath}`;
|
||||
}
|
||||
}
|
||||
|
||||
function terrainTextureToUrl(name: string) {
|
||||
name = name.replace(/^terrain\./, "");
|
||||
try {
|
||||
return getUrlForPath(`textures/terrain/${name}.png`);
|
||||
} catch (err) {
|
||||
return `${BASE_URL}/black.png`;
|
||||
}
|
||||
}
|
||||
|
||||
function uint16ToFloat32(src: Uint16Array) {
|
||||
const out = new Float32Array(src.length);
|
||||
for (let i = 0; i < src.length; i++) {
|
||||
out[i] = src[i] / 65535;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
async function loadMission(name: string) {
|
||||
const res = await fetch(getUrlForPath(`missions/${name}.mis`));
|
||||
const missionScript = await res.text();
|
||||
return parseMissionScript(missionScript);
|
||||
}
|
||||
|
||||
async function loadTerrain(fileName: string) {
|
||||
const res = await fetch(getUrlForPath(`terrains/${fileName}`));
|
||||
const terrainBuffer = await res.arrayBuffer();
|
||||
return parseTerrainBuffer(terrainBuffer);
|
||||
}
|
||||
|
||||
function resizeRendererToDisplaySize(renderer) {
|
||||
const canvas = renderer.domElement;
|
||||
const width = canvas.clientWidth;
|
||||
const height = canvas.clientHeight;
|
||||
const needResize = canvas.width !== width || canvas.height !== height;
|
||||
if (needResize) {
|
||||
renderer.setSize(width, height, false);
|
||||
}
|
||||
return needResize;
|
||||
}
|
||||
|
||||
const excludeMissions = new Set([
|
||||
"SkiFree",
|
||||
"SkiFree_Daily",
|
||||
"SkiFree_Randomizer",
|
||||
]);
|
||||
|
||||
const missions = getResourceList()
|
||||
.map((resourcePath) => resourcePath.match(/^missions\/(.+)\.mis$/))
|
||||
.filter(Boolean)
|
||||
.map((match) => match[1])
|
||||
.filter((name) => !excludeMissions.has(name));
|
||||
|
||||
export default function HomePage() {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const [missionName, setMissionName] = useState("TWL_Raindance");
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
const renderer = new THREE.WebGLRenderer({
|
||||
canvas,
|
||||
antialias: true,
|
||||
});
|
||||
|
||||
const textureLoader = new THREE.TextureLoader();
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
const camera = new THREE.PerspectiveCamera(
|
||||
75,
|
||||
canvas.clientWidth / canvas.clientHeight,
|
||||
0.1,
|
||||
2000
|
||||
);
|
||||
|
||||
function setupColor(tex) {
|
||||
tex.wrapS = tex.wrapT = THREE.RepeatWrapping; // Still need this for tiling to work
|
||||
tex.colorSpace = THREE.SRGBColorSpace;
|
||||
tex.anisotropy = renderer.capabilities.getMaxAnisotropy?.() ?? 16;
|
||||
tex.generateMipmaps = true;
|
||||
tex.minFilter = THREE.LinearMipmapLinearFilter;
|
||||
tex.magFilter = THREE.LinearFilter;
|
||||
return tex;
|
||||
}
|
||||
|
||||
function setupMask(data) {
|
||||
const tex = new THREE.DataTexture(
|
||||
data,
|
||||
256,
|
||||
256,
|
||||
THREE.RedFormat, // 1 channel
|
||||
THREE.UnsignedByteType // 8-bit
|
||||
);
|
||||
|
||||
// Masks should stay linear
|
||||
tex.colorSpace = THREE.NoColorSpace;
|
||||
|
||||
// Set tiling / sampling. For NPOT sizes, disable mips or use power-of-two.
|
||||
tex.wrapS = tex.wrapT = THREE.RepeatWrapping;
|
||||
tex.generateMipmaps = false; // if width/height are not powers of two
|
||||
tex.minFilter = THREE.LinearFilter; // avoid mips if generateMipmaps=false
|
||||
tex.magFilter = THREE.LinearFilter;
|
||||
|
||||
tex.needsUpdate = true;
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
async function loadMap() {
|
||||
const mission = await loadMission(missionName);
|
||||
const terrainFile = getTerrainFile(mission);
|
||||
const terrain = await loadTerrain(terrainFile);
|
||||
|
||||
const layerCount = terrain.textureNames.length;
|
||||
|
||||
console.log({ terrain });
|
||||
|
||||
const baseTextures = terrain.textureNames.map((name) => {
|
||||
return setupColor(textureLoader.load(terrainTextureToUrl(name)));
|
||||
});
|
||||
|
||||
const alphaTextures = terrain.alphaMaps.map((data) => setupMask(data));
|
||||
|
||||
// Geometry: a simple plane (512x512 meters to match Tribes 2 scale)
|
||||
const planeSize = 512;
|
||||
const geom = new THREE.PlaneGeometry(planeSize, planeSize, 256, 256);
|
||||
geom.rotateX(-Math.PI / 2);
|
||||
|
||||
const f32HeightMap = uint16ToFloat32(terrain.heightMap);
|
||||
|
||||
const heightMap = new THREE.DataTexture(
|
||||
f32HeightMap,
|
||||
256,
|
||||
256,
|
||||
THREE.RedFormat,
|
||||
THREE.FloatType
|
||||
);
|
||||
heightMap.colorSpace = THREE.NoColorSpace;
|
||||
heightMap.generateMipmaps = false;
|
||||
heightMap.needsUpdate = true;
|
||||
|
||||
// Start with a standard material; assign map to trigger USE_MAP/vMapUv
|
||||
const mat = new THREE.MeshStandardMaterial({
|
||||
// map: base0,
|
||||
displacementMap: heightMap,
|
||||
map: heightMap,
|
||||
// In Tribes 2, heightmap values are 0-0xFFFF (65535),
|
||||
// already converted to 0-1 range by uint16ToFloat32.
|
||||
// Scale by 2048 to match Tribes 2's height units in meters
|
||||
displacementScale: 512,
|
||||
displacementBias: -32,
|
||||
});
|
||||
|
||||
// Inject our 4-layer blend before lighting
|
||||
mat.onBeforeCompile = (shader) => {
|
||||
// uniforms for 4 albedo maps + 3 alpha masks
|
||||
baseTextures.forEach((tex, i) => {
|
||||
shader.uniforms[`albedo${i}`] = { value: tex };
|
||||
});
|
||||
alphaTextures.forEach((tex, i) => {
|
||||
if (i > 0) {
|
||||
shader.uniforms[`mask${i}`] = { value: tex };
|
||||
}
|
||||
});
|
||||
|
||||
// Add per-texture tiling uniforms
|
||||
baseTextures.forEach((tex, i) => {
|
||||
shader.uniforms[`tiling${i}`] = {
|
||||
value: Math.min(32, Math.pow(2, i + 2)),
|
||||
};
|
||||
});
|
||||
|
||||
// Declare our uniforms at the top of the fragment shader
|
||||
shader.fragmentShader =
|
||||
`
|
||||
uniform sampler2D albedo0;
|
||||
uniform sampler2D albedo1;
|
||||
uniform sampler2D albedo2;
|
||||
uniform sampler2D albedo3;
|
||||
uniform sampler2D albedo4;
|
||||
uniform sampler2D albedo5;
|
||||
uniform sampler2D mask1;
|
||||
uniform sampler2D mask2;
|
||||
uniform sampler2D mask3;
|
||||
uniform sampler2D mask4;
|
||||
uniform sampler2D mask5;
|
||||
uniform float tiling0;
|
||||
uniform float tiling1;
|
||||
uniform float tiling2;
|
||||
uniform float tiling3;
|
||||
uniform float tiling4;
|
||||
uniform float tiling5;
|
||||
` + shader.fragmentShader;
|
||||
|
||||
// Replace the default map sampling block with our layered blend.
|
||||
// We rely on vMapUv provided by USE_MAP.
|
||||
shader.fragmentShader = shader.fragmentShader.replace(
|
||||
"#include <map_fragment>",
|
||||
`
|
||||
// Sample base albedo layers (sRGB textures auto-decoded to linear)
|
||||
vec2 baseUv = vMapUv;
|
||||
vec3 c0 = texture2D(albedo0, baseUv * vec2(tiling0)).rgb;
|
||||
${
|
||||
layerCount > 1
|
||||
? `vec3 c1 = texture2D(albedo1, baseUv * vec2(tiling1)).rgb;`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
layerCount > 2
|
||||
? `vec3 c2 = texture2D(albedo2, baseUv * vec2(tiling2)).rgb;`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
layerCount > 3
|
||||
? `vec3 c3 = texture2D(albedo3, baseUv * vec2(tiling3)).rgb;`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
layerCount > 4
|
||||
? `vec3 c4 = texture2D(albedo4, baseUv * vec2(tiling4)).rgb;`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
layerCount > 5
|
||||
? `vec3 c5 = texture2D(albedo5, baseUv * vec2(tiling5)).rgb;`
|
||||
: ""
|
||||
}
|
||||
|
||||
// Sample linear masks (use R channel)
|
||||
float a1 = texture2D(mask1, baseUv).r;
|
||||
${layerCount > 1 ? `float a2 = texture2D(mask2, baseUv).r;` : ""}
|
||||
${layerCount > 2 ? `float a3 = texture2D(mask3, baseUv).r;` : ""}
|
||||
${layerCount > 3 ? `float a4 = texture2D(mask4, baseUv).r;` : ""}
|
||||
${layerCount > 4 ? `float a5 = texture2D(mask5, baseUv).r;` : ""}
|
||||
|
||||
// Bottom-up compositing: each mask tells how much the higher layer replaces lower
|
||||
${layerCount > 1 ? `vec3 blended = mix(c0, c1, clamp(a1, 0.0, 1.0));` : ""}
|
||||
${layerCount > 2 ? `blended = mix(blended, c2, clamp(a2, 0.0, 1.0));` : ""}
|
||||
${layerCount > 3 ? `blended = mix(blended, c3, clamp(a3, 0.0, 1.0));` : ""}
|
||||
${layerCount > 4 ? `blended = mix(blended, c4, clamp(a4, 0.0, 1.0));` : ""}
|
||||
${layerCount > 5 ? `blended = mix(blended, c5, clamp(a5, 0.0, 1.0));` : ""}
|
||||
|
||||
// Assign to diffuseColor before lighting
|
||||
diffuseColor.rgb = ${layerCount > 1 ? "blended" : "c0"};
|
||||
`
|
||||
);
|
||||
};
|
||||
|
||||
// for (let gx = -1; gx <= 1; gx++) {
|
||||
// for (let gz = -1; gz <= 1; gz++) {
|
||||
// }
|
||||
// }
|
||||
const mesh = new THREE.Mesh(geom, mat);
|
||||
// mesh.position.set(gx * planeSize, 0, gz * planeSize);
|
||||
scene.add(mesh);
|
||||
}
|
||||
|
||||
// const displacementMap = textureLoader.load("/heightmap.png");
|
||||
|
||||
// const planeMesh = new THREE.Mesh(
|
||||
// new THREE.PlaneGeometry(256, 256, 256, 256),
|
||||
// new THREE.MeshPhongMaterial({
|
||||
// side: THREE.DoubleSide,
|
||||
// displacementMap: displacementMap,
|
||||
// map: displacementMap,
|
||||
// displacementScale: 50,
|
||||
// })
|
||||
// );
|
||||
|
||||
// scene.add(planeMesh);
|
||||
|
||||
const controls = new OrbitControls(camera, renderer.domElement);
|
||||
|
||||
// const geometry = new THREE.BoxGeometry(1, 1, 1);
|
||||
// const material = new THREE.MeshPhongMaterial({
|
||||
// color: "rgba(255, 255, 255, 1)",
|
||||
// });
|
||||
// const cube = new THREE.Mesh(geometry, material);
|
||||
// scene.add(cube);
|
||||
|
||||
const skyColor = "rgba(209, 237, 255, 1)";
|
||||
const groundColor = "rgba(186, 200, 181, 1)";
|
||||
const intensity = 2;
|
||||
const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
|
||||
scene.add(light);
|
||||
|
||||
// const loader = new GLTFLoader();
|
||||
// loader.load("/flagstand.gltf", (gltf) => {
|
||||
// scene.add(gltf.scene); // gltf.scene is a THREE.Group containing the model
|
||||
// camera.position.set(0, 0, 300);
|
||||
// controls.update();
|
||||
// });
|
||||
|
||||
camera.position.set(100, 15, 100);
|
||||
camera.lookAt(0, 0, -200);
|
||||
controls.update();
|
||||
|
||||
const animate = () => {
|
||||
// cube.rotation.x += 0.01;
|
||||
// cube.rotation.y += 0.01;
|
||||
|
||||
if (resizeRendererToDisplaySize(renderer)) {
|
||||
const canvas = renderer.domElement;
|
||||
camera.aspect = canvas.clientWidth / canvas.clientHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
}
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
};
|
||||
renderer.setAnimationLoop(animate);
|
||||
|
||||
loadMap();
|
||||
}, [missionName]);
|
||||
|
||||
return (
|
||||
<main>
|
||||
<canvas ref={canvasRef} id="canvas" />
|
||||
<select
|
||||
id="missionList"
|
||||
value={missionName}
|
||||
onChange={(e) => setMissionName(e.target.value)}
|
||||
>
|
||||
{missions.map((missionName) => (
|
||||
<option key={missionName}>{missionName}</option>
|
||||
))}
|
||||
</select>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
17
app/style.css
Normal file
17
app/style.css
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
display: block;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
#missionList {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
}
|
||||
2736
generated/hxDif.cjs
Normal file
2736
generated/hxDif.cjs
Normal file
File diff suppressed because it is too large
Load diff
1465
generated/mission.cjs
Normal file
1465
generated/mission.cjs
Normal file
File diff suppressed because it is too large
Load diff
95
mission.pegjs
Normal file
95
mission.pegjs
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
start
|
||||
= document
|
||||
|
||||
document
|
||||
= body:statement* !. { return body.filter(Boolean); }
|
||||
|
||||
statement
|
||||
= comment
|
||||
/ instance
|
||||
/ definition
|
||||
/ datablock
|
||||
/ space+ { return null; }
|
||||
|
||||
comment
|
||||
= "//" text:$[^\n\r]* { return { type: 'comment', text }; }
|
||||
|
||||
datablock
|
||||
= "datablock " space* className:identifier space*
|
||||
"(" space* instanceName:objectName? space* ")" space*
|
||||
(":" space* baseName:objectName)? space*
|
||||
"{" body:body* "}" sep*
|
||||
{
|
||||
return {
|
||||
type: 'datablock',
|
||||
className,
|
||||
instanceName,
|
||||
body: body.filter(Boolean)
|
||||
}
|
||||
}
|
||||
|
||||
instance
|
||||
= "new " space* className:identifier space*
|
||||
"(" space* instanceName:objectName? space* ")" space*
|
||||
"{" body:body* "}" sep*
|
||||
{
|
||||
return {
|
||||
type: 'instance',
|
||||
className,
|
||||
instanceName,
|
||||
body: body.filter(Boolean)
|
||||
}
|
||||
}
|
||||
|
||||
body
|
||||
= space+ { return null; }
|
||||
/ definition
|
||||
/ instance
|
||||
/ comment
|
||||
|
||||
definition
|
||||
= target:lhs space* "=" space* value:rhs ";"?
|
||||
{ return { type: 'definition', target, value }; }
|
||||
|
||||
string
|
||||
= "\"" values:(escape / notDoubleQuote)* "\"" { return { type: 'string', value: values.join('') }; }
|
||||
/ "'" values:(escape / notSingleQuote)* "'" { return { type: 'string', value: values.join('') }; }
|
||||
|
||||
escape = "\\" char:. { return char}
|
||||
notDoubleQuote = $[^\\"]+
|
||||
notSingleQuote = $[^\\']+
|
||||
|
||||
space = [ \t\n\r] { return null; }
|
||||
|
||||
sep = ";"
|
||||
|
||||
identifier = $([$%]?[a-zA-Z][a-zA-Z0-9_]*)
|
||||
|
||||
objectName
|
||||
= identifier
|
||||
/ number
|
||||
|
||||
lhs = name:identifier index:index* { return { name, index }; }
|
||||
|
||||
rhs
|
||||
= string
|
||||
/ number
|
||||
/ instance
|
||||
/ boolean
|
||||
/ ref:identifier { return { type: 'reference', value: ref }; }
|
||||
|
||||
index = arrayIndex / propertyIndex
|
||||
|
||||
arrayIndex = "[" space* index:accessor space* "]" { return index; }
|
||||
|
||||
propertyIndex = "." index:identifier { return index; }
|
||||
|
||||
accessor
|
||||
= number
|
||||
/ identifier
|
||||
|
||||
number = digits:$[0-9.]+ { return { type: 'number', value: parseFloat(digits) }; }
|
||||
|
||||
boolean = literal:("true" / "false") { return { type: 'boolean', value: literal === "true" }; }
|
||||
|
||||
eol = "\n" / "\r\n" / "\r"
|
||||
6
next-env.d.ts
vendored
Normal file
6
next-env.d.ts
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
/// <reference path="./.next/types/routes.d.ts" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||
7
next.config.ts
Normal file
7
next.config.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
module.exports = {
|
||||
output: "export",
|
||||
distDir: process.env.NODE_ENV === "production" ? "./docs" : undefined,
|
||||
basePath: "/t2-mapper",
|
||||
assetPrefix: "/t2-mapper/",
|
||||
trailingSlash: true,
|
||||
};
|
||||
2015
package-lock.json
generated
Normal file
2015
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
31
package.json
Normal file
31
package.json
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "t2-mapper",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"author": "Brian Beck <exogen@gmail.com>",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build:parser": "peggy mission.pegjs -o generated/mission.cjs",
|
||||
"find": "find public -iname",
|
||||
"start": "next dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-three/fiber": "^9.3.0",
|
||||
"next": "^15.5.2",
|
||||
"peggy": "^5.0.6",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"three": "^0.180.0",
|
||||
"unzipper": "^0.12.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "24.3.1",
|
||||
"@types/react": "19.1.12",
|
||||
"@types/three": "^0.180.0",
|
||||
"@types/unzipper": "^0.10.11",
|
||||
"tsx": "^4.20.5",
|
||||
"typescript": "5.9.2"
|
||||
}
|
||||
}
|
||||
BIN
public/Perlin_noise_example.png
Normal file
BIN
public/Perlin_noise_example.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 336 KiB |
1417
public/base/@vl2/4thGradeDropout.vl2/missions/4thGradeDropout.mis
Normal file
1417
public/base/@vl2/4thGradeDropout.vl2/missions/4thGradeDropout.mis
Normal file
File diff suppressed because it is too large
Load diff
Binary file not shown.
3099
public/base/@vl2/BeneathTheHill.vl2/missions/BeneathTheHill.mis
Normal file
3099
public/base/@vl2/BeneathTheHill.vl2/missions/BeneathTheHill.mis
Normal file
File diff suppressed because it is too large
Load diff
BIN
public/base/@vl2/BeneathTheHill.vl2/terrains/BeneathTheHill.spn
Normal file
BIN
public/base/@vl2/BeneathTheHill.vl2/terrains/BeneathTheHill.spn
Normal file
Binary file not shown.
8
public/base/@vl2/Classic_maps_v1.vl2/classic_maps.txt
Normal file
8
public/base/@vl2/Classic_maps_v1.vl2/classic_maps.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
Tribes2 Classic map pack version 2
|
||||
10/31/02
|
||||
|
||||
The "classic_maps_v1.vl2" file should be put into
|
||||
your "...\Tribes2\GameData\base" directory, overwriting
|
||||
any existing earlier version.
|
||||
|
||||
See the "classic_readme.txt" file for a list of changes.
|
||||
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/Starfallen.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/Starfallen.dif
Normal file
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/bbase_ccb5.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/bbase_ccb5.dif
Normal file
Binary file not shown.
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/bbunke.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/bbunke.dif
Normal file
Binary file not shown.
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/bmisc_nefvbay.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/bmisc_nefvbay.dif
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/dbunk_vbunk1.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/dbunk_vbunk1.dif
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/dmisc_nefobj1.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/dmisc_nefobj1.dif
Normal file
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/dmisc_nefobj2.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/dmisc_nefobj2.dif
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/flagbridge.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/flagbridge.dif
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/pbunk4a_CC.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/pbunk4a_CC.dif
Normal file
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/pbunk7a_CC.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/pbunk7a_CC.dif
Normal file
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ram_base.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ram_base.dif
Normal file
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ram_tower.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ram_tower.dif
Normal file
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ram_wall4.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ram_wall4.dif
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ruin1.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ruin1.dif
Normal file
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ruin2.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ruin2.dif
Normal file
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ruin3.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ruin3.dif
Normal file
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ruin4.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ruin4.dif
Normal file
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ruinarch.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/ruinarch.dif
Normal file
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/sbunk_nef1.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/sbunk_nef1.dif
Normal file
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/siege.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/siege.dif
Normal file
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/smisc_nef1.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/smisc_nef1.dif
Normal file
Binary file not shown.
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/t_bbase_ccb2a.dif
Normal file
BIN
public/base/@vl2/Classic_maps_v1.vl2/interiors/t_bbase_ccb2a.dif
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1549
public/base/@vl2/Classic_maps_v1.vl2/missions/AcidRain.mis
Normal file
1549
public/base/@vl2/Classic_maps_v1.vl2/missions/AcidRain.mis
Normal file
File diff suppressed because it is too large
Load diff
1556
public/base/@vl2/Classic_maps_v1.vl2/missions/Blastside_nef.mis
Normal file
1556
public/base/@vl2/Classic_maps_v1.vl2/missions/Blastside_nef.mis
Normal file
File diff suppressed because it is too large
Load diff
1452
public/base/@vl2/Classic_maps_v1.vl2/missions/Broadside_nef.mis
Normal file
1452
public/base/@vl2/Classic_maps_v1.vl2/missions/Broadside_nef.mis
Normal file
File diff suppressed because it is too large
Load diff
1656
public/base/@vl2/Classic_maps_v1.vl2/missions/Confusco.mis
Normal file
1656
public/base/@vl2/Classic_maps_v1.vl2/missions/Confusco.mis
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
3774
public/base/@vl2/Classic_maps_v1.vl2/missions/DesertofDeath_nef.mis
Normal file
3774
public/base/@vl2/Classic_maps_v1.vl2/missions/DesertofDeath_nef.mis
Normal file
File diff suppressed because it is too large
Load diff
3121
public/base/@vl2/Classic_maps_v1.vl2/missions/Gorgon.mis
Normal file
3121
public/base/@vl2/Classic_maps_v1.vl2/missions/Gorgon.mis
Normal file
File diff suppressed because it is too large
Load diff
2074
public/base/@vl2/Classic_maps_v1.vl2/missions/Hillside.mis
Normal file
2074
public/base/@vl2/Classic_maps_v1.vl2/missions/Hillside.mis
Normal file
File diff suppressed because it is too large
Load diff
1897
public/base/@vl2/Classic_maps_v1.vl2/missions/IceRidge_nef.mis
Normal file
1897
public/base/@vl2/Classic_maps_v1.vl2/missions/IceRidge_nef.mis
Normal file
File diff suppressed because it is too large
Load diff
1951
public/base/@vl2/Classic_maps_v1.vl2/missions/Lakefront.mis
Normal file
1951
public/base/@vl2/Classic_maps_v1.vl2/missions/Lakefront.mis
Normal file
File diff suppressed because it is too large
Load diff
1573
public/base/@vl2/Classic_maps_v1.vl2/missions/Magmatic.mis
Normal file
1573
public/base/@vl2/Classic_maps_v1.vl2/missions/Magmatic.mis
Normal file
File diff suppressed because it is too large
Load diff
1849
public/base/@vl2/Classic_maps_v1.vl2/missions/Raindance_nef.mis
Normal file
1849
public/base/@vl2/Classic_maps_v1.vl2/missions/Raindance_nef.mis
Normal file
File diff suppressed because it is too large
Load diff
6013
public/base/@vl2/Classic_maps_v1.vl2/missions/Ramparts.mis
Normal file
6013
public/base/@vl2/Classic_maps_v1.vl2/missions/Ramparts.mis
Normal file
File diff suppressed because it is too large
Load diff
2647
public/base/@vl2/Classic_maps_v1.vl2/missions/Rollercoaster_nef.mis
Normal file
2647
public/base/@vl2/Classic_maps_v1.vl2/missions/Rollercoaster_nef.mis
Normal file
File diff suppressed because it is too large
Load diff
1985
public/base/@vl2/Classic_maps_v1.vl2/missions/Sandstorm.mis
Normal file
1985
public/base/@vl2/Classic_maps_v1.vl2/missions/Sandstorm.mis
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue