23
2013
01

金庸武侠年表-清朝以前

 原作者 lonely 

背景知识,分享一下,供武侠mud做任务参考用

1092年,《天龙八部》故事开始。秋季,段誉参加无量剑比斗。后结识钟灵、木婉清等。
《〈天龙八部〉释名》:“本书故事发生于北宋哲宗元佑、绍圣年间,公元一○九四年前后。”《天龙八部》第6章:“是时北宋汴梁哲宗天子在位,年岁尚幼,太皇太后高氏垂帘听政。……保定帝在位十一年,改元三,曰保定、建安、天佑,其时正当天估年间,四境宁静,国泰民安。”按北宋哲宗元佑为1086—1093年,而大理天佑元年为公元1090年,则故事开始时约在1090年或稍晚。

1093年,年初,段誉为鸠摩智所擒,三月中被掳至江南。于无锡与乔峰结拜。
第11章《向来痴》:“他虽无处世经历,但这二十余日来,对此事早已深思熟虑,想明白了其中关窍……自此一路向东,又行了二十余日,段誉听着途人的口音,渐觉清雅绵软,菜肴中也没了辣椒。……这时正是三月天气,杏花夹径,绿柳垂湖,暖洋洋的春风吹在身上,当真是醺醺欲醉。”
本年,乔峰为查明身份,离杏子林后先后赴少林、聚贤庄、雁门关、信阳,后,因中马夫人计,于小镜湖误杀阿朱,伤心离中原而出关。

1094年,二月初八,擂鼓山珍珑棋会,虚竹得无涯子功力,此后辗转得遇天山童姥、李秋水,终成天山灵鹫宫之主。
29章:“段誉接过一看,见帖上写着四行字道:‘苏星河奉请天下精通棋艺才俊,于二月初八日驾临河南擂鼓山天聋弈棋。’”

本年,六月十五,少林寺大会。萧远山、慕容博现身,后被无名僧点化,皈依佛门。
40章:“各人都接到丐帮帮主庄聚贤的英雄帖,说道少林寺和丐帮向来并峙中原,现庄聚贤新任丐帮帮主,意欲立一位中原的武林盟主,并定下若干规章,以便同道一齐遵守,定六月十五亲赴少林寺,与玄慈方丈商酌。”

本年,八月中秋,西夏招驸马,虚竹寻得梦姑。
40章:“公冶乾颇识诸国文字,从头至尾看了一遍,说道:‘果然是西夏国王招驸马的榜文。文中言道:西夏国文仪公主年将及笄,国王要征选一位文武双全、俊雅英伟的未婚男子为驸马,定放今年八月中秋起选拔,不论何国人士,自信为天下一等一人才者,于该日之前投文晋谒,国王皆予优容接见。即令不中驸马之选,亦当量才录用,授以官爵,更次一等者赏以金银……’”
本年十月,段正淳及其情侣殒于曼陀山庄。
本年,北宋哲宗元佑九年,太皇太后驾崩,哲宗改元绍圣。耶律洪基伺机征宋,为萧峰所阻。萧自尽,《天龙八部》结束。

1115年,北宋政和五年,黄裳刻道藏。数年后成武功高手。
《射雕英雄传》后记:“《射雕英雄传》中所说的黄裳真有其人。近人陈国符先生《道藏源流考》中考证宋徽宗访求天下道教遗书刻板的经过颇详。徽宗于政和三年下诏天下访求道教仙经,所获甚众。政和五年设经局,敕道士校定,送福州闽县,由郡守黄裳役工镂板。所刊道藏称为《政和万寿道藏》,共五百四十函,五千四百八十一卷。”
黄裳,字晟仲,人称演山先生,福建延平人,高宗建炎三年(1042—1129)卒,年八十七。
独孤求败(1100?-1170年),生年不详,死于公元1170年


1180——1190年间,某年中秋,少林寺武功考校中,火工头陀击毙达摩堂首座苦智禅师,寺中内讧,罗汉堂首座苦慧禅师忿而出走开创西域少林。
详见《倚天屠龙记第2章。文中时间为郭襄19岁游少林,其时为1263年,而“七十余年前”则在1180——1190年间。


1200年,首次华山论剑。

1204年,《射雕》故事开始。

1205年,郭靖出生。

1223年,中秋嘉兴烟雨楼之会,郭靖18岁。穆念慈怀杨过。

