var app = require('electron').remote, fs = require('fs'), nativeImage = require('electron').nativeImage, exec = require('child_process').exec, originalFs = require('original-fs'), https = require('https'), currentwindow = app.getCurrentWindow(), dialog_win = null, latest_version = false, preventClosing = true; recent_projects= undefined const shell = require('electron').shell; const {clipboard} = require('electron') $(document).ready(function() { if (app.process.argv.length >= 2) { if (app.process.argv[1].substr(-5) == '.json') { readFile(app.process.argv[1], true) } } $('.open-in-browser').click((event) => { event.preventDefault(); shell.openExternal(event.target.href); return true; }); if (fs.existsSync(app.app.getPath('userData')+osfs+'backups') === false) { fs.mkdirSync( app.app.getPath('userData')+osfs+'backups') } createBackup() $('.web_only').remove() if (__dirname.includes('C:\\xampp\\htdocs\\blockbench\\web')) { Blockbench.addFlag('dev') } }) getLatestVersion(true) //Called on start to show message function getLatestVersion(init) { if (process.platform == 'linux') return; $.getJSON('https://blockbench.net/api/index.json', (data) => { if (data.version) { latest_version = data.version if (compareVersions(latest_version, appVersion) && init === true) { Blockbench.showMessageBox({ translateKey: 'update_notification', message: tl('message.update_notification.message', [latest_version]), icon: 'update', buttons: [tl('message.update_notification.install'), tl('message.update_notification.later')], confirm: 0, cancel: 1 }, (result) => { if (result === 0) { checkForUpdates(true) } }) } else if (init === false) { checkForUpdates() } } }).fail(function() { latest_version = false }) } //Recent Projects function updateRecentProjects() { if (recent_projects === undefined) { //Setup recent_projects = [] var raw = localStorage.getItem('recent_projects') if (raw) { recent_projects = JSON.parse(raw) } } //Set Local Storage localStorage.setItem('recent_projects', JSON.stringify(recent_projects)) } function addRecentProject(data) { var i = recent_projects.length-1 while (i >= 0) { var p = recent_projects[i] if (p.path === data.path) { recent_projects.splice(i, 1) } i--; } recent_projects.push({name: data.name, path: data.path}) if (recent_projects.length > 8) { recent_projects.shift() } updateRecentProjects() } //Updates function checkForUpdates(instant) { showDialog('updater') setProgressBar('update_bar', 0, 1) var data; if (latest_version === false) { data = `
refresh
${tl('dialog.update.refresh')}
cloud_off${tl('dialog.update.no_connection')}
`; } else if (latest_version !== appVersion) { data = `
${tl('dialog.update.latest')}: ${latest_version}
${tl('dialog.update.installed')}: ${appVersion}
`; if (instant) { setTimeout(function() { installUpdate() }, 60) } } else { data = `
refresh
${tl('dialog.update.refresh')}
check ${tl('dialog.update.up_to_date')}
`; } $('#updater_content').html(data) } function refreshUpdateDialog() { currentwindow.webContents.session.clearCache(function() { data = '
refresh'+tl('dialog.update.connecting')+'
' $('#updater_content').html(data) getLatestVersion(false) }) } function installUpdate() { console.log('Starting Update') var received_bytes = 0; var total_bytes = 0; $('.uc_btn').css('visibility', 'hidden') var asar_path = __dirname if (asar_path.includes('.asar') === false) { asar_path = asar_path + osfs+'resources'+osfs+'app.asar' } var file = originalFs.createWriteStream(asar_path) var request = https.get("https://blockbench.net/api/app.asar", function(response) { response.pipe(file); total_bytes = parseInt(response.headers['content-length']); response.on('end', updateInstallationEnd) response.on('data', function(chunk) { received_bytes += chunk.length; setProgressBar('update_bar', received_bytes / total_bytes, 1); }) }); } function updateInstallationEnd() { hideDialog() var exe_path = __dirname.split(osfs) exe_path.splice(-2) exe_path = exe_path.join(osfs)+osfs+'blockbench.exe' if (showSaveDialog(true)) { exec(exe_path) } else { Blockbench.showQuickMessage('message.restart_to_update') } } //Image Editor function changeImageEditor(texture) { var dialog = new Dialog({ title: tl('message.image_editor.title'), id: 'image_editor', lines: ['
'], draggable: true, onConfirm: function() { var id = $('.dialog#image_editor option:selected').attr('id') var path; switch (id) { case 'ps': path = 'C:\\Program Files\\Adobe\\Adobe Photoshop CC 2018\\Photoshop.exe'; break; case 'gimp':path = 'C:\\Program Files\\GIMP 2\\bin\\gimp-2.10.exe'; break; case 'pdn': path = 'C:\\Program Files\\paint.net\\PaintDotNet.exe'; break; } if (id === 'other') { selectImageEditorFile(texture) } else if (path) { settings.image_editor.value = path if (texture) { texture.openEditor() } } dialog.hide() } }).show() /* Ask for file IF _other selected */ } function selectImageEditorFile(texture) { app.dialog.showOpenDialog(currentwindow, { title: tl('message.image_editor.exe'), filters: [{name: 'Executable Program', extensions: ['exe']}] }, function(filePaths) { if (filePaths) { settings.image_editor.value = filePaths[0] if (texture) { texture.openEditor() } } }) } //Default Pack function openDefaultTexturePath() { var answer = app.dialog.showMessageBox(currentwindow, { type: 'info', buttons: ( settings.default_path.value ? [tl('dialog.cancel'), tl('message.default_textures.continue'), tl('message.default_textures.remove')] : [tl('dialog.cancel'), tl('message.default_textures.continue')] ), noLink: true, title: tl('message.default_textures.title'), message: tl('message.default_textures.message'), detail: tl('message.default_textures.detail'), }) if (answer === 0) { return; } else if (answer === 1) { app.dialog.showOpenDialog(currentwindow, { title: tl('message.default_textures.select'), properties: ['openDirectory'], }, function(filePaths) { if (filePaths) { settings.default_path.value = filePaths[0] } }) } else { settings.default_path.value = false } } function findEntityTexture(mob, return_path) { var textures = { 'geometry.chicken': 'chicken', 'geometry.blaze': 'blaze', 'geometry.llamaspit': 'llama/spit', 'geometry.llama': 'llama/llama_creamy', 'geometry.dragon': 'dragon/dragon', 'geometry.ghast': 'ghast/ghast', 'geometry.slime': 'slime/slime', 'geometry.slime.armor': 'slime/slime', 'geometry.lavaslime': 'slime/magmacube', 'geometry.silverfish': 'silverfish', 'geometry.shulker': 'shulker/shulker_undyed', 'geometry.rabbit': 'rabbit/brown', 'geometry.horse': 'horse/horse_brown', 'geometry.horse.v2': 'horse2/horse_brown', 'geometry.humanoid': 'steve', 'geometry.creeper': 'creeper/creeper', 'geometry.enderman': 'enderman/enderman', 'geometry.zombie': 'zombie/zombie', 'geometry.zombie.husk': 'zombie/husk', 'geometry.zombie.drowned': 'zombie/drowned', 'geometry.pigzombie': 'pig/pigzombie', 'geometry.pigzombie.baby': 'pig/pigzombie', 'geometry.skeleton': 'skeleton/skeleton', 'geometry.skeleton.wither': 'skeleton/wither_skeleton', 'geometry.skeleton.stray': 'skeleton/stray', 'geometry.squid': 'squid', 'geometry.spider': 'spider/spider', 'geometry.cow': 'cow/cow', 'geometry.mooshroom': 'cow/mooshroom', 'geometry.sheep.sheared': 'sheep/sheep', 'geometry.sheep': 'sheep/sheep', 'geometry.phantom': 'phantom', 'geometry.pig': 'pig/pig', 'geometry.bat': 'bat', 'geometry.dolphin': 'dolphin', 'geometry.irongolem': 'iron_golem', 'geometry.snowgolem': 'snow_golem', 'geometry.zombie.villager': 'zombie_villager/zombie_farmer', 'geometry.evoker': 'illager/evoker', 'geometry.vex': 'vex/vex', 'geometry.vindicator': 'vindicator', 'geometry.wolf': 'wolf/wolf', 'geometry.ocelot': 'cat/ocelot', 'geometry.cat': 'cat/siamese', 'geometry.trident': 'trident', 'geometry.guardian': 'guardian', 'geometry.polarbear': 'polarbear', 'geometry.turtle': 'sea_turtle', 'geometry.villager': 'villager/farmer', 'geometry.villager.witch': 'witch', 'geometry.witherBoss': 'wither_boss/wither', 'geometry.agent': 'agent', 'geometry.armor_stand': 'armor_stand', 'geometry.parrot': 'parrot/parrot_red_blue', 'geometry.bed': 'bed/white', 'geometry.player_head': 'steve', 'geometry.mob_head': 'skeleton/skeleton', 'geometry.dragon_head': 'dragon/dragon', 'geometry.boat': 'boat/boat_oak', 'geometry.minecart': 'minecart', 'geometry.cod': 'fish/fish', 'geometry.pufferfish.small': 'fish/pufferfish', 'geometry.pufferfish.mid': 'fish/pufferfish', 'geometry.pufferfish.large': 'fish/pufferfish', 'geometry.salmon': 'fish/salmon', 'geometry.tropicalfish_a': 'fish/tropical_a', 'geometry.tropicalfish_b': 'fish/tropical_b', 'geometry.endermite': 'endermite', 'geometry.panda': 'panda/panda', } var path = textures[mob.split(':')[0]] if (!path) { path = mob.split(':')[0].replace('geometry.', '') } if (path) { var texture_path = Prop.file_path.split(osfs) var index = texture_path.lastIndexOf('models') - texture_path.length texture_path.splice(index) texture_path = [...texture_path, 'textures', 'entity', ...path.split('/')].join(osfs) if (return_path === true) { return texture_path+'.png'; } else { if (fs.existsSync(texture_path + '.png')) { var texture = new Texture({keep_size: true}).fromPath(texture_path + '.png').add() } else if (fs.existsSync(texture_path + '.tga')) { var texture = new Texture({keep_size: true}).fromPath(texture_path + '.tga').add() } else if (settings.default_path && settings.default_path.value) { texture_path = settings.default_path.value + osfs + 'entity' + osfs + path.split('/').join(osfs) if (fs.existsSync(texture_path + '.png')) { var texture = new Texture({keep_size: true}).fromPath(texture_path + '.png').add() } else if (fs.existsSync(texture_path + '.tga')) { var texture = new Texture({keep_size: true}).fromPath(texture_path + '.tga').add() } } } } } //Writers function saveFile(props) { if (Prop.file_path) { Prop.project_saved = true; setProjectTitle(pathToName(Prop.file_path, false)) var extension = pathToExtension(Prop.file_path) if (Blockbench.entity_mode === false) { if (extension === 'jpm') { BarItems.export_optifine_part.trigger() } else { var content = buildBlockModel() fs.writeFile(Prop.file_path, content, function (err) { if (err) { console.log('Error Saving File: '+err) } if (props && props.closeAfter) { preventClosing = false setTimeout(function() { currentwindow.close() }, 12) } Blockbench.showQuickMessage(tl('message.save_file', [pathToName(Prop.file_path, true)])) }) } } else { if (extension === 'jem') { BarItems.export_optifine_full.trigger() } else { var content = buildEntityModel({raw: true}) writeFileEntity(content, Prop.file_path) } } } else { if (Blockbench.entity_mode === false) { Blockbench.export({ type: 'JSON Model', extensions: ['json'], name: Project.name||'model', startpath: Prop.file_path, custom_writer: function(content, path) { Prop.file_path = path Project.name = pathToName(path, true) saveFile(props) } }) } else { var content = buildEntityModel({raw: true}); Blockbench.export({ type: 'JSON Entity Model', extensions: ['json'], name: Project.name, startpath: Prop.file_path, content: content, custom_writer: writeFileEntity }) } } } function writeFileEntity(content, filepath) { Prop.file_path = filepath fs.readFile(filepath, 'utf-8', function (errx, data) { var obj = {} if (!errx) { try { obj = JSON.parse(data.replace(/\/\*[^(\*\/)]*\*\/|\/\/.*/g, '')) } catch (err) { err = err+'' var answer = app.dialog.showMessageBox(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(filepath, true) + ' backup ' + new Date().toLocaleString().split(':').join('_') backup_file_name = filepath.replace(pathToName(filepath, 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) }) } }) } } } } var model_name = Project.parent if (model_name == '') model_name = 'geometry.unknown' obj[model_name] = content content = autoStringify(obj) fs.writeFile(filepath, content, function (err) { if (err) { console.log('Error Saving Entity Model: '+err) } Blockbench.showQuickMessage('message.save_entity') Prop.project_saved = true; setProjectTitle(pathToName(filepath, false)) addRecentProject({name: pathToName(filepath, 'mobs_id'), path: filepath}) }) }) } function writeFileObj(content, filepath) { if (filepath === undefined) { return; } var content = buildOBJModel(pathToName(filepath, false)) //OBJECT fs.writeFile(filepath, content.obj, function (err) {}) //MATERIAL fs.writeFile(filepath.split('.obj').join('.mtl'), content.mtl, function (err) {}) //IMAGES if (settings.obj_textures.value === true) { for (var key in content.images) { var texture = content.images[key] if (content.images.hasOwnProperty(key) && texture.path) { if (texture.mode === 'link') { var native_image_instance = nativeImage.createFromPath(texture.path) } else { var native_image_instance = nativeImage.createFromDataURL(texture.source) } var image = native_image_instance.toPNG() var image_path = filepath.split(osfs) image_path.pop() image_path = image_path.join(osfs) + osfs + texture.name if (image_path.substr(-4) !== '.png') { image_path = image_path + '.png' } fs.writeFile(image_path, image, function (err) {}) } } } Blockbench.showQuickMessage('message.save_obj') } //Open function readFile(filepath, makeNew) { fs.readFile(filepath, 'utf-8', function (err, data) { if (err) { console.log(err) Blockbench.showMessageBox({ translateKey: 'file_not_found', icon: 'error_outline' }) return; } addRecentProject({name: pathToName(filepath, 'mobs_id'), path: filepath}) loadModel(data, filepath, !makeNew) }) } //Backup function createBackup(init) { setTimeout(createBackup, limitNumber(parseFloat(settings.backup_interval.value), 1, 10e8)*60000) if (init || elements.length === 0) return; var model = buildBlockModel({ backup: true, raw: true, cube_name: true, prevent_dialog: true, comment: false, groups: true }) var d = new Date() var file_name = 'backup_'+d.getDate()+'.'+(d.getMonth()+1)+'.'+(d.getYear()-100)+'_'+d.getHours()+'.'+d.getMinutes() var file_path = app.app.getPath('userData')+osfs+'backups'+osfs+file_name+'.json' fs.writeFile(file_path, JSON.stringify(model), function (err) { if (err) { console.log('Error creating backup: '+err) } }) } //Zoom function setZoomLevel(mode) { switch (mode) { case 'in': Prop.zoom += 5; break; case 'out': Prop.zoom -= 5; break; case 'reset': Prop.zoom = 100; break; } var level = (Prop.zoom - 100) / 12 currentwindow.webContents.setZoomLevel(level) resizeWindow() } //Close window.onbeforeunload = function() { if (preventClosing === true) { setTimeout(function() { showSaveDialog(true) }, 2) return true; } } function showSaveDialog(close) { if (Blockbench.flags.includes('allow_reload')) { close = false } var unsaved_textures = 0; textures.forEach(function(t) { if (!t.saved) { unsaved_textures++; } }) if ((Prop.project_saved === false && elements.length > 0) || unsaved_textures) { var answer = app.dialog.showMessageBox(currentwindow, { type: 'question', buttons: [tl('dialog.save'), tl('dialog.discard'), tl('dialog.cancel')], title: 'Blockbench', message: tl('message.close_warning.message'), noLink: true }) if (answer === 0) { saveFile({closeAfter: close}) return false; } else if (answer === 2) { return false; } else { if (close === true) { preventClosing = false setTimeout(function() { currentwindow.close() }, 12) } return true; } } else { if (close === true) { preventClosing = false setTimeout(function() { currentwindow.close() }, 12) } return true; } }