Project1

标题: 如何防作弊?防存档修改? [打印本页]

作者: 望月神绮    时间: 2016-6-21 14:55
标题: 如何防作弊?防存档修改?
如题……游戏发出去之后想要在一定程度上防止他人对游戏存档进行修改,起码不让人那么容易的作弊……有脚本或什么办法能实现吗?
作者: kuerlulu    时间: 2016-6-21 18:04
本帖最后由 kuerlulu 于 2016-6-22 12:25 编辑

作弊基本是没法避免的, 你听说过内存注入吗
关于存档方法有很多, 比如自己定义存档数据的加密解密算法什么的
不过,
你这个游戏值得玩家去作弊, 修改存档吗
---- 6月22日更新 ----
补一张图hh

https://knewone.com/entries/566e751a102b537cf5000701
作者: 望月神绮    时间: 2016-6-21 18:22
kuerlulu 发表于 2016-6-21 18:04
作弊基本是没法避免的, 你听说过内存注入吗
关于存档方法有很多, 比如自己定义存档数据的加密解密算法什么 ...

人们为什么要互相伤害呢……
作者: 洛克人SZ    时间: 2016-6-21 19:01
存档修改是很难防御的,所以,与其消耗精力去搞反修改,还不如去专心搞好游戏……
作者: yang1zhi    时间: 2016-6-21 21:58
进入游戏后弹出选择(普通版)(完美存档版)(一键通关版)
作者: 英顺的马甲    时间: 2016-6-21 22:12
本帖最后由 英顺的马甲 于 2016-6-21 22:26 编辑

一般上只有两种玩家会想要作弊
1. 只想看剧情,因此以作弊加快游戏进度
2. 爱炫耀但没能力通关的玩家

第一种人的出现证明了游戏剧情的优秀,而第二种人稍微防一防就能去掉大半,毕竟有能力的人还需要作弊?
至于那些防不住的,就让他们带着羞耻心去玩游戏吧

p/s:个人认为玩游戏纯粹图个开心,怎么玩是玩家的事,而游戏开发者只要开发出好游戏就行了,而作弊的玩家自然有作弊玩家如果安安分分的玩个开心就算了那没什么,但如果遇到作弊了还到处炫耀的熊孩子玩家,你跟熊孩子计较不久中计了么?一款游戏的精髓到底是游戏本身还是游戏加密这点不能本末倒置,如果说作弊破坏了游戏的精髓,那么作弊玩家正是那种体验不到游戏精髓的悲哀玩家。

注:以上言论不适于用在网游,单机再怎么折腾都不会影响他人,但联机作弊就会影响游戏的公平性,因此需要大幅度提防
作者: 七重    时间: 2016-6-21 22:37
假如是我自己的话

对制作精美的游戏也会抱有敬意,会认真地体验完。

说到玩游戏习惯修改的人,本身就是已经不是服务范围之中了呢
作者: 望月神绮    时间: 2016-6-22 00:04
英顺的马甲 发表于 2016-6-21 22:12
一般上只有两种玩家会想要作弊
1. 只想看剧情,因此以作弊加快游戏进度
2. 爱炫耀但没能力通关的玩家

RyanBern大大说了我的心理话QAQ
跪求帮忙,只是稍微防一防。
作者: 英顺的马甲    时间: 2016-6-22 00:58
本帖最后由 英顺的马甲 于 2016-6-22 01:04 编辑
望月神绮 发表于 2016-6-22 00:04
RyanBern大大说了我的心理话QAQ
跪求帮忙,只是稍微防一防。


