Giter Club home page Giter Club logo

lockstepserver's Introduction

Lock Step Server

GoDoc Build Status Go Report

用golang写的帧同步服务器,目标是作为一个可以横向扩展,完全脱离玩法逻辑的帧同步服务器。

特性

  • 采用KCP(可根据需求改成其他协议)作为网络底层
  • 采用帧同步方式
  • protobuf作为传输协议
  • 支持断线重连

运行example server

  1. 启动server go run cmd/example_server/main.go
  2. 创建房间:
    • 方法1. 浏览器打开 http://localhost 点创建
    • 方法2. 命令 sh cmd/example_client/create_room.sh

运行example client

  1. 启动1号客户端 go run cmd/example_client/main.go -room=1 -id=1
  2. 启动2号客户端 go run cmd/example_client/main.go -room=1 -id=2

网络层

  • 初始化网络层,使用的kcp-go,可以根据需求切换成其他的
  • 消息包格式
     |-----------------------------message-----------------------------------------|
     |----------------------Header------------------|------------Body--------------|
     |------Body Length-------|--------Msg ID-------|------------Body--------------|
     |---------uint16---------|---------uint8-------|------------bytes-------------|
     |-----------2------------|----------1----------|-----------len(Body)----------|
    

客户端接入流程

proto文件

  • 消息流程
    1. 客户端发送第一个连接的消息包
      C->S: MSG_Connect & C2S_ConnectMsg
    2. 服务端给返回连接结果
      S->C: MSG_Connect & S2C_ConnectMsg
    3. 如果2返回ok,客户端向服务端发送进入房间消息
      C->S: MSG_JoinRoom
    4. 服务端返回进入房间消息
      S->C: MSG_Connect & S2C_JoinRoomMsg
    5. 客户端这时进入读条,并广播读条进度,其他客户端收到广播读条进度
      C->S: MSG_Progress & C2S_ProgressMsg
      S->C: MSG_Progress & S2C_ProgressMsg 注:广播者收不到这个消息
    6. 客户端告诉服务端自己已经准备好
      C->S: MSG_Ready
      S->C: MSG_Ready
    7. 当所有客户端都已经准备好,服务端广播开始
      S->C: MSG_Start
    8. 客户端可以进入游戏状态,客户端不停的向服务端发送操作,服务端不停的广播帧数据
      ∞ C->S: MSG_Input & C2S_InputMsg
      ∞ S->C: MSG_Frame & S2C_FrameMsg
    9. 当客户端游戏逻辑结束告诉服务端自己结束
      C->S: MSG_Result & C2S_ResultMsg
      S->C: MSG_Result
    10. 当客户端收到MSG_Result或者MSG_Close客户端断开网络连接进入其他流程
      注:客户端收到MSG_Result表示服务端已经收到并处理的客户端发来的结果
      注:客户端收到MSG_Close表示服务端房间已经关闭,客户端如果游戏流程没完也要强制退出

断线重连

  • 客户端只要发 C->S: MSG_Connect & C2S_ConnectMsg **(前提是当前游戏房间还存在)**即可进入房间,服务端会把之前的帧分批次发给客户端。(这里可以考虑改成客户端请求缺失的帧)

客户端工程

https://github.com/byebyebruce/lockstep-client-unity

lockstepserver's People

Contributors

byebyebruce avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lockstepserver's Issues

协议可简化

我定义的帧同步服务器协议如下,可以讨论下:

