Exemple #1
0
        protected void VerifySyncValidForType(System.Type typeToSync, UdonSyncMode syncMode)
        {
            if (syncMode == UdonSyncMode.NotSynced)
            {
                return;
            }

            if (visitorContext.behaviourSyncMode == BehaviourSyncMode.NoVariableSync)
            {
                throw new System.Exception($"Cannot sync variable because behaviour is set to NoVariableSync, change the behaviour sync mode to sync variables");
            }

            if (!VRC.Udon.UdonNetworkTypes.CanSync(typeToSync) &&
                typeToSync != typeof(uint) && typeToSync != typeof(uint[])) // Workaround for the uint types missing from the syncable type list >_>
            {
                throw new System.NotSupportedException($"Udon does not currently support syncing of the type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'");
            }
            else if (syncMode == UdonSyncMode.Linear && !VRC.Udon.UdonNetworkTypes.CanSyncLinear(typeToSync))
            {
                throw new System.NotSupportedException($"Udon does not support linear interpolation of the synced type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'");
            }
            else if (syncMode == UdonSyncMode.Smooth && !VRC.Udon.UdonNetworkTypes.CanSyncSmooth(typeToSync))
            {
                throw new System.NotSupportedException($"Udon does not support smooth interpolation of the synced type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'");
            }

            if (visitorContext.behaviourSyncMode == BehaviourSyncMode.Manual && syncMode != UdonSyncMode.None)
            {
                throw new System.NotSupportedException($"Udon does not support variable tweening when the behaviour is in Manual sync mode");
            }
            else if (visitorContext.behaviourSyncMode == BehaviourSyncMode.Continuous && typeToSync.IsArray)
            {
                throw new System.NotSupportedException($"Syncing of array type {UdonSharpUtils.PrettifyTypeName(typeToSync.GetElementType())}[] is only supported in manual sync mode");
            }
        }
Exemple #2
0
        public override void VisitFieldDeclaration(FieldDeclarationSyntax node)
        {
            UpdateSyntaxNode(node);

            var variables = node.Declaration.Variables;

            for (int i = 0; i < variables.Count; ++i)
            {
                VariableDeclaratorSyntax variable = variables[i];

                if (variable.Initializer != null)
                {
                    fieldsWithInitializers.Add(node);
                }
            }

            if (node.Modifiers.HasModifier("static"))
            {
                throw new System.NotSupportedException("Static fields are not yet supported by UdonSharp");
            }

            UdonSyncMode fieldSyncMode = GetSyncAttributeValue(node);

            List <System.Attribute> fieldAttributes = GetFieldAttributes(node);

            bool isPublic             = (node.Modifiers.Any(SyntaxKind.PublicKeyword) || fieldAttributes.Find(e => e is SerializeField) != null) && fieldAttributes.Find(e => e is System.NonSerializedAttribute) == null;
            bool isConst              = (node.Modifiers.Any(SyntaxKind.ConstKeyword) || node.Modifiers.Any(SyntaxKind.ReadOnlyKeyword));
            SymbolDeclTypeFlags flags = (isPublic ? SymbolDeclTypeFlags.Public : SymbolDeclTypeFlags.Private) |
                                        (isConst ? SymbolDeclTypeFlags.Readonly : 0);

            List <SymbolDefinition> fieldSymbols = HandleVariableDeclaration(node.Declaration, flags, fieldSyncMode);

            foreach (SymbolDefinition fieldSymbol in fieldSymbols)
            {
                FieldDefinition fieldDefinition = new FieldDefinition(fieldSymbol);
                fieldDefinition.fieldAttributes = fieldAttributes;

                if (fieldSymbol.IsUserDefinedType())
                {
                    System.Type fieldType = fieldSymbol.userCsType;
                    while (fieldType.IsArray)
                    {
                        fieldType = fieldType.GetElementType();
                    }

                    foreach (ClassDefinition classDefinition in visitorContext.externClassDefinitions)
                    {
                        if (classDefinition.userClassType == fieldType)
                        {
                            fieldDefinition.userBehaviourSource = classDefinition.classScript;
                            break;
                        }
                    }
                }

                visitorContext.localFieldDefinitions.Add(fieldSymbol.symbolUniqueName, fieldDefinition);
            }
        }
