This commit is contained in:
JannisX11 2018-12-16 16:18:20 +01:00 committed by GitHub
parent fdd60bd27b
commit d4e6ad1471
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 542 additions and 391 deletions

View File

@ -1381,6 +1381,7 @@
position: absolute;
opacity: 0.4;
cursor: inherit;
pointer-events: none;
}
#uv_dialog_toolbar {
clear: both;
@ -1561,7 +1562,6 @@
width: 100%;
min-height: 34px;
padding-left: 6px;
border-bottom: 2px solid var(--color-border);
}
#settings h3 > i {
margin-top: 5px;
@ -1618,7 +1618,6 @@
}
#settingslist > li {
padding-left: 6px;
border-bottom: 2px solid var(--color-border);
}
#settingslist li li {
padding-top: 7px;

View File

@ -144,7 +144,7 @@
<li v-for="item in currentBar" v-bind:title="item.name" :key="item.id||item">
<div v-if="typeof item === 'string'" class="toolbar_separator"></div>
<div v-else class="tool">
<span class="icon_wrapper" v-bind:style="{opacity: BARS.condition(item.condition) ? 1 : 0.4}" v-html="Blockbench.getIconNode(item.icon).outerHTML"></span>
<span class="icon_wrapper" v-bind:style="{opacity: BARS.condition(item.condition) ? 1 : 0.4}" v-html="Blockbench.getIconNode(item.icon, item.color).outerHTML"></span>
<div class="tooltip">{{item.name + (BARS.condition(item.condition) ? '' : ' (' + tl('dialog.toolbar_edit.hidden') + ')' )}}</div>
</div>
</li>
@ -159,7 +159,7 @@
<ul class="list" id="bar_item_list">
<li v-for="item in searchedBarItems" v-on:click="addItem(item)">
<div class="icon_wrapper normal" v-html="Blockbench.getIconNode(item.icon).outerHTML"></div>
<div class="icon_wrapper normal" v-html="Blockbench.getIconNode(item.icon, item.color).outerHTML"></div>
<div class="icon_wrapper add"><i class="material-icons">add</i></div>
{{ item.name }}
</li>
@ -452,13 +452,13 @@
<div class="setting_element" v-html="Blockbench.getIconNode(setting.icon).outerHTML"></div>
</template>
<template v-else-if="!setting.type"><!--TOGGLE-->
<div class="setting_element"><input type="checkbox" v-model="setting.value" v-on:click="saveSettings()"></div>
<div class="setting_element"><input type="checkbox" v-model="setting.value" v-bind:id="'setting_'+key" v-on:click="saveSettings()"></div>
</template>
<div class="setting_label">
<label class="setting_label" v-bind:for="'setting_'+key">
<div class="setting_name">{{ tl('settings.'+key) }}</div>
<div class="setting_description">{{ tl('settings.'+key+'.desc') }}</div>
</div>
</label>
<template v-if="setting.type === 'text'">
<input type="text" class="dark_bordered" style="width: 96%" v-model="setting.value" v-on:input="saveSettings()">

218
index.php
View File

