package cs;

/*
  约定：
  CM前缀：客户端发给服务器的消息(client message)
  SM前缀：服务器发给客户的的消息(server message)
  MF前缀：消息的内嵌字段，只能作为其他消息的内嵌字段不能send(message field)
  _e后缀：枚举类型
  _uniid后缀：唯一id
  union_前缀：联合体
  _前缀：该字段仅服务器使用客户端无需处理

  网络包格式：msghead + msgbody
  msghead: packagelen + msgid + seqid + magiccode + reserved = 2 + 2 + 4 + 2 + 2 = 12字节
  msgbody： protobuf数据
  msghead说明
  packagelen（unsigned short）： 双字节网络包长度，
  msgid(unsigned short): 双字节消息id
  seqid(unsigned int): 4字节序号id
  magiccode(unsigned short): 2字节魔数，并且为固定常数KS，占位符客户端不需什么处理
  reserved(unsigned short): 保留

  十六进制位运算数据表示法
  0x01 == 1<<0
  0x02 == 1<<1
  0x04 == 1<<2

  data_flags字段的意义
  由于protobuf的二义性无法描述repeated字段是否有值(非repeated的字段可以通过msg.xxx == null来a判断)
  所以给协议添加了data_flags这样的字段用来描述字段是否有值
  data_flags32：描述id 1-31的字段哪些是赋值
  data_flags64: 描述id 31-63直接的字段是否赋值
  data_flags128...... 以此类推
  message MFRoleInfo
  {
    optional int32 role_id = 1;
    optional int32 role_name = 2;

    optional int32 role_level = 34;

    optional uint32 data_flags32 = 256;
    optional uint32 data_flags64 = 257;
  }
  role_id是否赋值 (data_flags32 & (1<<(1 - 1))) != 0
  role_name是否赋值 (data_flags32 & (1<<(2 - 1))) != 0
  role_level是否赋值 (data_flags64 & (1<<(34 - 33)) != 0
  客户端可以根据protobuf反射得到字段名和字段id的对应关系做到自动化判断
*/

//常量
enum Constant_e
{
    ProtoVersion = 2022032201; //系统版本
}

//心跳
message CMPing
{
}
message SMPing
{
    optional int32 param1 = 1;
}

//rpc调用错误
message SMRpcError
{
    optional int32 error_code = 1;
    optional string error_msg = 2;
    optional string debug_msg = 3;
    optional string file = 4;
    optional int32 lineno = 5;
    optional int32 error_param = 6;
}

//int32键值对
message MFPair
{
    optional int32 key = 1; //key
    optional int32 value = 2; //val
}

//int64键值对
message MFPair64
{
    optional int64 key = 1; //key
    optional int64 value = 2; //val
}

//int32元组
message MFTuple
{
    repeated int32 values = 1; //values
}

//向量
message MFVec2
{
    optional float x = 1; //x轴
    optional float y = 2; //y轴
}

//属性变更
/*
  property_type: 1 血量
  property_type: 2 最大血量
  property_type: 3 库存
     property_subtype: 库存数组索引
  property_type: 4 技能cd时间（剩余时间）
  property_type: 5 技能cd时间（总时间）
  property_type: 6 载具剩余子弹数
  property_type: 7 载具油量
     property_subtype: 0（当前油量）1(总油量)) 在同步当前油量前必然同步过总油量!
  property_type: 8 当前武器的子弹剩余数量
  property_type: 9 当前道具(目前只有伪装)
     property_subtype: 道具id
     valule: 当前数量(数量<=0时除)
  property_type: 10 更新武器子弹数
     property_subtype: 武器索引
     valule: 当前数量
  property_type: 11 载具
     property_subtype: car_uniid
     valule: seat
  property_type: 23 charid
     valule: charid
  property_type: 24 技能cd时间
     property_subtype: 技能id
     valule: 技能cd时间(剩余时间)
  property_type: 25 技能次数
     property_subtype: 技能id
     valule: 当前可用次数
  property_type: 26 技能次数上限
     property_subtype: 技能id
     valule: 次数上限
  property_type: 27 载具油量
     property_subtype: 当前油量
     valule: 最大油量
  property_type: 28 绝对值属性加成
     property_subtype: 属性id
     valule: 属性绝对值
  property_type: 29 百分比属性加成
     property_subtype: 属性id
     valule: 百分比绝对值
  property_type: 30 跟随目标id
     valule: 目标id
  property_type: 31 下潜后氧气
     property_subtype: 总量
     valule: 当前量
  property_type: 32 更新技能经验(需要容错，skill_id可能在本地找不到)
     property_subtype: skill_id
     valule: 经验
*/
message MFPropertyChg
{
    optional int32 obj_id = 1; //对象id
    optional int32 property_type = 2; //属性类型
    optional int32 property_subtype = 3; //属性子类型
    optional float value = 4; //属性值
}

//碰撞体
message MFCollider
{
    optional int32 shape = 1;  //形状 1：矩形 2：圆形（当是圆形的时候width=height）
    optional int32 width = 2; //宽度
    optional int32 height = 3; //高度
}

//地图物件
message MFMapObject
{
    optional int32 object_id = 1;  //物件id(mapThing表id)
    optional MFVec2 pos = 2; //位置
}

//玩家信息
message MFPlayerInfo
{
    optional int32 player_id = 1;
    optional int32 team_id = 2;
    optional string name = 3;
}

message MFGoods
{
    optional string name = 1;
    optional int32 num = 2;
}

