Minecraft(我的世界)中文论坛

标题: [1.14+] 组合结构的随机生成及修饰 [打印本页]

作者: Ordis    时间: 2019-8-9 20:05
标题: [1.14+] 组合结构的随机生成及修饰
本帖最后由 Ordis 于 2019-8-17 20:32 编辑



效果:

使用命令方块,随机生成三次



使用数据包,随机生成三次

_____________________________________________________________
基本思路
  将一个完整的建筑切割成不同结构,之后将结构随机拼装


  整个过程中,盔甲架作为生成器,通过生成并激活结构方块调出结构
  生成器自身也应被存入结构。结构被调出时,新的生成器将重复以上步骤。
  若不加限制,建筑可以无限延伸

**本文中数据包无需依赖提供的存档,但使用前需要提供结构
**数据包为更新内容,部分介绍省略,建议与"命令方块"页结合理解
**"命令方块"部分不再更新,且只具有随机生成结构的功能
_____________________________________________________________


使用function实现:

(19.08.17 20:15更新)
**为防止代码被删除,此处提供具有注释的数据包供解读(仅供解读,请勿使用)**此数据包注释对应更新5数据包
dynamicgeneration5注释.rar (6.98 KB, 下载次数: 2)
更新4 的数据包结构:


大体思路:



附件:
dynamicgeneration.rar (4.27 KB, 下载次数: 2) 此文件为本文使用的数据包
使用方式:解压至存档中datapacks文件夹   wiki
游戏内在命令方块内输入
  1. function 1:start
复制代码
并在海晶灯上放置盔甲架。激活命令方块,建筑将从此处开始生成
生成完毕后,初始命令方块会被复原

generated.rar (26.18 KB, 下载次数: 2)
此文件保存了文中使用的结构
使用方式:解压至存档下

更新:
--------------------------------------------------------------------------------------------
19.08.12  00:14 更新1

dynamicgeneration1.rar (4.38 KB, 下载次数: 0) 数据包更新:调整数据包结构,不改变使用效果
启动方式同上文,但需要修改启动指令
  1. function dynagnr:1/start
复制代码
--------------------------------------------------------------------------------------------
19.08.16 17:10 更新2
dynamicgeneration2.rar (4.81 KB, 下载次数: 0)
数据包更新:合并运行时生成的命令方块,压缩运行所需空间至1*1*1
启动方式同更新1


--------------------------------------------------------------------------------------------
19.08.16 17:40 更新3
dynamicgeneration3.rar (4.91 KB, 下载次数: 0)
数据包更新:可以彻底脱离命令方块运行



--------------------------------------------------------------------------------------------
19.08.16 21:05 更新4
dynamicgeneration4.rar (5.03 KB, 下载次数: 0)
数据包更新:在结构末端生成终点结构
generated4.rar (26.9 KB, 下载次数: 3)
存储了上述数据包使用的结构文件,添加了简单的终点结构

--------------------------------------------------------------------------------------------
19.08.17 19:00 更新5
dynamicgeneration5.rar (6.33 KB, 下载次数: 3)
数据包更新:自动修饰(此数据包中表现为随机放置箱子)生成完毕的地图


_____________________________________________________________
附注:
    数据包中没有提供南向结构生成,建筑不会向南生成
    本文中结构的相对生成位置只适用于体积为15*15*15的结构。调整此参数需要修改相关的函数文件(2/n中第三条指令等)。
      数据包与下文命令方块使用的指令略有差异。

使用命令方块实现:
(初代系统,有少量bug,实际应用推荐使用数据包)


(本页不再更新)


  本存档中,海晶灯上的盔甲架会作为初始结构生成器
1.生成起始结构

标记“初始生成器”
  1. execute as @e[type=minecraft:armor_stand,tag=!start] at @s if block ~ ~-1 ~ minecraft:sea_lantern run tag @s add start
复制代码

生成并激活结构方块
  1. execute as @e[tag=start] at @s run setblock ~ ~ ~ minecraft:structure_block{mode:"LOAD",posX:-7,posY:-2,posZ:-15,name:gnr_start1}