@ -25,6 +25,7 @@
<script src="lib/jquery-ui.min.js"></script>
<script src="lib/targa.js"></script>
<script src="lib/jimp.min.js"></script>
<script src="lib/gif.js"></script>
<script src="lib/spectrum.js"></script>
<script src="lib/three.js"></script>
<script src="js/OrbitControls.js"></script>
@ -38,18 +39,13 @@
<script src="js/blockbench.js"></script>
<script src="js/undo.js"></script>
<script type="text/javascript">
if (isApp === false) {
document.write("<script type='application/x-suppress'>");
}
</script>
<script type="text/javascript" src="js/app.js"></script>
<script type="text/javascript">
if (isApp === true) {
document.write("<script type='application/x-suppress'>");
document.write("<script src='js/app.js'><\/script>");
} else {
document.write("<script src='js/web.js'><\/script>");
}
</script>
<script type="text/javascript" src="js/web.js"></script>
<script src="js/api.js"></script>
<script src="js/actions.js"></script>
@ -67,22 +63,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><?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="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 style="display: none;"></div>
@ -160,10 +156,10 @@
<ul class="bar" id="bar_items_current" v-sortable="{onChoose: choose, onUpdate: sort, onEnd: drop, animation: 160 }">
<li v-for="item in currentBar" v-bind:title="item.name" :key="item.id||item">
<div v-if="typeof item === 'string'" class="toolbar_seperator"></div>
<div v-if="typeof item === 'string'" class="toolbar_separator"></div>
<div v-else class="tool">
<span class="icon_wrapper" v-html="Blockbench.getIconNode(item.icon).outerHTML"></span>
<div class="tooltip">{{item.name}}</div>
<span class="icon_wrapper" v-bind:style="{opacity: BARS.condition(item.condition) ? 1 : 0.4}" v-html="Blockbench.getIconNode(item.icon, item.color).outerHTML"></span>
<div class="tooltip">{{item.name + (BARS.condition(item.condition) ? '' : ' (' + tl('dialog.toolbar_edit.hidden') + ')' )}}</div>
</div>
</li>
</ul>
@ -177,7 +173,7 @@
<ul class="list" id="bar_item_list">
<li v-for="item in searchedBarItems" v-on:click="addItem(item)">
<div class="icon_wrapper normal" v-html="Blockbench.getIconNode(item.icon).outerHTML"></div>
<div class="icon_wrapper normal" v-html="Blockbench.getIconNode(item.icon, item.color).outerHTML"></div>
<div class="icon_wrapper add"><i class="material-icons">add</i></div>
{{ item.name }}
</li>
@ -234,10 +230,6 @@
<canvas height="256" width="256" id="extrusion_canvas"></canvas>
<div class="progress_bar" id="extrusion_bar">
<div class="progress_bar_inner"></div>
</div>
<div class="dialog_bar">
<button type="button" class="large tl confirm_btn" onclick="Extruder.startConversion()">Scan and Import</button>
</div>
@ -369,7 +361,7 @@
</div>
<div class="dialog_bar">
<button type="button" class="large tl confirm_btn" onclick="createPreset()">dialog.display_preset.create</button>
<button type="button" class="large tl confirm_btn" onclick="DisplayMode.createPreset()">dialog.display_preset.create</button>
<button type="button" class="large tl cancel_btn" onclick="hideDialog()">dialog.cancel</button>
</div>
<div id="dialog_close_button" onclick="$('.dialog#'+open_dialog).find('.cancel_btn:not([disabled])').click()"><i class="material-icons">clear</i></div>
@ -459,40 +451,40 @@
<h2 class="tl i_b">dialog.settings.settings</h2>
<ul id="settingslist">
<li v-for="category in structure">
<h3 v-on:click="toggleCategory(category)">
<i class="material-icons">{{ category.open ? 'expand_more' : 'navigate_next' }}</i>
{{ category.name }}
</h3>
<ul v-if="category.open">
<li v-for="category in structure">
<h3 v-on:click="toggleCategory(category)">
<i class="material-icons">{{ category.open ? 'expand_more' : 'navigate_next' }}</i>
{{ category.name }}
</h3>
<ul v-if="category.open">
<li v-for="(setting, key) in category.items" v-on="setting.click ? {click: setting.click} : {}">
<template v-if="setting.type === 'number'">
<div class="setting_element"><input type="number" v-model="setting.value" v-on:input="saveSettings()"></div>
</template>
<template v-else-if="setting.type === 'click'">
<div class="setting_element" v-html="Blockbench.getIconNode(setting.icon).outerHTML"></div>
</template>
<template v-else-if="!setting.type"><!--TOGGLE-->
<div class="setting_element"><input type="checkbox" v-model="setting.value" v-on:click="saveSettings()"></div>
</template>
<li v-for="(setting, key) in category.items" v-on="setting.click ? {click: setting.click} : {}">
<template v-if="setting.type === 'number'">
<div class="setting_element"><input type="number" v-model="setting.value" v-on:input="saveSettings()"></div>
</template>
<template v-else-if="setting.type === 'click'">
<div class="setting_element" v-html="Blockbench.getIconNode(setting.icon).outerHTML"></div>
</template>
<template v-else-if="!setting.type"><!--TOGGLE-->
<div class="setting_element"><input type="checkbox" v-model="setting.value" v-bind:id="'setting_'+key" v-on:click="saveSettings()"></div>
</template>
<div class="setting_label">
<div class="setting_name">{{ tl('settings.'+key) }}</div>
<div class="setting_description">{{ tl('settings.'+key+'.desc') }}</div>
</div>
<label class="setting_label" v-bind:for="'setting_'+key">
<div class="setting_name">{{ tl('settings.'+key) }}</div>
<div class="setting_description">{{ tl('settings.'+key+'.desc') }}</div>
</label>
<template v-if="setting.type === 'text'">
<input type="text" class="dark_bordered" style="width: 96%" v-model="setting.value" v-on:input="saveSettings()">
</template>
<template v-else-if="setting.type === 'select'">
<select v-model="setting.value" class="dark_bordered">
<option v-for="(text, id) in setting.options" v-bind:value="id">{{ text }}</option>
</select>
</template>
</li>
</ul>
</li>
<template v-if="setting.type === 'text'">
<input type="text" class="dark_bordered" style="width: 96%" v-model="setting.value" v-on:input="saveSettings()">
</template>
<template v-else-if="setting.type === 'select'">
<select v-model="setting.value" class="dark_bordered">
<option v-for="(text, id) in setting.options" v-bind:value="id">{{ text }}</option>
</select>
</template>
</li>
</ul>
</li>
</ul>
</div>
<div id="keybindings" class="hidden tab_content">
@ -605,7 +597,7 @@
</div>
<div class="color_field">
<input type="color" class="color_input" id="color_text_acc" oninput="changeUIColor(event)" onclick="initUIColor(event)">
<label for="color_text_acc" style="background-color: var(--color-text-acc)" class="color_input"></label>
<label for="color_text_acc" style="background-color: var(--color-text_acc)" class="color_input"></label>
<div class="desc">
<h4 class="tl">layout.color.accent_text</h4>
<p class="tl">layout.color.accent_text.desc</p>
@ -652,15 +644,16 @@
<p class="tl">about.vertex_snap</p>
<p><b class="tl">about.icons</b> <a href="https://material.io/icons/" class="open-in-browser">material.io/icons</a> &amp; <a href="http://fontawesome.io/icons/" class="open-in-browser">fontawesome</a></p>
<p><b class="tl">about.libraries</b>
<a href="https://jquery.com" class="open-in-browser">jQuery</a>,
<a href="https://jqueryui.com" class="open-in-browser">jQuery UI</a>,
<a href="http://touchpunch.furf.com" class="open-in-browser">jQuery UI Touch Punch</a>,
<a href="https://vuejs.org" class="open-in-browser">VueJS</a>,
<a href="https://github.com/weibangtuo/vue-tree" class="open-in-browser">Vue Tree</a>,
<a href="https://github.com/sagalbot/vue-sortable" class="open-in-browser">Vue Sortable</a>,
<a href="https://threejs.org" class="open-in-browser">ThreeJS</a>,
<a href="https://github.com/oliver-moran/jimp" class="open-in-browser">Jimp</a>,
<a href="https://bgrins.github.io/spectrum" class="open-in-browser">Spectrum</a>
<a class="open-in-browser" href="https://jquery.com">jQuery</a>,
<a class="open-in-browser" href="https://jqueryui.com">jQuery UI</a>,
<a class="open-in-browser" href="http://touchpunch.furf.com">jQuery UI Touch Punch</a>,
<a class="open-in-browser" href="https://vuejs.org">VueJS</a>,
<a class="open-in-browser" href="https://github.com/weibangtuo/vue-tree">Vue Tree</a>,
<a class="open-in-browser" href="https://github.com/sagalbot/vue-sortable">Vue Sortable</a>,
<a class="open-in-browser" href="https://threejs.org">ThreeJS</a>,
<a class="open-in-browser" href="https://github.com/oliver-moran/jimp">Jimp</a>,
<a class="open-in-browser" href="https://bgrins.github.io/spectrum">Spectrum</a>,
<a class="open-in-browser" href="https://github.com/jnordberg/gif.js">gif.js</a>
</p>
</div>
<div class="dialog_bar">
@ -750,71 +743,80 @@
<p class="tl">display.slot</p>
<div id="display_bar" class="bar tabs_small">
<input class="hidden" type="radio" name="display" id="thirdperson_righthand" checked>
<label class="tool" for="thirdperson_righthand" onclick="loadDispThirdRight()"><i class="material-icons">accessibility</i><div class="tooltip tl">display.slot.third_right</div></label>
<label class="tool" for="thirdperson_righthand" onclick="DisplayMode.loadThirdRight()"><i class="material-icons">accessibility</i><div class="tooltip tl">display.slot.third_right</div></label>
<input class="hidden" type="radio" name="display" id="thirdperson_lefthand">
<label class="tool" for="thirdperson_lefthand" onclick="loadDispThirdLeft()"><i class="material-icons">accessibility</i><div class="tooltip tl">display.slot.third_left</div></label>
<label class="tool" for="thirdperson_lefthand" onclick="DisplayMode.loadThirdLeft()"><i class="material-icons">accessibility</i><div class="tooltip tl">display.slot.third_left</div></label>
<input class="hidden" type="radio" name="display" id="firstperson_righthand">
<label class="tool" for="firstperson_righthand" onclick="loadDispFirstRight()"><i class="material-icons">person</i><div class="tooltip tl">display.slot.first_right</div></label>
<label class="tool" for="firstperson_righthand" onclick="DisplayMode.loadFirstRight()"><i class="material-icons">person</i><div class="tooltip tl">display.slot.first_right</div></label>
<input class="hidden" type="radio" name="display" id="firstperson_lefthand">
<label class="tool" for="firstperson_lefthand" onclick="loadDispFirstLeft()"><i class="material-icons">person</i><div class="tooltip tl">display.slot.first_left</div></label>
<label class="tool" for="firstperson_lefthand" onclick="DisplayMode.loadFirstLeft()"><i class="material-icons">person</i><div class="tooltip tl">display.slot.first_left</div></label>
<input class="hidden" type="radio" name="display" id="head">
<label class="tool" for="head" onclick="loadDispHead()"><i class="material-icons">sentiment_satisfied</i><div class="tooltip tl">display.slot.head</div></label>
<label class="tool" for="head" onclick="DisplayMode.loadHead()"><i class="material-icons">sentiment_satisfied</i><div class="tooltip tl">display.slot.head</div></label>
<input class="hidden" type="radio" name="display" id="ground">
<label class="tool" for="ground" onclick="loadDispGround()"><i class="icon-ground"></i><div class="tooltip tl">display.slot.ground</div></label>
<label class="tool" for="ground" onclick="DisplayMode.loadGround()"><i class="icon-ground"></i><div class="tooltip tl">display.slot.ground</div></label>
<input class="hidden" type="radio" name="display" id="fixed">
<label class="tool" for="fixed" onclick="loadDispFixed()"><i class="material-icons">filter_frames</i><div class="tooltip tl">display.slot.frame</div></label>
<label class="tool" for="fixed" onclick="DisplayMode.loadFixed()"><i class="material-icons">filter_frames</i><div class="tooltip tl">display.slot.frame</div></label>
<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 tl">display.slot.gui</div></label>
<label class="tool" for="gui" onclick="DisplayMode.loadGUI()"><i class="material-icons">border_style</i><div class="tooltip tl">display.slot.gui</div></label>
</div>
<p class="reference_model_bar tl">display.reference</p>
<div id="display_ref_bar" class="bar tabs_small reference_model_bar">
</div>
<p class="tl">display.rotation</p><div class="tool head_right" onclick="resetDisplaySettings('rotation')"><i class="material-icons">replay</i></div>
<p class="tl">display.rotation</p><div class="tool head_right" onclick="DisplayMode.resetDisplaySettings('rotation')"><i class="material-icons">replay</i></div>
<div class="bar">
<input type="range" class="tool disp_range" id="rotation_x" name="" min="-180" max="180" step="1" value="0" oninput="syncDispInput(this, 'rotation', 'x')">
<input type="number" class="tool disp_text" id="rotation_x" oninput="syncDispInput(this, 'rotation', 'x')" min="-180" max="180" step="0.5" value="0">
<input type="range" class="tool disp_range" id="rotation_x" name="" min="-180" max="180" step="1" value="0" oninput="DisplayMode.syncDispInput(this, 'rotation', 'x')">
<input type="number" class="tool disp_text" id="rotation_x" oninput="DisplayMode.syncDispInput(this, 'rotation', 'x')" min="-180" max="180" step="0.5" value="0">
</div>
<div class="bar">
<input type="range" class="tool disp_range" id="rotation_y" name="" min="-180" max="180" step="1" value="0" oninput="syncDispInput(this, 'rotation', 'y')">
<input type="number" class="tool disp_text" id="rotation_y" oninput="syncDispInput(this, 'rotation', 'y')" min="-180" max="180" step="0.5" value="0">
<input type="range" class="tool disp_range" id="rotation_y" name="" min="-180" max="180" step="1" value="0" oninput="DisplayMode.syncDispInput(this, 'rotation', 'y')">
<input type="number" class="tool disp_text" id="rotation_y" oninput="DisplayMode.syncDispInput(this, 'rotation', 'y')" min="-180" max="180" step="0.5" value="0">
</div>
<div class="bar">
<input type="range" class="tool disp_range" id="rotation_z" name="" min="-180" max="180" step="1" value="0" oninput="syncDispInput(this, 'rotation', 'z')">
<input type="number" class="tool disp_text" id="rotation_z" oninput="syncDispInput(this, 'rotation', 'z')" min="-180" max="180" step="0.5" value="0">
<input type="range" class="tool disp_range" id="rotation_z" name="" min="-180" max="180" step="1" value="0" oninput="DisplayMode.syncDispInput(this, 'rotation', 'z')">
<input type="number" class="tool disp_text" id="rotation_z" oninput="DisplayMode.syncDispInput(this, 'rotation', 'z')" min="-180" max="180" step="0.5" value="0">
</div>
<p class="tl">display.translation</p><div class="tool head_right" onclick="resetDisplaySettings('translation')"><i class="material-icons">replay</i></div>
<p class="tl">display.translation</p><div class="tool head_right" onclick="DisplayMode.resetDisplaySettings('translation')"><i class="material-icons">replay</i></div>
<div class="bar">
<input type="range" class="tool disp_range" id="translation_x" name="" min="-32" max="32" step="0.5" value="0" oninput="syncDispInput(this, 'translation', 'x')">
<input type="number" class="tool disp_text" id="translation_x" oninput="syncDispInput(this, 'translation', 'x')" min="-80" max="80" step="0.5" value="0">
<input type="range" class="tool disp_range" id="translation_x" name="" min="-32" max="32" step="0.5" value="0" oninput="DisplayMode.syncDispInput(this, 'translation', 'x')">
<input type="number" class="tool disp_text" id="translation_x" oninput="DisplayMode.syncDispInput(this, 'translation', 'x')" min="-80" max="80" step="0.5" value="0">
</div>
<div class="bar">
<input type="range" class="tool disp_range" id="translation_y" name="" min="-32" max="32" step="0.5" value="0" oninput="syncDispInput(this, 'translation', 'y')">
<input type="number" class="tool disp_text" id="translation_y" oninput="syncDispInput(this, 'translation', 'y')" min="-80" max="80" step="0.5" value="0">
<input type="range" class="tool disp_range" id="translation_y" name="" min="-32" max="32" step="0.5" value="0" oninput="DisplayMode.syncDispInput(this, 'translation', 'y')">
<input type="number" class="tool disp_text" id="translation_y" oninput="DisplayMode.syncDispInput(this, 'translation', 'y')" min="-80" max="80" step="0.5" value="0">
</div>
<div class="bar">
<input type="range" class="tool disp_range" id="translation_z" name="" min="-32" max="32" step="0.5" value="0" oninput="syncDispInput(this, 'translation', 'z')">
<input type="number" class="tool disp_text" id="translation_z" oninput="syncDispInput(this, 'translation', 'z')" min="-80" max="80" step="0.5" value="0">
<input type="range" class="tool disp_range" id="translation_z" name="" min="-32" max="32" step="0.5" value="0" oninput="DisplayMode.syncDispInput(this, 'translation', 'z')">
<input type="number" class="tool disp_text" id="translation_z" oninput="DisplayMode.syncDispInput(this, 'translation', 'z')" min="-80" max="80" step="0.5" value="0">
</div>
<p class="tl">display.scale</p><div class="tool head_right" onclick="resetDisplaySettings('scale')"><i class="material-icons">replay</i></div>
<p class="tl">display.scale</p><div class="tool head_right" onclick="DisplayMode.resetDisplaySettings('scale')"><i class="material-icons">replay</i></div>
<div class="bar">
<input type="range" class="tool disp_range scaleRange" id="scale_x" name="" min="-4" max="4" step="0.1" value="0" oninput="syncDispInput(this, 'scaleRange', 'x', event)">
<input type="number" class="tool disp_text scale" id="scale_x" oninput="syncDispInput(this, 'scale', 'x')" step="0.1" min="-4" max="4">
<div class="tool display_scale_invert" id="display_scale_invert_x" onclick="DisplayMode.syncDispMirror(this, 'x')">
<i class="material-icons">check_box_outline_blank</i><div class="tooltip tl">display.mirror</div>
</div>
<input type="range" class="tool disp_range scaleRange" id="scale_x" name="" min="-4" max="4" step="0.1" value="0" oninput="DisplayMode.syncDispInput(this, 'scaleRange', 'x', event)">
<input type="number" class="tool disp_text scale" id="scale_x" oninput="DisplayMode.syncDispInput(this, 'scale', 'x')" step="0.1" min="-4" max="4">
</div>
<div class="bar">
<input type="range" class="tool disp_range scaleRange" id="scale_y" name="" min="-4" max="4" step="0.1" value="0" oninput="syncDispInput(this, 'scaleRange', 'y', event)">
<input type="number" class="tool disp_text scale" id="scale_y" oninput="syncDispInput(this, 'scale', 'y')" step="0.1" min="-4" max="4">
<div class="tool display_scale_invert" id="display_scale_invert_y" onclick="DisplayMode.syncDispMirror(this, 'x')">
<i class="material-icons">check_box_outline_blank</i><div class="tooltip tl">display.mirror</div>
</div>
<input type="range" class="tool disp_range scaleRange" id="scale_y" name="" min="-4" max="4" step="0.1" value="0" oninput="DisplayMode.syncDispInput(this, 'scaleRange', 'y', event)">
<input type="number" class="tool disp_text scale" id="scale_y" oninput="DisplayMode.syncDispInput(this, 'scale', 'y')" step="0.1" min="-4" max="4">
</div>
<div class="bar">
<input type="range" class="tool disp_range scaleRange" id="scale_z" name="" min="-4" max="4" step="0.1" value="0" oninput="syncDispInput(this, 'scaleRange', 'z', event)">
<input type="number" class="tool disp_text scale" id="scale_z" oninput="syncDispInput(this, 'scale', 'z')" step="0.1" min="-4" max="4">
<div class="tool display_scale_invert" id="display_scale_invert_z" onclick="DisplayMode.syncDispMirror(this, 'x')">
<i class="material-icons">check_box_outline_blank</i><div class="tooltip tl">display.mirror</div>
</div>
<input type="range" class="tool disp_range scaleRange" id="scale_z" name="" min="-4" max="4" step="0.1" value="0" oninput="DisplayMode.syncDispInput(this, 'scaleRange', 'z', event)">
<input type="number" class="tool disp_text scale" id="scale_z" oninput="DisplayMode.syncDispInput(this, 'scale', 'z')" step="0.1" min="-4" max="4">
</div>
</div>
<div id="animations" class="panel">
@ -824,7 +826,7 @@
<li
v-for="animation in animations"
v-bind:class="{ selected: animation.selected }"
v-bind:texid="animation.uuid"
v-bind:anim_id="animation.uuid"
class="animation"
v-on:click.stop="animation.select()"
@contextmenu.prevent.stop="animation.showContextMenu($event)"
@ -839,19 +841,19 @@
<p class="tl" id="keyframe_type_label"></p>
<div class="bar" id="keyframe_bar_x">
<label>X</label>
<input type="text" id="keyframe_x" class="dark_bordered code" axis="x" oninput="updateKeyframeValue(this)">
<input type="text" id="keyframe_x" class="dark_bordered code keyframe_input" axis="x" oninput="updateKeyframeValue(this)">
</div>
<div class="bar" id="keyframe_bar_y">
<label>Y</label>
<input type="text" id="keyframe_y" class="dark_bordered code" axis="y" oninput="updateKeyframeValue(this)">
<input type="text" id="keyframe_y" class="dark_bordered code keyframe_input" axis="y" oninput="updateKeyframeValue(this)">
</div>
<div class="bar" id="keyframe_bar_z">
<label>Z</label>
<input type="text" id="keyframe_z" class="dark_bordered code" axis="z" oninput="updateKeyframeValue(this)">
<input type="text" id="keyframe_z" class="dark_bordered code keyframe_input" axis="z" oninput="updateKeyframeValue(this)">
</div>
<div class="bar" id="keyframe_bar_w">
<label>W</label>
<input type="text" id="keyframe_w" class="dark_bordered code" axis="w" oninput="updateKeyframeValue(this)">
<input type="text" id="keyframe_w" class="dark_bordered code keyframe_input" axis="w" oninput="updateKeyframeValue(this)">
</div>
</div>
<div id="variable_placeholders" class="panel grow">