Exemple #3
0
        private UdonSyncMode GetSyncAttributeValue(FieldDeclarationSyntax node)
        {
            UdonSyncMode syncMode = UdonSyncMode.NotSynced;

            if (node.AttributeLists != null)
            {
                foreach (AttributeListSyntax attributeList in node.AttributeLists)
                {
                    foreach (AttributeSyntax attribute in attributeList.Attributes)
                    {
                        using (ExpressionCaptureScope attributeTypeCapture = new ExpressionCaptureScope(visitorContext, null))
                        {
                            attributeTypeCapture.isAttributeCaptureScope = true;
                            Visit(attribute.Name);

                            if (attributeTypeCapture.captureType != typeof(UdonSyncedAttribute))
                            {
                                continue;
                            }

                            if (attribute.ArgumentList == null ||
                                attribute.ArgumentList.Arguments == null ||
                                attribute.ArgumentList.Arguments.Count == 0)
                            {
                                syncMode = UdonSyncMode.None;
                            }
                            else
                            {
                                using (ExpressionCaptureScope attributeCaptureScope = new ExpressionCaptureScope(visitorContext, null))
                                {
                                    Visit(attribute.ArgumentList.Arguments[0].Expression);

                                    if (!attributeCaptureScope.IsEnum())
                                    {
                                        throw new System.Exception("Invalid attribute argument provided for sync");
                                    }

                                    syncMode = (UdonSyncMode)attributeCaptureScope.GetEnumValue();
                                }
                            }

                            break;
                        }
                    }

                    if (syncMode != UdonSyncMode.NotSynced)
                    {
                        break;
                    }
                }
            }

            return(syncMode);
        }
Exemple #4
0
        private void VerifySyncValidForType(System.Type typeToSync, UdonSyncMode syncMode)
        {
            if (syncMode == UdonSyncMode.NotSynced)
            {
                return;
            }

#if UDON_BETA_SDK
            if (!VRC.Udon.UdonNetworkTypes.CanSync(typeToSync))
            {
                throw new System.NotSupportedException($"Udon does not currently support syncing of the type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'");
            }
            else if (syncMode == UdonSyncMode.Linear && !VRC.Udon.UdonNetworkTypes.CanSyncLinear(typeToSync))
            {
                throw new System.NotSupportedException($"Udon does not support linear interpolation of the synced type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'");
            }
            else if (syncMode == UdonSyncMode.Smooth && !VRC.Udon.UdonNetworkTypes.CanSyncSmooth(typeToSync))
            {
                throw new System.NotSupportedException($"Udon does not support smooth interpolation of the synced type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'");
            }

            if (visitorContext.behaviourSyncMode == BehaviourSyncMode.Manual && syncMode != UdonSyncMode.None)
            {
                throw new System.NotSupportedException($"Udon does not support variable tweening when the behaviour is in Manual sync mode");
            }
#else
            if (!UdonSharpUtils.IsUdonSyncedType(typeToSync))
            {
                throw new System.NotSupportedException($"Udon does not currently support syncing of the type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'");
            }

            if (syncMode != UdonSyncMode.None && (typeToSync == typeof(string) || typeToSync == typeof(char)))
            {
                throw new System.NotSupportedException($"Udon does not support tweening the synced type '{UdonSharpUtils.PrettifyTypeName(typeToSync)}'");
            }
#endif
        }
Exemple #5
0
 public UdonSyncedAttribute(UdonSyncMode networkSyncTypeIn = UdonSyncMode.None)
 {
     NetworkSyncType = networkSyncTypeIn;
 }
Exemple #6
0
        protected List <SymbolDefinition> HandleVariableDeclaration(VariableDeclarationSyntax node, SymbolDeclTypeFlags symbolType, UdonSyncMode syncMode)
        {
            UpdateSyntaxNode(node);

            bool isVar = node.Type.IsVar;

            System.Type variableType = null;

            if (!isVar)
            {
                using (ExpressionCaptureScope typeCapture = new ExpressionCaptureScope(visitorContext, null))
                {
                    Visit(node.Type);

                    if (!typeCapture.IsType())
                    {
                        throw new System.Exception($"The type or namespace name '{typeCapture.unresolvedAccessChain}' could not be found (are you missing a using directive?)");
                    }

                    variableType = typeCapture.captureType;
                }
            }

            List <SymbolDefinition> newSymbols = new List <SymbolDefinition>();

            foreach (VariableDeclaratorSyntax variableDeclarator in node.Variables)
            {
                SymbolDefinition newSymbol = null;

                string variableName = variableDeclarator.Identifier.ValueText;

                using (ExpressionCaptureScope symbolCreationScope = new ExpressionCaptureScope(visitorContext, null))
                {
                    if (!isVar)
                    {
                        newSymbol = visitorContext.topTable.CreateNamedSymbol(variableDeclarator.Identifier.ValueText, variableType, symbolType);
                    }

                    // Run the initializer if it exists
                    // Todo: Run the set on the new symbol scope from within the initializer scope for direct setting
                    if (variableDeclarator.Initializer != null && symbolType.HasFlag(SymbolDeclTypeFlags.Local))
                    {
                        using (ExpressionCaptureScope initializerCapture = new ExpressionCaptureScope(visitorContext, null, newSymbol))
                        {
                            Visit(variableDeclarator.Initializer);

                            if (newSymbol == null)
                            {
                                // TODO: Find a way to determine the return type before generating initializer code, to avoid a copy on 'var' local initializers
                                variableType = initializerCapture.GetReturnType(true);
                                newSymbol    = visitorContext.topTable.CreateNamedSymbol(variableDeclarator.Identifier.ValueText, variableType, symbolType);
                            }

                            symbolCreationScope.SetToLocalSymbol(newSymbol);
                            symbolCreationScope.ExecuteSet(initializerCapture.ExecuteGet());
                        }
                    }

                    newSymbol.syncMode = syncMode;
                }

                VerifySyncValidForType(newSymbol.symbolCsType, syncMode);
                newSymbols.Add(newSymbol);
            }

            if (!visitorContext.resolverContext.IsValidUdonType(variableType))
            {
                throw new System.NotSupportedException($"Udon does not support variables of type '{variableType.Name}' yet");
            }

            return(newSymbols);
        }
Exemple #7
0
        private List <System.Attribute> GetFieldAttributes(FieldDeclarationSyntax node)
        {
            List <System.Attribute> attributes = new List <System.Attribute>();

            if (node.AttributeLists != null)
            {
                foreach (AttributeListSyntax attributeList in node.AttributeLists)
                {
                    UpdateSyntaxNode(attributeList);

                    foreach (AttributeSyntax attribute in attributeList.Attributes)
                    {
                        using (ExpressionCaptureScope attributeTypeCapture = new ExpressionCaptureScope(visitorContext, null))
                        {
                            attributeTypeCapture.isAttributeCaptureScope = true;
                            Visit(attribute.Name);

                            System.Type captureType = attributeTypeCapture.captureType;

                            if (captureType == typeof(UdonSyncedAttribute))
                            {
                                UdonSyncMode syncMode = UdonSyncMode.NotSynced;

                                if (attribute.ArgumentList == null ||
                                    attribute.ArgumentList.Arguments == null ||
                                    attribute.ArgumentList.Arguments.Count == 0)
                                {
                                    syncMode = UdonSyncMode.None;
                                }
                                else
                                {
                                    using (ExpressionCaptureScope attributeCaptureScope = new ExpressionCaptureScope(visitorContext, null))
                                    {
                                        Visit(attribute.ArgumentList.Arguments[0].Expression);

                                        if (!attributeCaptureScope.IsEnum())
                                        {
                                            throw new System.Exception("Invalid attribute argument provided for sync");
                                        }

                                        syncMode = (UdonSyncMode)attributeCaptureScope.GetEnumValue();
                                    }
                                }
                                attributes.Add(new UdonSyncedAttribute(syncMode));
                            }
                            else if (captureType != null)
                            {
                                try
                                {
                                    object attributeObject = null;

                                    if (attribute.ArgumentList == null ||
                                        attribute.ArgumentList.Arguments == null ||
                                        attribute.ArgumentList.Arguments.Count == 0)
                                    {
                                        attributeObject = System.Activator.CreateInstance(captureType);
                                    }
                                    else
                                    {
                                        // todo: requires constant folding to support decently
                                        object[] attributeArgs = new object[attribute.ArgumentList.Arguments.Count];

                                        for (int i = 0; i < attributeArgs.Length; ++i)
                                        {
                                            AttributeArgumentSyntax attributeArg = attribute.ArgumentList.Arguments[i];

                                            using (ExpressionCaptureScope attributeCapture = new ExpressionCaptureScope(visitorContext, null))
                                            {
                                                Visit(attributeArg);

                                                SymbolDefinition attrSymbol = attributeCapture.ExecuteGet();

                                                if (!attrSymbol.declarationType.HasFlag(SymbolDeclTypeFlags.Constant))
                                                {
                                                    throw new System.ArgumentException("Attributes do not support non-constant expressions");
                                                }

                                                attributeArgs[i] = attrSymbol.symbolDefaultValue;
                                            }
                                        }

                                        attributeObject = System.Activator.CreateInstance(captureType, attributeArgs);
                                    }

                                    if (attributeObject != null)
                                    {
                                        attributes.Add((System.Attribute)attributeObject);
                                    }
                                }
                                catch (System.Reflection.TargetInvocationException constructionException)
                                {
                                    throw constructionException.InnerException;
                                }
                            }
                        }
                    }
                }
            }

            return(attributes);
        }
