2.6.3 • Published 6 years ago

unthink v2.6.3

Weekly downloads
4
License
MIT
Repository
github
Last release
6 years ago

unthink

一个可自由扩展的协议代码生成器

安装

npm install unthink -g

使用

创建一个存放协议描述文件的目录,执行如下操作

unthink init

会生成如下目录树:

  • config.json        ---配置文件
  • start.cmd        ---执行命令的批处理
  • client_only        ---只对客户端做代码输出
    • api.json
    • enum.json
    • struct.json
  • common        ---客户端服务器同时输出
    • api.json        ---协议接口描述文件,以下统称interface文件
    • enum.json        ---通用枚举描述文件,以下统称interface文件
    • struct.json        ---通用数据结构描述文件,以下统称interface文件
  • server_only        ---只对服务器做代码输出
    • api.json
    • enum.json
    • struct.json

common目录下描述的内容客户端和服务器代码都会导出,client_only描述的内容只有客户端代码会导出,
server_only描述的内容只有服务器会导出。client_onlyserver_only在一般场景中不会用到。
client_only设计意图是在服务器本身内置了一部分接口功能,但是没有或者没有必要提供客户端接口,
这时候可以在client_only文件中补充描述,server_only目录功能类似。

执行代码生成

配置config.json代码路径,执行start.cmd生成代码。

协议版本号介绍

工具会自动记录协议版本号,提供给游戏逻辑做协议版本校验
版本号是以一个枚举提供的,在工具中自动生成,不需要描述文件添加,ts代码格式如下:

export class ProtoVersion { //工具自动生成的枚举,记录协议版本号
    static versionCode = 2; //协议版本号数字表示
    static versionName = '0.0.2'; //协议版本号字符表示
}

同时在interface根目录下生成一个version文件用来记录老的代码,内容如下:

{
  "versionCode": 2,
  "versionName": "0.0.2",
  "versionMD5": "1299e5e90d906a07685a9d7e53b28b2f"
}

versionName记录了版本号的字符表示,每10个小版本会提升一个大版本。可以手动修改此文件来矫正版本号提升。
versionMD5字段是所有interface文件字符计算出的md5,并且过滤掉了注释,只是修改注释,并不会导致版本号提升。

文件格式介绍

config.json

注意:本项目下的所有json文件都支持注释,如果使用vscode编辑,建议右下角文件类型由JSON切换至JSON with Comments。可以消除红线错误提示。高于1.20版本有这个文件类型。
config完整内容如下:

{
    "out": { /* 需要输出的文件种类,对应backend的种类*/
        "unity": "./out/unity", /*unity工程Scripts目录*/
        "unity-gameframework": { /*使用gameframework工程的Scripts目录*/
            "path": "./out/unity-gfw/Assets/Scripts", /*unity工程Script目录*/
            "namespace": "StarForce"
        },
        "thinkjs": "./out/thinkjs/", /*thinkjs 项目根目录*/
        "json-schema": "./out/thinkjs/public/schema", /*json-schema目录*/
        "sql": {
            "path": "./out/thinkjs/public/sql/",
            "dbname": "gamedb"
        }
    },
    "request_required": true, /*是否坚持每个api声明了request*/
    "response_required": true  /*是否坚持每个api声明了response*/
}
  • out 属性配置了所有支持的导出,可以删掉不需要的导出
    • unity 提供了原生unity的协议导出,并且提供了一个简单的http封装ServerContext.cs,这个文件可以手动修改,不会被工具再次生成覆盖。
    • unity-gameframework 提供了基于技术中心提供的gameframework框架的协议导出,框架包含了事件机制,请求顺序化机制等,详细介绍请阅读框架文档。namespace是生成代码的命名空间。
    • thinkjs thinkjs服务器框架导出的协议文件,并且会在对应的controller文件中做处理函数声明。controller部分的修改是借助于于typescript抽象语法树的分析修改,不会影响现有逻辑的实现。
    • json-schema 是http请求参数的json格式校验,生成的描述文件符合json-schema标准,可以使用ajv或者中心提供的think-game-validator模块来校验。
    • sql所有interface文件中声明的结构,如果是需要存数据库的,会生成一份数据库DDL文件,直接通过phpadmin或者其他工具导入该文件,即可完成数据库的更新。做到了完全不需要手动操作数据库的效果。
  • request_required 是否允许单方向协议接口,http必须是双向的,一个req对应一个res,在长连接协议中,可能不是对应的。该字段留给后续扩展,暂时全部为true。
  • response_required 同上。

协议内置类型及关键字介绍

内置类型