复制代码
清除结构方块
  1. execute as @e[tag=start] at @s run fill ~ ~ ~ ~ ~1 ~ air
复制代码
2.计分板的创建与初始化(准备第二部分)

创建(准则均为dummy):
tick--------------计时
tickCPR.1-------作为tick上限
gnr_nMAX------向北结构 生成尝试次数上线
gnr_wMAX------向西结构 略
gnr_eMAX------略
gnr_sMAX-------略 (存档中未使用)
gnr_n------------向北结构的生成次数
gnr_w-----------略
gnr_e------------略
gnr_s------------略(存档中未使用)

初始化(将值设置为0):
gnr_n
gnr_e
gnr_w
gnr_s

初始化(任意值):
gnr_eMAX
gnr_nMAX
gnr_wMAX
gnr_sMAX



1.(假装是)随机模块


本存档中通过获取并存储(到计分板UIDM)实体的UUID(假装)得到随机数
此过程中需要不断生成并清除实体,导致实体的分数删除。因此另外创建一个计分板Random,将每次得到的值赋给此计分板中玩家的分数


创建以下计分板(dummy):
UIDM------存储实体UUIDMost
Random---玩家的Random分数 = 某一实体的UIDM分数

获取随机值部分:
生成实体
  1. summon minecraft:armor_stand 2 56 30 {Tags:["getUID"]}
复制代码
存储并简单处理UUIDMost(此过程中自动忽略字母)
  1. execute as @e[type=minecraft:armor_stand,tag=getUID] store result score @s UIDM run data get entity @s UUIDMost 0.0000000000000000005
复制代码
实体的UIDM赋值给玩家的Random
  1. execute as @e[tag=getUID] run scoreboard players operation @a Random = @s UIDM
复制代码
清除此实体
  1. kill @e[tag=getUID]
复制代码
返回“生成实体”步骤(“返回”即重新执行,与“循环高频执行”有差异)

2.生成随机结构
本存档中,在黄、红、绿色混凝土上的盔甲架分别作为北向、东向、西向结构生成器

计时器:
循环指令方块,在第一部分结束后启动。
  1. scoreboard players add @a tick 1
复制代码



北向结构生成:
生成次数未达到上限时,所有黄色混凝土上的盔甲架标记为“北向结构预备生成器”
  1. execute as @e[type=minecraft:armor_stand,tag=!regnr_n] at @s if block ~ ~-1 ~ minecraft:yellow_concrete if score @r gnr_n <= @r gnr_nMAX run tag @s add regnr_n
复制代码
随机选择一个预备生成器作为正式生成器
  1. execute as @e[tag=!gnr_n,tag=regnr_n,limit=1,sort=random,tag=!gnr_Used] if score @r gnr_n <= @r gnr_nMAX run tag @s add gnr_n
复制代码
若未使用的正式生成器周围1-5米无使用过的生成器,则生成结构方块  **此命令方块的内容由其他命令方块随机更改[sup](1)[/sup]
  1. execute as @e[tag=gnr_n,tag=!gnr_Used] at @s unless entity @e[distance=1..5,type=minecraft:armor_stand,tag=!start,tag=gnr_Used] run setblock ~ ~ ~ minecraft:structure_block{mode:"LOAD",posX:-7,posY:-2,posZ:-15,name:"gnr_n3"}
复制代码
激活结构方块,之后清除此方块
  1. execute as @e[tag=gnr_n,tag=!gnr_Used] at @s run setblock ~ ~1 ~ minecraft:redstone_block
复制代码

北向结构生成尝试次数+1  **此连锁命令方块限制条件为“不受制约”,即使生成未成功也会激活
  1. scoreboard players add @a gnr_n 1
复制代码
重置计时器,准备下一次生成
  1. scoreboard players set @a tick 0
复制代码
将此盔甲架标记为“已使用”(基本禁用)
  1. execute as @e[tag=gnr_n,tag=!gnr_Used] at @s run tag @s add gnr_Used