Exemple #8
0
 public void AddSyncTag(Value syncValue, UdonSyncMode syncMode)
 {
     AddInstruction(new SyncTag(syncValue, syncMode));
 }
 public SyncTag(Value syncedValue, UdonSyncMode syncMode)
 {
     SyncedValue = syncedValue;
     SyncMode    = syncMode;
 }
        public override void VisitFieldDeclaration(FieldDeclarationSyntax node)
        {
            UpdateSyntaxNode(node);

            var variables = node.Declaration.Variables;

            for (int i = 0; i < variables.Count; ++i)
            {
                VariableDeclaratorSyntax variable = variables[i];

                if (variable.Initializer != null)
                {
                    fieldsWithInitializers.Add(node);
                }
            }

            if (node.Modifiers.HasModifier("static"))
            {
                throw new System.NotSupportedException("Static fields are not yet supported by UdonSharp");
            }

            UdonSyncMode fieldSyncMode = GetSyncAttributeValue(node);

            List <System.Attribute> fieldAttributes = GetFieldAttributes(node);


            bool isPublic             = (node.Modifiers.Any(SyntaxKind.PublicKeyword) || fieldAttributes.Find(e => e is SerializeField) != null) && fieldAttributes.Find(e => e is System.NonSerializedAttribute) == null;
            bool isConst              = (node.Modifiers.Any(SyntaxKind.ConstKeyword) || node.Modifiers.Any(SyntaxKind.ReadOnlyKeyword));
            SymbolDeclTypeFlags flags = (isPublic ? SymbolDeclTypeFlags.Public : SymbolDeclTypeFlags.Private) |
                                        (isConst ? SymbolDeclTypeFlags.Readonly : 0);

            FieldChangeCallbackAttribute varChange = fieldAttributes.OfType <FieldChangeCallbackAttribute>().FirstOrDefault();

            List <SymbolDefinition> fieldSymbols = HandleVariableDeclaration(node.Declaration, flags, fieldSyncMode);

            foreach (SymbolDefinition fieldSymbol in fieldSymbols)
            {
                FieldDefinition fieldDefinition = new FieldDefinition(fieldSymbol);
                fieldDefinition.fieldAttributes = fieldAttributes;

                if (fieldSymbol.IsUserDefinedType())
                {
                    System.Type fieldType = fieldSymbol.userCsType;
                    while (fieldType.IsArray)
                    {
                        fieldType = fieldType.GetElementType();
                    }

                    foreach (ClassDefinition classDefinition in visitorContext.externClassDefinitions)
                    {
                        if (classDefinition.userClassType == fieldType)
                        {
                            fieldDefinition.userBehaviourSource = classDefinition.classScript;
                            break;
                        }
                    }
                }

                visitorContext.localFieldDefinitions.Add(fieldSymbol.symbolUniqueName, fieldDefinition);

                if (varChange != null)
                {
                    string targetProperty = varChange.CallbackPropertyName;

                    if (variables.Count > 1 || visitorContext.onModifyCallbackFields.ContainsKey(targetProperty))
                    {
                        throw new System.Exception($"Only one field may target property '{targetProperty}'");
                    }

                    PropertyDefinition foundProperty = visitorContext.definedProperties.FirstOrDefault(e => e.originalPropertyName == targetProperty);

                    if (foundProperty == null)
                    {
                        throw new System.ArgumentException($"Invalid target property for {nameof(FieldChangeCallbackAttribute)} on {node.Declaration}");
                    }

                    PropertyDefinition property = visitorContext.definedProperties.FirstOrDefault(e => e.originalPropertyName == targetProperty);
                    if (property == null)
                    {
                        throw new System.ArgumentException($"Property not found for '{targetProperty}'");
                    }

                    if (property.type != fieldDefinition.fieldSymbol.userCsType)
                    {
                        throw new System.Exception($"Types must match between property and variable change field");
                    }

                    visitorContext.onModifyCallbackFields.Add(targetProperty, fieldDefinition);
                }
            }
        }