类型名称默认值DB默认类型说明
bool布尔型falsetinyint(4)
string字符串“”varchar(64)
intint0int(11)区分各种数字类型是考虑到c#类型和db类型,js统一为number
int6464位int0bigint(20)同上
float浮点型0.0float同上
double双精度浮点型0.0double同上
array数组nulltext(json字符串)数组支持嵌套
object对象nulltext(json字符串)对象类型和自定义类型区别是,对象的属性是动态的

关键字

名称效果说明可省略
<type>指定变量的类型可以是上表的内置类型或者自定义结构或者是纯数字枚举(当做int处理)
<default>指定变量的默认值需要用户自己保证默认值在各种语言导出版本中语法正确,不指定采用内置默认值
<dbtype>指定变量对应的db类型当内置默认类型不能满足需求的时候指定对应的默认值
<nodb>强制使继承DBObject对象的结构不导出到sql文件DDL中某个中间类,不需要sql中对其建表的时候使用
<dbindex>如果结构存库,指定对应表的索引子类会覆盖父类指定的索引
<extends>指定结构继承的父类只支持单继承
<req>接口声明中request参数http中是必须的
<res>接口声明中require参数http中是必须的

下面interface文件会详细提供语法举例。

enum.json

注意:本项目所有的注释,直接在对应需要注释的对象后面使用 //形式编写。
举例如下:

{
    "EItemState": { //物品状态
        "normal": 0, //正常状态
        "locked": 1, //被锁定
        "countdown": 2, //冷却中
    },
   "ECommon": { // 通用枚举
        "MaxNameLenth": 20, //名字最大长度
        "DefaultName": "Brad Pitt", // 默认名字
        "MoveSpeed": 1.3, // 移动速度
        "CanJump": false // 开启跳跃
    }   
},

以上声明了两种枚举,一种是纯数字枚举EItemState,这种枚举可以作为类型提供给其他变量使用(当做int类型)。另外一种是数字,浮点,字符串或者布尔型混合的枚举ECommon,这种枚举是用静态class实现的,不能作为类型给其他变量使用。

struct.json

普通结构声明:

    "RewardItem": // 奖励使用的物品结构
    {
        "cid":"int",
        "count":"int",
    },
    "Reward":
    {
        "gold":"int", // 奖励的金币
        "items":"array<RewardItem>", //奖励的物品数组
        "id":{     //对应的关卡id
            "<type>":"int",// 类型
            "<default>":"123" // 默认值,可以不写这个属性,默认值是安装前面表格的默认值
        }
    }

可以看到 RewardRewardItem是结构名,定义结构不用区分先后顺序。Reward有三个成员: gold,items,id

  • gold是用简便方法声明的,
  • id是用详细语法声明的。详细声明方法中<type>是必须的,<default>是可以省略的,
  • items是一个数组并且成员类型是我们自己定义的类型。还可以给id添加<dbtype>描述数据库存储格式,当然要求Reward对象必须声明成存储在数据库中的对象,下面会介绍语法。 注意:关于简便语法和详细语法,起到的作用是一样的,只是详细语法可以更详细的指定一些属性,比如<default>:默认值,<dbtype>:对应的数据库表的字段类型。如果不用详细语法指定,会使用工具内置默认值,参见前面的关键字表格。建议使用简易描述所有结构,节省开发时间。在特殊需求的地方或者上线前的优化过程中,使用详细描述。

数据库结构声明:

这个功能是可选的,如果需要自由的控制对象的存库行为,不导出sql文件。这个功能可以跳过。
首先明确一个设计概念,struct.json的一个结构 对应了一条玩家数据(或者非玩家数据,如公会信息),同时对应了数据库中的一张表,这三个是一一对应的,结构名和玩家数据类型和数据库表名是一致的。 工具内置了3个相关结构:

    "DBBase": { // 所有入库对象应该继承此类 
    },
    "DBObject": { // 所有玩家个人数据应该继承此类。
        "<extends>": "DBBase",
        "<nodb>": true,
        "<dbindex>": "PRIMARY KEY (`uuid`),KEY `USRID` (`usrid`)",
        "uuid": "string",
        "usrid": "int64"
    },
    "DBGlobalObject": { // 所有全局数据应该继承此类(例如公会)。
        "<extends>": "DBBase",
        "<nodb>": true,
        "<dbindex>": "PRIMARY KEY (`uuid`)",
        "uuid": "string",
    },
  • DBBase,继承该结构的所有结构,如果没有指定<nodb>那么都会在数据库生成一张对应表格。
  • DBObject所有玩家所属对象的基类,比如物品对象,任务对象等等。带有两个字段uuidusrid, 一个是该对象的唯一id,一个是玩家id。<dbindex>描述了对应索引,如果某个表有特殊的索引要求,可以拥有自己的<dbindex>
  • DBGlobalObject 是全局对象的基类,比如公会表。 以上结构除了DBBase的结构名不能修改(判断是否导出数据库表的依据),其他都可以根据需求修改 下面是举例
     "Item": { // 玩家物品的结构
        "<extends>": "DBObject",
        "cid":"int",//对应的策划表id
        "count":"int", // 物品的数量
        "state":"EItemState" // 对应物品的状态。 
    },
    "Task": {
        "<extends>": "DBObject",
        "cid":"int",
        "phase":"int" // 或者定义一个对应枚举
    }

