Skip to content

Instantly share code, notes, and snippets.

@daeken
Created January 12, 2022 05:07
Show Gist options
  • Save daeken/de98704a1ffcabe8e6cdee4e584fc8b7 to your computer and use it in GitHub Desktop.
Save daeken/de98704a1ffcabe8e6cdee4e584fc8b7 to your computer and use it in GitHub Desktop.
from yaml import load
try:
from yaml import CLoader as Loader
except ImportError:
from yaml import Loader
spec = load(file('spec.yaml'), Loader=Loader)
import pprint
pprint.pprint(spec)
namespaces = {}
namespace = None
def genName(name):
if '.' in name:
return name
assert namespace is not None
nsl = namespace.split('.')
name = '.'.join(nsl[:-3] + [name] + nsl[-3:])
return name
def splitNamespace(name):
nl = name.split('.')
namespace = '.'.join(nl[:-4])
name = nl[-4]
return namespace, name
def getNs(namespace):
if namespace not in namespaces:
namespaces[namespace] = dict(
structs={},
interfaces={},
enums={}
)
return namespaces[namespace]
def title(x):
return x[0].upper() + x[1:]
def parseType(type):
if type.startswith('array['):
return ['array', parseType(type[6:-1])]
elif type.startswith('callback['):
type = type[9:-1] + ','
elems = []
bracket = 0
last = 0
for i, c in enumerate(type):
if c == '[':
bracket += 1
elif c == ']':
bracket -= 1
elif bracket == 0 and c == ',':
elems.append(type[last:i])
last = i + 1
return ['callback'] + map(parseType, elems)
else:
return [type]
def parseInterface(elem): # TODO: Handle inheritance
if 'name' in elem:
name = genName(elem['name'])
else:
name = namespace
assert name is not None
def proc(elem):
if isinstance(elem, dict):
name = elem.keys()[0]
oparams = elem[name]
params = []
for elem in oparams:
if isinstance(elem, dict):
type = elem.keys()[0]
pname = elem[type]
params.append((type, pname))
else:
params.append(elem)
else:
name = elem
params = []
if len(params) == 0:
params = ['void']
return name, params
events = map(proc, elem['events']) if 'events' in elem else []
methods = map(proc, elem['methods']) if 'methods' in elem else []
emethods = []
for ename, params in events:
if len(params) == 1:
cparams = 'callback[%s]' % params[0], 'callback'
else:
cparams = 'callback[%s,%s]' % (params[0], ','.join(type for type, _ in params[1:])), 'callback'
emethods.append(('Subscribe' + title(ename), ['void', cparams]))
emethods.append(('Unsubscribe' + title(ename), ['void', cparams]))
methods = emethods + methods
methods = [(ename, [parseType(params[0])] + [(parseType(type), pname) for type, pname in params[1:]]) for ename, params in methods]
ns, name = splitNamespace(name)
ns = getNs(ns)
ns['interfaces'][name] = {'methods' : methods}
def parseExtension(elem):
global namespace
assert len(elem) >= 1 and 'name' in elem[0]
namespace = elem[0]['name']
nsl = namespace.split('.')
assert len(nsl) > 3 and nsl[-3].startswith('v')
parse(elem[1:])
def parseStruct(elem):
assert len(elem) >= 1 and 'name' in elem[0]
name = genName(elem[0]['name'])
ns, name = splitNamespace(name)
ns = getNs(ns)
def proc(elem):
type = elem.keys()[0]
return parseType(type), elem[type]
ns['structs'][name] = map(proc, elem[1:])
def parseFlags(elem):
assert len(elem) >= 2 and 'name' in elem[0] and 'type' in elem[1]
name = genName(elem[0]['name'])
type = elem[1]['type'] # TODO: Support enum types
ns, name = splitNamespace(name)
ns = getNs(ns)
bit = [0]
def proc(elem):
if isinstance(elem, dict):
name = elem.keys()[0]
return (name, elem[name])
value = 1 << bit[0]
bit[0] += 1
return (elem, value)
ns['enums'][name] = (False, map(proc, elem[2:]))
def parseEnum(elem):
pass
def parse(data):
for elem in data:
if 'interface' in elem:
parseInterface(elem['interface'])
elif 'extension' in elem:
parseExtension(elem['extension'])
elif 'struct' in elem:
parseStruct(elem['struct'])
elif 'flags' in elem:
parseFlags(elem['flags'])
elif 'enum' in elem:
parseEnum(elem['enum'])
else:
print 'Unhandled:', `elem`
parse(spec)
btypes = dict(
void='void',
string='string',
uuid='Uuid',
u8='byte',
i8='sbyte',
u16='ushort',
i16='short',
u32='uint',
i32='int',
vu32='uint',
vi32='int',
u64='ulong',
i64='long',
vu64='ulong',
vi64='long',
matrix4x4='Matrix4x4',
)
vtypes = (
'vu32', 'vi32',
'vu64', 'vi64',
)
def typed(type, isRet=False):
if isRet:
if type == ['void']:
return 'Task'
else:
return 'Task<%s>' % typed(type)
if type[0] == 'array':
return '%s[]' % typed(type[1])
elif type[0] == 'callback':
ret = typed(type[1], True)
params = type[2:]
if len(params):
return 'Func<%s, %s>' % (', '.join(map(typed, params)), ret)
else:
return 'Func<%s>' % ret
elif type[0] in btypes:
return btypes[type[0]]
assert len(type) == 1
return title(type[0])
with file('../NetLib/Generated/Protocol.cs', 'w') as fp:
print >>fp, '''#pragma warning disable CS1998
// ReSharper disable ConvertClosureToMethodGroup
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UseObjectOrCollectionInitializer
// ReSharper disable RedundantUsingDirective
// ReSharper disable RedundantAssignment'''
print >>fp, 'using System;'
print >>fp, 'using System.Numerics;'
print >>fp, 'using System.Collections.Generic;'
print >>fp, 'namespace NetLib.Generated;'
for nsn, ns in namespaces.items():
def genDeserialize(type, name, depth = 0):
ws = '\t\t' + '\t' * depth
if type[0] == 'array':
print >>fp, ws + '%s = new %s[(int) NetExtensions.DeserializeVu64(buf, ref offset)];' % (name, typed(type[1]))
print >>fp, ws + 'for(var i%i = 0; i%i < %s.Length; ++i%i) {' % (depth, depth, name, depth)
genDeserialize(type[1], '%s[i%i]' % (name, depth), depth + 1)
print >>fp, ws + '}'
elif type[0] in btypes and type[0] != 'uuid':
print >>fp, ws + '%s = NetExtensions.Deserialize%s(buf, ref offset);' % (name, title(type[0]))
elif type[0] in ns['enums']:
print >>fp, ws + '%s = (%s) NetExtensions.DeserializeVu64(buf, ref offset);' % (name, title(type[0])) # TODO: Support enum types
elif type[0] == 'object' or type[0] in ns['interfaces']:
assert False
else:
print >>fp, ws + '%s = %s.Deserialize(buf, ref offset);' % (name, title(type[0]))
def genMsgDeserialize(type, name, depth = 0):
ws = '\t\t\t\t' + '\t' * depth
if type[0] == 'array':
print >>fp, ws + '%s%s = new %s[(int) NetExtensions.DeserializeVu64(buf.Span, ref offset)];' % ('var ' if depth == 0 else '', name, typed(type[1]))
print >>fp, ws + 'for(var i%i = 0; i%i < %s.Length; ++i%i) {' % (depth, depth, name, depth)
genMsgDeserialize(type[1], '%s[i%i]' % (name, depth), depth + 1)
print >>fp, ws + '}'
elif type[0] in btypes and type[0] != 'uuid':
print >>fp, ws + '%s%s = NetExtensions.Deserialize%s(buf.Span, ref offset);' % ('var ' if depth == 0 else '', name, title(type[0]))
elif type[0] in ns['enums']:
print >>fp, ws + '%s%s = (%s) NetExtensions.DeserializeVu64(buf.Span, ref offset);' % ('var ' if depth == 0 else '', name, title(type[0])) # TODO: Support enum types
elif type[0] == 'object' or type[0] in ns['interfaces']:
assert False
elif type[0] == 'callback':
print >>fp, ws + '%s%s = Connection.GetCallback<%s>(NetExtensions.DeserializeVu64(buf.Span, ref offset), () =>' % ('var ' if depth == 0 else '', name, typed(type))
print >>fp, ws + '\tasync (%s) => {' % ', '.join('_%i' % i for i, _ in enumerate(type[2:]))
print >>fp, ws + '\t}'
print >>fp, ws + ');'
else:
print >>fp, ws + '%s%s = %s.Deserialize(buf.Span, ref offset);' % ('var ' if depth == 0 else '', name, title(type[0]))
def genSerialize(type, value, depth = 0):
ws = '\t\t' + '\t' * depth
if type[0] == 'array':
print >>fp, ws + 'NetExtensions.SerializeVu64((ulong) %s.Length, buf, ref offset);' % value
print >>fp, ws + 'foreach(var _%i in %s) {' % (depth, value)
genSerialize(type[1], '_%i' % depth, depth+1)
print >>fp, ws + '}'
elif type[0] in btypes and type[0] != 'uuid':
print >>fp, ws + 'NetExtensions.Serialize%s(%s, buf, ref offset);' % (title(type[0]), value)
elif type[0] in ns['enums']:
genSerialize(['vu64'], '(ulong) ' + value, depth) # TODO: Support enum types
elif type[0] == 'object' or type[0] in ns['interfaces']:
assert False
else:
print >>fp, ws + '%s.Serialize(buf, ref offset);' % value
def genMsgSerialize(type, value, depth = 0):
ws = '\t\t\t\t\t' + '\t' * depth
if type[0] == 'array':
print >>fp, ws + 'NetExtensions.SerializeVu64((ulong) %s.Length, buf.Span, ref offset);' % value
print >>fp, ws + 'foreach(var _%i in %s) {' % (depth, value)
genMsgSerialize(type[1], '_%i' % depth, depth+1)
print >>fp, ws + '}'
elif type[0] in btypes and type[0] != 'uuid':
print >>fp, ws + 'NetExtensions.Serialize%s(%s, buf.Span, ref offset);' % (title(type[0]), value)
elif type[0] in ns['enums']:
genMsgSerialize(['vu64'], '(ulong) ' + value, depth) # TODO: Support enum types
elif type[0] == 'object' or type[0] in ns['interfaces']:
genMsgSerialize(['vu64'], '%s.ObjectId' % value, depth)
else:
print >>fp, ws + '%s.Serialize(buf.Span, ref offset);' % value
def genSize(type, value, depth = 0):
if type[0] == 'array':
return 'NetExtensions.SizeVu64((ulong) %s.Length) + %s.Select(_%i => %s).Sum()' % (value, value, depth, genSize(type[1], '_%i' % depth, depth + 1))
elif type[0] == 'uuid':
return '16'
elif type[0] in btypes:
return 'NetExtensions.Size%s(%s)' % (title(type[0]), value)
elif type[0] in ns['enums']:
return 'NetExtensions.SizeVu64((ulong) %s)' % value
elif type[0] == 'object' or type[0] in ns['interfaces']:
return 'NetExtensions.SizeVu64(%s.ObjectId)' % value
else:
return '%s.SerializedSize' % value
for name, iface in ns['interfaces'].items():
print >>fp
print >>fp, 'public interface %s%s {' % (title(name), ' : Object' if nsn != 'hypercosm' or name != 'object' else '')
if nsn == 'hypercosm' and name == 'object':
print >>fp, '\tulong ObjectId { get; }'
for mname, params in iface['methods']:
print >>fp, '\t%s %s(%s);' % (typed(params[0], isRet=True), title(mname), ', '.join('%s %s' % (typed(type), pname) for type, pname in params[1:]))
print >>fp, '}'
print >>fp, 'public abstract class Base%s : %s%s {' % (title(name), 'BaseObject, ' if nsn != 'hypercosm' or name != 'object' else 'ILocalObject, ', title(name))
if nsn == 'hypercosm' and name == 'object':
print >>fp, '\tprotected readonly IConnection Connection;'
print >>fp, '\tpublic ulong ObjectId { get; }'
print >>fp, '\tprotected BaseObject(IConnection connection) {'
print >>fp, '\t\tConnection = connection;'
print >>fp, '\t\tObjectId = Connection.RegisterLocalObject(this);'
print >>fp, '\t}'
else:
print >>fp, '\tprotected Base%s(IConnection connection) : base(connection) {}' % title(name)
for mname, params in iface['methods']:
print >>fp, '\tpublic abstract %s %s(%s);' % (typed(params[0], isRet=True), title(mname), ', '.join('%s %s' % (typed(type), pname) for type, pname in params[1:]))
print >>fp
print >>fp, '\tpublic %sasync Task HandleMessage(ulong sequence, int commandNumber, Memory<byte> buf, int offset) {' % ('new ' if nsn != 'hypercosm' or name != 'object' else '')
print >>fp, '\t\tswitch(commandNumber) {'
cmdNum = 0
if nsn != 'hypercosm' or name != 'object':
cmdNum = 2
print >>fp, '\t\t\tcase 0 or 1: await ((BaseObject) this).HandleMessage(sequence, commandNumber, buf, offset); break;'
for mname, params in iface['methods']:
print >>fp, '\t\t\tcase %i: {' % cmdNum
for type, pname in params[1:]:
genMsgDeserialize(type, title(pname))
if params[0] == ['void']:
ret = ''
else:
ret = 'var __ret = '
print >>fp, '\t\t\t\t%sawait %s(%s);' % (ret, title(mname), ', '.join(title(pname) for _, pname in params[1:]))
print >>fp, '\t\t\t\tif(sequence != 0) {'
if params[0] == ['void']:
print >>fp, '\t\t\t\t\tawait Connection.Respond(sequence, Memory<byte>.Empty);'
else:
print >>fp, '\t\t\t\t\tbuf = new byte[%s];' % genSize(params[0], '__ret')
print >>fp, '\t\t\t\t\toffset = 0;'
genMsgSerialize(params[0], '__ret')
print >>fp, '\t\t\t\t\tawait Connection.Respond(sequence, buf);'
print >>fp, '\t\t\t\t}'
print >>fp, '\t\t\t\tbreak;'
print >>fp, '\t\t\t}'
cmdNum += 1
print >>fp, '\t\t\tdefault:'
print >>fp, '\t\t\t\tthrow new UnknownCommandException();'
print >>fp, '\t\t}'
print >>fp, '\t}'
print >>fp, '}'
print >>fp, 'public class Remote%s : %s%s {' % (title(name), 'RemoteObject, ' if nsn != 'hypercosm' or name != 'object' else 'IRemoteObject, ', title(name))
for mname, params in iface['methods']:
print >>fp, '\tpublic async %s %s(%s) {' % (typed(params[0], isRet=True), title(mname), ', '.join('%s %s' % (typed(type), pname) for type, pname in params[1:]))
print >>fp, '\t}'
print >>fp, '}'
for name, struct in ns['structs'].items():
print >>fp
print >>fp, 'public struct %s {' % title(name)
for type, fname in struct:
print >>fp, '\tpublic %s %s;' % (typed(type), title(fname))
print >>fp
if len(struct) == 0:
print >>fp, '\tpublic int SerializedSize => 0;'
else:
print >>fp, '\tpublic int SerializedSize => %s;' % ' + '.join(genSize(type, title(fname)) for type, fname in struct)
print >>fp, '\tpublic void Serialize(IConnection connection, Span<byte> buf, ref int offset) {'
for type, fname in struct:
genSerialize(type, title(fname))
print >>fp, '\t}'
print >>fp, '\tpublic static %s Deserialize(IConnection connection, Span<byte> buf, ref int offset) {' % title(name)
print >>fp, '\t\tvar obj = new %s();' % title(name)
for type, fname in struct:
genDeserialize(type, 'obj.' + title(fname))
print >>fp, '\t\treturn obj;'
print >>fp, '\t}'
print >>fp, '}'
for name, (isFlags, enum) in ns['enums'].items():
print >>fp
if isFlags:
print >>fp, '[Flags]'
print >>fp, 'public enum %s : ulong {' % title(name) # TODO: Support enum types
for ename, value in enum:
print >>fp, '\t%s = %s,' % (title(ename), value)
print >>fp, '}'
#pragma warning disable CS1998
// ReSharper disable ConvertClosureToMethodGroup
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UseObjectOrCollectionInitializer
// ReSharper disable RedundantUsingDirective
// ReSharper disable RedundantAssignment
using System;
using System.Numerics;
using System.Collections.Generic;
namespace NetLib.Generated;
public interface World : Object {
Task SubscribeAddEntities(Func<EntityInfo[], Task> callback);
Task UnsubscribeAddEntities(Func<EntityInfo[], Task> callback);
Task SubscribeUpdateEntities(Func<EntityInfo[], Task> callback);
Task UnsubscribeUpdateEntities(Func<EntityInfo[], Task> callback);
Task SubscribeRemoveEntities(Func<Entity[], Task> callback);
Task UnsubscribeRemoveEntities(Func<Entity[], Task> callback);
}
public abstract class BaseWorld : BaseObject, World {
protected BaseWorld(IConnection connection) : base(connection) {}
public abstract Task SubscribeAddEntities(Func<EntityInfo[], Task> callback);
public abstract Task UnsubscribeAddEntities(Func<EntityInfo[], Task> callback);
public abstract Task SubscribeUpdateEntities(Func<EntityInfo[], Task> callback);
public abstract Task UnsubscribeUpdateEntities(Func<EntityInfo[], Task> callback);
public abstract Task SubscribeRemoveEntities(Func<Entity[], Task> callback);
public abstract Task UnsubscribeRemoveEntities(Func<Entity[], Task> callback);
public new async Task HandleMessage(ulong sequence, int commandNumber, Memory<byte> buf, int offset) {
switch(commandNumber) {
case 0 or 1: await ((BaseObject) this).HandleMessage(sequence, commandNumber, buf, offset); break;
case 2: {
var Callback = Connection.GetCallback<Func<EntityInfo[], Task>>(NetExtensions.DeserializeVu64(buf.Span, ref offset), () =>
async (_0) => {
}
);
await SubscribeAddEntities(Callback);
if(sequence != 0) {
await Connection.Respond(sequence, Memory<byte>.Empty);
}
break;
}
case 3: {
var Callback = Connection.GetCallback<Func<EntityInfo[], Task>>(NetExtensions.DeserializeVu64(buf.Span, ref offset), () =>
async (_0) => {
}
);
await UnsubscribeAddEntities(Callback);
if(sequence != 0) {
await Connection.Respond(sequence, Memory<byte>.Empty);
}
break;
}
case 4: {
var Callback = Connection.GetCallback<Func<EntityInfo[], Task>>(NetExtensions.DeserializeVu64(buf.Span, ref offset), () =>
async (_0) => {
}
);
await SubscribeUpdateEntities(Callback);
if(sequence != 0) {
await Connection.Respond(sequence, Memory<byte>.Empty);
}
break;
}
case 5: {
var Callback = Connection.GetCallback<Func<EntityInfo[], Task>>(NetExtensions.DeserializeVu64(buf.Span, ref offset), () =>
async (_0) => {
}
);
await UnsubscribeUpdateEntities(Callback);
if(sequence != 0) {
await Connection.Respond(sequence, Memory<byte>.Empty);
}
break;
}
case 6: {
var Callback = Connection.GetCallback<Func<Entity[], Task>>(NetExtensions.DeserializeVu64(buf.Span, ref offset), () =>
async (_0) => {
}
);
await SubscribeRemoveEntities(Callback);
if(sequence != 0) {
await Connection.Respond(sequence, Memory<byte>.Empty);
}
break;
}
case 7: {
var Callback = Connection.GetCallback<Func<Entity[], Task>>(NetExtensions.DeserializeVu64(buf.Span, ref offset), () =>
async (_0) => {
}
);
await UnsubscribeRemoveEntities(Callback);
if(sequence != 0) {
await Connection.Respond(sequence, Memory<byte>.Empty);
}
break;
}
default:
throw new UnknownCommandException();
}
}
}
public class RemoteWorld : RemoteObject, World {
public async Task SubscribeAddEntities(Func<EntityInfo[], Task> callback) {
}
public async Task UnsubscribeAddEntities(Func<EntityInfo[], Task> callback) {
}
public async Task SubscribeUpdateEntities(Func<EntityInfo[], Task> callback) {
}
public async Task UnsubscribeUpdateEntities(Func<EntityInfo[], Task> callback) {
}
public async Task SubscribeRemoveEntities(Func<Entity[], Task> callback) {
}
public async Task UnsubscribeRemoveEntities(Func<Entity[], Task> callback) {
}
}
public interface Object {
ulong ObjectId { get; }
Task<string[]> ListInterfaces();
Task Release();
}
public abstract class BaseObject : ILocalObject, Object {
protected readonly IConnection Connection;
public ulong ObjectId { get; }
protected BaseObject(IConnection connection) {
Connection = connection;
ObjectId = Connection.RegisterLocalObject(this);
}
public abstract Task<string[]> ListInterfaces();
public abstract Task Release();
public async Task HandleMessage(ulong sequence, int commandNumber, Memory<byte> buf, int offset) {
switch(commandNumber) {
case 0: {
var __ret = await ListInterfaces();
if(sequence != 0) {
buf = new byte[NetExtensions.SizeVu64((ulong) __ret.Length) + __ret.Select(_0 => NetExtensions.SizeString(_0)).Sum()];
offset = 0;
NetExtensions.SerializeVu64((ulong) __ret.Length, buf.Span, ref offset);
foreach(var _0 in __ret) {
NetExtensions.SerializeString(_0, buf.Span, ref offset);
}
await Connection.Respond(sequence, buf);
}
break;
}
case 1: {
await Release();
if(sequence != 0) {
await Connection.Respond(sequence, Memory<byte>.Empty);
}
break;
}
default:
throw new UnknownCommandException();
}
}
}
public class RemoteObject : IRemoteObject, Object {
public async Task<string[]> ListInterfaces() {
}
public async Task Release() {
}
}
public interface Root : Object {
Task<string[]> ListExtensions();
Task Ping();
Task<Object> GetObjectById(Uuid id);
Task<Object> GetObjectByName(string name);
}
public abstract class BaseRoot : BaseObject, Root {
protected BaseRoot(IConnection connection) : base(connection) {}
public abstract Task<string[]> ListExtensions();
public abstract Task Ping();
public abstract Task<Object> GetObjectById(Uuid id);
public abstract Task<Object> GetObjectByName(string name);
public new async Task HandleMessage(ulong sequence, int commandNumber, Memory<byte> buf, int offset) {
switch(commandNumber) {
case 0 or 1: await ((BaseObject) this).HandleMessage(sequence, commandNumber, buf, offset); break;
case 2: {
var __ret = await ListExtensions();
if(sequence != 0) {
buf = new byte[NetExtensions.SizeVu64((ulong) __ret.Length) + __ret.Select(_0 => NetExtensions.SizeString(_0)).Sum()];
offset = 0;
NetExtensions.SerializeVu64((ulong) __ret.Length, buf.Span, ref offset);
foreach(var _0 in __ret) {
NetExtensions.SerializeString(_0, buf.Span, ref offset);
}
await Connection.Respond(sequence, buf);
}
break;
}
case 3: {
await Ping();
if(sequence != 0) {
await Connection.Respond(sequence, Memory<byte>.Empty);
}
break;
}
case 4: {
var Id = Uuid.Deserialize(buf.Span, ref offset);
var __ret = await GetObjectById(Id);
if(sequence != 0) {
buf = new byte[NetExtensions.SizeVu64(__ret.ObjectId)];
offset = 0;
NetExtensions.SerializeVu64(__ret.ObjectId, buf.Span, ref offset);
await Connection.Respond(sequence, buf);
}
break;
}
case 5: {
var Name = NetExtensions.DeserializeString(buf.Span, ref offset);
var __ret = await GetObjectByName(Name);
if(sequence != 0) {
buf = new byte[NetExtensions.SizeVu64(__ret.ObjectId)];
offset = 0;
NetExtensions.SerializeVu64(__ret.ObjectId, buf.Span, ref offset);
await Connection.Respond(sequence, buf);
}
break;
}
default:
throw new UnknownCommandException();
}
}
}
public class RemoteRoot : RemoteObject, Root {
public async Task<string[]> ListExtensions() {
}
public async Task Ping() {
}
public async Task<Object> GetObjectById(Uuid id) {
}
public async Task<Object> GetObjectByName(string name) {
}
}
public interface Assetdelivery : Object {
Task SubscribeLoadAssets(Func<Asset[], Task> callback);
Task UnsubscribeLoadAssets(Func<Asset[], Task> callback);
Task SubscribeUnloadAssets(Func<Uuid[], Task> callback);
Task UnsubscribeUnloadAssets(Func<Uuid[], Task> callback);
Task<Asset> FetchAssetById(Uuid id);
Task<Asset> FetchAssetByName(string name);
Task<Asset[]> FetchAssetsByIds(Uuid[] ids);
Task<Asset[]> FetchAssetsByNames(string[] names);
Task<Uuid> GetId(string name);
}
public abstract class BaseAssetdelivery : BaseObject, Assetdelivery {
protected BaseAssetdelivery(IConnection connection) : base(connection) {}
public abstract Task SubscribeLoadAssets(Func<Asset[], Task> callback);
public abstract Task UnsubscribeLoadAssets(Func<Asset[], Task> callback);
public abstract Task SubscribeUnloadAssets(Func<Uuid[], Task> callback);
public abstract Task UnsubscribeUnloadAssets(Func<Uuid[], Task> callback);
public abstract Task<Asset> FetchAssetById(Uuid id);
public abstract Task<Asset> FetchAssetByName(string name);
public abstract Task<Asset[]> FetchAssetsByIds(Uuid[] ids);
public abstract Task<Asset[]> FetchAssetsByNames(string[] names);
public abstract Task<Uuid> GetId(string name);
public new async Task HandleMessage(ulong sequence, int commandNumber, Memory<byte> buf, int offset) {
switch(commandNumber) {
case 0 or 1: await ((BaseObject) this).HandleMessage(sequence, commandNumber, buf, offset); break;
case 2: {
var Callback = Connection.GetCallback<Func<Asset[], Task>>(NetExtensions.DeserializeVu64(buf.Span, ref offset), () =>
async (_0) => {
}
);
await SubscribeLoadAssets(Callback);
if(sequence != 0) {
await Connection.Respond(sequence, Memory<byte>.Empty);
}
break;
}
case 3: {
var Callback = Connection.GetCallback<Func<Asset[], Task>>(NetExtensions.DeserializeVu64(buf.Span, ref offset), () =>
async (_0) => {
}
);
await UnsubscribeLoadAssets(Callback);
if(sequence != 0) {
await Connection.Respond(sequence, Memory<byte>.Empty);
}
break;
}
case 4: {
var Callback = Connection.GetCallback<Func<Uuid[], Task>>(NetExtensions.DeserializeVu64(buf.Span, ref offset), () =>
async (_0) => {
}
);
await SubscribeUnloadAssets(Callback);
if(sequence != 0) {
await Connection.Respond(sequence, Memory<byte>.Empty);
}
break;
}
case 5: {
var Callback = Connection.GetCallback<Func<Uuid[], Task>>(NetExtensions.DeserializeVu64(buf.Span, ref offset), () =>
async (_0) => {
}
);
await UnsubscribeUnloadAssets(Callback);
if(sequence != 0) {
await Connection.Respond(sequence, Memory<byte>.Empty);
}
break;
}
case 6: {
var Id = Uuid.Deserialize(buf.Span, ref offset);
var __ret = await FetchAssetById(Id);
if(sequence != 0) {
buf = new byte[__ret.SerializedSize];
offset = 0;
__ret.Serialize(buf.Span, ref offset);
await Connection.Respond(sequence, buf);
}
break;
}
case 7: {
var Name = NetExtensions.DeserializeString(buf.Span, ref offset);
var __ret = await FetchAssetByName(Name);
if(sequence != 0) {
buf = new byte[__ret.SerializedSize];
offset = 0;
__ret.Serialize(buf.Span, ref offset);
await Connection.Respond(sequence, buf);
}
break;
}
case 8: {
var Ids = new Uuid[(int) NetExtensions.DeserializeVu64(buf.Span, ref offset)];
for(var i0 = 0; i0 < Ids.Length; ++i0) {
Ids[i0] = Uuid.Deserialize(buf.Span, ref offset);
}
var __ret = await FetchAssetsByIds(Ids);
if(sequence != 0) {
buf = new byte[NetExtensions.SizeVu64((ulong) __ret.Length) + __ret.Select(_0 => _0.SerializedSize).Sum()];
offset = 0;
NetExtensions.SerializeVu64((ulong) __ret.Length, buf.Span, ref offset);
foreach(var _0 in __ret) {
_0.Serialize(buf.Span, ref offset);
}
await Connection.Respond(sequence, buf);
}
break;
}
case 9: {
var Names = new string[(int) NetExtensions.DeserializeVu64(buf.Span, ref offset)];
for(var i0 = 0; i0 < Names.Length; ++i0) {
Names[i0] = NetExtensions.DeserializeString(buf.Span, ref offset);
}
var __ret = await FetchAssetsByNames(Names);
if(sequence != 0) {
buf = new byte[NetExtensions.SizeVu64((ulong) __ret.Length) + __ret.Select(_0 => _0.SerializedSize).Sum()];
offset = 0;
NetExtensions.SerializeVu64((ulong) __ret.Length, buf.Span, ref offset);
foreach(var _0 in __ret) {
_0.Serialize(buf.Span, ref offset);
}
await Connection.Respond(sequence, buf);
}
break;
}
case 10: {
var Name = NetExtensions.DeserializeString(buf.Span, ref offset);
var __ret = await GetId(Name);
if(sequence != 0) {
buf = new byte[16];
offset = 0;
__ret.Serialize(buf.Span, ref offset);
await Connection.Respond(sequence, buf);
}
break;
}
default:
throw new UnknownCommandException();
}
}
}
public class RemoteAssetdelivery : RemoteObject, Assetdelivery {
public async Task SubscribeLoadAssets(Func<Asset[], Task> callback) {
}
public async Task UnsubscribeLoadAssets(Func<Asset[], Task> callback) {
}
public async Task SubscribeUnloadAssets(Func<Uuid[], Task> callback) {
}
public async Task UnsubscribeUnloadAssets(Func<Uuid[], Task> callback) {
}
public async Task<Asset> FetchAssetById(Uuid id) {
}
public async Task<Asset> FetchAssetByName(string name) {
}
public async Task<Asset[]> FetchAssetsByIds(Uuid[] ids) {
}
public async Task<Asset[]> FetchAssetsByNames(string[] names) {
}
public async Task<Uuid> GetId(string name) {
}
}
public struct Asset {
public Uuid Id;
public string Name;
public byte[] Data;
public int SerializedSize => 16 + NetExtensions.SizeString(Name) + NetExtensions.SizeVu64((ulong) Data.Length) + Data.Select(_0 => NetExtensions.SizeU8(_0)).Sum();
public void Serialize(Span<byte> buf, ref int offset) {
Id.Serialize(buf, ref offset);
NetExtensions.SerializeString(Name, buf, ref offset);
NetExtensions.SerializeVu64((ulong) Data.Length, buf, ref offset);
foreach(var _0 in Data) {
NetExtensions.SerializeU8(_0, buf, ref offset);
}
}
public static Asset Deserialize(Span<byte> buf, ref int offset) {
var obj = new Asset();
obj.Id = Uuid.Deserialize(buf, ref offset);
obj.Name = NetExtensions.DeserializeString(buf, ref offset);
obj.Data = new byte[(int) NetExtensions.DeserializeVu64(buf, ref offset)];
for(var i0 = 0; i0 < obj.Data.Length; ++i0) {
obj.Data[i0] = NetExtensions.DeserializeU8(buf, ref offset);
}
return obj;
}
}
public interface Entity : Object {
Task Interact();
}
public abstract class BaseEntity : BaseObject, Entity {
protected BaseEntity(IConnection connection) : base(connection) {}
public abstract Task Interact();
public new async Task HandleMessage(ulong sequence, int commandNumber, Memory<byte> buf, int offset) {
switch(commandNumber) {
case 0 or 1: await ((BaseObject) this).HandleMessage(sequence, commandNumber, buf, offset); break;
case 2: {
await Interact();
if(sequence != 0) {
await Connection.Respond(sequence, Memory<byte>.Empty);
}
break;
}
default:
throw new UnknownCommandException();
}
}
}
public class RemoteEntity : RemoteObject, Entity {
public async Task Interact() {
}
}
public struct EntityInfo {
public Uuid AssetId;
public Entity Entity;
public Matrix4x4 Transformation;
public EntityFlags Flags;
public int SerializedSize => 16 + NetExtensions.SizeVu64(Entity.ObjectId) + NetExtensions.SizeMatrix4x4(Transformation) + NetExtensions.SizeVu64((ulong) Flags);
public void Serialize(Span<byte> buf, ref int offset) {
AssetId.Serialize(buf, ref offset);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment