lixianmin / road

改编自pitaya的golang游戏库
15 stars 3 forks source link

pitaya 是有保证某个玩家得消息顺序执行的 #2

Open lyh1091106900 opened 1 year ago

lyh1091106900 commented 1 year ago

` func (h *HandlerService) Handle(conn acceptor.PlayerConn) { a := h.agentFactory.CreateAgent(conn) go a.Handle()

logger.Log.Debugf("New session established: %s", a.String())

// guarantee agent related resource is destroyed
defer func() {
    a.GetSession().Close()
    logger.Log.Debugf("Session read goroutine exit, SessionID=%d, UID=%s", a.GetSession().ID(), a.GetSession().UID())
}()

for {
    msg, err := conn.GetNextMessage()

    if err != nil {
        if err != constants.ErrConnectionClosed {
            logger.Log.Errorf("Error reading next available message: %s", err.Error())
        }

        return
    }

    packets, err := h.decoder.Decode(msg)
    if err != nil {
        logger.Log.Errorf("Failed to decode message: %s", err.Error())
        return
    }

    if len(packets) < 1 {
        logger.Log.Warnf("Read no packets, data: %v", msg)
        continue
    }

    // process all packet
    for i := range packets {
        if err := h.processPacket(a, packets[i]); err != nil {
            logger.Log.Errorf("Failed to process packet: %s", err.Error())
            return
        }
    }
}

}` 你可以发现pitaya是以数组形式处理消息,所以保证了单个玩家得消息顺序执行

lixianmin commented 1 year ago

我当年用的应该是pitaya 1.x的版本, 很久以前来, 后来遇到过不少问题, 包括但不限于:

  1. 网络消息相关的bug太多了
  2. 网络层相关的架构有些过度设计, 不利于的bugfix以及添加新内容
  3. unity3d中的client是以二进制的形式发布的, 在mac, windows, android都需要使用不同二进制包, 而我希望有一个csharp的版本
  4. js的代码几乎都写在一个叫starx的文件中, 而且代码前后呼应, 改不动

鉴于以上各类问题, 网络层我已经完全重写了. 目前集成到 https://github.com/lixianmin/gonsole 这个库的road目录下, 而这个独立的road项目, 已经不再更新了, 版本也比较旧了

以上提到的pitaya相关的问题, 限于1.x版本, 新的版本是什么样子的, 我没有研究过.

lyh1091106900 commented 1 year ago

我看到版本1.11已经是有这段代码了,现在版本是2.x.x。能讨论一下怎样子去设计一个好的框架吗?我挺感兴趣的,请指教。 对于你说的第三点关于unity client,如何才能消除平台差异,我知道unity是跨平台的。对于不同的通信协议应该要引入不同的二进制包。能在csharp那一层就把差异抹平了吗?

lixianmin commented 1 year ago

如何设计好的框架好像不是一两句能说明白的事, 不同的开发方向有不同的最佳实践总结. 对pitaya的1.xx版本来说, 它多少存在我前述所说的问题. 但最关键的是, 它不正确, 在很多情况下数据传错了. 本来我是想修这些bug的, 但是发现pitaya做了很多没必要的设计, 比如它在Message和Packet层都做了编解码. 后来我觉得把它修好可能还不如我自己写一遍快, 于是就重写了一份, 新写的代码量好像只有pitaya的1/3不到的样子.

新的代码在gonsole项目的road目录下, pitaya中配套的starx.js, 我也使用js重写过了, 放在web/src/code/road目录下. 你想了解的话, 也可以参考.

至于unity client消除平台差异的事. 我就是用csharp把网络层写一遍, 因为golang和js的逻辑都写过了一遍, 所以大体逻辑是把js翻译成csharp即可, 只是会多出来多线程数据交换的逻辑.

你提到不同的通信协议的事情, 在gonsole项目中有一个serde目录, 里面内置了一个json_serde.go, 实现了golang版本的序列化/反序列机制, 对应的js版本在json_serde.js中, 你可以看一下, 就一两句代码的事. 实践中, 为了支持游戏应用, 我补了protobuf协议支持, protobuf序列化/反序列化其实也是几句代码就搞定了 (编写*.proto文件以及生成协议相关的代码需要单独处理). 整体来讲, 把变的部分 (就像这里的serde序列化), 单独摘出来, 也算是设计框架的小技巧吧.

