本帖最后由 qaz1-qaz1- 于 2019-2-13 17:29 编辑

引言
这个东西应该火星了,但是因为forge1.13还没有发出来,于是就蹭一下热度好了。我想想这个标题中的"1"要不要加,万一填补上坑就凉了,但是也许有后续呢?还是加上好了。
不废话了,上效果:

在这个帖子中,使用说明在第二页,附有下载,如果要细看则在之后的几页,我认为可供参考的地方在目录的抛砖引玉处,最后有想说的话
使用说明
安装:
百度云:
https://pan.baidu.com/s/10Rw2N8Te27r2yH0_PKG-bw
密码:hhig
  • 下载此数据包
  • 在安装前找到数据包下的 数据包/data/tool/functions/clone 目录
  • 在目录中打开 start.mcfunction,按注释要求进行更改
  • 在目录中打开 clone.mcfunction,按注释要求进行更改
  • 安装数据包
  • 进入游戏,输入 /function tool:help 查看帮助

使用:
  • 使用 function tool:tool 获得选择工具
  • 对着你想定位的方块按右键,此处的方块指的是一整个方块,比如说玻璃、草、石头、泥土...,如果要选择不是一整个的方块,如玻璃板...,请先把选择整个方块,再将方块替换成你想要的,比如你想选择玻璃板:在玻璃板处放下玻璃,选择玻璃,把玻璃打碎放上玻璃板
  • 选中三个点后使用 /function tool:commands/fill 来填充
  • 如果选错了,可以用 /function tool:remove 来移除最近放下的定位点,如果不放心,可以多用几次,直到跳出提示

这个数据包很脆弱,没有设置误操作处理,别尝试去作,用用够了,这个理论上是支持多人的。

功能实现
选择 file: .../functions/selector/set.mcfunction
这个功能主要分为两部分来实现
一、射出箭矢
二、射中时生成盔甲架
射出箭这一个部分在我之前的传送法杖一文已经讲过了,这里就不再赘述的,这里主要讲讲生成盔甲架的部分。步骤与命令如下图所示,为了文章的简略性,命令有所删减
检测箭的落地,这里只要检测箭有没有inGround标签即可
  1. execute as @e[tag=tool_arrow,nbt={inGround:1b}] at @s run function tool:selector/set
复制代码

在箭前面放置定位点,用execute命令,这里的 rotate as 非常关键,规定了以人的方向为基准执行这个命令,这样可以省去将人的Rotation复制到箭上的麻烦,而且还避免了bug(复制很可能不会成功)
  1. execute at @e[tag=tool_arrow_setting] rotated as @s positioned ^ ^ ^0.5 align y run summon minecraft:armor_stand ~ ~ ~ {...}
复制代码

功能实现
复制 file: .../functions/clone/

在这个目录下有两个函数,start 用于初始化,即搭建一个中继环境,clone用于封装复制模块,功能是把 @e[tag=tool_from] 处的方块复制到 @e[tag=tool_to] 处,这里主要讲克隆模块。
克隆主要分为两步,1.打开冰箱门把方块复制到中继处,2.将中继处的方块复制出来。
因为一个命令的两组坐标无法直接相对于两个实体,只能用中继的方法了,不然就是用结构方块。这里是这样实现的
  1. execute at @e[tag=tool_from] run clone ~ ~ ~ ~ ~ ~ -168 3 -783
  2. execute at @e[tag=tool_to] run clone -168 3 -783 -168 3 -783 ~ ~ ~
复制代码

非常的简单粗暴了

功能实现
填充 file: .../functions/fill/
初始化 file: .../function/commands/fill.mcfunction

初始化非常的简单,需要算出3个数据来:两个定位的xyz差值,再作类似于植树问题的处理不好的回忆啊,实现如下,以dx值为例
  1. execute store result score #x_temp tool_calc run data get entity @e[tag=tool_belong,scores={tool_selector=2},limit=1] Pos[0]
  2. execute store result score #x_left tool_calc run data get entity @e[tag=tool_belong,scores={tool_selector=3},limit=1] Pos[0]
  3. scoreboard players operation #x_left tool_calc -= #x_temp tool_calc
  4. execute if score #x_left tool_calc matches 0.. run scoreboard players add #x_left tool_calc 1
  5. execute if score #x_left tool_calc matches ..-1 run scoreboard players remove #x_left tool_calc 1