1224年,杨过出生。
《射雕》中农历七月十五日是丐帮君山大会,而郭靖和黄蓉在七天后(即七月二十二日)至铁掌峰并见到杨康、穆念慈。穆念慈正是在此期间有了杨过。以正常十月怀胎计算,杨过生于次年农历五月间。

  1225年,郭靖、黄蓉南下途经江西上饶,救穆念慈,为杨过起名。成吉思汗逝世。二次华山论剑。《射雕英雄传》结束。

1238年,杨过14岁,被郭靖、黄蓉夫妇收留。以不见容于桃花岛,被郭靖送往终南山重阳宫学艺。其后机缘巧合,入古墓结识小龙女。此时小龙女20岁。

1242年,杨过18岁,在古墓生活3年有余。后与龙出秘道,在终南山学习王重阳留下的《九阴真经》。

1243年,杨过19岁,先后结识陆无双与程英,并于华山见到洪七公与欧阳峰。

1244年,郭襄出生。杨过20岁,与小龙女分别于绝情谷。
1246年,张君宝(三丰)出生。
《倚天屠龙记》第3章:……一路上虽然桃红柳绿,春色正浓,他却也无心赏玩,心中默默计算:‘今日三月廿四,到四月初九还有一十四天,须得道上丝毫没有耽搁,方能及时赶到武当山,祝贺恩师他老人家九十岁大寿。’”
1259年,襄阳大战,郭襄16岁。《神雕侠侣》结束。
《神雕侠侣》第39章:“自蒙古和宋军交锋以来,从未有如此大败,而一国之主丧于城下,更是军心大沮。蒙古大汗之位并非父死子袭,系由皇族王公、重臣大将会议拥立。蒙哥既死,其弟七王子阿里不哥在北方蒙古老家被得王公拥戴而为大汗。忽必烈得讯后领军北归,与阿里不哥争位,兄弟各率精兵互斗。最后忽必烈得胜,但蒙古军已然大伤元气,无力南攻,襄阳城得保太平。直到一十三年后的宋度宗咸淳九年,蒙古军始再进攻襄阳。”按,南宋度宗咸淳九年为公元1273年。
1263年,郭襄19岁,游历少林,结识何足道。张君宝逃出少林寺。
《倚天屠龙记》第1章:“郭襄自和杨过、小龙女夫妇在华山绝顶分手后,三年来没得到他二人半点音讯。”
1285年,南宋淳佑五年,郭襄40岁,创立峨眉派。
1336年,《倚天屠龙记》新故事开始。
《倚天屠龙记》第3章:“这一年是元顺帝至元二年,宋朝之亡至此已五十余年。”
1346年,张无忌9岁,随父母自冰火岛返回中原。
《倚天屠龙记》第8章 穷发十载始归航。
1348年,张无忌11岁,下随张三丰下武当山求医。
《倚天屠龙记》第18章:“他瞧着这位相别九年的六师叔时,只见他满脸风尘之色,两鬓微见斑白,想是纪晓芙之死于他心灵有极大打击。”
1352年,张无忌15岁,被困昆仑仙境,得《九阳真经》。
《倚天屠龙记》第17章:“他进来时十五岁,身子尚小,出去已是二十岁,长大成人,却钻不过那狭窄的洞穴了。他吸一口气,运起了缩骨功,全身骨骼挤拢,骨头和骨头之间的空隙缩小,轻轻易易的便钻了过去。”
1357年,张无忌20岁,习得九阳神功,解光明顶之围,任明教教主。

1358年,韩林儿死。张无忌归隐。《倚天屠龙记》结束。

1428年左右,日月神教夜袭武当山。
《倚天屠龙记》结束时张无忌21岁,杨不悔约16岁。两人的影响力比较合理的估计是70年左右(误差不超过10年),此时张无忌超过90岁,杨也年过八旬。而《倚天屠龙记》中少林大会上,殷梨亭下场斗周芷若时,杨不悔已怀孕。武当七侠的后辈中最杰出的宋青书已死,则殷杨之后人很有可能继承武当衣钵或杨逍武功,凭与张无忌的关系或许还可能得张真传,实力也不容小视。故此,不仅需要张无忌、杨不悔等人老迈或身故,而且要待其直系徒弟或子嗣的影响力衰减时,日月神教才可能发动攻击。

