public static MapBackground Parse(WZProperty data)
        {
            MapBackground result = new MapBackground();

            result.BackgroundSet = data.ResolveForOrNull <string>("bS");
            result.pathToImage   = string.Join("/", new [] {
                result.BackgroundSet, // backgroundSet,
                "back",
                data.ResolveForOrNull <string>("no")
            });
            result.Index = int.Parse(data.Name);
            result.Front = data.ResolveFor <bool>("front") ?? false;
            result.Alpha = (data.ResolveFor <int>("a") ?? 255) / 255;
            result.Flip  = data.ResolveFor <bool>("f") ?? false;
            WZProperty tileCanvas = data.ResolveOutlink($"Map/Back/{result.pathToImage}") ?? data.ResolveOutlink($"Map2/Back/{result.pathToImage}") ?? data.ResolveOutlink($"Map001/Back/{result.pathToImage}");

            if (tileCanvas != null) // Could be null as we're not supporting ani backgrounds
            {
                result.Canvas = Frame.Parse(tileCanvas?.Children.FirstOrDefault(c => c.Type == PropertyType.Canvas) ?? tileCanvas);
            }
            else
            {
                return(null);
            }
            if (result.Canvas.Image == null)
            {
                return(null);
            }
            if (result.Flip && result.Canvas != null && result.Canvas.Image != null)
            {
                result.Canvas.Image = result.Canvas.Image.Clone(c => c.Flip(FlipMode.Horizontal));
            }
            result.Type     = (BackgroundType)(data.ResolveFor <int>("type") ?? 0);
            result.Position = new Vector3(
                data.ResolveFor <int>("x") ?? 0,
                data.ResolveFor <int>("y") ?? 0,
                result.Front ? 100000000 : int.Parse(data.NameWithoutExtension)
                );
            result.rx = data.ResolveFor <int>("rx") ?? 0;
            result.ry = data.ResolveFor <int>("ry") ?? 0;
            result.cx = data.ResolveFor <int>("cx") ?? 0;
            result.cy = data.ResolveFor <int>("cy") ?? 0;
            return(result);
        }
        public MapRenderPlan(Map info, WZProperty mapNode)
        {
            map          = info;
            this.mapNode = mapNode;

            IEnumerable <WZProperty>            layerNodes          = mapNode.Children.Where(c => int.TryParse(c.Name, out int blah)).ToArray();
            Dictionary <WZProperty, WZProperty> tileSets            = layerNodes.ToDictionary(c => c.Resolve("tile"), c => c.ResolveOutlink("Map/Tile/" + c.ResolveForOrNull <string>("info/tS")));
            IEnumerable <WZProperty>            allLayerNodeFolders = layerNodes.SelectMany(c => c.Children).Where(c => c.Name == "obj" || c.Name == "tile").ToArray();
            Dictionary <WZProperty, Tuple <WZProperty, WZProperty> > layersToFolders = allLayerNodeFolders.GroupBy(c => c.Parent).ToDictionary(c => c.Key, c => new Tuple <WZProperty, WZProperty>(c.First(), c.Last()));
            IEnumerable <WZProperty> allGraphics = allLayerNodeFolders.SelectMany(c => c.Children).ToArray();

            allGraphicsParsed = allLayerNodeFolders.ToDictionary(c => c.Path, c => new ConcurrentBag <IPositionedFrameContainer>());
            ConcurrentDictionary <string, int>            tileZIndexes = new ConcurrentDictionary <string, int>();
            ConcurrentDictionary <string, FrameContainer> parsedFrames = new ConcurrentDictionary <string, FrameContainer>();

            ConcurrentBag <MapBackground> bgs = new ConcurrentBag <MapBackground>();

            Parallel.ForEach(mapNode.Children.FirstOrDefault(c => c.Name == "back")?.Children, backgroundNode => {
                MapBackground bg = MapBackground.Parse(backgroundNode);
                if (bg != null)
                {
                    bgs.Add(bg);
                }
            });
            Backgrounds = new MapBackground[bgs.Count];
            int k = 0;

            while (bgs.TryTake(out MapBackground back))
            {
                Backgrounds[k++] = back;
            }

            ProcessGraphicsNode(tileSets, allGraphics);
            AllGraphicLayers = allGraphicsParsed.ToDictionary(c => c.Key, c =>
            {
                IPositionedFrameContainer[] positionedContainers = new IPositionedFrameContainer[c.Value.Count];
                int i = 0;
                while (c.Value.TryTake(out IPositionedFrameContainer res))
                {
                    positionedContainers[i++] = res;
                }
                return(positionedContainers);
            });