复制代码
返回第一步

其他方向的结构生成略

此部分存在bug:
部分预备生成器不会升级为正式生成器,原因未知
删除以上代码中 选择器(@e)的 limit=1与 sort=random 参数可以解决
但此时所有同一方向的生成器只会生成相同的结构


[sup](1) [/sup]此命令方块的控制器

循环命令方块,第二部分中激活。当玩家的Random分数在[-6,3]中,[sup](1)[/sup]处命令方块将生成结构gnr_n1
  1. /execute as @a at @s if score @s Random matches -6..-3 run data merge block 10 56 26 {Command:'execute as @e[tag=gnr_n,tag=!gnr_Used] at @s unless entity @e[distance=1..5,type=minecraft:armor_stand,tag=!start,tag=gnr_Used] run setblock ~ ~ ~ minecraft:structure_block{mode:"LOAD",posX:-7,posY:-2,posZ:-15,name:"gnr_n1"}'}
复制代码
下同
  1. /execute as @a at @s if score @s Random matches -2..0 run data merge block 10 56 26 {Command:'execute as @e[tag=gnr_n,tag=!gnr_Used] at @s unless entity @e[distance=1..5,type=minecraft:armor_stand,tag=!start,tag=gnr_Used] run setblock ~ ~ ~ minecraft:structure_block{mode:"LOAD",posX:-7,posY:-2,posZ:-15,name:"gnr_n2"}'}
复制代码
其他方向略,见存档

3.第二部分后续+第三部分预备

循环命令方块,在第二部分开始时启动。tick≥tickCPR.1(即计时器不再被重置)时,判定生成结束,同时作为下个连锁命令方块的条件
  1. execute as @a if score @r tick >= @r tickCPR.1 run title @a actionbar "generationCompleted"
复制代码


添加并初始化计分板:
tick1------第三部分计时器

清除正式生成器 **此时没有参加生成的生成器会被保留,作为路线清扫的起始点
  1. execute as @a if score @r tick >= @r tickCPR.1 run kill @e[tag=gnr_w]
复制代码
▲就是不带南方玩


1.消除所有盔甲架重力
循环命令方块,始终开启
  1. execute as @a run execute as @e[type=minecraft:armor_stand] at @s run data merge entity @s {NoGravity:1}
复制代码
2.清扫受阻路径
若发生结构重叠情况,路径可能受阻。这是防止路线受阻的最后办法
**实现此部分需要手动在结构中设置路径,即用特定方块(存档中为平滑石英)在同一平面完全连接结构的所有接口。存档中,路径隐藏在地面下

将所有全场盔甲架(即未被清除的预备生成器)标记为清扫器
  1. execute as @e[tag=!sweep,type=minecraft:armor_stand] at @s run tag @s add sweep
复制代码
使未使用的清扫器在路径上生成新的盔甲架
  1. execute as @e[tag=sweep,tag=!used] at @s if block ~-1 ~-2 ~ minecraft:smooth_quartz run summon minecraft:armor_stand ~-1 ~ ~
  2. execute as @e[tag=sweep,tag=!used] at @s if block ~1 ~-2 ~ minecraft:smooth_quartz run summon minecraft:armor_stand ~1 ~ ~
  3. execute as @e[tag=sweep,tag=!used] at @s if block ~ ~-2 ~-1 minecraft:smooth_quartz run summon minecraft:armor_stand ~ ~ ~-1
  4. execute as @e[tag=sweep,tag=!used] at @s if block ~ ~-2 ~1 minecraft:smooth_quartz run summon minecraft:armor_stand ~ ~ ~1
复制代码
将参与本次行为的清扫器标记为“已使用”
  1. execute as @e[tag=sweep,tag=!used] at @s run tag @s add used
复制代码
使已使用的清扫器清除路径方块和路径上方的障碍(清扫范围可以修改)
  1. execute as @e[type=minecraft:armor_stand,tag=used] at @s run setblock ~ ~-2 ~ air
复制代码
返回第一步



第一步开始同时,执行
  1. scoreboard players add @a tick1 1
复制代码
tick1计时器的玩家分数在≥200时,停止清扫
  1. execute as @a if score @r tick1 matches 200.. run setblock 24 56 13 minecraft:bedrock
复制代码
删除全场盔甲架
  1. kill @e[type=minecraft:armor_stand]
复制代码
生成结束

_____________________________________________________________
关于“结构方块”:

存档(已知1.14.3与1.14.4可用):
dynaGeneration 提取码:wdxt
存档仅供参考

_____________________________________________________________


2019/08/09 23:25

关于随机模块:
炒了原本的随机模块
现在可以脱离实体运行。
(计分板比我想象中的强大..)
@...算了


创建计分板(dummy):
x-----先作种子,后存储(a[sub]0[/sub]x-1+b[sub]0[/sub])mod(m)值,赋值给@a的Random分数
a-----先作乘数a[sub]0[/sub],后存储a[sub]0[/sub]x值
-1----b+(-1)作增量,之后-1存储a[sub]0[/sub]x-1值
b-----b+(-1)作增量,之后b存储a[sub]0[/sub]x-1+b[sub]0[/sub]值
m----作模量

初始化(任意值)
  1. scoreboard players set z -1 -1
复制代码
  1. scoreboard players set z a 5
复制代码
  1. scoreboard players set z b 3
复制代码
  1. scoreboard players set z m 17
复制代码


计算:
a存储a[sub]0[/sub]x值
  1. scoreboard players operation z a *= z x
复制代码

同上
  1. scoreboard players operation z -1 += z a
复制代码
  1. scoreboard players operation z b += z -1
复制代码
  1. scoreboard players operation z b %= z m
复制代码
  1. scoreboard players operation z x = z b
复制代码


返回初始化


x赋值给玩家的Random(循环命令方块,始终开启)
  1. scoreboard players operation @a Random = z x
复制代码
[0,16]
**上文中z不需要存在

关于路线清扫:
其实可以调整fill参数改变清扫范围

实际上清扫是没有办法的办法,清扫有效就意味着建筑重叠,自然会出现很喜感(暴力)的画面
最好的办法还是直接防止结构重叠,不过目前没什么头绪,只能通过探测生成器附近的生成器决定是否进一步生成


关于@r:
1.14版本中@r似乎不能选择非玩家实体
可以使用@e[limit=1,sort=random]实现此功能,且更强大(见wiki)

_______________________________________________________________________________________
存档:19/08/09 23:20改  提取码:alju
弃用的模块会用结构方块可视化范围标注

写得较为仓促,希望各位都能看懂...
谢谢各位的提议啦


















































作者: ItIsEnderman    时间: 2019-8-9 20:30
本帖最后由 ItIsEnderman 于 2019-8-9 22:01 编辑

伪随机数还是搞个像样的吧?比方说最初等的线性同余算法,一个mcfunction就可完成。

(细想一下,用UUID生成还真算新奇……倒不如多取几个?)



↓考虑到低配难以承受住过多实体,我还是倾向于硬算
作者: ruhuasiyu    时间: 2019-8-9 22:17
随机数可以通过战利品表或是@r药水云加分,都是成熟便捷的做法。

然后的话,如果能用数据包实现我觉得会更好,也便于他人使用,不知道你有没有这个想法。

这个东西还是有很多应用场景的。
作者: ruhuasiyu    时间: 2019-8-9 22:19
ItIsEnderman 发表于 2019-8-9 20:30
伪随机数还是搞个像样的吧?比方说最初等的线性同余算法,一个mcfunction就可完成。