1484年,华山派气宗、剑宗决战于玉女峰,气宗胜出,剑宗高手伤亡殆尽。此后五年内,岳不群继任华山派掌门。
《笑傲江湖》第9回:“岳不群在石上坐下,缓缓的道:‘二十五年之前,本门功夫本来分为正邪两途。’”《笑傲江湖》第11回:“那封不平大声道:‘你篡夺华山派掌门之位,已二十多年啦,到今天还做不够?应该让位了罢?’师父笑道:‘各位大动阵仗的来到华山,却原来想夺在下这掌门之位。那有甚么希罕?封兄如自忖能当这掌门,在下自当奉让。’那封不平道:‘当年你师父凭着阴谋诡计,篡夺了本派掌门之位,现下我已禀明五岳盟主左盟主,奉得旗令,来执掌华山一派。’”又:“岳不群道:‘成兄,你们“剑宗”一支,二十五年前早已离开本门,自认不再是华山派弟子,何以今日又来生事?倘若你们自认功夫了得,不妨自立门户,在武林中扬眉吐气,将华山派压了下来,岳某自也佩服。今日这等噜唆不清,除了徒伤和气,更有何益?’” 


令狐冲慢慢坐了下来,道:“我是个无父无母的孤儿,十五年前蒙恩师和师母收录门下,那时小师妹还只三岁,我比她大得多,常常抱了她出去采野果、捉兔子。我和她是从小一块儿长大的。师父师母没儿子,待我犹似亲生儿子一般,小师妹便等于是我的妹子。”

第三十章  密议
1509年,《笑傲江湖》故事开始。春,福威镖局为青城派灭门。令狐冲约25岁,被罚面壁一年。
《笑傲江湖》第1回:“林震南忽道:‘娘子,你今年三十九岁罢?’王夫人啐道:‘呸!这当儿还来问我的年纪?我是属虎,你不知道我几岁吗?’林震南道:‘我发帖子出去,便说是给你做四十岁的大生日……’王夫人道:‘为甚么好端端给我添上一岁年纪?我还老得不够快么?’”王夫人属虎,在《笑傲江湖》开始时39岁,可见当年为蛇年。正德年间共有两个蛇年,即正德四年和正德十六年。据金庸新修订版的介绍,故事发生在明正德年间。而正德十六年正德皇帝就驾崩了,可排除正德十六年为故事发生第一年的可能。如此则《笑傲江湖》故事发生的第一年为正德四年即公元1509年。

1510年,夏,令狐冲结识向问天,以营救任我行被囚梅庄地牢。十二月十五聚群雄围少林。
1511年,三月十五,五岳剑派并派。日月神教归还武当书剑。
1514年,令狐与盈盈成亲。
1515年,暮春,《笑傲江湖》故事结束。

1563年,《侠客行》故事发生。
《侠客行》13章中石清言道:“那是三十年前的事了,他二人那时尚是少年。各门派帮会的首脑接到铜牌请柬之人依约前往,自是无事,否则他这一门派或是帮会不免大祸临头,当时便问:‘到底去是不去?’最先接到铜牌请柬的,是川西青城派掌门人旭山道长。他长笑之下,将两块铜牌抓在手中,运用内力,将两块铜牌熔成了两团废铜。这原是震烁当时的独步内功……”《笑傲江湖》中青城派几乎全军覆没,但《侠客行》故事发生的30年前青城派又出现了顶尖高手旭山道长。余沧海之徒皆以“人”字排行,旭山道长当是其徒孙辈,当在《笑傲江湖》结束后二三十年。所以《侠客行》当在《笑傲江湖》后约五六十年,即明代后期隆庆万历年间(1563—1620)。《侠客行》第19章:“……只见簿面上写着‘河北通州聂家拳‘七字,打开簿子,第一行触目惊心,便是‘庚申五月初二,聂宗台在沧州郝家庄奸杀二命,留书嫁祸于黑虎寨盗贼’,第二行书道:‘庚申十月十七,聂宗峰在济南府以小故击伤刘文质之长子,当夜杀刘家满门一十三人灭口。’” 明末的庚申年有1560年和1620年。而1620年华山派已有穆人清等高手,故此“庚申”只能是1560年。第19章:“……姓白的倘若早得几年见了这本帐簿,侠客岛就是对他手下留情,姓白的也要杀他全家。”从白自在之言可知,聂氏灭门在几年前,则《侠客行》故事发生在1560—1570年间。而第20章记载转年有闰二月。查此段时间仅1564年有闰二月。则《侠客行》发生于前一年即1563年。


