Minecraft(我的世界)中文论坛

 找回密码
 注册(register)
查看: 1654|回复: 61

[命令] 【CBL|丢人素学姐,00ll00】丢人钟V3:完全压缩,防沉迷系统等

[复制链接]
丢人素学姐 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
1946
钻石
性别
保密
注册时间
2017-3-6
查看详细资料
 楼主| 发表于 2019-7-26 07:41:30 | 显示全部楼层 |阅读模式
"原版模组"
中文名称: 丢人钟
英文名称: Diuren Clock
是否有配套资源包:
语言支持: English 
原版模组版本: 2.0
适用版本: 1.14.X 
下载地址: http://附件.org
与多人游戏兼容性: 完全兼容
原版模组类型:
V3 V2

您尚未登录,立即登录享受更好的浏览体验!

您需要 登录 才可以下载或查看,没有帐号?注册(register)

x
本帖最后由 Vinogradov 于 2019-8-4 16:15 编辑


丢人钟V3:完全压缩,防沉迷系统等

作者:丢人素学姐,00ll00

丢人钟系统可能是目前为止唯一可以在原版Minecraft中获取机器时间的解决方案。经历了V1V2两个版本,它的体积大幅缩小,也不会造严重卡顿。

但作者仍然想问:我还能做得更好吗?基于这套系统我还能做些什么?

基于这样的动机,在好几位大佬的提点下,作者完成了丢人钟的第三个版本,这也会是最后一个版本。以后丢人钟只会基于bug进行帖内更新。


更新内容:

  • 压缩到1个命令方块。在目前的游戏机制下这已经是理论最优值。
  • 加载即用,无需安装。
  • 拆分数据包,重写附加功能。
  • (可选)添加了在生存模式获取告示牌时钟的方法。
  • (可选)使游戏内时间与机器时间同步。
  • (可选,仅服务器可用)实现了原版防沉迷系统:在管理员指定的时间段内(可设置)非白名单成员(可设置)禁止上服务器。

在以下内容中,作者会不加说明地使用
V1V2的发布帖中提到的内容,所以如果有读不懂的地方请自行翻阅旧帖 (虽然V2的帖子并不算很旧)。

核心系统:

使用方法:加载即用,无需安装。

注意事项:加载该数据包时会将maxCommandChainLength设为1000000(当然实际上峰值只是8万多,并不会到一百万)。另外,在服务器中使用时请保证enable-command-block为true。

毫无疑问,要做到只有1个CB,除了被探测LastOutput的那个以外,其余所有的命令都放入mcfunction中被高频执行(带有minecraft:tick的标签)。于是我们就来分析一下这个被循环的函数(DiurenClock\data\diuren-clock\functions\main_loop.mcfunction):

  1. scoreboard players set DiurenClock.flag DiurenClock.impl 0
  2. execute if score DiurenClock.SecFromMidnight DiurenClock.impl matches ..43199 run function diuren-clock:bisearch/bs_0_43199
  3. execute if score DiurenClock.SecFromMidnight DiurenClock.impl matches 43200.. run function diuren-clock:bisearch/bs_43200_86399
  4. execute if score DiurenClock.flag DiurenClock.impl matches 0 run function #diuren-clock:runtime_all
  5. scoreboard players operation DiurenClock.hour DiurenClock = DiurenClock.SecFromMidnight DiurenClock.impl
  6. scoreboard players operation DiurenClock.hour DiurenClock /= Const3600 DiurenClock.impl
  7. scoreboard players operation DiurenClock.minute DiurenClock = DiurenClock.SecFromMidnight DiurenClock.impl
  8. scoreboard players operation DiurenClock.minute DiurenClock /= Const60 DiurenClock.impl
  9. scoreboard players operation DiurenClock.minute DiurenClock %= Const60 DiurenClock.impl
  10. scoreboard players operation DiurenClock.second DiurenClock = DiurenClock.SecFromMidnight DiurenClock.impl
  11. scoreboard players operation DiurenClock.second DiurenClock %= Const60 DiurenClock.impl
