metagen/targets/cs/metagen.cs

1609 lines
35 KiB
C#
Raw Permalink Normal View History

2022-05-16 14:20:20 +03:00
using MsgPack;
using System.IO;
using System;
using System.Collections;
using System.Collections.Generic;
using CodeStage.AntiCheat.ObscuredTypes;
namespace metagen {
//NOTE: don't change existing values
public enum MetaIoError
{
NONE = 0,
NO_SPACE_LEFT_IN_ARRAY = 1,
HAS_LEFT_SPACE = 2,
ARRAY_STACK_IS_EMPTY = 3,
FAIL_READ = 4,
TYPE_DONT_MATCH = 5,
DATA_MISSING = 7,
GENERIC = 10,
}
public class MetaException : Exception
{
public MetaIoError err;
public MetaException(MetaIoError err)
{
this.err = err;
}
}
[System.Flags]
public enum MetaSyncContextOpts
{
NONE = 0,
USE_MASK = 1
}
[System.Flags]
public enum MetaSyncFieldOpts
{
NONE = 0,
SKIP_NOT_IN_MASK = 1,
SKIP_OPTIONAL = 2
}
public struct MetaSyncContext
{
public bool is_read;
public IDataReader reader;
public IDataWriter writer;
public Func<uint, IMetaStruct> factory;
public MetaSyncContextOpts opts;
public bool CanReadField(MetaSyncFieldOpts opts)
{
return is_read && (opts & MetaSyncFieldOpts.SKIP_NOT_IN_MASK) != MetaSyncFieldOpts.SKIP_NOT_IN_MASK;
}
public bool CanWriteField(MetaSyncFieldOpts opts)
{
return !is_read && (opts & MetaSyncFieldOpts.SKIP_NOT_IN_MASK) != MetaSyncFieldOpts.SKIP_NOT_IN_MASK;
}
public bool IsMaskUsed()
{
return (opts & MetaSyncContextOpts.USE_MASK) > 0;
}
public static MetaSyncContext NewForRead(Func<uint, IMetaStruct> factory, IDataReader reader, MetaSyncContextOpts opts = 0)
{
var ctx = new MetaSyncContext() {
is_read = true,
reader = reader,
writer = null,
factory = factory,
opts = opts
};
return ctx;
}
public static MetaSyncContext NewForWrite(IDataWriter writer, MetaSyncContextOpts opts = 0)
{
var ctx = new MetaSyncContext() {
is_read = false,
reader = null,
writer = writer,
opts = opts
};
return ctx;
}
}
public interface IMetaStruct
{
uint CLASS_ID();
int getFieldsCount();
int getWritableFieldsCount();
void syncFields(MetaSyncContext ctx);
void reset();
}
public interface IMetaCloneable
{
void copy(IMetaStruct source);
IMetaStruct clone();
}
public abstract class BaseMetaStruct : IMetaStruct
{
public virtual uint CLASS_ID() { return 0; }
public virtual int getFieldsCount() { return 0; }
public virtual int getWritableFieldsCount() { return 0; }
public virtual void reset() {}
public virtual void syncFields(MetaSyncContext ctx) {}
}
public interface IRpcError
{
bool isOk();
}
public interface IRpc
{
int getCode();
IMetaStruct getRequest();
IMetaStruct getResponse();
IRpcError getError();
void setError(IRpcError err);
}
public interface IDataReader
{
MetaIoError ReadI8(ref sbyte v);
MetaIoError ReadU8(ref byte v);
MetaIoError ReadI16(ref short v);
MetaIoError ReadU16(ref ushort v);
MetaIoError ReadI32(ref int v);
MetaIoError ReadU32(ref uint v);
MetaIoError ReadU64(ref ulong v);
MetaIoError ReadI64(ref long v);
MetaIoError ReadFloat(ref float v);
MetaIoError ReadBool(ref bool v);
MetaIoError ReadDouble(ref double v);
MetaIoError ReadString(ref string v);
MetaIoError ReadRaw(ref byte[] v, ref int vlen);
MetaIoError ReadNil();
MetaIoError BeginContainer();
MetaIoError GetContainerSize(ref int v);
MetaIoError EndContainer();
}
public interface IDataWriter
{
MetaIoError WriteI8(sbyte v);
MetaIoError WriteU8(byte v);
MetaIoError WriteI16(short v);
MetaIoError WriteU16(ushort v);
MetaIoError WriteI32(int v);
MetaIoError WriteU32(uint v);
MetaIoError WriteI64(long v);
MetaIoError WriteU64(ulong v);
MetaIoError WriteFloat(float v);
MetaIoError WriteBool(bool v);
MetaIoError WriteDouble(double v);
MetaIoError WriteString(string v);
MetaIoError WriteRaw(byte[] v);
MetaIoError BeginContainer(int len);
MetaIoError EndContainer();
MetaIoError End();
MetaIoError WriteNil();
}
public static class Meta
{
public delegate void LogCb(string text);
public static LogCb LogError = DefaultLog;
public static LogCb LogWarn = DefaultLog;
public static LogCb LogDebug = DefaultLog;
public struct BitfieldsContext
{
long fields_mask;
int curr_field_idx;
MetaSyncContext ctx;
readonly bool use_mask;
public BitfieldsContext(MetaSyncContext ctx, long fields_mask)
{
this.ctx = ctx;
this.use_mask = ctx.IsMaskUsed();
this.fields_mask = fields_mask;
this.curr_field_idx = -1;
}
public void SyncMaskHeader()
{
if(!use_mask)
return;
if(ctx.is_read)
{
ensure(ctx.reader.ReadNil());
ensure(ctx.reader.ReadI64(ref fields_mask));
}
else
{
ensure(ctx.writer.WriteNil());
ensure(ctx.writer.WriteI64(fields_mask));
}
}
public MetaSyncFieldOpts GetCurrentOpts()
{
if(!use_mask || curr_field_idx < 0 || curr_field_idx > 63)
return 0;
long curr_field_ptr = 1L << curr_field_idx;
if((curr_field_ptr & fields_mask) == 0)
return MetaSyncFieldOpts.SKIP_NOT_IN_MASK;
return 0;
}
public MetaSyncFieldOpts GetNextOpts()
{
Advance();
return GetCurrentOpts();
}
public void Advance()
{
curr_field_idx++;
#if DEBUG
if(curr_field_idx > 64)
{
LogError("overflow in @bitfields struct. Does it have > 64 fields?");
throw new MetaException(MetaIoError.GENERIC);
}
#endif
}
}
public const int MASK_HEADER_FIELDS_COUNT = 2;
public static List<int> tmp_enums_list = new List<int>();
static void DefaultLog(string s)
{}
public delegate string L_TCb(string text);
public static L_TCb L_T;
public delegate string L_FromListCb(IList<string> list);
public static L_FromListCb L_FromList;
public delegate string L_PFromListCb(IList<string> list, double force_n = double.NaN);
public static L_PFromListCb L_Pluralize;
public delegate bool L_PListCheckCb(IList<string> list, string plural_mark);
public static L_PListCheckCb L_IsPlural;
public static void ensure(MetaIoError err)
{
if(err != 0)
throw new MetaException(err);
}
static bool canSkipOptionalRead(MetaIoError err, MetaSyncFieldOpts opts)
{
return err != 0 && (opts & MetaSyncFieldOpts.SKIP_OPTIONAL) == MetaSyncFieldOpts.SKIP_OPTIONAL;
}
static MetaIoError checkRead(MetaIoError err, MetaSyncFieldOpts opts)
{
if(canSkipOptionalRead(err, opts))
{
LogWarn("Skipping optional field");
return MetaIoError.NONE;
}
else
return err;
}
public static void Sync(MetaSyncContext ctx, ref byte[] v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
{
int len = 0;
ensure(checkRead(ctx.reader.ReadRaw(ref v, ref len), opts));
}
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteRaw(v));
}
public static void Sync(MetaSyncContext ctx, ref string v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
ensure(checkRead(ctx.reader.ReadString(ref v), opts));
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteString(v));
}
public static void Sync(MetaSyncContext ctx, ref ObscuredString v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
{
string tmp = string.Empty;
ensure(checkRead(ctx.reader.ReadString(ref tmp), opts));
v = tmp;
}
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteString(v));
}
public static void Sync(MetaSyncContext ctx, ref long v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
ensure(checkRead(ctx.reader.ReadI64(ref v), opts));
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteI64(v));
}
public static void Sync(MetaSyncContext ctx, ref ObscuredLong v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
{
long tmp = 0;
ensure(checkRead(ctx.reader.ReadI64(ref tmp), opts));
v = tmp;
}
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteI64(v));
}
public static void Sync(MetaSyncContext ctx, ref int v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
ensure(checkRead(ctx.reader.ReadI32(ref v), opts));
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteI32(v));
}
public static void Sync(MetaSyncContext ctx, ref ObscuredInt v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
{
int tmp = 0;
ensure(checkRead(ctx.reader.ReadI32(ref tmp), opts));
v = tmp;
}
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteI32(v));
}
public static void Sync(MetaSyncContext ctx, ref short v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
ensure(checkRead(ctx.reader.ReadI16(ref v), opts));
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteI16(v));
}
public static void Sync(MetaSyncContext ctx, ref ObscuredShort v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
{
short tmp = 0;
ensure(checkRead(ctx.reader.ReadI16(ref tmp), opts));
v = tmp;
}
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteI16(v));
}
public static void Sync(MetaSyncContext ctx, ref sbyte v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
ensure(checkRead(ctx.reader.ReadI8(ref v), opts));
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteI8(v));
}
public static void Sync(MetaSyncContext ctx, ref ObscuredSByte v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
{
sbyte tmp = 0;
ensure(checkRead(ctx.reader.ReadI8(ref tmp), opts));
v = tmp;
}
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteI8(v));
}
public static void Sync(MetaSyncContext ctx, ref ulong v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
ensure(checkRead(ctx.reader.ReadU64(ref v), opts));
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteU64(v));
}
public static void Sync(MetaSyncContext ctx, ref ObscuredULong v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
{
ulong tmp = 0;
ensure(checkRead(ctx.reader.ReadU64(ref tmp), opts));
v = tmp;
}
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteU64(v));
}
public static void Sync(MetaSyncContext ctx, ref ushort v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
ensure(checkRead(ctx.reader.ReadU16(ref v), opts));
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteU16(v));
}
public static void Sync(MetaSyncContext ctx, ref ObscuredUShort v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
{
ushort tmp = 0;
ensure(checkRead(ctx.reader.ReadU16(ref tmp), opts));
v = tmp;
}
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteU16(v));
}
public static void Sync(MetaSyncContext ctx, ref uint v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
ensure(checkRead(ctx.reader.ReadU32(ref v), opts));
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteU32(v));
}
public static void Sync(MetaSyncContext ctx, ref ObscuredUInt v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
{
uint tmp = 0;
ensure(checkRead(ctx.reader.ReadU32(ref tmp), opts));
v = tmp;
}
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteU32(v));
}
public static void Sync(MetaSyncContext ctx, ref byte v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
ensure(checkRead(ctx.reader.ReadU8(ref v), opts));
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteU8(v));
}
public static void Sync(MetaSyncContext ctx, ref ObscuredByte v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
{
byte tmp = 0;
ensure(checkRead(ctx.reader.ReadU8(ref tmp), opts));
v = tmp;
}
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteU8(v));
}
public static void Sync(MetaSyncContext ctx, ref bool v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
ensure(checkRead(ctx.reader.ReadBool(ref v), opts));
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteBool(v));
}
public static void Sync(MetaSyncContext ctx, ref ObscuredBool v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
{
bool tmp = false;
ensure(checkRead(ctx.reader.ReadBool(ref tmp), opts));
v = tmp;
}
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteBool(v));
}
public static void Sync(MetaSyncContext ctx, ref float v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
ensure(checkRead(ctx.reader.ReadFloat(ref v), opts));
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteFloat(v));
}
public static void Sync(MetaSyncContext ctx, ref ObscuredFloat v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
{
float tmp = 0f;
ensure(checkRead(ctx.reader.ReadFloat(ref tmp), opts));
v = tmp;
}
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteFloat(v));
}
public static void Sync(MetaSyncContext ctx, ref double v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
ensure(checkRead(ctx.reader.ReadDouble(ref v), opts));
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteDouble(v));
}
public static void Sync(MetaSyncContext ctx, ref ObscuredDouble v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
{
double tmp = 0;
ensure(checkRead(ctx.reader.ReadDouble(ref tmp), opts));
v = tmp;
}
else if(ctx.CanWriteField(opts))
ensure(ctx.writer.WriteDouble(v));
}
static int SyncBeginListGetSize(MetaSyncContext ctx, IList v, MetaSyncFieldOpts opts)
{
if(ctx.CanReadField(opts))
{
var err = ctx.reader.BeginContainer();
if(canSkipOptionalRead(err, opts))
{
LogWarn("Skipping optional array field");
return -1;
}
ensure(err);
int size = 0;
ensure(ctx.reader.GetContainerSize(ref size));
return size;
}
else if(ctx.CanWriteField(opts))
{
int size = v == null ? 0 : v.Count;
ensure(ctx.writer.BeginContainer(size));
return size;
}
else
return -1;
}
static int SyncBeginList<T>(MetaSyncContext ctx, List<T> v, ref MetaSyncFieldOpts opts)
{
int size = SyncBeginListGetSize(ctx, v, opts);
if(size == -1)
return size;
if(ctx.is_read && v.Capacity < size)
v.Capacity = size;
//NOTE: unsetting opts for array items
opts &= ~MetaSyncFieldOpts.SKIP_OPTIONAL;
opts &= ~MetaSyncFieldOpts.SKIP_NOT_IN_MASK;
return size;
}
static void SyncEndList(MetaSyncContext ctx, IList v)
{
if(ctx.is_read)
ensure(ctx.reader.EndContainer());
else
ensure(ctx.writer.EndContainer());
}
public static void Sync(MetaSyncContext ctx, List<string> v, MetaSyncFieldOpts opts = 0)
{
int size = SyncBeginList(ctx, v, ref opts);
if(size == -1)
return;
for(int i = 0; i < size; ++i)
{
var tmp = ctx.is_read ? "" : v[i];
Sync(ctx, ref tmp, opts);
if(ctx.is_read)
v.Add(tmp);
}
SyncEndList(ctx, v);
}
public static void Sync(MetaSyncContext ctx, List<long> v, MetaSyncFieldOpts opts = 0)
{
int size = SyncBeginList(ctx, v, ref opts);
if(size == -1)
return;
for(int i = 0; i < size; ++i)
{
var tmp = ctx.is_read ? default(long) : v[i];
Sync(ctx, ref tmp, opts);
if(ctx.is_read)
v.Add(tmp);
}
SyncEndList(ctx, v);
}
public static void Sync(MetaSyncContext ctx, List<int> v, MetaSyncFieldOpts opts = 0)
{
int size = SyncBeginList(ctx, v, ref opts);
if(size == -1)
return;
for(int i = 0; i < size; ++i)
{
var tmp = ctx.is_read ? default(int) : v[i];
Sync(ctx, ref tmp, opts);
if(ctx.is_read)
v.Add(tmp);
}
SyncEndList(ctx, v);
}
public static void Sync(MetaSyncContext ctx, List<short> v, MetaSyncFieldOpts opts = 0)
{
int size = SyncBeginList(ctx, v, ref opts);
if(size == -1)
return;
for(int i = 0; i < size; ++i)
{
var tmp = ctx.is_read ? default(short) : v[i];
Sync(ctx, ref tmp, opts);
if(ctx.is_read)
v.Add(tmp);
}
SyncEndList(ctx, v);
}
public static void Sync(MetaSyncContext ctx, List<sbyte> v, MetaSyncFieldOpts opts = 0)
{
int size = SyncBeginList(ctx, v, ref opts);
if(size == -1)
return;
for(int i = 0; i < size; ++i)
{
var tmp = ctx.is_read ? default(sbyte) : v[i];
Sync(ctx, ref tmp, opts);
if(ctx.is_read)
v.Add(tmp);
}
SyncEndList(ctx, v);
}
public static void Sync(MetaSyncContext ctx, List<ulong> v, MetaSyncFieldOpts opts = 0)
{
int size = SyncBeginList(ctx, v, ref opts);
if(size == -1)
return;
for(int i = 0; i < size; ++i)
{
var tmp = ctx.is_read ? default(ulong) : v[i];
Sync(ctx, ref tmp, opts);
if(ctx.is_read)
v.Add(tmp);
}
SyncEndList(ctx, v);
}
public static void Sync(MetaSyncContext ctx, List<uint> v, MetaSyncFieldOpts opts = 0)
{
int size = SyncBeginList(ctx, v, ref opts);
if(size == -1)
return;
for(int i = 0; i < size; ++i)
{
var tmp = ctx.is_read ? default(uint) : v[i];
Sync(ctx, ref tmp, opts);
if(ctx.is_read)
v.Add(tmp);
}
SyncEndList(ctx, v);
}
public static void Sync(MetaSyncContext ctx, List<ushort> v, MetaSyncFieldOpts opts = 0)
{
int size = SyncBeginList(ctx, v, ref opts);
if(size == -1)
return;
for(int i = 0; i < size; ++i)
{
var tmp = ctx.is_read ? default(ushort) : v[i];
Sync(ctx, ref tmp, opts);
if(ctx.is_read)
v.Add(tmp);
}
SyncEndList(ctx, v);
}
public static void Sync(MetaSyncContext ctx, List<byte> v, MetaSyncFieldOpts opts = 0)
{
int size = SyncBeginList(ctx, v, ref opts);
if(size == -1)
return;
for(int i = 0; i < size; ++i)
{
var tmp = ctx.is_read ? default(byte) : v[i];
Sync(ctx, ref tmp, opts);
if(ctx.is_read)
v.Add(tmp);
}
SyncEndList(ctx, v);
}
public static void Sync(MetaSyncContext ctx, List<bool> v, MetaSyncFieldOpts opts = 0)
{
int size = SyncBeginList(ctx, v, ref opts);
if(size == -1)
return;
for(int i = 0; i < size; ++i)
{
var tmp = ctx.is_read ? default(bool) : v[i];
Sync(ctx, ref tmp, opts);
if(ctx.is_read)
v.Add(tmp);
}
SyncEndList(ctx, v);
}
public static void Sync(MetaSyncContext ctx, List<float> v, MetaSyncFieldOpts opts = 0)
{
int size = SyncBeginList(ctx, v, ref opts);
if(size == -1)
return;
for(int i = 0; i < size; ++i)
{
var tmp = ctx.is_read ? default(float) : v[i];
Sync(ctx, ref tmp, opts);
if(ctx.is_read)
v.Add(tmp);
}
SyncEndList(ctx, v);
}
public static void Sync(MetaSyncContext ctx, List<double> v, MetaSyncFieldOpts opts = 0)
{
int size = SyncBeginList(ctx, v, ref opts);
if(size == -1)
return;
for(int i = 0; i < size; ++i)
{
var tmp = ctx.is_read ? default(double) : v[i];
Sync(ctx, ref tmp, opts);
if(ctx.is_read)
v.Add(tmp);
}
SyncEndList(ctx, v);
}
public static void Sync<T>(MetaSyncContext ctx, List<T> v, MetaSyncFieldOpts opts = 0) where T : IMetaStruct, new()
{
int size = SyncBeginList(ctx, v, ref opts);
if(size == -1)
return;
if(ctx.is_read)
v.Clear();
for(int i = 0; i < size; ++i)
{
var tmp = ctx.is_read ? new T() : v[i];
Sync(ctx, ref tmp, opts);
if(ctx.is_read)
v.Add(tmp);
}
SyncEndList(ctx, v);
}
public static IMetaStruct SyncGeneric(MetaSyncContext ctx, IMetaStruct v, MetaSyncFieldOpts opts = 0)
{
if(ctx.CanReadField(opts))
{
ensure(ctx.reader.BeginContainer());
uint clid = 0;
ensure(ctx.reader.ReadU32(ref clid));
//NOTE: when reading we ignore the passed argument
v = ctx.factory(clid);
if(v == null)
{
LogError("Could not create struct: " + clid);
ensure(MetaIoError.TYPE_DONT_MATCH);
}
v.reset();
v.syncFields(ctx);
ensure(ctx.reader.EndContainer());
}
else if(ctx.CanWriteField(opts))
{
ensure(ctx.writer.BeginContainer(v.getFieldsCount() + 1));
ensure(ctx.writer.WriteU32(v.CLASS_ID()));
v.syncFields(ctx);
ensure(ctx.writer.EndContainer());
}
return v;
}
public static void SyncGeneric<T>(MetaSyncContext ctx, List<T> v, MetaSyncFieldOpts opts = 0) where T : IMetaStruct, new()
{
int size = SyncBeginList(ctx, v, ref opts);
if(size == -1)
return;
for(int i = 0; i < size; ++i)
{
var tmp = SyncGeneric(ctx, ctx.is_read ? default(T) : v[i]);
if(ctx.is_read)
v.Add((T)tmp);
}
SyncEndList(ctx, v);
}
public static void Sync<T>(MetaSyncContext ctx, ref T v, MetaSyncFieldOpts opts = 0) where T : IMetaStruct
{
if(ctx.CanReadField(opts))
{
var err = ctx.reader.BeginContainer();
if(canSkipOptionalRead(err, opts))
{
LogWarn("Skipping optional struct field");
return;
}
ensure(err);
v.reset();
v.syncFields(ctx);
ensure(ctx.reader.EndContainer());
}
else if(ctx.CanWriteField(opts))
{
int array_size = getWriteFieldsCount(ctx, v);
ensure(ctx.writer.BeginContainer(array_size));
v.syncFields(ctx);
ensure(ctx.writer.EndContainer());
}
}
public static MetaIoError SyncSafe<T>(MetaSyncContext ctx, ref T v, MetaSyncFieldOpts opts = 0) where T : IMetaStruct
{
try
{
Sync(ctx, ref v, opts);
}
catch(MetaException e)
{
LogError(e.Message + " " + e.StackTrace);
return e.err;
}
catch(Exception e)
{
LogError(e.Message + " " + e.StackTrace);
return MetaIoError.GENERIC;
}
return MetaIoError.NONE;
}
static int getWriteFieldsCount(MetaSyncContext ctx, IMetaStruct v)
{
if(ctx.IsMaskUsed())
return v.getWritableFieldsCount();
else
return v.getFieldsCount();
}
public static MetaSyncContext PrepareForClone<T>(ref T src) where T : IMetaStruct
{
var stream = new MemoryStream();
var ctx = new MetaSyncContext() {
is_read = false,
reader = new MsgPackDataReader(stream),
writer = new MsgPackDataWriter(stream),
opts = 0
};
Sync(ctx, ref src);
ctx.is_read = true;
stream.Position = 0;
return ctx;
}
//Shared mask utils below
public static int GetDirtyFieldsCount(long fields_mask, int fields_count)
{
int changed_fields = 0;
long ptr = 1L;
for(int i=0; i<fields_count; ++i, ptr = ptr << 1)
{
if((ptr & fields_mask) != 0)
changed_fields++;
}
return changed_fields;
}
public static void SetFieldDirty(ref long fields_mask, int field_index)
{
long diff = 1L << field_index;
fields_mask |= diff;
}
public static bool IsFieldDirty(long fields_mask, int field_index)
{
return (fields_mask & 1L << field_index) != 0;
}
public static void ClearList<T>(ref List<T> v)
{
if(v == null)
v = new List<T>();
v.Clear();
}
public static string I18NPick(string raw_val, List<string> list_val, string plural_marker, double pluralize_for_n)
{
if(raw_val.Length != 0)
return Meta.L_T(raw_val);
if(Meta.L_IsPlural(list_val, plural_marker))
return Meta.L_Pluralize(list_val, pluralize_for_n);
return Meta.L_FromList(list_val);
}
public static void Reset<T>(ref T v) where T : IMetaStruct, new()
{
if(v == null)
v = new T();
v.reset();
}
}
public class MsgPackDataWriter : IDataWriter
{
Stream stream;
MsgPackWriter io;
Stack<int> space = new Stack<int>();
public MsgPackDataWriter(Stream _stream)
{
reset(_stream);
}
public void reset(Stream _stream)
{
stream = _stream;
io = new MsgPackWriter(stream);
space.Clear();
space.Push(1);
}
MetaIoError decSpace()
{
if(space.Count == 0)
return MetaIoError.NO_SPACE_LEFT_IN_ARRAY;
int left = space.Pop();
left--;
if(left < 0)
return MetaIoError.NO_SPACE_LEFT_IN_ARRAY;
space.Push(left);
return 0;
}
public MetaIoError BeginContainer(int size)
{
MetaIoError err = decSpace();
if(err != 0)
return err;
space.Push(size);
io.WriteArrayHeader(size);
return 0;
}
public MetaIoError EndContainer()
{
if(space.Count <= 1)
return MetaIoError.ARRAY_STACK_IS_EMPTY;
int left = space.Pop();
if(left != 0)
return MetaIoError.HAS_LEFT_SPACE;
return 0;
}
public MetaIoError End()
{
if(space.Count != 1)
return MetaIoError.ARRAY_STACK_IS_EMPTY;
return 0;
}
public MetaIoError WriteI8(sbyte v)
{
io.Write(v);
return decSpace();
}
public MetaIoError WriteU8(byte v)
{
io.Write(v);
return decSpace();
}
public MetaIoError WriteI16(short v)
{
io.Write(v);
return decSpace();
}
public MetaIoError WriteU16(ushort v)
{
io.Write(v);
return decSpace();
}
public MetaIoError WriteI32(int v)
{
io.Write(v);
return decSpace();
}
public MetaIoError WriteU32(uint v)
{
io.Write(v);
return decSpace();
}
public MetaIoError WriteU64(ulong v)
{
io.Write(v);
return decSpace();
}
public MetaIoError WriteI64(long v)
{
io.Write(v);
return decSpace();
}
public MetaIoError WriteBool(bool v)
{
io.Write(v);
return decSpace();
}
public MetaIoError WriteFloat(float v)
{
io.Write(v);
return decSpace();
}
public MetaIoError WriteDouble(double v)
{
io.Write(v);
return decSpace();
}
public MetaIoError WriteString(string v)
{
if(v == null)
io.Write("");
else
io.Write(v);
return decSpace();
}
public MetaIoError WriteNil()
{
io.WriteNil();
return decSpace();
}
public MetaIoError WriteRaw(byte[] v)
{
io.Write(v);
return decSpace();
}
}
public class MsgPackDataReader : IDataReader
{
Stream stream;
MsgPackReader io;
public struct ContainerPosition
{
public int max;
public int curr;
public ContainerPosition(int length)
{
curr = 0;
max = length - 1;
}
}
Stack<ContainerPosition> stack = new Stack<ContainerPosition>();
public MsgPackDataReader(Stream _stream)
{
reset(_stream);
}
public void reset(Stream _stream)
{
stream = _stream;
stack.Clear();
io = new MsgPackReader(stream);
}
public void setPos(long pos)
{
stream.Position = pos;
stack.Clear();
}
int nextInt(ref MetaIoError err)
{
if(!ContainerPositionValid())
{
err = MetaIoError.DATA_MISSING;
return 0;
}
if(!io.Read())
{
err = MetaIoError.FAIL_READ;
return 0;
}
ContainerPositionMoveNext();
if(io.IsSigned())
return io.ValueSigned;
else if(io.IsUnsigned())
return (int)io.ValueUnsigned;
else
{
Meta.LogWarn("Got type: " + io.Type);
err = MetaIoError.TYPE_DONT_MATCH;
return 0;
}
}
uint nextUint(ref MetaIoError err)
{
if(!ContainerPositionValid())
{
err = MetaIoError.DATA_MISSING;
return 0;
}
if(!io.Read())
{
err = MetaIoError.FAIL_READ;
return 0;
}
ContainerPositionMoveNext();
if(io.IsUnsigned())
return io.ValueUnsigned;
else if(io.IsSigned())
return (uint)io.ValueSigned;
else
{
Meta.LogWarn("Got type: " + io.Type);
err = MetaIoError.TYPE_DONT_MATCH;
return 0;
}
}
bool nextBool(ref MetaIoError err)
{
if(!ContainerPositionValid())
{
err = MetaIoError.DATA_MISSING;
return false;
}
if(!io.Read())
{
err = MetaIoError.FAIL_READ;
return false;
}
ContainerPositionMoveNext();
if(io.IsBoolean())
return (bool)io.ValueBoolean;
else if(io.IsUnsigned())
return io.ValueUnsigned != 0;
else if(io.IsSigned())
return (uint)io.ValueSigned != 0;
else
{
Meta.LogWarn("Got type: " + io.Type);
err = MetaIoError.TYPE_DONT_MATCH;
return false;
}
}
ulong nextUint64(ref MetaIoError err)
{
if(!ContainerPositionValid())
{
err = MetaIoError.DATA_MISSING;
return 0;
}
if(!io.Read())
{
err = MetaIoError.FAIL_READ;
return 0;
}
ContainerPositionMoveNext();
if(io.IsUnsigned())
return io.ValueUnsigned;
else if(io.IsSigned())
return (ulong)io.ValueSigned;
else if(io.IsUnsigned64())
return io.ValueUnsigned64;
else if(io.IsSigned64())
return (ulong)io.ValueSigned64;
else
{
Meta.LogWarn("Got type: " + io.Type);
err = MetaIoError.TYPE_DONT_MATCH;
return 0;
}
}
long nextInt64(ref MetaIoError err)
{
if(!ContainerPositionValid())
{
err = MetaIoError.DATA_MISSING;
return 0;
}
if(!io.Read())
{
err = MetaIoError.FAIL_READ;
return 0;
}
ContainerPositionMoveNext();
if(io.IsUnsigned())
return (long)io.ValueUnsigned;
else if(io.IsSigned())
return io.ValueSigned;
else if(io.IsUnsigned64())
return (long)io.ValueUnsigned64;
else if(io.IsSigned64())
return io.ValueSigned64;
else
{
Meta.LogWarn("Got type: " + io.Type);
err = MetaIoError.TYPE_DONT_MATCH;
return 0;
}
}
public MetaIoError ReadI8(ref sbyte v)
{
MetaIoError err = 0;
v = (sbyte) nextInt(ref err);
return err;
}
public MetaIoError ReadI16(ref short v)
{
MetaIoError err = 0;
v = (short) nextInt(ref err);
return err;
}
public MetaIoError ReadI32(ref int v)
{
MetaIoError err = 0;
v = nextInt(ref err);
return err;
}
public MetaIoError ReadU8(ref byte v)
{
MetaIoError err = 0;
v = (byte) nextUint(ref err);
return err;
}
public MetaIoError ReadU16(ref ushort v)
{
MetaIoError err = 0;
v = (ushort) nextUint(ref err);
return err;
}
public MetaIoError ReadU32(ref uint v)
{
MetaIoError err = 0;
v = nextUint(ref err);
return err;
}
public MetaIoError ReadU64(ref ulong v)
{
MetaIoError err = 0;
v = nextUint64(ref err);
return err;
}
public MetaIoError ReadI64(ref long v)
{
MetaIoError err = 0;
v = nextInt64(ref err);
return err;
}
public MetaIoError ReadBool(ref bool v)
{
MetaIoError err = 0;
v = nextBool(ref err);
return err;
}
public MetaIoError ReadFloat(ref float v)
{
if(!ContainerPositionValid())
return MetaIoError.DATA_MISSING;
if(!io.Read())
{
return MetaIoError.FAIL_READ;
}
if(io.IsUnsigned())
{
v = io.ValueUnsigned;
}
else if(io.IsSigned())
{
v = io.ValueSigned;
}
else
{
switch(io.Type)
{
case TypePrefixes.Float:
v = io.ValueFloat;
break;
case TypePrefixes.Double:
var tmp = io.ValueDouble;
//TODO:
//if(tmp > float.MaxValue || tmp < float.MinValue)
//{
// Meta.LogWarn("Double -> Float bad conversion: " + tmp);
// return MetaIoError.TYPE_DONT_MATCH;
//}
v = (float) tmp;
break;
default:
Meta.LogWarn("Got type: " + io.Type);
return MetaIoError.TYPE_DONT_MATCH;
}
}
ContainerPositionMoveNext();
return 0;
}
public MetaIoError ReadDouble(ref double v)
{
if(!ContainerPositionValid())
return MetaIoError.DATA_MISSING;
if(!io.Read())
{
return MetaIoError.FAIL_READ;
}
if(io.IsUnsigned())
{
v = io.ValueUnsigned;
}
else if(io.IsSigned())
{
v = io.ValueSigned;
}
else
{
switch(io.Type)
{
case TypePrefixes.Float:
v = (double) io.ValueFloat;
break;
case TypePrefixes.Double:
v = io.ValueDouble;
break;
case TypePrefixes.UInt64:
v = (double) io.ValueUnsigned64;
break;
case TypePrefixes.Int64:
v = (double) io.ValueSigned64;
break;
default:
Meta.LogWarn("Got type: " + io.Type);
return MetaIoError.TYPE_DONT_MATCH;
}
}
ContainerPositionMoveNext();
return 0;
}
public MetaIoError ReadRaw(ref byte[] v, ref int vlen)
{
if(!ContainerPositionValid())
return MetaIoError.DATA_MISSING;
if(!io.Read())
return MetaIoError.FAIL_READ;
if(!io.IsRaw())
{
Meta.LogWarn("Got type: " + io.Type);
return MetaIoError.TYPE_DONT_MATCH;
}
vlen = (int)io.Length;
if(v == null)
v = new byte[vlen];
else if(v.Length < vlen)
Array.Resize(ref v, vlen);
io.ReadValueRaw(v, 0, vlen);
ContainerPositionMoveNext();
return 0;
}
public MetaIoError ReadNil()
{
if(!ContainerPositionValid())
return MetaIoError.DATA_MISSING;
if(!io.Read())
return MetaIoError.FAIL_READ;
if(io.Type != TypePrefixes.Nil)
{
Meta.LogWarn("Got type: " + io.Type);
return MetaIoError.TYPE_DONT_MATCH;
}
ContainerPositionMoveNext();
return 0;
}
public MetaIoError ReadString(ref string v)
{
if(!ContainerPositionValid())
return MetaIoError.DATA_MISSING;
if(!io.Read())
return MetaIoError.FAIL_READ;
if(!io.IsRaw())
{
Meta.LogWarn("Got type: " + io.Type);
return MetaIoError.TYPE_DONT_MATCH;
}
//TODO: use shared buffer for strings loading
byte[] strval = new byte[io.Length];
io.ReadValueRaw(strval, 0, strval.Length);
v = System.Text.Encoding.UTF8.GetString(strval);
ContainerPositionMoveNext();
return 0;
}
public MetaIoError BeginContainer()
{
if(!ContainerPositionValid())
return MetaIoError.DATA_MISSING;
if(!io.Read())
return MetaIoError.FAIL_READ;
if(!io.IsArray())
{
Meta.LogWarn("Got type: " + io.Type);
return MetaIoError.TYPE_DONT_MATCH;
}
ContainerPosition ap = new ContainerPosition((int)io.Length);
stack.Push(ap);
return 0;
}
public MetaIoError GetContainerSize(ref int v)
{
if(!io.IsArray())
{
Meta.LogWarn("Got type: " + io.Type);
return MetaIoError.TYPE_DONT_MATCH;
}
v = (int) io.Length;
return 0;
}
void SkipField()
{
if(!io.Read())
return;
if(!io.IsArray() && !io.IsMap())
{
//NOTE: if value is a raw string we need to read all of its data
if(io.IsRaw())
io.ReadRawString();
return;
}
uint array_len = io.Length;
for(uint i=0; i<array_len; ++i)
SkipField();
}
void SkipTrailingFields()
{
while(ContainerEntriesLeft() > -1)
{
SkipField();
ContainerPositionMoveNext();
}
}
public MetaIoError EndContainer()
{
SkipTrailingFields();
stack.Pop();
ContainerPositionMoveNext();
return 0;
}
int ContainerEntriesLeft()
{
if(stack.Count == 0)
return 0;
ContainerPosition ap = stack.Peek();
return ap.max - ap.curr;
}
bool ContainerPositionValid()
{
return ContainerEntriesLeft() >= 0;
}
void ContainerPositionMoveNext()
{
if(stack.Count > 0)
{
ContainerPosition ap = stack.Pop();
ap.curr++;
stack.Push(ap);
}
}
}
} //namespace metagen