1633年,《碧血剑》故事开始,袁承志10岁。

1643年,袁承志20岁,初下华山。
《碧血剑》第3回:“这时已是崇祯十六年,袁承志也已二十岁了。这十年之间,袁承志所练华山本门的拳剑内功,与日俱深,天下事却已千变万化,眼下更是如沸如羹,百姓正遭逢无穷无尽的劫难。”

1644年,崇祯十七年三月,李自成攻陷北京。明朝灭亡。

本年四月,华山弟子集会,《碧血剑》结束。
《碧血剑》第19回:“袁承志见封皮上写着‘字谕诸弟子’字样,认得是师父笔迹,先作了一揖,然后恭恭敬敬的接过来,抽出信纸,见信上写道:‘吾华山派历来门规,不得在朝居官任职。今闯王大业克就,吾派弟子功成身退,其于四月月圆之夕,齐集华山之巅。’下面签着个‘清’字。” 

23
2013
01

MudOS中的内存管理

 

有关内存管理的算法实在是太多了,多到什么程度呢?基本上能想得到的数据结构,都能出现在各式各样的内存管理算法之中,数组、链表、散列表、二叉树等等都在这里大放异彩。研究内存管理实在是一件有趣的事情,同时也能极大的提高自己的编程能力。

内存管理方案 

MudOS中定义了至少3套内存分配函数库:

1.         Build-in system malloc——系统内建函数库,即malloc,realloc,calloc,free;

23
2013
01

ubuntu下MUDOS v22.2b14 完全编译

 运行./build.MudOS
vi socket_efuns.c

       o 修改Ln:1198的代码为 
       addr_in = (local ? &lpc_socks[fd].l_addr : &lpc_socks[fd].r_addr);
下面几个文件添加stdlib.h去掉一些警告(找不到exit()之类的)
vi edit_source.c
       添加 #include <stdlib.h>
vi preprocess.c
       添加 #include <stdlib.h>
vi make_finc.y
       添加 #include <stdlib.h>
修改一下option.h文件兼容老的lib
vi options.h
      
   添加巫师的功能
         修改 Ln:225 #undef NO_WIZARDS
         
采用老的lpc语法(关于nosave - static之类的)
         修改 Ln:266 #undef SENSIBLE_MODIFIERS
         
启用driver 的权限机制
         修改 Ln:659 #define PACKAGE_UIDS
   创建三个文件、否则会找不到  malloc.c 目标啥的  
    touch malloc.c
    touch mallocwrapper.c
    touch applies_table.c
    * 需要新建的三个文件是在make过程生成的,由于ubuntu下的make工具似乎不能识别make过程中的
      文件,所以需要新建三个空白文件,这样在make开始的时候就会识别到,当然在make过程中会复写这三个文件
    数据库部分、拷自nt2的driver 、(特此声明)
    由于以前的数据库api太老connect换成real_connect之类的

    添加数据库部分
    option.h修改下列配置
    #define PACKAGE_DB
    #ifdef PACKAGE_DB
    #undef USE_MSQL        /* MiniSQL, it's small; it's free */
    #define USE_MYSQL 2        /* MySQL, bigger; it's free */
    #define DEFAULT_DB USE_MYSQL    /* default database */
    #endif
    
    修改 db.h 头文件:
    将 24 行至 37 行注释掉,紧接着写上你自己的 MySQL 头文件的位置,
    例如在 /usr/local/mysql/include/mysql.h
    就写上:
    #include "/usr/local/mysql/include/mysql.h"
    
    在源代码目录里的 system_libs 文件里加上 mysql 连接库的位置,
    例如在 /usr/local/mysql/lib
    就加上:
    -L/usr/local/mysql/lib -lmysqlclient
   编译好的diver可能会遇到count(*)返零的问题
    MySQL_fetch对数据类型进行判断时、不包含Count(*)
的数据类型
    最后default赋值为零
[font=楷体_gb2312;]    count(*)返回的数据了类型为FIELD_TYPE_LONGLONG[font=楷体_gb2312;]
    在db.c 650行左右添加