复制代码

  • 将flag设为0【第1行】
  • 通过二分法(实际上作者使用了二分和三分的混合。为什么要这么做?因为作者很无聊。),由当前的DiurenClock.SecFromMidnight(即日秒)决定具体要运行的是哪个穷举的分组(每个分组中穷举30秒。这个数字是可以,且应该被缩小的。但作者懒得改了,反正也不会造成卡顿,而且拆分更细的话反而可能会引起载入的卡顿)并执行该分组。若执行成功的话将flag设为1【第3行-第4行】
  • 若flag仍然为0,则一次性执行所有穷举,强制同步。【第6行】

第8行-第14行不过是简单的计算,不再分析。

在上述第2步中,有一个技巧是如何只使用一条命令,在匹配成功的分支中同时设置日秒的值并将flag设为1?利用execute store success!示例如下:

  1. execute if block ~ 0 ~ repeating_command_block{LastOutput: "{"extra":[{"color":"red","extra":[{"color":"gray","clickEvent":{"action":"suggest_command","value":"/ayaka"},"extra":[{"text":"/"},{"underlined":true,"color":"red","text":"ayaka"},{"italic":true,"color":"red","translate":"command.context.here"}],"text":""}],"text":""}],"text":"[00:09:00] "}"} run execute store success score DiurenClock.flag DiurenClock.impl run scoreboard players set DiurenClock.SecFromMidnight DiurenClock.impl 540
复制代码

至于这样的过程的合理性,留作习题。。。额。。。不对。。。显然,略。

这样下来,在常规tick,每tick只有几十个命令在执行,且多为记分板命令,不会造成卡顿。


免安装

注意到带有minecraft:tick或者minecraft:load标签的函数在自动执行时,执行地点为世界出生点,所以只需要在数据包的安装函数(带minecraft:load标签)中,使用

  1. setblock ~ 0 ~ minecraft:repeating_command_block[facing=up]{auto:1b,Command:"/ayaka"}
复制代码

,并在穷举时把坐标改成0 ~ 0 即可。如果玩家中途更改了出生点,只需/reload或者重进游戏即可,非常方便。

附加功能:

怀表(数据包名:DiurenClock-Holding,命名空间:diuren-clock.holding)

使用方法:加载即用,无需安装。

这和V2中没有很大的变化。只是将一处记分板实现改为了tag,稍稍化简了命令。

告示牌时钟 (数据包名:DiurenClock-Sign,命名空间:diuren-clock.sign)

使用方法:将一个钻石块和一个钟丢在地上合成蝙蝠蛋,然后对着告示牌(任何种类都可)Shift+右键即可。

告示牌显示和V1与V2中的技术完全一样,不另加分析。

首先,这里的合成是标准的ground crafting(我看外国论坛上是这么叫的,就是把原料扔到地上然后合成产物。为什么不用recipes?不能带nbt啊。)。

对着告示牌右键时,蝙蝠蛋会在此位置生成一个带特定tag的药水云。execute at 这个药水云,summon一个带Sign tag的marker。在这之后,同1tick内,该药水云会被杀死。之后只需高频执行

  1. execute at @e[tag=Sign] run xxx
复制代码

即可用一条命令对所有启动的告示牌时钟经行显示更新。

注意:当告示牌方块变为其他方块时,该marker会被(刻意地)清除。想要重新获得告示牌时钟需重复上述步骤。


同步游戏时间为机器时间(数据包名:DiurenClock-GameTimeSync,命名空间:diuren-clock.game_time_sync)

使用方法:加载即用,无需安装。

注意事项:加载该数据包时会将doDaylightCycle设为false。

先把日秒换算成游戏内tick数,然后再使用time add二分地将这个值设为当前游戏时间。

防沉迷系统(数据包名:DiurenClock-GoToBed,命名空间:diuren-clock.go_to_bed)

