[閒聊] LPMud

看板mud (網路地下城/文字遊戲)作者 (小太保)時間10年前 (2014/07/06 10:25), 10年前編輯推噓3(300)
留言3則, 1人參與, 最新討論串1/1
我想從更根本的東西談起。 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://www.ptt.cc/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

07/06 11:27, , 1F
確實已經習慣資料庫+函數的作業模式
07/06 11:27, 1F

07/06 11:30, , 2F
了,都是直接使用API,比較容易糾結
07/06 11:30, 2F

07/06 11:33, , 3F
在固定函數上的使用。慢慢來吧
07/06 11:33, 3F
這篇會改寫後放進 [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
文章代碼(AID): #1JkBE4ab (mud)
文章代碼(AID): #1JkBE4ab (mud)