//视野 x1 x4 x8
message MFPlug
{
    optional string name = 1;
    optional int32 id = 2;
    optional int32 param = 3;
}

//武器
message MFWeapon
{
    optional int32 weapon_id = 1; //武器id 当weapon_id == 0时表示无装备（装备位置显示空）
    optional int32 weapon_lv = 2; //武器等级
    optional int32 ammo = 4; //弹药数
    optional int32 volume = 5; //弹夹容量
}

//皮肤
message MFSkin
{
    optional int32 skin_id = 1; //皮肤id
    optional int32 skin_lv = 2; //皮肤等级
}

//玩家信息-部分
message MFPlayerPart
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional MFVec2 dir = 3; //朝向
    optional float speed = 4; //速度
}

//属性增量
message MFAttrAddition
{
    optional int32 attr_id = 1; //属性id
    optional float abs_val = 2; //绝对值加成
    optional float rate_val = 3; //百分比
}

//玩家信息-全量
message MFPlayerFull
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional MFVec2 dir = 3; //朝向
    optional int64 guild_id = 4; //公会id

    optional float max_health = 5; //血量
    optional float health = 6; //血量
    optional bool dead = 7; //是否已死亡
    optional bool downed = 8; //是否跌倒
    optional bool disconnected = 9; //是否断网
    optional int32 anim_type = 10; //
    optional int32 anim_seq = 11; //
    //optional int32 action_type = 12; //0: none 1:reload 2:useitem 3:relive 4: rescue
    //optional int32 action_duration = 22; //持续时间毫秒
    repeated MFSkin skin = 13; //皮肤id
    optional int32 backpack = 14; //背包
    optional int32 helmet = 16; //头盔
    optional int32 chest = 17; //防弹衣
    optional MFWeapon weapon = 18; //武器
    optional int32 energy_shield = 19; //能量护盾
    optional int32 vip = 20; //vip
    optional int32 sdmg = 21;
    optional int32 max_energy_shield = 22; //最大能量护盾
    repeated MFBodyState states = 23; //角色状态
    optional int32 kill_count = 24; //击杀数
    optional int32 emoji1 = 25; //表情1
    optional int32 emoji2 = 26; //表情2
    optional int32 parachute = 27; //降落伞
    repeated MFBuff buff_list = 28; //buff列表
    optional int32 car_uniid = 29; //载具id
    optional int32 car_seat = 34; //载具-座位0-3

    optional bool can_revive = 30; //是否可复活
    optional int32 revive_countdown = 31; //复活倒计时
    optional string killer_name = 32; //杀手名称
    optional int32 killer_id = 33; //杀手id(自杀时为自己) 特殊id: -1:倒在安全区

    optional int32 vip_lv = 35 [default = 0]; //vip等级
    optional int32 head_frame = 36 [default = 0]; //头像框
    optional int32 sex = 37 [default = 0]; //性别

    repeated MFSkill skill_list = 38; //技能列表

    repeated MFAttrAddition attr_addition= 61; //属性加成
    optional int32 follow_target = 62 [default = 0]; //跟随的目标id 0: 未跟随

    optional int32 charid = 44; //人物id
    optional float speed = 45; //速度

    optional float shoot_offset_x = 50 [default = 0]; //射击偏移量-x
    optional float shoot_offset_y = 51 [default = 0]; //射击偏移量-y

    optional string user_data = 60 [default = ""]; //用户自定义数据
}

//阻挡物-部分
message MFObstaclePart
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional float scale = 3; //缩放比
}

//阻挡物-全量
message MFObstacleFull
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional float scale = 3; //缩放比
    //出生帧号 born_frameno == SMUpdate.frmanoe时表示在当前这帧出生(可能出现为0的情况比如静态物件)
    optional int32 born_frameno = 4 [default = 0];

    optional int32 obstacle_id = 6; //阻挡物id
    optional float health = 7; //血量
    optional bool dead = 8; //是否已死亡
    optional bool dead_at_thisframe = 9; //是否当前帧死亡(播放死亡特效)

    optional bool is_door = 20; //是否门
    //只有当is_door==ture时以下字段才有意义
    //门状态定义： 0:关 1:开 当door_old_state != door_new_state时播动画（开/关门）
    optional int32 door_id = 22; //门id
    optional int32 door_old_state = 23; //门前一个状态
    optional int32 door_new_state = 24; //门当前状态
    optional int32 door_house_uniid = 25; //门所属房间唯一id
    optional int32 door_house_id = 26; //门所属房间id
    optional float door_width = 27; //门宽度
    optional float door_height = 28; //门高度
    optional int32 door_open_times = 29; //门开启次数,每次开/关 ++times 0:客户端自动开
    optional string button_name = 30; //按钮名（不为空是显示按钮，靠近时显示）
    optional MFCollider collider = 31; //碰撞体（有值的时候读取没值的时候还是读取配置表里的碰撞）
}

//建筑物-部分
message MFBuildingPart
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
}

//建筑物-全量
message MFBuildingFull
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional int32 building_id = 3; //建筑物id

    optional bool ceiling_dead = 6;
}

//loot出生点-部分 补给箱
message MFLootSpawnerPart
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional int32 loot_id = 3; //id
}

//loot出生点-全量
message MFLootSpawnerFull
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional int32 loot_id = 3; //id
}

//loot-部分
message MFLootPart
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
}

//loot-全量
message MFLootFull
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional MFVec2 born_pos = 3; //出生位置
    optional bool show_anim = 4; //是否显示动画

    optional int32 item_id = 6; //道具id
    optional int32 count = 7; //数量
    optional int32 age_ms = 8;
    optional int32 item_level = 9 [default = 1]; //道具等级
}

