New protocol.hjson type system
This commit is contained in:
parent
e71ae319a2
commit
e09c70a51a
|
@ -5,6 +5,10 @@ text = ''
|
|||
varint_max_size = 5
|
||||
indent_count = 0
|
||||
|
||||
# Print to stderr
|
||||
def warn(value, *args, sep='', end='\n', flush=False):
|
||||
print(value, *args, sep=sep, end=end, file=sys.stderr, flush=flush)
|
||||
|
||||
def indent():
|
||||
global indent_count
|
||||
indent_count += 1
|
||||
|
@ -32,37 +36,74 @@ def extract_array_type(type):
|
|||
def extract_array_count(type):
|
||||
if '[' in type and ']' in type:
|
||||
return int(type[type.find('[')+1:type.rfind(']')])
|
||||
return 1
|
||||
return None
|
||||
|
||||
def resolve_type(aliases, type):
|
||||
type_no_array = type.rstrip('_')
|
||||
if type_no_array in aliases:
|
||||
return aliases[type_no_array]
|
||||
return type
|
||||
def get_type_info(types, typename, aliases={}):
|
||||
name = extract_array_type(typename)
|
||||
|
||||
def get_type_size(type):
|
||||
global varint_max_size
|
||||
count = extract_array_count(type)
|
||||
type = extract_array_type(type)
|
||||
alias_name = None
|
||||
if aliases and name in aliases:
|
||||
alias_name = name
|
||||
name = aliases[name]
|
||||
|
||||
# TODO: encode type sizes in Hjson data
|
||||
if type == 'varint':
|
||||
return varint_max_size
|
||||
elif type == 'int64' or type == 'uint64' or type == 'double' or type == 'position':
|
||||
return 8
|
||||
elif type == 'int32' or type == 'uint32' or type == 'float':
|
||||
return 4
|
||||
elif type == 'int16' or type == 'uint16':
|
||||
return 2
|
||||
elif type == 'int8' or type == 'uint8' or type == 'byte' or type == 'bool':
|
||||
return 1
|
||||
elif type == 'string':
|
||||
return count
|
||||
elif type == 'uuid':
|
||||
return 16
|
||||
if not name in types:
|
||||
warn('WARNING: Type name "{}" is not a known type or alias.'.format(name))
|
||||
return {
|
||||
type: name
|
||||
}
|
||||
|
||||
tp = types[name]
|
||||
|
||||
if 'alias' in tp:
|
||||
alias = tp['alias']
|
||||
tp = get_type_info(types, tp['alias']).copy()
|
||||
tp['alias'] = alias
|
||||
if tp['generic'] == True:
|
||||
tp['type'] = name
|
||||
|
||||
if alias_name:
|
||||
tp = tp.copy()
|
||||
tp['alias'] = name
|
||||
tp['type'] = alias_name
|
||||
|
||||
# types without a 'type' value use their own name (e.g. double, float)
|
||||
if not 'type' in tp:
|
||||
tp['type'] = name
|
||||
|
||||
return tp
|
||||
|
||||
def resolve_type(types, typename, aliases={}):
|
||||
tp = get_type_info(types, typename, aliases)
|
||||
if 'type' in tp:
|
||||
return tp['type']
|
||||
else:
|
||||
print(type)
|
||||
assert False
|
||||
return typename
|
||||
|
||||
def get_type_size(types, typename, aliases={}):
|
||||
global varint_max_size
|
||||
|
||||
tp = get_type_info(types, typename, aliases)
|
||||
|
||||
if not 'size' in tp:
|
||||
if 'alias' in tp:
|
||||
return get_type_size(types, tp['alias'])
|
||||
else:
|
||||
warn('ERROR: Non-alias type "{}" does not have "size" field.'.format(typename))
|
||||
exit(1)
|
||||
|
||||
size = tp['size']
|
||||
|
||||
if size == 'count':
|
||||
size = extract_array_count(typename)
|
||||
|
||||
if not size:
|
||||
warn('ERROR: Cannot get size for type "{}"'.format(typename))
|
||||
exit(1)
|
||||
|
||||
|
||||
#print("get_type_size: {} -> {}".format(typename, size))
|
||||
|
||||
return int(size)
|
||||
|
||||
def print_enum(name, dict, primitive = 'int32_t'):
|
||||
add_text('enum class {} : {}', name, primitive)
|
||||
|
@ -73,21 +114,27 @@ def print_enum(name, dict, primitive = 'int32_t'):
|
|||
unindent()
|
||||
add_text('}};')
|
||||
|
||||
def get_rw_func(primitiveType, aliasedType, read):
|
||||
prefix = 'Read' if read else 'Write'
|
||||
if aliasedType == 'varint':
|
||||
if primitiveType == 'int32_t':
|
||||
return '{}VarInt'.format(prefix)
|
||||
else:
|
||||
return '{}VarInt<{}>'.format(prefix, primitiveType)
|
||||
elif aliasedType == 'string':
|
||||
return '{}String'.format(prefix)
|
||||
elif aliasedType == 'position':
|
||||
return '{}Position'.format(prefix)
|
||||
else:
|
||||
return '{}<{}>'.format(prefix, primitiveType)
|
||||
def get_rw_func(types, typename, read, aliases={}):
|
||||
method = 'Read' if read else 'Write'
|
||||
|
||||
def print_messages(list, global_aliases, primitives):
|
||||
#print("{}: ({}, {})".format(method, typename, read))
|
||||
|
||||
tp = get_type_info(types, typename, aliases)
|
||||
|
||||
if 'method' in tp:
|
||||
method += tp['method']
|
||||
|
||||
generic = 'generic' in tp and tp['generic']
|
||||
alias = 'alias' in tp
|
||||
|
||||
if (generic and alias) or not 'method' in tp:
|
||||
method += '<' + tp['type'] + '>'
|
||||
|
||||
#print('{} -> {}'.format(typename, method))
|
||||
|
||||
return method
|
||||
|
||||
def print_messages(list, types):
|
||||
global text
|
||||
for state, direction_list in list.items():
|
||||
add_text('namespace {}', state.capitalize())
|
||||
|
@ -97,10 +144,8 @@ def print_messages(list, global_aliases, primitives):
|
|||
serverbound = direction == 'serverbound'
|
||||
for message_name, message in messages.items():
|
||||
|
||||
# global and local aliases
|
||||
aliases = global_aliases.copy()
|
||||
|
||||
# add any local aliases
|
||||
aliases = {}
|
||||
if 'aliases' in message:
|
||||
for alias in message['aliases']:
|
||||
aliases[alias] = message['aliases'][alias]
|
||||
|
@ -108,8 +153,8 @@ def print_messages(list, global_aliases, primitives):
|
|||
global varint_max_size
|
||||
size = varint_max_size # Packet Length
|
||||
size += varint_max_size # Packet Id
|
||||
for name, type in message['vars'].items():
|
||||
size += get_type_size(resolve_type(aliases, type))
|
||||
for name, typename in message['vars'].items():
|
||||
size += get_type_size(types, typename, aliases)
|
||||
|
||||
struct_name = '{}{}'.format(direction.capitalize(), message_name)
|
||||
add_text('struct {}', struct_name)
|
||||
|
@ -124,7 +169,7 @@ def print_messages(list, global_aliases, primitives):
|
|||
for enum in message['enums']:
|
||||
if enum in aliases:
|
||||
# lookup enum primitive type from aliases
|
||||
prim = resolve_type(primitives, aliases[enum])
|
||||
prim = resolve_type(types, aliases[enum])
|
||||
print_enum(enum, message['enums'][enum], prim)
|
||||
else:
|
||||
print_enum(enum, message['enums'][enum])
|
||||
|
@ -133,8 +178,11 @@ def print_messages(list, global_aliases, primitives):
|
|||
add_text('{}(PacketReader& reader)', struct_name)
|
||||
add_text('{{')
|
||||
indent()
|
||||
for name, type in message['vars'].items():
|
||||
add_text('{} = reader.{}();', name, get_rw_func(resolve_type(primitives, extract_array_type(type)), resolve_type(aliases, extract_array_type(type)), True))
|
||||
for name, typename in message['vars'].items():
|
||||
add_text('{} = reader.{}();',
|
||||
name,
|
||||
get_rw_func(types, typename, True, aliases)
|
||||
)
|
||||
unindent()
|
||||
add_text('}}')
|
||||
newline()
|
||||
|
@ -144,15 +192,18 @@ def print_messages(list, global_aliases, primitives):
|
|||
indent()
|
||||
add_text('NetworkMessage msg(MaxSize);')
|
||||
add_text('msg.WriteVarInt(PacketId);')
|
||||
for name, type in message['vars'].items():
|
||||
add_text('msg.{}({});', get_rw_func(resolve_type(primitives, extract_array_type(type)), resolve_type(aliases, extract_array_type(type)), False), name)
|
||||
for name, typename in message['vars'].items():
|
||||
add_text('msg.{}({});',
|
||||
get_rw_func(types, typename, False, aliases),
|
||||
name
|
||||
)
|
||||
add_text('msg.Finalize();')
|
||||
add_text('return msg;')
|
||||
unindent()
|
||||
add_text('}}')
|
||||
|
||||
for name, type in message['vars'].items():
|
||||
resolved_type = resolve_type(primitives, extract_array_type(type))
|
||||
for name, typename in message['vars'].items():
|
||||
resolved_type = resolve_type(types, extract_array_type(typename), aliases)
|
||||
if not serverbound and resolved_type == 'std::string':
|
||||
add_text('const {}& {};', resolved_type, name)
|
||||
else:
|
||||
|
@ -229,8 +280,8 @@ def print_protocol():
|
|||
|
||||
print_messages(
|
||||
message_scheme['messages'],
|
||||
message_scheme['types']['aliases'],
|
||||
message_scheme['types']['primitives'])
|
||||
message_scheme['types']
|
||||
)
|
||||
|
||||
newline()
|
||||
|
||||
|
|
|
@ -1,29 +1,53 @@
|
|||
{
|
||||
types :
|
||||
types:
|
||||
{
|
||||
aliases :
|
||||
{
|
||||
ProtocolState : varint
|
||||
varint: {
|
||||
type: int32_t
|
||||
size: 5
|
||||
method: VarInt
|
||||
generic: true
|
||||
}
|
||||
|
||||
primitives :
|
||||
{
|
||||
varint : int32_t
|
||||
string : std::string
|
||||
uuid : MinecraftUUID
|
||||
position: BlockPos
|
||||
|
||||
uint64 : uint64_t
|
||||
int64 : int64_t
|
||||
uint32 : uint32_t
|
||||
int32 : int32_t
|
||||
uint16 : uint16_t
|
||||
int16 : int16_t
|
||||
uint8 : uint8_t
|
||||
int8 : int8_t
|
||||
byte : uint8_t
|
||||
bool : uint8_t
|
||||
ProtocolState: {
|
||||
alias: varint
|
||||
}
|
||||
|
||||
string: {
|
||||
type: std::string
|
||||
method: String
|
||||
size: count
|
||||
}
|
||||
|
||||
uuid: {
|
||||
type: MinecraftUUID
|
||||
size: 16
|
||||
}
|
||||
|
||||
position: {
|
||||
type: BlockPos
|
||||
size: 8
|
||||
method: Position
|
||||
}
|
||||
|
||||
uint64: {type: 'uint64_t', size: 8}
|
||||
int64: {type: 'int64_t', size: 8}
|
||||
|
||||
uint32: {type: 'uint32_t', size: 4}
|
||||
int32: {type: 'int32_t', size: 4}
|
||||
|
||||
uint16: {type: 'uint16_t', size: 2}
|
||||
int16: {type: 'int16_t', size: 2}
|
||||
|
||||
uint8: {type: 'uint8_t', size: 1}
|
||||
int8: {type: 'int8_t', size: 1}
|
||||
|
||||
byte: {type: 'uint8_t', size: 1}
|
||||
|
||||
bool: {type: 'bool', size: 1}
|
||||
|
||||
float: {size: 4}
|
||||
double: {size: 8}
|
||||
|
||||
}
|
||||
|
||||
states :
|
||||
|
|
Loading…
Reference in New Issue