作者laechan (小太保)
看板mud
标题[闲聊] LPMud
时间Sun Jul 6 10:25:05 2014
我想从更根本的东西谈起。
LPMUD 我个人认为,它有几个重要的组成元素
1.data 资料
2.body 资料承载体(物件)
3.function 函数(方法)
4.program 程式(描述)
例如以底下的程式段为例
body function data串
↓ ↓ ↓
me->add_moneys(30000,"balance");
也就是说,LPMud 说穿了大部份的运作模式就是一句:
写 program 以便透过 functoin 对 body 进行 data 的存取。
^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
手段 这才是最终目的
所以今天并不是因为
SetExits 这个函数表面上的意义是
设定出口,
SetExits((["down":"002"]))
就等於房间多了往 down 这个出口的
资料,这是错误的。
我理解 LPMud 的组成元素,是以我能修改 tmi2_v3,也能修改 ds,
因为它们都是 LPMud,不管怎麽变都是万变不离其宗,对我来说只差
在改 tmi2_v3 比改 ds 花的时间更少,也就是跟熟悉度有关罢了。
是以不熟悉 tmi2_v3_改、不熟悉 LPMud 的人,该如何从不熟悉到变
成熟悉?很简单,就是在看 code 之前,先理解 LPMud 上述的四个组
成元素就行了,这样你就会知道:
SetExits((["down":"002"]));
跟
Exits["room"]["down"]="/d/area/newbie/002";
这两个是等义的,差别在於前者透过函数存取资料,後者不透过函数
直接对本地变数资料进行操作。我的意思就是对 tmi2_v3 来说:
set("exits/down",QR"002");
跟
data["exits"]["down"]=QR+"002";
也是等义的。
既然是等义的,为什麽不直接对变数资料进行操作就好,而要额外透
过函数来存取资料?
因为现实上,做任何事情都需要建立方法,就像你存在银行里的钱,
银行不允许你本人直接进金库存取,而是建立各种方法让你存取银行
里的钱一样(临柜存提款、网路银行、ATM提款机、..)。
临柜存提款 ──┐
│
网路银行 ───┼─→ 存取钱
│
ATM 提款机 ──┘
这些都是手段 它们的最终目的都是这个
所以我认为对想要熟悉 LPMud 的使用者来说,最重要的就是要先理解
资料的存在,以及很多的 code 其实说穿了都是在做资料的存取。
set("level",100
); 资料的存取
SetExits((["down":"002"])
); 资料的存取
vobjd->
vobj_data("query","m002"
); 资料的存取
new_stat(me
); 资料的存取
map_delete(data,"exits"
); 资料的存取
data["exits"]["down"]
=__DIR__+"002.c"; 资料的存取
tmps
-=({me}); 资料的存取
data["time"]
+=10; 资料的存取
race
=data["race"]; 资料的存取
.
.
至於建立各种方法与手段的种种考量,也并非重点,反而是要先理解
「为何要建立各种方法与手段?因为它们本来就各有考量」,才不会
让自己局限在那些已存在的手段上,而无法去变通它。
就像世界上有各式各样的人类,它们的资料本质都是 dna,而人类或
是蟑螂,说穿了都是 dna 的载体罢了。人类在尚未了解 dna 这个东
西之前会说:人类是上帝拿泥巴造出来的。
我希望这个举例就足以充份说明,为何了解资料的存在,比了解其它
东西还要更优先的缘故。
例如以底下的房间物件来说:
void create()
{
set("short","一间房间"); 实际上在做 data["short"] 的存取
set("long","这是一间普通的房间.\n"); 实际上在做 data["long"] 的存取
set("exits/down",QR"002"); 实际上在做 data["exits"] 的存取
}
或许你会说:code 明明就没有看到 data 啊。
相同的,网路银行也没有让你看到白花花的钞票跟硬币啊,你看到的
只是数字,以及数字的改变。
那因此可以理解那些数字就是钱吗?当然不可以。
你存在银行里的钱才是「钱」。
那为什麽明明是你的钱,银行却不允许你直接存取?这可以用一个很
简单的例子做说明:
void 提款(object 银行客户,int 提领金额)
{
string id=银行客户->读取("帐户ID");
银行客户->提款(提领金额);
纪录(id+" 在 "+ctime(time())+" 领出 "+提领金额);
}
那麽任何透过上面的函数做提款动作的银行客户,在
提款的瞬间,也
会同时被
纪录。
银行客户->提款(提领金额); 类似 me->set("level",10); ─┐
├→ data["level"]=10;
提款(银行客户,提领金额); 类似 set_level(me,10); ┬┘
└→ 但是还可以做一些额
外的事情如纪录
(事实上 set() 也可以做额外的事情,只是为方便讲解就先不提)
对银行来说这样很方便,但是对银行客户来说,这样就很麻烦,因为
这本来就是相对的。为什麽今天要设定一个房间非得要透过一堆 set
或是 setXXX,而不这样写就好呢:
> more /d/area/test_room.c
inherit ROOM;
void create()
{
::create();
data["light"]=1;
data["short"]="一间房间";
data["long"]="这是一间普通的房间.\n";
data["exits"]=([]);
data["exits"]["down"]="/d/area/newbie/002";
}
> update /d/area/test_room
/d/area/test_room: Updated and loaded.
> goto /d/area/test_room
You twitch briefly.
> look
[/d/area/test_room ]
一间房间
这是一间普通的房间.
明显出口有: down.
我的意思就是,你确实可以这样写。
因为重点从来就不是存取资料的手段为何,而是要理解这些手段的目
的都是为了存取资料,然後才是理解为什麽要建立那些手段、以及它
们背後的原因是什麽。
这才是身为一个世界的创造者所应具备的格局。
例如「人类是上帝拿泥巴造成的」,信仰者会将其奉为圭臬,但是以
我来说我接着就会问「那泥巴哪里来的?」「上帝造的?那上帝又是
从哪里来的?」...
反过来说今天如果我相信人类是上帝拿泥巴造成的,而它实际上是错
的,那会产生什麽结果?
任何建立在「人类是上帝拿泥巴造成的」的种种教义,也会是错的。
就像以前人类相信天动说,并以天动说为基础建立了很多认知,可後
来才发现是地动而非天动时 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
↑
└
这些通通都变成了垃圾
就像他妈的霍金讲了一辈子的黑洞,现在突然说:黑洞不存在!....
好像扯远了,总之,LPMud 说穿了就是这麽回事,资料、物件、函数
、程式段,就是这些构成元素罢了,如何宣告一个资料及设定它的结
构,远比如何写房间怪物武防物品还要来的重要,对於浸润其它 mud
多年的 wiz 甚至 adm 来说,只要了解 LPMud 的本质,那上手 tmi2
mudlib 只是时间的问题而已,mud 的概念其实是差不多的,越早理
解其本质,就能越早上手使用。
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 1.165.169.193
※ 文章网址: http://webptt.com/cn.aspx?n=bbs/mud/M.1404613508.A.925.html
※ 编辑: laechan (1.165.169.193), 07/06/2014 10:34:47
※ laechan:转录至看板 mud_sanc 07/06 10:35
1F:推 tenyfish :确实已经习惯资料库+函数的作业模式 42.75.67.129 07/06 11:27
2F:推 tenyfish :了,都是直接使用API,比较容易纠结 42.75.67.129 07/06 11:30
3F:推 tenyfish :在固定函数上的使用。慢慢来吧 42.75.67.129 07/06 11:33
这篇会改写後放进 [LPC] 资料夹,再以这篇为基础,让使用者逐渐
从资料→物件→函数→程式段开始理解。
我现在完全可以理解你觉得武功全废的感觉,但 LPC 让使用者可自
订资料存取的方式及自订存取的函数(包括释出的我,以及可改写的
你)是有好处的,就是使用者可控管资料的存取,包括 ds 也允许使
用者自订函数(只是它已经先帮你订好一堆了)。
例如你定义你的 mud,怪物的等级最高只能设定为 Lv255,结果有一
位 wiz 没有照你订的规则,擅自将怪物的等级设为 500:
SetLevel(500);
那 SetLevel 函数这时就能发挥把关的功能:
void SetLevel(int level)
{
if(level>255) return ; // 只要侦测到带了超过 255 以上的值就无作用
或者
void SetLevel(int level)
{
if(level>255)
{
// 纪录是哪一只 mob 设定了超过 255 的值
log("SetLevelError",base_name(this_object())+" SetLevel("+level+").\n");
return ;
今天假设 ds 已经为你准备好 SetLevel 函数,那你只要依你的需要
去改动 SetLevel 函数即可,不需要创造新函数,而要创造也是可以
的。
(前提就是你要知道函数只是存取资料的手段)
函数化有这样的好处,但是函数化的缺点就是「它就是没有直接存取
来得有效率」,set("level",100) 的效率一定高於 SetLevel(100),
我们 coder 就是经常在衡量要如何设计资料存取的方式,才能在效能
与负荷之间取得理想平衡。
※ 编辑: laechan (1.165.169.193), 07/06/2014 20:33:15