查看: 4631|回复: 22

[讨论] 通过DLL发包进行的RMXP服务器联机已获得初步进展

[复制链接]
梦石
5
星屑
3525
在线时间
403 小时
注册时间
2016-6-25
回帖
217
发表于 2018-2-28 06:29:34 | 显示全部楼层 |阅读模式

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

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

×
RMXP的联机脚本可能这不是第一个,而且DLL扩展应该也是非常容易的
所以之前肯定有人研究过通过DLL进行的联机


RMXP联机.gif
本DLL采用的TCP联机,通过向服务端发送用户信息并进行匹配发包同步数据达成多终端联机
地图对象生成方面采用的是先建立默认事件再通过复制该事件到指定位置并改变一些参数
达到多个玩家同屏游玩
由于NPC移动速度和玩家移动速度并不一致的问题,数据同步会有0.2-0.8秒的延迟,由于不影响机能目前暂不解决
NPC映射方面相关代码如下
[pre lang="ruby"]# ▼▲▼ TCP服务器映射 ▼▲▼
# by 零教授
#
#!需DLL和服务器支持!
#==============================================================================
# ■ Window_Base
#==============================================================================


$TCPput = Win32API.new('tcpforRMXP', 'tcpput', %w(i i i p), 'v')
$TCPget = Win32API.new('tcpforRMXP', 'tcpget', 'v','p')
$JOIN = Win32API.new('tcpforRMXP', 'join', 'v','v')
$Name = KOISHI::GetPrivateProfileString("Base","Name")
Map001 = load_datax(sprintf("Data/Map%03d.rxdata", 1))
$other_players = {}
$map_players = []
$old_x = 0
$old_y = 0

class Game_Map
  alias setup_tcp setup
  def setup(map_id)
    setup_tcp(map_id)
    #$map_players = []
   
   # for i in 0...10
   #   @events[i+2000].erase if @events[i+2000] != nil
   # end
    #p $other_players
    if $map_players.size > 0
      for i in 0...$map_players.size
        player = $other_players[$map_players]
        if player[2].to_i == map_id
          #p $other_players[3]
          @events[i+2000] = Game_Event.new(map_id, Map001.events[1])
          @events[i+2000].erased = false
          @events[i+2000].name = player[3]
          @events[i+2000].character_hue = rand(360)
          @events[i+2000].moveto(player[0].to_i,player[1].to_i)
          @events[i+2000].refresh
          #@events[i+2000].x = $other_players[0].to_i
          #@events[i+2000].y = $other_players[1].to_i
          #p @events[i+2000]
        end
      end
    end
  end
  
  alias update_tcp update
  def update
    update_tcp
    #if (Graphics.frame_count % 40) == 1
      if $old_x != $game_player.x or $old_y != $game_player.y
        $TCPput.call($game_player.x ,$game_player.y ,@map_id ,$Name)
        $old_x, $old_y = $game_player.x, $game_player.y
      end
      begin
        string = $TCPget.call
      rescue
        string = ""
      end
     # p string
      tplayer = string.split(",")
if string != "" && tplayer.size == 5
    if $other_players[tplayer[4]] == nil
      $map_players.push(tplayer[4])
    end
    $other_players[tplayer[4]] = tplayer
    if tplayer[2] == 0
      $map_players.delete(tplayer[4])
      $other_players[tplayer[4]] = nil
      $game_temp.player_transferring = true
      $game_temp.player_new_map_id = @map_id
      $game_temp.player_new_x = $game_player.x
      $game_temp.player_new_y = $game_player.y
      $game_temp.player_new_direction = 5
      $game_player_shock_flag = true
      return
    end  