使用方法:将服务器的function-permission-level改为4,并在DiurenClock-GoToBed\data\diuren-clock.go_to_bed\functions\white_list.mcfunction中添加自己的名字(使用方法见文件内示例)。在同一文件夹的setup.mcfunction中将StartSec的值修改为开始管制的时间点的日秒数(hour*3600+minute+60+second),将EndSec的值修改为结束管制的时间点的日秒数。默认的值为StartSec=82800,EndSec=25200;即晚上11点到次日早上7点,非白名单人员禁止入服。这些设置在数据包加载后,在游戏中也可手工修改。
注意事项:该数据包只会在服务器上生效,且仅支持1.14.4。
这个功能实现起来并不复杂,无非是高频检测目前日秒是否在管制时间段内,若是则把不带白名单tag的玩家kick出去。在管制时间到来之前的5分钟,1分钟,10秒,9秒,。。。,1秒时会对非白名单玩家弹出提醒。

其它

本来想做个闹钟啥的,后来觉得太麻烦就咕了。


改进

我想,如果Minecraft内无法直接操作字符串的话,现在的架构应该很完美了。虽然作者在V2的帖子里也说过这样的话,但现在应该真的做到底了。

唯一可能改进的地方之前也提到了,就是现在实际上没有必要像V2一样一次性穷举30个可能性。为了保证检测的流畅性,每次检测两三个连续的时间点即可。具体地说,设目前日秒为s,那么V3中单次会检测s所在的半分钟(即xx:xx:00-xx:xx:29或者xx:xx:30-xx:xx::59)内的30秒及这接在这半分钟后的两秒。多两秒是为了在相邻的两个半分钟切换时不会造成变化的不均匀,也有更强的鲁棒性,即在服务器发生比较严重的卡顿时也不容易需要强行同步。但这个数字30是来源于V2中压缩CB大阵体积的需求。事实上,我们只需1+2=3条命令(1是从现在的30改的,后面的2还是起增强稳定性的作用)即可在V3中维持同样的鲁棒性,且每tick也少了20+条命令的执行。

然而这样带来的问题就是我们需要86400个runtime函数(如上所述,每个文件里是三条穷举命令),比起原来86400/30个runtime函数,会加剧加载时的卡顿。另一方面,现在这多余的20+条命令并不会对服务器的流畅运行造成明显卡顿,所以就决定维持现状了。

另外,二分和三分的混合是由于作者的强迫症:86400=2^6*3*5*30。所以实际上是先6次二分,再一次三分,再一个文件中穷举5个runtime函数。 这是不科学的,但鉴于它并不会带来多少性能损失,所以也不改了。


写在最后

从最初想到读LastOutput,到现在丢人钟的坑彻底填完,也有两年多了。在这期间,我得到了很多大佬的帮助和鼓励,这其中包括玄素,如花,土球,SPG,洞洞幺幺洞洞,panda4994,等。我对他们表示衷心的感谢。现在我的三次元事务很多,想开的长期坑也不知何时可以真正地开始做。但至少,我仍然对此保留兴趣与热忱。

感谢

  • 洞洞幺幺洞洞  与他的讨论使我受益良多。他参与了部分测试,并帮我找出了一些我找不出的问题。
  • 如花似玉 V3使用的二分法就是来自他的指导意见。
  • SPGoding 他在V2的帖子下面给出了非常有意思的回复,并提出了一个看似可行的改进方案(即使用技巧拼接字符串,反向穷举)。虽然这个方案最后被证明目前不能用,但这样的思路是我从来没有考虑,或者说即使考虑了也无从下手的。


DiurenClock.7z.zip (252.38 KB, 下载次数: 12)

评分

