301 lines
10 KiB
JavaScript
301 lines
10 KiB
JavaScript
/**
|
|
* @author JannisX11
|
|
* @modified by 芥子
|
|
* @date 2024年11月30日
|
|
* @improvement 更改了碰撞箱的计算方式可以直接得出max/min,json文本改为中国版可用的格式可以直接复制粘贴,并汉化了一下。
|
|
*/
|
|
/// <reference path="../types/index.d.ts" />
|
|
|
|
(function() {
|
|
let scale = 1;
|
|
let position = [0, 0, 0];
|
|
let rotation = 0;
|
|
let new_version = true;
|
|
|
|
|
|
window.SeatPositioner = {
|
|
getDialogLines() {
|
|
return [
|
|
`<div class="dialog_bar">
|
|
<label class="inline_label">新版</label>
|
|
<input type="checkbox" id="STP-v" oninput="SeatPositioner.update()" checked="${new_version}">
|
|
</div>`,
|
|
`<div class="dialog_bar">
|
|
<label class="inline_label">模型大小</label>
|
|
<input type="number" step="0.1" id="STP-s" oninput="SeatPositioner.update()" class="dark_bordered medium_width" value="${scale}">
|
|
</div>`,
|
|
`<div class="dialog_bar">
|
|
<label class="inline_label">X: </label>
|
|
<input type="number" step="0.1" id="STP-px" class="dark_bordered medium_width" oninput="SeatPositioner.update()" value="${position[0]}">
|
|
<label class="inline_label">Y: </label>
|
|
<input type="number" step="0.1" id="STP-py" class="dark_bordered medium_width" oninput="SeatPositioner.update()" value="${position[1]}">
|
|
<label class="inline_label">Z: </label>
|
|
<input type="number" step="0.1" id="STP-pz" class="dark_bordered medium_width" oninput="SeatPositioner.update()" value="${position[2]}">
|
|
<label class="inline_label">旋转</label>
|
|
<input type="number" step="1" id="STP-r" oninput="SeatPositioner.update()" class="dark_bordered medium_width" value="${rotation}">
|
|
</div>`,
|
|
`<div class="dialog_bar">
|
|
<input type="text" id="STP-out" class="dark_bordered input_wide code" readonly>
|
|
</div>`
|
|
]
|
|
},
|
|
dialog: new Dialog({
|
|
id: 'seat_position',
|
|
title: '座位位置预览',
|
|
width: 540,
|
|
lines: [],
|
|
singleButton: true,
|
|
onConfirm: function() {
|
|
scene.remove(SeatPositioner.object);
|
|
this.hide()
|
|
}
|
|
}),
|
|
object: new THREE.Object3D(),
|
|
setupObject: function() {
|
|
|
|
if (SeatPositioner.init) return;
|
|
|
|
var O = SeatPositioner.object;
|
|
var M = new THREE.MeshLambertMaterial({color: 0xffffff});
|
|
|
|
var head = new THREE.Mesh(new THREE.BoxGeometry(8, 8, 8), M);
|
|
head.position.y = 19;
|
|
O.add(head);
|
|
|
|
var body = new THREE.Mesh(new THREE.BoxGeometry(8, 12, 4), M);
|
|
body.position.y = 9;
|
|
O.add(body);
|
|
|
|
var leg_geo = new THREE.BoxGeometry();
|
|
leg_geo.setShape([-2, -12, -2], [2, 0, 2]);
|
|
|
|
var leg_r = new THREE.Mesh(leg_geo, M);
|
|
leg_r.position.set(2, 3, 0);
|
|
leg_r.rotation.x = Math.degToRad(70);
|
|
leg_r.rotation.z = Math.degToRad(13);
|
|
O.add(leg_r);
|
|
|
|
var leg_l = new THREE.Mesh(leg_geo, M);
|
|
leg_l.position.set(-2, 3, 0);
|
|
leg_l.rotation.x = Math.degToRad(70);
|
|
leg_l.rotation.z = Math.degToRad(-13);
|
|
O.add(leg_l);
|
|
|
|
var arm_geo = new THREE.BoxGeometry();
|
|
arm_geo.setShape([-2, -10, -2], [2, 2, 2]);
|
|
|
|
var arm_r = new THREE.Mesh(arm_geo, M);
|
|
arm_r.position.set(6, 13, 0);
|
|
arm_r.rotation.x = Math.degToRad(36);
|
|
O.add(arm_r);
|
|
|
|
var arm_l = new THREE.Mesh(arm_geo, M);
|
|
arm_l.position.set(-6, 13, 0);
|
|
arm_l.rotation.x = Math.degToRad(36);
|
|
O.add(arm_l);
|
|
|
|
SeatPositioner.init = true;
|
|
},
|
|
update: function() {
|
|
let output = '';
|
|
|
|
position[0] = trimFloatNumber(parseFloat($('#STP-px').val())||0);
|
|
position[1] = trimFloatNumber(parseFloat($('#STP-py').val())||0);
|
|
position[2] = trimFloatNumber(parseFloat($('#STP-pz').val())||0);
|
|
|
|
new_version = $('#STP-v').is(':checked');
|
|
SeatPositioner.object.position.set(
|
|
position[0] * -16,
|
|
position[1] * 16 + (new_version ? 2.2 : 0),
|
|
position[2] * -16,
|
|
);
|
|
output = `"position": [${position.join(', ')}]`;
|
|
|
|
scale = parseFloat( $('#STP-s').val() )||0
|
|
var s = 1 / scale;
|
|
SeatPositioner.object.scale.set(s, s, s);
|
|
|
|
rotation = parseFloat( $('#STP-r').val() )||0;
|
|
SeatPositioner.object.rotation.y = -Math.degToRad(rotation);
|
|
if (rotation) {
|
|
output += `, "rotate_rider_by": ${trimFloatNumber(rotation)}`
|
|
}
|
|
|
|
$('#STP-out').val(output);
|
|
|
|
}
|
|
};
|
|
|
|
|
|
window.SetupHitboxHelper = {
|
|
dialog: new Dialog({
|
|
id: 'setup_hitbox',
|
|
title: '中国版碰撞箱预览',
|
|
width: 540,
|
|
form: {
|
|
type: {label: '模式', type: 'select', options: {
|
|
entity_hitbox: '生物射线碰撞箱',
|
|
entity_collision: '生物实体碰撞箱',
|
|
block_selection_box: '方块射线碰撞箱',
|
|
block_collision: '方块实体碰撞箱',
|
|
}},
|
|
size_entity: {label: '大小', type: 'vector', value: [1, 1], dimensions: 2, step: 0.1, condition: form => form.type == 'entity_hitbox' || form.type == 'entity_collision'},
|
|
offset_entity: {label: '偏移', type: 'vector', value: [0, 0, 0], step: 0.1, condition: form => form.type == 'entity_hitbox'},
|
|
size_block: {label: '大小', type: 'vector', value: [16, 16, 16], max: 16, min: 0, dimensions: 3, condition: form => form.type.startsWith('block')},//方块初始显示
|
|
offset_block: {label: '偏移', type: 'vector', value: [-8, 0, 8], condition: form => form.type.startsWith('block')},
|
|
result: {type: 'textarea', height: 130, readonly: true}
|
|
},
|
|
singleButton: true,
|
|
//生物碰撞箱
|
|
onFormChange({type, size_entity, size_block, offset_entity, offset_block}) {
|
|
if (type.startsWith('entity')) {
|
|
SetupHitboxHelper.object.scale.x = SetupHitboxHelper.object.scale.z = size_entity[0] || 0.01;
|
|
SetupHitboxHelper.object.scale.y = size_entity[1] || 0.01;
|
|
SetupHitboxHelper.object.position.fromArray(offset_entity).multiplyScalar(16);
|
|
SetupHitboxHelper.object.position.set(
|
|
-offset_entity[0] * 16,
|
|
offset_entity[1] * 16,
|
|
-offset_entity[2] * 16
|
|
);
|
|
} else {
|
|
SetupHitboxHelper.object.scale.x = size_block[0]/16 || 0.01;
|
|
SetupHitboxHelper.object.scale.z = size_block[2]/16 || 0.01;
|
|
SetupHitboxHelper.object.scale.y = size_block[1]/16 || 0.01;
|
|
SetupHitboxHelper.object.position.set(
|
|
-offset_block[0],
|
|
offset_block[1],
|
|
offset_block[2]
|
|
);
|
|
}
|
|
|
|
let result_string;
|
|
if (type == 'entity_hitbox') {
|
|
// Entity
|
|
result_string = '"minecraft:custom_hit_test": '+ compileJSON({
|
|
"hitboxes": [
|
|
{
|
|
width: size_entity[0],
|
|
height: size_entity[1],
|
|
pivot: [offset_entity[0], offset_entity[1] + size_entity[1]/2, offset_entity[2]]
|
|
}
|
|
]
|
|
})
|
|
} else if (type == 'entity_collision') {
|
|
// Entity
|
|
result_string = '"minecraft:collision_box": '+ compileJSON({
|
|
width: size_entity[0],
|
|
height: size_entity[1],
|
|
})
|
|
} else {
|
|
// Block
|
|
let value = compileJSON({
|
|
max: [1-(offset_block[0] - size_block[0]/2 + 8 + size_block[0] +8)/16+size_block[0]/16, (size_block[1]+offset_block[1])/16,(offset_block[2] - size_block[2]/2 + 8 + size_block[2]-8)/16],
|
|
min: [1-(offset_block[0] - size_block[0]/2 + 8 +8)/16-size_block[0]/16, offset_block[1]/16, (offset_block[2] - size_block[2]/2 + 8 -8)/16]
|
|
//origin: [offset_block[0] - size_block[0]/2, offset_block[1], offset_block[2] - size_block[2]/2],
|
|
//size: size_block
|
|
});16
|
|
|
|
if (size_block.allEqual(0)) value = false;
|
|
if (size_block.allEqual(16) && offset_block.allEqual(0)) value = true;
|
|
|
|
result_string = "方块模型规范:面朝N所指方向,红蓝线交点作方块的左上角,方块模型需要从这里开始,向右下角伸展。\n"+`"${type == 'block_collision' ? 'collision' : 'clip'}": ` + value
|
|
}
|
|
$('dialog#setup_hitbox textarea').val(result_string).addClass('code');
|
|
},
|
|
onOpen() {
|
|
if (!this.getFormResult().type?.endsWith('block') && Format.id == 'bedrock_block') {
|
|
setTimeout(() => {
|
|
this.setFormValues({type: 'block_collision'});
|
|
}, 10);
|
|
}
|
|
},
|
|
onConfirm() {
|
|
scene.remove(SetupHitboxHelper.object);
|
|
this.hide()
|
|
}
|
|
}),
|
|
size: [1, 0],
|
|
offset: [0, 0, 0],
|
|
object: null,
|
|
setupObject: function() {
|
|
|
|
if (SetupHitboxHelper.init) return;
|
|
let object = SetupHitboxHelper.object = new THREE.LineSegments(
|
|
new THREE.BufferGeometry(),
|
|
new THREE.LineBasicMaterial({color: 0xffbd2e})
|
|
)
|
|
let position_array = [
|
|
8, 0, 8, 8, 16, 8,
|
|
8, 0, -8, 8, 16, -8,
|
|
-8, 0, 8, -8, 16, 8,
|
|
-8, 0, -8, -8, 16, -8,
|
|
|
|
8, 0, 8, -8, 0, 8,
|
|
8, 0, -8, -8, 0, -8,
|
|
8, 16, 8, -8, 16, 8,
|
|
8, 16, -8, -8, 16, -8,
|
|
|
|
8, 0, 8, 8, 0, -8,
|
|
-8, 0, 8, -8, 0, -8,
|
|
8, 16, 8, 8, 16, -8,
|
|
-8, 16, 8, -8, 16, -8,
|
|
]
|
|
object.geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(position_array), 3));
|
|
object.geometry.attributes.position.needsUpdate = true;
|
|
SetupHitboxHelper.init = true;
|
|
}
|
|
};
|
|
|
|
var seat_pos_action, hitbox_action, style;
|
|
|
|
Plugin.register('中国版碰撞箱座位预览', {
|
|
title: '中国版碰撞箱座位预览',
|
|
icon: 'event_seat',
|
|
author: '芥子(原作者JannisX11)',
|
|
description: '适用于中国版的载具座位,生物/方块的射线碰撞箱实体碰撞箱预览工具。\n原作者开源地址:https://github.com/JannisX11/blockbench-plugins/tree/master/plugins/seat_position.js',
|
|
tags: ["Minecraft: Bedrock Edition"],
|
|
version: '1.0.4',
|
|
variant: 'both',
|
|
onload() {
|
|
seat_pos_action = new Action('open_seat_position', {
|
|
name: '设置座椅位置',
|
|
icon: 'event_seat',
|
|
condition: _ => Format.bone_rig,
|
|
click: () => {
|
|
SeatPositioner.dialog.lines = SeatPositioner.getDialogLines();
|
|
SeatPositioner.dialog.show();
|
|
$('#blackout').hide(0);
|
|
SeatPositioner.setupObject();
|
|
scene.add(SeatPositioner.object);
|
|
}
|
|
})
|
|
hitbox_action = new Action('open_hitbox_setup', {
|
|
name: '设置碰撞箱',
|
|
description: '设置实体或方块的射线碰箱或实体碰撞箱',
|
|
icon: 'view_in_ar',
|
|
condition: _ => Format.bone_rig,
|
|
click: () => {
|
|
SetupHitboxHelper.dialog.show();
|
|
$('#blackout').hide(0);
|
|
SetupHitboxHelper.setupObject();
|
|
scene.add(SetupHitboxHelper.object);
|
|
SetupHitboxHelper.dialog.updateFormValues();
|
|
}
|
|
})
|
|
MenuBar.addAction(seat_pos_action, 'filter');
|
|
MenuBar.addAction(hitbox_action, 'filter');
|
|
|
|
style = Blockbench.addCSS(`
|
|
dialog#setup_hitbox textarea {
|
|
tab-size: 40px;
|
|
}
|
|
`)
|
|
},
|
|
onunload() {
|
|
seat_pos_action.delete();
|
|
hitbox_action.delete();
|
|
}
|
|
})
|
|
|
|
})()
|