end
      #p $other_players
      #for i in 0..100-$other_players.size
      #  @events[2100-i] = nil
      #end  
      for i in 0...$map_players.size
        player = $other_players[$map_players]
        if player[2].to_i == @map_id
          if @events[i+2000].nil? or @events[i+2000].erased
            @events[i+2000] = Game_Event.new(@map_id, Map001.events[1])
            @events[i+2000].erased = false
            @events[i+2000].character_hue = rand(360)
            @events[i+2000].moveto(player[0].to_i,player[1].to_i)
            @events[i+2000].animation_id = 8
            @events[i+2000].refresh
          end  
          eve = @events[i+2000]
          #eve.moveto($other_players[0].to_i,$other_players[1].to_i)
          #p $other_players[3]
          if eve.x != player[0].to_i
            if eve.x < player[0].to_i
              if eve.y != player[1].to_i
                if eve.y < player[1].to_i
                  eve.move_lower_right
                else
                  eve.move_upper_right
                end
              else
                eve.move_right
              end
            else
              if eve.y != player[1].to_i
                if eve.y < player[1].to_i
                  eve.move_lower_left
                else
                  eve.move_upper_left
                end  
              else
                eve.move_left
              end
            end
          else
               if eve.y != player[1].to_i
                 if eve.y < player[1].to_i
                   eve.move_down
                 else
                   eve.move_up
                 end
               end
            
          end
   
          #@events[i+2000].x = $other_players[0].to_i
          #@events[i+2000].y = $other_players[1].to_i
        #else  #不在当前地图
         # @events[i+2000].erase if @events[i+2000] != nil
        end #if

      end #for

      #p $other_players
    #end
  
  end #def

end #class[/pre]
22.png 33.png 44.png
目前脚本和DLL都处于调试阶段,会出现诸多BUG
如下: 出现BUG.jpg

虽然效果上已经达到相当好的成果,但是是否能胜任网游的制作还有待考量

评分

参与人数 3星屑 +100 赞 +3 收起 理由
水母书亚 + 1 塞糖
RyanBern + 100 + 1 精品文章
congwsbn + 1 6

查看全部评分

横版类魂动作游戏《幻恋夜宴》好评发售中!https://store.steampowered.com/app/1684100
恋恋冒险CRPG《东方恋迷踪》~~火热开发中~~

梦石
0
星屑
127
在线时间
14 小时
注册时间
2015-3-19
回帖
17
发表于 2018-2-28 08:53:44 | 显示全部楼层
回复一下,
回复

使用道具 举报

梦石
0
星屑
2213
在线时间
759 小时
注册时间
2017-10-13
回帖
53
发表于 2018-2-28 12:29:25 | 显示全部楼层
牛的一笔
回复

使用道具 举报

梦石
1
星屑
24088
在线时间
3339 小时
注册时间
2011-7-8
回帖
3862

开拓者

发表于 2018-2-28 12:44:23 | 显示全部楼层
如果有好的异步的tcp通讯就很棒了~其实我更感兴趣的是分辨率怎么扩大的?我写的联机,数据传输是走的http request而不是用tcp socket,但是客户端拿到数据后如何处理,这些是通用的,有兴趣可以去看看。

https://gitee.com/rmxp/rgss_server

点评

啊对了,有一件事情忘记问了,您知不知道有什么API可以让RM打开游戏的窗口自动转化为无边缘窗口,这两天一直在找  发表于 2018-3-5 04:27
嗯,服务端的一些多线程优化处理还有加密解密操作是目前需要学习的  发表于 2018-2-28 17:47

评分

参与人数 1星屑 +30 收起 理由
RyanBern + 30 赞认真的回复

查看全部评分

熟悉rgss和ruby,xp区版主~
正在填坑:《膜拜组传奇》讲述膜拜组和学霸们的故事。
已上steam:与TXBD合作的Reformers《变革者》
* 战斗调用公共事件 *
* RGSOS 网络脚本 *
回复

使用道具 举报

梦石
0
星屑
9292
在线时间
2504 小时
注册时间
2011-5-20
回帖
14521

开拓者

发表于 2018-2-28 14:19:18 | 显示全部楼层
图中的全部都是玩家?还是大部分是npc
如果其中一个玩家用了物品,使用物品的音效其他玩家可以听到吗?

点评

因为是频道制度,玩家一旦改变数据(显示动画、移动位置)就会发包给同房间的人,然后在他们自己本地的游戏里就能显示变化了  发表于 2018-2-28 17:39
做个吃鸡也有可能了  发表于 2018-2-28 16:02
感觉这个应该看游戏类型来定···(如果你可以完全收到附近玩家使用物品/技能时产生的动画和音效,可能会崩掉吧···)不过最好是能做到,这样的话   发表于 2018-2-28 16:01
通常的道具,定期同步 animation_id 就行啦  发表于 2018-2-28 14:56
[img]http://service.t.sina.com.cn/widget/qmd/5339802982/c02e16bd/7.png
回复

使用道具 举报

梦石
5
星屑
3525
在线时间
403 小时
注册时间
2016-6-25
回帖
217
 楼主| 发表于 2018-2-28 17:18:38 | 显示全部楼层