//尸体-部分
message MFDeadBodyPart
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
}

//尸体-全量
message MFDeadBodyFull
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional int32 player_id = 3; //玩家id

    optional int32 inkjet = 6;
}

//decal-部分
message MFDecalPart
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional int32 decal_id = 3; //id
}

//decal-全量
message MFDecalFull
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional int32 decal_id = 3; //id
}

//发射体-部分
message MFProjectilePart
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional float pos_z = 3; //没用到
}

//发射体-全量
message MFProjectileFull
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional float pos_z = 3; //没用到
}

//英雄(分身)-部分
message MFHeroPart
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional MFVec2 dir = 3; //朝向

}

//英雄(分身)-全量
message MFHeroFull
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional MFVec2 dir = 3; //朝向
    optional int32 heroid = 4; //配置表id
    optional int32 master_uniid = 5; //主人id
    optional float health = 10; //血量
    optional bool dead = 11; //是否已死亡
    repeated MFBuff buff_list = 12; //buff列表
    optional float max_health = 13; //最大血量
}

//烟雾-部分
message MFSmokePart
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional float rad = 3; //半径
}

//烟雾-全量
message MFSmokeFull
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional float rad = 3; //半径
}

//载具-部分
message MFCarPart
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional MFVec2 dir = 3; //朝向
}

//载具-全量
message MFCarFull
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional MFVec2 dir = 3; //朝向
    optional int32 car_id = 4; //载具id
    optional int32 driver = 5; //驾驶员id
    optional int32 heroid = 7; //配置表id
    optional float health = 10; //血量
    optional bool dead = 11; //是否已死亡
    repeated MFBuff buff_list = 12; //buff列表
    optional float max_health = 13; //最大血量
    optional int32 oil = 14; //当前油量
    optional int32 max_oil = 15; //最大油量
    optional int32 bullet_num = 16; //子弹数量

    /*
      乘客列表（包含驾驶员）
      !!!注意这里只返回客户端必要的用于显示玩家外观的信息而不是全量信息
     */
    repeated MFPlayerFull passengers = 6;
    optional int32 seat_num = 17; //座位数
    optional int32 born_frameno = 8; //出生帧号 born_frameno == SMUpdate.frmanoe时表示在当前这帧出生
}

//对象信息-部分
message MFObjectPart
{
    //1:player 2:obstacle 3:building 4:lootspawner 5:loot 6:deadbody 7:decal 8:projectile 9:smoke 10:hero 11:car
    optional int32 object_type = 1;

    optional MFPlayerPart union_obj_1 = 2;
    optional MFObstaclePart union_obj_2 = 3;
    optional MFBuildingPart union_obj_3 = 4;
    optional MFLootSpawnerPart union_obj_4 = 5;
    optional MFLootPart union_obj_5 = 6;
    optional MFDeadBodyPart union_obj_6 = 7;
    optional MFDecalPart union_obj_7 = 8;
    optional MFProjectilePart union_obj_8 = 9;
    optional MFSmokePart union_obj_9 = 10;
    optional MFHeroPart union_obj_10 = 11;
    optional MFCarPart union_obj_11 = 12;
}

//对象信息-全量
message MFObjectFull
{
    //1:player 2:obstacle 3:building 4:lootspawner 5:loot 6:deadbody 7:decal 8:projectile 9:smoke 10:hero 11:car
    optional int32 object_type = 1;

    optional MFPlayerFull union_obj_1 = 2;
    optional MFObstacleFull union_obj_2 = 3;
    optional MFBuildingFull union_obj_3 = 4;
    optional MFLootSpawnerFull union_obj_4 = 5;
    optional MFLootFull union_obj_5 = 6;
    optional MFDeadBodyFull union_obj_6 = 7;
    optional MFDecalFull union_obj_7 = 8;
    optional MFProjectileFull union_obj_8 = 9;
    optional MFSmokeFull union_obj_9 = 10;
    optional MFHeroFull union_obj_10 = 11;
    optional MFCarFull union_obj_11 = 12;

    optional int32 obj_uniid = 14; //唯一id
    optional int32 object_flags = 15; //对象标志位 1<<0: 存缓存 1<<1：读缓存
}

//活跃玩家数据(当前)
message MFActivePlayerData
{
    optional int32 action_type = 3; //0: none 1:reload 2:useitem 3:relive 4: rescue
    optional int32 action_duration = 5; //持续时间毫秒
    optional int32 action_item_id = 6;
    optional int32 action_target_id = 7;
    /*
      action触发的帧号，当服务器下发的action_type和客户端本地的action_type相同时
      action_frameno不同也要播放对应的动画，视为同一种action_type的不同触发
    */
    optional int32 action_frameno = 1;

    repeated MFPair items = 8; //存放玩家身上携带的装备信息（目前只存伪装） key:道具id value:数量

    repeated MFSkin skin = 30; //皮肤id
    optional int32 backpack = 31; //背包
    optional int32 helmet = 32; //头盔
    optional int32 chest = 33; //防弹衣

    optional float max_health = 34; //血量
    optional float health = 35; //血量

    optional int32 cur_scope = 10; //当前视野倍数 1 2 4 8 15
    /*
      0: 9mm
      1: 556mm
      2: 762mm
      3: 12gauge
      4: rpg火药（榴弹炮）
      5: frag 手雷
      6: smoke 烟雾弹
      7: healthkit 医疗包
      8: 止痛药
      9:
      10:
      11:

      12: 1xscope
      13: 2xscope
      14: 4xscope
      15: 8xscope
      16: 15xscope
     */
    repeated int32 inventory = 11; //库存

    optional int32 cur_weapon_idx = 15; //当前武器索引 0-4
    repeated MFWeapon weapons = 16; //武器列表1-4 0：拳头 1：枪 2：枪  3：手雷 4：烟雾弹

    optional int32 energy_shield = 40; //能量护盾
    optional int32 max_energy_shield = 41; //最大能量护盾

    optional int32 spectator_count = 20;
    repeated MFBodyState states = 27; //角色状态

    repeated MFSkill skill_list = 28; //技能列表

    repeated MFAttrAddition attr_addition= 61; //属性加成
    optional string name = 62; //昵称,不为undefine的时候覆盖本地

    optional float shoot_offset_x = 50 [default = 0]; //射击偏移量-x
    optional float shoot_offset_y = 51 [default = 0]; //射击偏移量-y

    optional int32 dive_oxygen_max = 63; //下潜时氧气总量
    optional int32 dive_oxygen_curr = 64; //下潜时氧气当前量
}

