Atmosphäre-Tools, EZ-Tree-Fixes, i18n, AnimSet, Baum-Export
- blight-lang: TextResolver + EN/DE Sprachpakete (TextReference i18n) - AnimSet: Clips + ActionMap in .animset.json zusammengeführt - EZ-Tree: Branch-Parameter-Fixes (length/radius/children/force nicht senden, twist Grad→Radiant, leaves.size ×5); Ordner-ComboBox mit Auto-Refresh - Logging beim Baum-Export in allen drei Generatoren (EZ-Tree, Blight, Palme) - Atmosphäre-Tools: Emitter, Licht, Wasser, Sound-/Musikbereiche, Spiel-Starten - AnimPreviewState, RetargetingSystem, AnimationLibrary (Animations-Editor) - Terrain-Transparenz-Fix, Schatten-Fix, ThirdPersonCamera-Fix - DayNightState, WeatherState, CloudsNode, JmeConsole - MapIO v6, neue blight-common Modell-Klassen (GameCharacter, NPC, Quests…) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1
tools/.gitignore
vendored
Normal file
1
tools/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules/
|
||||
21
tools/dom_polyfill.cjs
Normal file
21
tools/dom_polyfill.cjs
Normal file
@@ -0,0 +1,21 @@
|
||||
// Minimal DOM polyfill so Three.js TextureLoader doesn't crash in Node.js
|
||||
global.document = {
|
||||
createElementNS: (ns, name) => ({
|
||||
style: {},
|
||||
addEventListener: () => {},
|
||||
removeEventListener: () => {},
|
||||
dispatchEvent: () => {},
|
||||
src: '',
|
||||
onload: null,
|
||||
onerror: null
|
||||
}),
|
||||
createElement: (name) => ({
|
||||
style: {},
|
||||
addEventListener: () => {},
|
||||
removeEventListener: () => {},
|
||||
src: '',
|
||||
onload: null,
|
||||
onerror: null
|
||||
})
|
||||
};
|
||||
global.window = global;
|
||||
123
tools/ez_tree_generate.mjs
Normal file
123
tools/ez_tree_generate.mjs
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Headless ez-tree geometry generator.
|
||||
* Usage: node --require ./dom_polyfill.cjs ez_tree_generate.mjs '<JSON>'
|
||||
*
|
||||
* Input JSON: { preset: "Oak Medium", params: { seed, type, bark, branch, leaves, trellis } }
|
||||
* Output JSON: { branches: { positions, normals, uvs, indices }, leaves: { ... } }
|
||||
*/
|
||||
|
||||
import { Tree, TreePreset } from '@dgreenheck/ez-tree';
|
||||
|
||||
const input = JSON.parse(process.argv[2] ?? '{}');
|
||||
const presetName = input.preset ?? 'Oak Medium';
|
||||
const params = input.params ?? {};
|
||||
|
||||
if (!TreePreset[presetName]) {
|
||||
process.stderr.write('Unknown preset: ' + presetName + '\n');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const options = structuredClone(TreePreset[presetName]);
|
||||
applyParams(options, params);
|
||||
|
||||
const tree = new Tree();
|
||||
tree.options.copy(options);
|
||||
|
||||
try {
|
||||
tree.generate();
|
||||
} catch (e) {
|
||||
// generate() may fail on DOM APIs for materials, but geometry arrays are
|
||||
// already populated at that point — continue.
|
||||
}
|
||||
|
||||
const branches = tree.branches;
|
||||
const leaves = tree.leaves;
|
||||
|
||||
if (!branches || !leaves) {
|
||||
process.stderr.write('Generation produced no geometry\n');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const leafNormals = leaves.normals?.length > 0
|
||||
? leaves.normals
|
||||
: computeFlatNormals(leaves.verts, leaves.indices);
|
||||
|
||||
const result = {
|
||||
branches: {
|
||||
positions: Array.from(branches.verts),
|
||||
normals: Array.from(branches.normals),
|
||||
uvs: Array.from(branches.uvs),
|
||||
indices: Array.from(branches.indices),
|
||||
},
|
||||
leaves: {
|
||||
positions: Array.from(leaves.verts),
|
||||
normals: Array.from(leafNormals),
|
||||
uvs: Array.from(leaves.uvs),
|
||||
indices: Array.from(leaves.indices),
|
||||
},
|
||||
};
|
||||
|
||||
process.stdout.write(JSON.stringify(result));
|
||||
|
||||
// ── Parameter-Overrides ────────────────────────────────────────────────────
|
||||
|
||||
function applyParams(options, params) {
|
||||
if (params.seed !== undefined) options.seed = params.seed;
|
||||
if (params.type !== undefined) options.type = params.type;
|
||||
|
||||
if (params.bark) {
|
||||
const b = params.bark;
|
||||
if (b.tint !== undefined) options.bark.tint = b.tint;
|
||||
if (b.flatShading !== undefined) options.bark.flatShading = b.flatShading;
|
||||
if (b.textureScale) {
|
||||
if (b.textureScale.x !== undefined) options.bark.textureScale.x = b.textureScale.x;
|
||||
if (b.textureScale.y !== undefined) options.bark.textureScale.y = b.textureScale.y;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.branch) {
|
||||
const br = params.branch;
|
||||
if (br.levels !== undefined) options.branch.levels = br.levels;
|
||||
if (br.force) {
|
||||
if (br.force.strength !== undefined)
|
||||
options.branch.force.strength = br.force.strength;
|
||||
if (br.force.direction) {
|
||||
if (br.force.direction.x !== undefined) options.branch.force.direction.x = br.force.direction.x;
|
||||
if (br.force.direction.y !== undefined) options.branch.force.direction.y = br.force.direction.y;
|
||||
if (br.force.direction.z !== undefined) options.branch.force.direction.z = br.force.direction.z;
|
||||
}
|
||||
}
|
||||
// Per-level maps: replace entirely when provided (Java sends the full map)
|
||||
for (const key of ['angle','children','gnarliness','length','radius',
|
||||
'sections','segments','start','taper','twist']) {
|
||||
if (br[key] !== undefined) options.branch[key] = br[key];
|
||||
}
|
||||
}
|
||||
|
||||
if (params.leaves) {
|
||||
Object.assign(options.leaves, params.leaves);
|
||||
}
|
||||
|
||||
if (params.trellis) {
|
||||
Object.assign(options.trellis, params.trellis);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Helpers ────────────────────────────────────────────────────────────────
|
||||
|
||||
function computeFlatNormals(verts, indices) {
|
||||
const normals = new Float32Array(verts.length);
|
||||
for (let i = 0; i < indices.length; i += 3) {
|
||||
const ia = indices[i] * 3, ib = indices[i + 1] * 3, ic = indices[i + 2] * 3;
|
||||
const ax = verts[ib] - verts[ia], ay = verts[ib+1] - verts[ia+1], az = verts[ib+2] - verts[ia+2];
|
||||
const bx = verts[ic] - verts[ia], by = verts[ic+1] - verts[ia+1], bz = verts[ic+2] - verts[ia+2];
|
||||
const nx = ay*bz - az*by, ny = az*bx - ax*bz, nz = ax*by - ay*bx;
|
||||
const len = Math.sqrt(nx*nx + ny*ny + nz*nz) || 1;
|
||||
for (const idx of [ia, ib, ic]) {
|
||||
normals[idx] += nx/len;
|
||||
normals[idx+1] += ny/len;
|
||||
normals[idx+2] += nz/len;
|
||||
}
|
||||
}
|
||||
return Array.from(normals);
|
||||
}
|
||||
31
tools/package-lock.json
generated
Normal file
31
tools/package-lock.json
generated
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "blight-tools",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "blight-tools",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@dgreenheck/ez-tree": "^1.1.0",
|
||||
"three": "^0.167.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dgreenheck/ez-tree": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@dgreenheck/ez-tree/-/ez-tree-1.1.0.tgz",
|
||||
"integrity": "sha512-6pvS6hD6B6h00dm0SnkgYeT4ABU5Y1Z9M44p1tXiV5C0eKrQy2sKECXshoaUv0qAOqYVL68w/PwadUxDFDiHUg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"three": ">=0.167"
|
||||
}
|
||||
},
|
||||
"node_modules/three": {
|
||||
"version": "0.167.1",
|
||||
"resolved": "https://registry.npmjs.org/three/-/three-0.167.1.tgz",
|
||||
"integrity": "sha512-gYTLJA/UQip6J/tJvl91YYqlZF47+D/kxiWrbTon35ZHlXEN0VOo+Qke2walF1/x92v55H6enomymg4Dak52kw==",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
10
tools/package.json
Normal file
10
tools/package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "blight-tools",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@dgreenheck/ez-tree": "^1.1.0",
|
||||
"three": "^0.167.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user