(细想一下,用UUID生 ...

首先@r药水云的做法是用完即删,不会导致卡顿的。

另一方面,可以使用战利品表,大约只需要1个盔甲架用来装战利品表物品就行了。

线性同余算法如果你指的是利用gametick来算的话,如果在单tick实现这个功能就会导致没随机了。
作者: SPGoding    时间: 2019-8-9 22:32
不但命令写得好,还是个建筑 dalao hh

提前在结构中用特定方块标记路径,然后在第三步中用 tag=sweep 的清扫器打通路径确实是很巧妙的做法,不过打出这种通道略为喜感(不


原版 Minecraft 在生成村庄时采用了拼图方块来连接各个结构,防止通道断裂。但事实上,Mojang 这么做以后村庄生成 bug 频出,大概还是一种比较复杂的做法。我本人除穷举以外目前也没有特别好的思路。

帖子编写很认真,不过距离优秀还是略逊一筹,经过讨论先暂给一周高亮奖励。

(另外,帖子里提到的「此部分存在bug」为什么我没太看懂…)
作者: Ordis    时间: 2019-8-10 00:42
SPGoding 发表于 2019-8-9 22:32
不但命令写得好,还是个建筑 dalao hh

提前在结构中用特定方块标记路径,然后在第三步中用 tag=sweep 的清 ...

第二阶段生成时可能出现阶段未结束,但生成停止的情况
除去"所有接口生成完毕"的情况,有时还能明显看到生成器符合生成条件,但始终没有生成
用data发现上述生成器的Tags中只有regnr_,说明他是预备生成器。此时明显可以升级为正式生成器,但他没有

我怀疑负责正式生成器选择器(@e[limit=1,sort=random,....])在搞事,但我没有证据
作者: 故人123    时间: 2019-8-10 15:18
        想想这个伪随机数脑洞还真是新奇.
作者: SPGoding    时间: 2019-8-10 21:17
Ordis 发表于 2019-8-10 00:42
第二阶段生成时可能出现阶段未结束,但生成停止的情况
除去"所有接口生成完毕"的情况,有时还能明显看到 ...

一般而言选择器并不会出错。删掉 sort=random,limit=1 后,执行该命令一次就会将所有的预备生成器升级为正式生成器,所以不会出现该问题,但后果如你帖中所述。

出现这种状况我怀疑是这条命令在后续由于某种原因没有被执行到,不过具体为什么我也没太多时间细看了(跑

试试改造成数据包,当命令执行顺序更加可靠以后,说不定问题就解决了呢(
作者: 秋果86    时间: 2019-8-11 09:33
本帖最后由 秋果86 于 2019-8-12 13:44 编辑

原贴删除      

作者: guixiansheng    时间: 2019-8-11 11:54
命令方块咋子用???
作者: ruhuasiyu    时间: 2019-8-11 23:07
你这个命名空间和记分板取名有点飘逸啊……

命名空间就1和2,记分板就abcxm,
作者: SPGoding    时间: 2019-8-11 23:35
什么,这么快就改成函数了,先给个优秀再说



不过仍有两个小建议

命名空间主要是用于避免和别的数据包冲突,你这命名空间如 ruhuasiyu 所说太飘逸了。图方便怎么行(摔

建议取个正常些的命名空间),把 123 移进去,改用 xxx:1/start 之类的调用函数,大概不会显得这么见鬼了



1:scorereload 函数里面采用了放置循环型命令方块高频执行命令的方式,其实可以依靠给某个函数添加 #minecraft:tick 函数标签来达到高频执行这个函数的目的,彻底摆脱命令方块的魔爪。某个帖子的这一页靠下部分有所提及


作者: Ordis    时间: 2019-8-11 23:48
SPGoding 发表于 2019-8-11 23:35
什么,这么快就改成函数了,先给个优秀再说



阿...我把命名空间理解错了,现在争取改一下吧
至于何时完全脱离命令方块,要看我对数据包的理解程度了...现在我只会函数的一小部分,minecraft:tick什么的还是抄来的,完全是一知半解。平时时间不多,这部分可能要等周末实现了
另外,谢谢评价啦..挺激动的..
作者: 2360329435    时间: 2019-8-12 01:49
学到了学到了学到了学到了




欢迎光临 Minecraft(我的世界)中文论坛 (https://www.mcbbs.net/) Powered by Discuz! X3.5