Printable Version of Topic

Click here to view this topic in its original format

The Ring of Wonder _ Θεός Μηχανή 『神之机器』 _ qq机器人原理

Posted by: bx_bob 2010-05-27, 07:18

出于qq群的群众需要,我编写了一个qq机器人,用于投骰等目的。
现在已经到了第4个主版本。
项目主页:
http://code.google.com/p/qqdicebot/
svn链接:(未稳定,随时更新)
https://qqdicebot.googlecode.com/svn/branches/qqdicebot4_xp
代码基于小虾的myqq,使用GPLv3协议。

向下翻到第3点,直接开始有意思的部分。
开发者注意!最近更新:这里
-------------------------------------------------
待完成的内容:

dnd的骰属性功能
wod骰
各种投骰结果的细节显示

Posted by: bx_bob 2010-05-27, 20:48

1.机器人的形式
一开始计划做这个机器人的时候,是想做一个qq的插件,抓取内容然后自动说话什么的。可惜腾讯不断加强qq的抗木马/病毒能力,又不开放任何api。
后来想到可以用一个独立开源的qq客户端(最初想的是gaim(pidgin)),在接受/发送消息函数后插入函数对内容进行分析。经过搜索,找到了小虾的myqq:
http://xiaoxia.org/home/read.do?id=1222
经过测试可以使用后就决定用它了。

这样做的优点是开发容易(原作者用的是gnu c呢……),缺点是需要单独占用一个qq号,而且随着qq更新,不知道哪一天就会用不了。
-------------------------------------------------

Posted by: bx_bob 2010-05-31, 18:49

2.机器人的结构
一开始各种投骰的函数是直接写在myqq.c中的,后来因为维护麻烦,引入了lua脚本。
再后来因为代码异常混乱,下定决心重写一遍,将更多的功能塞进lua里,就有了现在的第4版。
基本的结构如下
qq客户端宿主(myqq.exe)--lua脚本宿主(lua51.dll,lua5.1.dll)--lua脚本(main.lua……以及很多)
由myqq.exe加载main.lua,并且向这个脚本暴露say_qun(消息内容,群号),say_buddy(消息内容,qq号),to_gb(内容)三个函数。
具体代码如下

r90:myqq.c:699:

CODEBOX
L=lua_open();
luaL_openlibs(L);
luaL_dofile(L,"main.lua");
lua_pushcfunction(L, lua_say_qun);
lua_setglobal(L, "say_qun");
lua_pushcfunction(L, lua_say_buddy);
lua_setglobal(L, "say_buddy");
lua_pushcfunction(L, lua_to_gb_force);
lua_setglobal(L, "to_gb");
而main.lua则起了重要的承接作用,它首先会载入其他的lua文件(都在luascript文件夹下),
CODEBOX
loadfile("luascript\\dnddice.lua")()
loadfile("luascript\\woddice.lua")()
loadfile("luascript\\roll.lua")()
loadfile("luascript\\getlink.lua")()
loadfile("luascript\\dictionary.lua")()
loadfile("luascript\\wiki.lua")()
loadfile("luascript\\knight.lua")()
loadfile("luascript\\godmachine.lua")()
然后通过两个函数将来自myqq.exe的参数传递过去:
CODEBOX
function main(msg,msg_time,buddy_name,buddy_num,qun_name,qun_num)
if msg==nil then return end
getlink(msg,msg_time,buddy_name,buddy_num,qun_name,qun_num)
roll(msg,msg_time,buddy_name,buddy_num,qun_name,qun_num)
dnddice(msg,msg_time,buddy_name,buddy_num,qun_name,qun_num)
woddice(msg,msg_time,buddy_name,buddy_num,qun_name,qun_num)
dictionary(msg,msg_time,buddy_name,buddy_num,qun_name,qun_num)
wiki(msg,msg_time,buddy_name,buddy_num,qun_name,qun_num)
knight(msg,msg_time,buddy_name,buddy_num,qun_name,qun_num)
godmachine(msg,msg_time,buddy_name,buddy_num,qun_name,qun_num)
end

