You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
6.9 KiB
201 lines
6.9 KiB
1 month ago
|
#!/usr/bin/python
|
||
|
#-*- coding:UTF-8 -*-
|
||
|
import os
|
||
|
import re
|
||
|
import codecs
|
||
|
import shutil
|
||
|
current_dir = os.getcwd()
|
||
|
generated_dir = current_dir+"/../../pandora_cli_proj/pandora/Assets/Lua/Const/"
|
||
|
base_type_map = {
|
||
|
"string":"string",
|
||
|
"int32":"Int32",
|
||
|
"int64":"Int64",
|
||
|
"bool":"bool",
|
||
|
"uint32":"UInt32",
|
||
|
"uint64":"UInt64",
|
||
|
"bytes":"byte[]"
|
||
|
}
|
||
|
base_default_value = {
|
||
|
"string":"''",
|
||
|
"int32":"0",
|
||
|
"int64":"0",
|
||
|
"bool":"false",
|
||
|
"uint32":"0",
|
||
|
"uint64":"0",
|
||
|
"bytes":"nil"
|
||
|
}
|
||
|
class MessageClass:
|
||
|
def __init__(self,name,fields,enumnames):
|
||
|
self._class_name = name
|
||
|
self._fields = fields
|
||
|
self._enumnames = enumnames
|
||
|
def generate(self):
|
||
|
constructor = """
|
||
|
function New{0}()
|
||
|
local result = {{}}{1}
|
||
|
return result
|
||
|
end"""
|
||
|
parse_body = ""
|
||
|
base_type_line_template = """
|
||
|
result.{0} = msgData.{0}"""
|
||
|
base_type_list_line_template = """
|
||
|
result.{0} = {{}}
|
||
|
rawList = msgData.{0}
|
||
|
for i = 1,rawList:len() do
|
||
|
table.insert(result.{0},rawList:get(i))
|
||
|
end"""
|
||
|
high_type_line_template = """
|
||
|
result.{0} = Parse{1}(msgData.{0})"""
|
||
|
high_type_list_line_template = """
|
||
|
result.{0} = {{}}
|
||
|
rawList = msgData.{0}
|
||
|
for i = 1,rawList:len() do
|
||
|
table.insert(result.{0},Parse{1}(rawList:get(i)))
|
||
|
end"""
|
||
|
for field in self._fields:
|
||
|
type_name = field["type"]
|
||
|
origin_field_name = field["name"]
|
||
|
isBase = base_type_map.get(type_name) != None
|
||
|
if isBase:
|
||
|
type_name = base_type_map.get(type_name)
|
||
|
if field["isList"]:
|
||
|
if isBase:
|
||
|
parse_body = parse_body+base_type_list_line_template.format(origin_field_name)
|
||
|
else:
|
||
|
parse_body = parse_body + high_type_list_line_template.format(origin_field_name,type_name)
|
||
|
else:
|
||
|
if isBase:
|
||
|
parse_body = parse_body+base_type_line_template.format(origin_field_name)
|
||
|
else:
|
||
|
parse_body = parse_body+high_type_line_template.format(origin_field_name,type_name)
|
||
|
|
||
|
new_body = ""
|
||
|
base_type_line_template = """
|
||
|
result.{0} = {1}"""
|
||
|
base_type_list_line_template = """
|
||
|
result.{0} = {{}}"""
|
||
|
high_type_line_template = """
|
||
|
result.{0} = New{1}()"""
|
||
|
high_type_list_line_template = """
|
||
|
result.{0} = {{}}"""
|
||
|
for field in self._fields:
|
||
|
type_name = field['type']
|
||
|
origin_field_name = field['name']
|
||
|
isBase = base_type_map.get(type_name)!=None
|
||
|
# if isBase:
|
||
|
# type_name = base_type_map.get(type_name)
|
||
|
if field['isList']:
|
||
|
if isBase:
|
||
|
new_body = new_body+base_type_list_line_template.format(origin_field_name)
|
||
|
else:
|
||
|
new_body = new_body+high_type_list_line_template.format(origin_field_name)
|
||
|
else:
|
||
|
isEnum = self._enumnames.count(type_name) > 0
|
||
|
if isBase or isEnum:
|
||
|
value = base_default_value.get(type_name)
|
||
|
if isEnum:
|
||
|
value = "0"
|
||
|
new_body = new_body+base_type_line_template.format(origin_field_name,value)
|
||
|
else:
|
||
|
new_body = new_body+high_type_line_template.format(origin_field_name,type_name)
|
||
|
constructor = constructor.format(self._class_name,new_body)
|
||
|
return constructor
|
||
|
def load_file_data(filename):
|
||
|
data = None
|
||
|
with open(filename, 'r', encoding='UTF-8') as handle:
|
||
|
data = handle.read()
|
||
|
return data
|
||
|
def save_file_data(filename,data):
|
||
|
with codecs.open(filename,"w","utf8") as handle:
|
||
|
handle.write(data)
|
||
|
def delete_comments(content):
|
||
|
comment_regex = re.compile(r'//.*\n')
|
||
|
content = comment_regex.sub("\n",content)
|
||
|
return content
|
||
|
def parse_property(property):
|
||
|
property = property.lstrip(' ')
|
||
|
property = property.lstrip('\t')
|
||
|
components = property.split(' ')
|
||
|
components = [str.replace(" ","") for str in components]
|
||
|
components = [str for str in components if len(str) > 0]
|
||
|
result = {"type":components[0],"name":components[1],"isList":False}
|
||
|
if components[0] == 'repeated':
|
||
|
result["type"] = components[1]
|
||
|
result["name"] = components[2]
|
||
|
result["isList"] = True
|
||
|
return result
|
||
|
def parse_field(field):
|
||
|
components = field.split(' ')
|
||
|
components = [str for str in components if len(str)>0]
|
||
|
return {"name":components[0],"value":components[2]}
|
||
|
def parse_message(message):
|
||
|
linebreak_regex = re.compile(r'[\r|\n]')
|
||
|
table_regex = re.compile(r'\t')
|
||
|
message = linebreak_regex.sub('',message)
|
||
|
message = table_regex.sub(' ',message)
|
||
|
fields = message.split(';')
|
||
|
results = []
|
||
|
for field in fields:
|
||
|
blank_regex = re.compile(' ')
|
||
|
blank_match = blank_regex.findall(field)
|
||
|
if len(field) > len(blank_match):
|
||
|
results.append(parse_property(field))
|
||
|
return results
|
||
|
def parse_enum(enum):
|
||
|
linebreak_regex = re.compile(r'[\t\n]')
|
||
|
enum = linebreak_regex.sub('',enum)
|
||
|
fields = enum.split(';')
|
||
|
results = []
|
||
|
for field in fields:
|
||
|
blank_regex = re.compile(r' ')
|
||
|
blank_match = blank_regex.findall(field)
|
||
|
if len(field) > len(blank_match):
|
||
|
results.append(parse_field(field))
|
||
|
return results
|
||
|
def parse_protocol(content):
|
||
|
message_regex = re.compile(r'message\s*(\w+)\s*\{([\s\S]*?)\}')
|
||
|
enum_regex = re.compile(r'enum\s*(\w+)\s*\{([\s\S]*?)\}')
|
||
|
content = delete_comments(content)
|
||
|
match = message_regex.findall(content)
|
||
|
results = []
|
||
|
enum_match = enum_regex.findall(content)
|
||
|
enum_names = []
|
||
|
if enum_match:
|
||
|
for enum in enum_match:
|
||
|
enum_name = enum[0]
|
||
|
# print enum_name
|
||
|
enum_names.append(enum_name)
|
||
|
if match:
|
||
|
for message in match:
|
||
|
message_name = message[0]
|
||
|
message_body = message[1]
|
||
|
message_fields = parse_message(message_body)
|
||
|
# print message_name[len(message_name) -3:]
|
||
|
if not message_name[len(message_name)-3:] == "Req":
|
||
|
results.append(MessageClass(message_name,message_fields,enum_names))
|
||
|
|
||
|
return results
|
||
|
if __name__ == "__main__":
|
||
|
protocol_name = "GameCs.proto"
|
||
|
message_classes = parse_protocol(load_file_data(protocol_name))
|
||
|
content = """local M = {{}}
|
||
|
local string = string
|
||
|
local NETMSG = NETMSG
|
||
|
_ENV = M
|
||
|
function Parse(msgId,msgData)
|
||
|
local parserName = string.format("Parse%s",NETMSG.MsgList[msgId])
|
||
|
if M[parserName] then
|
||
|
return M[parserName](msgData)
|
||
|
else
|
||
|
LogWarn("NetMsgParser",string.format("no parser for net msg %s",msgId))
|
||
|
end
|
||
|
end
|
||
|
{0}
|
||
|
return M"""
|
||
|
content_body = ""
|
||
|
for message in message_classes:
|
||
|
content_body = content_body + message.generate()
|
||
|
content = content.format(content_body)
|
||
|
output_name = generated_dir+"NetMsgParser.lua"
|
||
|
save_file_data(output_name,content)
|