//毒圈数据
message MFGasData
{
    /*
      0: 进入战前准备
      3：跳伞状态
      1: 辐射区将在多少时间后扩大
      2: 辐射区正在扩大
     */
    optional int32 mode = 1; //0:inactive 1:waiting 2:moving 3:jump
    optional float duration = 2; //持续时间(秒)
    optional MFVec2 pos_old = 3; //前一个圆心
    optional MFVec2 pos_new = 4; //新圆心
    optional float rad_old = 5; //前一个圆半径
    optional float rad_new = 6; //新圆半径
}

//队伍数据
message MFTeamData
{
    optional int32 team_id = 61; //队伍Id
    optional int32 player_id = 1; //玩家id
    optional MFVec2 pos = 2; //位置
    optional MFVec2 dir = 3; //方向
    optional float health = 4; //血量
    optional bool disconnected  = 5 [default = false]; //是否短线
    optional bool dead = 6 [default = false]; //是否死亡
    optional bool downed = 7 [default = false]; //是否倒下
    optional string name = 8; //名字
    optional float max_health = 9; //最大血量
    optional bool riding = 40 [default = false]; //是否倒 下
    optional string user_data = 60 [default = ""]; //用户自定义数据（只同步一次）
    optional int32 can_follow = 62 [default = 0]; //是否可跟随

    //一下字段只在结算的时候该字段才有内容
    optional string account_id = 10; //账号id
    optional string avatar_url = 11; //头像
    optional int64 user_value1 = 31; //对应好友系统的user_value1
    optional int64 user_value2 = 32; //对应好友系统的user_value2
    optional int64 user_value3 = 33; //对应好友系统的user_value3
    optional int64 guild_id = 34; //公会id
    optional int32 vip_lv = 35 [default = 0]; //等级
    optional int32 head_frame = 36 [default = 0]; //头像框
    optional int32 sex = 37 [default = 0]; //性别
    repeated MFSkin skin = 39; //皮肤id
}

//子弹
message MFBullet
{
    optional int32 player_id = 1; //玩家id
    optional int32 bullet_id = 2; //子弹id
    optional MFVec2 pos = 3; //位置
    optional MFVec2 dir = 4; //方向
    optional int32 gun_lv = 5; //枪等级
    optional int32 bulletskin = 6; //子弹皮肤 未用到
    optional bool crit = 7;
    optional int32 reflect_count = 8;
    optional int32 reflect_objid = 9;
    optional int32 gun_id = 10; //枪id
    optional float fly_distance = 11; //只有手雷和烟雾弹时这个字段才有意义
    optional int32 bullet_uniid = 12; //子弹唯一id
}

//射击
message MFShot
{
    optional int32 player_id = 1; //玩家id
    optional MFWeapon weapon = 2; //武器id
    optional bool offhand = 3; //没用的
    optional int32 bullskin = 4; //没用到
    optional int32 hole = 5 [default = 0]; //炮孔(从0开始)
}

//爆炸
message MFExplosion
{
    optional int32 item_id = 1; //配置表id
    optional MFVec2 pos = 2; //位置
    optional int32 player_id = 3; //玩家id
    optional int32 effect = 4 [default = 0]; //爆照效果 0：普通爆照 1:核爆炸
}

//烟雾
message MFSmoke
{
    optional int32 item_id = 1; //配置表id
    optional MFVec2 pos = 2; //位置
    optional int32 player_id = 4; //玩家id
    optional float time_addition = 5; //烟雾弹时间加成(单位毫秒)
}

//表情
message MFEmote
{
    optional int32 emote_id = 1; //表情id
    optional int32 player_id = 3; //玩家id
    optional string msg = 5;
}

