// Outputs a DEFINE_IL2CPP_ARG_TYPE call for all root or non-generic types defined by this file
        private void DefineIl2CppArgTypes(CppStreamWriter writer, CppTypeContext context)
        {
            var type = context.LocalType;

            // DEFINE_IL2CPP_ARG_TYPE
            var(ns, il2cppName) = type.This.GetIl2CppName();
            // For Name and Namespace here, we DO want all the `, /, etc
            if (!type.This.IsGeneric)
            {
                IncludeIl2CppTypeCheckIfNotAlready(writer);
                string fullName = context.GetCppName(context.LocalType.This, true, true, CppTypeContext.NeedAs.Definition, CppTypeContext.ForceAsType.Literal)
                                  ?? throw new UnresolvedTypeException(context.LocalType.This, context.LocalType.This);
                if (context.LocalType.Info.Refness == Refness.ReferenceType)
                {
                    fullName += "*";
                }
                writer.WriteLine($"DEFINE_IL2CPP_ARG_TYPE({fullName}, \"{ns}\", \"{il2cppName}\");");
            }
            else if (type.This.DeclaringType is null || !type.This.DeclaringType.IsGeneric)
            {
                IncludeIl2CppTypeCheckIfNotAlready(writer);
                string templateName = context.GetCppName(context.LocalType.This, true, false, CppTypeContext.NeedAs.Declaration, CppTypeContext.ForceAsType.Literal)
                                      ?? throw new UnresolvedTypeException(context.LocalType.This, context.LocalType.This);
                var structStr = context.LocalType.Info.Refness == Refness.ReferenceType ? "CLASS" : "STRUCT";
                writer.WriteLine($"DEFINE_IL2CPP_ARG_TYPE_GENERIC_{structStr}({templateName}, \"{ns}\", \"{il2cppName}\");");
            }

            foreach (var nested in context.NestedContexts.Where(n => n.InPlace))
            {
                DefineIl2CppArgTypes(writer, nested);
            }
        }
        internal void Serialize(CppTypeContext context)
        {
            var data           = context.LocalType;
            var headerLocation = Path.Combine(_config.OutputDirectory, _config.OutputHeaderDirectory, context.HeaderFileName);

            Directory.CreateDirectory(Path.GetDirectoryName(headerLocation));
            using var ms        = new MemoryStream();
            using var rawWriter = new StreamWriter(ms);
            using var writer    = new CppStreamWriter(rawWriter, "  ");
            // Write header
            writer.WriteComment($"Autogenerated from {nameof(CppHeaderCreator)}");
            writer.WriteComment("Created by Sc2ad");
            writer.WriteComment("=========================================================================");
            writer.WriteLine("#pragma once");
            // TODO: determine when/if we need this
            // For sizes that are valid, we ALSO want to write with pack of 1
            // Invalid sizes are ignored.

            // Write SerializerContext and actual type
            try
            {
                _serializer.Serialize(writer, context, true);
            }
            catch (UnresolvedTypeException e)
            {
                if (_config.UnresolvedTypeExceptionHandling?.TypeHandling == UnresolvedTypeExceptionHandling.DisplayInFile)
                {
                    writer.WriteComment("Unresolved type exception!");
                    writer.WriteLine("/*");
                    writer.WriteLine(e);
                    writer.WriteLine("*/");
                }
                else if (_config.UnresolvedTypeExceptionHandling?.TypeHandling == UnresolvedTypeExceptionHandling.SkipIssue)
                {
                    return;
                }
                else if (_config.UnresolvedTypeExceptionHandling?.TypeHandling == UnresolvedTypeExceptionHandling.Elevate)
                {
                    throw new InvalidOperationException($"Cannot elevate {e} to a parent type- there is no parent type!");
                }
            }
            // End the namespace
            writer.CloseDefinition();
            hasIl2CppTypeCheckInclude = context.NeedIl2CppUtilsFunctionsInHeader;

            if (data.This.Namespace == "System" && data.This.Name == "ValueType")
            {
                IncludeIl2CppTypeCheckIfNotAlready(writer);
                writer.WriteLine("template<class T>");
                writer.WriteLine("struct is_value_type<T, typename std::enable_if_t<std::is_base_of_v<System::ValueType, T>>> : std::true_type{};");
            }

            DefineIl2CppArgTypes(writer, context);
            writer.WriteLine("#include \"extern/beatsaber-hook/shared/utils/il2cpp-utils-methods.hpp\"");
            _serializer.WritePostSerializeMethods(writer, context, true);
            writer.Flush();

            writer.WriteIfDifferent(headerLocation, context);
        }
        internal void WriteIfDifferent(string filePath, CppTypeContext context)
        {
            if (!Written.Add(Path.GetFullPath(filePath)))
            {
                throw new InvalidOperationException($"Was about to overwrite existing file: {filePath} with context: {context.LocalType.This}");
            }

            if (WriteIfDifferent(filePath, rawWriter.BaseStream))
            {
                NumChangedFiles++;
            }
        }