本帖最后由 零教授 于 2018-2-28 17:24 编辑
guoxiaomi 发表于 2018-2-28 12:44
如果有好的异步的tcp通讯就很棒了~其实我更感兴趣的是分辨率怎么扩大的?我写的联机,数据传输是走的http r ...

QQ图片20180220191229.png
分辨率WIN32AI是用论坛的
光修改分辨率非常容易,但是要修改地图图块元件和人物元件,以及场景窗口就需要自适应
除开修改分辨率外还必须修改Scene_Battle、Spriteset_Battle、Scene_Map、Spriteset_Map、Game_Battler、Sprite_Battler、RPG::Weather这些主要的图片处理的类
QQ图片20180228171458.png QQ图片20180228171944.png
[pre lang="ruby"]#==============================================================================
# 本脚本来自www.66RPG.com,使用和转载请保留此信息
#==============================================================================
# ————————————————————————————————————
# 本脚本来自www.66rpg.com,转载请保留此信息
# ————————————————————————————————————

#ウィンドウサイズの変更(v1.00)
module THNDJ
  GAME_INI_FILE = ".\\Game.ini"
  #--------------------------------------------------------------------------
  # ● 读取配置文件
  #--------------------------------------------------------------------------
  def THNDJ.GetPrivateProfileString(section, key)
     val = "\0"*256
     gps = Win32API.new('kernel32', 'GetPrivateProfileString',%w(p p p p l p), 'l')
     gps.call(section, key, "", val, 256, GAME_INI_FILE)
     val.delete!("\0")
     return val
  end
   
  #--------------------------------------------------------------------------
  # ● 写入配置文件
  #--------------------------------------------------------------------------
  def THNDJ.WritePrivateProfileString(section, key, val)
     gps = Win32API.new('kernel32', 'WritePrivateProfileString',%w(p p p p), 'i')
     return gps.call(section, key, val.to_s , GAME_INI_FILE)
   end
  
   
   
   
  #--------------------------------------------------------------------------
  #--------------------------------------------------------------------------
  def THNDJ.FindWindow(class_name, title)
    fw = Win32API.new('user32', 'FindWindow', %(p, p), 'i')
    hWnd = fw.call(class_name, title)
    return hWnd
  end

  HWND_TOP     = 0
  HWND_TOPMOST = -1
  SWP_NOMOVE   = 0
  
  #--------------------------------------------------------------------------
  #--------------------------------------------------------------------------
  def THNDJ.SetWindowPos(hWnd, w, h)
    system_metrics = Win32API.new('user32', 'GetSystemMetrics', %(i), 'i')
    sw = system_metrics.call(0)
    sh = system_metrics.call(1)
   # if sw <= 800 or sh <=600
  #    return false
  #  end
    x_alias = (sw - w)/2
    y_alias = (sh - h)/2
    swp = Win32API.new('user32', 'SetWindowPos', %(l, l, i, i, i, i, i), 'i')
    ok = swp.call(hWnd, HWND_TOP, x_alias, y_alias, w, h, SWP_NOMOVE)
    # 下の行を有効にすると、常に前面に表示されるウィンドウになる。
    #ok = swp.call(hWnd, HWND_TOPMOST, 0, 0, w, h, SWP_NOMOVE)

    #SetWindowPos(const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags );
    #参数1是在屏幕显示的层次优先级(最上最下);后四个决定窗口四个角的坐标;最后一个指定显示的状态。具体可以参阅MSDN.
    return ok
  end
end

title = THNDJ.GetPrivateProfileString("THNDJ", "NormalTitle")
$hWnd = THNDJ.FindWindow("RGSS Player", title)

def resize_window
  
  # 幅320、高さ480に変更
  $width = [[THNDJ.GetPrivateProfileString("THNDJ","$width").to_i,640].max,1280].min
  $height = [[THNDJ.GetPrivateProfileString("THNDJ","$height").to_i,480].max,960].min
  ok = THNDJ.SetWindowPos($hWnd, $width, $height)
  $XRXS65AX = ($width-546)/2
  $XRXS65AY = $height-90
  if(ok == 0)
    p "サイズ変更失敗"
    $width = 640
    $height = 480
    $XRXS65AX = ($width-546)/2
    $XRXS65AY = $height-90
    return false
  end
  return true
end