RM的存档修改的方法不外乎就那几个,也就是说只要在存档上随便做点小手脚基本上就GG了
比如说这样:
RUBY 代码复制
  1. unless $ORIGINAL_SCENE_SAVE
  2.   $ORIGINAL_SCENE_SAVE = Scene_Save.clone
  3.   $ORIGINAL_SCENE_LOAD = Scene_Load.clone
  4.   $ORIGINAL_WINDOW_SAVEFILE = Window_SaveFile.clone
  5. end
  6. class Scene_Save < $ORIGINAL_SCENE_SAVE
  7.   def on_decision(filename)
  8.     super(filename)
  9.     buffer = ""
  10.     File.open(filename, "rb"){|f|buffer = Zlib::Deflate.deflate(f.read)}
  11.     File.open(filename, "wb"){|f|f.write [Zlib.crc32(buffer), buffer].pack("La*")}
  12.   end
  13. end
  14. class Scene_Load < $ORIGINAL_SCENE_LOAD
  15.   def on_decision(filename)
  16.     crc = 0; buffer = ""
  17.     File.open(filename, "rb"){|f|crc, buffer = f.read.unpack("La*")}
  18.     File.open(filename, "wb"){|f|f.write Zlib::Inflate.inflate(buffer)} if crc == Zlib.crc32(buffer)
  19.     super(filename)
  20.   end
  21. end
  22. class Window_SaveFile < $ORIGINAL_WINDOW_SAVEFILE
  23.   def initialize(index, filename)
  24.     @file_exist = FileTest.exist?(filename)
  25.     if @file_exist
  26.       File.open(filename, "rb"){|f|@crc, @buffer = f.read.unpack("La*")}
  27.       File.open(filename, "wb"){|f|f.write Zlib::Inflate.inflate(@buffer)}
  28.     end
  29.     super(index, filename)
  30.     if @file_exist
  31.       File.open(filename, "wb"){|f|f.write [@crc, @buffer].pack("La*")}
  32.     end
  33.   end
  34. end
但这只是最简单的手脚,稍微厉害一些的人还没打开脚本就看破了

还有个方法就是利用真假存档掩护,假存档光明正大的摆在那让人改,但是每次读取时读取的都是藏在别处的真存档
作者: 望月神绮    时间: 2016-6-24 12:21
@RyanBern ,给我扣分,给马甲发卡吧。
差不多明白怎么做了。
作者: 望月神绮    时间: 2016-6-24 13:40
英顺的马甲 发表于 2016-6-22 00:58
RM的存档修改的方法不外乎就那几个,也就是说只要在存档上随便做点小手脚基本上就GG了
比如说这样:
unle ...

存档文件代码如下
  1. #==============================================================================
  2. # ■ Scene_File
  3. #------------------------------------------------------------------------------
  4. #  存档画面及读档画面的超级类。
  5. #==============================================================================

  6. class Scene_File
  7.   #--------------------------------------------------------------------------
  8.   # ● 初始化对像
  9.   #     help_text : 帮助窗口显示的字符串
  10.   #--------------------------------------------------------------------------
  11.   def initialize(help_text)
  12.     @help_text = help_text
  13.   end
  14.   #--------------------------------------------------------------------------
  15.   # ● 主处理
  16.   #--------------------------------------------------------------------------
  17.   def main
  18.     # 生成帮助窗口
  19.     @help_window = Window_Help.new
  20.     @help_window.set_text(@help_text)
  21.     # 生成存档文件窗口
  22.     @savefile_windows = []
  23.     for i in 0..3
  24.       @savefile_windows.push(Window_SaveFile.new(i, make_filename(i)))
  25.     end
  26.     # 选择最后操作的文件
  27.     @file_index = $game_temp.last_file_index
  28.     @savefile_windows[@file_index].selected = true
  29.     # 执行过渡
  30.     Graphics.transition
  31.     # 主循环
  32.     loop do
  33.       # 刷新游戏画面
  34.       Graphics.update
  35.       # 刷新输入信息
  36.       Input.update
  37.       # 刷新画面
  38.       update
  39.       # 如果画面被切换的话就中断循环
  40.       if $scene != self
  41.         break
  42.       end
  43.     end
  44.     # 准备过渡
  45.     Graphics.freeze
  46.     # 释放窗口
  47.     @help_window.dispose
  48.     for i in @savefile_windows
  49.       i.dispose
  50.     end
  51.   end
  52.   #--------------------------------------------------------------------------
  53.   # ● 刷新画面
  54.   #--------------------------------------------------------------------------
  55.   def update
  56.     # 刷新窗口
  57.     @help_window.update
  58.     for i in @savefile_windows
  59.       i.update
  60.     end
  61.     # 按下 C 键的情况下
  62.     if Input.trigger?(Input::C)
  63.       # 调用过程 on_decision (定义继承目标)
  64.       on_decision(make_filename(@file_index))
  65.       $game_temp.last_file_index = @file_index
  66.       return
  67.     end
  68.     # 按下 B 键的情况下
  69.     if Input.trigger?(Input::B)
  70.       # 调用过程 on_cancel (定义继承目标)
  71.       on_cancel
  72.       return
  73.     end
  74.     # 按下方向键下的情况下
  75.     if Input.repeat?(Input::DOWN)
  76.       # 方向键下的按下状态不是重复的情况下、
  77.       # 并且光标的位置在 3 以前的情况下
  78.       if Input.trigger?(Input::DOWN) or @file_index < 3
  79.         # 演奏光标 SE
  80.         $game_system.se_play($data_system.cursor_se)
  81.         # 光标向下移动
  82.         @savefile_windows[@file_index].selected = false
  83.         @file_index = (@file_index + 1) % 4
  84.         @savefile_windows[@file_index].selected = true
  85.         return
  86.       end
  87.     end
  88.     # 按下方向键上的情况下
  89.     if Input.repeat?(Input::UP)
  90.       # 方向键上的按下状态不是重复的情况下、
  91.       # 并且光标的位置在 0 以后的情况下
  92.       if Input.trigger?(Input::UP) or @file_index > 0
  93.         # 演奏光标 SE
  94.         $game_system.se_play($data_system.cursor_se)
  95.         # 光标向上移动
  96.         @savefile_windows[@file_index].selected = false
  97.         @file_index = (@file_index + 3) % 4
  98.         @savefile_windows[@file_index].selected = true
  99.         return
  100.       end
  101.     end
  102.   end
  103.   #--------------------------------------------------------------------------
  104.   # ● 生成文件名
  105.   #     file_index : 文件名的索引 (0~3)
  106.   #--------------------------------------------------------------------------
  107.   def make_filename(file_index)
  108.     return "Save#{file_index + 1}.rxdata"
  109.   end
  110. end