function main_buddy(msg,msg_time,buddy_name,buddy_num)
dnddice(msg,msg_time,buddy_name,buddy_num)
wiki(msg,msg_time,buddy_name,buddy_num)
getlink(msg,msg_time,buddy_name,buddy_num)
dictionary(msg,msg_time,buddy_name,buddy_num)
end
唔,我觉得这已经足够清晰了。
然后,具体的功能都在各自的lua文件里了。

Posted by: bx_bob 2010-05-31, 18:49

3.机器人各功能的实现
这里举一个例子。

r90:roll.lua:

CODEBOX
n=1
function roll(msg,msg_time,buddy_name,buddy_num,qun_name,qun_num)
if string.match(msg, "^%.roll")==nil then return end
math.randomseed(os.time()+n)
math.random()
if n<10000 then n=n+1 end
max=string.match(msg, "^%.roll (%d+)")
if max==nil then return end
if tonumber(max)>10000 then return end
result=msg_time.."\n"..buddy_name.."进行投掷(最大"..max.."点):"..math.random(1,max)
say_qun(result,qun_num)
end

msg里放着一条消息的正文,msg_time是这个消息发出的时间。buddy_name和buddy_num对应发送者的名称和qq号。qun_name和qun_num对应所在的群和群号。
接下来就很容易了,对msg进行正则表达式匹配,并且进行相应的运算。

在这里要重点讲讲随机的问题。lua的随机其实是封装的c的math库里的随机,但是lua的时间却没有封装c的毫秒计时,只有一个以秒为单位的os.time()。这个时候就有一个问题,一般来说,作为随机数种子的都是系统时间,但是以秒为单位的话,可能会出现两人在同一秒内投骰的情况。于是只好加入一个全局变量n,每次投骰之后加一,让随机数种子不一样。
lua的随机还有一个……莫名的问题,就是第一个随出来的数字会有规律。所以这里加了一个math.random()但是没有获取,就是为了跳过第一个随机数。
-------------------------------------------------
-------------------------------------------------
最近更新,开发者注意
-------------------------------------------------
某月某日(忘了)
-------------------------------------------------
在自己编写的新模块开头要记得加上这么一句:
table.insert(main_help_table,".wiki 查询内容 查询维基")
后面引号内的内容就是这个模块的功能介绍。
这是因为新加入了.help功能,提供所有功能的列表。
-------------------------------------------------
6月10日
-------------------------------------------------
引入了luaJIT,据说能提升效率,有兴趣的人重新获取一下新版本吧。
-------------------------------------------------
9月1日
-------------------------------------------------
更新到luaJIT 2.0.0 beta 5!

Posted by: bx_bob 2010-05-31, 18:51

附:
-----------------------------------------
qqdicebot编译指引
首先,你需要一个svn,从svn链接下载最新版本的程序和源代码。在本项目中,一些必须的库和dll文件已经包含在里面了。
获取程序和源代码的命令是(如果你使用的是命令行工具的话)
svn checkout https://qqdicebot.googlecode.com/svn/branches/qqdicebot4_xp
这里可以用http协议代替
如果是gui工具,点checkout然后填入链接即可。
然后,必须得有一个mingw c编译环境。这里我推荐下载codeblocks,这是一个IDE,官方网站上有带了编译环境的版本下载。链接:
http://www.codeblocks.org/downloads/5
选这个:codeblocks-8.02mingw-setup.exe

如果你正常地获得了源代码,应该有一个.cbp文件,用codeblocks打开即可。
接着就可以修改源代码并编译啦。

如果想修改lua脚本部分,用记事本工具打开对应的.lua文件,修改后保存即可。记得重启机器人哦。

-----------------------------------------
qqdicebot运行指引
首先,你需要一个qq号(和它的密码)。在这里,邮箱形式的qq号是不行的,必须得是数字。
然后,打开setting.lua文件,修改里面对应的参数,填入账号密码。
最后运行myqq.exe,最小化并等待一会儿。

-----------------------------------------

Posted by: bcatyan 2010-06-01, 06:21

那个,我们也有个qq的bot,已经用过一段时间了~~

晚上我把做bot的家伙拉过来~~~

http://ddodnd.uueasy.com/read-htm-tid-85.html
这是最早的一个版本,最近那个家伙重新写了一个,有时间你们可以交流一下~