个人理解, 欢迎探讨.

On Mon, Sep 25, 2023 at 12:05 PM lyh1091106900 @.***> wrote:

我看到版本1.11已经是有这段代码了,现在版本是2.x.x。能讨论一下怎样子去设计一个好的框架吗?我挺感兴趣的,请指教。 对于你说的第三点关于unity client,如何才能消除平台差异,我知道unity是跨平台的。对于不同的通信协议应该要引入不同的二进制包。能在csharp那一层就把差异抹平了吗?

— Reply to this email directly, view it on GitHub https://github.com/lixianmin/road/issues/2#issuecomment-1732872166, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGISVKGOLXTAP5CCN7VIWJTX4D7IFANCNFSM6AAAAAA5CTVDT4 . You are receiving this because you commented.Message ID: @.***>

actfuns commented 7 months ago

` func (h *HandlerService) Handle(conn acceptor.PlayerConn) { a := h.agentFactory.CreateAgent(conn) go a.Handle()

logger.Log.Debugf("New session established: %s", a.String())

// guarantee agent related resource is destroyed
defer func() {
  a.GetSession().Close()
  logger.Log.Debugf("Session read goroutine exit, SessionID=%d, UID=%s", a.GetSession().ID(), a.GetSession().UID())
}()

for {
  msg, err := conn.GetNextMessage()

  if err != nil {
      if err != constants.ErrConnectionClosed {
          logger.Log.Errorf("Error reading next available message: %s", err.Error())
      }

      return
  }

  packets, err := h.decoder.Decode(msg)
  if err != nil {
      logger.Log.Errorf("Failed to decode message: %s", err.Error())
      return
  }

  if len(packets) < 1 {
      logger.Log.Warnf("Read no packets, data: %v", msg)
      continue
  }

  // process all packet
  for i := range packets {
      if err := h.processPacket(a, packets[i]); err != nil {
          logger.Log.Errorf("Failed to process packet: %s", err.Error())
          return
      }
  }
}

}` 你可以发现pitaya是以数组形式处理消息,所以保证了单个玩家得消息顺序执行

processPacket 只是把消息放在chLocalProcess, chLocalProcess最终还是并发执行的把 还有会导致乱序把 个人理解

lixianmin commented 7 months ago

road已经把相关的逻辑都重写了, 好久没管pitaya的事了; 而road已经作为一个子目录合并到这里了, https://github.com/lixianmin/gonsole/tree/master/road , 因为各种原因, 重构过几个版本了

On Mon, Mar 25, 2024 at 11:29 AM actfuns @.***> wrote:

` func (h *HandlerService) Handle(conn acceptor.PlayerConn) { a := h.agentFactory.CreateAgent(conn) go a.Handle()

logger.Log.Debugf("New session established: %s", a.String())

// guarantee agent related resource is destroyed defer func() { a.GetSession().Close() logger.Log.Debugf("Session read goroutine exit, SessionID=%d, UID=%s", a.GetSession().ID(), a.GetSession().UID()) }()

for { msg, err := conn.GetNextMessage()

if err != nil { if err != constants.ErrConnectionClosed { logger.Log.Errorf("Error reading next available message: %s", err.Error()) }

  return

}

packets, err := h.decoder.Decode(msg) if err != nil { logger.Log.Errorf("Failed to decode message: %s", err.Error()) return }

if len(packets) < 1 { logger.Log.Warnf("Read no packets, data: %v", msg) continue }

// process all packet for i := range packets { if err := h.processPacket(a, packets[i]); err != nil { logger.Log.Errorf("Failed to process packet: %s", err.Error()) return } } }

}` 你可以发现pitaya是以数组形式处理消息,所以保证了单个玩家得消息顺序执行

processPacket 只是把消息放在chLocalProcess, chLocalProcess最终还是并发执行的把 还有会导致乱序把 个人理解

— Reply to this email directly, view it on GitHub https://github.com/lixianmin/road/issues/2#issuecomment-2017145404, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGISVKH7PP7LEVKRXETYYZTYZ6K3HAVCNFSM6AAAAAA5CTVDT6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMJXGE2DKNBQGQ . You are receiving this because you commented.Message ID: @.***>