#!/usr/bin/python # -*- coding: UTF-8 -*- # 从proto文件中提取数据到lua 目前只有GameCs.proto import os import re import codecs import string import time import getpass import shutil CurDir = os.getcwd() ProtoName = "../protocol/GameCs.proto" # ProtoBytesName = "GameCs.proto.bytes" FileHead = "using System.Collections.Generic;\nusing ProtoCSClass;\nusing xFrame.NetWork;\nusing Type = System.Type;\nnamespace Proto{\n" ClassHead = "\npublic class NetMsgs{\n\tpublic Dictionary msgMap = new Dictionary(3000);\n\tpublic NetMsgs(){\n\t\t" FileFoot = "\n}}" # ConstDir = CurDir + "/../../client/client/Assets/Lua/Const" ProtocolDir = "../../client/client/Assets/Protocol/" MsgFileName = "NetMsgs.cs" MsgFilter = ["CS_MSGID_NONE", "CS_GAMEMSGID_NONE", "SC_GAMEMSGID_NONE"] def getFileData(fileName): data = None with open(fileName, encoding='UTF-8') as f: data = f.read() return data def fileWrite(fileName, data): with codecs.open(fileName, "w", "utf8") as f: # timeStr = "-- build by:" + getpass.getuser() + " " + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + "\n" f.write(FileHead + data + FileFoot) return # 获取SC_GAMEMSGID_ENTER_DESK_NOTIFY = 3001 def getMsgIDStr(data, keyword): content = re.findall(r"\s+" + keyword + r"\s*{([^{}]*)}", data) if len(content) > 0: lines = content[0].split("\n") # 逐行 lineList = [] # del_list = [] for line in lines: # lineList = re.findall(r"(/*\s*\w+\s*=\s*\d+)", content[0]) val = line pos = line.find("//") if pos != -1: # 截取注释 val = line[0:pos] ss = re.findall(r"(\w+\s*=\s*\d+)", val) if len(ss) > 0: s = ss[0] if s.find(MsgFilter[0]) == -1 and s.find(MsgFilter[1]) == -1 and s.find(MsgFilter[2]) == -1: # 注释掉的协议剔除 lineList.append(s) return lineList def getEnumKeyList(data): enumKeyList = re.findall(r"enum\s+(\w+)", data) delEnumKeyList = re.findall(r"/{2,}[\t\r\f ]*enum\s+(\w+)", data) for s in delEnumKeyList: try: enumKeyList.remove(s) except ValueError: pass return enumKeyList # 获取枚举和消息ID类型 def getEnumData(data): msgValueMap = {} msgRegex = r"([\w_]+)\s?=\s?(\d+)" enumKeyList = getEnumKeyList(data) msgIdData = "public enum ClientMsgId{" enumData = "" for key in enumKeyList: if key.find("MsgID") != -1: msgIdData = msgIdData + "\n// " + key + '\n' for s in getMsgIDStr(data, key): msgKeyValue = re.findall(msgRegex, s) for pair in msgKeyValue: msgValueMap[pair[0]] = int(pair[1]) msgIdData = msgIdData + s + ',\n' msgIdData = msgIdData + '\n' else: _str = "public enum " + key + "{\n" for s in getMsgIDStr(data, key): _str = _str + '\t' + s + ',\n' _str = _str + '}\n\n' # enumData = enumData + _str for key in msgValueMap: if key.find("REQ") != -1: resKey = key.replace("REQ", "RES") if msgValueMap.get(resKey): if msgValueMap[key] + 1 != msgValueMap[resKey]: print(key, "请求和响应的消息ID不连续,需要修正") else: print(key, "没有响应消息") return enumData + msgIdData + "}" # 获取消息ID与消息名对应的值 ''' 通过//注释匹配 支持多ID对应一个消息 //CS_MSGID_PING //CS_GAMEMSGID_PING message CSPing { int64 clientTime = 1; int64 serverTime = 2; } ''' messageRe = re.compile(r"message\s*(\w+)\s*{") def getMessageByMsgID(data, msgID): idSearch = re.search(r"//[ \t]*" + msgID + r"\W", data) if idSearch: msgNameSearch = messageRe.search(data, idSearch.span()[1]) if msgNameSearch: return msgNameSearch.group(1) return "" # def normalName(name) def getMsgName(data): msgIdList = re.findall(r"enum\s+(\w+MsgID)", data) undefined = "/*\n" msgData = "\n" for key in msgIdList: for s in getMsgIDStr(data, key): nameSearch = re.search(r"(\w+)\s*=", s) if nameSearch: name = nameSearch.group(1) msg = getMessageByMsgID(data, name) if len(msg) == 0: log = name + " not found the annotation!" undefined = undefined + log + '\n' print(log) else: msgData = msgData + ("\tmsgMap.Add((int)ClientMsgId.%s, typeof(%s));\n") % (name, msg) undefined = undefined + "*/" msgData = msgData + "}" return undefined + "\n" + msgData if __name__ == '__main__': protoc = os.path.join(CurDir, "protoc") protoc = os.path.join(protoc, "protoc.exe") protocolFile = os.path.join(CurDir, ProtoName) # print("protoc", protoc) # if not os.path.exists(ProtocolDir): # os.makedirs(ProtocolDir) # # shutil.copy(protocolFile, os.path.join(ProtocolDir, ProtoName)) # shutil.copy(protocolFile, os.path.join(ProtocolDir, ProtoBytesName)) # cmd = "%s ./%s --csharp_out=%s" % (protoc, ProtoName, ProtocolDir) # os.system(cmd) fileData = getFileData(protocolFile) enumData = getEnumData(fileData) msgNameData = getMsgName(fileData) fileWrite(os.path.join(ProtocolDir, MsgFileName), enumData + ClassHead + msgNameData)