设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 3136|回复: 0
打印 上一主题 下一主题

[原创发布] 【不是创意的创意】解决调用环境变量中文乱码现象

[复制链接]

Lv3.寻梦者 (暗夜天使)

精灵族の天使

梦石
0
星屑
1697
在线时间
3038 小时
注册时间
2007-3-16
帖子
33731

开拓者贵宾

跳转到指定楼层
1
发表于 2014-10-11 15:18:21 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
本帖最后由 精灵使者 于 2015-2-1 17:44 编辑

精灵在汉化游戏的时候,发现一些使用中文用户名的游戏无法启动,症状如下:

经检查出问题的脚本如下:
RUBY 代码复制
  1. # Create Path Where Folder Should Be Created
  2.   path = " " * 256
  3.   path = ENV['AV_APPDATA'].rstrip
  4.   $appPath = path.to_s + "\\To the Moon - Freebird Games"   
  5.  
  6.   # Create Your Folder
  7.   if !File.exists?($appPath)  
  8.     Dir.mkdir($appPath) #出问题的那行
  9.   end

于是就麻烦了。
中文用户名导致EV['AV_APPDATA']产生乱码,以至于后面的建立文件夹失败。
所以就需要进行S2U转换一下。
解决脚本如下:
RUBY 代码复制
  1. #Using for Non-english speaking words encoding conversion
  2.   #quintess non-english paths
  3.   APPNAME = "\\To the Moon - Freebird Games"
  4. module Seiran20
  5.   module_function
  6.   class ::Integer; def to_ptr; self; end; def to_param; 'i'; end; def ord; self; end; end
  7.   class ::String;def to_ptr; [self].pack('p').unpack('L').first; end; def to_param; 'p'; end; end
  8.  
  9.   def procname(a, b)
  10.     class << a; self; end.send :define_method, :inspect do b end
  11.     a
  12.   end
  13.  
  14.   def api(dll,func)
  15.     procname lambda{|*args|
  16.        Win32API.new(dll,func,args.map{|x|x.to_param}, 'i').call *args
  17.     }, "Seiran20.api<#{dll}!#{func}>"
  18.   end
  19.  
  20.   LL = api("kernel32", "LoadLibrary")
  21.   GPA = api("kernel32", "GetProcAddress")
  22.   def funcaddr(dll, func)
  23.      x = GPA.call(LL.call(dll), func)
  24.      x == 0 ? nil : x
  25.   end
  26.   def capi(dll, func)
  27.      callproc(GPA.call(LL.call(dll), func))
  28.       procname lambda{|*args|apicall.call((code=[0x55,0xe589].pack('CS')+args.map{|x| [0x68, x.to_ptr].pack('CL')}.reverse.join+[0xb8, addr.to_ptr, 0xD0FF, 0xc481, (stdcall ? 0 : args.length*4) , 0x10c2c9].pack('CLSSLL')),0,0,0,0)}, "Seiran20.capi<#{dll}!#{func}>"
  29.   end
  30.  
  31.     def to_wc(str, cp = 65001)
  32.     (buf = "\0\0"*str.length)[0, 2*api('Kernel32', 'MultiByteToWideChar').call(cp, 0, str.to_ptr, -1, buf, buf.length)]
  33.   end
  34.  
  35.   def to_mb(str, cp = 65001)
  36.     (buf = "\0\0"* str.length)[0, api('Kernel32', 'WideCharToMultiByte').call(cp, 0, str.to_ptr, -1, buf, buf.length, 0, 0)]
  37.   end
  38.  
  39. end
  40. # Create Path Where Folder Should Be Created (edited)
  41. #  path = " " * 256
  42. #  path = ENV['AV_APPDATA'].rstrip
  43. path = Seiran20.to_mb(Seiran20.to_wc(ENV['AV_APPDATA']+"\0", 0)+"\0\0").sub(/\0+$/, "")
  44. $appPath = path.to_s + APPNAME   
  45.  
  46. # redef File.exist for #72 Error
  47. def File.exists?(f)
  48.   ((open("#{f}\\nul", "rb").close || true) rescue false) ||
  49.   ((open(f, "rb").close || true) rescue false)
  50. end
  51.  
  52.   # Create Your Folder
  53.   if !File.exists?($appPath)  
  54.     Dir.mkdir($appPath)
  55.   end

由于是商业脚本所以考虑到没有权限修改,所以在此备份。
这是个严重的问题。
上面那个脚本依然出错的原因是,中文路径不支持File.exists
于是精灵就采用更改路径到公共路径下的方式来做,而各自的用户名将会被转换成数字分开。
RUBY 代码复制
  1. # Create Path Where Folder Should Be Created(edited)
  2.   $commonpath = ENV['CommonProgramfiles'] + "\\To the Moon - Freebird Games"
  3.   $filename = " " * 36
  4.   $filename = (ENV['USERNAME'].rstrip).unpack("H*")[0].to_i(16).to_s(36)
  5.   $appPath = $commonpath + "\\" + $filename
  6.  
  7.   # Create Your Folder
  8.   if !File.exists?($commonpath)  
  9.     Dir.mkdir($commonpath)
  10.   end
  11.  
  12.   if !File.exists?($appPath)  
  13.     Dir.mkdir($appPath)
  14.   end
  15.  
  16.   save_file_a = $appPath
  17.   music_file = $appPath + "\\" + "music.txt"
  18.   window_file = $appPath + "\\" + "window.txt"
  19.   user_name_file = $appPath + "\\" "user_name.txt" #make a mark of username

