/** * @author JannisX11 * @modified by 芥子 * @date 2024年11月30日 * @improvement 更改了碰撞箱的计算方式可以直接得出max/min,json文本改为中国版可用的格式可以直接复制粘贴,并汉化了一下。 */ /// (function() { let scale = 1; let position = [0, 0, 0]; let rotation = 0; let new_version = true; window.SeatPositioner = { getDialogLines() { return [ `
`, `
`, `
`, `
` ] }, 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(); } }) })()