Item,Task代表玩家的物品和任务数据,数据库中会对应生成一下sql的DDL

     DROP TABLE IF EXISTS `Item`;
     CREATE TABLE IF NOT EXISTS `Item` (
       `uuid` varchar(64) NOT NULL,
       `usrid` bigint(20) NOT NULL,
       `cid` int(11) NOT NULL COMMENT '对应的策划表id',
       `count` int(11) NOT NULL COMMENT ' 物品的数量',
       `state` text NOT NULL COMMENT ' 对应物品的状态。 ',
       PRIMARY KEY (`uuid`),KEY `USRID` (`usrid`)  
     ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=' 玩家物品的结构';
     
     
     DROP TABLE IF EXISTS `Task`;
     CREATE TABLE IF NOT EXISTS `Task` (
       `uuid` varchar(64) NOT NULL,
       `usrid` bigint(20) NOT NULL,
       `cid` int(11) NOT NULL,
       `phase` int(11) NOT NULL COMMENT ' 或者定义一个对应枚举',
       PRIMARY KEY (`uuid`),KEY `USRID` (`usrid`)  
     ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

如果是中文注释,注意导入时的编码格式,命令行导入可能需要指定编码--default-character-set=utf8
另外中心仓库提供了一个unthink模块:think-game-unthink,封装了玩家数据操作api,实现了玩家数据的加载,缓存(reids)和落地功能,结合该模块,可以让服务器开发只关注于编写逻辑。

api.json

描述客户端和服务器通讯接口的文件。 格式如下:

     "System": { // System模块
        "login": { // 玩家登陆api
            "<req>": { // 请求登陆
                "name": "string",
                "pwd": "string"
            },
            "<res>": {
                "usr": "UserInfo", // 玩家信息(需要在结构描述文件中提前定义)
                "error": "EError" //错误类型(需要在枚举文件中提前定义)
            }
        },
        "Logout": { //玩家登出api
            "<req>": {},
            "<res>": {
                "error": "EError"
            }
        }
    },
    "Test": { // 测试模块
        "Echo": { // 回显
            "<req>": {
                "msg": "string", // 回显消息
                "time": "int" //时间戳
            },
            "<res>": {
                "msg": "string", //客户端发来的消息
                "time": "int" //客户端发来的时间戳
            }
        }
    }

SystemTest是模块名,建议不同的游戏模块采用不同的名字,loginSystem模块下的一个api,统一模块下可以声明多个api。比如login<req><res>对应了http的reqres;

扩展

如果该工具不能满足项目需求,可以从gi上获取源码进行修改,源码res目录就是interface的目录 lib/backend文件夹下是各种代码的输出逻辑,可以根据需求新增代码输出和修改已有的输出。

结束

2.6.3

6 years ago

2.6.2

6 years ago

2.6.1

6 years ago

2.6.0

6 years ago

2.5.0

6 years ago

2.4.4

6 years ago

2.3.4

6 years ago

2.2.4

6 years ago

2.1.4

6 years ago

2.0.4

6 years ago

2.0.3

6 years ago

2.0.2

6 years ago

2.0.1

6 years ago

2.0.0

6 years ago

1.0.8

6 years ago

1.0.7

6 years ago

1.0.6

6 years ago

1.0.5

6 years ago

1.0.4

6 years ago

1.0.3

6 years ago

1.0.2

6 years ago

1.0.1

6 years ago

1.0.0

6 years ago

0.2.3

6 years ago

0.2.2

6 years ago

0.2.1

6 years ago

0.2.0

6 years ago

0.1.1

6 years ago

0.1.0

6 years ago

0.0.7

6 years ago

0.0.6

6 years ago

0.0.5

6 years ago

0.0.4

6 years ago

0.0.3

6 years ago

0.0.2

6 years ago

0.0.1

6 years ago