[font=楷体_gb2312;] case FIELD_TYPE_LONGLONG:如下
switch (field->type) {

        case FIELD_TYPE_TINY:
        case FIELD_TYPE_SHORT:
        case FIELD_TYPE_DECIMAL:
        case FIELD_TYPE_LONG:
       case FIELD_TYPE_LONGLONG:
            v->item.type = T_NUMBER;
            v->item.u.number = atoi(target_row);
            break;

        case FIELD_TYPE_FLOAT:
        case FIELD_TYPE_DOUBLE:
            v->item.type = T_REAL;
            v->item.u.real = atof(target_row);
            break;

        case FIELD_TYPE_TINY_BLOB:
        case FIELD_TYPE_MEDIUM_BLOB:
        case FIELD_TYPE_LONG_BLOB:
        case FIELD_TYPE_BLOB:
        case FIELD_TYPE_STRING:
        case FIELD_TYPE_VAR_STRING:
                    if (field->flags & BINARY_FLAG) {
#ifndef NO_BUFFER_TYPE
                v->item.type = T_BUFFER;
                v->item.u.buf = allocate_buffer(field->length);
                write_buffer(v->item.u.buf, 0, target_row, field->length);
#else
                        v->item = const0u;
#endif
                    } else {
                v->item.type = T_STRING;
                if (target_row) {
                v->item.subtype = STRING_MALLOC;
                v->item.u.string = string_copy(target_row, "MySQL_fetch");
                } else {
                v->item.subtype = STRING_CONSTANT;
                v->item.u.string = "";
                }
                    }
            break;

        default:
            v->item = const0u;
            break;
    }
    最后是time()不跑的问题
    在driver里面,有个变量current_time标示时间
    每次心跳时、会current_time++
    心跳的触发要看backend.c 
186行左右 heart_beat_flag的标志变量
    
heart_beat_flag为1才会出发
    
heart_beat_flag 置1、是通过
    
backend.c-> call_haert_beat()
     391行左右
    signal(SIGALRM, sigalrm_handler);
    ualarm(HEARTBEAT_INTERVAL, 0);
    到时触发函数
sigalrm_handler()heart_beat_flag 置1
     在v22.2b14中ualarm没有调用成功、没有设置时钟、就不触发函数sigalrm_handler()
   心跳会停掉
    原因是ualarm.c文件#include "std.h"放的位置不正确
    因为 #ifndef HAS_UALARM 且 std.h里定义了HAS_UALARM 所以放到 #ifndef HAS_UALARM前
    就不会编译ualarm.c文件、就掉不到
ualarm()
    应该将#include "std.h"放到 #ifndef HAS_UALARM 之后

08
2013
01

Mudos V22pre11在windows xp下的编译

网上找的mudos编译完全手册(包括本论坛转载的)有些关键地方需要修正
这次编译,并不完全是在windows下完成的,因为有些文件在windows下无法生成。
编译环境:
Windows Xp sp2,VC6.0(最好)和VS2003均可。还有一个工具是UltraEdit  v15.10.0.1019(用来转换格式)

至于什么bison这些,我没有需要

现在来说步骤
    1,首先下一份mudos V22pre11源代码,首先在lfreebsd环境下编译,linux下应该也可以,如果你没有,你可以叫朋友帮忙编译好
然后把所有的编译好的代码文件都发给你,这里面就会有关键的文件,比如类似grammar.tab.h等
    2。这里是最关键的。把windows下的Mudos.mak文件放到上层代码目录下,然后,用UltraEdit 打开mak文件,利用里面的替换,把^n替换成^p,为什么要做这一步?主要是把unix格式的换行符变成windows下的换行符,然后保存。用VC6.0打开mudos.mak,应该就可以看到代码文件了,如果不转换,是无法看到代码文件的,我当初就卡在这里。
    3,现在,如果没有cc.h,那你就添加一个cc.h文件,如果有了,那么替换一下,内容如下:
#define COMPILER "cl" 
#define OPTIMIZE "-G4" 
#define CFLAGS "-DWIN32 -D_ALL_SOURCE -G4" 
#define OBJDIR "obj" 
4,删除 工程里的malloc.c,mallocwrapper.c,在工程里添加package/uids.c,package/mudlib_stats.c

5,修改 backend.c 中的函数 call_heart_beat(): 
删除以下: 
#ifdef WIN32 
static long Win32Thread = -1; 
#endif 
删除以下: 
if (Win32Thread == -1) Win32Thread = _beginthread(alarm_loop, 256, 0); 

6,修改 crc32.h 在 compute_crc32 函数之前加入: 
typedef unsigned int UINT32; 
修改 crc32.c 在前面增加: 
#include "crc32.h" 

7,修改 crypt.h 中的句子 
char *custom_crypt( CONST char *key, CONST char *salt, byte *rawout);
为 
char *custom_crypt( char *key, char *salt, byte *rawout); 
(即删除所有的 CONST) 

8,将 interface.h, efuns_main.c, compile_file.c, mudlib/interface.c 中所有名为 interface 的变量名都替换成 if_t_array。 

9,修改configure.h文件为下列内容,如果没有,请创建:
#define INCL_STDLIB_H
#define INCL_TIME_H
#define INCL_FCNTL_H
#define INCL_DOS_H
#define INCL_SYS_STAT_H
#define INCL_LIMITS_H
#define USE_STRUCT_DIRENT
#define INCL_STDARG_H
#define HAS_MEMMOVE
#define RAND
#define HAS_STRERROR
#define HAS_GETCWD

#define SIZEOF_INT 4
#define SIZEOF_PTR 4
#define SIZEOF_SHORT 2
#define SIZEOF_FLOAT 4
#define SIZEOF_INT 4
#define SIZEOF_PTR 4
#define SIZEOF_SHORT 2
#define SIZEOF_FLOAT 4
#define CONFIGURE_VERSION    5

好了。编译你的Mudos吧

编译好之后,是一个win32控制台的mudos,在winxp下可以运行,其他平台没测试

运行办法:
把生成好的mudos放到你mudlib的bin目录下,然后在创建一个快捷方式在当前目录,查看快捷方式的属性,并在目标那一栏mudos.exe后面空格加上你的config文件,比如:
F:\xkx\bin\MudOS.exe config.xkx
然后运行你的快捷方式,成功

 

08
2013
01

详谈add_action()及其BUG

   几年前,add_action()的当机BUG是令众多巫师极为头痛的事情,如今各显神通,有
从MUDOS上解决,有从MUDLIB里调整。基本上已经看不到这种问题了。但是,如果未能了
解这个BUG的产生原理,那么还有可能在其它的很多地方再次产生各种各样的新BUG,结
合本人的摸索感受,试图全面介绍一下这方面的知识。

  首先我们来了解一下MUD对玩家输入信息的处理流程。玩家在客户端的指令行里输入
一些或长或短的字符后,系统接收到之后首先会调用在/feature/目录下的alias.c里的p
rocess_input(string str)函数
进行预处理。而那些字符也就是参数str。
(例一:玩家输入gall str==gall
 例二:玩家输入c 我要go str==我要go
 例三:玩家输入out  str==out
 例四:玩家输入kill llm str==kill llm)
  这个函数首先要对玩家的信息进行一些过滤判断,例如对于连续重复指令方面的判
断呀之类的,主要是对机器人的限制。然后就是调用玩家自己设定的alias以及系统设定
的alias(主要由/adm/daemons/下的aliasd.c定义)看看str里面是否有事先设定的alias
,有的话就要转换成原先真正的指令,最后返回
这个经过处理过的新的字符串str。
(例一:gall 经检查发现与玩家设定gall==get all,因此str==get all
例二:c 我要go 经检查发现玩家设定c==chat,因此str==chat 我要go
例三:out 检查没发现alias,因此out==out
 例四:kill llm 检查后没发现alias,因此str==kill llm )

  在玩家进入MUD之后,连线程序logind.c在成功创造玩家的身体之后,会调用一个函
数enable_player(),这个函数原型是在/feature/command.c里。该函数首先调用一个外
部函数enable_commands(),允许它使用 add_action()所加入的命令。然后就add_actio
n("command_hook", "", 1);
  add_action()这是一个外部函数,格式如add_action(A,B,C);就是表示如果玩家输
