source: binary-improvements/7dtd-server-fixes/src/MapRendering/MapRendering.cs @ 135

Last change on this file since 135 was 135, checked in by alloc, 6 years ago

Fixes

File size: 7.8 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Threading;
5using UnityEngine;
6
7namespace AllocsFixes.MapRendering
8{
9        public class MapRendering
10        {
11                private static MapRendering instance;
12
13                public static MapRendering Instance {
14                        get {
15                                if (instance == null) {
16                                        instance = new MapRendering ();
17                                }
18                                return instance;
19                        }
20                }
21
22                private RegionFileManager rfm;
23                private Texture2D fullMapTexture;
24                private MapRenderBlockBuffer[] zoomLevelBuffers = new MapRenderBlockBuffer[Constants.ZOOMLEVELS];
25                private Color[] chunkColors = new Color[Constants.MAP_CHUNK_SIZE * Constants.MAP_CHUNK_SIZE];
26                private System.Timers.Timer chunkSaveTimer = new System.Timers.Timer (500);
27                private bool renderingFullMap = false;
28
29                private MapRendering ()
30                {
31                        Constants.MAP_DIRECTORY = StaticDirectories.GetSaveGameDir () + "/map";
32
33                        for (int i = 0; i < Constants.ZOOMLEVELS; i++) {
34                                zoomLevelBuffers [i] = new MapRenderBlockBuffer (i);
35                        }
36
37                        chunkSaveTimer.AutoReset = false;
38                        chunkSaveTimer.Elapsed += new System.Timers.ElapsedEventHandler (SaveAllBlockMaps);
39                }
40
41                public static void RenderSingleChunk (Chunk chunk)
42                {
43                        ThreadPool.QueueUserWorkItem ((o) =>
44                        {
45                                try {
46                                        if (!Instance.renderingFullMap) {
47                                                Chunk c = (Chunk)o;
48                                                Vector3i cPos = c.GetWorldPos ();
49                                                Vector2i cPos2 = new Vector2i (cPos.x / Constants.MAP_CHUNK_SIZE, cPos.z / Constants.MAP_CHUNK_SIZE);
50                                                Instance.RenderChunk (c, cPos2);
51                                                Instance.chunkSaveTimer.Stop ();
52                                                Instance.chunkSaveTimer.Start ();
53                                        }
54                                } catch (Exception e) {
55                                        Log.Out ("Exception in MapRendering.RenderSingleChunk(): " + e);
56                                }
57                        }, chunk);
58                }
59
60                public void RenderFullMap ()
61                {
62                        MicroStopwatch microStopwatch = new MicroStopwatch ();
63
64                        string regionSaveDir = StaticDirectories.GetSaveGameRegionDir ();
65                        rfm = new RegionFileManager (regionSaveDir, regionSaveDir, 1, false);
66
67                        if (Directory.Exists (Constants.MAP_DIRECTORY))
68                                Directory.Delete (Constants.MAP_DIRECTORY, true);
69
70                        renderingFullMap = true;
71
72                        Vector2i minChunk, maxChunk;
73                        Vector2i minPos, maxPos;
74                        int widthChunks, heightChunks, widthPix, heightPix;
75                        getWorldExtent (out minChunk, out maxChunk, out minPos, out maxPos, out widthChunks, out heightChunks, out widthPix, out heightPix);
76
77                        Log.Out (String.Format ("RenderMap: min: {0}, max: {1}, minPos: {2}, maxPos: {3}, w/h: {4}/{5}, wP/hP: {6}/{7}",
78                                                minChunk.ToString (), maxChunk.ToString (),
79                                                minPos.ToString (), maxPos.ToString (),
80                                                widthChunks, heightChunks,
81                                                widthPix, heightPix));
82
83                        fullMapTexture = new Texture2D (widthPix, heightPix);
84
85                        Vector2i curFullMapPos;
86                        Vector2i curChunkPos;
87                        for (curFullMapPos.x = 0; curFullMapPos.x < widthPix; curFullMapPos.x += Constants.MAP_CHUNK_SIZE) {
88                                for (curFullMapPos.y = 0; curFullMapPos.y < heightPix; curFullMapPos.y += Constants.MAP_CHUNK_SIZE) {
89                                        curChunkPos.x = (curFullMapPos.x / Constants.MAP_CHUNK_SIZE) + minChunk.x;
90                                        curChunkPos.y = (curFullMapPos.y / Constants.MAP_CHUNK_SIZE) + minChunk.y;
91
92                                        RenderChunk (curChunkPos, curFullMapPos);
93                                }
94                                Log.Out (String.Format ("RenderMap: {0}/{1} ({2}%)", curFullMapPos.x, widthPix, (int)((float)curFullMapPos.x / widthPix * 100)));
95                        }
96                        SaveAllBlockMaps (null, null);
97
98                        rfm = null;
99
100                        byte[] array = fullMapTexture.EncodeToPNG ();
101                        File.WriteAllBytes (Constants.MAP_DIRECTORY + "/map.png", array);
102                        Texture2D.Destroy (fullMapTexture);
103
104                        renderingFullMap = false;
105
106                        Log.Out ("Generating map took: " + microStopwatch.ElapsedMilliseconds + " ms");
107                        Log.Out ("World extent: " + minPos + " - " + maxPos);
108                }
109
110                private int saveCount = 0;
111
112                private void SaveAllBlockMaps (object source, System.Timers.ElapsedEventArgs e)
113                {
114                        Monitor.Enter (zoomLevelBuffers);
115                        try {
116                                Log.Out ("------- SaveAllBlockMaps " + ++saveCount);
117                                for (int i = 0; i < Constants.ZOOMLEVELS; i++) {
118                                        zoomLevelBuffers [i].SaveBlock ();
119                                }
120                        } finally {
121                                Monitor.Exit (zoomLevelBuffers);
122                        }
123                }
124
125                private bool RenderChunk (Vector2i chunkPos, Vector2i fullMapPos = default(Vector2i))
126                {
127                        long chunkKey = WorldChunkCache.MakeChunkKey (chunkPos.x, chunkPos.y);
128                        if (rfm.ContainsChunkSync (chunkKey)) {
129                                Chunk chunk = rfm.GetChunkSync (chunkKey);
130                                return RenderChunk (chunk, chunkPos, fullMapPos);
131                        }
132                        return false;
133                }
134
135                private bool RenderChunk (Chunk chunk, Vector2i chunkPos, Vector2i fullMapPos = default(Vector2i))
136                {
137                        Monitor.Enter (zoomLevelBuffers);
138                        try {
139                                ushort[] mapColors = chunk.GetMapColors ();
140                                if (mapColors != null) {
141                                        Vector2i block, blockOffset;
142                                        getBlockNumber (chunkPos, out block, out blockOffset, Constants.MAP_BLOCK_TO_CHUNK_DIV, Constants.MAP_CHUNK_SIZE);
143
144                                        for (int i_colors = 0; i_colors < mapColors.Length; i_colors++) {
145                                                chunkColors [i_colors] = shortColorToColor (mapColors [i_colors]);
146                                        }
147
148                                        zoomLevelBuffers [Constants.ZOOMLEVELS - 1].LoadBlock (block);
149                                        zoomLevelBuffers [Constants.ZOOMLEVELS - 1].SetPart (blockOffset, Constants.MAP_CHUNK_SIZE, chunkColors);
150
151                                        if (renderingFullMap)
152                                                fullMapTexture.SetPixels (fullMapPos.x, fullMapPos.y, Constants.MAP_CHUNK_SIZE, Constants.MAP_CHUNK_SIZE, chunkColors);
153
154                                        RenderZoomLevel (Constants.ZOOMLEVELS - 1, block);
155
156                                        return true;
157                                }
158                                return false;
159                        } finally {
160                                Monitor.Exit (zoomLevelBuffers);
161                        }
162                }
163
164                private void RenderZoomLevel (int level, Vector2i innerBlock)
165                {
166                        if (level > 0) {
167                                Vector2i block, blockOffset;
168                                getBlockNumber (innerBlock, out block, out blockOffset, 2, Constants.MAP_BLOCK_SIZE / 2);
169
170                                zoomLevelBuffers [level - 1].LoadBlock (block);
171                                zoomLevelBuffers [level - 1].SetPart (blockOffset, Constants.MAP_BLOCK_SIZE / 2, zoomLevelBuffers [level].GetHalfScaled ());
172
173                                RenderZoomLevel (level - 1, block);
174                        }
175                }
176
177                private void getBlockNumber (Vector2i innerPos, out Vector2i block, out Vector2i blockOffset, int scaleFactor, int offsetSize)
178                {
179                        block.x = ((innerPos.x + 16777216) / scaleFactor) - (16777216 / scaleFactor);
180                        block.y = ((innerPos.y + 16777216) / scaleFactor) - (16777216 / scaleFactor);
181                        blockOffset.x = ((innerPos.x + 16777216) % scaleFactor) * offsetSize;
182                        blockOffset.y = ((innerPos.y + 16777216) % scaleFactor) * offsetSize;
183                }
184
185                private void getWorldExtent (out Vector2i minChunk, out Vector2i maxChunk,
186                                            out Vector2i minPos, out Vector2i maxPos,
187                                            out int widthChunks, out int heightChunks,
188                                            out int widthPix, out int heightPix)
189                {
190                        long[] keys = rfm.GetAllChunkKeys ();
191                        int minX = Int32.MaxValue;
192                        int minY = Int32.MaxValue;
193                        int maxX = Int32.MinValue;
194                        int maxY = Int32.MinValue;
195                        foreach (long key in keys) {
196                                int x = WorldChunkCache.extractX (key);
197                                int y = WorldChunkCache.extractZ (key);
198
199                                if (x < minX)
200                                        minX = x;
201                                if (x > maxX)
202                                        maxX = x;
203                                if (y < minY)
204                                        minY = y;
205                                if (y > maxY)
206                                        maxY = y;
207                        }
208
209                        minChunk.x = minX;
210                        minChunk.y = minY;
211
212                        maxChunk.x = maxX;
213                        maxChunk.y = maxY;
214
215                        minPos.x = minX * Constants.MAP_CHUNK_SIZE;
216                        minPos.y = minY * Constants.MAP_CHUNK_SIZE;
217
218                        maxPos.x = maxX * Constants.MAP_CHUNK_SIZE;
219                        maxPos.y = maxY * Constants.MAP_CHUNK_SIZE;
220
221                        widthChunks = maxX - minX + 1;
222                        heightChunks = maxY - minY + 1;
223
224                        widthPix = widthChunks * Constants.MAP_CHUNK_SIZE;
225                        heightPix = heightChunks * Constants.MAP_CHUNK_SIZE;
226                }
227
228                private Color32 shortColorToColor32 (ushort col)
229                {
230                        return new Color32 ((byte)((float)(col >> 10 & 31) / 31f * 255f), (byte)((float)(col >> 5 & 31) / 31f * 255f), (byte)((float)(col & 31) / 31f * 255f), 255);
231                }
232
233                private Color shortColorToColor (ushort col)
234                {
235                        return new Color (((float)(col >> 10 & 31) / 31f), ((float)(col >> 5 & 31) / 31f), ((float)(col & 31) / 31f), 255);
236                }
237
238        }
239}
Note: See TracBrowser for help on using the repository browser.