| 赞 | 0 |
| VIP | |
| 好人卡 | |
| 积分 | 7 |
| 经验 | |
| 最后登录 | 2021-10-29 |
| 在线时间 | 2184 小时 |
- 梦石
- 0
- 星屑
- 672
- 在线时间
- 2184 小时
- 注册时间
- 2009-12-6
- 回帖
- 571

|
发表于 2015-2-22 18:08:58
|
显示全部楼层
本帖最后由 ML4455739 于 2015-2-23 13:47 编辑
楼下已经给出了一套完善的方案,所以敬请无视此楼……
[fold=请无视]
发一下可能有用的东西,个人整理,不代表楼主的观点。
相信不少人都看过这个脚本,wininet。
[pre lang="ruby"]# てつ
class Get_Version_Info
AGENT = "RGSS PLAYER"
INTERNET_OPEN_TYPE_PRECONFIG = 0
INTERNET_OPEN_TYPE_DIRECT = 1
def Get_Version_Info.InternetOpen()
io = Win32API.new('wininet', 'InternetOpen', %(p, l, p, p, l), 'l')
hInternet = io.call(AGENT, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0)
return hInternet
end
def Get_Version_Info.InternetOpenUrl(hSession, url)
iou = Win32API.new('wininet', 'InternetOpenUrl', %(l, p, p, l, l, l), 'l')
hService = iou.call(hSession, url, nil, 0, 0, 0)
return hService
end
def Get_Version_Info.InternetReadFile(hService)
content = ""
read_size = 1024
irf = Win32API.new('wininet', 'InternetReadFile', %(l, p, i, p), 'i')
while(true)
buf = "\0" * read_size
red = [0].pack('L')
irf.call( hService, buf, read_size, red )
if(red.unpack('L') == [0])
break
end
buf.delete!("\0")
content += buf
end
return content
end
HTTP_QUERY_STATUS_CODE = 19
def Get_Version_Info.HttpQueryInfo(hService)
read_size = 1024
buf = "\0" * read_size
red = [read_size-1].pack('L')
hqi = Win32API.new('wininet', 'HttpQueryInfo', %(l, l, p, p, p), 'i')
isOk = hqi.call( hService, HTTP_QUERY_STATUS_CODE, buf, red, nil)
buf.delete!("\0")
return buf
end
def Get_Version_Info.InternetCloseHandle(hInternet)
ich = Win32API.new('winInet', 'InternetCloseHandle', %(l), 'i')
isOk = ich.call(hInternet)
return isOk
end
HTTP_CODE_OK = "200"
def Get_Version_Info.get_version(url)
version = nil
begin
hInternet = InternetOpen()
if(hInternet != 0)
hService = InternetOpenUrl(hInternet, url)
if(hService != 0)
status_code = HttpQueryInfo(hService)
if(status_code == HTTP_CODE_OK)
version = InternetReadFile(hService)
end
InternetCloseHandle(hService)
end
InternetCloseHandle(hInternet)
end
rescue
return nil
end
return version
end
end[/pre]
虽然来路不太明确还是贴一下,不过用不上就是啦。
上面这个脚本能够实现RM获取一个指定地址的文本内容,严格上说是html代码,
如Get_Version_Info.get_version("http://www.baidu.com/")
这个脚本的问题就是,它会导致游戏进程阻塞,尤其容易在网络环境不佳时发生,
默认情况下,如果游戏超过10s没有调用一次Graphics.update方法,
就会弹出“脚本已备份”然后退出游戏,即使利用脚本根除10s问题,
长时间画面卡顿的等待,也是非常糟糕的体验。
楼主此帖的意义就在于,把访问网络的工作交给一个外部可执行程序去办,
而且楼主已经把这个程序提供给我们了,真的非常方便。
好了,废话到此为止。
1. 如何启动楼主提供的外部exe程序
[pre lang="ruby"]a = Win32API.new("shell32","ShellExecute","lppppl","l")
a.call(0,0,"RMHttpDelegate.exe","#{$$}",0,0)[/pre]
"RMHttpDelegate.exe"为楼主所提供的外部可执行程序的路径和文件名
$$是获取Game.exe的进程PID的,在任务管理器中可以找到,此外,
因为要把PID这个参数传给楼主的外部程序,这个需要把变量转换成字符串
用$$.to_s也行吧,不再赘述,总之这两行脚本就是启动楼主的程序了,
就如楼主所说,占用内存很小很小,所以游戏一开始就打开也没什么。
2. 如何获取临时文件夹路径,摘自这里,直接使用ENV['temp']应该也没问题
楼主的外部程序是通过Temp文件夹中的一个文件实现与RM游戏的通讯的
[pre lang="ruby"]get_temp_path = Win32API.new('kernel32', 'GetTempPath', 'lp', 'l')
temp_path = ' ' * 256
get_temp_path.call(256, temp_path)
temper = temp_path.strip
temper = temper.split("Temp")
temper = temper[0].gsub!("\\"){"/"}
temper += "Temp/"
# p temper
[/pre]
temper就是绝对路径了,我这台电脑测试时返回的是
"C:/Users/ADMINI~1/AppData/Local/Temp/"
直接使用ENV['temp']的话,返回的是这样
"C:\\Users\\ADMINI~1\\AppData\\Local\\Temp"
3. 如何通过文件实现游戏对外部程序的通讯
[pre lang="ruby"]f = open(temper + "RM_HTTP_REQUEST_#{$$}","w")
f.write("www.server.com\nlist.php\nPOST\nname=player&result=100&rand=#{rand(1000)}")
f.close
[/pre]
蛮普通的写法,总之文件的内容至少三行,POST方法传参数自然是四行- www.server.com
- list.php
- POST
- name=player&result=100
复制代码 就像这样。换行是通过\n来控制的。
我是在测试网络排行榜,所以这里是使用了POST方法向服务器上的list.php传递了
name和result两个参数,rand是用来防止缓存的,别在意啦
总之要实现对外部程序的控制,就是利用那三行脚本,向RM_HTTP_REQUEST_XXXX这个文件
写入所需要的四行文字
4. 如何通过文件实现外部程序对游戏的通讯
游戏需要知道外部程序把工作完成的怎么样了
[pre lang="ruby"]sleep(1)
# sleep是等待1秒,不要也行吧,楼主的程序每秒都会读取一次文件内容
g = File.open(temper + "RM_HTTP_RESULT_#{$$}","r").read rescue nil
g = g.to_s
#g.gsub!(/0/) {}
#g.gsub!(/\r\n/) {}
if g.include?("Success")
print "成功"
elsif g.include?("Failure")
print "失败"
else
print "未知错误"
end[/pre]
由我们的游戏这边向RM_HTTP_REQUEST_XXXX这一文件中写入指令,
外部程序读取并执行后,会在Temp目录中生成一个RM_HTTP_RESULT_XXXX文件,
该文件的内容为Success或Failure,意味成功和失败,
我们的游戏通过对其的判断,知道外部程序的工作是否完成。
5. 获取目标网页的内容
这一点就和最上方的那个脚本一样了,因此完全可以用来替代那个脚本,
在获取成功的情况下,除RM_HTTP_RESULT_XXXX文件外,
还会生成另一个RM_HTTP_CONTENT_XXXX文件,内容为获取到的数据- con = Get_Version_Info.get_version("http://www.baidu.com/")
- p con
复制代码 这个是最上面那个脚本的方法,而对于楼主提供的工程- con = File.open(temper + "RM_HTTP_CONTENT_#{$}","r").read rescue nil
- p con
复制代码 这样就好了。
6. 附带一个用浏览器打开指定地址的API
[pre lang="ruby"]
v = "http://www.baidu.com/"
Win32API.new('shell32.dll','ShellExecuteA',%w(p p p p p i),'i').call(0, 'open', v ,0, 0, 1)
[/pre]
如果是排行榜的话,刚才的工作已经把玩家player得到100分的情况告知了服务器,
只要打开排行榜网页,把排行信息给玩家们看就好了。
关于排行榜网页本身,可以进一步学习PHP语言,如果有人实在需要的话还请楼主补充一下,
因为本人的水平拙劣,代码风格奇特,恐不符大众口味,还望见谅。
楼主所提供的这个功能并不只是适用于POST方法的传递成绩,总之就是获取某网页的文本内容,
至于有什么用的话,比如获取网络时间,还可使用GET方法实现从服务器上获取最新版本号,等等…
虽然本楼最开始的脚本就能做到,但楼主的方法最大的优势就在于,非阻塞,异步执行,不卡顿。
关于该外部可执行程序的安全性问题,我无权给予评价,
反正已经经过此人肉鸡实测和毫无生命特征的360安全卫士V10.0.0.2001的扫描了。
有强迫症的朋友也不必担心,外部程序会随着Game.exe的退出而退出,
退出时还会自动删除相关的文件,保证干净利落。
希望更多的人用到这个东西。
V0.3追加的直接文件下载功能:
[pre lang="ruby"]a = Win32API.new("shell32","ShellExecute","lppppl","l")
a.call(0,0,"RMHttpDelegate.exe","https://rpg.blue/template/co_ilite/image/logo.png","logo.png",0,0)[/pre]
V0.3的这个外部程序是可以运行多个的,所以通过开启新程序下载文件,
传递的参数中不需要PID,但必须文件的下载路径,以及保存到本地的文件名,注意需要后缀名。
上例为下载66RPG的Logo,并以logo.png的文件名下载到本地,注意路径中的斜杠。
[/fold]
楼下已经给出了一套完善的方案,所以敬请无视此楼…… |
评分
-
查看全部评分
|