OSDN Git Service

nope this fixed it!
[automap/automap.git] / Automap / Subsystems / Snapshot.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.IO;
5 using System.Linq;
6 using System.Threading;
7 using System.Threading.Tasks;
8
9 using Hjg.Pngcs;
10 using Hjg.Pngcs.Chunks;
11 using Vintagestory.API.Common;
12
13 namespace Automap
14 {
15         public class Snapshotter
16         {
17                 public readonly int chunkSize;
18                 public string fileName;
19                 public string chunkPath;
20                 public ColumnsMetadata cols;
21                 //TODO: Refactor - so Edges are set at construction time, as ColumnsMetadata is async updating in real time!
22                 public int NorthEdge => cols.North_mostChunk;
23                 public int WestEdge => cols.West_mostChunk;
24                 public int Width => (cols.East_mostChunk - WestEdge + 1);
25                 public int Height => (cols.South_mostChunk - NorthEdge + 1);
26
27
28                 public Snapshotter(string path, ColumnsMetadata cols, int chunkSize, int worldSeed)
29                 {
30                         this.fileName = Path.Combine(path, $"snapshot_{worldSeed}.png");
31                         this.chunkPath = Path.Combine(path, AutomapSystem._chunkPath);
32                         this.cols = cols;
33                         this.chunkSize = chunkSize;
34                 }
35
36                 /// <summary>
37                 /// takes a snapshot. this should be called from an extra thread.
38                 /// </summary>
39                 public async void Take()
40                 {
41
42                         ImageInfo info = new ImageInfo(Width * chunkSize, Height * chunkSize, 8, false);
43
44                         PngWriter snapWriter = FileHelper.CreatePngWriter(fileName, info, true);
45
46                         PngMetadata meta = snapWriter.GetMetadata( );
47                         meta.SetTimeNow( );
48                         var transparencyChunk = meta.CreateTRNSChunk( );
49                         transparencyChunk.SetRGB(0, 0, 0);//CHECK: This is pure black.
50                         meta.SetText("Northmost", NorthEdge.ToString("D"));
51                         meta.SetText("Eastmost", WestEdge.ToString("D"));
52                         meta.SetText("Width", Width.ToString("D"));
53                         meta.SetText("Height", Height.ToString("D"));
54
55
56                 
57                         /*
58                         Red:   2 bytes, range 0 .. (2^bitdepth)-1
59                         Green: 2 bytes, range 0 .. (2^bitdepth)-1
60                         Blue:  2 bytes, range 0 .. (2^bitdepth)-1
61                         */
62
63
64                         snapWriter.CompLevel = 5;
65                         snapWriter.CompressionStrategy = Hjg.Pngcs.Zlib.EDeflateCompressStrategy.Filtered;
66
67
68
69                         var orderedList =
70                                 from ch in cols
71                                 group ch by ch.Location.Y into g
72                                 orderby g.Key
73                                 select g;
74                         // that sorts things in ascending order so we can only create (chunkSize) lines at once
75                         int row = 0, lastPosY = 0, posY = 0;
76                         foreach (var chunkGroup in orderedList)
77                         {
78                                 // oh god here we go...
79                                 posY = chunkGroup.Key - NorthEdge;
80                                 var delta = posY - lastPosY;
81                                 lastPosY = posY;
82
83                                 // if there is more than 1 blank step then the gap needs to be filled.
84                                 for (int i = 1; i < delta; i++)
85                                 {
86                                         byte[] blankLine = new byte[info.BytesPerRow];
87                                         for (int j = 0; j < chunkSize; j++)
88                                                 snapWriter.WriteRowByte(blankLine, row++);
89                                 }
90
91                                 var inGroup = (await ReadAllInGroup(chunkGroup)).ToArray();
92                                 
93                                 for (int r = 0; r < chunkSize; r++)
94                                 {
95                                         var line = new byte[info.BytesPerRow];
96                                         for (int chunk = 0; chunk < inGroup.Length; chunk++)
97                                         {
98                                                 var posX = inGroup[chunk].Key * chunkSize * info.BytesPixel;
99                                                 inGroup[chunk].Value?[r].CopyTo(line, posX);
100                                         }
101                                         snapWriter.WriteRowByte(line, row++);
102                                 }
103                         }
104                         snapWriter.ShouldCloseStream = true;
105                         try
106                         {
107                                 snapWriter.End();
108                         }
109                         catch (Exception)
110                         {
111                                 Console.WriteLine("Snapshot exception!");
112                         }
113                 }
114
115                 private async Task<Dictionary<int, byte[][]>> ReadAllInGroup(IGrouping<int, ColumnMeta> group)
116                 {
117                         var taskGroup = new Dictionary<int, byte[][]>(group.Count());
118                         foreach (var shardMeta in group)
119                         {
120                                 var shardPath = Path.Combine(chunkPath, $"{shardMeta.Location.X}_{shardMeta.Location.Y}.png");
121                                 taskGroup.Add(shardMeta.Location.X - WestEdge, await ReadNoThrow(shardPath));
122                         }
123                         return taskGroup;
124                 }
125
126                 private async Task<byte[][]> ReadNoThrow(string readPath)
127                 {
128                         try
129                         {
130                                 return await Task.Run(() => FileHelper.CreatePngReader(readPath).ReadRowsByte().ScanlinesB);
131                         }
132                         catch (Exception e)
133                         {
134                                 Console.WriteLine(e.Message);
135                                 return null;
136                         } // do nothing on error
137                 }
138         }
139 }