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

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

Fixes

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