This commit is contained in:
JannisX11 2017-11-16 22:23:41 +01:00 committed by GitHub
parent 51c7cfda12
commit 8cd21810af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 809 additions and 349 deletions

View File

@ -129,6 +129,11 @@
height: 30px;
width: 24px;
}
i.material-icons.message_box_icon {
font-size: 40pt;
float: left;
padding-right: 8px;
}
/*Vars*/
body {
@ -408,6 +413,7 @@
}
header div#title {
width: auto;
min-width: 154px;
padding-right: 16px;
padding-left: 06px;
padding-top: 2px;
@ -588,8 +594,9 @@
.ui#textures {
bottom: 0;
position: fixed;
top: 520px;
top: 514px;
width: 328px;
border-top: 1px solid var(--color-border);
}
.ui#uv {
@ -1143,7 +1150,7 @@
#options .bar .tool.wide {
width: 83px;
}
.tool#origin2geometry .tooltip {
.tool .tooltip.clip_right {
right: 0;
}
#cube_rescale {
@ -1409,6 +1416,16 @@
image-rendering: pixelated;
margin-bottom: -7px;
}
#entity_mode_resolution_button {
display: none;
}
body.entity_mode #entity_mode_resolution_button {
display: block;
padding: 0;
height: 32px;
width: 154px;
border: none;
}
/*Display*/
.mode_tab {

View File

@ -54,8 +54,22 @@
<script src="js/plugin_loader.js"></script>
<script>if (window.module) module = window.module;</script>
<div id="post_model" class="web_only post_data" hidden></div>
<div id="post_textures" class="web_only post_data" hidden></div>
<div id="post_model" class="web_only post_data" hidden><?php
if ( $_SERVER['REQUEST_METHOD'] == 'POST' ) {
$model = $_POST['model'];
if ($model != "text") {
echo $model;
}
}
?></div>
<div id="post_textures" class="web_only post_data" hidden><?php
if ( $_SERVER['REQUEST_METHOD'] == 'POST' ) {
$textures = $_POST['textures'];
if ($textures != "text") {
echo $textures;
}
}
?></div>
<!---->
<div id="blackout" onclick="$('.dialog#'+open_dialog).find('.cancel_btn:not([disabled])').click()"></div>
@ -63,7 +77,6 @@
<div id="welcome_content"></div>
<button type="button" class="large cancel_btn hidden" onclick="hideDialog()">Cancel</button>
<div id="dialog_close_button" onclick="$('.dialog#'+open_dialog).find('.cancel_btn:not([disabled])').click()"><i class="material-icons">clear</i></div>
</div>
<div class="dialog draggable paddinged" id="file_loader">
@ -270,7 +283,7 @@
<div class="dialog_bar" style="height: 32px;">
<input type="range" id="model_scale_range" value="1" min="0" max="4" step="0.02" oninput="modelScaleSync()">
<input type="number" class="f_left" id="model_scale_label" min="0" max="4" value="1" oninput="modelScaleSync(true)">
<input type="number" class="f_left" id="model_scale_label" min="0" max="4" step="0.02" value="1" oninput="modelScaleSync(true)">
</div>
<div class="dialog_bar narrow" id="scaling_clipping_warning"></div>
@ -937,8 +950,8 @@
<input class="hidden" type="radio" name="display" id="gui">
<label class="tool" for="gui" onclick="loadDispGUI()"><i class="material-icons">border_style</i><div class="tooltip">GUI</div></label>
</div>
<p>Reference Model</p>
<div id="display_ref_bar" class="bar tabs_small">
<p class="reference_model_bar">Reference Model</p>
<div id="display_ref_bar" class="bar tabs_small reference_model_bar">
</div>
<p>Rotation</p><div class="tool head_right" onclick="resetDisplaySettings('rotation')"><i class="material-icons">replay</i></div>
@ -1043,22 +1056,22 @@
<option value="z" id="z">Z Axis</option>
</select>
<div class="tool" id="cube_rescale_tool"><input type="checkbox" id="cube_rescale" class="rotation_tool" onclick="Rotation.set()"><div class="tooltip">Rescale</div></div>
<div class="tool right_tool" id="origin2geometry" onclick="Rotation.remove()"><i class="material-icons">clear</i><div class="tooltip">Remove Rotation</div></div>
<div class="tool right_tool" id="rotation_function_button" onclick="Rotation.fn()"><i class="material-icons">clear</i><div class="tooltip clip_right">Remove Rotation</div></div>
</div>
<div class="bar">
<div class="placeholder"></div>Origin
<div class="placeholder"></div><div id="rotation_origin_label">Origin</div>
</div>
<div class="bar">
<div class="tool wide nslide_tool"><div class="nslide" n-action="origin_x"></div><div class="tooltip">Origin X</div></div>
<div class="tool wide nslide_tool"><div class="nslide" n-action="origin_y"></div><div class="tooltip">Origin Y</div></div>
<div class="tool wide nslide_tool"><div class="nslide" n-action="origin_z"></div><div class="tooltip">Origin Z</div></div>
<div class="tool right_tool" id="origin2geometry" onclick="origin2geometry()"><i class="material-icons">center_focus_strong</i><div class="tooltip">Origin To Geometry</div></div>
<div class="tool right_tool" id="origin2geometry" onclick="origin2geometry()"><i class="material-icons">center_focus_strong</i><div class="tooltip clip_right">Origin To Geometry</div></div>
</div>
</div>
<div id="outliner" class="ui">
<h3>Outliner</h3>
<div class="bar m_edit">
<div class="tool" onclick="addCube(0,0,0,canvas_grid,canvas_grid,canvas_grid)"><i class="material-icons">add_box</i><div class="tooltip">Add Cube</div></div>
<div class="tool" onclick="addCube()"><i class="material-icons">add_box</i><div class="tooltip">Add Cube</div></div>
<div class="tool" onclick="addGroup()"><i class="material-icons">create_new_folder</i><div class="tooltip">Add Group</div></div>
<div class="tool" id="outliner_option_toggle" onclick="toggleOutlinerOptions()"><i class="material-icons">view_stream</i><div class="tooltip">More Options</div></div>
<div id="outliner_stats">0/0</div>

View File

@ -643,7 +643,7 @@
};
this.calcPosition = function(offset) {
/*this.calcPosition = function(offset) {
if (selected.length === 0) return;
scope.children[0].rotation.set(0, 0, 0)
@ -666,13 +666,32 @@
}
var vec = new THREE.Vector3()
vec.set(center[0], center[1], center[2])
if (settings.entity_mode.value) {
var obj = elements[selected[0]]
if (obj.display.parent !== 'root' &&
typeof obj.display.parent === 'object' &&
obj.display.parent.display.parent === 'root' &&
obj.display.parent.rotation.join('_') !== '0_0_0'
) {
vec.setFromMatrixPosition(obj.display.mesh.matrixWorld)
scope.rotation['x'] = Math.PI / (180 / obj.display.parent.rotation[0])
scope.rotation['y'] = Math.PI / (180 / obj.display.parent.rotation[1])
scope.rotation['z'] = Math.PI / (180 / obj.display.parent.rotation[2])
vec.x -= obj.display.parent.origin[0]
vec.y -= obj.display.parent.origin[1]
vec.z -= obj.display.parent.origin[2]
}
} else {
scope.rotation.set(0, 0, 0)
}
if (offset !== undefined) {
vec.add(offset)
if (movementAxis === true) {
var obj = elements[selected[0]]
if (obj.rotation) {
if (obj.rotation && settings.entity_mode.value === false) {
vec.setFromMatrixPosition(obj.display.mesh.matrixWorld)
scope.children[0].rotation[obj.rotation.axis] = Math.PI / (180 / obj.rotation.angle)
scope.rotation[obj.rotation.axis] = Math.PI / (180 / obj.rotation.angle)
vec.x -= obj.rotation.origin[0]
vec.y -= obj.rotation.origin[1]
vec.z -= obj.rotation.origin[2]
@ -681,7 +700,7 @@
scope.position.copy(vec)
//scope.position.add(vec)
}
}
}*/
function onPointerHover( event ) {
@ -803,13 +822,10 @@
var axis = scope.axis.toLowerCase()
scope.direction = true
}
//if (axis !== 'x') point.x = 0;
//if (axis !== 'y') point.y = 0;
//if (axis !== 'z') point.z = 0;
var axisNumber = getAxisNumber(axis)
var snap_factor = getSnapFactor(event)
point[axis] = Math.round( point[axis] / snap_factor ) * snap_factor
var snap_factor = canvasGridSize(event.shiftKey, event.ctrlKey)
point[axis] = Math.round( point[axis] / snap_factor ) * snap_factor * (useBedrockFlipFix(axis) ? -1 : 1)
if (previousValue !== point[axis]) {
@ -840,8 +856,8 @@
if ( scope.axis !== "Y") point.y = 0;
if ( scope.axis !== "Z") point.z = 0;
var snap_factor = getSnapFactor(event)
point[axis] = Math.round( point[axis] / snap_factor ) * snap_factor
var snap_factor = canvasGridSize(event.shiftKey, event.ctrlKey)
point[axis] = Math.round( point[axis] / snap_factor ) * snap_factor * (useBedrockFlipFix(axis) ? -1 : 1)
if (previousValue !== point[axis]) {
@ -863,6 +879,14 @@
if (movementAxis === true) {
rotatedPoint.applyEuler( scope.objects[0].rotation )
}
var obj = elements[selected[0]]
if (settings.entity_mode.value &&
typeof obj.display.parent === 'object' &&
obj.display.parent.display.parent === 'root' &&
obj.display.parent.rotation.join('_') !== '0_0_0'
) {
rotatedPoint.applyEuler( scope.objects[0].rotation )
}
scope.objects.forEach(function(s, i) {
s.position.copy( oldPositionArray[i] );
@ -910,7 +934,7 @@
}
selected.forEach(function(s) {
moveCube(elements[s], elements[s].from[getAxisNumber(axis)] + difference, getAxisNumber(axis))
moveCube(elements[s], elements[s].from[getAxisNumber(axis)] + difference * (useBedrockFlipFix(axis) ? -1 : 1), getAxisNumber(axis))
})
setUndo('Moved cube'+pluralS(selected))

View File

@ -41,6 +41,63 @@ class API {
showQuickMessage(message)
}
}
showMessageBox(options, cb) {
if (options.confirm === undefined) options.confirm = 0
if (options.cancel === undefined) options.cancel = 0
if (!options.buttons) options.buttons = ['Ok']
var jq_dialog = $('<div class="dialog paddinged" style="width: auto;" id="message_box"><h2 class="dialog_handle">'+options.title+'</h2></div>')
jq_dialog.append('<div class="dialog_bar" style="height: auto; min-height: 56px; margin-bottom: 16px;">'+
(options.icon ? '<i class="material-icons message_box_icon">'+options.icon+'</i>' : '')+
options.message+'</div>'
)
var buttons = []
options.buttons.forEach(function(b, i) {
var btn = $('<button type="button" class="large">'+b+'</button>')
btn.click(function(e) {
hideDialog()
setTimeout(function() {
jq_dialog.remove()
},200)
cb(i)
})
buttons.push(btn)
})
buttons[options.confirm].addClass('confirm_btn')
buttons[options.cancel].addClass('cancel_btn')
jq_dialog.append($('<div class="dialog_bar"></div>').append(buttons))
jq_dialog.addClass('draggable')
jq_dialog.draggable({
handle: ".dialog_handle"
})
var x = ($(window).width()-540)/2
jq_dialog.css('left', x+'px')
jq_dialog.css('position', 'absolute')
$('#plugin_dialog_wrapper').append(jq_dialog)
$('.dialog').hide(0)
$('#blackout').fadeIn(100)
jq_dialog.fadeIn(100)
jq_dialog.css('top', limitNumber($(window).height()/2-jq_dialog.height()/2, 0, 100)+'px')
if (options.width) {
jq_dialog.css('width', options.width+'px')
} else {
jq_dialog.css('width', limitNumber(options.buttons.length*170+44, 380, 894)+'px')
}
setTimeout(function() {
$('.context_handler.ctx').removeClass('ctx')
}, 64)
open_dialog = 'message_box'
return jq_dialog
}
import(type, cb, extensions) {
type = type.replace('.', '')
@ -168,7 +225,6 @@ function Dialog(settings) {
setTimeout(function() {
$(scope.object).remove()
},this.fadeTime)
console.log('Hiding Dialog')
}
this.confirmEnabled = settings.confirmEnabled === false ? false : true
@ -302,4 +358,4 @@ function ContextMenu(event, array) {
return ctxmenu;
}
var Blockbench = new API()
var Blockbench = new API()

132
js/app.js
View File

@ -38,7 +38,7 @@ function getLatestVersion(init) {
$.getJSON('http://blockbench.net/api/index.json', function(data) {
if (data.version) {
latest_version = data.version
if (latest_version !== appVersion && init === true) {
if (compareVersions(latest_version, appVersion) && init === true) {
showDialog('update_notification')
$('.dialog#update_notification h2 span').text(latest_version)
console.log('Found new version: '+latest_version)
@ -209,52 +209,9 @@ function saveFileEntity() {
if (fileName === undefined) {
return;
}
var content = buildEntityModel(false)
fs.readFile(fileName, 'utf-8', function (errx, data) {
var obj = {}
if (!errx) {
try {
obj = JSON.parse(data)
} catch (err) {
err = err+''
var answer = app.dialog.showMessageBox(currentwindow, {
type: 'warning',
buttons: ['Create Backup and Overwrite', 'Overwrite', 'Cancel'],
title: 'Blockbench',
message: 'Blockbench cannot combine this model with the old file',
detail: err,
noLink: false
})
if (answer === 0) {
var backup_file_name = pathToName(fileName, true) + ' backup ' + new Date().toLocaleString().split(':').join('_')
backup_file_name = fileName.replace(pathToName(fileName, 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;
}
}
}
var model_name = Project.parent
if (model_name == '') model_name = 'geometry.unknown'
obj[model_name] = content
content = autoStringify(obj)
fs.writeFile(fileName, content, function (err) {
if (err) {
console.log('Error Saving Entity Model: '+err)
}
showQuickMessage('Saved as bedrock entity model')
})
})
var content = buildEntityModel({raw: true})
writeFileEntity(content, fileName)
})
}
function saveFileObj() {
@ -297,25 +254,80 @@ function saveFileObj() {
//Writers
function saveFile(props) {
if (Prop.file_path !== 'Unknown') {
var content = buildBlockModel(true)
Prop.project_saved = true;
$('title').text(pathToName(Prop.file_path, false)+' - Blockbench')
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)
}
showQuickMessage('Saved as '+ pathToName(Prop.file_path, true))
})
if (settings.entity_mode.value === false) {
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)
}
showQuickMessage('Saved as '+ pathToName(Prop.file_path, true))
})
} else {
var content = buildEntityModel({raw: true})
writeFileEntity(content, Prop.file_path)
}
} else {
saveFileBlock()
if (settings.entity_mode.value === false) {
saveFileBlock()
} else {
saveFileEntity()
}
}
}
function writeFileEntity(content, fileName) {
Prop.file_path = fileName
fs.readFile(fileName, 'utf-8', function (errx, data) {
var obj = {}
if (!errx) {
try {
obj = JSON.parse(data)
} catch (err) {
err = err+''
var answer = app.dialog.showMessageBox(currentwindow, {
type: 'warning',
buttons: ['Create Backup and Overwrite', 'Overwrite', 'Cancel'],
title: 'Blockbench',
message: 'Blockbench cannot combine this model with the old file',
detail: err,
noLink: false
})
if (answer === 0) {
var backup_file_name = pathToName(fileName, true) + ' backup ' + new Date().toLocaleString().split(':').join('_')
backup_file_name = fileName.replace(pathToName(fileName, 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;
}
}
}
var model_name = Project.parent
if (model_name == '') model_name = 'geometry.unknown'
obj[model_name] = content
content = autoStringify(obj)
fs.writeFile(fileName, content, function (err) {
if (err) {
console.log('Error Saving Entity Model: '+err)
}
showQuickMessage('Saved as bedrock entity model')
})
})
}
//Open
function openFile(makeNew) {

View File

@ -1,4 +1,4 @@
var appVersion = '1.10.0'
var appVersion = '1.10.1'
var osfs = '/'
var File, i;
var browser_name = 'electron'
@ -26,7 +26,6 @@ var nslide = {
lock: null
}
var uv_clipboard;
var canvas_grid = 1;
var outliner, texturelist;
var pe_list_data = []
var _vect;
@ -99,6 +98,7 @@ function initializeApp() {
Prop.fps = framespersecond;
framespersecond = 0;
}, 1000)
settings.entity_mode.value = false
main_uv = new UVEditor('main_uv', false, true)
main_uv.setToMainSlot()
@ -117,6 +117,15 @@ function initializeApp() {
dropOutlinerObjects(item, undefined, event)
}
})
$('#cubes_list').contextmenu(function(event) {
new ContextMenu(event, [
{icon: 'add_box', name: 'Add Cube', click: function() {addCube()} },
{icon: 'create_new_folder', name: 'Add Group', click: function() {addGroup()} },
{icon: 'sort_by_alpha', name: 'Sort', click: function() {sortOutliner()} },
{icon: 'playlist_add_check', name: 'Select All', click: function() {selectAll()} },
{icon: 'dns', name: 'Toggle Options', click: function() {toggleOutlinerOptions()} },
])
})
//Events
@ -167,11 +176,9 @@ function initializeApp() {
if (!isApp) {
showSplashScreen = tryLoadPOSTModel()
}
if (isApp && showSplashScreen) {
showSplashScreen = __dirname.includes('htdocs') === false
}
if (showSplashScreen) {
$('#welcome_content').load('http://www.blockbench.net/api/welcome/index.html', function() {
//$('#welcome_content').load('http://www.blockbench.net/api/welcome/index.html', function() {
$('#welcome_content').load('C:\\xampp\\htdocs\\blockbench\\api\\welcome\\index.html', function() {
$('#welcome_screen #welcome_content').css('max-height', ($(window).height() - 460)+'px')
showDialog('welcome_screen')
localStorage.setItem('welcomed_version', appVersion)
@ -229,14 +236,20 @@ function setupVue() {
textures[index].selected = true
}
var index = textures.indexOf(item)
new ContextMenu(event, [
{icon: 'crop_original', name: 'Apply to Faces', click: function() { item.apply()}},
{icon: 'fa-cube', name: 'Apply to Cubes', click: function() { item.apply(true)}},
var menu_points = []
if (settings.entity_mode.value === false) {
menu_points = [
{icon: 'crop_original', name: 'Apply to Faces', click: function() { item.apply()}},
{icon: 'fa-cube', name: 'Apply to Cubes', click: function() { item.apply(true)}},
]
}
menu_points.push(
{icon: 'refresh', name: 'Refresh', local_only: true, click: function() {item.reloadTexture()}},
{icon: 'folder', name: 'Open in Folder', local_only: true, click: function() {item.openFolder()}},
{icon: 'delete', name: 'Delete', click: function() { item.remove()}},
{icon: 'settings',name: 'Settings', click: function() { openTextureMenu(index)}}
])
{icon: 'list', name: 'Properties', click: function() { openTextureMenu(index)}}
)
new ContextMenu(event, menu_points)
}
}
})
@ -344,8 +357,20 @@ function resetAllKeybindings() {
$.extend(keybinds, keybindSetup(true))
localStorage.setItem('keybinds', JSON.stringify(omitKeys(keybinds, ['name'], true)))
}
function calcCanvasGridSize() {
canvas_grid = 16 / limitNumber(settings.edit_size.value, 1, 64)
function canvasGridSize(shift, ctrl) {
if (!shift && !ctrl) {
return 16 / limitNumber(settings.edit_size.value, 1, 64)
} else if (ctrl && shift) {
var basic = 16 / limitNumber(settings.edit_size.value, 1, 64)
var control = 16 / limitNumber(settings.ctrl_size.value, 1, 1024)
var shift = 16 / limitNumber(settings.shift_size.value, 1, 1024)
control = basic / control
return shift / control
} else if (ctrl) {
return 16 / limitNumber(settings.ctrl_size.value, 1, 1024)
} else {
return 16 / limitNumber(settings.shift_size.value, 1, 1024)
}
}
//NSlide Trigger
@ -367,7 +392,7 @@ function setupNslides(scope) {
nslideSlide(this, event, ui)
},
start: function(event, ui) {
nslide.pre = canvas_grid
nslide.pre = canvasGridSize()
nslide.top = ui.position.top
nslide.left = ui.position.left
},
@ -469,7 +494,7 @@ function nslideSlide(obj, event, ui) {
//Math
var offset = Math.round((event.clientX-nslide.left)/50)
if (isUV === false) {
offset *= canvas_grid;
offset *= canvasGridSize();
}
var difference = offset - nslide.pre;
nslide.pre = offset;
@ -521,17 +546,10 @@ function nslideArrow(button, difference, event) {
if (action.includes('uv') === false) {
difference *= canvas_grid;
difference *= canvasGridSize(event.shiftKey, event.ctrlKey);
}
if (event.shiftKey === true) {
difference *= 0.25
}
if (event.ctrlKey === true) {
difference *= 0.1
}
var isUV = false
if (action.includes('uv') === true) isUV = true
@ -589,6 +607,7 @@ function nslideStorage(key, val, index) {
selected_group.origin[2] = val
break;
}
Canvas.updatePositions()
} else if (selected.length > 0) {
if (index !== undefined) {
affected = [index]
@ -768,30 +787,15 @@ function moveCube(obj, val, axis) {
if (obj.rotation && movementAxis === false) {
obj.rotation.origin[axis] += difference
}
obj.mapAutoUV()
}
function scaleCube(obj, val, axis) {
obj.to[axis] = limitToBox(val + obj.from[axis])
if (obj.display.autouv === true && settings.entity_mode.value === false) {
obj.faces.north.uv = calcAutoUV(obj, 'north', [obj.size(0), obj.size(1)])
obj.faces.east.uv = calcAutoUV(obj, 'east', [obj.size(2), obj.size(1)])
obj.faces.south.uv = calcAutoUV(obj, 'south', [obj.size(0), obj.size(1)])
obj.faces.west.uv = calcAutoUV(obj, 'west', [obj.size(2), obj.size(1)])
obj.faces.up.uv = calcAutoUV(obj, 'up', [obj.size(0), obj.size(2)])
obj.faces.down.uv = calcAutoUV(obj, 'down', [obj.size(0), obj.size(2)])
Canvas.updateUV(elements.indexOf(obj))
}
obj.mapAutoUV()
}
function scaleCubeNegative(obj, val, axis) {
obj.from[axis] = limitToBox(obj.to[axis] - val)
if (obj.display.autouv === true && settings.entity_mode.value === false) {
obj.faces.north.uv = calcAutoUV(obj, 'north', [obj.size(0), obj.size(1)])
obj.faces.east.uv = calcAutoUV(obj, 'east', [obj.size(2), obj.size(1)])
obj.faces.south.uv = calcAutoUV(obj, 'south', [obj.size(0), obj.size(1)])
obj.faces.west.uv = calcAutoUV(obj, 'west', [obj.size(2), obj.size(1)])
obj.faces.up.uv = calcAutoUV(obj, 'up', [obj.size(0), obj.size(2)])
obj.faces.down.uv = calcAutoUV(obj, 'down', [obj.size(0), obj.size(2)])
Canvas.updateUV(elements.indexOf(obj))
}
obj.mapAutoUV()
}
function moveCubesRelative(difference, index) { //Multiple
var axes = []
@ -820,7 +824,7 @@ function moveCubesRelative(difference, index) { //Multiple
if (index === 2 && height !== 'down') difference *= -1
if (index === 1 && height === 'up') difference *= -1
difference *= canvas_grid;
difference *= canvasGridSize();
var action = 'pos_'+axes[index]
selected.forEach(function(s) {
@ -844,7 +848,7 @@ function addToSelection(id, event, isOutlinerClick) {
} else {
starting_point = true
}
if (s.title === 'Cube') {
if (s.type === 'cube') {
var index = elements.indexOf(s)
if (!selected.includes(index)) {
selected.push(index)
@ -853,7 +857,7 @@ function addToSelection(id, event, isOutlinerClick) {
s.selectLow()
}
} else if (starting_point) {
if (s.title === 'Cube') {
if (s.type === 'cube') {
var index = elements.indexOf(s)
if (!selected.includes(index)) {
selected.push(index)
@ -899,7 +903,7 @@ function updateSelection() {
//Selected Elements
selected = selected.filter(function(s) {
return typeof elements[s] === 'object' && elements[s].title === 'Cube'
return typeof elements[s] === 'object' && elements[s].type === 'cube'
})
@ -919,7 +923,10 @@ function updateSelection() {
} else if (selected.length === 0) {
$('.selection_only').css('visibility', 'hidden')
}
if ((selected.length > 0) || settings.entity_mode.value && selected_group) {
if (
(settings.entity_mode.value === true && selected_group !== undefined) ||
(settings.entity_mode.value === false && (selected_group !== undefined || selected.length > 0))
) {
Rotation.load()
}
$('#outliner_stats').text(selected.length+'/'+elements.length)
@ -928,11 +935,6 @@ function updateSelection() {
movementAxis = isMovementOnRotatedAxis()
centerTransformer()
updateNslideValues()
if (selected_group && selected.length === 0) {
Rotation.groupMode()
} else if (selected.length > 0) {
Rotation.cubeMode()
}
if (settings.entity_mode.value) {
if (selected_group) {
$('.selection_only#options').css('visibility', 'visible')
@ -1082,9 +1084,11 @@ var Undo = {
entry.textures.forEach(function(s) {
var tex = new Texture(s)
var arr = tex.iconpath.split('?')
arr[arr.length-1] = tex_version
tex.iconpath = arr.join('?')
if (Blockbench.isWeb === false) {
var arr = tex.iconpath.split('?')
arr[arr.length-1] = tex_version
tex.iconpath = arr.join('?')
}
tex.load()
textures.push(tex)
@ -1160,8 +1164,9 @@ function paint() {
elements[selected[0]].from[1]+0,
elements[selected[0]].from[2]+0
]
var canvas_grid = canvasGridSize()
var sizes = [canvas_grid, canvas_grid, canvas_grid]
if (brush_template && brush_template.title === 'Cube') {
if (brush_template && brush_template.type === 'cube') {
sizes = brush_template.size()
}
switch (main_uv.face) {
@ -1498,6 +1503,9 @@ function mirror(axis) {
setUndo('Mirrored cubes')
}
function openScaleAll() {
$('#model_scale_range').val(1)
$('#model_scale_label').val(1)
selected.forEach(function(s) {
var obj = elements[s]
obj.display.before = {from: [], to: [], origin: [8, 8, 8]}
@ -1522,7 +1530,7 @@ function scaleAll(save, size) {
hideDialog()
}
if (size === undefined) {
size = $('#model_scale_range').val()
size = $('#model_scale_label').val()
}
origin = [8, 8, 8]
if (settings.entity_mode.value) {

View File

@ -79,7 +79,7 @@ function initCanvas() {
//TransformControls
Transformer = new THREE.TransformControls(cameraPers, canvas1)
Transformer.setSize(0.5)
Transformer.setTranslationSnap(canvas_grid)
Transformer.setTranslationSnap(canvasGridSize())
scene.add(Transformer)
enterScene(true)
@ -327,7 +327,7 @@ function buildGrid() {
if (settings.full_grid.value === true) {
size = 24
step = canvas_grid;
step = canvasGridSize();
var geometry = new THREE.Geometry();
@ -401,7 +401,7 @@ function buildGrid() {
if (settings.base_grid.value === true) {
size = 8
step = canvas_grid;
step = canvasGridSize();
var geometry = new THREE.Geometry();
@ -579,8 +579,7 @@ function canvasClick( event ) {
}
main_uv.setFace(selectedFace)
var obj = TreeElements.findRecursive('uuid', intersects[0].object.name)
event.cube = obj
Blockbench.dispatchEvent( 'canvas_select', event )
Blockbench.dispatchEvent( 'canvas_select', {event: event, intersects: intersects, face: selectedFace, cube: obj} )
addToSelection(elements.indexOf(obj), event)
if (Prop.tool === 'brush' && event.shiftKey === false) {
@ -607,6 +606,10 @@ function toggleTools() {
function centerTransformer(offset) {
if (selected.length === 0) return;
var obj = elements[selected[0]]
//Getting Center
var center = [0, 0, 0]
var i = 0;
@ -624,26 +627,68 @@ function centerTransformer(offset) {
center[i] = center[i] / (selected.length * 2)
i++;
}
var obj = elements[selected[0]]
var vec = new THREE.Vector3(center[0], center[1], center[2])
if (selected.length === 1 && obj.rotation !== undefined) {
vec.x -= obj.rotation.origin[0]
vec.y -= obj.rotation.origin[1]
vec.z -= obj.rotation.origin[2]
vec.applyEuler(obj.display.mesh.rotation)
vec.x += obj.rotation.origin[0]
vec.y += obj.rotation.origin[1]
vec.z += obj.rotation.origin[2]
}
Transformer.position.copy(vec)
Transformer.rotation.set(0, 0, 0)
if (obj.rotation !== undefined && movementAxis === true) {
Transformer.rotation[obj.rotation.axis] = Math.PI / (180 / obj.rotation.angle)
//Position + Rotation
if (settings.entity_mode.value === false) {
//Blockmodel Mode
Transformer.rotation.set(0, 0, 0)
if (selected.length === 1 && obj.rotation !== undefined) {
vec.x -= obj.rotation.origin[0]
vec.y -= obj.rotation.origin[1]
vec.z -= obj.rotation.origin[2]
if (obj.display.mesh) {
vec.applyEuler(obj.display.mesh.rotation)
}
vec.x += obj.rotation.origin[0]
vec.y += obj.rotation.origin[1]
vec.z += obj.rotation.origin[2]
}
Transformer.position.copy(vec)
if (obj.rotation !== undefined && movementAxis === true) {
Transformer.rotation[obj.rotation.axis] = Math.PI / (180 / obj.rotation.angle)
}
} else {
//Entity Mode
var group;
if (selected_group) {
var group = selected_group
} else {
var i = 0;
while (i < selected.length) {
if (typeof elements[selected[i]].display.parent === 'object' &&
elements[selected[i]].display.parent.type === 'group'
) {
var group = elements[selected[i]].display.parent
}
i++;
}
}
if (group) {
vec.x -= group.origin[0]
vec.y -= group.origin[1]
vec.z -= group.origin[2]
vec.applyEuler(obj.display.mesh.rotation)
vec.x += group.origin[0]
vec.y += group.origin[1]
vec.z += group.origin[2]
}
Transformer.position.copy(vec)
Transformer.rotation.copy(elements[selected[0]].display.mesh.rotation)
}
if (offset !== undefined) {
Transformer.position.add(offset)
}
}
function getRescalingFactor(angle) {
@ -828,7 +873,7 @@ class CanvasController {
var arr = selected.slice()
if (settings.entity_mode.value && selected_group) {
selected_group.children.forEach(function(s) {
if (s.title === 'Cube') {
if (s.type === 'cube') {
var index = elements.indexOf(s)
if (!arr.includes(index)) {
arr.push(index)
@ -836,7 +881,7 @@ class CanvasController {
}
})
}
selected.forEach(function(s) {
arr.forEach(function(s) {
if (elements[s].display.visibility == true) {
Canvas.adaptObjectPosition(elements[s].display.mesh, elements[s])
}

View File

@ -226,7 +226,7 @@ class refModel {
var skin = 'assets/player_skin.png';
$.getJSON('http://blockbench.net/api/index.json', function (data) {
if (data.donatorSkin == true) {
skin = 'http://blockbench.net/api/player_skin.png';
skin = 'http://blockbench.net/api/player_skin.png?'+(Math.random()+'').substr(2, 3);
}
}).always(function() {
scope.buildModel(things, skin);
@ -975,6 +975,11 @@ var displayReferenceObjects = {
this.refmodels[buttons[0]].load()
return;
}
if (buttons.length < 2) {
$('.reference_model_bar').css('visibility', 'hidden')
} else {
$('.reference_model_bar').css('visibility', 'visible')
}
var i = 0;
while (i < buttons.length) {
var ref = this.refmodels[buttons[i]]

View File

@ -64,11 +64,14 @@ var OutlinerButtons = {
},
autouv: {
title: 'Auto UV',
icon: ' fa fa-magic',
icon_off: ' fa fa-minus',
icon: ' fa fa-thumb-tack',
icon_off: ' fa fa-times-circle-o',
icon_alt: ' fa fa-magic',
advanced_option: true,
click: function(obj) {
var state = !obj.display.autouv
var state = obj.display.autouv+1
if (state > 2) state = 0
if (selected.length < 2 || !selected.includes(obj.index())) {
obj.setAutoUV(state)
} else {
@ -85,7 +88,7 @@ var selected_group;
//Cubes
class Face {
constructor() {
this.uv = [0, 0, canvas_grid, canvas_grid]
this.uv = [0, 0, canvasGridSize(), canvasGridSize()]
}
}
class OutlinerElement {
@ -100,7 +103,7 @@ class OutlinerElement {
if (group === undefined) {
group = 'root'
} else if (group !== 'root') {
if (group.title === 'Cube') {
if (group.type === 'cube') {
if (group.display.parent === 'root') {
index = TreeElements.indexOf(group)
group = 'root'
@ -110,7 +113,7 @@ class OutlinerElement {
}
}
}
if (group != 'root' && group.title === 'Group') {
if (group != 'root' && group.type === 'group') {
var i = 0
var level = group;
while (i < 50) {
@ -218,7 +221,13 @@ class OutlinerElement {
return this.shade
break;
case 'Auto UV':
return this.display.autouv
if (!this.display.autouv) {
return false
} else if (this.display.autouv === 1) {
return true
} else {
return 'alt'
}
break;
}
return true;
@ -230,9 +239,9 @@ class Cube extends OutlinerElement {
var x1 = 0;
var y1 = 0;
var z1 = 0;
var x2 = canvas_grid;
var y2 = canvas_grid;
var z2 = canvas_grid;
var x2 = canvasGridSize();
var y2 = x2;
var z2 = x2;
if (!name) name = 'cube';
if (!shade) shade = true;
this.name = name;
@ -242,7 +251,7 @@ class Cube extends OutlinerElement {
this.display = {
visibility: true,
isselected: true,
autouv: settings.autouv.value,
autouv: (settings.autouv.value ? 1 : 0),
export: true,
parent: 'root'
}
@ -352,6 +361,121 @@ class Cube extends OutlinerElement {
duplicateCubes()
elements[selected[0]].addTo(this)
}
mapAutoUV() {
if (settings.entity_mode.value) return;
var scope = this
if (scope.display.autouv === 2) {
var all_faces = ['north', 'south', 'west', 'east', 'up', 'down']
all_faces.forEach(function(side) {
var uv = scope.faces[side].uv.slice()
switch (side) {
case 'north':
uv = [
16 - scope.to[0],
16 - scope.to[1],
16 - scope.from[0],
16 - scope.from[1],
];
break;
case 'south':
uv = [
scope.from[0],
16 - scope.to[1],
scope.to[0],
16 - scope.from[1],
];
break;
case 'west':
uv = [
scope.from[2],
16 - scope.to[1],
scope.to[2],
16 - scope.from[1],
];
break;
case 'east':
uv = [
16 - scope.to[2],
16 - scope.to[1],
16 - scope.from[2],
16 - scope.from[1],
];
break;
case 'up':
uv = [
scope.from[0],
scope.from[2],
scope.to[0],
scope.to[2],
];
break;
case 'down':
uv = [
scope.from[0],
16 - scope.to[2],
scope.to[0],
16 - scope.from[2],
];
break;
}
uv.forEach(function(s, uvi) {
uv[uvi] = limitNumber(s, 0, 16)
})
scope.faces[side].uv = uv
})
Canvas.updateUV(scope.index())
} else if (scope.display.autouv === 1) {
function calcAutoUV(face, size) {
var sx = scope.faces[face].uv[0]
var sy = scope.faces[face].uv[1]
var rot = scope.faces[face].rotation
//Match To Rotation
if (rot === 90 || rot === 270) {
size.reverse()
}
//Limit Input to 16
size.forEach(function(s) {
if (s > 16) {
s = 16
}
})
//Calculate End Points
var x = sx + size[0]
var y = sy + size[1]
//Prevent Over 16
if (x > 16) {
sx = 16 - (x - sx)
x = 16
}
if (y > 16) {
sy = 16 - (y - sy)
y = 16
}
//Prevent Negative
if (sx < 0) sx = 0
if (sy < 0) sy = 0
//Prevent Mirroring
if (x < sx) x = sx
if (y < sy) y = sy
//if ()
//Return
return [sx, sy, x, y]
}
scope.faces.north.uv = calcAutoUV('north', [scope.size(0), scope.size(1)])
scope.faces.east.uv = calcAutoUV('east', [scope.size(2), scope.size(1)])
scope.faces.south.uv = calcAutoUV('south', [scope.size(0), scope.size(1)])
scope.faces.west.uv = calcAutoUV('west', [scope.size(2), scope.size(1)])
scope.faces.up.uv = calcAutoUV('up', [scope.size(0), scope.size(2)])
scope.faces.down.uv = calcAutoUV('down', [scope.size(0), scope.size(2)])
Canvas.updateUV(scope.index())
} else {
//
}
}
setVisibility(val) {
this.display.visibility = val !== false;
//
@ -365,12 +489,13 @@ class Cube extends OutlinerElement {
//
}
setAutoUV(val) {
this.display.autouv = val !== false;
//scaleCube(this, 0, 0)
this.display.autouv = val;
this.mapAutoUV()
Canvas.updateSelectedFaces()
}
}
Cube.prototype.title = 'Cube'
Cube.prototype.type = 'cube'
Cube.prototype.icon = 'fa fa-cube'
Cube.prototype.isParent = false
Cube.prototype.buttons = [
@ -444,6 +569,7 @@ class Group extends OutlinerElement {
if (this.display.isselected === false) return;
selected_group = undefined;
this.display.isselected = false
return this;
}
openUp() {
this.isOpen = true
@ -453,6 +579,7 @@ class Group extends OutlinerElement {
} else {
this.scrollOutlinerTo()
}
return this;
}
remove() {
this.unselect()
@ -489,6 +616,7 @@ class Group extends OutlinerElement {
TreeElements.clearObjectRecursive(this)
selected_group = undefined
delete this
return array
}
renameChildren() {
stopRenameCubes()
@ -496,13 +624,45 @@ class Group extends OutlinerElement {
}
showContextMenu(event) {
var scope = this;
new ContextMenu(event, [
var menu_points = [
{icon: 'content_copy', name: 'Duplicate', click: function() {scope.duplicate();setUndo('Duplicated Group')}},
{icon: 'sort_by_alpha', name: 'Sort', click: function() {scope.sortContent()}},
{icon: 'fa-leaf', name: 'Resolve', click: function() {scope.resolve();setUndo('Resolved Group')}},
{icon: 'text_format', name: 'Rename', click: function() {scope.rename()}},
{icon: 'fa-align-left', name: 'Rename Content', click: function() {scope.renameChildren()}}
])
]
if (settings.entity_mode.value) {
menu_points.push({icon: 'rotate_90_degrees_ccw', name: 'Rotation', click: function() {
scope.boneRotationDialog()
}})
}
new ContextMenu(event, menu_points)
}
boneRotationDialog() {
this.select()
var bone_rotation_dialog = new Dialog({
title: 'Bone Rotation',
draggable: true,
lines: [
'<div class="dialog_bar"><label class="inline_label">X: </label><input type="number" class="dark_bordered rotation_x" min="-180" max="180" step="0.5" oninput="selected_group.setBoneRotation(0, $(this))"></div>',
'<div class="dialog_bar"><label class="inline_label">Y: </label><input type="number" class="dark_bordered rotation_y" min="-180" max="180" step="0.5" oninput="selected_group.setBoneRotation(1, $(this))"></div>',
'<div class="dialog_bar"><label class="inline_label">Z: </label><input type="number" class="dark_bordered rotation_z" min="-180" max="180" step="0.5" oninput="selected_group.setBoneRotation(2, $(this))"></div>'
],
id: 'bone_rotation',
fadeTime: 100,
onCancel: function() {
hideDialog()
},
singleButton: true
}).show()
$(bone_rotation_dialog.object).find('input.rotation_x').val(this.rotation[0])
$(bone_rotation_dialog.object).find('input.rotation_y').val(this.rotation[1])
$(bone_rotation_dialog.object).find('input.rotation_z').val(this.rotation[2])
}
setBoneRotation(axis, obj) {
this.rotation[axis] = limitNumber(parseFloat(obj.val()), -180, 180)
if (isNaN(this.rotation[axis])) this.rotation[axis] = 0
Canvas.updatePositions()
}
sortContent() {
if (this.children.length < 1) return;
@ -517,7 +677,7 @@ class Group extends OutlinerElement {
var array = g1.children
i = 0;
while (i < array.length) {
if (array[i].title === 'Cube') {
if (array[i].type === 'cube') {
var dupl = new Cube().extend(array[i])
dupl.addTo(g2)
elements.push(dupl)
@ -551,7 +711,7 @@ class Group extends OutlinerElement {
var i = 0
while (i < this.children.length) {
func(this.children[i])
if (this.children[i].title === 'Group') {
if (this.children[i].type === 'group') {
this.children[i].forEachChild(func)
}
i++;
@ -584,14 +744,15 @@ class Group extends OutlinerElement {
}
setAutoUV(val) {
this.forEachChild(function(s) {
s.display.autouv = val !== false;
s.display.autouv = val;
s.updateElement()
})
this.display.autouv = val !== false;
this.display.autouv = val;
this.updateElement()
}
}
Group.prototype.title = 'Group'
Group.prototype.type = 'group'
Group.prototype.icon = 'fa fa-folder'
Group.prototype.isParent = true
Group.prototype.buttons = [
@ -660,7 +821,7 @@ function getAllOutlinerGroups() {
function iterate(array) {
var i = 0;
while (i < array.length) {
if (array[i].title === 'Group')
if (array[i].type === 'group')
ta.push(array[i])
if (array[i].children && array[i].children.length > 0) {
iterate(array[i].children)
@ -676,7 +837,7 @@ function compileGroups(save_nonexported, lut) {
function iterate(array, save_array) {
var i = 0;
while (i < array.length) {
if (array[i].title === 'Cube') {
if (array[i].type === 'cube') {
if (!save_nonexported || array[i].display.save_nonexported === true) {
if (lut) {
var index = lut[elements.indexOf(array[i])]
@ -687,29 +848,34 @@ function compileGroups(save_nonexported, lut) {
save_array.push(index)
}
}
} else if (array[i].title === 'Group') {
} else if (array[i].type === 'group') {
var obj = {
name: array[i].name,
isOpen: array[i].isOpen,
display: $.extend(true, {}, array[i].display),
children: []
}
if (array[i].origin.join('_') !== '8_8_8') {
obj.origin = array[i].origin
if (lut === undefined || obj.display.export === true) {
if (array[i].origin.join('_') !== '8_8_8') {
obj.origin = array[i].origin
}
if (array[i].rotation.join('_') !== '0_0_0') {
obj.rotation = array[i].rotation
}
if (array[i].reset) {
obj.reset = true
}
if (lut) {
delete obj.display.export
}
delete obj.display.parent
delete obj.display.isselected
delete obj.display.object
if (array[i].children.length > 0) {
iterate(array[i].children, obj.children)
}
save_array.push(obj)
}
if (array[i].rotation.join('_') !== '0_0_0') {
obj.rotation = array[i].rotation
}
if (array[i].reset) {
obj.reset = true
}
delete obj.display.parent
delete obj.display.isselected
delete obj.display.object
if (array[i].children.length > 0) {
iterate(array[i].children, obj.children)
}
save_array.push(obj)
}
i++;
}
@ -808,9 +974,9 @@ function loadOutlinerDraggable() {
//Texture
var id = $(ui.helper).attr('texid')
var sides = ['north', 'east', 'south', 'west', 'up', 'down']
if (target.title === 'Group') {
if (target.type === 'group') {
target.forEachChild(function(s) {
if (s.title === 'Group') return;
if (s.type === 'group') return;
sides.forEach(function(side) {
s.faces[side].texture = '#'+id
})
@ -839,7 +1005,7 @@ function loadOutlinerDraggable() {
function dropOutlinerObjects(item, target, event) {
var items;
if (item.title === 'Cube' && selected.includes( item.index() )) {
if (item.type === 'cube' && selected.includes( item.index() )) {
items = selected.Elements()
} else {
items = [item]
@ -847,7 +1013,7 @@ function dropOutlinerObjects(item, target, event) {
items.forEach(function(item) {
if (item && item !== target) {
if (event.altKey) {
if (item.title === 'Cube') {
if (item.type === 'cube') {
elements.push(new Cube().extend(item).addTo(target))
} else {
item.duplicate().addTo(target)
@ -869,10 +1035,15 @@ function addCube() {
var base_cube = new Cube().addTo()
if (selected_group) {
base_cube.addTo(selected_group)
} else {
base_cube.addTo()
}
if (textures.length && settings.entity_mode.value) {
var sides = ['north', 'east', 'south', 'west', 'up', 'down']
sides.forEach(function(side) {
base_cube.faces[side].texture = '#'+textures[0].id
})
main_uv.loadData()
}
if (selected_group) selected_group.unselect()
elements.push(base_cube)
@ -886,6 +1057,10 @@ function addCube() {
renameCubes()
}
})
if (settings.entity_mode.value) {
var new_group =
base_cube.addTo(new Group().addTo('root').openUp())
}
Blockbench.dispatchEvent( 'add_cube', {object: base_cube} )
return base_cube
}
@ -915,7 +1090,7 @@ function addGroup() {
//Misc
function isMovementOnRotatedAxis() {
if (settings.move_origin.value) {
if ((settings.move_origin.value || Prop.tool === 'scale') && !settings.entity_mode.value) {
if (selected.length > 1) {
if (elements[selected[0]].rotation === undefined) return false;
var i = 0;
@ -984,6 +1159,7 @@ function origin2geometry() {
var Rotation = {
angleBefore: 0,
load: function() {
$('.selection_only#options').css('visibility', 'visible')
if (settings.entity_mode.value === false) {
var s = selected[0]
try {
@ -1135,31 +1311,22 @@ var Rotation = {
})
},
remove: function() {
if (selected.length == 0) {return;}
selected.forEach(function(s) {
if (elements[s].rotation !== undefined) {
delete elements[s].rotation;
}
})
Rotation.load()
updateNslideValues()
Canvas.updatePositions()
},
fn: function (argument) {
if (settings.entity_mode.value === false) {
if (selected.length == 0) {return;}
selected.forEach(function(s) {
if (elements[s].rotation !== undefined) {
delete elements[s].rotation;
}
})
Rotation.load()
updateNslideValues()
Canvas.updatePositions()
Rotation.remove()
} else if (selected_group) {
selected_group.rotation[getAxisNumber($('#cube_axis option:selected').attr('id'))] = 0
Canvas.updatePositions()
selected_group.boneRotationDialog()
}
},
groupMode: function() {
setOriginHelper({origin: selected_group.origin, axis: 'x', angle: 0})
$('.ui#options').css('visibility', 'visible')
$('.ui#options h3').text('Group Settings')
$('div.nslide[n-action="origin_x"]:not(".editing")').text(trimFloatNumber(selected_group.origin[0]))
$('div.nslide[n-action="origin_y"]:not(".editing")').text(trimFloatNumber(selected_group.origin[1]))
$('div.nslide[n-action="origin_z"]:not(".editing")').text(trimFloatNumber(selected_group.origin[2]))
},
cubeMode: function() {
}
}
function deleteCubes(array) {

View File

@ -31,7 +31,6 @@ function colorSettingsSetup(reset) {
$.extend(app_colors, stored_app_colors)
}
updateUIColor()
calcCanvasGridSize()
buildGrid()
}
@ -120,6 +119,39 @@ function renameCubeList(name) {
elements[s].name = name.split('%').join(s).split('$').join(i)
})
}
function randomHelpMessage() {
var tips = [
'Go to the Settings menu and select the Keybindings tab to change your keys.',
'Blockbench works as a Program on Windows, macOS and Linux, or as a web app on any device, including tablets.',
'Double click in the canvas or hit spacebar to toggle between the scale and the drag tool.',
'Create groups to manage different parts of your model.',
'Open the Display tab in the top right corner to change how the model looks in your hands.',
'Only open textures that are in your resource pack.',
'Use Fizzy81\'s animation generator to create animated models.',
'Use blockmodels.com or sketchfab.com to share your models.',
'Press Ctrl + P to take a screenshot, press Ctrl + V to paste it into a Discord chat or a tweet.',
'Hold Shift or Ctrl to select multiple cubes',
'Join the Discord server to ask for help: discord.blockbench.net',
'You can load a blueprint of your model to make it easier to get the proportions right. Enter a side view and drag the image into the background. Use the menu on the bottom right to adjust it.',
'There are many useful plugins by the community in the plugin menu. Just click install and go.',
'Keep Blockbench updated. Updates add new functions to Blockbench, fix bugs and installing them is as easy opening the updates screen from the File menu and clicking the Update button',
'Check the Move Relative box in the Edit menu to move cubes on their rotated axis.'
]
var message = tips[Math.floor(Math.random()*tips.length)]
Blockbench.showMessageBox({
width: 640,
title: 'Tip',
icon: 'info',
message: message,
cancel: 1,
confirm: 0,
buttons: ['Next', 'Close']
}, function(answer) {
if (answer === 0) {
randomHelpMessage()
}
})
}
//Scenes
function enterScene(scene) {

View File

@ -32,15 +32,12 @@ function buildBlockModel(options) { //Export Blockmodel
function iterate(arr) {
var i = 0;
if (!arr || !arr.length) {
console.log('return')
return;
}
for (i=0; i<arr.length; i++) {
if (arr[i].title === 'Cube') {
if (arr[i].type === 'cube') {
computeCube(arr[i])
console.log(arr[i])
} else if (arr[i].title === 'Group') {
console.log('g')
iterate(arr[i].children)
}
}
@ -97,11 +94,22 @@ function buildBlockModel(options) { //Export Blockmodel
if (checkExport('elements', elements.length >= 1)) {
blockmodel.elements = clear_elements
}
if (checkExport('groups', settings.export_groups.value)) {
if (checkExport('groups', (settings.export_groups.value && getAllOutlinerGroups().length))) {
blockmodel.groups = compileGroups(undefined, element_index_lut)
}
if (checkExport('display', Object.keys(display).length >= 1)) {
blockmodel.display = display
var new_display = {}
for (var key in display) {
if (display.hasOwnProperty(key)) {
if (display[key].scale.join('_') !== '1_1_1' ||
display[key].rotation ||
display[key].translation
) {
new_display[key] = display[key]
}
}
}
blockmodel.display = new_display
}
if (options.raw) {
return blockmodel
@ -115,7 +123,6 @@ function loadFile(data, filepath, makeNew) { //Load File Into GUI
if (makeNew === true) {
//Create New Project
if (newProject() == false) return;
Prop.file_path = filepath
Prop.file_name = pathToName(Prop.file_path, true)
Project.name = pathToName(Prop.file_path, false)
if (Project.name.length > 0) {
@ -124,6 +131,7 @@ function loadFile(data, filepath, makeNew) { //Load File Into GUI
$('title').text('Blockbench')
}
Prop.project_saved = true;
Prop.file_path = filepath
} else {
//Add to Current Project
previous_length = elements.length
@ -364,9 +372,10 @@ function loadPEModel() {
setUndo('Opened entity model')
}
function buildEntityModel(options) {
if (options === undefined) options = {}
var entitymodel = {}
entitymodel.texturewidth = Project.texture_width;
entitymodel.textureheight = Project.texture_height;
entitymodel.texturewidth = parseInt(Project.texture_width);
entitymodel.textureheight = parseInt(Project.texture_height);
var bones = []
TreeElements.forEach(function(g) {
if (g.title !== 'Group') return;
@ -395,7 +404,11 @@ function buildEntityModel(options) {
})
entitymodel.bones = bones
return entitymodel
if (options.raw) {
return entitymodel
} else {
return autoStringify(entitymodel)
}
}
function buildOptifineModel() {
var jpm = {}
@ -451,6 +464,7 @@ function newProject(entity_mode) {
TreeElements.splice(0, 1)
textures.length = 0
selected.length = 0
selected_group = undefined
display = {}
Prop.file_path = 'Unknown';
Prop.file_name = '-';

View File

@ -184,15 +184,8 @@ function loadPlugin(id, cb, install) {
if (cb !== undefined) cb()
}).fail(function() {
console.log('Could not find file of plugin "'+id+'". Uninstalling it instead.')
var index = Plugins.installed.indexOf(id)
if (index > -1) {
Plugins.installed.splice(index, 1)
}
var data_obj = Plugins.data.findInArray('id', id)
data_obj.installed = false
if (data_obj.uninstall) {
data_obj.uninstall()
}
uninstallPlugin(id)
saveInstalledPlugins()
})
} else {
$.getScript('http://blockbench.net/api/plugins/'+id+'.js', function() {

View File

@ -22,6 +22,7 @@ function keybindSetup(get) {
confirm: {shift: false, ctrl: false, alt: false, code: 13, name: 'Confirm', char: 'ENTER'},
cancel: {shift: false, ctrl: false, alt: false, code: 27, name: 'Cancel', char: 'ESCAPE'},
screenshot_clean:{shift: false, ctrl: true, alt: false, code: 80, name: 'Screenshot', char: 'Ctrl + P'},
plugin_reload:{shift: false, ctrl: true, alt: false, code: 74, name: 'Reload Dev Plugins', char: 'Ctrl + J'},
headline2: {is_title: true, title: "File"},
open_file: {shift: false, ctrl: true, alt: false, code: 79, name: 'Open File', char: 'Ctrl + O'},
@ -120,14 +121,19 @@ function settingSetup() {
entity_mode: {value: false, name: 'Entity Model Mode', desc: 'Unrestricted editing mode for Bedrock and Optifine models'},
undo_limit: {value: 20, is_number: true, name: 'Undo Limit', desc: 'Number of steps you can undo'},
move_origin: {value: false, name: 'Move on Relative Axes', desc: 'Move rotated elements on their own axes if possible'},
snapnslide: {value: false, name: 'Snap Slider', desc: 'Snaps combo-sliders to their valid positions'},
autouv: {value: true, name: 'Auto UV', desc: 'Enable AutoUV by default'},
create_rename:{value: false, name: 'Rename new Cube', desc: 'Focus name field when creating new element or group'},
canvas_unselect:{value: false, name: 'Canvas Click Unselect', desc: 'Unselects all elements when clicking on the canvas background'},
edit_size: {value: 16, is_number: true, name: 'Grid Resolution', desc: 'Resolution of the grid that cubes snap to'},
show_actions: {value: false, name: 'Tell Actions', desc: 'Display every action in the status bar'},
//Snapping
headline4: {is_title: true, title: "Snapping"},
edit_size: {value: 16, is_number: true, name: 'Grid Resolution', desc: 'Resolution of the grid that cubes snap to'},
shift_size: {value: 64, is_number: true, name: 'Shift Resolution', desc: 'Resolution of the grid while holding shift'},
ctrl_size: {value: 160, is_number: true, name: 'Control Resolution', desc: 'Resolution of the grid while holding control'},
//rotation_snap:{value: true, name: 'Rotation Snap', desc: 'Snap Rotations to 22.5° (limit of the Minecraft model format)'},
snapnslide: {value: false, name: 'Snap Slider', desc: 'Snaps combo-sliders to their valid positions'},
//Export
headline4: {is_title: true, title: "Export"},
headline5: {is_title: true, title: "Export"},
minifiedout: {value: false,name: 'Minified Export', desc: 'Write JSON file in one line'},
max_json_length:{value: 56, is_number: true, name: 'Maximum Line Length', desc: 'Break JSON lines after this number'},
round_digits: {value: 4, is_number: true, name: 'Round numbers', desc: 'Round numbers'},
@ -154,7 +160,7 @@ function projectTagSetup() {
Project.parent = "";
Project.description = "";
Project.texture_width = 64;
Project.texture_height = 32;
Project.texture_height = 64;
Project.ambientocclusion = true;
}
function displayPresetsSetup() {
@ -359,7 +365,7 @@ $(document).keydown(function(e) {
Undo.redo()
}
if (compareKeys(e, keybinds.add_cube)) {
addCube(0,0,0,canvas_grid,canvas_grid,canvas_grid)
addCube()
}
if (compareKeys(e, keybinds.new_group)) {
addGroup()
@ -471,7 +477,7 @@ function saveSettings() {
Canvas.materials[mat].transparent = settings.transparency.value
}
setScreenRatio()
calcCanvasGridSize()
canvasGridSize()
buildGrid()
setShading()
if (settings.snapnslide.value === true) {
@ -497,6 +503,12 @@ function saveSettings() {
hideDialog()
updateUIColor()
updateSelection()
if (settings.entity_mode.value) {
main_uv.setGrid()
if (uv_dialog.editors) {
uv_dialog.editors.single.setGrid()
}
}
Blockbench.dispatchEvent( 'update_settings')
}
function toggleSetting(setting) {
@ -517,19 +529,38 @@ var entityMode = {
settings.entity_mode.value = true
$('body').addClass('entity_mode')
$('label[for="project_parent"]').text('Mob Geometry Name')
//Rotation Menu
$('#cube_rescale_tool div').text('Reset Bone')
$('#rotation_function_button i').text('settings')
$('#rotation_function_button .tooltip').text('Rotation Menu')
$('.ui#options h3').text('Bone Settings')
$('#rotation_origin_label').text('Pivot')
$('input#cube_rotate').attr('min', '-180').attr('max', '180').attr('step', '5.625').addClass('entity_mode')
main_uv.buildDom().setToMainSlot().setFace('north')
main_uv.autoGrid = true
$('.block_mode_only').hide()
buildGrid()
Blockbench.dispatchEvent('join_entity_mode')
},
leave: function() {
settings.entity_mode.value = false
$('body').removeClass('entity_mode')
$('label[for="project_parent"]').text('Parent Model')
//Rotation Menu
$('#cube_rescale_tool div').text('Rescale')
$('#rotation_function_button i').text('clear')
$('#rotation_function_button .tooltip').text('Remove Rotation')
$('.ui#options h3').text('Rotation')
$('#rotation_origin_label').text('Origin')
$('input#cube_rotate').attr('min', '-67.5').attr('max', '67.5').attr('step', '22.5').removeClass('entity_mode')
$('.block_mode_only').show()
$('.ui#textures').css('top', 514+'px')
main_uv.buildDom(true).setToMainSlot()
buildGrid()
elements.forEach(function(s, i) {
//Push elements into 3x3 block box
[0, 1, 2].forEach(function(ax) {
@ -556,5 +587,6 @@ var entityMode = {
}
})
})
Blockbench.dispatchEvent('leave_entity_mode')
}
}

View File

@ -31,7 +31,7 @@ class Texture {
}
}
}
load(isDefault) {
load(isDefault, reloading) {
var scope = this;
this.error = false;
@ -69,18 +69,22 @@ class Texture {
scope.dark_box = (scope.average_color.r + scope.average_color.g + scope.average_color.b) >= 383
//Width / Animation
if (img.naturalWidth !== img.naturalHeight) {
if (img.naturalWidth !== img.naturalHeight && settings.entity_mode.value === false) {
if (img.naturalHeight % img.naturalWidth === 0) {
scope.frameCount = img.naturalHeight / img.naturalWidth
Canvas.updateAllUVs()
} else if (settings.entity_mode.value === false) {
} else {
scope.error = true;
showQuickMessage('Texture needs to be square')
}
}
if (textures.indexOf(scope) === 0) {
if (settings.entity_mode.value && textures.indexOf(scope) === 0 && !reloading) {
Project.texture_width = img.naturalWidth
Project.texture_height = img.naturalHeight
if (selected.length) {
main_uv.loadData()
main_uv.setGrid()
}
}
if ($('.dialog#texture_edit:visible').length >= 1 && scope.selected === true) {
loadTextureMenu(scope)
@ -210,7 +214,7 @@ class Texture {
}
this.iconpath = this.path + '?' + tex_version;
this.iconpath = this.iconpath.replace(/\?\d+$/, '?' + tex_version)
this.load()
this.load(undefined, true)
if (single) {
Canvas.updateAllFaces()
main_uv.loadData()
@ -263,11 +267,31 @@ class Texture {
return this;
}
add() {
var scope = this
if (!textures.includes(this)) {
textures.push(this)
}
Blockbench.dispatchEvent( 'add_texture', {texture: this})
Blockbench.dispatchEvent( 'add_texture', {texture: this})
loadTextureDraggable()
if (settings.entity_mode.value && elements.length) {
var sides = ['north', 'east', 'south', 'west', 'up', 'down']
elements.forEach(function(s) {
sides.forEach(function(side) {
s.faces[side].texture = '#'+scope.id
})
})
Canvas.updateAllFaces()
if (selected.length) {
main_uv.loadData()
}
textures.forEach(function (t, i) {
if (t !== scope) {
textures.splice(i, 1)
}
})
setUndo('Loaded Texture')
}
return this;
}
extend(properties) {

View File

@ -20098,6 +20098,7 @@
$('#status_bar').html('<div><i class="material-icons">warning</i></div><div>Your '+isApp ? 'computer' : 'browser'+' is not compatible with WebGL.</div>')
console.error('Could not create WebGL context')
console.error(error)
}

View File

@ -12,12 +12,12 @@
'<input type="text" class="cube_name" v-model="node.name" disabled>' +
'<a v-for="btn in node.buttons" class="ml5" href="javascript:" :title="btn.title" v-on:click.stop="btnClick(btn, node)" v-bind:class="{advanced_option: btn.advanced_option}">' +
'<i v-if="node.isIconEnabled(btn.title) === true" :class="btn.icon"></i>' +
'<i v-else-if="node.isIconEnabled(btn.title) === \'alt\'" :class="btn.icon_alt"></i>' +
'<i v-else :class="btn.icon_off"></i>' +
'</a>' +
'</div>' +
//Other Entries
'<ul v-show="node.isOpen">' +
//'<li v-show="node.showLoading && node._loading"><i class="fa fa-spinner fa-pulse"></i></li>' +
'<vue-tree-item v-for="item in node.children" :node="item" v-key="item.uuid"></vue-tree-item>' +
'</ul>' +
'</li>',

View File

@ -272,15 +272,6 @@ function limitNumber(number, min, max) {
if (number < min) number = min;
return number;
}
function getSnapFactor(event) {
if (event.shiftKey) {
return canvas_grid / 4;
} else if (event.ctrlKey) {
return canvas_grid / 10;
} else {
return canvas_grid;
}
}
function compareVersions(string1/*new*/, string2/*old*/) {
// Is string1 newer than string2 ?
var arr1 = string1.split('.')
@ -299,4 +290,34 @@ function compareVersions(string1/*new*/, string2/*old*/) {
i++;
}
return false;
}
function useBedrockFlipFix(axis) {
if (settings.entity_mode.value === false) return false;
if (typeof axis === 'string') {
axis = getAxisNumber(axis)
}
var group;
if (selected_group) {
var group = selected_group
} else {
var i = 0;
while (i < selected.length) {
if (typeof elements[selected[i]].display.parent === 'object' &&
elements[selected[i]].display.parent.type === 'group'
) {
var group = elements[selected[i]].display.parent
}
i++;
}
}
if (group) {
var rotations = group.rotation.slice()
rotations.splice(axis, 1)
rotations.forEach(function(r, i) {
rotations[i] = (r >= -90 && r <= 90)
})
return rotations[0] !== rotations[1]
} else {
return false
}
}

133
js/uv.js
View File

@ -1,49 +1,3 @@
function calcAutoUV(obj, face, size) {
var sx = obj.faces[face].uv[0]
var sy = obj.faces[face].uv[1]
var rot = obj.faces[face].rotation
//Match To Rotation
if (rot === 90 || rot === 270) {
size.reverse()
}
//Limit Input to 16
size.forEach(function(s) {
if (s > 16) {
s = 16
}
})
//Calculate End Points
var x = sx + size[0]
var y = sy + size[1]
//Prevent Over 16
if (x > 16) {
sx = 16 - (x - sx)
x = 16
}
if (y > 16) {
sy = 16 - (y - sy)
y = 16
}
//Prevent Negative
if (sx < 0) sx = 0
if (sy < 0) sy = 0
//Prevent Mirroring
if (x < sx) x = sx
if (y < sy) y = sy
//if ()
//Return
return [sx, sy, x, y]
}
function triggerAutoUV() {
Vue.nextTick(function() {
setTimeout(function() {
scaleCube(elements[selected[0]], 0, 'x')
}, 10)
})
}
function getTextureById(id) {
if (id === undefined) return;
if (id == '$transparent') {
@ -100,6 +54,7 @@ class UVEditor {
'<div class="tool wide nslide_tool"><div class="nslide" n-action="moveuv_y"></div><div class="tooltip">Move Y</div></div>' +
(settings.entity_mode.value ? '' : '<div class="tool wide nslide_tool"><div class="nslide" n-action="scaleuv_x"></div><div class="tooltip">Scale X</div></div>') +
(settings.entity_mode.value ? '' : '<div class="tool wide nslide_tool"><div class="nslide" n-action="scaleuv_y"></div><div class="tooltip">Scale Y</div></div>') +
'<button class="large" id="entity_mode_resolution_button" onclick="showDialog(\'project_settings\');">Resolution</button>'+
'</div>'
)
this.jquery.main.append(this.jquery.nslides)
@ -275,11 +230,16 @@ class UVEditor {
}
}
//Set
setSize(size) {
setSize(size, cancel_load) {
this.size = size
this.jquery.frame.height(size)
this.jquery.frame.width(size)
if (settings.entity_mode.value === false) {
if (settings.entity_mode.value) {
this.jquery.frame.height(size / (Project.texture_width/Project.texture_height))
$('.ui#textures').css('top', 133+(size / (Project.texture_width/Project.texture_height))+'px')
} else {
this.jquery.frame.height(size)
this.jquery.size.resizable('option', 'maxHeight', size)
this.jquery.size.resizable('option', 'maxWidth', size)
this.jquery.size.resizable('option', 'grid', [size/this.grid, size/this.grid])
@ -287,10 +247,16 @@ class UVEditor {
var nslide_width = (size / 4) - (size % 4 > 0 ? 1 : 0)
this.jquery.nslides.find('.nslide_tool').css('width', (size/4-2)+'px')
this.jquery.nslides.find('.nslide').css('width', (size/4-2)+'px')
this.loadData()
if (!cancel_load) {
this.loadData()
}
return this;
}
setGrid(grid, load) {
if (grid === undefined || grid === 'dialog') {
if (settings.entity_mode.value) {
this.autoGrid = false;
grid = Project.texture_width
} else if (grid === undefined || grid === 'dialog') {
this.autoGrid = false;
if (grid === undefined) {
grid = this.jquery.bar.find('#uv_snap option:selected').attr('id')
@ -388,7 +354,7 @@ class UVEditor {
var pixelSize = this.size/16
//Save UV from Frame to object!!
var left = this.jquery.size.position().left / pixelSize
var top = this.jquery.size.position().top / pixelSize
var top = this.jquery.size.position().top / pixelSize * (Project.texture_width/Project.texture_height)
var left2 = (this.jquery.size.width()) / pixelSize + left
var top2 = (this.jquery.size.height()) / pixelSize + top
@ -453,6 +419,9 @@ class UVEditor {
this.setGrid(tex.res, false)
}
}
if (settings.entity_mode.value) {
this.setSize(this.size, true)
}
}
displayTransformInfo() {
var ref = elements[selected[0]].faces[this.face]
@ -470,7 +439,7 @@ class UVEditor {
}
}
displayEmptyTexture() {
this.jquery.frame.css('background', 'var(--color-back)')
this.jquery.frame.css('background-color', 'var(--color-back)').css('background-image', 'none')
this.texture = false;
this.setFrameColor()
if (this.autoGrid) {
@ -487,7 +456,7 @@ class UVEditor {
//X
if (settings.entity_mode.value) {
var width = (elements[selected[0]].size(0) + elements[selected[0]].size(2))*2
width = width/Project.texture_width * 16
width = limitNumber(width/Project.texture_width * 16, 0, 16)
} else {
var width = limitNumber(face.uv[2]-face.uv[0], -16, 16)
}
@ -502,7 +471,7 @@ class UVEditor {
//Y
if (settings.entity_mode.value) {
var height = elements[selected[0]].size(2) + elements[selected[0]].size(1)
height = height/Project.texture_width * 16
height = limitNumber(height/Project.texture_width * 16, 0, 16)
} else {
var height = limitNumber(face.uv[3]-face.uv[1], -16, 16)
}
@ -520,10 +489,16 @@ class UVEditor {
}
displayNslides() {
var face_uv = elements[selected[0]].faces[this.face].uv
this.jquery.nslides.find('div.nslide[n-action="moveuv_x"]:not(".editing")').text(trimFloatNumber(face_uv[0]))
this.jquery.nslides.find('div.nslide[n-action="moveuv_y"]:not(".editing")').text(trimFloatNumber(face_uv[1]))
this.jquery.nslides.find('div.nslide[n-action="scaleuv_x"]:not(".editing")').text(trimFloatNumber(face_uv[2] - face_uv[0]))
this.jquery.nslides.find('div.nslide[n-action="scaleuv_y"]:not(".editing")').text(trimFloatNumber(face_uv[3] - face_uv[1]))
var values = [
trimFloatNumber(face_uv[0] * (settings.entity_mode.value ? Project.texture_width / 16 : 1)),
trimFloatNumber(face_uv[1] * (settings.entity_mode.value ? Project.texture_height / 16 : 1)),
trimFloatNumber(face_uv[2] - face_uv[0]),
trimFloatNumber(face_uv[3] - face_uv[1])
]
this.jquery.nslides.find('div.nslide[n-action="moveuv_x"]:not(".editing")').text(values[0])
this.jquery.nslides.find('div.nslide[n-action="moveuv_y"]:not(".editing")').text(values[1])
this.jquery.nslides.find('div.nslide[n-action="scaleuv_x"]:not(".editing")').text(values[2])
this.jquery.nslides.find('div.nslide[n-action="scaleuv_y"]:not(".editing")').text(values[3])
}
displayTools() {
//Cullface
@ -543,6 +518,11 @@ class UVEditor {
}
//Nslide
slider(action, difference, index) {
if (settings.entity_mode.value === false) {} else if (action.includes('x')) {
difference *= (16 / Project.texture_width)
} else {
difference *= (16 / Project.texture_height)
}
var before;
switch (action) {
case 'moveuv_x':
@ -578,6 +558,11 @@ class UVEditor {
$('#nslide_head #nslide_offset').text('Offset: '+difference)
}
nslideInput(action, difference) {
if (settings.entity_mode.value === false) {} else if (action.includes('x')) {
difference *= (16 / Project.texture_width)
} else {
difference *= (16 / Project.texture_height)
}
var scope = this;
selected.forEach(function(s) {
var obj = elements[s]
@ -600,12 +585,26 @@ class UVEditor {
}
moveCoord(index, val, obj) {
var uvTag = obj.faces[this.face].uv
var size = uvTag[index + 2] - uvTag[index]
val = limitNumber(val, 0, 16)
val = limitNumber(val + size, 0, 16) - size
if (settings.entity_mode.value === false) {
var size = uvTag[index + 2] - uvTag[index]
val = limitNumber(val, 0, 16)
val = limitNumber(val + size, 0, 16) - size
uvTag[index] = val
uvTag[index + 2] = size + val
uvTag[index] = val
uvTag[index + 2] = size + val
} else {
if (index === 0) {
var size = (elements[selected[0]].size(0) + elements[selected[0]].size(2))*2
size = size/Project.texture_width * 16
} else {
var size = elements[selected[0]].size(2) + elements[selected[0]].size(1)
size = size/Project.texture_height * 16
}
val = limitNumber(val, 0, 16)
val = limitNumber(val + size, 0, 16) - size
uvTag[index] = val
uvTag[index + 2] = 16
}
this.displayNslides()
this.displayFrame()
@ -1126,9 +1125,11 @@ var uv_dialog = {
y: obj.height()
}
if (uv_dialog.single) {
var menu_gap = settings.entity_mode.value ? 38 : 130
var editor_size = size.x
if (size.x > size.y - 130) {
editor_size = size.y - 130
size.y = (size.y - menu_gap) * (settings.entity_mode.value ? Project.texture_width/Project.texture_height : 1)
if (size.x > size.y) {
editor_size = size.y
}
editor_size = editor_size - (editor_size % 16)
uv_dialog.editors.single.setSize(editor_size)

View File

@ -220,11 +220,11 @@ function saveFileEntity() {
var obj = {}
var model_name = Project.parent
if (model_name == '') model_name = 'geometry.unknown'
obj[model_name] = buildEntityModel()
obj[model_name] = buildEntityModel({raw: true})
var data = autoStringify(obj)
var blob = new Blob([data], {type: "text/plain;charset=utf-8"});
saveAs(blob, 'model.json')
saveAs(blob, 'mobs.json')
showQuickMessage('Saved as bedrock entity model')
}
function saveFileObj() {

View File

@ -18,7 +18,7 @@ function createWindow () {
win.maximize()
win.show()
win.loadURL(url.format({
pathname: path.join(__dirname, 'index.php'),
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))

View File

@ -1,7 +1,7 @@
{
"name": "Blockbench",
"description": "Minecraft Block Model Editor",
"version": "0.10.0",
"version": "1.10.1",
"author": {
"name": "JannisX11",
"email": "info@blockbench.net"
@ -26,11 +26,6 @@
"icon.ico",
"icon.png"
],
"publish": [{
"provider": "github",
"owner": "JannisX11",
"releaseType": "draft"
}],
"dmg": {
"contents": [
{"x": 130, "y": 220},