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.
 
 
 
 
 
 

200 lines
6.9 KiB

#!/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)