View File

@ -535,14 +535,14 @@ class BarSelect extends Widget {
})
}
change(event) {
this.set( $(event.target).find('option:selected').attr('id') )
this.set( $(event.target).find('option:selected').prop('id') )
if (this.onChange) {
this.onChange(this, event)
}
}
set(id) {
this.value = id
$(this.nodes).find('option#'+id).attr('selected', true).siblings().attr('selected', false)
$(this.nodes).find('option#'+id).prop('selected', true).siblings().prop('selected', false)
}
get() {
return this.value

View File

@ -407,11 +407,12 @@ class Keyframe {
}
}
get(axis) {
let num = parseFloat(this[axis])
if (isNaN(num)) {
return this[axis]
if (!this[axis]) {
return 0;
} else if (!isNaN(this[axis])) {
return parseFloat(this[axis])
} else {
return num
return this[axis]
}
}
calc(axis) {
@ -423,6 +424,9 @@ class Keyframe {
}
}
getArray() {
if (this.channel === 'scale') {
return this.get('x')
}
var arr = [
this.get('x'),
this.get('y'),
@ -636,7 +640,7 @@ function selectAllKeyframes() {
updateKeyframeSelection()
}
function removeSelectedKeyframes() {
Undo.initEdit({keyframes: Timeline.selected})
Undo.initEdit({keyframes: Timeline.selected, keep_saved: true})
var i = Timeline.keyframes.length;
while (i > 0) {
i--;
@ -645,6 +649,7 @@ function removeSelectedKeyframes() {
kf.remove()
}
}
updateKeyframeSelection()
Undo.finishEdit('remove keyframes')
}
@ -689,6 +694,10 @@ const Animator = {
if (Animator.selected) {
Animator.selected.select()
}
if (isApp && !Prop.animation_path && !Animator.animations.length && Prop.file_path) {
//Load
findBedrockAnimation()
}
},
leave: function (argument) {
Timeline.pause()
@ -745,6 +754,9 @@ const Animator = {
}
}
}
if (isApp && file.path) {
Prop.animation_path = file.path
}
}
},
buildFile: function(options) {
@ -866,7 +878,7 @@ const Timeline = {
}
})
$('.keyframe_input').click(e => {
Undo.initEdit({keyframes: Timeline.selected})
Undo.initEdit({keyframes: Timeline.selected, keep_saved: true})
}).focusout(e => {
Undo.finishEdit('edit keyframe')
})
@ -878,7 +890,7 @@ const Timeline = {
axis: 'x',
distance: 10,
start: function(event, ui) {
Undo.initEdit({keyframes: Timeline.keyframes})
Undo.initEdit({keyframes: Timeline.keyframes, keep_saved: true})
var id = $(ui.helper).attr('id')
var i = 0;
while (i < Timeline.vue._data.keyframes.length) {
@ -1020,7 +1032,7 @@ const Timeline = {
Blockbench.showQuickMessage('message.no_bone_selected')
return
}
Undo.initEdit({keyframes: bone.keyframes})
Undo.initEdit({keyframes: bone.keyframes, keep_saved: true})
var kf = bone.addKeyframe(false, Timeline.second, channel?channel:'rotation')
kf.select()
Undo.finishEdit('add_keyframe')
@ -1041,7 +1053,7 @@ const Timeline = {
}
var bone = Animator.selected.getBoneAnimator()
if (bone) {
Undo.initEdit({keyframes: bone.keyframes})
Undo.initEdit({keyframes: bone.keyframes, keep_saved: true})
var kf = bone.addKeyframe(false, Math.round(time*30)/30, row === 2 ? 'scale' : (row === 1 ? 'position' : 'rotation'))
kf.select().callMarker()
Vue.nextTick(Timeline.update)
@ -1096,8 +1108,10 @@ BARS.defineActions(function() {
condition: () => Animator.open,
click: function () {
var content = autoStringify(Animator.buildFile())
var path = Prop.file_path
if (isApp) {
var path = Prop.animation_path
if (isApp && !path) {
path = Prop.file_path
var exp = new RegExp(osfs.replace('\\', '\\\\')+'models'+osfs.replace('\\', '\\\\'))
var m_index = path.search(exp)
if (m_index > 3) {
@ -1160,7 +1174,7 @@ BARS.defineActions(function() {
Animator.preview()
},
onBefore: function() {
Undo.initEdit({keyframes: Timeline.selected})
Undo.initEdit({keyframes: Timeline.selected, keep_saved: true})
},
onAfter: function() {
Undo.finishEdit('edit keyframe')

150
js/api.js
View File

@ -42,16 +42,22 @@ class API {
icon = icon()
}
if (icon === undefined) {
//Missing
jq = $('<i class="material-icons icon">help_outline</i>')
} else if (icon instanceof HTMLElement) {
//Node
jq = $(icon)
} else if (icon.substr(0, 2) === 'fa') {
//Font Awesome
jq = $('<i class="icon fa fa_big ' + icon + '"></i>')
} else if (icon.substr(0, 5) === 'icon-') {
//Icomoon
jq = $('<i class="' + icon + '"></i>')
} else if (icon.substr(0, 14) === 'data:image/png') {
//Data URL
jq = $('<img class="icon" src="'+icon+'">')
} else {
//Material Icon
jq = $('<i class="material-icons icon">' + icon + '</i>')
}
if (color) {
@ -228,77 +234,7 @@ class API {
defaultPath: options.startpath
},
function (fileNames) {
if (fileNames == undefined) return;
var results = [];
var result_count = 0;
var i = 0;
var errant;
while (i < fileNames.length) {
(function() {
var this_i = i;
var file = fileNames[i]
if (options.readtype === 'image') {
//
var extension = pathToExtension(file)
if (extension === 'tga') {
var targa_loader = new Targa()
targa_loader.open(file, () => {
results[this_i] = {
name: pathToName(file, true),
path: file,
content: targa_loader.getDataURL()
}
result_count++;
if (result_count === fileNames.length) {
cb(results)
}
})
} else {
results[this_i] = {
name: pathToName(file, true),
path: file
}
result_count++;
if (result_count === fileNames.length) {
cb(results)
}
}
} else /*text*/ {
fs.readFile(file, 'utf-8', function (err, data) {
if (err) {
console.log(err)
if (!errant && options.errorbox !== false) {
Blockbench.showMessageBox({
translateKey: 'file_not_found',
icon: 'error_outline'
})
}
errant = true
return;
}
if (data.charCodeAt(0) === 0xFEFF) {
data = data.substr(1)
}
results[this_i] = {
name: pathToName(file, true),
path: file,
content: data
}
result_count++;
if (result_count === fileNames.length) {
cb(results)
}
})
}
})()
i++;
}
Blockbench.read(fileNames, options, cb)
})
} else {
$('<input '+
@ -350,6 +286,78 @@ class API {
}).click()
}
}
read(paths, options, cb) {
if (!isApp || paths == undefined) return false;
var results = [];
var result_count = 0;
var i = 0;
var errant;
while (i < paths.length) {
(function() {
var this_i = i;
var file = paths[i]
if (options.readtype === 'image') {
//
var extension = pathToExtension(file)
if (extension === 'tga') {
var targa_loader = new Targa()
targa_loader.open(file, () => {
results[this_i] = {
name: pathToName(file, true),
path: file,
content: targa_loader.getDataURL()
}
result_count++;
if (result_count === paths.length) {
cb(results)
}
})
} else {
results[this_i] = {
name: pathToName(file, true),
path: file
}
result_count++;
if (result_count === paths.length) {
cb(results)
}
}
} else /*text*/ {
fs.readFile(file, 'utf-8', function (err, data) {
if (err) {
console.log(err)
if (!errant && options.errorbox !== false) {
Blockbench.showMessageBox({
translateKey: 'file_not_found',
icon: 'error_outline'
})
}
errant = true
return;
}
if (data.charCodeAt(0) === 0xFEFF) {
data = data.substr(1)
}
results[this_i] = {
name: pathToName(file, true),
path: file,
content: data
}
result_count++;
if (result_count === paths.length) {
cb(results)
}
})
}
})()
i++;
}
}
export(options, cb) {
if (!options) return;
/*

View File

@ -356,6 +356,18 @@ function findEntityTexture(mob, return_path) {
}
}
}
function findBedrockAnimation() {
var animation_path = Prop.file_path.split(osfs)
var index = animation_path.lastIndexOf('models')
animation_path.splice(index)
animation_path = [...animation_path, 'animations', pathToName(Prop.file_path)+'.json'].join(osfs)
if (fs.existsSync(animation_path)) {
Blockbench.read([animation_path], {}, (files) => {
Animator.loadFile(files[0])
})
}
}
//Writers
function saveFile(props) {
if (Prop.file_path) {

View File

@ -1,4 +1,4 @@
const appVersion = '2.2.0'
const appVersion = '2.2.1'
var osfs = '/'
var File, i;
const elements = [];
@ -535,7 +535,7 @@ var Clipbench = {
if (open_dialog == 'uv_dialog') {
uv_dialog.copy(event)
} else if (display_mode) {
copyDisplaySlot()
DisplayMode.copy()
} else if (Animator.open) {
if (Timeline.selected.length) {
Clipbench.setKeyframes(Timeline.selected)
@ -564,7 +564,7 @@ var Clipbench = {
if (open_dialog == 'uv_dialog') {
uv_dialog.paste(event)
} else if (display_mode) {
pasteDisplaySlot()
DisplayMode.paste()
} else if (Animator.open) {
//
if (isApp) {

View File

@ -36,7 +36,7 @@ class refModel {
} else if (display_slot === 'thirdperson_lefthand') {
setDisplayArea(-x, y, -z, -67.5,0,0, 1, 1, 1)
} else if (display_slot === 'head') {
setDisplayArea(0, 22, 0, 0, 0, 0, 0.625, 0.625, 0.625)
setDisplayArea(0, 28, 0, 0, 0, 0, 0.625, 0.625, 0.625)
}
}
break;
@ -1245,28 +1245,24 @@ enterDisplaySettings = function() { //Enterung Display Setting Mode, changes th
exitDisplaySettings = function() { //Enterung Display Setting Mode, changes the scene etc
resetDisplayBase()
setDisplayArea(0,0,0, 0,0,0, 1,1,1)
display_area.updateMatrixWorld()
display_base.updateMatrixWorld()
setTimeout(() => {
display_mode = false;
main_preview.fullscreen()
$('.m_disp').hide()
$('.m_edit').show()
$('.selection_only').css('visibility', 'hidden')
$('body').removeClass('display_mode')
resizeWindow()
updateInterface()
if (quad_previews.enabled_before) {
openQuadView()
}
buildGrid()
setShading()
Canvas.updateRenderSides()
}, 60)
display_mode = false;
main_preview.fullscreen()
$('.m_disp').hide()
$('.m_edit').show()
$('.selection_only').css('visibility', 'hidden')
$('body').removeClass('display_mode')
resizeWindow()
updateInterface()
if (quad_previews.enabled_before) {
openQuadView()
}
buildGrid()
setShading()
Canvas.updateRenderSides()
}
function axisIndex(index) {
if (typeof index === 'number') {
@ -1352,7 +1348,7 @@ DisplayMode.syncDispMirror = function(node, axis) {
}
var axis = (node.id||'x').substr(-1)
display_base.scale[axis] = display[display_slot].scale[axisIndex(axis)] *= -1
loadDisp(display_slot)
DisplayMode.load(display_slot)
}
function dispRotate(val, axis) { //Change the actual thing
if (display[display_slot].rotation == undefined) {
@ -1447,7 +1443,7 @@ DisplayMode.createPreset = function() {
}
function setDisplayArea(x, y, z, rx, ry, rz, sx, sy, sz) {//Sets the Work Area to the given Space
var setDisplayArea = DisplayMode.setBase = function(x, y, z, rx, ry, rz, sx, sy, sz) {//Sets the Work Area to the given Space
display_area.rotation['x'] = Math.PI / (180 / rx);
display_area.rotation['y'] = Math.PI / (180 / ry);
display_area.rotation['z'] = Math.PI / (180 / rz);
@ -1624,12 +1620,12 @@ DisplayMode.load = function(slot) {
}
}
function copyDisplaySlot() {
DisplayMode.copy = function() {
var base_setting = {rotation: [0, 0, 0], translation: [0, 0, 0], scale: [1, 1, 1]}
$.extend(true, base_setting, display[display_slot])
display_clipboard = base_setting
}
function pasteDisplaySlot() {
DisplayMode.paste = function() {
if (display_clipboard == undefined) return;
if (typeof display_clipboard.rotation === 'object' && display_clipboard.rotation.join('_') === '0_0_0') {

View File

@ -264,6 +264,19 @@ class OutlinerElement {
}
return true;
}
isChildOf(group, max_levels) {
function iterate(obj, level) {
if (!obj || obj === 'root') {
return false;
} else if (obj === group) {
return true;
} else if (!max_levels || level < max_levels-1) {
return iterate(obj.parent, level+1)
}
return false;
}
return iterate(this.parent, 0)
}
}
class Cube extends OutlinerElement {
constructor(data, uuid) {
@ -333,15 +346,11 @@ class Cube extends OutlinerElement {
}
}
rotationAxis() {
if (this.rotation_axis) {
return this.rotation_axis
}
var axis_i = 0;
while (axis_i < 3) {
for (var axis = 0; axis < 3; axis++) {
if (this.rotation[axis_i] !== 0) {
return getAxisLetter(axis_i)
this.rotation_axis = getAxisLetter(axis_i);
return this.rotation_axis;
}
axis_i++;
}
}
getMesh() {
@ -688,7 +697,9 @@ class Cube extends OutlinerElement {
}
setColor(index) {
this.color = index;
Canvas.updateSelectedFaces()
if (this.visibility) {
Canvas.adaptObjectFaces(obj)
}
}
showContextMenu(event) {
if (!this.selected) {
@ -1014,7 +1025,8 @@ class Group extends OutlinerElement {
var scope = this;
if (Blockbench.hasFlag('renaming')) return;
if (!event) event = {shiftKey: false}
var allSelected = (selected_group === this && selected.length === this.children.length)
var allSelected = selected_group === this && selected.length && this.matchesSelection()
//(selected_group === this && selected.length >= this.children.length)
//Clear Old Group
if (selected_group) selected_group.unselect()
@ -1077,6 +1089,21 @@ class Group extends OutlinerElement {
this.selected = false
return this;
}
matchesSelection() {
var scope = this;
var match = true;
for (var i = 0; i < selected.length; i++) {
if (!selected[i].isChildOf(scope, 20)) {
return false
}
}
this.forEachChild(obj => {
if (!obj.selected) {
match = false
}
})
return match;
}
extend(object) {
Merge.string(this, object, 'name')
Merge.boolean(this, object, 'shade')
@ -1207,6 +1234,7 @@ class Group extends OutlinerElement {
} else if (destination !== 'cache') {
base_group.addTo(destination, false)
}
Canvas.updatePositions()
loadOutlinerDraggable()
return base_group;
}

View File

@ -463,6 +463,7 @@ function updateInterfacePanels() {
var panel = Interface.Panels[key]
panel.update()
}
return;
var left_width = $('.sidebar#left_bar > .panel:visible').length ? Interface.data.left_bar_width : 0
var right_width = $('.sidebar#right_bar > .panel:visible').length ? Interface.data.right_bar_width : 0
$('body').css(

View File

@ -15,6 +15,7 @@ function newProject(entity_mode) {
Project.ambientocclusion = true;
Prop.file_path = Prop.file_name = Prop.file_name_alt = '';
Prop.project_saved = true;
Prop.animation_path = '';
Prop.added_models = 0;
setProjectTitle();
Canvas.updateAll();
@ -1313,9 +1314,26 @@ function buildClassModel(options) {
var bones = []
var bone_nr = 1
var model_id = Project.parent.replace('geometry.', '')
var model_id = Project.parent.replace('geometry.', '') || 'unknown';
var all_groups = getAllOutlinerGroups()
var loose_cubes = []
TreeElements.forEach(obj => {
if (obj.type === 'cube') {
loose_cubes.push(obj)
}
})
if (loose_cubes.length) {
var group = {
name: 'bb_main',
rotation: [0, 0, 0],
origin: [0, 0, 0],
parent: 'root',
children: loose_cubes
}
all_groups.splice(0, 0, group)
}
all_groups.forEach((g) => {
//model += `\nthis.bone${bone_nr} = new ModelRenderer`
var id = g.name
@ -1377,7 +1395,7 @@ function buildClassModel(options) {
var model = (settings.credit.value
? '//'+settings.credit.value+'\n'
: '')+
'//Paste this code into your mod. Don\'t forget to add your imports\n' +
'//Paste this code into your mod.\n' +
'\nimport org.lwjgl.opengl.GL11;'+
'\nimport net.minecraft.client.model.ModelBase;'+
'\nimport net.minecraft.client.model.ModelBox;'+
@ -1387,7 +1405,7 @@ function buildClassModel(options) {
'\npublic class '+model_id+' extends ModelBase {'
bones.forEach((bone) => {
model += `\n public ModelRenderer ${bone.id};`;
model += `\n private final ModelRenderer ${bone.id};`;
})
model += '\n'+
@ -1402,7 +1420,7 @@ function buildClassModel(options) {
model +=
' }\n'+
'\n @Override'+
'\n public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) { '
'\n public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) {'
bones.forEach((bone) => {
if (bone.rootBone) {

View File

@ -33,7 +33,7 @@ const Language = {
nl: 'Nederlands (Dutch)',
pl: 'Polski (Polish)',
ru: '\u0440\u0443\u0441\u0441\u043A\u0438\u0439 (Russian)',
//sv: 'Svenska (Swedish)',
sv: 'Svenska (Swedish)',
zh: '\u4e2d\u6587 (Chinese)',//中文
}
}

View File

@ -11,7 +11,7 @@ class BBPainter {
})
}
edit(texture, cb, options) {
if (!options.noUndo) {
if (!options.no_undo) {
Undo.initEdit({textures: [texture], bitmap: true})
}
if (options.use_cache &&
@ -19,9 +19,12 @@ class BBPainter {
typeof Painter.current.image === 'object'
) {
Painter.current.image = cb(Painter.current.image) || Painter.current.image
if (options.no_update === true) {
return;
}
Painter.current.image.getBase64(Jimp.MIME_PNG, function(a, dataUrl){
texture.updateSource(dataUrl)
if (!options.noUndo) {
if (!options.no_undo) {
Undo.finishEdit('edit_texture')
}
})
@ -32,7 +35,7 @@ class BBPainter {
Painter.current.image = image
image.getBase64(Jimp.MIME_PNG, function(a, dataUrl){
texture.updateSource(dataUrl)
if (!options.noUndo) {
if (!options.no_undo) {
Undo.finishEdit('edit_texture')
}
})
@ -85,7 +88,7 @@ class BBPainter {
while (i < length) {
x = end_x - diff.x / length * i
y = end_y - diff.y / length * i
Painter.useBrush(texture, x, y, data.cube.faces[data.face].uv)
Painter.useBrush(texture, x, y, data.cube.faces[data.face].uv, i < length-1)
i++;
}
Painter.current.x = end_x
@ -121,7 +124,7 @@ class BBPainter {
Jimp.read(texture.source).then(getPxColor)
}
}
useBrush(texture, x, y, uvTag) {
useBrush(texture, x, y, uvTag, no_update) {
if ((Painter.currentPixel[0] !== x || Painter.currentPixel[1] !== y)) {
Painter.currentPixel = [x, y]
Painter.brushChanges = true
@ -175,7 +178,7 @@ class BBPainter {
})
}
Painter.editing_area = undefined
}, {noUndo: true, use_cache: true})
}, {no_undo: true, use_cache: true, no_update: no_update})
}
}
stopBrush() {
@ -569,18 +572,30 @@ class BBPainter {
})
}
var face_data = {
up: {c1: 0xb4d4e1ff, c2: 0xecf8fdff, place: t => {return {x: t.posx+t.z, y: t.posy, w: t.x, h: t.z}}},
down: {c1: 0x536174ff, c2: 0x6e788cff, place: t => {return {x: t.posx+t.z+t.x, y: t.posy, w: t.x, h: t.z}}},
east: {c1: 0x43e88dff, c2: 0x7BFFA3ff, place: t => {return {x: t.posx, y: t.posy+t.z, w: t.z, h: t.y}}},
north: {c1: 0x5bbcf4ff, c2: 0x7BD4FFff, place: t => {return {x: t.posx+t.z, y: t.posy+t.z, w: t.x, h: t.y}}},
west: {c1: 0xf48686ff, c2: 0xFFA7A4ff, place: t => {return {x: t.posx+t.z+t.x, y: t.posy+t.z, w: t.z, h: t.y}}},
south: {c1: 0xf8dd72ff, c2: 0xFFF899ff, place: t => {return {x: t.posx+t.z+t.x+t.z,y: t.posy+t.z, w: t.x, h: t.y}}},
}
//Drawing
new Jimp(max_size*res_multiple, max_size*res_multiple, 0, function(err, image) {
bone_temps.forEach(function(bt) {
bt.forEach(function(t) {
drawTemplateRectangle(image, 0xb4d4e1ff, 0xecf8fdff, {x: t.posx+t.z, y: t.posy, w: t.x, h: t.z})// up
drawTemplateRectangle(image, 0x536174ff, 0x6e788cff, {x: t.posx+t.z+t.x, y: t.posy, w: t.x, h: t.z})// down
drawTemplateRectangle(image, 0x43e88dff, 0x7BFFA3ff, {x: t.posx, y: t.posy+t.z, w: t.z, h: t.y})// east
drawTemplateRectangle(image, 0x5bbcf4ff, 0x7BD4FFff, {x: t.posx+t.z, y: t.posy+t.z, w: t.x, h: t.y})// north
drawTemplateRectangle(image, 0xf48686ff, 0xFFA7A4ff, {x: t.posx+t.z+t.x, y: t.posy+t.z, w: t.z, h: t.y})// west
drawTemplateRectangle(image, 0xf8dd72ff, 0xFFF899ff, {x: t.posx+t.z+t.x+t.z,y: t.posy+t.z, w: t.x, h: t.y})// south
for (var face in face_data) {
let d = face_data[face]
if (!options.use_texture || (t.obj.faces[face].texture)) {
//Colored
drawTemplateRectangle(image, d.c1, d.c2, d.place(t))
} else {
//Texture
}
}
let obj = t.obj
obj.uv_offset[0] = t.posx

View File

@ -172,19 +172,14 @@ class Preview {
render() {
if (this.canvas.isConnected === false) return;
this.controls.update()
if (display_mode === false) {
if (this.isOrtho === true) {
this.renderer.render(scene, this.camOrtho)
} else {
this.renderer.render(scene, this.camPers)
}
} else {
if (this.isOrtho === true) {
this.renderer.render(display_scene, this.camOrtho)
} else {
this.renderer.render(display_scene, this.camPers)
}
}
this.renderer.render(
display_mode
? display_scene
: scene,
this.isOrtho
? this.camOrtho
: this.camPers
)
}
//Camera
setNormalCamera() {
@ -589,6 +584,7 @@ class Preview {
edit(Transformer)
edit(outlines)
edit(rot_origin)
edit(Vertexsnap.vertexes)
selected.forEach(function(obj) {
var m = obj.getMesh()
if (m && m.outline) {
@ -597,7 +593,7 @@ class Preview {
})
}
editVis(function(obj) {
editVis(obj => {
obj.was_visible = obj.visible
obj.visible = false
})
@ -619,7 +615,7 @@ class Preview {
})
});
editVis(function(obj) {
editVis(obj => {
obj.visible = obj.was_visible
delete obj.was_visible
})
@ -890,7 +886,12 @@ function initCanvas() {
img.onload = function() {
this.tex.needsUpdate = true;
}
northMarkMaterial = new THREE.MeshBasicMaterial({map: tex, transparent: true, side: THREE.DoubleSide})
northMarkMaterial = new THREE.MeshBasicMaterial({
map: tex,
transparent: true,
side: THREE.DoubleSide,
alphaTest: 0.2
})
//Rotation Pivot
var helper1 = new THREE.AxesHelper(2)
@ -1754,20 +1755,21 @@ class CanvasController {
}
buildOutline(obj) {
if (obj.visibility == false) return;
var mesh = obj.getMesh()
var mesh = obj.getMesh();
if (mesh === undefined) return;
if (mesh.outline) {
mesh.outline.geometry.verticesNeedUpdate = true;
return;
}
mesh.remove(mesh.outline)
mesh.remove(mesh.outline);
var line = Canvas.getOutlineMesh(mesh)
line.name = obj.uuid+'_outline'
line.visible = obj.selected
mesh.outline = line
mesh.add(line)
var line = Canvas.getOutlineMesh(mesh);
line.name = obj.uuid+'_outline';
line.visible = obj.selected;
line.renderOrder = 2;
mesh.outline = line;
mesh.add(line);
}
}
var Canvas = new CanvasController()

View File

@ -11,12 +11,13 @@ function settingSetup() {
show_actions: {value: false},
backup_interval: {value: 10, type: 'number'},
//Preview
origin_size: {category: 'preview', value: 10, type: 'number'},
control_size: {category: 'preview', value: 10, type: 'number'},
display_skin: {category: 'preview', value: false, type: 'click', condition: isApp, icon: 'icon-player', click: function() { changeDisplaySkin() }},
shading: {category: 'preview', value: true},
transparency: {category: 'preview', value: true},
texture_fps: {category: 'preview', value: 2, type: 'number'},
origin_size: {category: 'preview', value: 10, type: 'number'},
control_size: {category: 'preview', value: 10, type: 'number'},
display_skin: {category: 'preview', value: false, type: 'click', condition: isApp, icon: 'icon-player', click: function() { changeDisplaySkin() }},
seethrough_outline: {category: 'preview', value: false},
shading: {category: 'preview', value: true},
transparency: {category: 'preview', value: true},
texture_fps: {category: 'preview', value: 2, type: 'number'},
//Grid
base_grid: {category: 'grid', value: true,},
large_grid: {category: 'grid', value: false},
@ -228,7 +229,8 @@ function saveSettings(force_update) {
action.toggleLinkedSetting(false)
}
}
if (hasSettingChanged('base_grid') || hasSettingChanged('large_grid') || hasSettingChanged('full_grid') ||hasSettingChanged('large_box') || hasSettingChanged('display_grid')) {
if (hasSettingChanged('base_grid') || hasSettingChanged('large_grid') || hasSettingChanged('full_grid')
||hasSettingChanged('large_box') || hasSettingChanged('display_grid') || hasSettingChanged('edit_size')) {
buildGrid()
}
if (hasSettingChanged('transparency')) {
@ -238,6 +240,7 @@ function saveSettings(force_update) {
}
}
}
Canvas.outlineMaterial.depthTest = !settings.seethrough_outline.value
if (hasSettingChanged('shading')) {
setShading()
}

View File

@ -54,7 +54,9 @@ class Texture {
selected: this.selected,
mode: this.mode,
saved: this.saved,
uuid: this.uuid
uuid: this.uuid,
old_width: this.old_width,
old_height: this.old_height
}
if (bitmap || this.mode === 'link') {
copy.source = this.source
@ -135,33 +137,37 @@ class Texture {
Blockbench.showQuickMessage('message.square_textures')
}
}
if (Blockbench.entity_mode && textures.indexOf(scope) === 0 && !scope.keep_size) {
var size = {
ow: Project.texture_width,
oh: Project.texture_height,
nw: img.naturalWidth,
nh: img.naturalHeight
}
if (size.ow != size.nw || size.oh != size.nh) {
Blockbench.showMessageBox({
translateKey: 'update_res',
icon: 'photo_size_select_small',
buttons: [tl('message.update_res.update'), tl('dialog.cancel')],
confirm: 0,
cancel: 1
}, function(result) {
if (result === 0) {
var lockUV = ( // EG. Texture Optimierung > Modulo geht nicht in allen Bereichen auf
(size.ow%size.nw || size.oh%size.nh) &&
(size.nw%size.ow || size.nh%size.oh)
)
entityMode.setResolution(img.naturalWidth, img.naturalHeight, lockUV)
if (selected.length) {
main_uv.loadData()
main_uv.setGrid()
if (Blockbench.entity_mode && textures.indexOf(scope) === 0) {
if (!scope.keep_size) {
var size = {
pw: Project.texture_width,
ph: Project.texture_height,
nw: img.naturalWidth,
nh: img.naturalHeight
}
if ((scope.old_width != size.nw || scope.old_height != size.nh) && (size.pw != size.nw || size.ph != size.nh)) {
Blockbench.showMessageBox({
translateKey: 'update_res',
icon: 'photo_size_select_small',
buttons: [tl('message.update_res.update'), tl('dialog.cancel')],
confirm: 0,
cancel: 1
}, function(result) {
if (result === 0) {
var lockUV = ( // EG. Texture Optimierung > Modulo geht nicht in allen Bereichen auf
(size.pw%size.nw || size.ph%size.nh) &&
(size.nw%size.pw || size.nh%size.ph)
)
entityMode.setResolution(img.naturalWidth, img.naturalHeight, lockUV)
if (selected.length) {
main_uv.loadData()
main_uv.setGrid()
}
}
}
})
})
}
scope.old_width = img.naturalWidth
scope.old_height = img.naturalHeight
}
}
if ($('.dialog#texture_edit:visible').length >= 1 && scope.selected === true) {

View File

@ -265,10 +265,23 @@ function mirrorSelected(axis) {
if (!selected.length) return;
Undo.initEdit({cubes: selected})
var center = 8
if (selected_group && Blockbench.entity_mode) {
center = selected_group.origin[axis]
} else if (Blockbench.entity_mode) {
if (Blockbench.entity_mode) {
center = 0
if (selected_group && selected_group.matchesSelection()) {
function flipGroup(group) {
if (group.type === 'group') {
for (var i = 0; i < 3; i++) {
if (i === axis) {
group.origin[i] *= -1
} else {
group.rotation[i] *= -1
}
}
}
}
flipGroup(selected_group)
selected_group.forEachChild(flipGroup)
}
}
selected.forEach(function(obj) {
obj.flip(axis, center, false)
@ -279,6 +292,12 @@ function mirrorSelected(axis) {
})
updateSelection()
Undo.finishEdit('mirror')
/*
Conditions:
Selection equals group cubes:
all selected cubes have group as parent
*/
}
//Scale
function scaleAll(save, size) {

View File

@ -12,10 +12,11 @@ var Undo = {
Undo.current_save = new Undo.save(aspects)
},
finishEdit: function(action, aspects) {
aspects = aspects || Undo.current_save.aspects
//After
var entry = {
before: Undo.current_save,
post: new Undo.save(aspects || Undo.current_save.aspects),
post: new Undo.save(aspects),
action: action
}
Undo.current_save = entry.post
@ -30,7 +31,9 @@ var Undo = {
Undo.history.shift()
}
Undo.index = Undo.history.length
Prop.project_saved = false;
if (!aspects || !aspects.keep_saved) {
Prop.project_saved = false;
}
},
undo: function() {
if (Undo.history.length <= 0 || Undo.index < 1) return;

View File

@ -718,10 +718,15 @@ class UVEditor {
if (!Blockbench.entity_mode) return this;
var scope = this;
var pixels = scope.getPixelSize()
function addElement(x,y,width, height, n, color) {
function addElement(x, y, width, height, n, color) {
x *= pixels;
y *= pixels;
width = limitNumber(width *pixels + x, 0, scope.size) - x;
height = limitNumber(height*pixels + y, 0, scope.height)- y;
scope.jquery.size.append('<div class="uv_mapping_overlay" '+
'style="left: '+x*pixels+'px; top: '+y*pixels+'px;'+
'height: '+height*pixels+'px; width: '+width*pixels+'px;'+
'style="left: '+x+'px; top: '+y+'px;'+
'height: '+height+'px; width: '+width+'px;'+
'background: '+color+';"></div>')
}
var size = selected[0].size(undefined, true)
@ -1759,8 +1764,8 @@ BARS.defineActions(function() {
south: tl('face.south'),
west: tl('face.west'),
east: tl('face.east'),
top: tl('face.up'),
bottom: tl('face.down'),
up: tl('face.up'),
down: tl('face.down'),
},
onChange: function(sel, event) {
Undo.initEdit({cubes: selected, uv_only: true})

View File

@ -809,5 +809,7 @@
"menu.preview.background.set_position": "Position festlegen",
"dialog.toolbar_edit.hidden": "Ausgeblendet",
"action.export_class_entity": "Java Entity exportieren",
"action.export_class_entity.desc": "Exportiert das Modell als Java Class."
"action.export_class_entity.desc": "Exportiert das Modell als Java Class.",
"settings.seethrough_outline": "Durchscheinende Auswahl",
"settings.seethrough_outline.desc": "Zeige Auswahl durch Objekte hindurch an"
}

View File

@ -312,6 +312,8 @@
"settings.control_size.desc": "Size of the 3 axis control tool",
"settings.display_skin": "Display Skin",
"settings.display_skin.desc": "Skin used for the display reference player model",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects",
"settings.shading": "Shading",
"settings.shading.desc": "Enable shading",
"settings.transparency": "Transparency",

View File

@ -805,9 +805,11 @@
"action.record_model_gif.desc": "Graba un GIF animado de este modelo desde este ángulo",
"display.mirror": "Invertir",
"data.separator": "Separador",
"message.set_background_position.title": "Background Position",
"menu.preview.background.set_position": "Set Position",
"dialog.toolbar_edit.hidden": "Hidden",
"action.export_class_entity": "Export Java Entity",
"action.export_class_entity.desc": "Export the entity model as a Java class"
"message.set_background_position.title": "Posición del Fondo",
"menu.preview.background.set_position": "Ajustar Posición",
"dialog.toolbar_edit.hidden": "Oculto",
"action.export_class_entity": "Exportar Entidad de Java",
"action.export_class_entity.desc": "Exporta el modelo de entidad como una clase de Java",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
}

View File

@ -809,5 +809,7 @@
"menu.preview.background.set_position": "Définir la position",
"dialog.toolbar_edit.hidden": "Hidden",
"action.export_class_entity": "Export Java Entity",
"action.export_class_entity.desc": "Export the entity model as a Java class"
"action.export_class_entity.desc": "Export the entity model as a Java class",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
}

View File

@ -805,9 +805,11 @@
"action.record_model_gif.desc": "現在の角度からモデルのアニメーションGIFを記録する",
"display.mirror": "ミラー",
"data.separator": "セパレータ",
"message.set_background_position.title": "Background Position",
"menu.preview.background.set_position": "Set Position",
"dialog.toolbar_edit.hidden": "Hidden",
"action.export_class_entity": "Export Java Entity",
"action.export_class_entity.desc": "Export the entity model as a Java class"
"message.set_background_position.title": "背景の位置",
"menu.preview.background.set_position": "位置をセット",
"dialog.toolbar_edit.hidden": "隠す",
"action.export_class_entity": "Java Entityをエクスポート",
"action.export_class_entity.desc": "エンティティモデルをjava としてエクスポートする",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
}

View File

@ -809,5 +809,7 @@
"menu.preview.background.set_position": "Set Position",
"dialog.toolbar_edit.hidden": "Hidden",
"action.export_class_entity": "Export Java Entity",
"action.export_class_entity.desc": "Export the entity model as a Java class"
"action.export_class_entity.desc": "Export the entity model as a Java class",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
}

View File

@ -809,5 +809,7 @@
"menu.preview.background.set_position": "Set Position",
"dialog.toolbar_edit.hidden": "Hidden",
"action.export_class_entity": "Export Java Entity",
"action.export_class_entity.desc": "Export the entity model as a Java class"
"action.export_class_entity.desc": "Export the entity model as a Java class",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
}

View File

@ -557,12 +557,12 @@
"menu.preview.background.position": "Позиция",
"menu.preview.background.lock": "Привязать к камере",
"menu.preview.background.remove": "Удалить",
"menu.preview.screenshot": "Снимок экрана",
"menu.preview.screenshot": "Скриншот",
"menu.preview.perspective": "Перспектива",
"menu.preview.perspective.normal": "Обычная",
"menu.preview.quadview": "Четыре вида",
"menu.preview.fullview": "Полный вид",
"menu.preview.stop_drag": "Закончить изменение расположения",
"menu.preview.stop_drag": "Закончить изменение позиции",
"menu.uv.copy": "Копировать",
"menu.uv.paste": "Вставить",
"menu.uv.mapping": "UV-преобразование",
@ -588,7 +588,7 @@
"switches.shading": "Тень",
"switches.autouv": "Авто UV",
"panel.uv": "UV",
"panel.display": "Дисплей",
"panel.display": "Отображение",
"panel.textures": "Текстуры",
"panel.outliner": "Элементы",
"panel.options": "Поворот",
@ -609,37 +609,37 @@
"direction.east": "Восток",
"direction.top": "Верх",
"direction.bottom": "Низ",
"display.slot.third_right": "Третье лицо справа",
"display.slot.third_left": "Третье лицо слева",
"display.slot.first_right": "Первое лицо справа",
"display.slot.first_left": "Первое лицо слева",
"display.slot.third_right": "Третье лицо: правая рука",
"display.slot.third_left": "Третье лицо: левая рука",
"display.slot.first_right": "Первое лицо: правая рука",
"display.slot.first_left": "Первое лицо: левая рука",
"display.slot.head": "Голова",
"display.slot.ground": "Земля",
"display.slot.frame": "Рамка",
"display.slot.gui": "ГПИ",
"display.slot.gui": "Интерфейс",
"display.rotation": "Поворот",
"display.translation": "Смещение",
"display.scale": "Масштаб",
"display.slot": "Слот",
"display.reference": "Эталонная модель",
"display.presetname": "Имя",
"display.presetname": "Название",
"display.reference.player": "Игрок",
"display.reference.zombie": "Зомби",
"display.reference.armor_stand": "Стойка для брони",
"display.reference.baby_zombie": "Маленький зомби",
"display.reference.armor_stand_small": "Маленькая стойка для брони",
"display.reference.monitor": "Обычный",
"display.reference.monitor": "Обычный вид",
"display.reference.bow": "Лук",
"display.reference.block": "Блок",
"display.reference.frame": "Рамка",
"display.reference.inventory_nine": "3x3",
"display.reference.inventory_full": "Инвентарь",
"display.reference.hud": "HUD",
"display.preset.blank_name": "Пожалуйста, введите имя",
"display.preset.item": "Предмет по умолчанию",
"display.preset.block": "Блок по умолчанию",
"display.preset.handheld": "Оружие по умолчанию",
"display.preset.rod": "Стержень по умолчанию",
"display.preset.blank_name": "Введите название",
"display.preset.item": "Предмет",
"display.preset.block": "Блок",
"display.preset.handheld": "Оружие",
"display.preset.rod": "Стержень",
"dialog.continue": "Продолжить",
"message.square_textures": "Текстуры должны быть квадратными",
"message.unsaved_texture.title": "Несохранённая текстура",
@ -651,22 +651,22 @@
"action.brush_mode.brush": "Кисть",
"action.brush_mode.noise": "Шум",
"action.brush_mode.eraser": "Ластик",
"action.brush_mode.fill": "Заполнить",
"action.vertex_snap_mode.move": "Двигать",
"action.vertex_snap_mode.scale": "Масштабировать",
"action.open_model_folder": "Открыть папку модели",
"action.open_model_folder.desc": "Открывает модель в которой находится текстура",
"action.change_textures_folder": "Изменить папку текстур",
"action.change_textures_folder.desc": "Изменить папку в которой сохранены все текстуры",
"action.brush_mode.fill": "Заливка",
"action.vertex_snap_mode.move": "Перемещение",
"action.vertex_snap_mode.scale": "Масштабирование",
"action.open_model_folder": "Открыть расположение модели",
"action.open_model_folder.desc": "Открывает папку, в которой находится модель",
"action.change_textures_folder": "Изменить расположение текстур",
"action.change_textures_folder.desc": "Изменить папку, в которой сохранены текстуры",
"menu.texture.particle": "Использовать для частиц",
"message.update_notification.title": "Доступно обновление",
"message.update_notification.message": "Доступно обновление Blockbench \"%0\". Вы хотите установить его?",
"message.update_notification.message": "Доступно обновление Blockbench «%0». Хотите установить его?",
"message.update_notification.install": "Установить",
"message.update_notification.later": "Позже",
"message.untextured": "Эта поверхность не имеет текстур",
"dialog.toolbar_edit.title": "Настроить панель инструментов",
"dialog.shift_uv.title": "Сместить UV",
"dialog.shift_uv.message": "Введите число по которому Вы хотите умножить смещение UV. Математические выражения разрешены. Добавьте \"+\" перед числом если Вы хотите добавить его.",
"dialog.shift_uv.message": "Введите число по которому нужно умножить смещение UV. Математические выражения разрешены. Добавьте «+» перед числом, если нужно его добавить.",
"dialog.shift_uv.horizontal": "Горизонтально",
"dialog.shift_uv.vertical": "Вертикально",
"keybindings.reset": "Сбросить",
@ -809,5 +809,7 @@
"menu.preview.background.set_position": "Установить позицию",
"dialog.toolbar_edit.hidden": "Спрятано",
"action.export_class_entity": "Экспортировать сущность Java",
"action.export_class_entity.desc": "Экспортировать модель сущности как класс Java"
"action.export_class_entity.desc": "Экспортировать модель сущности как класс Java",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
}

View File

@ -809,5 +809,7 @@
"menu.preview.background.set_position": "Set Position",
"dialog.toolbar_edit.hidden": "Hidden",
"action.export_class_entity": "Export Java Entity",
"action.export_class_entity.desc": "Export the entity model as a Java class"
"action.export_class_entity.desc": "Export the entity model as a Java class",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
}

View File

@ -1,5 +1,5 @@
{
"dialog.ok": "好的",
"dialog.ok": "确认",
"dialog.cancel": "取消",
"dialog.confirm": "确认",
"dialog.close": "关闭",
@ -19,7 +19,7 @@
"keys.shift": "Shift",
"keys.alt": "Alt",
"keys.meta": "Cmd",
"keys.delete": "删除",
"keys.delete": "Delete",
"keys.space": "空格",
"keys.leftclick": "左键点击",
"keys.middleclick": "中键点击",
@ -402,9 +402,9 @@
"action.load_plugin.desc": "通过导入源文件加载插件。",
"action.reload_plugins": "重新加载插件",
"action.reload_plugins.desc": "重载所有开发插件。",
"action.uv_dialog": "UV 窗口",
"action.uv_dialog": "打开全部 UV 窗口",
"action.uv_dialog.desc": "打开 UV 对话框以查看彼此相邻的所有面",
"action.uv_dialog_full": "视图",
"action.uv_dialog_full": "视图",
"action.uv_dialog_full.desc": "打开UV对话框以全屏编辑一个面",
"action.undo": "撤消",
"action.undo.desc": "撤消上次更改",
@ -561,7 +561,7 @@
"menu.preview.perspective": "透视",
"menu.preview.perspective.normal": "正常",
"menu.preview.quadview": "四视图",
"menu.preview.fullview": "视图",
"menu.preview.fullview": "视图",
"menu.preview.stop_drag": "停止背景定位",
"menu.uv.copy": "复制",
"menu.uv.paste": "粘贴",
@ -583,7 +583,7 @@
"cube.color.blue": "蓝色",
"cube.color.green": "绿色",
"cube.color.lime": "黄绿色",
"switches.visibility": "可见",
"switches.visibility": "切换可见",
"switches.export": "导出",
"switches.shading": "阴影",
"switches.autouv": "自动UV",
@ -593,16 +593,16 @@
"panel.outliner": "大纲",
"panel.options": "旋转",
"panel.options.angle": "角度",
"panel.options.origin": "原点",
"panel.options.origin": "旋转原点",
"uv_editor.title": "UV 编辑器",
"uv_editor.all_faces": "全部",
"uv_editor.no_faces": "无",
"face.north": "北",
"face.south": "南",
"face.west": "西",
"face.east": "东",
"face.up": "上",
"face.down": "下",
"face.north": "北/-X面",
"face.south": "南/X面",
"face.west": "西/-Y面",
"face.east": "东/Y面",
"face.up": "上/Z面",
"face.down": "下/-Z面",
"direction.north": "北",
"direction.south": "南",
"direction.west": "西",
@ -649,7 +649,7 @@
"dialog.update.installed": "已安装的版本",
"dialog.update.update": "更新",
"action.brush_mode.brush": "笔刷",
"action.brush_mode.noise": "点",
"action.brush_mode.noise": "像素点",
"action.brush_mode.eraser": "橡皮擦",
"action.brush_mode.fill": "油漆桶",
"action.vertex_snap_mode.move": "移动",
@ -711,13 +711,13 @@
"uv_editor.maximized": "最大化",
"uv_editor.autouv": "尺寸自动",
"uv_editor.mirrored": "镜像",
"uv_editor.to_all": "适用于所有",
"uv_editor.to_all": "适用于所有的面",
"uv_editor.transparent": "设置透明度",
"uv_editor.cullface_on": "开启面剔除",
"uv_editor.cullface_off": "关闭面剔除",
"uv_editor.tint_on": "开启着色",
"uv_editor.tint_off": "关闭着色",
"action.uv_apply_all": "适用于所有",
"action.uv_apply_all": "适用于所有的面",
"action.uv_apply_all.desc": "将当前面的设置应用于所有面",
"message.convert_mode.title": "模型转换",
"message.convert_mode.message": "您确定要将此类型转换为 %0 吗?您无法撤消此步骤",
@ -795,19 +795,21 @@
"panel.variable_placeholders": "变量占位符",
"panel.variable_placeholders.info": "列出要通过 name=value 预览的变量",
"status_bar.vertex_distance": "距离: %0",
"dialog.create_gif.title": "Record GIF",
"dialog.create_gif.length": "Length (Seconds)",
"dialog.create_gif.title": "录制GIF",
"dialog.create_gif.length": "长度(秒)",
"dialog.create_gif.fps": "FPS",
"dialog.create_gif.compression": "Compression Amount",
"dialog.create_gif.play": "Start Animation",
"category.animation": "Animation",
"action.record_model_gif": "Record GIF",
"action.record_model_gif.desc": "Record an animated GIF of the model from the current angle",
"display.mirror": "Mirror",
"dialog.create_gif.compression": "压缩量",
"dialog.create_gif.play": "播放动画",
"category.animation": "动画",
"action.record_model_gif": "录制GIF",
"action.record_model_gif.desc": "从当前角度记录模型的GIF动画",
"display.mirror": "镜像",
"data.separator": "分隔符",
"message.set_background_position.title": "Background Position",
"menu.preview.background.set_position": "Set Position",
"dialog.toolbar_edit.hidden": "Hidden",
"action.export_class_entity": "Export Java Entity",
"action.export_class_entity.desc": "Export the entity model as a Java class"
"message.set_background_position.title": "背景位置",
"menu.preview.background.set_position": "设置位置",
"dialog.toolbar_edit.hidden": "隐藏",
"action.export_class_entity": "导出java实体",
"action.export_class_entity.desc": "作为java class导出模型",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
}

View File

@ -1,7 +1,7 @@
{
"name": "Blockbench",
"description": "Minecraft Block Model Editor",
"version": "2.2.0",
"version": "2.2.1",
"license": "MIT",
"author": {
"name": "JannisX11",