Ejemplo n.º 1
0
        public string GenerateMcFunction(BuildEnvironment env)
        {
            if (_compiled != null)
            {
                return(_compiled);
            }

            // Compile to vanilla mcfunction
            var builder = new StringBuilder();

            // Append header
            string header = env.Constants["compiled_header"];

            header = header.Replace("{date}", DateTime.Now.ToString("yyyy-MM-dd HH:mm"));
            header = header.Replace("{file}", Id);
            builder.Append("# " + header + "\n");

            // Compile commands
            foreach (Command.Command command in Commands)
            {
                string compiled = command.Compile(env);

                if (compiled != null)
                {
                    builder.Append(compiled + "\n");
                }
            }

            _compiled = builder.ToString();

            return(_compiled);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Compile MCFunction.
        /// </summary>
        /// <param name="env">Build environment</param>
        /// <param name="generateOutput">Should a text output be generated?</param>
        public void Compile(BuildEnvironment env, bool generateOutput = true)
        {
            // Apply custom commands
            var toRemove = new List <Command.Command>();

            int i = 0;

            while (i < Commands.Count)
            {
                Command.Command command = Commands[i];

                foreach (ICustomCommand customCommand in CustomCommands)
                {
                    if (customCommand.DoesApply(env, command))
                    {
                        ApplyResult result = customCommand.Apply(env, command);

                        // Strip command from output if requested
                        if (result.StripFromOutput)
                        {
                            toRemove.Add(command);
                        }

                        // Add replacement commands
                        Commands.InsertRange(i + 1, result.AddCommands);
                    }
                }

                i++;
            }

            // Remove compiler commands (they are not meant for the output)
            foreach (Command.Command command in toRemove)
            {
                Commands.Remove(command);
            }
            toRemove.Clear();

            // Split function blocks into seperate McFunctions
            SplitFunctionBlocks(env);

            if (generateOutput)
            {
                // Compile to vanilla MCFunction file
                GenerateMcFunction(env);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Save this MCFunction and optionally it's children.
        /// </summary>
        /// <param name="env"></param>
        /// <param name="saveChildren"></param>
        public void Save(BuildEnvironment env, bool saveChildren = true)
        {
            string output = env.GetPath(Id, "mcfunction", env.OutputPath);

            Directory.GetParent(output).Create();
            File.WriteAllText(output, GenerateMcFunction(env));

            Logger.Info("Saved to: " + output);

            if (saveChildren)
            {
                foreach (McFunction function in ChildFunctions)
                {
                    function.Save(env);
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Get a list of files that need to be compiled.
        /// </summary>
        private static List <string> GetFiles(BuildEnvironment env)
        {
            var paths = Directory.GetFiles(env.Path, "*.mcfunction", SearchOption.AllDirectories);

            var list = new List <string>();

            foreach (string path in paths)
            {
                string localPath = path.Substring(env.Path.Length).Replace('\\', '/');

                Match match = Regex.Match(localPath, @"^\/data\/([^\/?<>\\:*|""]+)\/functions\/([^?<>\\:*|""]+)\.mcfunction$");
                if (!match.Success)
                {
                    continue;
                }

                list.Add(match.Groups[1].Value + ":" + match.Groups[2].Value);
            }

            return(list);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Search for function blocks and split them out into their own McFunctions.
        /// </summary>
        public void SplitFunctionBlocks(BuildEnvironment env)
        {
            // Iterate over commands, finding function blocks in the *root level*
            // We then make take those commands into their own McFunction and run this function again on the sub McFunction.
            var functionBlocks = new Dictionary <Argument, Range>();
            int nesting        = 0;
            int i = 0;

            foreach (Command.Command command in Commands)
            {
                Argument arg = command.Arguments.LastOrDefault();
                if (arg == null)
                {
                    continue;
                }

                if (arg.Tokens.FirstOrDefault() is OpenFunctionBlockToken)
                {
                    nesting++;

                    if (nesting > FunctionBlockNestingLimit)
                    {
                        throw new Exception($"Exceeded function block nesting limit of {FunctionBlockNestingLimit}!");
                    }

                    if (nesting == 1)
                    {
                        // Root level function block.
                        functionBlocks.Add(arg, new Range(i, -1));
                    }
                }

                if (arg.Tokens.FirstOrDefault() is CloseFunctionBlockToken)
                {
                    nesting--;

                    if (nesting < 0)
                    {
                        throw new Exception("Unexpected additional function block bracket!");
                    }

                    if (nesting == 0)
                    {
                        // Back to root nesting, close this function block
                        functionBlocks.Last().Value.Maximum = i;
                    }
                }

                i++;
            }

            if (nesting > 0)
            {
                throw new Exception("Unclosed function block!");
            }

            // Move commands into child McFunctions
            int functionId = 0;

            foreach (KeyValuePair <Argument, Range> range in functionBlocks)
            {
                string parent = Id.Substring(0, Math.Max(Id.LastIndexOf("/"), Id.LastIndexOf(":")) + 1);
                string name   = Id.Substring(Math.Max(Id.LastIndexOf("/"), Id.LastIndexOf(":")) + 1);

                if (!parent.EndsWith("_subs/"))
                {
                    parent += "_subs/";
                }

                var mcFunction = new McFunction(parent + name + "_" + functionId++);
                ChildFunctions.Add(mcFunction);

                // Move commands
                mcFunction.Commands.AddRange(Commands.GetRange(range.Value.Minimum + 1, range.Value.Length - 1));
                Commands.RemoveRange(range.Value.Minimum + 1, range.Value.Length);

                // Replace argument with function call
                range.Key.Tokens.Clear();
                range.Key.Tokens.Add(new TextToken("function " + mcFunction.Id));

                Logger.Debug($"Function block \"{mcFunction.Id}\" created from commands {functionBlocks.Last().Value} in {Id}!");

                // Run split function blocks on child so they can do their own function blocks.
                mcFunction.SplitFunctionBlocks(env);
            }
        }
Ejemplo n.º 6
0
        public static void Compile(Options.CompileDatapack options)
        {
            Logger.Info($"Compile datapack\n\t{options.SourceDirectory} -> {options.OutputDirectory}");

            var env = new BuildEnvironment(options.SourceDirectory);

            env.OutputPath = options.OutputDirectory;

            // Try to add custom constants into build environment
            var constants = options.ToConstantsDictonary();

            if (constants != null)
            {
                foreach (var constant in constants)
                {
                    env.Constants.Add(constant.Key, constant.Value);
                }
                Logger.Info($"{constants.Count} command line constant{(constants.Count == 1 ? "" : "s")} provided.");
            }

            // Get file list
            List <string> files = GetFiles(env);

            Logger.Info($"{files.Count} files found to be compiled.");

            // Start parse & compile
            Logger.Info("Starting parse & compile...");
            var parser = new Parser.Parser(env);

            Timer.Start("parse_and_compile");

            var totalParseTime   = new TimeSpan();
            var totalCompileTime = new TimeSpan();

            foreach (string file in files)
            {
                // Parse
                Logger.Info($"Parsing {file}...");
                Timer.Start("parse");
                McFunction mcFunction = parser.Parse(file);
                totalParseTime = totalParseTime.Add(Timer.End("parse"));

                Logger.Debug($"Parsed {file}. {mcFunction.Commands.Count} commands found.");

                // Compile
                Logger.Info($"Compiling {file}...");
                Timer.Start("compile");
                mcFunction.Compile(env);
                totalCompileTime = totalCompileTime.Add(Timer.End("compile"));
                Logger.Debug($"Compiled {file}.");

                // Save
                mcFunction.Save(env);
            }

            TimeSpan parseAndCompileTime = Timer.End("parse_and_compile");

            Logger.Info($"Datapack compile finished. Took {Math.Round(parseAndCompileTime.TotalSeconds, 3)}s");
            Logger.Debug($"Total parse time: {Math.Round(totalParseTime.TotalSeconds, 3)}s");
            Logger.Debug($"Total compile time: {Math.Round(totalCompileTime.TotalSeconds, 3)}s");
        }