Commit c71c7dad authored by Max Bebök's avatar Max Bebök

chg: event stuff, WIP state

parent 44725b1f
......@@ -5,6 +5,13 @@ The current released and prebuilt stable version is: **2.1.0**
<hr/>
### WIP - Version 2.3.0 - "Convenience Update"
**General** <br/>
#dev - Clone / Add now generates a new HashId
<hr/>
### WIP - Version 2.2.0 - "Convenience Update"
**Field + Shrine Editor** <br/>
......
......@@ -28,7 +28,7 @@ module.exports = class Field_Editor extends Mubin_Editor
this.titleBgHandler = titleBgHandler;
this.loadActorData = true;
this.loadProdData = true;
this.loadProdData = false;
this.loadMapMesh = this.project.getConfig().getValue("fieldEditor.loadModel");
this.fieldModelLoader = new Field_Model_Loader();
......
......@@ -150,7 +150,7 @@ module.exports = class App extends App_Base
files.forEach(file =>
{
if(shrineRegex.test(file))// || file.startsWith("Remains")) // <- 4 main dungeons
if(shrineRegex.test(file) || file.startsWith("Remains")) // <- 4 main dungeons
{
const shrineName = file.replace(".pack", "");
shrinesHtml += `<option value="${shrineName}">${shrineName}</option>`;
......
......@@ -147,6 +147,35 @@
<span class="nav-group-item">
<button class="btn btn btn-default data-tool-openLogicEditor">Logic-Viewer [WIP]</button>
</span>
<span class="nav-group-item">
<button class="btn btn btn-default data-tool-addActorStatic">Add Actor (Static)</button>
</span>
<span class="nav-group-item">
<button class="btn btn btn-default data-tool-addActorDyn">Add Actor (Dynamic)</button>
</span>
</nav>
<h5 class="nav-group-title">Actor-Templates</h5>
<nav class="nav-group tool-group"></nav>
<span class="nav-group-item">
<select class="btn btn btn-default data-tool-actorTemplate">
<option value="door_switch">Door - Switch</option>
<option value="door_torch">Door - Torch</option>
<option value="door_ball">Door - Walk-Ball</option>
<option value="door_switch_temp">Door - Switch/Temp</option>
<option value="enemy_killed">Door - Enemies</option>
<option value="lift_big">Lift - Big</option>
<option value="weather_area">Area - Weather</option>
<option value="void_out_area">Area - Void-Out</option>
<option value="entrance_elevator">Entrance Elevator</option>
<option value="lamp_rope">Lamp + Rope</option>
<option value="fire_trap">Fire-Trap</option>
</select>
</span>
<span class="nav-group-item">
<button class="btn btn btn-default data-tool-addActorTemplate">Add</button>
</span>
</nav>
<h5 class="nav-group-title">Render-Settings</h5>
......
......@@ -16,6 +16,7 @@ const Filter = requireGlobal("lib/filter.js");
const Binary_File_Loader = require("binary-file").Loader;
const SARC = require("sarc-lib");
const Shrine_Editor = require("./lib/shrine_editor.js");
const ActorParams = require('../../lib/mubin_editor/actor/params');
const String_Table = requireGlobal("lib/string_table/string_table.js");
const JSON_IPC = require("./../../lib/json_ipc/json_ipc");
......@@ -77,6 +78,19 @@ module.exports = class App extends App_Base
this.windowHandler.open("logic_editor", {mapName: this.shrineName});
};
this.node.querySelector(".data-tool-addActorStatic").onclick = async () => {
this.shrineEditor.actorHandler.addFromData(ActorParams.createTemplate("FldObj_HugeMazeTorchStand_A_01"), "Static");
};
this.node.querySelector(".data-tool-addActorDyn").onclick = async () => {
this.shrineEditor.actorHandler.addFromData(ActorParams.createTemplate("FldObj_HugeMazeTorchStand_A_01"), "Dynamic");
};
this.node.querySelector(".data-tool-addActorTemplate").onclick = async () => {
const templateName = this.node.querySelector(".data-tool-actorTemplate").value;
this.shrineEditor.actorHandler.addFromTemplate(templateName);
};
}
/**
......@@ -113,10 +127,11 @@ module.exports = class App extends App_Base
let fileName = shrineDirOrFile.split(/[\\/]+/).pop();
this.shrineDir = path.join(this.project.getShrinePath("unpacked"), fileName + ".unpacked");
this.shrineName = fileName.match(/Dungeon[0-9]+/);
this.shrineName = fileName.match(/Dungeon[0-9]+/) || fileName.match(/Remains[A-Za-z]+/);
if(this.shrineName != null)
if(this.shrineName != null) {
this.shrineName = this.shrineName[0];
}
const alreadyExtracted = await fs.pathExists(this.shrineDir);
......
......@@ -56,6 +56,12 @@ module.exports = class Shrine_Creator
this.saveActors("Static", shrineDir, shrineName),
]);
const cemuPackPath = "/home/mbeboek/graphicPacks/BreathOfTheWild_EventTest/content/Pack/Dungeon059";
await Promise.all([
this.saveActors("Dynamic", cemuPackPath, shrineName),
this.saveActors("Static", cemuPackPath, shrineName),
]);
if(packData)
{
const sarc = new SARC();
......@@ -74,6 +80,11 @@ module.exports = class Shrine_Creator
{
const actorPath = path.join(shrineDir, "Map", "CDungeon", shrineName, `${shrineName}_${typeName}.smubin`);
const byaml = new BYAML.Creator();
const byamlData = {...(typeName == "Dynamic" ? this.actorHandler.dataActorDyn : this.actorHandler.dataActorStatic)};
byamlData.Objs = byamlData.Objs.sort((a, b) => a.HashId.value - b.HashId.value);
this.actorHandler.dataActorDyn.Objs
const actorBuffer = byaml.create(typeName == "Dynamic" ? this.actorHandler.dataActorDyn : this.actorHandler.dataActorStatic);
const actorYaz = yaz0.encode(actorBuffer);
......
......@@ -56,7 +56,12 @@ module.exports = class Shrine_Model_Loader
*/
async _loadShrineTexture(filesBasePath)
{
const shrineTexPath = filesBasePath + ".Tex2.sbfres";
//return undefined;
let shrineTexPath = filesBasePath + ".Tex1.sbfres";
if(!fs.existsSync(shrineTexPath)) {
shrineTexPath = filesBasePath + ".Tex2.sbfres";
}
if(fs.existsSync(shrineTexPath))
{
const texBuffer = this.fileLoader.buffer(shrineTexPath);
......
......@@ -37,7 +37,10 @@ module.exports = class Shrine_Editor extends Mubin_Editor
*/
generateMubinPath(actorType)
{
return path.join(this.mubinDir, "Map", "CDungeon", this.mubinName, `${this.mubinName}_${actorType}.smubin`);
const mapDir = this.mubinName.startsWith("Remains") ? "MainFieldDungeon" : "CDungeon";
console.log(this);
console.log(this.mubinDir, "Map", mapDir, this.mubinName, `${this.mubinName}_${actorType}.smubin`);
return path.join(this.mubinDir, "Map", mapDir, this.mubinName, `${this.mubinName}_${actorType}.smubin`);
}
/**
......
......@@ -16,7 +16,7 @@ const CUBE_COLORS_FLOAT = [
[0.0, 1.0, 1.0, 1.0], [1.0, 1.0, 0.0, 1.0], [1.0, 0.0, 1.0, 1.0]
];
const CUBE_SIZE = 1.01; // most non-model actors are placed exactly 1 unit inside walls, add a tiny bit to one to prevent clipping/flickering
const CUBE_SIZE = 1.00001; // most non-model actors are placed exactly 1 unit inside walls, add a tiny bit to one to prevent clipping/flickering
module.exports = class Renderer_Helper_Model extends Base
{
......@@ -27,7 +27,12 @@ module.exports = class Renderer_Helper_Model extends Base
this.helperShader = helperShader;
this.helperTexture = new Renderer_Helpep_Texture(this.THREE);
this.textureGridBW = new THREE.TextureLoader().load("assets/img/texture_grid_01.png"); // to debug UV coordinates
this.specialTextures = {
"default": new THREE.TextureLoader().load("assets/img/texture_grid_01.png"),
"LookTag": new THREE.TextureLoader().load("assets/img/texture_cam.png"),
"LinkTagAnd": new THREE.TextureLoader().load("assets/img/texture_and.png"),
"Area": new THREE.TextureLoader().load("assets/img/texture_area.png"),
};
}
_createTexture(textureData, name)
......@@ -66,24 +71,13 @@ module.exports = class Renderer_Helper_Model extends Base
let materialConf = {};
let texture;
if(texture = this._createTexture(model.textureColor, `${model.name}_color`))
materialConf.map = texture;
if(texture = this._createTexture(model.textureNormal, `${model.name}_normal`))
materialConf.normalMap = texture;
/*
if(texture = this._createTexture(model.textureEmission, `${model.name}_emission`))
{
materialConf.emissiveMap = texture;
materialConf.emissive = new this.THREE.Color(0x4040FF); // @TODO read from FTEX/GX surface
materialConf.emissiveIntensity = 1.0;
}
*/
//materialConf.map = new THREE.TextureLoader().load("assets/img/texture_dummy.png"); // to debug UV coordinates
let material = materialConf.map != null ? new this.THREE.MeshPhongMaterial(materialConf) : new this.THREE.MeshNormalMaterial();
material.transparent = true;
material.alphaTest = 0.125; // @TODO check if the texture has trnsparency
......@@ -113,31 +107,11 @@ module.exports = class Renderer_Helper_Model extends Base
if(model.uv1Array || model.uv0Array)
geometry.addAttribute('uvNormalMap', new this.THREE.BufferAttribute((model.uv1Array || model.uv0Array), 2));
//geometry.computeFaceNormals();
//geometry.computeVertexNormals();
//geometry.maxInstancedCount = 5;
const uniforms = {
colorBlendFactor: {value: 0.0},
};
let texture;
if(texture = this._createTexture(model.textureColor, `${model.name}_color`))
uniforms.texColor = {type: "t", value: texture};
else
uniforms.texColor = {type: "t", value: this.textureGridBW};
//if(texture = this._createTexture(model.textureNormal, `${model.name}_normal`))
//uniforms.texNormal = {type: "t", value: textureNormal};
/*
if(texture = this._createTexture(model.textureEmission, `${model.name}_emission`))
{
materialConf.emissiveMap = texture;
materialConf.emissive = new this.THREE.Color(0x4040FF); // @TODO read from FTEX/GX surface
materialConf.emissiveIntensity = 1.0;
}
*/
uniforms.texColor = {type: "t", value: this._getTexture(model.name, model.textureColor)};
const material = await this.helperShader.getShader("actor");
material.uniforms = uniforms;
......@@ -152,9 +126,21 @@ module.exports = class Renderer_Helper_Model extends Base
return mesh;
}
async createInstancedBox()
_getTexture(modelName, textureColor)
{
let texture = textureColor ? this._createTexture(textureColor, `${modelName}_color`) : undefined;
if(!texture)
{
return this.specialTextures[modelName]
? this.specialTextures[modelName]
: this.specialTextures.default;
}
return texture;
}
async createInstancedBox(actorName, scale = 1)
{
const boxGeometry = new this.THREE.BoxBufferGeometry( CUBE_SIZE, CUBE_SIZE, CUBE_SIZE );
const boxGeometry = new this.THREE.BoxBufferGeometry( CUBE_SIZE * scale, CUBE_SIZE * scale, CUBE_SIZE * scale);
const geometry = new THREE.InstancedBufferGeometry();
geometry.setIndex(new this.THREE.BufferAttribute(boxGeometry.index.array, 1));
......@@ -175,10 +161,9 @@ module.exports = class Renderer_Helper_Model extends Base
}
geometry.addAttribute('color', new this.THREE.BufferAttribute(colorBuffer, 4));
const uniforms = {
colorBlendFactor: {value: 0.75},
texColor: {type: "t", value: this.textureGridBW}
texColor: {type: "t", value: this._getTexture(actorName)}
};
const material = await this.helperShader.getShader("actor");
......
......@@ -226,9 +226,9 @@ module.exports = class Renderer
return await this.helper.model.createInstancedModel(model);
}
async createInstancedBox()
async createInstancedBox(actorName, scale = 1)
{
return await this.helper.model.createInstancedBox();
return await this.helper.model.createInstancedBox(actorName, scale);
}
async getShader(name)
......
......@@ -123,11 +123,14 @@ module.exports = class FMDL_Parser
else
console.warn("FMAT: model has own texture!");
if(texRef.texture == null)
if(texRef.texture == null) {
continue;
}
switch(texRef.name.substr(-3))
let prefix = texRef.name.endsWith("_norm") ? "Nrm" : texRef.name.substr(-3);
switch(prefix)
{
default:
case "Alb":
if(!model.textureColor) // @TODO check hoe to better handle this
model.textureColor = texRef.texture.surface;
......
......@@ -46,6 +46,7 @@ module.exports = class ModelConverter_MTL
*/
saveTextureAsPNG(surface, fileName)
{
return;
if(surface.imageBuffer != null)
{
let pngBuffer = PNG.encode(surface.imageBuffer, surface.sizeX, surface.sizeY);
......
......@@ -19,6 +19,7 @@ module.exports = class Actor
this.objInstance.setActor(this);
this.selected = false;
this.links = [];
}
getName()
......@@ -31,6 +32,11 @@ module.exports = class Actor
return (this.params.HashId && this.params.HashId.value) ? this.params.HashId.value : 0;
}
setHashId(id)
{
this.params.HashId.value = id;
}
getSRTHash()
{
return (this.params.SRTHash && this.params.SRTHash.value) ? this.params.SRTHash.value : 0;
......@@ -119,6 +125,9 @@ module.exports = class Actor
if(this.handler)
await this.handler.deleteActor(this);
this.links.forEach(link => link.parent.remove(link));
this.links = [];
this.objInstance.delete();
this.objInstance = undefined;
}
......@@ -153,6 +162,7 @@ module.exports = class Actor
}
this.objInstance.update();
this.handler.updateLinks();
if(this.gui)
{
......
......@@ -4,7 +4,7 @@
* @license GNU-GPLv3 - see the "LICENSE" file in the root directory
*/
const fs = require('fs');
const fs = require('fs-extra');
const uuid = require("uuid/v4");
const path = require("path");
......@@ -62,6 +62,35 @@ module.exports = class Actor_Handler
this.actorObjHandler.update();
}
updateLinks()
{
Object.values(this.actors).forEach(actor =>
{
if(actor.params.LinksToObj)
{
const scene = this.mubinRenderer.renderer.scene;
actor.links.forEach(link => scene.remove(link));
actor.links = [];
actor.params.LinksToObj.forEach(link => {
const targetId = link.DestUnitHashId.value;
const linkedActor = this.getActorByHashId(targetId);
if (linkedActor)
{
const material = new THREE.LineBasicMaterial({color: 0x0000ff});
var geometry = new THREE.Geometry();
geometry.vertices = [actor.objInstance.pos, linkedActor.objInstance.pos];
const line = new THREE.Line(geometry, material);
scene.add(line);
actor.links.push(line);
}
});
}
});
}
clear()
{
for(let actor of Object.values(this.actors))
......@@ -97,6 +126,11 @@ module.exports = class Actor_Handler
console.error(`getActorArray: invalid type '${type}'`);
}
getActorByHashId(hashId)
{
return Object.values(this.actors).find(actor => actor.getHashId() == hashId);
}
getActorArrayObject(type)
{
if(type === "Dynamic") {
......@@ -243,16 +277,65 @@ module.exports = class Actor_Handler
{
console.log(actor);
const paramCopy = BYAML.Helper.deepCopy(actor.params);
if(paramCopy.Translate)
{
paramCopy.Translate[1].value += 1.0;
paramCopy.HashId.value = 0;
//paramCopy.Translate[0].value += 1.0;
}
paramCopy.HashId.value = this.getFreeHashId();
const newActor = await this.addActor(actor.getName(), paramCopy, actor.type);
this.history.add();
if(this.editor) {
this.editor.selectActor(newActor);
this.editor.deselectActor(actor);
}
return newActor;
}
async addFromData(actorData, actorType = "Dynamic")
{
const actorName = actorData.UnitConfigName.value;
const bymlParams = BYAML.Helper.deepCopy(actorData);
const newActor = await this.addActor(actorName, bymlParams, actorType);
if(newActor.getHashId() == 0) {
newActor.setHashId(this.getFreeHashId());
}
this.history.add();
if(this.editor) {
newActor.move(this.editor.getCurrentPos());
this.editor.selectActor(newActor);
}
return newActor;
}
async addFromTemplate(name)
{
const actorData = await fs.readJSON(__dirname + `/../templates/${name}.json`);
const hashIds = new Array(actorData.ids).fill(0).map((_, i) => i + this.getFreeHashId());
let actorDataStr = JSON.stringify(actorData.actors);
hashIds.forEach((hashId, idx) => {
actorDataStr = actorDataStr.replace(new RegExp(`"\\{ID${idx}\\}"`, 'g'), hashId)
});
JSON.parse(actorDataStr).forEach(actorData => {
this.addFromData(actorData, "Static");
});
}
getFreeHashId()
{
const maxStatic = Math.max(...this.dataActorStatic.Objs.map(actor => actor.HashId.value));
const maxDyn = Math.max(...this.dataActorDyn.Objs.map(actor => actor.HashId.value));
return Math.max(maxStatic, maxDyn) + 1;
}
/**
* refreshes the actor model by removing and adding it again
......@@ -285,4 +368,12 @@ module.exports = class Actor_Handler
return dataObj[dataIndex];
}
findActorDefinitions(name)
{
name = name.toLowerCase();
return this.actorObjHandler.actorObjLoader.actorData.Actors.filter(
entry => entry.name.value.toLowerCase().includes(name)
);
}
};
......@@ -58,11 +58,19 @@ module.exports = class Actor_Object_Loader
this.actorInfo[actor.name.value] = actor;
}
// create default box
const objGroup = this.mubinRenderer.renderer.createObjectGroup("__DEFAULT_BOX");
objGroup.add(await this.mubinRenderer.renderer.createInstancedBox());
objGroup.userData = {type: "actor", visible: false};
this.objects["__DEFAULT_BOX"] = new Actor_Object(objGroup);
for(let actorName of ["__DEFAULT_BOX", "LookTag", "LinkTagAnd"])
{
const objGroup = this.mubinRenderer.renderer.createObjectGroup(actorName);
objGroup.add(await this.mubinRenderer.renderer.createInstancedBox(actorName));
objGroup.userData = {type: "actor", visible: false};
this.objects[actorName] = new Actor_Object(objGroup);
}
const areaObjGroup = this.mubinRenderer.renderer.createObjectGroup("Area");
const areaBoxMesh = await this.mubinRenderer.renderer.createInstancedBox("Area", 2.0);
areaObjGroup.add(areaBoxMesh);
areaObjGroup.userData = {type: "actor", visible: false};
this.objects["Area"] = new Actor_Object(areaObjGroup);
}
/**
......
{
"ids": 4,
"actors": [
{
"!Parameters": {
"DropTable": {
"type": 160,
"value": "Normal"
},
"FieldBodyGroup": {
"type": 209,
"value": 0
},
"SharpWeaponJudgeType": {
"type": 209,
"value": 0
},
"TraversePos": {
"X": {
"type": 210,
"value": 0
},
"Y": {
"type": 210,
"value": 26.75
},
"Z": {
"type": 210,
"value": 0
}
},
"TraverseRadiusXZ": {
"type": 210,
"value": 35.35533905029297
},
"UniqueNameMessageLabel": {
"type": 160,
"value": "Pa_BossGauge_FantomGanonFire"
}
},
"HashId": {
"type": 211,
"value": 674596187
},
"LinksToObj": [
{
"DefinitionName": {
"type": 160,
"value": "Reference"
},
"DestUnitHashId": {
"type": 211,
"value": 3992196830
}
},
{
"!Parameters": {
"NoAutoDemoMember": {
"type": 208,
"value": false
}
},
"DefinitionName": {
"type": 160,
"value": "BasicSig"
},
"DestUnitHashId": {
"type": 211,
"value": 2308274967
}
},
{
"DefinitionName": {
"type": 160,
"value": "SyncLink"
},
"DestUnitHashId": {
"type": 211,
"value": 1821846322
}
}
],
"LinksToRail": [
{
"DefinitionName": {
"type": 160,
"value": "GuideRef"
},
"DestUnitHashId": {
"type": 211,
"value": 3281567353
}
}
],
"OnlyOne": {
"type": 208,
"value": true
},
"Rotate": {
"type": 210,
"value": -3.1415927410125732
},
"SRTHash": {
"type": 209,
"value": -416180424
},
"Translate": [
{
"type": 210,
"value": 8.74227794156468e-7
},
{
"type": 210,
"value": 23.5
},
{
"type": 210,
"value": 15
}
],
"UniqueName": {
"type": 160,
"value": "0"
},
"UnitConfigName": {
"type": 160,
"value": "Enemy_SiteBoss_Lsword"
}
},
{
"!Parameters": {
"FieldBodyGroup": {
"type": 209,
"value": 0
},
"IncrementSave": {
"type": 208,
"value": false
},
"MakeSaveFlag": {
"type": 209,
"value": 0
},
"NoChangeSignal": {
"type": 208,
"value": false
},
"SaveFlagOnOffType": {
"type": 209,
"value": 0
}
},
"HashId": {
"type": 211,
"value": 4203676317
},
"LinksToObj": [
{
"!Parameters": {
"AppearFade": {
"type": 208,
"value": false
}
},