这是另外一种方案,但是会和以前的英文版路径不兼容。这个问题解决有些麻烦。
所以使用注册表修改av_data这个也是个好办法,就是直接修改变量。这样不会影响到用户名的绝大多数玩家。
2015年2月1日更新:
精灵已经完成了插件脚本方式,不需要对原始的脚本做任何修改就可以兼容中文!
使用方法新建文档插入即可。
脚本如下:
RUBY 代码复制
  1. #==============================================================================
  2. # ** Rewrite function on Dir and File (edited by fay_envoy)
  3. #------------------------------------------------------------------------------
  4. #  rewrite this code for solve the problem of non-English character problem.
  5. #  some function only using for the game commercial scripts.
  6. #==============================================================================
  7.   #--------------------------------------------------------------------------
  8.   # * Function needed
  9.   #--------------------------------------------------------------------------
  10. module Seiran20
  11.   module_function
  12.   class ::Integer; def to_ptr; self; end; def to_param; 'i'; end; def ord; self; end; end
  13.   class ::String;def to_ptr; [self].pack('p').unpack('L').first; end; def to_param; 'p'; end; end
  14.  
  15.   def procname(a, b)
  16.     class << a; self; end.send :define_method, :inspect do b end
  17.     a
  18.   end
  19.  
  20.   def api(dll,func)
  21.     procname lambda{|*args|
  22.        Win32API.new(dll,func,args.map{|x|x.to_param}, 'i').call *args
  23.     }, "Seiran20.api<#{dll}!#{func}>"
  24.   end
  25.  
  26.   LL = api("kernel32", "LoadLibrary")
  27.   GPA = api("kernel32", "GetProcAddress")
  28.   def funcaddr(dll, func)
  29.      x = GPA.call(LL.call(dll), func)
  30.      x == 0 ? nil : x
  31.   end
  32.   def capi(dll, func)
  33.      callproc(GPA.call(LL.call(dll), func))
  34.       procname lambda{|*args|apicall.call((code=[0x55,0xe589].pack('CS')+args.map{|x| [0x68, x.to_ptr].pack('CL')}.reverse.join+[0xb8, addr.to_ptr, 0xD0FF, 0xc481, (stdcall ? 0 : args.length*4) , 0x10c2c9].pack('CLSSLL')),0,0,0,0)}, "Seiran20.capi<#{dll}!#{func}>"
  35.   end
  36.  
  37.     def to_wc(str, cp = 65001)
  38.     (buf = "\0\0"*str.length)[0, 2*api('Kernel32', 'MultiByteToWideChar').call(cp, 0, str.to_ptr, -1, buf, buf.length)]
  39.   end
  40.  
  41.   def to_mb(str, cp = 65001)
  42.     (buf = "\0\0"* str.length)[0, api('Kernel32', 'WideCharToMultiByte').call(cp, 0, str.to_ptr, -1, buf, buf.length, 0, 0)]
  43.   end
  44.   def transcode(str)
  45.   return to_mb(to_wc(str +"\0", 0)+"\0\0").sub(/\0+$/, "")
  46. end
  47. end
  48. PathFileExists = Win32API.new("shlwapi", "PathFileExistsW", "P", "I")
  49. MultiByteToWideChar = Win32API.new("kernel32", "MultiByteToWideChar", "ILPIPI", "I")
  50.   #--------------------------------------------------------------------------
  51.   # * File.exists rewrite
  52.   #--------------------------------------------------------------------------
  53. def File.exists?(filename)
  54.   nfilename = Seiran20.transcode(filename) + "\0"
  55.   len = MultiByteToWideChar.call(65001, 0, nfilename, -1, 0, 0) << 1
  56.   buf = " " * len
  57.   MultiByteToWideChar.call(65001, 0, nfilename, -1, buf, len)
  58.   return PathFileExists.call(buf) == 0 ? false : true
  59.   end
  60.   #--------------------------------------------------------------------------
  61.   # * FileTest.exist rewrite
  62.   #--------------------------------------------------------------------------
  63. def FileTest.exist?(filename)
  64.   return File.exists?(filename)
  65. end
  66.   #--------------------------------------------------------------------------
  67.   # * Dir function rewrite (only needed)
  68.   #--------------------------------------------------------------------------
  69. class << Dir
  70.    alias_method :old_mkdir, :mkdir
  71.    def mkdir(*args,&block)
  72.     args[0] = Seiran20.transcode(args[0])
  73.     old_mkdir(*args,&block)
  74.    end
  75. end
  76.   #--------------------------------------------------------------------------
  77.   # * File.new and open rewrite
  78.   #--------------------------------------------------------------------------
  79. class << File
  80.    alias_method :old_new, :new
  81.    alias_method :old_open, :open
  82.    def new(*args,&block)
  83.     args[0] = Seiran20.transcode(args[0])
  84.     old_new(*args,&block)
  85.    end
  86.    def open(*args,&block)
  87.     args[0] = Seiran20.transcode(args[0])
  88.     old_open(*args,&block)
  89.    end
  90. end
  91.   #--------------------------------------------------------------------------
  92.   # * open rewrite( for commercial scripts)
  93.   #--------------------------------------------------------------------------
  94.   alias old_open open
  95.   def open(*args,&block)
  96.     args[0] = Seiran20.transcode(args[0])
  97.     old_open(*args,&block)
  98.   end
您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-4-29 15:13

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表