参与人数 12人气 +26 金粒 +122 绿宝石 +30 贡献 +3 收起 理由
玄素 + 30 + 1 MCBBS有你更精彩~
土球球 + 4 + 1 神乎其技,不服不行!
+ 2 + 2 Ssssssssssssssssssss
EternityTQ + 2 不丢人的丢人钟XDD
ruhuasiyu + 5 + 30 + 1 优秀
00ll00 + 1 + 15 坐等单CB的V3(run
Jokey_钥匙 + 2 穷举,你将更加强大——素学姐.
SPGoding + 3  
⊙v⊙ + 2 穷举使你变强
BlackCB. + 1 + 10 MCBBS有你更精彩~
御龙九秋 + 1 + 15 神乎其技,不服不行!
ItIsEnderman + 3 + 50 MCBBS有你更精彩~

查看全部评分

1234fzk 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
460
钻石
性别
保密
注册时间
2018-5-19
查看详细资料
发表于 2019-7-26 08:29:21 | 显示全部楼层
这是怎么玩的
回复

使用道具 举报

BlackCB. 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
8207
钻石
性别
保密
注册时间
2015-6-20
查看详细资料
发表于 2019-7-26 09:38:09 | 显示全部楼层
本帖最后由 天狼星black 于 2019-7-26 09:41 编辑
execute store result entity @e[tag=s,limit=1] Pose.Head[0] float 6 run scoreboard players get DiurenClock.second DiurenClock

这样不会导致其数值大于360吗?

好像真的可以……我好丢人

回复

使用道具 举报

丢人素学姐 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
1946
钻石
性别
保密
注册时间
2017-3-6
查看详细资料
 楼主| 发表于 2019-7-26 10:00:50 | 显示全部楼层
天狼星black 发表于 2019-7-26 09:38
这样不会导致其数值大于360吗?

好像真的可以……我好丢人

second不是0-59嘛
回复

使用道具 举报

隐退 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
2394
钻石
性别
保密
注册时间
2017-8-25
查看详细资料
发表于 2019-7-26 16:05:07 | 显示全部楼层
本帖最后由 Teenager_Yang 于 2019-7-26 16:38 编辑

还是没有摆脱命令方块
要是能存储和调用字符串,对字符串进行运算(如字符串连接、提取子串等),就啥事都没有了……
回复

使用道具 举报

丢人素学姐 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
1946
钻石
性别
保密
注册时间
2017-3-6
查看详细资料
 楼主| 发表于 2019-7-26 19:57:25 | 显示全部楼层

加载存档呗
回复

使用道具 举报

丢人素学姐 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
1946
钻石
性别
保密
注册时间
2017-3-6
查看详细资料
 楼主| 发表于 2019-7-26 19:58:31 | 显示全部楼层
Teenager_Yang 发表于 2019-7-26 16:05
还是没有摆脱命令方块
要是能存储和调用字符串,对字符串进行运算(如字符串连接、提取子串 ...

这话怎么这么眼熟。。。

啊我好像也说过

评分

参与人数 1人气 +1 收起 理由
隐退 + 1 ……

查看全部评分

回复

使用道具 举报

梓榆 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
390
钻石
性别
保密
注册时间
2019-7-24
查看详细资料
发表于 2019-7-27 19:58:10 | 显示全部楼层
本帖最后由 梓榆 于 2019-7-27 22:25 编辑

有个大胆的想法,不穷举真实时间,而是穷举记分板拼出来的时间(



通过 JSON 文本和三个记分板动态拼出一个文本:
["[",{"score":{"objective":"diuRenClock","Name":"$hour"}},":",{"score":{"objective":"diuRenClock","Name":"$minute"}},":",{"score":{"objective":"diuRenClock","Name":"$second"}},"] "]

把这个文本放到告示牌中,就会自动解析出分数的值:
'{"extra":[{"score":{"name":"$hour","objective":"diuRenClock","value":"12"}},{"text":":"},{"score":{"name":"$minute","objective":"diuRenClock","value":"34"}},{"text":":"},{"score":{"name":"$second","objective":"diuRenClock","value":"56"}},{"text":"] "}],"text":"["}'

这个格式和 lastOutput 中的格式差得太大了。可以把它转存到一个实体的名称中,对这个实体使用命令(需要注意的是,我们应该使用的命令要满足两个条件 (a)没有语法错误,不然不执行;(b)要发生运行时错误,错误信息中还要包含实体名。如果没有发生运行时错误的话,显示出来的实体名会被解析成更长的一大串东西,而不是简单的文本。比如 enchant @e[tag=marker] minecraft:aqua_affinity),把这一长串 JSON 拍扁到命令方块的 lastOutput 里:
'{"extra":[{"color":"red","extra":[{"translate":"commands.enchant.failed.itemless","with":["[12:34:56] "]}],"text":""}],"text":"[hh:mm:ss] "}'

于是 extra 中已经有了拍扁的文本。



接下来,再把真实时间用同样的办法,转存到实体名称里面,再对这个实体用一次 enchant,我们就得到了包含真实时间的 JSON 文本:
'{"extra":[{"color":"red","extra":[{"translate":"commands.enchant.failed.itemless","with":["[hh:mm:ss] "]}],"text":""}],"text":"[hh:mm:ss] "}'



通过 data modify block ... LastOutput from block ... LastOutput,并储存命令的返回值,判断是否为 0,即可知道动态生成的文本与真实时间的文本是否相同。
接下来所要做的,就是用函数递归穷举 $hout $minute $second 了,没什么难度。

全部过程,只需要两个 CB,一个告示牌。如果想要再简化一下,可以把 CB 的内容转存到告示牌上,这样只需要一个 CB 与一个告示牌了,不过这样其实效率更低,得不偿失。



其实最早是在国外某个 MinecraftCommands 的 Discord 组看到的思路,后来仔细试了试,大概就是这样了,以上内容都是我是嫖来的(跑



评分

参与人数 1人气 +2 收起 理由
Jokey_钥匙 + 2 MCBBS有你更精彩~

查看全部评分

回复

使用道具 举报

kfz大大 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
25
钻石
性别
保密
注册时间
2019-7-27
查看详细资料
发表于 2019-7-28 13:23:03 | 显示全部楼层
有点意思啊这个
回复

使用道具 举报

chyx 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
17395
钻石
性别
保密
注册时间
2014-3-20
查看详细资料
发表于 2019-7-30 01:15:34 | 显示全部楼层
梓榆 发表于 2019-7-27 19:58
有个大胆的想法,不穷举真实时间,而是穷举记分板拼出来的时间(



我对这种穷举已经失去了兴趣。
我现在打算用这个
回复

使用道具 举报

Chaoren⑥ 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
292
钻石
性别
保密
注册时间
2019-7-10
查看详细资料
发表于 2019-7-30 02:12:52 来自手机 | 显示全部楼层
中间都是啥,我在哪里,我在看什么,有这种操作,溜了溜了,看不懂
回复

使用道具 举报

颜魂i 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
176
钻石
性别
保密
注册时间
2019-7-28
查看详细资料
发表于 2019-7-30 14:34:17 | 显示全部楼层
我瞎了吗,这啥
回复

使用道具 举报

MC_HJY 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
50
钻石
性别
保密
注册时间
2019-7-29
查看详细资料
发表于 2019-7-30 15:49:37 | 显示全部楼层
我看不见啊:)....
回复

使用道具 举报

271457236 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
29
钻石
性别
保密
注册时间
2019-7-29
查看详细资料
发表于 2019-7-30 19:20:10 | 显示全部楼层
hhhhhhhhhh

评分

参与人数 1人气 -1 金粒 -10 收起 理由
ruhuasiyu -1 -10

查看全部评分

回复

使用道具 举报

271457236 当前离线
帖子
主题
精华
贡献
最后登录
1970-1-1
爱心
积分
29
钻石
性别
保密
注册时间
2019-7-29
查看详细资料
发表于 2019-7-30 19:20:31 | 显示全部楼层
hhhhhhhhhh

评分

参与人数 1人气 -1 金粒 -10 收起 理由
ruhuasiyu -1 -10

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册(register)

本版积分规则

Archiver|小黑屋|Mcbbs.net ( 京ICP备15023768号-1 ) | 京公网安备 11010502037624号 | 手机版

GMT+8, 2019-10-22 00:36 , Processed in 0.056276 second(s), Total 24, Slave 23 queries , Gzip On, MemCached On.

"Minecraft"以及"我的世界"为Mojang Synergies AB的商标 本站与Mojang以及微软公司没有从属关系

© 2010-2019 我的世界中文论坛 版权所有 本站原创图文内容版权属于原创作者,未经许可不得转载

快速回复 返回顶部 返回列表