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

Last change on this file since 136 was 136, checked in by alloc, 7 years ago

Fixes

File size: 7.9 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 = null;
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
84                        if (widthPix <= 8000 && heightPix <= 8000)
85                                fullMapTexture = new Texture2D (widthPix, heightPix);
86
87                        Vector2i curFullMapPos;
88                        Vector2i curChunkPos;
89                        for (curFullMapPos.x = 0; curFullMapPos.x < widthPix; curFullMapPos.x += Constants.MAP_CHUNK_SIZE) {
90                                for (curFullMapPos.y = 0; curFullMapPos.y < heightPix; curFullMapPos.y += Constants.MAP_CHUNK_SIZE) {
91                                        curChunkPos.x = (curFullMapPos.x / Constants.MAP_CHUNK_SIZE) + minChunk.x;
92                                        curChunkPos.y = (curFullMapPos.y / Constants.MAP_CHUNK_SIZE) + minChunk.y;
93
94                                        RenderChunk (curChunkPos, curFullMapPos);
95                                }
96                                Log.Out (String.Format ("RenderMap: {0}/{1} ({2}%)", curFullMapPos.x, widthPix, (int)((float)curFullMapPos.x / widthPix * 100)));
97                        }
98                        SaveAllBlockMaps (null, null);
99
100                        rfm = null;
101
102                        if (fullMapTexture != null) {
103                                byte[] array = fullMapTexture.EncodeToPNG ();
104                                File.WriteAllBytes (Constants.MAP_DIRECTORY + "/map.png", array);
105                                Texture2D.Destroy (fullMapTexture);
106                                fullMapTexture = null;
107                        }
108
109                        renderingFullMap = false;
110
111                        Log.Out ("Generating map took: " + microStopwatch.ElapsedMilliseconds + " ms");
112                        Log.Out ("World extent: " + minPos + " - " + maxPos);
113                }
114
115                private int saveCount = 0;
116
117                private void SaveAllBlockMaps (object source, System.Timers.ElapsedEventArgs e)
118                {
119                        Monitor.Enter (zoomLevelBuffers);
120                        try {
121                                Log.Out ("------- SaveAllBlockMaps " + ++saveCount);
122                                for (int i = 0; i < Constants.ZOOMLEVELS; i++) {
123                                        zoomLevelBuffers [i].SaveBlock ();
124                                }
125                        } finally {
126                                Monitor.Exit (zoomLevelBuffers);
127                        }
128                }
129
130                private bool RenderChunk (Vector2i chunkPos, Vector2i fullMapPos = default(Vector2i))
131                {
132                        long chunkKey = WorldChunkCache.MakeChunkKey (chunkPos.x, chunkPos.y);
133                        if (rfm.ContainsChunkSync (chunkKey)) {
134                                Chunk chunk = rfm.GetChunkSync (chunkKey);
135                                return RenderChunk (chunk, chunkPos, fullMapPos);
136                        }
137                        return false;
138                }
139
140                private bool RenderChunk (Chunk chunk, Vector2i chunkPos, Vector2i fullMapPos = default(Vector2i))
141                {
142                        Monitor.Enter (zoomLevelBuffers);
143                        try {
144                                ushort[] mapColors = chunk.GetMapColors ();
145                                if (mapColors != null) {
146                                        Vector2i block, blockOffset;
147                                        getBlockNumber (chunkPos, out block, out blockOffset, Constants.MAP_BLOCK_TO_CHUNK_DIV, Constants.MAP_CHUNK_SIZE);
148
149                                        for (int i_colors = 0; i_colors < mapColors.Length; i_colors++) {
150                                                chunkColors [i_colors] = shortColorToColor (mapColors [i_colors]);
151                                        }
152
153                                        zoomLevelBuffers [Constants.ZOOMLEVELS - 1].LoadBlock (block);
154                                        zoomLevelBuffers [Constants.ZOOMLEVELS - 1].SetPart (blockOffset, Constants.MAP_CHUNK_SIZE, chunkColors);
155
156                                        if (renderingFullMap && fullMapTexture != null)
157                                                fullMapTexture.SetPixels (fullMapPos.x, fullMapPos.y, Constants.MAP_CHUNK_SIZE, Constants.MAP_CHUNK_SIZE, chunkColors);
158
159                                        RenderZoomLevel (Constants.ZOOMLEVELS - 1, block);
160
161                                        return true;
162                                }
163                                return false;
164                        } finally {
165                                Monitor.Exit (zoomLevelBuffers);
166                        }
167                }
168
169                private void RenderZoomLevel (int level, Vector2i innerBlock)
170                {
171                        if (level > 0) {
172                                Vector2i block, blockOffset;
173                                getBlockNumber (innerBlock, out block, out blockOffset, 2, Constants.MAP_BLOCK_SIZE / 2);
174
175                                zoomLevelBuffers [level - 1].LoadBlock (block);
176                                zoomLevelBuffers [level - 1].SetPart (blockOffset, Constants.MAP_BLOCK_SIZE / 2, zoomLevelBuffers [level].GetHalfScaled ());
177
178                                RenderZoomLevel (level - 1, block);
179                        }
180                }
181
182                private void getBlockNumber (Vector2i innerPos, out Vector2i block, out Vector2i blockOffset, int scaleFactor, int offsetSize)
183                {
184                        block.x = ((innerPos.x + 16777216) / scaleFactor) - (16777216 / scaleFactor);
185                        block.y = ((innerPos.y + 16777216) / scaleFactor) - (16777216 / scaleFactor);
186                        blockOffset.x = ((innerPos.x + 16777216) % scaleFactor) * offsetSize;
187                        blockOffset.y = ((innerPos.y + 16777216) % scaleFactor) * offsetSize;
188                }
189
190                private void getWorldExtent (out Vector2i minChunk, out Vector2i maxChunk,
191                                            out Vector2i minPos, out Vector2i maxPos,
192                                            out int widthChunks, out int heightChunks,
193                                            out int widthPix, out int heightPix)
194                {
195                        long[] keys = rfm.GetAllChunkKeys ();
196                        int minX = Int32.MaxValue;
197                        int minY = Int32.MaxValue;
198                        int maxX = Int32.MinValue;
199                        int maxY = Int32.MinValue;
200                        foreach (long key in keys) {
201                                int x = WorldChunkCache.extractX (key);
202                                int y = WorldChunkCache.extractZ (key);
203
204                                if (x < minX)
205                                        minX = x;
206                                if (x > maxX)
207                                        maxX = x;
208                                if (y < minY)
209                                        minY = y;
210                                if (y > maxY)
211                                        maxY = y;
212                        }
213
214                        minChunk.x = minX;
215                        minChunk.y = minY;
216
217                        maxChunk.x = maxX;
218                        maxChunk.y = maxY;
219
220                        minPos.x = minX * Constants.MAP_CHUNK_SIZE;
221                        minPos.y = minY * Constants.MAP_CHUNK_SIZE;
222
223                        maxPos.x = maxX * Constants.MAP_CHUNK_SIZE;
224                        maxPos.y = maxY * Constants.MAP_CHUNK_SIZE;
225
226                        widthChunks = maxX - minX + 1;
227                        heightChunks = maxY - minY + 1;
228
229                        widthPix = widthChunks * Constants.MAP_CHUNK_SIZE;
230                        heightPix = heightChunks * Constants.MAP_CHUNK_SIZE;
231                }
232
233                private Color32 shortColorToColor32 (ushort col)
234                {
235                        return new Color32 ((byte)((float)(col >> 10 & 31) / 31f * 255f), (byte)((float)(col >> 5 & 31) / 31f * 255f), (byte)((float)(col & 31) / 31f * 255f), 255);
236                }
237
238                private Color shortColorToColor (ushort col)
239                {
240                        return new Color (((float)(col >> 10 & 31) / 31f), ((float)(col >> 5 & 31) / 31f), ((float)(col & 31) / 31f), 255);
241                }
242
243        }
244}
Note: See TracBrowser for help on using the repository browser.