复制代码

详细解释如下:
  • 获取第一个选择点的x
  • 获得第二个选择点的x
  • 相减
  • 分类做"植树问题"处理,因为如果直接相减,则会遗漏掉一层,所以还要加(或者减)一


位移 file: .../function/fill/

核心思想就是迭代迭代迭代迭代迭代迭代迭代迭代迭代迭代迭代迭代根本停不下来
在使用过程中会有以下的逻辑
x方向的移动
=> 如果x方向移动完了,就在y方向上移动一次,并重置x
=> 如果y方向移动完了,就在z方向上移动一次,并重置y
=> 如果z方向移动完了,就完成操作,否则继续重复
这里以移动x为例贴上具体函数(move_x.mcfunction)
  1. #x
  2. #+
  3. #如果在1上面,就向x+移动
  4. execute if score #x_left tool_calc matches 1.. run tp @s ~1 ~ ~
  5. #修改left
  6. execute if score #x_left tool_calc matches 1.. run scoreboard players remove #x_left tool_calc 1

  7. #-
  8. #如果在-1下,就向x-移动
  9. execute if score #x_left tool_calc matches ..-1 run tp @s ~-1 ~ ~
  10. #修改left
  11. execute if score #x_left tool_calc matches ..-1 run scoreboard players add #x_left tool_calc 1
复制代码

分类讨论是向正方向移动还是向负方向移动后,主要分为两个步骤:位移与记分板的运算。

重置 file: .../function/fill/

因为复制的操作是类似于打印机一样一行一行复制的,所以每次移动完x方向后,就要再在移动y方向移动1格,并且重置x坐标,接下来,以重置x坐标为例说明
  1. #获得位置
  2. execute store result score #x_temp tool_calc run data get entity @s Pos[0] 1000
  3. #将x_origin*1000
  4. scoreboard players operation #x_origin tool_calc *= #thousand tool_calc
  5. #相加
  6. scoreboard players operation #x_temp tool_calc -= #x_origin tool_calc
  7. #写入
  8. execute store result entity @s Pos[0] double 0.001 run scoreboard players get #x_temp tool_calc
  9. #将x_origin/1000
  10. scoreboard players operation #x_origin tool_calc /= #thousand tool_calc
  11. #恢复left
  12. scoreboard players operation #x_left tool_calc = #x_origin tool_calc
复制代码

  • 获得x坐标,记为x1
  • 将x1减去在x轴上已经移动的距离
  • 将x1写入Pos[0]完成重置(讲的不是很清楚)

对y方向上进行的重置也是同理

其他想说的

在写函数的过程中,我陷入了递归懵逼之中:为什么不行 => 改了这个应该就行了 => 为什么不行 => 改了这个应该就行了 => ...
而这一切的一切都是因为甩锅,明明就是技术不好233没有很好的调试工具,来看一看文件中随处可见的心酸的痕迹,
  1. #log
  2. # tellraw @a [">>reset x"]
  3. # execute store result score yo_y test run data get entity @s Pos[0] 1000
  4. # tellraw @a ["x: ",{"score":{"objective":"test","name":"yo_y"}}]
  5. # execute store result score yo_y test run data get entity @s Pos[1] 1000
  6. # tellraw @a ["y: ",{"score":{"objective":"test","name":"yo_y"}}]
  7. # execute store result score yo_y test run data get entity @s Pos[2] 1000
  8. # tellraw @a ["z: ",{"score":{"objective":"test","name":"yo_y"}}]
复制代码

但是我还是凑着过来了,真好。
我实现这一个东西应该是因为打fill指令挺麻烦的,希望大家能用的愉快。不愉快也轻喷