(function() { function parseGeometry(data) { let geometry_name = data.name.replace(/^geometry\./, ''); let existing_tab = isApp && ModelProject.all.find(project => ( Project !== project && project.export_path == Project.export_path && project.geometry_name == geometry_name )) if (existing_tab) { Project.close().then(() => { existing_tab.select(); }); return; } codec.dispatchEvent('parse', {model: data.object}); Project.geometry_name = geometry_name; Project.texture_width = data.object.texturewidth || 64; Project.texture_height = data.object.textureheight || 64; if (typeof data.object.visible_bounds_width == 'number' && typeof data.object.visible_bounds_height == 'number') { Project.visible_box[0] = Math.max(Project.visible_box[0], data.object.visible_bounds_width || 0); Project.visible_box[1] = Math.max(Project.visible_box[1], data.object.visible_bounds_height || 0); if (data.object.visible_bounds_offset && typeof data.object.visible_bounds_offset[1] == 'number') { Project.visible_box[2] = data.object.visible_bounds_offset[1] || 0; } } var bones = {} if (data.object.bones) { var included_bones = [] data.object.bones.forEach(function(b) { included_bones.push(b.name) }) data.object.bones.forEach(function(b, bi) { var group = new Group({ name: b.name, origin: b.pivot, rotation: b.rotation, material: b.material, color: Group.all.length%markerColors.length }).init() bones[b.name] = group if (b.pivot) { group.origin[0] *= -1 } group.rotation[0] *= -1; group.rotation[1] *= -1; group.mirror_uv = b.mirror === true group.reset = b.reset === true if (b.cubes) { b.cubes.forEach(function(s) { var base_cube = new Cube({name: b.name, autouv: 0, color: group.color}) if (s.origin) { base_cube.from.V3_set(s.origin); base_cube.from[0] = -(base_cube.from[0] + s.size[0]) if (s.size) { base_cube.to[0] = s.size[0] + base_cube.from[0] base_cube.to[1] = s.size[1] + base_cube.from[1] base_cube.to[2] = s.size[2] + base_cube.from[2] } } if (s.uv) { base_cube.uv_offset[0] = s.uv[0] base_cube.uv_offset[1] = s.uv[1] } if (s.inflate && typeof s.inflate === 'number') { base_cube.inflate = s.inflate } if (s.mirror === undefined) { base_cube.mirror_uv = group.mirror_uv } else { base_cube.mirror_uv = s.mirror === true } base_cube.addTo(group).init() }) } if (b.children) { b.children.forEach(function(cg) { cg.addTo(group) }) } if (b.locators) { for (var key in b.locators) { var coords, rotation; if (b.locators[key] instanceof Array) { coords = b.locators[key]; } else { coords = b.locators[key].offset; rotation = b.locators[key].rotation; } coords[0] *= -1 var locator = new Locator({position: coords, name: key, rotation}).addTo(group).init(); } } var parent_group = 'root'; if (b.parent) { if (bones[b.parent]) { parent_group = bones[b.parent] } else { data.object.bones.forEach(function(ib) { if (ib.name === b.parent) { ib.children && ib.children.length ? ib.children.push(group) : ib.children = [group] } }) } } group.addTo(parent_group) }) } codec.dispatchEvent('parsed', {model: data.object}); loadTextureDraggable() Canvas.updateAllBones() setProjectTitle() if (isApp && Project.geometry_name && Project.BedrockEntityManager) { Project.BedrockEntityManager.initEntity() } Validator.validate() updateSelection() } var codec = new Codec('bedrock_old', { name: 'Bedrock Entity Model', extension: 'json', remember: true, multiple_per_file: true, load_filter: { type: 'json', extensions: ['json'], condition(model) { return (model.format_version && compareVersions('1.12.0', model.format_version)) || Object.keys(model).find(s => s.match(/^geometry\./)); } }, compile(options) { if (options === undefined) options = {} var entitymodel = {} entitymodel.texturewidth = Project.texture_width; entitymodel.textureheight = Project.texture_height; var bones = [] var visible_box = new THREE.Box3() var groups = getAllGroups(); var loose_elements = []; Outliner.root.forEach(obj => { if (obj.type === 'cube' || obj.type == 'locator') { loose_elements.push(obj) } }) if (loose_elements.length) { let group = new Group({ name: 'bb_main' }); group.children.push(...loose_elements); group.is_catch_bone = true; group.createUniqueName(); groups.splice(0, 0, group); } groups.forEach(function(g) { if (g.type !== 'group') return; if (!settings.export_empty_groups.value && !g.children.find(child => child.export)) return; //Bone var bone = {} bone.name = g.name if (g.parent.type === 'group') { bone.parent = g.parent.name } bone.pivot = g.origin.slice() bone.pivot[0] *= -1 if (!g.rotation.allEqual(0)) { bone.rotation = [ -g.rotation[0], -g.rotation[1], g.rotation[2] ] } if (g.reset) bone.reset = true; if (g.mirror_uv && Project.box_uv) bone.mirror = true; if (g.material) bone.material = g.material; //Elements var cubes = [] var locators = {}; for (var obj of g.children) { if (obj.export) { if (obj instanceof Cube) { var template = new oneLiner() template.origin = obj.from.slice() template.size = obj.size() template.origin[0] = -(template.origin[0] + template.size[0]) template.uv = obj.uv_offset if (obj.inflate && typeof obj.inflate === 'number') { template.inflate = obj.inflate } if (obj.mirror_uv === !bone.mirror) { template.mirror = obj.mirror_uv } //Visible Bounds var mesh = obj.mesh if (mesh) { visible_box.expandByObject(mesh) } cubes.push(template) } else if (obj instanceof Locator) { locators[obj.name] = obj.position.slice(); locators[obj.name][0] *= -1; } } } if (cubes.length) { bone.cubes = cubes } if (Object.keys(locators).length) { bone.locators = locators } bones.push(bone) }) if (bones.length && options.visible_box !== false) { let visible_box = calculateVisibleBox(); entitymodel.visible_bounds_width = visible_box[0] || 0; entitymodel.visible_bounds_height = visible_box[1] || 0; entitymodel.visible_bounds_offset = [0, visible_box[2] || 0, 0] } if (bones.length) { entitymodel.bones = bones } this.dispatchEvent('compile', {model: entitymodel, options}); if (options.raw) { return entitymodel } else { var model_name = 'geometry.' + (Project.geometry_name||Project.name||'unknown') return autoStringify({ format_version: '1.10.0', [model_name]: entitymodel }) } }, parse(data, path) { let geometries = []; for (let key in data) { if (typeof data[key] !== 'object') continue; geometries.push({ name: key, object: data[key] }); } if (geometries.length === 1) { parseGeometry(geometries[0]); return; } else if (isApp && BedrockEntityManager.CurrentContext?.geometry) { return parseGeometry(geometries.find(geo => geo.name == BedrockEntityManager.CurrentContext.geometry)); } geometries.forEach(geo => { geo.uuid = guid(); geo.bonecount = 0; geo.cubecount = 0; if (geo.object.bones instanceof Array) { geo.object.bones.forEach(bone => { geo.bonecount++; if (bone.cubes instanceof Array) geo.cubecount += bone.cubes.length; }) } }) let selected = null; new Dialog({ id: 'bedrock_model_select', title: 'dialog.select_model.title', buttons: ['Import', 'dialog.cancel'], component: { data() {return { search_term: '', geometries, selected: null, }}, computed: { filtered_geometries() { if (!this.search_term) return this.geometries; let term = this.search_term.toLowerCase(); return this.geometries.filter(geo => { return geo.name.toLowerCase().includes(term) }) } }, methods: { selectGeometry(geo) { this.selected = selected = geo; }, open(geo) { Dialog.open.hide(); parseGeometry(geo); }, tl }, template: `
` }, onConfirm() { parseGeometry(selected); } }).show(); }, export() { var scope = this; Blockbench.export({ resource_id: 'model', type: this.name, extensions: [this.extension], name: this.fileName(), startpath: this.startPath(), content: this.compile({raw: isApp}), custom_writer: isApp ? (a, path) => scope.overwrite(a, path, () => scope.afterSave(path)) : null, }) }, overwrite(content, path, cb) { var model_name = 'geometry.' + (Project.geometry_name.replace(/^geometry\./, '')||'unknown') var data; try { data = fs.readFileSync(path, 'utf-8') } catch (err) {} var obj = { format_version: '1.10.0' } if (data) { try { obj = autoParseJSON(data, false) } catch (err) { err = err+'' var answer = electron.dialog.showMessageBoxSync(currentwindow, { type: 'warning', buttons: [ tl('message.bedrock_overwrite_error.backup_overwrite'), tl('message.bedrock_overwrite_error.overwrite'), tl('dialog.cancel') ], title: 'Blockbench', message: tl('message.bedrock_overwrite_error.message'), detail: err, noLink: false }) if (answer === 0) { var backup_file_name = pathToName(path, true) + ' backup ' + new Date().toLocaleString().split(':').join('_') backup_file_name = path.replace(pathToName(path, false), backup_file_name) fs.writeFile(backup_file_name, data, function (err2) { if (err2) { console.log('Error saving backup model: ', err2) } }) } if (answer === 2) { return; } } if (typeof obj === 'object') { for (var key in obj) { if (obj.hasOwnProperty(key) && obj[key].bones && typeof obj[key].bones === 'object' && obj[key].bones.constructor.name === 'Array' ) { obj[key].bones.forEach(function(bone) { if (typeof bone.cubes === 'object' && bone.cubes.constructor.name === 'Array' ) { bone.cubes.forEach(function(c, ci) { bone.cubes[ci] = new oneLiner(c) }) } }) } } } } obj[model_name] = this.compile({raw: true}); content = autoStringify(obj); Blockbench.writeFile(path, {content}, cb); } }) var format = new ModelFormat({ id: 'bedrock_old', extension: 'json', icon: 'icon-format_bedrock_legacy', category: 'minecraft', show_on_start_screen: false, box_uv: true, single_texture: true, bone_rig: true, centered_grid: true, animated_textures: true, animation_files: true, animation_controllers: true, animation_mode: true, locators: true, codec, onSetup(project) { if (isApp) { project.BedrockEntityManager = new BedrockEntityManager(project); } } }) codec.format = format; BARS.defineActions(function() { codec.export_action = new Action({ id: 'export_entity', icon: format.icon, category: 'file', condition: () => Format == format, click: function () { codec.export() } }) }) })()