mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-07-01 00:31:56 +00:00
Import code from previous AssetBuilder version
This commit is contained in:
98
src/ZoneCodeGenerator/Generating/CodeGenerator.cs
Normal file
98
src/ZoneCodeGenerator/Generating/CodeGenerator.cs
Normal file
@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using ZoneCodeGenerator.Domain.StructureInformation;
|
||||
using ZoneCodeGenerator.Interface;
|
||||
using ZoneCodeGenerator.Persistence;
|
||||
|
||||
namespace ZoneCodeGenerator.Generating
|
||||
{
|
||||
static class CodeGenerator
|
||||
{
|
||||
private class GeneratorPreset
|
||||
{
|
||||
public string FileName { get; }
|
||||
public string TemplateName { get; }
|
||||
|
||||
public GeneratorPreset(string fileName, string templateName)
|
||||
{
|
||||
FileName = fileName;
|
||||
TemplateName = templateName;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, GeneratorPreset> presets =
|
||||
new Dictionary<string, GeneratorPreset>(StringComparer.CurrentCultureIgnoreCase)
|
||||
{
|
||||
{
|
||||
"ZoneLoad", new GeneratorPreset("$asset/$asset_load_db", "ZoneLoad.stg")
|
||||
},
|
||||
{
|
||||
"ZoneWrite", new GeneratorPreset("$asset/$asset_write_db", "ZoneWrite.stg")
|
||||
}
|
||||
};
|
||||
|
||||
public static IEnumerable<string> Presets => presets.Keys;
|
||||
|
||||
public static bool GenerateCodeForPreset(string presetName, StructureInformation asset, CUISession session)
|
||||
{
|
||||
if (!presets.ContainsKey(presetName))
|
||||
return false;
|
||||
|
||||
var preset = presets[presetName];
|
||||
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(session.GeneratorOutputPath))
|
||||
Directory.CreateDirectory(session.GeneratorOutputPath);
|
||||
|
||||
var codeTemplate = CodeTemplate.FromResources(preset.TemplateName);
|
||||
|
||||
if (codeTemplate == null)
|
||||
{
|
||||
Console.WriteLine($"Could not find template '{preset.TemplateName}'");
|
||||
return false;
|
||||
}
|
||||
|
||||
var resolvedFileName = preset.FileName.Replace("$asset", asset.Type.Name.ToLower());
|
||||
var fullPath = Path.Combine(session.GeneratorOutputPath, resolvedFileName);
|
||||
var folderOfFile = Path.GetDirectoryName(fullPath);
|
||||
|
||||
if (!Directory.Exists(folderOfFile))
|
||||
Directory.CreateDirectory(folderOfFile);
|
||||
|
||||
var renderingContext = RenderingContext.BuildContext(session, asset);
|
||||
|
||||
if (renderingContext == null)
|
||||
return false;
|
||||
|
||||
var generatedCode = false;
|
||||
if (codeTemplate.HasHeaderTemplate)
|
||||
{
|
||||
generatedCode = true;
|
||||
using (var fileStream = new FileStream(fullPath + ".h", FileMode.Create))
|
||||
{
|
||||
codeTemplate.RenderHeaderFile(fileStream, renderingContext);
|
||||
fileStream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
if (codeTemplate.HasSourceTemplate)
|
||||
{
|
||||
generatedCode = true;
|
||||
using (var fileStream = new FileStream(fullPath + ".cpp", FileMode.Create))
|
||||
{
|
||||
codeTemplate.RenderSourceFile(fileStream, renderingContext);
|
||||
fileStream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
return generatedCode;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
54
src/ZoneCodeGenerator/Generating/CodeTemplate.cs
Normal file
54
src/ZoneCodeGenerator/Generating/CodeTemplate.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using System.IO;
|
||||
using Antlr4.StringTemplate;
|
||||
|
||||
namespace ZoneCodeGenerator.Generating
|
||||
{
|
||||
class CodeTemplate
|
||||
{
|
||||
private const string SourceTemplateName = "source";
|
||||
private const string HeaderTemplateName = "header";
|
||||
|
||||
private readonly TemplateGroup templateGroup;
|
||||
|
||||
public bool HasSourceTemplate => templateGroup.IsDefined(SourceTemplateName);
|
||||
public bool HasHeaderTemplate => templateGroup.IsDefined(HeaderTemplateName);
|
||||
|
||||
private CodeTemplate(TemplateGroup templateGroup)
|
||||
{
|
||||
this.templateGroup = templateGroup;
|
||||
templateGroup.RegisterRenderer(typeof(string), new StringRenderer());
|
||||
}
|
||||
|
||||
public static CodeTemplate FromResources(string fileName)
|
||||
{
|
||||
var templateGroup = new TemplateGroupResources(fileName);
|
||||
|
||||
templateGroup.Load();
|
||||
|
||||
return new CodeTemplate(templateGroup);
|
||||
}
|
||||
|
||||
public void RenderSourceFile(Stream stream, RenderingContext context)
|
||||
{
|
||||
RenderTemplate(stream, templateGroup.GetInstanceOf(SourceTemplateName), context);
|
||||
}
|
||||
|
||||
public void RenderHeaderFile(Stream stream, RenderingContext context)
|
||||
{
|
||||
RenderTemplate(stream, templateGroup.GetInstanceOf(HeaderTemplateName), context);
|
||||
}
|
||||
|
||||
private static void RenderTemplate(Stream stream, Template template, RenderingContext context)
|
||||
{
|
||||
if (template == null)
|
||||
return;
|
||||
|
||||
template.Add("context", context);
|
||||
|
||||
using (var writer = new StreamWriter(stream))
|
||||
{
|
||||
template.Write(new AutoIndentWriter(writer));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
58
src/ZoneCodeGenerator/Generating/RenderingContext.cs
Normal file
58
src/ZoneCodeGenerator/Generating/RenderingContext.cs
Normal file
@ -0,0 +1,58 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ZoneCodeGenerator.Domain;
|
||||
using ZoneCodeGenerator.Domain.FastFileStructure;
|
||||
using ZoneCodeGenerator.Domain.StructureInformation;
|
||||
using ZoneCodeGenerator.Interface;
|
||||
using ZoneCodeGenerator.Persistence;
|
||||
|
||||
namespace ZoneCodeGenerator.Generating
|
||||
{
|
||||
class RenderingContext
|
||||
{
|
||||
public string Game { get; set; }
|
||||
public StructureInformation Asset { get; set; }
|
||||
public HashSet<StructureInformation> Structures { get; }
|
||||
public IEnumerable<StructureInformation> ReferencedAssets => Structures.Where(inf => inf.IsAsset && inf != Asset);
|
||||
|
||||
public List<FastFileBlock> Blocks { get; private set; }
|
||||
|
||||
public FastFileBlock DefaultNormalBlock => Blocks.FirstOrDefault(block => block.IsDefault && block.IsNormal) ??
|
||||
Blocks.FirstOrDefault(block => block.IsNormal);
|
||||
|
||||
private RenderingContext()
|
||||
{
|
||||
Structures = new HashSet<StructureInformation>();
|
||||
}
|
||||
|
||||
private void AddToContext(StructureInformation structureInformation)
|
||||
{
|
||||
if (!Structures.Add(structureInformation))
|
||||
return;
|
||||
|
||||
if (structureInformation.IsAsset && structureInformation != Asset)
|
||||
return;
|
||||
|
||||
foreach (var member in structureInformation.OrderedMembers)
|
||||
{
|
||||
if(member.StructureType != null)
|
||||
AddToContext(member.StructureType);
|
||||
}
|
||||
}
|
||||
|
||||
public static RenderingContext BuildContext(CUISession session, StructureInformation asset)
|
||||
{
|
||||
var context = new RenderingContext
|
||||
{
|
||||
Asset = asset,
|
||||
Game = session.Game,
|
||||
Blocks = session.Repository.GetAllFastFileBlocks().ToList()
|
||||
};
|
||||
|
||||
context.AddToContext(asset);
|
||||
|
||||
return context;
|
||||
}
|
||||
}
|
||||
}
|
126
src/ZoneCodeGenerator/Generating/TemplateGroupResources.cs
Normal file
126
src/ZoneCodeGenerator/Generating/TemplateGroupResources.cs
Normal file
@ -0,0 +1,126 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Antlr.Runtime;
|
||||
using Antlr4.StringTemplate;
|
||||
using Antlr4.StringTemplate.Compiler;
|
||||
using Antlr4.StringTemplate.Misc;
|
||||
|
||||
namespace ZoneCodeGenerator.Generating
|
||||
{
|
||||
public class TemplateGroupResources : TemplateGroup
|
||||
{
|
||||
private const string ResourceBasePath = "ZoneCodeGenerator.Generating.Templates";
|
||||
private const char DefaultDelimiterStart = '<';
|
||||
private const char DefaultDelimiterStop = '>';
|
||||
|
||||
private bool alreadyLoaded;
|
||||
private readonly string fileName;
|
||||
|
||||
public TemplateGroupResources(string fileName, char delimiterStartChar, char delimiterStopChar) : base(delimiterStartChar, delimiterStopChar)
|
||||
{
|
||||
this.fileName = fileName;
|
||||
alreadyLoaded = false;
|
||||
}
|
||||
|
||||
public TemplateGroupResources(string fileName) : this(fileName, DefaultDelimiterStart, DefaultDelimiterStop)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void ImportTemplates(IToken fileNameToken)
|
||||
{
|
||||
var text = Utility.Strip(fileNameToken.Text, 1);
|
||||
|
||||
TemplateGroup importingGroup = null;
|
||||
if (text.EndsWith(GroupFileExtension))
|
||||
{
|
||||
importingGroup = new TemplateGroupResources(text, DelimiterStartChar, DelimiterStopChar);
|
||||
}
|
||||
else if (text.EndsWith(TemplateFileExtension))
|
||||
{
|
||||
importingGroup = new TemplateGroup(DelimiterStartChar, DelimiterStopChar);
|
||||
|
||||
using (var resourceStream = StreamFromResources(text))
|
||||
{
|
||||
if (resourceStream != null)
|
||||
{
|
||||
using (var textStream = new StreamReader(resourceStream))
|
||||
{
|
||||
var inputStream = new ANTLRReaderStream(textStream)
|
||||
{
|
||||
name = fileName
|
||||
};
|
||||
|
||||
importingGroup.LoadTemplateFile("/", fileName, inputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (importingGroup != null)
|
||||
{
|
||||
importingGroup.Load();
|
||||
ImportTemplates(importingGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorManager.CompiletimeError(ErrorType.CANT_IMPORT, null, fileNameToken, text);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Load()
|
||||
{
|
||||
if (alreadyLoaded)
|
||||
return;
|
||||
alreadyLoaded = true;
|
||||
|
||||
if (Verbose)
|
||||
Console.WriteLine($"loading group file '{fileName}'");
|
||||
|
||||
using (var resourceStream = StreamFromResources(fileName))
|
||||
{
|
||||
if (resourceStream == null)
|
||||
{
|
||||
if (Verbose)
|
||||
Console.WriteLine($"Resource '{fileName}' doesn't exist");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
using (var textStream = new StreamReader(resourceStream))
|
||||
{
|
||||
var inputStream = new ANTLRReaderStream(textStream)
|
||||
{
|
||||
name = fileName
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var lexer = new GroupLexer(inputStream);
|
||||
var tokenStream = new CommonTokenStream(lexer);
|
||||
var parser = new GroupParser(tokenStream);
|
||||
|
||||
parser.group(this, "/");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorManager.IOError(null, ErrorType.CANT_LOAD_GROUP_FILE, ex, FileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Stream StreamFromResources(string fileName)
|
||||
{
|
||||
var resourceName = $"{ResourceBasePath}.{fileName}";
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
return assembly.GetManifestResourceStream(resourceName);
|
||||
}
|
||||
|
||||
public override string Name => "TemplateGroupResources";
|
||||
|
||||
public override string FileName => Name;
|
||||
}
|
||||
}
|
2
src/ZoneCodeGenerator/Generating/Templates/Common.stg
Normal file
2
src/ZoneCodeGenerator/Generating/Templates/Common.stg
Normal file
@ -0,0 +1,2 @@
|
||||
test() ::= <<
|
||||
>>
|
225
src/ZoneCodeGenerator/Generating/Templates/ZoneLoad.stg
Normal file
225
src/ZoneCodeGenerator/Generating/Templates/ZoneLoad.stg
Normal file
@ -0,0 +1,225 @@
|
||||
delimiters "$", "$"
|
||||
|
||||
import "Common.stg"
|
||||
|
||||
Capital(name) ::= "$name; format=\"cap\"$"
|
||||
|
||||
LoaderClassName(asset) ::= "Loader_$asset.Type.Name$"
|
||||
|
||||
HeaderConstructor(context) ::= "$LoaderClassName(context.Asset)$(IZoneScriptStringProvider* scriptStringProvider, Zone* zone, IZoneInputStream* stream);"
|
||||
|
||||
HeaderPtrLoadMethodDeclaration(structure) ::= "void LoadPtr_$structure.Type.Name$($structure.Type.FullName$** pPtr);"
|
||||
HeaderArrayLoadMethodDeclaration(structure) ::= "void LoadArray_$structure.Type.Name$($structure.Type.FullName$** pArray, size_t count, bool atStreamStart);"
|
||||
HeaderLoadMethodDeclaration(structure) ::= "void Load_$structure.Type.Name$($structure.Type.FullName$** p$structure.Type.Name$, bool atStreamStart);"
|
||||
|
||||
HeaderGetNameMethodDeclaration(asset) ::= "static std::string GetAssetName($asset.Type.FullName$* p$asset.Type.Name$);"
|
||||
HeaderAssetLoadMethodDeclaration(asset) ::= "void LoadAsset_$asset.Type.Name$($asset.Type.FullName$** pPtr);"
|
||||
|
||||
HeaderDeclaration(structure) ::= <%
|
||||
$if(structure.PointerReferenceExists)$
|
||||
$HeaderPtrLoadMethodDeclaration(structure)$
|
||||
$\n$
|
||||
$endif$
|
||||
|
||||
$if(structure.ArrayReferenceExists)$
|
||||
$HeaderArrayLoadMethodDeclaration(structure)$
|
||||
$\n$
|
||||
$endif$
|
||||
|
||||
$if(structure.NonEmbeddedReferenceExists)$
|
||||
$HeaderLoadMethodDeclaration(structure)$
|
||||
$\n$
|
||||
$endif$
|
||||
%>
|
||||
|
||||
// =======================
|
||||
// Header file entry point
|
||||
// =======================
|
||||
header(context) ::= <<
|
||||
// ====================================================================
|
||||
// This file has been generated by ZoneCodeGenerator.
|
||||
// Do not modify.
|
||||
// Any changes will be discarded when regenerating.
|
||||
// ====================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Loading/AssetLoader.h"
|
||||
#include "Game/$context.Game$/$context.Game$.h"
|
||||
#include <string>
|
||||
|
||||
namespace $context.Game$
|
||||
{
|
||||
class $LoaderClassName(context.Asset)$
|
||||
{
|
||||
$context.Structures:{structure | $if(!structure.IsAsset)$$HeaderDeclaration(structure)$$endif$}$
|
||||
$HeaderLoadMethodDeclaration(context.Asset)$
|
||||
$HeaderAssetLoadMethodDeclaration(context.Asset)$
|
||||
|
||||
public:
|
||||
$HeaderConstructor(context)$
|
||||
|
||||
$HeaderPtrLoadMethodDeclaration(context.Asset)$
|
||||
$HeaderGetNameMethodDeclaration(context.Asset)$
|
||||
};
|
||||
}
|
||||
>>
|
||||
|
||||
IncludeHeaderOfOtherAsset(asset) ::= <<
|
||||
#include "../$asset.Type.Name$/$asset.Type.Name; format="lower"$_load_db.h"
|
||||
|
||||
>>
|
||||
|
||||
LoadMethod(structure, context) ::= <<
|
||||
void $LoaderClassName(context.Asset)$::Load_$structure.Type.Name$($structure.Type.FullName$* p$structure.Type.Name$, const bool atStreamStart)
|
||||
{
|
||||
assert(p$structure.Type.Name$ != nullptr);
|
||||
|
||||
if(atStreamStart)
|
||||
m_stream->Load<$structure.Type.FullName$>();
|
||||
$if(structure.Block.IsTemp)$
|
||||
|
||||
m_stream->PushBlock($context.DefaultNormalBlock.Name$);
|
||||
$endif$
|
||||
|
||||
// Load content here
|
||||
$if(structure.Block.IsTemp)$
|
||||
|
||||
m_stream->PopBlock();
|
||||
$endif$
|
||||
}
|
||||
>>
|
||||
|
||||
LoadPtrMethod(structure, context) ::= <<
|
||||
void $LoaderClassName(context.Asset)$::LoadPtr_$structure.Type.Name$($structure.Type.FullName$** pPtr)
|
||||
{
|
||||
assert(pPtr != nullptr);
|
||||
|
||||
m_stream->PushBlock($structure.Block.Name$);
|
||||
|
||||
if(*pPtr != nullptr)
|
||||
{
|
||||
$if(structure.Block.IsTemp)$
|
||||
if(*pPtr == PTR_FOLLOWING || *pPtr == PTR_INSERT)
|
||||
$else$
|
||||
if(*pPtr == PTR_FOLLOWING)
|
||||
$endif$
|
||||
{
|
||||
$if(structure.Block.IsTemp)$
|
||||
$structure.Type.FullName$** toInsert = nullptr;
|
||||
if(*pPtr == PTR_INSERT)
|
||||
toInsert = m_stream->InsertPointer<$structure.Type.FullName$>();
|
||||
|
||||
$endif$
|
||||
$if(structure.HasNonDefaultAlign)$
|
||||
*pPtr = m_stream->Alloc<$structure.Type.FullName$>($structure.FastFileAlign$);
|
||||
$else$
|
||||
*pPtr = m_stream->Alloc<$structure.Type.FullName$>();
|
||||
$endif$
|
||||
Load_$structure.Type.Name$(*pPtr, true);
|
||||
$if(structure.IsAsset)$
|
||||
LoadAsset_$structure.Type.Name$(pPtr);
|
||||
$endif$
|
||||
$if(structure.Block.IsTemp)$
|
||||
|
||||
if(toInsert != nullptr)
|
||||
*toInsert = *pPtr;
|
||||
$endif$
|
||||
}
|
||||
else
|
||||
{
|
||||
$if(structure.Block.IsTemp)$
|
||||
*pPtr = m_stream->ConvertOffsetToAlias(*ptr);
|
||||
$else$
|
||||
*pPtr = m_stream->ConvertOffsetToPointer(*ptr);
|
||||
$endif$
|
||||
}
|
||||
}
|
||||
|
||||
m_stream->PopBlock();
|
||||
}
|
||||
>>
|
||||
|
||||
LoadArrayMethod(structure, context) ::= <<
|
||||
void $LoaderClassName(context.Asset)$::LoadArray_$structure.Type.Name$($structure.Type.FullName$** pArray, const size_t count, const bool atStreamStart)
|
||||
{
|
||||
assert(pArray != nullptr);
|
||||
|
||||
if(atStreamStart)
|
||||
m_stream->Load<$structure.Type.FullName$>(count);
|
||||
|
||||
for(size_t index = 0; index < count; index++)
|
||||
{
|
||||
Load_$structure.Type.Name$(&pArray[index], false);
|
||||
}
|
||||
}
|
||||
>>
|
||||
|
||||
SourceDefinition(structure, context) ::= <<
|
||||
$if(structure.NonEmbeddedReferenceExists)$
|
||||
$LoadMethod(structure, context)$
|
||||
|
||||
$endif$
|
||||
$if(structure.PointerReferenceExists)$
|
||||
$LoadPtrMethod(structure, context)$
|
||||
|
||||
$endif$
|
||||
$if(structure.ArrayReferenceExists)$
|
||||
$LoadArrayMethod(structure, context)$
|
||||
|
||||
$endif$
|
||||
>>
|
||||
|
||||
ConstructorMethod(context) ::= <<
|
||||
$LoaderClassName(context.Asset)$::$LoaderClassName(context.Asset)$(IZoneScriptStringProvider* scriptStringProvider, Zone* zone, IZoneInputStream* stream)
|
||||
: AssetLoader($context.Asset.AssetEnumEntry.Name$, scriptStringProvider, zone, stream){}
|
||||
>>
|
||||
|
||||
LoadAssetMethod(structure, context) ::= <<
|
||||
void $LoaderClassName(context.Asset)$::LoadAsset_$structure.Type.Name$($structure.Type.FullName$** pPtr)
|
||||
{
|
||||
assert(pPtr != nullptr);
|
||||
*pPtr = static_cast<$structure.Type.FullName$*>(LinkAsset(GetAssetName(*pPtr), *pPtr));
|
||||
}
|
||||
>>
|
||||
|
||||
GetNameMethod(context) ::= <<
|
||||
std::string $LoaderClassName(context.Asset)$::GetAssetName($context.Asset.Type.FullName$* p$context.Asset.Type.Name$)
|
||||
{
|
||||
$if(context.Asset.HasNameMember)$
|
||||
return p$context.Asset.Type.Name$->name;
|
||||
$else$
|
||||
return "$context.Asset.Type.Name$";
|
||||
$endif$
|
||||
}
|
||||
>>
|
||||
|
||||
// =======================
|
||||
// Source file entry point
|
||||
// =======================
|
||||
source(context) ::= <<
|
||||
// ====================================================================
|
||||
// This file has been generated by ZoneCodeGenerator.
|
||||
// Do not modify.
|
||||
// Any changes will be discarded when regenerating.
|
||||
// ====================================================================
|
||||
|
||||
#include "$context.Asset.Type.Name; format="lower"$_load_db.h"
|
||||
#include <cassert>
|
||||
|
||||
// Referenced Assets:
|
||||
$context.ReferencedAssets:IncludeHeaderOfOtherAsset()$
|
||||
|
||||
using namespace $context.Game$;
|
||||
|
||||
$ConstructorMethod(context)$
|
||||
|
||||
$context.Structures:{structure | $if(!structure.IsAsset)$$SourceDefinition(structure, context)$$endif$}$
|
||||
$LoadMethod(context.Asset, context)$
|
||||
|
||||
$LoadAssetMethod(context.Asset, context)$
|
||||
|
||||
$LoadPtrMethod(context.Asset, context)$
|
||||
|
||||
$GetNameMethod(context)$
|
||||
>>
|
38
src/ZoneCodeGenerator/Generating/Templates/ZoneWrite.stg
Normal file
38
src/ZoneCodeGenerator/Generating/Templates/ZoneWrite.stg
Normal file
@ -0,0 +1,38 @@
|
||||
delimiters "$", "$"
|
||||
|
||||
import "Common.stg"
|
||||
|
||||
WriterClassName(asset) ::= "$asset.Type.Name; format=\"cap\"$ZoneWriter"
|
||||
|
||||
// =======================
|
||||
// Header file entry point
|
||||
// =======================
|
||||
header(context) ::= <<
|
||||
#pragma once
|
||||
|
||||
namespace ZoneLoader
|
||||
{
|
||||
class $WriterClassName(context.Asset)$
|
||||
{
|
||||
public:
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
>>
|
||||
|
||||
IncludeHeaderOfOtherAsset(asset) ::= <<
|
||||
#include "../$asset.Type.Name$/$asset.Type.Name; format="lower"$_write_db.h"
|
||||
|
||||
>>
|
||||
|
||||
// =======================
|
||||
// Source file entry point
|
||||
// =======================
|
||||
source(context) ::= <<
|
||||
#include "$context.Asset.Type.Name; format="lower"$_write_db.h"
|
||||
|
||||
// Referenced Assets:
|
||||
$context.ReferencedAssets:IncludeHeaderOfOtherAsset()$
|
||||
|
||||
// TODO
|
||||
>>
|
Reference in New Issue
Block a user