入指令第一个空格之前的单词与B相同的话,就是调用函数A,后面的参数C一般用不着,
这里不细讲了。那么我们看看这里的就表示,如果玩家输入的第一个单词是"",其实就
是所有的指令都符合这个条件的,那么就会调用到
函数command_hook()。而command_hook()函数就是在command.c里。str如果超过一个单
词,也就是有空格,就会分成第一个为verb,后面的为arg。开始按顺序判断verb是否是
方向、固定指令、emote动作、频道指令,如果是的话,就会把arg作为相应的参数传入
。如果都不是,就会返回0,也就是出现“什麽”的
字样。
(例一:str==get all,get为一固定指令,调用get.c->main()参数是"all"
例二:str==chat 我要go,chat为频道名,调用channeld.c里的do_chat,
  参数arg是"我要go"
例三:str==out,玩家所在场景发现有名叫out的出口,因此调用go.c->main()
  参数arg是"out"
 例四:str==kill llm,kill是一固定指令,调kill.c->main(),arg是"llm" )

  以上是MUD处理信息的经过。
  因此,MUD里所有的指令都是通过add_action()来实现的。而add_action()可以增加
相同名称的指令,如果指令相同,则后加的会先执行,请注意这里,并不是说后加的“
覆盖”先加的,而是“先执行”。关于一个同样的动作单词就可以有好几层的add_actio
n。那么在上一层调用的函数如果是返回0的情况下,系统会自动再去执行下一层的add_a
ction()调用的函数,如果是其中任意一层返回是1,就表示到此中止,不会再执行下一
层的add_action(),关于这一点特性可以灵活地使用。比如一个kill指令,本身通过com
mand_hook已经加了一个,有的房间里再次调用一个add_action("do_kill","kill"),后
来进来一个NPC,NPC身上也带有一个新的add_action("do_kill","kill"),那么只要进
入这个房间后,玩家身上就会有了三层有关kill的add_action()。如果这里输入kill,
自然是先执行NPC身上的do_kill()。返回是0的话,再执行房间里的do_kill(),再是0的
话再执行kill.c。所以,在一般我们在房间,NPC以及OBJ里做的add_action()如果与/cm
ds目录下的指令相同的话,都会优先于指令先行。而且如果是后加的,肯定优先于前加
的。而其中任意一层一旦有返回1的话,就会立即中止。
  LPMUD里基本上所有的谜题和很多特殊效果都需要借助add_action()来实现,认真理
解并掌握它的用法是相当重要的。
  下面我们来谈谈add_action()的 BUG吧!很多老的玩家都知道它的用法,先由一个A
买一只鸡腿(包子也可以),由另一个B打昏它,然后B从A身上搜走鸡腿,再吃光鸡腿扔
掉。等A醒来输入eat jitui指令,系统便会立即当机。
  原因分析,传统MUDLIB的eat是一个add_action(),做在食物的标准继承food.c里。
玩家买下一只鸡腿,那么这个eat的add_action()就加到了玩家身上。在正常情况下,这
个物体消失(比如吃掉)或离开玩家所处环境(比如扔掉并离开),那么add_action()
都会正常去掉。但是在玩家昏迷时,其它人从它身上拿走这个带add_action()的物体,
这个add_action()并不能正常地从玩家身上去掉。而当玩家苏醒后,这个eat的add_acti
on()依旧存在于他身上,他依旧可以执行这个指令,如果执行的对象,比如鸡腿还在游
戏中,不论这只鸡腿被玩家B带到了多远的地方,A都可以通过eat jitui吃得到这只鸡腿
。这种情况只是有点滑稽而已。但是如果这个鸡腿已经消失了,比如B吃掉了,那么它只
能消除在B身上的add_action(),这时A再执行eat,系统一下子找不到jitui这个物体,
就会从内存中载入一大堆莫名其妙乱七八糟的东西,迅速进入死循环,直接导致当机。
所以要实现这个BUG的条件有二,一是找一件有add_action()并且可以通过正常方法摧毁
的,比如食物,不值钱的东西。二是用两个ID执行。
  目前新版本的MUDOS据说已经从底层上修改掉了这个BUG。同时明白了其中的原理也
可以在MUDLIB上用很多方法来避免这种情况的发生。
  再下面就谈一下较少有人知的另一个BUG,这个BUG表面上看起来问题不大,实际运