复制代码
存档脚本如下
  1. #==============================================================================
  2. # ■ Scene_Save
  3. #------------------------------------------------------------------------------
  4. #  处理存档画面的类。
  5. #==============================================================================

  6. class Scene_Save < Scene_File
  7.   #--------------------------------------------------------------------------
  8.   # ● 初始化对像
  9.   #--------------------------------------------------------------------------
  10.   def initialize
  11.     super("要保存到这个文件吗?")
  12.   end
  13.   #--------------------------------------------------------------------------
  14.   # ● 确定时的处理
  15.   #--------------------------------------------------------------------------
  16.   def on_decision(filename)
  17.     # 演奏存档 SE
  18.     $game_system.se_play($data_system.save_se)
  19.     # 写入存档数据
  20.     file = File.open(filename, "wb")
  21.     write_save_data(file)
  22.     file.close
  23.     # 如果被事件调用
  24.     if $game_temp.save_calling
  25.       # 清除存档调用标志
  26.       $game_temp.save_calling = false
  27.       # 切换到地图画面
  28.       $scene = Scene_Map.new
  29.       return
  30.     end
  31.     # 切换到菜单画面
  32.     $scene = Scene_Menu.new(4)
  33.   end
  34.   #--------------------------------------------------------------------------
  35.   # ● 取消时的处理
  36.   #--------------------------------------------------------------------------
  37.   def on_cancel
  38.     # 演奏取消 SE
  39.     $game_system.se_play($data_system.cancel_se)
  40.     # 如果被事件调用
  41.     if $game_temp.save_calling
  42.       # 清除存档调用标志
  43.       $game_temp.save_calling = false
  44.       # 切换到地图画面
  45.       $scene = Scene_Map.new
  46.       return
  47.     end
  48.     # 切换到菜单画面
  49.     $scene = Scene_Menu.new(4)
  50.   end
  51.   #--------------------------------------------------------------------------
  52.   # ● 写入存档数据
  53.   #     file : 写入用文件对像 (已经打开)
  54.   #--------------------------------------------------------------------------
  55.   def write_save_data(file)
  56.     # 生成描绘存档文件用的角色图形
  57.     characters = []
  58.     for i in 0...$game_party.actors.size
  59.       actor = $game_party.actors[i]
  60.       characters.push([actor.character_name, actor.character_hue])
  61.     end
  62.     # 写入描绘存档文件用的角色数据
  63.     Marshal.dump(characters, file)
  64.     # 写入测量游戏时间用画面计数
  65.     Marshal.dump(Graphics.frame_count, file)
  66.     # 增加 1 次存档次数
  67.     $game_system.save_count += 1
  68.     # 保存魔法编号
  69.     # (将编辑器保存的值以随机值替换)
  70.     $game_system.magic_number = $data_system.magic_number
  71.     # 写入各种游戏对像
  72.     Marshal.dump($game_system, file)
  73.     Marshal.dump($game_switches, file)
  74.     Marshal.dump($game_variables, file)
  75.     Marshal.dump($game_self_switches, file)
  76.     Marshal.dump($game_screen, file)
  77.     Marshal.dump($game_actors, file)
  78.     Marshal.dump($game_party, file)
  79.     Marshal.dump($game_troop, file)
  80.     Marshal.dump($game_map, file)
  81.     Marshal.dump($game_player, file)
  82.   end
  83. end
复制代码
读档脚本如下
  1. #==============================================================================
  2. # ■ Scene_Load
  3. #------------------------------------------------------------------------------
  4. #  处理读档画面的类。
  5. #==============================================================================

  6. class Scene_Load < Scene_File
  7.   #--------------------------------------------------------------------------
  8.   # ● 初始化对像
  9.   #--------------------------------------------------------------------------
  10.   def initialize
  11.     # 再生成临时对像
  12.     $game_temp = Game_Temp.new
  13.     # 选择存档时间最新的文件
  14.     $game_temp.last_file_index = 0
  15.     latest_time = Time.at(0)
  16.     for i in 0..3
  17.       filename = make_filename(i)
  18.       if FileTest.exist?(filename)
  19.         file = File.open(filename, "r")
  20.         if file.mtime > latest_time
  21.           latest_time = file.mtime
  22.           $game_temp.last_file_index = i
  23.         end
  24.         file.close
  25.       end
  26.     end
  27.     super("要载入哪个文件?")
  28.   end
  29.   #--------------------------------------------------------------------------
  30.   # ● 确定时的处理
  31.   #--------------------------------------------------------------------------
  32.   def on_decision(filename)
  33.     # 文件不存在的情况下
  34.     unless FileTest.exist?(filename)
  35.       # 演奏冻结 SE
  36.       $game_system.se_play($data_system.buzzer_se)
  37.       return
  38.     end
  39.     # 演奏读档 SE
  40.     $game_system.se_play($data_system.load_se)
  41.     # 写入存档数据
  42.     file = File.open(filename, "rb")
  43.     read_save_data(file)
  44.     file.close
  45.     # 还原 BGM、BGS
  46.     $game_system.bgm_play($game_system.playing_bgm)
  47.     $game_system.bgs_play($game_system.playing_bgs)
  48.     # 刷新地图 (执行并行事件)
  49.     $game_map.update
  50.     # 切换到地图画面
  51.     $scene = Scene_Map.new
  52.   end
  53.   #--------------------------------------------------------------------------
  54.   # ● 取消时的处理
  55.   #--------------------------------------------------------------------------
  56.   def on_cancel
  57.     # 演奏取消 SE
  58.     $game_system.se_play($data_system.cancel_se)
  59.     # 切换到标题画面
  60.     $scene = Scene_Title.new
  61.   end
  62.   #--------------------------------------------------------------------------
  63.   # ● 读取存档数据
  64.   #     file : 读取用文件对像 (已经打开)
  65.   #--------------------------------------------------------------------------
  66.   def read_save_data(file)
  67.     # 读取描绘存档文件用的角色数据
  68.     characters = Marshal.load(file)
  69.     # 读取测量游戏时间用画面计数
  70.     Graphics.frame_count = Marshal.load(file)
  71.     # 读取各种游戏对像
  72.     $game_system        = Marshal.load(file)
  73.     $game_switches      = Marshal.load(file)
  74.     $game_variables     = Marshal.load(file)
  75.     $game_self_switches = Marshal.load(file)
  76.     $game_screen        = Marshal.load(file)
  77.     $game_actors        = Marshal.load(file)
  78.     $game_party         = Marshal.load(file)
  79.     $game_troop         = Marshal.load(file)
  80.     $game_map           = Marshal.load(file)
  81.     $game_player        = Marshal.load(file)
  82.     # 魔法编号与保存时有差异的情况下
  83.     # (加入编辑器的编辑过的数据)
  84.     if $game_system.magic_number != $data_system.magic_number
  85.       # 重新装载地图
  86.       $game_map.setup($game_map.map_id)
  87.       $game_player.center($game_player.x, $game_player.y)
  88.     end
  89.     # 刷新同伴成员
  90.     $game_party.refresh
  91.   end
  92. end
复制代码
如果大神你有时间的话就稍微帮我看看吧……
我下午先上课去了~~~




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1