public void AddMethod(int i, ScenarioTag.ScriptMethodDefinition scriptMethod) { var modifiers = SyntaxTokenList.Create(Token(SyntaxKind.PublicKeyword)) .Add(Token(SyntaxKind.AsyncKeyword)); TypeSyntax returnType = ParseTypeName("Task"); if (scriptMethod.ReturnType != ScriptDataType.Void) { returnType = GenericName("Task").AddTypeArgumentListArguments(SyntaxUtil.ScriptTypeSyntax(scriptMethod.ReturnType)); } var method = MethodDeclaration( returnType, SyntaxUtil.SanitizeIdentifier(scriptMethod.Description)) .WithModifiers(modifiers); // Push root method body as first scope var block = new StatementBlockContext(); var rootScope = new Scope(scriptMethod.ReturnType, block, block); var retScope = EvaluateNodes(scriptMethod.SyntaxNodeIndex, rootScope); Debug.Assert(rootScope == retScope, "Last scope wasn't the provided root"); methods.Add(method.WithBody(Block(block.GetInnerStatements())) .AddAttributeLists(AttributeList(SeparatedList(new[] { Attribute(IdentifierName(nameof(ScriptMethodAttribute).Replace("Attribute", ""))) .AddArgumentListArguments( AttributeArgument(SyntaxUtil.LiteralExpression(i)), AttributeArgument(MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nameof(Lifecycle)), IdentifierName(scriptMethod.Lifecycle.ToString())))) })))); }
public StatementSyntax CreateWellKnownAssignment(TypeSyntax type, string desiredName, int itemIndex) { if (nameRepo.TryGetName(desiredName, nameof(ScenarioTag.EntityReference), itemIndex, out var name) == false) { throw new Exception("Unable to find property name"); } ExpressionSyntax access = ElementAccessExpression(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName("scenarioTag"), IdentifierName(nameof(ScenarioTag.WellKnownItems)))) .AddArgumentListArguments(Argument(SyntaxUtil.LiteralExpression(itemIndex))); access = ObjectCreationExpression( GenericName(nameof(ScenarioEntity <object>)) .AddTypeArgumentListArguments(type)) .AddArgumentListArguments( Argument(SyntaxUtil.LiteralExpression(itemIndex)), Argument(access)); var exp = AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, IdentifierName(name), access); return(ExpressionStatement(exp)); }
public void AddGlobalVariable(ScenarioTag.ScriptVariableDefinition variable) { Debug.Assert(variable.Value_H16 < scenario.ScriptSyntaxNodes.Length, "Variable expression is not valid"); var node = scenario.ScriptSyntaxNodes[variable.Value_H16]; Debug.Assert(node.Checkval == variable.Value_L16, "Variable expression checkval did not match"); var expressionContext = new SingleExpressionStatementContext(null, variable.DataType); var defScope = new Scope(variable.DataType, expressionContext, expressionContext); var retScope = EvaluateNodes(variable.Value_H16, defScope); Debug.Assert(retScope == defScope, "Returned scope was not the provided root"); var field = SyntaxUtil.CreateField(variable); fields.Add(field); var assignment = AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName(field.Declaration.Variables.First().Identifier.ToString())), expressionContext.GetInnerExpression()); constructorStatements.Add(ExpressionStatement(assignment)); }
public void CreateDataInitializer(ScenarioTag scnr) { var scenarioParam = Identifier("scenarioTag"); var sceneParam = Identifier("scene"); var statements = new List <StatementSyntax>(); statements.Add(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName(nameof(ScenarioScriptBase.Scenario))), IdentifierName(scenarioParam)))); for (int i = 0; i < scnr.WellKnownItems.Length; i++) { var externalRef = scnr.WellKnownItems[i]; if (externalRef.ItemType != ScenarioTag.WellKnownVarType.Undef && externalRef.Index != ushort.MaxValue) { var varType = SyntaxUtil.WellKnownTypeSyntax(externalRef.ItemType); statements.Add(CreateWellKnownAssignment(varType, externalRef.Identifier, i)); } } AddSquadInitialization(statements, scnr); this.methods.Add( MethodDeclaration( PredefinedType(Token(SyntaxKind.VoidKeyword)), nameof(ScenarioScriptBase.InitializeData)) .AddParameterListParameters( Parameter(scenarioParam).WithType(ParseTypeName(nameof(ScenarioTag))), Parameter(sceneParam).WithType(ParseTypeName(nameof(Scene)))) .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)) .WithBody(Block(statements))); }
public ScriptLoader(string generatedScriptOutput = null) { var suppressions = new Dictionary <string, ReportDiagnostic> { { "CS1998", ReportDiagnostic.Suppress } }; var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, specificDiagnosticOptions: suppressions, optimizationLevel: OptimizationLevel.Debug, platform: Platform.AnyCpu); var baseLibPath = Path.GetDirectoryName(typeof(object).Assembly.Location); var tpa = (string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES"); this.generatedScriptOutput = generatedScriptOutput; this.compilation = CSharpCompilation.Create(AssemblyName, options: compilationOptions) .AddReferences(MetadataReference.CreateFromFile(typeof(ScriptLoader).Assembly.Location)) .AddReferences(MetadataReference.CreateFromFile(Path.Combine(baseLibPath, "mscorlib.dll"))) .AddReferences(MetadataReference.CreateFromFile(Path.Combine(baseLibPath, "System.dll"))) .AddReferences(MetadataReference.CreateFromFile(Path.Combine(baseLibPath, "System.Core.dll"))); foreach (var asmPath in tpa.Split(';')) { this.compilation = this.compilation.AddReferences( MetadataReference.CreateFromFile(asmPath)); } foreach (var reference in typeof(ScriptLoader).Assembly.GetReferencedAssemblies()) { if (reference.CodeBase != null) { compilation = compilation.AddReferences(MetadataReference.CreateFromFile(reference.CodeBase)); } } var targetFrameworkUnit = SyntaxFactory.CompilationUnit() .AddAttributeLists( SyntaxFactory.AttributeList( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Attribute(SyntaxFactory.QualifiedName( SyntaxFactory.QualifiedName( SyntaxFactory.QualifiedName( SyntaxFactory.IdentifierName("System"), SyntaxFactory.IdentifierName("Runtime")), SyntaxFactory.IdentifierName("Versioning")), SyntaxFactory.IdentifierName("TargetFrameworkAttribute"))) .AddArgumentListArguments( SyntaxFactory.AttributeArgument(SyntaxUtil.LiteralExpression(".NETStandard,Version=v2.1")), SyntaxFactory.AttributeArgument(SyntaxUtil.LiteralExpression("")) .WithNameEquals(SyntaxFactory.NameEquals(SyntaxFactory.IdentifierName("FrameworkDisplayName")))))) .WithTarget(SyntaxFactory.AttributeTargetSpecifier(SyntaxFactory.Token(SyntaxKind.AssemblyKeyword)))); this.compilation = this.compilation.AddSyntaxTrees(targetFrameworkUnit.SyntaxTree); }
private void AddWellKnownPublicProperty(TypeSyntax type, string name, int itemIndex) { var propName = nameRepo.RegisterName(name, nameof(ScenarioTag.EntityReference), itemIndex); var propType = GenericName(nameof(ScenarioEntity <object>)) .AddTypeArgumentListArguments(type); var prop = PropertyDeclaration(propType, propName) .WithAccessorList(SyntaxUtil.AutoPropertyAccessorList()); properties.Add(prop.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword)))); }
public string RegisterName(string desiredName, string dataType, int?index = null) { if (string.IsNullOrWhiteSpace(desiredName)) { desiredName = "Unnamed"; } var sanitized = SyntaxUtil.SanitizeMemberAccess(desiredName); var name = new RegisteredName() { OriginalName = desiredName, TypeInfo = dataType, Index = index, }; var attempt = 0; var attemptName = sanitized; var key = SimplifiedKey(desiredName, dataType, index); if (originalNameLookup.TryGetValue(key, out var nameSlot)) { while (nameSlot.Any(n => n.UniqueName == attemptName) || finalNames.Contains(attemptName)) { attempt++; attemptName = sanitized + attempt; } name.UniqueName = attemptName; nameSlot.Add(name); } else { while (finalNames.Contains(attemptName)) { attempt++; attemptName = sanitized + attempt; } name.UniqueName = attemptName; originalNameLookup.Add(key, new List <RegisteredName>() { name }); } finalNames.Add(name.UniqueName); return(name.UniqueName); }
private void AddPublicProperty(ScriptDataType type, string name, int itemIndex) { var propName = nameRepo.RegisterName(name, type.ToString(), itemIndex); var scnrPropName = type switch { ScriptDataType.CameraPathTarget => nameof(ScenarioTag.CameraPathTargets), ScriptDataType.LocationFlag => nameof(ScenarioTag.LocationFlagDefinitions), ScriptDataType.CinematicTitle => nameof(ScenarioTag.CinematicTitleDefinitions), ScriptDataType.Trigger => nameof(ScenarioTag.TriggerVolumes), ScriptDataType.StartingProfile => nameof(ScenarioTag.StartingProfileDefinitions), ScriptDataType.DeviceGroup => nameof(ScenarioTag.DeviceGroupDefinitions), ScriptDataType.AI => nameof(ScenarioTag.AiSquadGroupDefinitions), ScriptDataType.AIOrders => nameof(ScenarioTag.AiOrderDefinitions), _ => throw new Exception("Not support!") }; ExpressionSyntax access = ElementAccessExpression(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nameof(ScenarioScriptBase.Scenario)), IdentifierName(scnrPropName))) .AddArgumentListArguments(Argument(SyntaxUtil.LiteralExpression(itemIndex))); var scnrProp = ScenarioTagProperties[scnrPropName]; if (scnrProp.PropertyType.HasElementType && scnrProp.PropertyType.GetElementType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IGameObjectDefinition <>))) { access = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, access, IdentifierName(nameof(IGameObjectDefinition <object> .GameObject))); } var prop = PropertyDeclaration(SyntaxUtil.ScriptTypeSyntax(type), propName) .WithExpressionBody(ArrowExpressionClause(access)) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)); properties.Add(prop.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword)))); }
public void Load(ScenarioTag scnr) { var scenarioParts = scnr.Name.Split('\\', StringSplitOptions.RemoveEmptyEntries) .Select(p => p.Trim()) .ToArray(); var repo = new MemberNameRepository(); // Reserve class field and method names for (var i = 0; i < scnr.ScriptVariables.Length; i++) { var variable = scnr.ScriptVariables[i]; var returnedName = repo.RegisterName(variable.Description, variable.DataType.ToString(), i); } for (var i = 0; i < scnr.ScriptMethods.Length; i++) { var method = scnr.ScriptMethods[i]; var returnedName = repo.RegisterName(method.Description, ScriptDataType.ScriptReference.ToString(), i); } var baseFields = typeof(ScenarioScriptBase).GetFields(); foreach (var field in baseFields) { var found = SyntaxUtil.TryGetScriptTypeFromType(field.FieldType, out var t); Debug.Assert(found); repo.RegisterName(field.Name, t.ToString()); } // Generate data properties var dataGen = new ScriptCSharpGenerator(scnr, repo); dataGen.AddProperties(scnr); dataGen.CreateDataInitializer(scnr); var originAttr = SyntaxFactory.Attribute( SyntaxFactory.ParseName("OriginScenario"), SyntaxFactory.AttributeArgumentList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.AttributeArgument( SyntaxFactory.LiteralExpression( SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(scnr.Name))) }))); var classGen = new ScriptCSharpGenerator(scnr, repo, classAttributes: new[] { originAttr }); foreach (var variable in scnr.ScriptVariables) { classGen.AddGlobalVariable(variable); } for (int i = 0; i < scnr.ScriptMethods.Length; i++) { classGen.AddMethod(i, scnr.ScriptMethods[i]); } this.AddCode($"{scenarioParts.Last()}.cs", classGen.Generate()); this.AddCode($"{scenarioParts.Last()}.Data.cs", dataGen.Generate()); }
public void AddProperties(ScenarioTag scnr) { for (int i = 0; i < scnr.WellKnownItems.Length; i++) { var externalRef = scnr.WellKnownItems[i]; if (externalRef.ItemType == ScenarioTag.WellKnownVarType.Undef) { continue; } var varType = SyntaxUtil.WellKnownTypeSyntax(externalRef.ItemType); AddWellKnownPublicProperty(varType, externalRef.Identifier, i); } for (int i = 0; i < scnr.CameraPathTargets.Length; i++) { var cam = scnr.CameraPathTargets[i]; AddPublicProperty(ScriptDataType.CameraPathTarget, cam.Description, i); } CreateNestedSquadClasses(scnr); for (int i = 0; i < scnr.AiSquadGroupDefinitions.Length; i++) { var ai = scnr.AiSquadGroupDefinitions[i]; AddPublicProperty(ScriptDataType.AI, ai.Description, i); } for (int i = 0; i < scnr.AiOrderDefinitions.Length; i++) { var order = scnr.AiOrderDefinitions[i]; AddPublicProperty(ScriptDataType.AIOrders, order.Description, i); } for (int i = 0; i < scnr.LocationFlagDefinitions.Length; i++) { var flag = scnr.LocationFlagDefinitions[i]; AddPublicProperty(ScriptDataType.LocationFlag, flag.Description, i); } for (int i = 0; i < scnr.CinematicTitleDefinitions.Length; i++) { var title = scnr.CinematicTitleDefinitions[i]; AddPublicProperty(ScriptDataType.CinematicTitle, title.Title, i); } for (int i = 0; i < scnr.TriggerVolumes.Length; i++) { var tv = scnr.TriggerVolumes[i]; AddPublicProperty(ScriptDataType.Trigger, tv.Description, i); } for (int i = 0; i < scnr.StartingProfileDefinitions.Length; i++) { var profile = scnr.StartingProfileDefinitions[i]; AddPublicProperty(ScriptDataType.StartingProfile, profile.Description, i); } for (int i = 0; i < scnr.DeviceGroupDefinitions.Length; i++) { var group = scnr.DeviceGroupDefinitions[i]; AddPublicProperty(ScriptDataType.DeviceGroup, group.Description, i); } }
// Make squads into nested classes public void CreateNestedSquadClasses(ScenarioTag tag) { for (var i = 0; i < tag.AiSquadDefinitions.Length; i++) { var squad = tag.AiSquadDefinitions[i]; var squadPropName = nameRepo.RegisterName(squad.Description, ScriptDataType.AI.ToString(), i); var dataClassProps = new List <PropertyDeclarationSyntax>(); dataClassProps.Add(SyntaxUtil.CreateProperty(ParseTypeName(nameof(ScenarioTag)), nameof(ScenarioTag))); var nestedRepo = new MemberNameRepository(); var m = 0; foreach (var ai in squad.StartingLocations) { var propName = nestedRepo.RegisterName(ai.Description, ScriptDataType.AI.ToString(), m); ExpressionSyntax startingLocationAccess = ElementAccessExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ElementAccessExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nameof(ScenarioTag)), IdentifierName(nameof(tag.AiSquadDefinitions)))) .AddArgumentListArguments(Argument(SyntaxUtil.LiteralExpression(i))), IdentifierName(nameof(squad.StartingLocations)))) .AddArgumentListArguments(Argument(SyntaxUtil.LiteralExpression(m))); dataClassProps.Add(PropertyDeclaration(SyntaxUtil.ScriptTypeSyntax(ScriptDataType.AI), propName) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) .WithExpressionBody(ArrowExpressionClause(startingLocationAccess)) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))); m++; } ExpressionSyntax squadAccess = ElementAccessExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nameof(ScenarioTag)), IdentifierName(nameof(tag.AiSquadDefinitions)))) .AddArgumentListArguments(Argument(SyntaxUtil.LiteralExpression(i))); // This is so the script can reference the squad itself, need special init handling dataClassProps.Add(PropertyDeclaration(SyntaxUtil.ScriptTypeSyntax(ScriptDataType.AI), "Squad") .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) .WithExpressionBody(ArrowExpressionClause(squadAccess)) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))); var squadTypeName = "Squad_" + squadPropName; var cls = ClassDeclaration(squadTypeName) .AddModifiers(Token(SyntaxKind.PublicKeyword)) .WithMembers(new SyntaxList <MemberDeclarationSyntax>(dataClassProps)) .AddMembers(ConstructorDeclaration(squadTypeName) .AddModifiers(Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters( Parameter(Identifier(nameof(ScenarioTag))) .WithType(ParseTypeName(nameof(ScenarioTag)))) .WithBody(Block(new List <StatementSyntax>() { ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName(nameof(ScenarioTag))), IdentifierName(nameof(ScenarioTag)))) }))); nestedDataClasses.Add(cls); nameRepo.NestedRepos.Add(squadPropName, nestedRepo); properties.Add(PropertyDeclaration(ParseTypeName(squadTypeName), squadPropName) .AddModifiers(Token(SyntaxKind.PublicKeyword)) .WithAccessorList(SyntaxUtil.AutoPropertyAccessorList())); } }