用中有时会产生很大的问题,就是sleep对add_action()的影响。大家可以仔细看看slee
p.c文件,玩家进入睡眠状态就会调用一个函数me->disable_player();这个函数原型在/
feature/command.c里,最终调用disable_commands();这个外部函数,disable_command
s()的用处就是让一个活物件变成「非活着」,一是add_actions 失效,二是livingp()
返回0值......也就是说,去掉了身上所有的add_action()。然
后在醒来之后,再次调用me->enable_player();这个函数我在前面文章的第五段里介绍
过用法与作用,它只是恢复了玩家的add_action("command_hook", "", 1);也就是所有
的系统固定指令。比如玩家身上物品的add_action,所处环境的add_action都是在init(
)里加载的,玩家在sleep之后并没有呼叫到init(),自然就没有这些。那么问题就会出
现了。假如我们在一个房间里或是在一个物体上作了一个企图覆盖掉正常指令的add_act
ion(想覆盖掉正常指令,只要让这个add_action()调用的函数总是返回1就行)。那么
,玩家只需sleep一下之后,就会让这个覆盖无效。无效之后产生的问题大小就与你当初
覆盖的目的有关了。要解决这一问题,可以修改sleep.c,在玩家醒来后的一瞬间,让玩
家离开原地再重新move回到所处的环境,再让玩家身上所有的东西也同样移出去再重新m
ove回到玩家身上,这样就让系统再次加载玩家身上应该加载的add_action。
  总之,MUDOS当初对于add_action的考虑并不是很完善。再加MUDLIB里的处理手法,
对于象过去的昏迷、睡觉以及今后要发展的点穴、捆绑等等的处理都需要屏蔽掉指令,
那么处理的前后则一定要小心,否则新东东一上,新BUG也就隆重登场。
         谁与争锋 叮当 2001、04、21

08
2013
01

检测有多少物件objects()在内存的代码

 int main(object me)
{
    object *all_objs;
    int size;

    all_objs = objects();
    size = sizeof(all_objs);

    tell_object(me,sprintf("内存中一共有:%d 个物件。\n",size));
    return 1;
}

08
2013
01

一个引起当机的BUG的讨论。

 

一个引起当机的BUG的讨论。 


作者:jackyboy  发表时间:2001年7月31日 12:45
--------------------------------------------------------------------------------

在我自己的环境上,我编写下面的命令代码,运行后自己即刻断线,然后在第一个call_out
未调用前自己再次上线,再次执行改命令,在第一个call_out到达时间开始执行时,将会因
为me的值由object变为0导致MUDOS的段失败崩溃。如果运行两次命令不会当,可以多运行几
次看看。在我自己的OS + LIB里这个问题似乎是屡试屡“爽”,但是我不能100%肯定,所以
贴出来请大家也试试看。我用的是v22.2b11版本。

08
2013
01

在Linux或者Unix下的编译mudos过程

 

   MudOS 是整个Mud的基础。一个成功Mud 不只需要一个成熟的MudLIB,而且需要一个稳定的MudOS。而对于不同版本的MudOS,MudLIB也需要一定的修改。如何修改就不是本文的主要介绍内容,以后有时间继续和大家谈谈如何对于不同版本的MudOS来修改MudLIB。本次的主要内容是如何在 Linux上成功的编译MudOS和使用编译好的MudOS成功架设一个Mud。 


   现在流行的MudOS有两个版本:MudOS v22pre11和 MudOS v22.1b22。这两个版本的MudOS差异甚大,但是在不同版本的Linux下编译过程基本上是一样的。下面就以v22pre11来介绍如何编译MudOS。 
   1、获得MudOS 源代码: 
对于C ++功力不够的巫师还无法修改。而从这里下载的源代码已经修改好了,不需要修改就可以直接编译。 
这里经常见到的错误有 
●没有下载原始MudOS源代码的补丁(MudOS V22pre11源代码)。 
●原始的MudOS 源代码中的几个文件有错误必须经过修改后才能成功架设Mud。否则就虽然能成功编译MudOS 但是启动Mud 时会出现各种的错误。 

08
2013
01

自动重启MudOS

 

这要自己做一个自动重新启动的脚本,因为UNIX下的MUDOS一般不会自动启动的. 
西游记2000里有一个比较好的自动重起脚本,可以拿来参考. 
下面给出一个最简单的脚本,如果想偷懒的话.... 

while [ 0 -eq 0 ] 
do 
ps -u mudadm>/export/home0/mudadm/fy3/bin/file1 
grep fy3driver /export/home0/mudadm/fy3/bin/file1 
if [ $? -eq 1 ] 
  then 
cd /export/home0/mudadm/fy3/bin 
limit descriptors 256 
fy3driver config.fy3 
else 
  sleep 150 
fi 
done 
  

«1»