/* 客户端服务器之间仅需通过kcp收发消息,没有实现grpc *\
// 中继服提供的房间中继接口,用于向客户端提供服务。
service Relay {
    rpc EnterRoom (EnterReq) returns (EnterResp) {}

    // 玩家动作
    rpc Act (stream ActMsg) returns (ActResp) {}

    // 帧广播
    rpc Tick (TickReq) returns (stream TickMsg) {}
}

各消息定义如下:

message EnterReq {
    // 服务器可以从 player_token 找到对应的房间和玩家号.
    optional string player_token = 1;

    // 上个帧号,需要服务器发送之后的帧: last_tick+1, last_tick+2, ...
    // 用于断线重连。
    // 如果是从头开始,则 last_tick 为0, 开始帧为 1.
    optional uint32 last_tick = 2;
}

message EnterResp {
    optional bool ok = 1;
    optional string error = 2;
    optional uint32 player_id = 3;
    optional uint32 ifs = 4; // 帧时间间隔
    optional uint64 rand_seed = 5; // 随机种子
}

message ActMsg {
    // 客户端自定义格式,服务器不会解析.
    optional bytes action = 1;
}

message ActResp {
}

message TickReq {
}

// 帧消息。
// 中继服将记录所有帧消息,用于断线重连。
message TickMsg {
    optional uint32 tick = 1;  // 当前帧号:1,2,...
    repeated PlayerActions player_actions = 2;  // 所有玩家的动作

    // 单个玩家当前帧的所有输入动作。保持输入次序。
    message PlayerActions {
        optional uint32 player_id = 1;
        repeated bytes actions = 2;
    }
}

一些疑问

为什么要限制玩家在一帧中只能输入一次操作,看其他帧同步项目,基本没有这个限制。
func (l *lockstep) pushCmd(cmd *pb.InputData) bool { ... //检查是否同一帧发来两次操作 for _, v := range f.cmds { if v.Id == cmd.Id { return false } } ...

空帧为什么不马上广播,客户端是需要空帧来驱动前进的。
我看你提供的客户端在没有输入的逻辑帧时,自动currentFrameIdx++了,是不是不够严谨了,正式项目肯定是不能丢帧的。
if !g.dirty && framesCount-g.clientFrameCount < BroadcastOffsetFrames { return }

Run the server.

Yo,

I tried to execute the server but without success. Have correct way to execute? I compiled the server and executed : ./example -web=10002 and got problem:

panic: listen tcp: address 10002: missing port in address

goroutine 19 [running]:
main.Init.func1()
        C:/Users/Julio Litwin/Desktop/lockstep-go/lockstepserver-master/example/main.go:45 +0xba
created by main.Init
        C:/Users/Julio Litwin/Desktop/lockstep-go/lockstepserver-master/example/main.go:42 +0x5d

@edit
It's running but it's giving me 404 error.

Thanks.

建议增加补帧逻辑

客户端丢帧的话,可否支持主动补齐丢失的帧,比如从第n帧开始到最新的。类似这样的接口

我可总算把这个项目跑起来了

在main.go中少一行引用:
_ "github.com/byebyebruce/lockstepserver/example/api"
不然启动不了api的init方法,无法创建房间

同时建议去game.go把MaxReadyTime设置时间长一点,至少60,不然你还没来得及起客户端就超时了

然后这个项目的具体操作方式是:

  1. 127.0.0.1:10002 打开浏览器,click创建房间,默认成员有1,2两个,一开始测试可以只设置1
  2. unity run&build客户端,pc上启动,连接设置127.0.0.1:10086连接
  3. �等待加载,成功

linux环境下无法连接

window环境客户端和服务器都正常,linux环境下客户端和服务器无法通信,ReadPacket报错:read error: io: read/write on closed pipe,是什么地方配置问题吗?

lockstepserver里的onclose方法调用时机

在客户端连上来后发起MSG_Connect消息后,conn里得callback被room的callback接管了,之后用户断开连接,也无法执行lockstepserver里得onclose方法来修正人数

kcp参数设置

你好,kcp的参数为什么这么设置,我看和kcpturn中的参数好像不太一致?
kcpConn.SetNoDelay(1, 10, 2, 1) kcpConn.SetStreamMode(true) // kcpturn (2048, 2048) kcpConn.SetWindowSize(4096, 4096) // kcpturn (16 * 1024 * 1024) kcpConn.SetReadBuffer(4 * 1024 * 1024) // kcpturn (16 * 1024 * 1024) kcpConn.SetWriteBuffer(4 * 1024 * 1024) // kcpturn (false) kcpConn.SetACKNoDelay(true)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.