//游戏结束时玩家统计信息
message MFPlayerStats
{
    optional int32 player_id = 1; //玩家id
    optional string player_avatar_url = 2; //玩家头像

    //本次成绩
    optional int32 time_alive = 3; //存活时间(毫秒)
    optional int32 kills = 4; //击杀敌人数
    optional int32 damage_amount = 8; //伤害总量
    optional int32 heal_amount = 20; //治疗总量
    //历史最佳成绩
    optional int32 history_time_alive = 30; //存活时间(毫秒)
    optional int32 history_kills = 31; //击杀敌人数
    optional int32 history_damage_amount = 32; //伤害总量
    optional int32 history_heal_amount = 33; //治疗总量

    optional int32 gold = 10; //金币
    optional int32 score = 11; //积分
    repeated MFPair items = 6; //奖励道具 key:item_id value:数量
    optional int32 pass_score = 9; //通行证积分
    optional int32 rank_score = 13; //排名积分
    optional bool has_pass = 27; //是否有通行证

    repeated MFPair extra_drop = 12; //额外掉落,key:item_id value:数量(看广告)

    optional bool dead = 5; //是否已死亡
    optional int32 killer_id = 7; //杀手id(自杀时为自己) 特殊id: -1:倒在安全区
    optional string killer_name = 40; //杀手名称
    optional string killer_avatar_url = 41; //杀手头像（机器人头像为空）
    optional string killer_account_id = 42; //杀手accountid(机器人为空)

    optional string account_id = 21; //账号id
    optional int64 guild_id = 22; //公会id
    optional int32 rescue_guild_member = 23; //救起公会成员次数

    optional int32 vip_lv = 35 [default = 0]; //等级
    optional int32 head_frame = 36 [default = 0]; //头像框
    optional int32 sex = 37 [default = 0]; //性别
    optional int32 charid = 38; //人物id
    optional int32 team_id = 39; //tamid
    optional string nickname = 43; //昵称

    repeated MFSkin skin = 45; //皮肤id
}

//空投
message MFAirDrop
{
    optional int32 appear_time = 1; //箱子出现时间(毫秒)
    optional int32 box_id = 2; //箱子id
    optional MFVec2 pos = 3; //位置
}

//空袭
message MFAirRaid
{
    optional int32 appear_time = 1; //空袭出现时间(毫秒)
    optional MFVec2 pos = 3; //空袭位置
    optional float rad = 4; //空袭半径
}

//buff
message MFBuff
{
    optional int32 buff_id = 1; //buff id
    optional float left_time = 2; //剩余时间(单位毫秒)
    optional float lasting_time = 3; //持续时间(总时间毫秒)
    repeated float params = 4; //当是驾驶员或者乘客状时 params[0]:car_id
    optional int32 buff_uniid = 5; //buff唯一id
}

//buff变更
message MFBuffChg
{
    optional int32 obj_id = 1; //对象id
    optional int32 chg = 2; //0:新增/更新 1:删除
    optional MFBuff buff = 3; //buff
}

//对象状态(只同步一次客户端自己到及时，有变化时服务器会再次下发)
message MFBodyState
{
    /*
      1: 止痛药持续加血
      2: 在飞机上(这时left_time、lasting_time无意义)
      3: 跳伞中

      4: 隐身中(队友可见)
      5: 加速中
      6: 伤害加深
      7: 护盾
      8: 回血
      9: 反伤
      10: 分身
      11：攻击加成
     */
    optional int32 state_type = 1;
    optional float left_time = 2; //剩余时间(单位毫秒)
    optional float lasting_time = 3; //持续时间(总时间毫秒)
}

//飞机
message MFPlane
{
    optional MFVec2 start_point = 1; //飞机起点
    optional MFVec2 end_point = 2; //飞机终点
    optional MFVec2 pos = 3; //飞机当前位置
}

//载具信息（用于小地图显示）
message MFMapCarInfo
{
    optional int32 car_id = 1; //载具id(读equip表)
    optional MFVec2 pos = 2; //载具坐标
}

//队友信息
message MFTeamMember
{
    optional string account_id = 1; //账号id
    optional int32 rank = 2; //段位
    optional bool is_leader = 3; //是否队长
    optional int32 game_times = 4; //游戏次数
    optional int32 win_times = 5; //吃鸡次数
    optional int32 kill_times = 6; //击杀数
    optional int32 create_time = 7; //账号创建时间
}

//位置信息
message MFPosition
{
    optional int32 obj_uniid = 1; //唯一id
    optional MFVec2 pos = 2; //位置
    optional MFVec2 dir = 3; //朝向
    optional int32 race = 4; //1:人 2:僵尸
}

message MFSkill
{
    optional int32 skill_id = 1; //技能id
    optional int32 left_time = 2; //技能cd时间(剩余时间)
    optional int32 cd_time = 3; //技能cd时间(总时间)
    optional int32 curr_times = 4; //当前可用次数
    optional int32 max_times = 5; //次数上限
    optional int32 exp = 7; //当前经验
    optional int32 max_exp = 8; //经验上限(当满级以后exp=0 max_exp=0)
}

message MFPlaySkill
{
    optional int32 obj_uniid = 1; //技能id
    optional int32 skill_id = 2; //技能id
}

message MFTextElement
{
    optional string text = 1; //文本内容
    optional int32 color = 2 [default = 0xFFFFFF]; //默认系统颜色rgb
}

message MFImageElement
{
    optional int32 id = 1; //装备id
}

message MFRichTextElement
{
    //1:TextElement 2:ImageElement
    optional int32 element_type = 1; //富文本类型
    optional MFTextElement union_obj_1 = 2; //文本元素
    optional MFImageElement union_obj_2 = 3; //图片元素
}

message MFMatchTeamMember
{
    optional string account_id = 1; //账号id account_id
    optional string name = 2; //角色名
    optional string avatar_url = 3; //头像
    optional int32 hero_id = 4; //英雄id
    repeated MFWeapon weapons = 5; //武器列表
    repeated MFSkin skins = 6; //皮肤列表 key: 皮肤id value:皮肤等级
    repeated MFPair skill_list = 7; //技能列表 key:技能id value:预留给之后扩展,目前传0就行
    optional bool is_leader = 8; //是否队长
    optional int32 state = 9; //0:准备 1:已准备
    optional int32 head_frame = 10; //头像框
    repeated int32 baseskin = 11; //皮肤id
    optional int32 hero_skin = 12; //英雄皮肤
}

//该消息每秒同步
message MFMatchInfo
{
    repeated MFMatchTeamMember members = 1; //成员列表
    optional int32 phase = 2; //阶段 1:合并队伍(匹配中) 2：选择角色 3:锁定（已准备）
    optional int32 countdown = 3; //倒计时(单位秒)
    optional int32 predict_time = 4; //预计时间(单位秒)
}

//end mfmsg

//加入
message CMJoin
{
    optional int32 server_id = 1; //serverid
    optional string team_uuid = 2; //队伍唯一id (没组队时为空字符串)
    optional string account_id = 3; //账号id account_id
    optional int32 team_mode = 4; //队伍模式 0:单人 1:多人
    optional int32 proto_version = 5; //协议版本号Constant_e.ProtoVersion
    optional bool auto_fill = 6; //是否自动填充玩家
    optional int32 bot = 7; //是否机器人
    optional string name = 8; //角色名
    optional bool use_touch = 9; //zzz
    repeated int32 emotes = 10; //表情列表
    optional string avatar_url = 11; //头像
    optional int32 energy_shield = 12; //能量护盾
    repeated int32 baseskin = 13; //皮肤id
    optional int32 basemelee = 14; //xx
    repeated int32 buff_list = 15; //周边系统带进来的战斗数据（护盾，立刻复活等）
    repeated MFWeapon weapons = 17; //武器列表
    repeated MFSkin skins = 18; //皮肤列表 key: 皮肤id value:皮肤等级
    repeated int32 prepare_items = 19; //战斗前准备道具 战前准备护盾存到energy_shield
    repeated MFPair prepare_items2 = 29; //战斗前准备道具 key:道具id value:数量
    optional string session_id = 20; //session_id
    optional string from_appid = 21; //from_appid
    optional float atk_add = 22; //攻击加成,废弃!!!
    optional string pre_settlement_info = 23; //透传game2001api预结算信息(为了本地结算用)
    optional int32 emoji1 = 24; //表情1
    optional int32 emoji2 = 25; //表情2
    optional int32 parachute = 26; //降落伞
    optional bool has_pass = 27; //是否有通行证
    optional int32 today_enter_times = 28; //今天进入游戏的次数
    repeated MFWeapon grow_weapons = 30; //武器养成
    optional int64 user_value1 = 31; //对应好友系统的user_value1
    optional int64 user_value2 = 32; //对应好友系统的user_value2
    optional int64 user_value3 = 33; //对应好友系统的user_value3
    optional int64 guild_id = 34; //公会id
    optional int32 vip_lv = 35 [default = 0]; //等级
    optional int32 head_frame = 36 [default = 0]; //头像框
    optional int32 sex = 37 [default = 0]; //性别
    optional bool force_entry_newbie_room = 50; //是否强制进新手房
    repeated MFTeamMember team_members = 51; //包括自己
    optional int32 room_mode = 52; //0:吃鸡模式 1:匹配赛模式
    optional int32 mapid = 53; //地图id 0:随机地图
    repeated MFPair skill_list = 54; //技能列表 key:技能id value:预留给之后扩展,目前传0就行
    optional string user_data = 60 [default = ""]; //用户自定义数据
    optional int32 hero_id = 61; //英雄id
    repeated MFPair talent_list = 64; //天赋列表 key:天赋id value:天赋等级
    /*
      是否显示队伍界面(回传getSwitch返回的结果)
      1:显示队伍界面
      注意！！！就算客户端传了show_team_ui=1服务器也会根据一下条件满足才会走新逻辑，客户端也应在本地做一下判断
      show_team_ui() && team_mode() == 1 && auto_fill() && team_members().size() < 4
      当服务器判断确实需要显示组队UI时回复SMShowTeamUI，否则正常进游戏
    */
    optional int32 show_team_ui = 62;
    optional int32 hero_skin = 63; //英雄皮肤
    optional string pre_battle_payload = 70; //透传api战前校验信息

    optional string hero_uniid = 71; //英雄唯一id
}

//断线重连
message CMReconnect
{
    optional int32 server_id = 1; //保留
    optional string team_uuid = 2; //保留
    optional string account_id = 3; //账号id
    optional string session_id = 4; //session_id
    optional string room_uuid = 5; //房间唯一id
    optional string server_info = 6; //服务器信息
}

//断线重连回复
message SMReconnect
{
    optional int32 errcode = 1; //错误码 0：成功 1:重连失败
    optional string errmsg = 2; //错误描述
}

