PageRenderTime 44ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/TEditXna/Editor/Clipboard/ClipboardBuffer.File.cs

https://github.com/Surfpup/Terraria-Map-Editor
C# | 536 lines | 449 code | 75 blank | 12 comment | 96 complexity | 193a96ad2d02b8bda8c10561d3cfb7dc MD5 | raw file
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Windows;
  5. using System.Windows.Media;
  6. using System.Windows.Media.Imaging;
  7. using BCCL.Geometry.Primitives;
  8. using TEditXNA.Terraria;
  9. using TEditXNA.Terraria.Objects;
  10. namespace TEditXna.Editor.Clipboard
  11. {
  12. public partial class ClipboardBuffer
  13. {
  14. public const int SchematicVersion = 3;
  15. public void Save(string filename, bool isFalseColor = false)
  16. {
  17. if (isFalseColor)
  18. {
  19. SaveFalseColor(filename);
  20. return;
  21. }
  22. // Catch pngs that are real color
  23. if (string.Equals(".png", Path.GetExtension(filename), StringComparison.InvariantCultureIgnoreCase))
  24. {
  25. Preview.SavePng(filename);
  26. return;
  27. }
  28. Name = Path.GetFileNameWithoutExtension(filename);
  29. using (var stream = new FileStream(filename, FileMode.Create))
  30. {
  31. using (var bw = new BinaryWriter(stream))
  32. {
  33. bw.Write(Name);
  34. bw.Write(SchematicVersion);
  35. bw.Write(Size.X);
  36. bw.Write(Size.Y);
  37. for (int x = 0; x < Size.X; x++)
  38. {
  39. for (int y = 0; y < Size.Y; y++)
  40. {
  41. var curTile = Tiles[x, y];
  42. bw.Write(curTile.IsActive);
  43. if (curTile.IsActive)
  44. {
  45. bw.Write(curTile.Type);
  46. if (World.TileProperties[curTile.Type].IsFramed)
  47. {
  48. bw.Write(curTile.U);
  49. bw.Write(curTile.V);
  50. }
  51. }
  52. if ((int)curTile.Wall > 0)
  53. {
  54. bw.Write(true);
  55. bw.Write(curTile.Wall);
  56. }
  57. else
  58. bw.Write(false);
  59. if ((int)curTile.Liquid > 0)
  60. {
  61. bw.Write(true);
  62. bw.Write(curTile.Liquid);
  63. bw.Write(curTile.IsLava);
  64. }
  65. else
  66. bw.Write(false);
  67. bw.Write(curTile.HasWire);
  68. }
  69. }
  70. for (int chestIndex = 0; chestIndex < 1000; chestIndex++)
  71. {
  72. if (chestIndex >= Chests.Count)
  73. {
  74. bw.Write(false);
  75. }
  76. else
  77. {
  78. Chest curChest = Chests[chestIndex];
  79. bw.Write(true);
  80. bw.Write(curChest.X);
  81. bw.Write(curChest.Y);
  82. for (int j = 0; j < Chest.MaxItems; ++j)
  83. {
  84. if (curChest.Items.Count > j)
  85. {
  86. bw.Write((byte)curChest.Items[j].StackSize);
  87. if (curChest.Items[j].StackSize > 0)
  88. {
  89. bw.Write(curChest.Items[j].NetId);
  90. bw.Write(curChest.Items[j].Prefix);
  91. }
  92. }
  93. else
  94. bw.Write((byte)0);
  95. }
  96. }
  97. }
  98. for (int signIndex = 0; signIndex < 1000; signIndex++)
  99. {
  100. if (signIndex >= Signs.Count || string.IsNullOrWhiteSpace(Signs[signIndex].Text))
  101. {
  102. bw.Write(false);
  103. }
  104. else
  105. {
  106. var curSign = Signs[signIndex];
  107. bw.Write(true);
  108. bw.Write(curSign.Text);
  109. bw.Write(curSign.X);
  110. bw.Write(curSign.Y);
  111. }
  112. }
  113. bw.Write(Name);
  114. bw.Write(SchematicVersion);
  115. bw.Write(Size.X);
  116. bw.Write(Size.Y);
  117. bw.Close();
  118. }
  119. }
  120. }
  121. public static ClipboardBuffer LoadFromImage(string filename)
  122. {
  123. var urifrompath = new Uri(filename);
  124. var bmp = new BitmapImage(urifrompath);
  125. if (bmp.Width > 8400)
  126. return null;
  127. if (bmp.Height > 2400)
  128. return null;
  129. string name = Path.GetFileNameWithoutExtension(filename);
  130. var buffer = new ClipboardBuffer(new Vector2Int32(bmp.PixelWidth, bmp.PixelHeight));
  131. buffer.Name = name;
  132. var wbmp = new WriteableBitmap(bmp);
  133. if (wbmp.Format.BitsPerPixel < 32)
  134. return null;
  135. wbmp.Lock();
  136. unsafe
  137. {
  138. var pixels = (int*)wbmp.BackBuffer;
  139. for (int y = 0; y < bmp.PixelHeight; y++)
  140. {
  141. int row = y * bmp.PixelWidth;
  142. for (int x = 0; x < bmp.PixelWidth; x++)
  143. {
  144. buffer.Tiles[x, y] = TileFromColor(pixels[x + row]);
  145. }
  146. }
  147. }
  148. wbmp.Unlock();
  149. return buffer;
  150. }
  151. private static Tile TileFromColor(int color)
  152. {
  153. byte a = (byte)(color >> 24);
  154. byte r = (byte)(color >> 16);
  155. byte g = (byte)(color >> 8);
  156. byte b = (byte)(color >> 0);
  157. var tile = new Tile();
  158. // try and find a matching brick
  159. var tileProperty = World.GetBrickFromColor(a, r, g, b);
  160. if (tileProperty != null && !tileProperty.IsFramed)
  161. {
  162. tile.IsActive = true;
  163. tile.Type = (byte)tileProperty.Id;
  164. }
  165. // try and find a matching wall
  166. var wallproperty = World.GetWallFromColor(a, r, g, b);
  167. if (wallproperty != null && !tile.IsActive)
  168. {
  169. tile.Wall = (byte)wallproperty.Id;
  170. }
  171. return tile;
  172. }
  173. public static ClipboardBuffer Load(string filename)
  174. {
  175. string ext = Path.GetExtension(filename);
  176. if (string.Equals(ext, ".jpg", StringComparison.InvariantCultureIgnoreCase) || string.Equals(ext, ".png", StringComparison.InvariantCultureIgnoreCase) || string.Equals(ext, ".bmp", StringComparison.InvariantCultureIgnoreCase))
  177. return LoadFromImage(filename);
  178. using (var stream = new FileStream(filename, FileMode.Open))
  179. {
  180. using (var br = new BinaryReader(stream))
  181. {
  182. string name = br.ReadString();
  183. int version = br.ReadInt32();
  184. if (name != Path.GetFileNameWithoutExtension(filename))
  185. {
  186. br.Close();
  187. stream.Close();
  188. return LoadOld(filename);
  189. }
  190. int sizeX = br.ReadInt32();
  191. int sizeY = br.ReadInt32();
  192. var buffer = new ClipboardBuffer(new Vector2Int32(sizeX, sizeY));
  193. buffer.Name = name;
  194. for (int x = 0; x < sizeX; x++)
  195. {
  196. for (int y = 0; y < sizeY; y++)
  197. {
  198. var curTile = new Tile();
  199. curTile.IsActive = br.ReadBoolean();
  200. if (curTile.IsActive)
  201. {
  202. curTile.Type = br.ReadByte();
  203. if (World.TileProperties[curTile.Type].IsFramed)
  204. {
  205. curTile.U = br.ReadInt16();
  206. curTile.V = br.ReadInt16();
  207. }
  208. }
  209. if (br.ReadBoolean())
  210. curTile.Wall = br.ReadByte();
  211. if (br.ReadBoolean())
  212. {
  213. curTile.Liquid = br.ReadByte();
  214. curTile.IsLava = br.ReadBoolean();
  215. }
  216. curTile.HasWire = br.ReadBoolean();
  217. buffer.Tiles[x, y] = curTile;
  218. }
  219. }
  220. for (int chestIndex = 0; chestIndex < 1000; chestIndex++)
  221. {
  222. if (br.ReadBoolean())
  223. {
  224. var curChest = new Chest(br.ReadInt32(), br.ReadInt32());
  225. for (int j = 0; j < Chest.MaxItems; ++j)
  226. {
  227. curChest.Items[j].StackSize = br.ReadByte();
  228. if (curChest.Items[j].StackSize > 0)
  229. {
  230. if (version >= 3)
  231. curChest.Items[j].NetId = br.ReadInt32();
  232. else
  233. curChest.Items[j].SetFromName(br.ReadString());
  234. curChest.Items[j].Prefix = br.ReadByte();
  235. }
  236. else
  237. {
  238. curChest.Items[j].SetFromName("[empty]");
  239. }
  240. }
  241. buffer.Chests.Add(curChest);
  242. }
  243. }
  244. for (int signIndex = 0; signIndex < 1000; signIndex++)
  245. {
  246. if (br.ReadBoolean())
  247. {
  248. string text = br.ReadString();
  249. int x = br.ReadInt32();
  250. int y = br.ReadInt32();
  251. buffer.Signs.Add(new Sign(x, y, text));
  252. }
  253. }
  254. if (buffer.Name == br.ReadString() &&
  255. version == br.ReadInt32() &&
  256. buffer.Size.X == br.ReadInt32() &&
  257. buffer.Size.Y == br.ReadInt32())
  258. {
  259. // valid;
  260. return buffer;
  261. }
  262. br.Close();
  263. return null;
  264. }
  265. }
  266. }
  267. public static ClipboardBuffer LoadOld(string filename)
  268. {
  269. using (var stream = new FileStream(filename, FileMode.Open))
  270. {
  271. using (var reader = new BinaryReader(stream))
  272. {
  273. int maxx = reader.ReadInt32();
  274. int maxy = reader.ReadInt32();
  275. var buffer = new ClipboardBuffer(new Vector2Int32(maxx, maxy));
  276. buffer.Name = Path.GetFileNameWithoutExtension(filename);
  277. for (int x = 0; x < buffer.Size.X; x++)
  278. {
  279. for (int y = 0; y < buffer.Size.Y; y++)
  280. {
  281. var tile = new Tile();
  282. tile.IsActive = reader.ReadBoolean();
  283. if (tile.IsActive)
  284. {
  285. tile.Type = reader.ReadByte();
  286. if (World.TileProperties[tile.Type].IsFramed && tile.Type != 4)
  287. {
  288. tile.U = reader.ReadInt16();
  289. tile.V = reader.ReadInt16();
  290. }
  291. else
  292. {
  293. tile.U = -1;
  294. tile.V = -1;
  295. }
  296. }
  297. // trash old lighted value
  298. reader.ReadBoolean();
  299. if (reader.ReadBoolean())
  300. {
  301. tile.Wall = reader.ReadByte();
  302. }
  303. if (reader.ReadBoolean())
  304. {
  305. tile.Liquid = reader.ReadByte();
  306. tile.IsLava = reader.ReadBoolean();
  307. }
  308. buffer.Tiles[x, y] = tile;
  309. }
  310. }
  311. for (int chestIndex = 0; chestIndex < 1000; chestIndex++)
  312. {
  313. if (reader.ReadBoolean())
  314. {
  315. var chest = new Chest();
  316. chest.X = reader.ReadInt32();
  317. chest.Y = reader.ReadInt32();
  318. for (int slot = 0; slot < Chest.MaxItems; slot++)
  319. {
  320. byte stackSize = reader.ReadByte();
  321. if (stackSize > 0)
  322. {
  323. string itemName = reader.ReadString();
  324. chest.Items[slot].SetFromName(itemName);
  325. chest.Items[slot].StackSize = stackSize;
  326. }
  327. }
  328. //Chests[chestIndex] = chest;
  329. buffer.Chests.Add(chest);
  330. }
  331. }
  332. for (int signIndex = 0; signIndex < 1000; signIndex++)
  333. {
  334. if (reader.ReadBoolean())
  335. {
  336. string signText = reader.ReadString();
  337. int x = reader.ReadInt32();
  338. int y = reader.ReadInt32();
  339. if (buffer.Tiles[x, y].IsActive && (buffer.Tiles[x, y].Type == 55 || buffer.Tiles[x, y].Type == 85))
  340. // validate tile location
  341. {
  342. var sign = new Sign(x, y, signText);
  343. //Signs[signIndex] = sign;
  344. buffer.Signs.Add(sign);
  345. }
  346. }
  347. }
  348. int checkx = reader.ReadInt32();
  349. int checky = reader.ReadInt32();
  350. if (checkx == maxx && checky == maxy)
  351. return buffer;
  352. }
  353. }
  354. return null;
  355. }
  356. public void SaveFalseColor(string filename)
  357. {
  358. var wbmp = new WriteableBitmap(Size.X, Size.Y, 96, 96, PixelFormats.Bgra32, null);
  359. for (int y = 0; y < Size.Y; y++)
  360. {
  361. for (int x = 0; x < Size.X; x++)
  362. {
  363. var curtile = Tiles[x, y];
  364. byte a = TileArgsToByte(curtile);
  365. byte r = curtile.Type;
  366. byte g = curtile.Wall;
  367. byte b = curtile.Liquid;
  368. wbmp.SetPixel(x, y, a, r, g, b);
  369. }
  370. }
  371. wbmp.SavePng(filename);
  372. }
  373. public static ClipboardBuffer LoadFalseColor(string filename)
  374. {
  375. var urifrompath = new Uri(filename);
  376. var bmp = new BitmapImage(urifrompath);
  377. if (bmp.Width > 8400)
  378. return null;
  379. if (bmp.Height > 2400)
  380. return null;
  381. string name = Path.GetFileNameWithoutExtension(filename);
  382. var buffer = new ClipboardBuffer(new Vector2Int32(bmp.PixelWidth, bmp.PixelHeight));
  383. buffer.Name = name;
  384. var wbmp = new WriteableBitmap(bmp);
  385. if (wbmp.Format.BitsPerPixel < 32)
  386. return null;
  387. wbmp.Lock();
  388. unsafe
  389. {
  390. var pixels = (int*)wbmp.BackBuffer;
  391. for (int y = 0; y < bmp.PixelHeight; y++)
  392. {
  393. int row = y * bmp.PixelWidth;
  394. for (int x = 0; x < bmp.PixelWidth; x++)
  395. {
  396. buffer.Tiles[x, y] = TileFromFalseColor(pixels[x + row]);
  397. }
  398. }
  399. }
  400. wbmp.Unlock();
  401. return buffer;
  402. }
  403. private static Tile TileFromFalseColor(int color)
  404. {
  405. byte a = (byte)(color >> 24);
  406. byte r = (byte)(color >> 16);
  407. byte g = (byte)(color >> 8);
  408. byte b = (byte)(color >> 0);
  409. var tile = new Tile();
  410. AppendTileFlagsFromByte(ref tile, a);
  411. // try and find a matching brick
  412. var tileProperty = World.TileProperties.FirstOrDefault(t => t.Id == r);
  413. if (tileProperty != null && !tileProperty.IsFramed)
  414. {
  415. tile.Type = (byte)tileProperty.Id;
  416. }
  417. else
  418. {
  419. // disable missing and framed tiles
  420. tile.IsActive = false;
  421. }
  422. // try and find a matching wall
  423. var wallproperty = World.WallProperties[g];
  424. if (wallproperty != null && !tile.IsActive)
  425. {
  426. tile.Wall = (byte)wallproperty.Id;
  427. }
  428. tile.Liquid = b;
  429. return tile;
  430. }
  431. [Flags]
  432. public enum TileFlags : byte
  433. {
  434. IsActive = 0x40,
  435. IsLava = 0x20,
  436. HasWire = 0x10,
  437. // still have 0x08, 0x04, 0x02, 0x01 available for additional flags
  438. }
  439. public byte TileArgsToByte(Tile tile)
  440. {
  441. byte b = 0;
  442. b |= 0x80; // turn on max bit so we can see stuff (otherwise alpha is too low)
  443. if (tile.IsActive)
  444. b |= (byte)TileFlags.IsActive;
  445. if (tile.IsLava)
  446. b |= (byte)TileFlags.IsLava;
  447. if (tile.HasWire)
  448. b |= (byte)TileFlags.HasWire;
  449. return b;
  450. }
  451. public static void AppendTileFlagsFromByte(ref Tile tile, byte flags)
  452. {
  453. if ((flags & (byte)TileFlags.IsActive) == (byte)TileFlags.IsActive)
  454. tile.IsActive = true;
  455. if ((flags & (byte)TileFlags.IsLava) == (byte)TileFlags.IsLava)
  456. tile.IsLava = true;
  457. if ((flags & (byte)TileFlags.HasWire) == (byte)TileFlags.HasWire)
  458. tile.HasWire = true;
  459. }
  460. }
  461. }