Posted by: SakuraSinojun 2010-06-01, 14:30

-.- 于是奉命前来报到-.-

Posted by: bx_bob 2010-06-01, 18:49

可以先下载一个玩玩?这个贴子没事总会更新一下。
写好的脚本可以以论坛附件的形式上传上来分享。
或者留下意见(我觉得最好能自己动手啦)。

如果想提交代码的话,留下一个google的账号,我会加进google code的开发者。

其实各种开源的聊天软件应该都能用上这个机器人的lua接口,只要把接口写好,嵌入一个luai就行了。这样的话各个机器人之间的脚本也能共享呢。真是一个好想法。

Posted by: SakuraSinojun 2010-06-04, 11:57

命令行QQ,还有lua脚本……真是有爱的东西 O.O
可是一直懒得看lua语法……嘛……希望加个插件DLL。。。

-.-或者需要自己动手?
[email protected]


Posted by: bx_bob 2010-06-06, 09:44

QUOTE(SakuraSinojun @ 2010-06-04, 11:57) *

命令行QQ,还有lua脚本……真是有爱的东西 O.O
可是一直懒得看lua语法……嘛……希望加个插件DLL。。。

-.-或者需要自己动手?
[email protected]

唔,插件dll的话我还不会……不如你添加了之后提交一个吧。不过那样的接口会不会太混乱?
已经把你加入代码提交者了。

Posted by: shin 2010-06-07, 16:03

很好的东西,而且还很适合我这种初学者学习,太感谢了 cool.gif

Posted by: pl02150363 2010-09-07, 08:12

蛮有趣的 一定要学过来

Posted by: 游荡的坎德人 2010-10-18, 22:47

好东西!第一次发现这里有这个分区…… 灰常感谢!
----------------------------------------------------------------------------
我的机器人 http://ellesime.anetcity.com/ellesime/bbs/?topic=32961.0

Posted by: rk920223 2011-02-15, 00:02

话说我觉得lua脚本还是不要总重启机器人比较好……注册小号当机器人……调试几次就要激活一下……