//移动
message CMMove
{
    optional int32 seq = 1; //序号

    optional MFVec2 move_dir = 2; //移动-方向
    optional MFVec2 attack_dir = 3; //攻击方向(朝向)

    optional bool shot_start = 4; //射击-单发
    optional bool shot_hold = 5; //射击-连发
    optional bool reload = 6; //装弹
    optional float fly_distance = 7; //子弹飞行距离(只有手雷和烟雾弹时这个字段才有意义)

    optional int32 select_weapon = 8; //切换武器(没切换是不用发)
    optional int32 drop_weapon = 9; //丢弃武器

    optional bool cancel_action = 10; //取消当前操作(比如取消使用道具装弹等)
    optional int32 use_item_idx = 11; //使用道具（对应库存索引0-16）
    optional int32 use_item_id = 12; //使用道具 (道具id目前只有伪装)
    optional int32 use_scope = 13; //使用倍镜 0-4

    optional bool interaction = 14; //是否有交互
    repeated int32 interaction_objids = 15; //交互的对象id列表
    optional bool aiming = 16; //是否瞄准中

    optional bool use_skill = 17; //使用技能
    optional int32 skill_id = 18; //技能id
    optional int32 skill_target_id = 19; //技能目标(单体攻击)
    optional MFVec2 skill_dir = 20; //技能方向
    optional float skill_distance = 21; //技能目标距离
    optional float skill_param1 = 22; //辅助参数

    optional bool spectate = 30; //自杀

    optional int32 emote = 31; //表情id

    optional bool jump = 32; //跳伞
    optional bool get_down = 33; //下车
    /*上车
      loot的uniid或者队友的uniid
      注意：当客户端同时发了下车和上车的时候服务器只处理上车，忽略下车
     */
    optional int32 get_on = 36;
    optional int32 switch_seat = 37; //切换座位

    optional int32 follow = 38; //跟随0:取消跟随 其他：玩家uniid

    optional int32 dive = 39; //下潜
}

//执行GM指令
message CMExecCommand
{
    optional string cmd = 1; //指令
}

//丢弃道具
message CMDropItem
{
    optional int32 item_id = 1; //道具id
    optional int32 weapon_idx = 2; //武器索引 0-4
}

//发送表情
message CMEmote
{
    optional int32 type = 1;
    optional MFVec2 pos = 2;
    optional bool team_only = 4;
}

//语音
message CMVoice
{
    optional string download_url = 2; //语音下载地址
}

//请求结算
message CMGameOver
{
}

//请求观战
message CMWatchWar
{

}

//离开 在飞机起飞前视为：逃跑 起飞后视为自杀
message CMLeave
{

}

//复活死亡后15秒内,如果超过15秒服务器发SMGameOver
message CMRevive
{
}

//取消复活
message CMCancelRevive
{
}

//开始播放广告(服务器收到消息后会添加一个看广告中的buff)
message CMAdStart
{
}

//取消看广告(用户中途取消看广告)
message CMAdCancel
{
}

//广告播放完毕(玩家看完广告)
message CMAdEnd
{
    optional int32 param = 1; //1:屠夫 2：南瓜
}

//获取宝箱信息
message CMGetBoxInfo
{
    optional int32 box_id = 1; //1：战前宝箱
}

//获取宝箱信息
message CMOpenBox
{
    optional int32 box_id = 1; //1: 战前宝箱
}

//组队匹配-取消
message CMMatchCancel
{
}

//组队匹配-选取英雄
message CMMatchChoose
{
    optional int32 hero_id = 1; //英雄id
    repeated MFWeapon weapons = 2; //武器列表
    repeated MFSkin skins = 3; //皮肤列表 key: 皮肤id value:皮肤等级
    repeated MFPair skill_list = 4; //技能列表 key:技能id value:预留给之后扩展,目前传0就行
    repeated int32 baseskin = 5; //皮肤id
    optional int32 hero_skin = 6; //头像框
}

//组队匹配-出击
message CMMatchStartGame
{
}

//组队匹配-出击
message CMMatchCancelStartGame
{
}

//组队匹配-指定成员发送消息
message CMMatchSendMsg
{
    //成员将收到SMMatchMemberMsgNotify消息
    repeated string target_list = 1; //目标列表,目标收到SMMatchMemberMsgNotify消息
    optional string content = 2; //消息内容
}

//组队匹配-队伍内广播消息
message CMMatchBroadcastMsg
{
    //成员将收到SMMatchMemberMsgNotify消息
    optional int32 exclude_self = 1; //include_self!=0时排除自己
    optional string content = 2; //消息内容
}

//endcmmsg

//观战error_code == 0 时关闭结算界面,回到战斗界面
message SMWatchWar
{
    optional int32 error_code = 1 [default = 0]; //错误码 0:成功 1:失败
    optional string error_msg = 2; //错误信息
    optional string name = 3; //昵称
}

//加入成功
message SMJoinedNotify
{
    optional int32 team_mode = 1; //队伍模式 0:单人 1:多人
    optional int32 player_id = 2; //玩家id(自己) 已经废弃移动到SMMapInfo
    optional bool started = 3; //游戏是否已开始 已经废弃移动到SMMapInfo
    optional string room_uuid = 4; //房间唯一id 已经废弃移动到SMMapInfo

    optional int32 map_type = 5; //目前没用到
    optional bool elo_start = 6; //目前没用到

    optional int32 error_code = 7; //错误 1:服务器维护中 2：服务器繁忙请稍后再进入
    optional int32 room_mode = 8; //0:吃鸡模式 1:僵尸模式

    optional string server_info = 9; //服务器信息（重连时使用） 已经废弃移动到SMMapInfo
}

//地图信息
message SMMapInfo
{
    optional int32 map_id = 1; //地图id
    optional float map_width = 2; //地图宽度
    optional float map_height = 3; //地图高度
    repeated MFMapObject objects = 6; //地图对象
    optional int32 player_id = 7; //玩家id(自己)
    optional bool started = 8; //游戏是否已开始
    optional string room_uuid = 9; //房间唯一id
    optional string server_info = 10; //服务器信息（重连时使用）
}

//玩家信息
message SMPlayerInfo
{
    optional MFPlayerInfo info = 1; //玩家信息
}