Exemplo n.º 4
0
        internal void Serialize(CppTypeContext context)
        {
            var             sourceLocation = _config.OneSourceFile ? Path.Combine(_config.OutputDirectory, _config.OutputSourceDirectory, context.CppFileName) : overallSourceLocation;
            CppStreamWriter?writer         = overallStreamWriter;

            if (writer is null)
            {
                Directory.CreateDirectory(Path.GetDirectoryName(sourceLocation));
                using var ms        = new MemoryStream();
                using var rawWriter = new StreamWriter(ms);
                writer = new CppStreamWriter(rawWriter, "  ");
            }
            // Write header
            writer.WriteComment($"Autogenerated from {nameof(CppSourceCreator)}");
            writer.WriteComment($"Created by Sc2ad");
            writer.WriteComment("=========================================================================");
            try
            {
                // Write SerializerContext and actual type
                _serializer.Serialize(writer, context, false);
            }
            catch (UnresolvedTypeException e)
            {
                if (_config.UnresolvedTypeExceptionHandling?.TypeHandling == UnresolvedTypeExceptionHandling.DisplayInFile)
                {
                    writer.WriteLine("// Unresolved type exception!");
                    writer.WriteLine("/*");
                    writer.WriteLine(e);
                    writer.WriteLine("*/");
                }
                else if (_config.UnresolvedTypeExceptionHandling?.TypeHandling == UnresolvedTypeExceptionHandling.SkipIssue)
                {
                    return;
                }
                else if (_config.UnresolvedTypeExceptionHandling?.TypeHandling == UnresolvedTypeExceptionHandling.Elevate)
                {
                    throw new InvalidOperationException($"Cannot elevate {e} to a parent type- there is no parent type!");
                }
            }
            writer.Flush();

            if (overallStreamWriter is null)
            {
                writer.WriteIfDifferent(sourceLocation, context);
                writer.Close();
                writer.Dispose();
            }
        }
        // Resolve the field into context here
        public override void PreSerialize(CppTypeContext context, IField field)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (field is null)
            {
                throw new ArgumentNullException(nameof(field));
            }
            // In this situation, if the type is a pointer, we can simply forward declare.
            // Otherwise, we need to include the corresponding file. This must be resolved via context
            // If the resolved type name is null, we won't serialize this field
            // First, resolve the field type to see if it exists
            // If it does, because it is a field, we can FD it if it is a pointer
            // If it is not a pointer, then we need to include it
            // If it is a nested class, we need to deal with some stuff (maybe)
            var resolvedName = context.GetCppName(field.Type, true);

            if (!string.IsNullOrEmpty(resolvedName))
            {
                Resolved(field);
            }
            // In order to ensure we get an UnresolvedTypeException when we serialize
            ResolvedTypeNames.Add(field, resolvedName);

            string SafeFieldName()
            {
                var name = field.Name;

                if (name.EndsWith("k__BackingField"))
                {
                    name = name.Split(angleBrackets, StringSplitOptions.RemoveEmptyEntries)[0];
                }
                name = string.Join("$", name.Split(angleBrackets)).Trim('_');
                if (char.IsDigit(name[0]))
                {
                    name = "_" + name;
                }
                return(_config.SafeName(name));
            }

            SafeFieldNames.Add(field, SafeFieldName());
        }
        internal static void CreateConversionOperator(CppDataSerializer ser, ITypeData type, CppTypeContext self)
        {
            if (self._soloFieldConversionOperator != null)
            {
                return;
            }
            FieldConversionOperator?parentFieldConversionOperator = null;

            if (type.Parent != null)
            {
                var resolved = type.Parent.Resolve(self.Types);
                if (resolved is null)
                {
                    throw new UnresolvedTypeException(type.This, type.Parent);
                }
                var parentContext = CppDataSerializer.TypeToContext[resolved];
                CreateConversionOperator(ser, resolved, parentContext);
                parentFieldConversionOperator = parentContext._soloFieldConversionOperator;
            }
            self._soloFieldConversionOperator = new FieldConversionOperator(type, parentFieldConversionOperator);
        }
Exemplo n.º 7
0
 public abstract void PreSerialize(CppTypeContext context, T obj);