于是试着做了个重读lua的东西(但是没有技术不会测试,不知道有没有造成内存泄漏

Posted by: bx_bob 2011-02-15, 12:11

理论上来说只要把L析构就不会有泄露问题,调用lua_close()估计就行了。

Posted by: rk920223 2011-02-15, 23:48

这样么……感觉不可靠啊……回来找技术帮我试试\("▔□▔)/

Posted by: bx_bob 2011-02-16, 10:49

QUOTE(rk920223 @ 2011-02-15, 23:48) *

这样么……感觉不可靠啊……回来找技术帮我试试\("▔□▔)/
嗯?为何会不可靠?
另外最好的测试方法是自己写一个say_qun()或say_buddy(),然后对lua模块进行单元测试,做好之后再载入。
因为宿主暴露给lua的就只有这两个函数。

Posted by: playerx 2011-04-16, 19:32

非常好用 我专门用它在2个群之间转发消息
唯一担心的是myqq 挂了。

Posted by: bx_bob 2011-04-16, 19:47

快挂了……

Posted by: playerx 2011-04-25, 08:47

采用2010的协议
http://code.google.com/p/libqq-pidgin/
替换pidgin原libqq.dll 可以正常工作
可以做下一个替补

Posted by: bx_bob 2011-05-02, 22:17

更新到2011协议
感谢myqq原作者小虾
顶楼链接有下载。

Posted by: hlxf19870330 2011-09-16, 17:55

弱弱问个问题,咱跑这个代码的时候,lua_pcall()这个函数的返回值一直是2,,,
是什么个原因呢,该怎么解决呢,,
咱木有学过Lua,不知道是不是平台啊还是什么其他的相关性问题。。
ps,用的是xp sp3系统,编译的是myqq_xp.c这个文件,,

Posted by: bx_bob 2011-09-19, 18:46

QUOTE(hlxf19870330 @ 2011-09-16, 17:55) *

弱弱问个问题,咱跑这个代码的时候,lua_pcall()这个函数的返回值一直是2,,,
是什么个原因呢,该怎么解决呢,,
咱木有学过Lua,不知道是不是平台啊还是什么其他的相关性问题。。
ps,用的是xp sp3系统,编译的是myqq_xp.c这个文件,,

lua_pcall()返回2的话,可以从栈顶获取那个错误,但是xp版本从栈顶弹出错误的地方总崩溃,所以被我屏蔽掉了。
不过让我猜的话,应该是settings.lua里面的设置啥的有问题?

Posted by: hlxf19870330 2011-10-10, 17:16

QUOTE(bx_bob @ 2011-09-19, 18:46) *

lua_pcall()返回2的话,可以从栈顶获取那个错误,但是xp版本从栈顶弹出错误的地方总崩溃,所以被我屏蔽掉了。
不过让我猜的话,应该是settings.lua里面的设置啥的有问题?

嗯,,调试通了,谢谢指点啊
问题出在main.lua里,有一行require“TAKL” ,,但是luascript目录下木有这个文件,导致main.lua载入不成功
注掉就OK了,

Posted by: copyman 2012-04-05, 05:21

翻译的网址是不是改变了?

Posted by: Linnena 2012-07-05, 20:03

请教一下为什么这个机器人在有的群能用有的群不能使用呢?我加到公会群使用一切正常,后来我又创建了一个小跑团群想和朋友们私下玩玩,但是投骰一直没有作用,还需要去别的群roll,应该怎么设置啊?

Posted by: bx_bob 2012-07-06, 00:22

QUOTE(Linnena @ 2012-07-05, 20:03) *

请教一下为什么这个机器人在有的群能用有的群不能使用呢?我加到公会群使用一切正常,后来我又创建了一个小跑团群想和朋友们私下玩玩,但是投骰一直没有作用,还需要去别的群roll,应该怎么设置啊?
qq某些群的群号之大,内部值已经超过int的极限,只能用uint才能容纳了。但是,lua 5.1未支持uint格式。

Posted by: zephyro 2012-09-26, 00:00

在myqq里实验了一下,很多群的id变成了负数,应该就是溢出了。内部群号没太怎么看是如何拿到的,正常的群号我是没有超过21亿的还。
顺便搂了一眼qun.c,里面qun_searcher,member_searcher,qun_ext_searcher三个方法里的强转应该是(uint) v吧,根据群号的定义是uint,似乎不应该强转成int的样子。

Posted by: bx_bob 2012-09-26, 12:11

和myqq本身没什么关系,lua换成luajit-2.0之后暂时解决了。

Posted by: silencecat 2013-03-16, 22:22

那个……google code上面那个最新版本我下载编译之后报错,怎么破?是不是我漏做了什么事?

↑好吧,我找到问题了,不过接收不到群的信息的问题还是存在,有的时候是只收到几条消息后就一直这样显示:

13:12:11<群名字>[16777216]

后面什么消息都没有,重要的是这个16777216,不管来自什么群的消息后面跟的都是这个数字。非常诡异- -

Posted by: bx_bob 2013-03-17, 12:28

那个版本的已经弃置了,因为腾讯果然换了协议,这个版里有个我新开的webqqdicebot……你找找吧,我放在github上的。

Posted by: silencecat 2013-03-17, 13:01

发现大坑…………好吧,我来试试看……厄,能告诉我这个web版的应该用什么编译?怎么用来着?

Posted by: bx_bob 2013-03-18, 20:22

Cmake配置,gcc编译

Posted by: kcirtap 2013-04-04, 15:01

bx_bob, webqqdicebot 怎样使用? 得下载平台?

我使用qqdicebot4.4时,对单人可以roll出结果,但是加入群中时却没有接收和输出。

求帮助!

谢谢!

Posted by: bx_bob 2013-04-04, 19:15

QUOTE(kcirtap @ 2013-04-04, 15:01) *

bx_bob, webqqdicebot 怎样使用? 得下载平台?

我使用qqdicebot4.4时,对单人可以roll出结果,但是加入群中时却没有接收和输出。

求帮助!

谢谢!

见前文,qqdicebot4.4已经被tencent关掉协议。

Posted by: aurora666 2013-04-10, 18:12

请问开发者大人,myqq是不是现在用不了了?那个插件对于我们非常、非常有用,所以,非常感谢。
另外请问各位,还有没有什么可以在QQ群使用的可替代的投骰机器人?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)