//帧事件
message SMUpdate
{
    repeated int32 out_objids = 1; //对象-移出视野
    repeated int32 del_objids = 2; //对象-待删除
    repeated MFObjectFull full_objects = 3; //对象-全量(出现在视野)
    repeated MFObjectPart part_objects = 4; //对象-部分(用于插值更新)
    optional int32 active_player_id = 5; //当前活跃玩家id(如果玩家死亡后是观战对象的id)
    optional MFActivePlayerData active_player_data = 6; //活跃玩家数据(如果玩家死亡后是观战对象的数据)
    optional int32 alive_count = 15; //存活数量
    optional int32 gas_progress = 16; //毒圈进度,表示缩进的像素数(只有当gas_data.mode == moving时才会发进度)
    optional MFVec2 gas_pos_old = 30; //毒圈当前圆心坐标
    optional MFGasData gas_data = 17; //毒圈数据
    repeated MFTeamData team_data = 18; //队伍数据
    repeated MFBullet bullets = 20; //子弹
    repeated MFShot shots = 21; //射击
    repeated MFExplosion explosions = 22; //爆炸
    repeated MFSmoke smokes = 25; //烟雾
    repeated MFEmote emotes = 23; //表情
    optional MFAirDrop airdrop = 26; //空投
    optional MFPlane plane = 27; //飞机
    repeated MFBuffChg chged_buff_list = 28; //buff变更列表
    repeated MFPropertyChg chged_property_list = 31; //property变更列表
    repeated MFPlaySkill play_skill_list = 32; //播放技能
    optional MFAirRaid airraid = 33; //空袭

    repeated MFTuple dead_alive_objs = 42; //玩家values[0]:objid values[1]:多少毫秒后复活 values[2]: 0:死亡 1:复活
    //一下字段只有僵尸模式才有效
    repeated MFPosition object_positions = 43; //对象坐标信息,如果对象已经在part_objects则可能不发,这时客户端可以读取part_objects里的左边更新小地图
    optional int32 game_left_time = 45; //游戏剩余时间(毫秒, 战斗开始后字段才有意义)
    optional int32 frameno = 46;
    repeated int32 del_bullets = 47; //子弹删除
}

//滚动消息
message SMRollMsg
{
    repeated MFRichTextElement elements = 1; //富文本信息
}

//个人信息统计
message SMPlayerStats
{
    optional MFPlayerStats player_stats = 1;
}

//游戏结束
message SMGameOver
{
    optional int32 team_id = 1; //队伍id
    optional int32 team_rank = 2; //队伍排名
    optional int32 team_allcnt = 3;
    optional bool game_over = 4; //是否结束
    optional bool victory = 5; //是否胜利
    optional int32 total_human_num = 12; //房间总人数
    optional int32 alive_human_num = 13; //房间剩余存活人数
    optional int32 watchable = 8; //是否可观战

    repeated MFPlayerStats player_stats = 6; //玩家信息统计
    optional string room_uuid = 7; //房间唯一id
    repeated MFTeamData team_data = 10; //队伍数据
    repeated MFTuple spoils_items = 11; //战利品 0: 道具id 1:道具数量
}

//离开
message SMLeave
{
}

//获取宝箱信息回复
message SMGetBoxInfo
{
    optional int32 box_id = 1; //1：战前宝箱
    repeated MFTuple items = 2; //values[0]:道具id values[1]:道具数量
}

//开宝箱回复
message SMOpenBox
{
    optional int32 box_id = 1; //1: 战前宝箱
    optional int32 errcode = 2; //错误码
    optional string errmsg = 3; //错误描述
    repeated MFTuple items = 4; //values[0]:道具id values[1]:道具数量
}

//断线通知
message SMDisconnectNotify
{
    optional string reason = 1; //断线原因
}

//语音通知
message SMVoiceNotify
{
    optional string account_id = 2; //唯一id
    optional string download_url = 3; //语音下载地址
}

//调试信息
message SMDebugMsg
{
    optional string debug_msg = 3; //调试信息
}

/*
  微信实时语音房间
  客户端需要调用loginserver签名后再加入微信实时语音房间
*/
message SMWxVoip
{
    optional string group_id = 1; //微信语聊房间id
}

//ui界面更新，一些不需要实时更新的数据
message SMUiUpdate
{
    optional int32 alive_count = 1; //存活数量
    optional int32 kill_count = 2; //击杀数
    repeated MFMapCarInfo car_list = 3; //载具列表

    //一下字段只有在僵尸模式有效
    optional int32 zombie_num = 10; //僵尸数
    optional int32 human_num = 11; //人类数
}

//游戏开始
message SMGameStart
{
}

//系统飘字
message SMSysPiaoMsg
{
    optional string msg = 1; //消息内容
    optional int32 color = 2; //字体颜色rgb
    optional int32 duration = 3; //持续时间（毫秒）
}

//线上倒计时面板
message SMShowCountdown
{
    optional string msg = 1; //消息内容
    optional int32 countdown = 2; //倒计时(单位秒),倒计时用来替换msg里的%d标识
    optional int32 msg_type = 3; //保留字段
}

//显示匹配队伍ui
message SMShowTeamUI
{
}

//更新匹配信息
message SMUpdateMatchInfo
{
    optional MFMatchInfo info = 1; //匹配信息
}

//匹配-队伍成员消息
message SMMatchMemberMsgNotify
{
    optional string sender = 1; //消息发送者
    optional string content = 2; //消息内容
}

//获得物品
message SMGetItemNotify
{
    repeated MFPair items = 8; //key:道具id value:数量
}