module KOISHI
  @player_id = THNDJ.GetPrivateProfileString("THNDJ", "player_id")
  KOISHI_FILE = ".\\"+@player_id+".ini"
  #--------------------------------------------------------------------------
  # ● 读取配置文件
  #--------------------------------------------------------------------------
  def KOISHI.GetPrivateProfileString(section, key)
     val = "\0"*256
     gps = Win32API.new('kernel32', 'GetPrivateProfileString',%w(p p p p l p), 'l')
     gps.call(section, key, "", val, 256, KOISHI_FILE)
     val.delete!("\0")
     return val
  end
   
  #--------------------------------------------------------------------------
  # ● 写入配置文件
  #--------------------------------------------------------------------------
  def KOISHI.WritePrivateProfileString(section, key, val)
     gps = Win32API.new('kernel32', 'WritePrivateProfileString',%w(p p p p), 'i')
     return gps.call(section, key, val.to_s , KOISHI_FILE)
   end

end
#==============================================================================
# 本脚本来自www.66RPG.com,使用和转载请保留此信息
#============================================================================== [/pre]

评分

参与人数 2星屑 +50 赞 +1 收起 理由
guoxiaomi + 1 我很赞同
RyanBern + 50 赞认真的回复

查看全部评分

横版类魂动作游戏《幻恋夜宴》好评发售中!https://store.steampowered.com/app/1684100
恋恋冒险CRPG《东方恋迷踪》~~火热开发中~~

回复

使用道具 举报

梦石
0
星屑
2724
在线时间
227 小时
注册时间
2016-3-27
回帖
557
发表于 2018-2-28 19:11:22 | 显示全部楼层
联机其实这个想法很多人都有想过
也有人付诸过实际行动
但是这方面最大的问题就在于服务器
有谁会愿意做一个免费的RM去开服务器给大家玩呢???
现在服务器又那么贵
除非是自己的经济来源来自于机房,然后可以分一小块,供RM使用
要不就得用RM做高品质的游戏,来吸引玩家一次性购买/内购
不过RM做高品质限制还是很多的
话说回来楼主还是 挺厉害的
加油吧

点评

好像很有道理  发表于 2018-3-1 17:43
你还需要一个非常宝贵的公网ip  发表于 2018-3-1 09:13
主要是真的会有人无偿开发游戏并且用服务器做online吗...qwq  发表于 2018-2-28 22:42
服务器就买来放在自己家里,电费和宽带费交着就不会感到压力,除非你要拿服务器去挖矿  发表于 2018-2-28 19:15

评分

参与人数 1星屑 +30 收起 理由
RyanBern + 30 可以去租vps 并不贵

查看全部评分

现在还能改名吗qwq
回复

使用道具 举报

老黄鸡

梦石
4
星屑
45700
在线时间
7948 小时
注册时间
2009-7-6
回帖
13338

MZ评测员RM创作大赛01组委会开拓者贵宾

发表于 2018-2-28 23:24:46 | 显示全部楼层
guoxiaomi 发表于 2018-2-28 12:44
如果有好的异步的tcp通讯就很棒了~其实我更感兴趣的是分辨率怎么扩大的?我写的联机,数据传输是走的http r ...

如果郭兄有需要我这里倒是可以糊一个突破限制的tilemap

点评

雷霆那边好像有把VA的图块改成48*48的方法  发表于 2018-3-1 19:20
暂时倒是不需要的  发表于 2018-3-1 01:48

评分

参与人数 1星屑 +20 收起 理由
RyanBern + 20 非常醋

查看全部评分

RGDirect - DirectX驱动的RGSS,点我了解.
(排满,暂停)RM全系列成套系统定制请联系QQ1213237796
不接受对其他插件维护的委托
回复

使用道具 举报

头像被屏蔽
梦石
0
星屑
172
在线时间
935 小时
注册时间
2010-11-13
回帖
897
发表于 2018-3-19 18:09:08 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽
回复

使用道具 举报

梦石
0
星屑
910
在线时间
94 小时
注册时间
2005-10-22
回帖
335
发表于 2018-3-24 15:15:51 | 显示全部楼层
10多年前确实有联网的dll出现,并且连接成功了,不过,后来就没有进一步进展了,那个实现的是在线走路和聊天对话,没完成在线组队打怪。
做脚本先从修改脚本做起,我只修改自己觉得能用到的东西。
以后的任何作品都将不会进行分享。
Bilibili:https://space.bilibili.com/288814521
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部