PageRenderTime 57ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/WorldView/Structures/World.cs

#
C# | 2079 lines | 1627 code | 383 blank | 69 comment | 393 complexity | 9320b8e9ac930749697fdff674978f91 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Drawing;
  5. using System.ComponentModel;
  6. using System.Timers;
  7. using MoreTerra.Utilities;
  8. using System.Text;
  9. namespace MoreTerra.Structures
  10. {
  11. public class World
  12. {
  13. // All the parts of a Terraria world.
  14. private WorldHeader header;
  15. private Tile[,] tiles;
  16. private List<Chest> chests;
  17. private List<Sign> signs;
  18. private List<NPC> npcs;
  19. private Footer footer;
  20. // Various file reading items.
  21. private BackwardsBinaryReader backReader;
  22. private BufferedBinaryReader buffReader;
  23. private BinaryReader reader;
  24. private FileStream stream;
  25. // Quick lookup for the world sizes.
  26. private int MaxX, MaxY;
  27. // Things to do with showing progress when reading/scanning.
  28. private int progress;
  29. private long progressPosition;
  30. private BackgroundWorker bw;
  31. // Lookup table for important tiles.
  32. private Boolean[] tileImportant;
  33. // Positions of each spot in the file.
  34. private Int64 posTiles;
  35. private Int64 posChests;
  36. private Int64 posSigns;
  37. private Int64 posNpcs;
  38. private Int64 posFooter;
  39. private Int64 posEnd;
  40. private Single readWorldPerc = 50;
  41. int[] sectionPointers;
  42. // List generated from reading in chest tiles.
  43. private Dictionary<Point, ChestType> chestTypeList;
  44. #region Structures
  45. // Helper structure for storing information for tile scanning.
  46. public class TileImportance
  47. {
  48. private Boolean[] tImportant;
  49. private Boolean[] tKnown;
  50. public TileImportance()
  51. {
  52. Int32 i;
  53. tImportant = new Boolean[256];
  54. tKnown = new Boolean[256];
  55. for (i = 0; i < 256; i++)
  56. {
  57. tImportant[i] = false;
  58. tKnown[i] = false;
  59. }
  60. }
  61. public TileImportance(TileImportance copyFrom)
  62. {
  63. Int32 i;
  64. tImportant = new Boolean[256];
  65. tKnown = new Boolean[256];
  66. for (i = 0; i < 256; i++)
  67. {
  68. tImportant[i] = copyFrom.tImportant[i];
  69. tKnown[i] = copyFrom.tKnown[i];
  70. }
  71. }
  72. public Boolean isImportant(Byte i)
  73. {
  74. return tImportant[i];
  75. }
  76. public void setImportant(Byte i, Boolean v)
  77. {
  78. tImportant[i] = v;
  79. }
  80. public Boolean isKnown(Byte i)
  81. {
  82. return tKnown[i];
  83. }
  84. public void setKnown(Byte i, Boolean v)
  85. {
  86. tKnown[i] = v;
  87. }
  88. }
  89. // Helper structure for storing all the information
  90. // for each path when scanning for tiles.
  91. public class tileReader
  92. {
  93. public static Int32 nextId = 0;
  94. public Int32 id;
  95. public Int64 filePos;
  96. public TileImportance tileLookup;
  97. public Tile tile;
  98. public List<Byte> tileOrder;
  99. public Int32 tilesRead;
  100. public Point startAt;
  101. public Byte splitAt;
  102. public tileReader(Int64 fPos)
  103. {
  104. id = nextId;
  105. nextId++;
  106. filePos = fPos;
  107. tileLookup = new TileImportance();
  108. tile = new Tile();
  109. tileOrder = new List<Byte>();
  110. tilesRead = 0;
  111. }
  112. public tileReader(tileReader copy)
  113. {
  114. id = nextId;
  115. nextId++;
  116. filePos = copy.filePos;
  117. tileLookup = new TileImportance(copy.tileLookup);
  118. tile = new Tile(copy.tile);
  119. tileOrder = new List<Byte>();
  120. tilesRead = copy.tilesRead;
  121. foreach (Byte b in copy.tileOrder)
  122. tileOrder.Add(b);
  123. }
  124. }
  125. #endregion
  126. #region Constructors
  127. public World()
  128. {
  129. Clear();
  130. Initialize();
  131. }
  132. #endregion
  133. private void Initialize()
  134. {
  135. // tileImportant = new Boolean[TileProperties.TYPES];
  136. // for (Int32 i = 0; i < TileProperties.TYPES; i++)
  137. // tileImportant[i] = TileProperties.tileTypeDefs[i].IsImportant;
  138. }
  139. public void Clear()
  140. {
  141. header = new WorldHeader();
  142. tiles = null;
  143. chests = null;
  144. signs = null;
  145. footer = null;
  146. posChests = 0;
  147. posEnd = 0;
  148. posFooter = 0;
  149. posNpcs = 0;
  150. posSigns = 0;
  151. posTiles = 0;
  152. MaxX = 0;
  153. MaxY = 0;
  154. progress = 0;
  155. if (reader != null)
  156. {
  157. reader.Close();
  158. reader = null;
  159. }
  160. if (stream != null)
  161. stream = null;
  162. if (buffReader != null)
  163. buffReader = null;
  164. if (bw != null)
  165. bw = null;
  166. }
  167. #region ReadFunctions
  168. public void ReadWorld(String world, BackgroundWorker worker = null)
  169. {
  170. Timer t = null;
  171. #if (DEBUG == false)
  172. try
  173. {
  174. #endif
  175. if (worker != null)
  176. {
  177. bw = worker;
  178. progressPosition = 0;
  179. t = new Timer(333);
  180. t.Elapsed += new ElapsedEventHandler(timer_ReadWorld);
  181. t.Start();
  182. }
  183. readWorldPerc = 50;
  184. stream = new FileStream(world, FileMode.Open, FileAccess.Read);
  185. reader = new BinaryReader(stream);
  186. ReadHeader();
  187. ReadWorldTiles();
  188. ReadChests();
  189. ReadSigns();
  190. ReadNPCs();
  191. ReadFooter();
  192. #if (DEBUG == false)
  193. }
  194. catch (Exception e)
  195. {
  196. if (bw != null)
  197. {
  198. t.Stop();
  199. bw = null;
  200. }
  201. reader.Close();
  202. throw e;
  203. }
  204. #endif
  205. if (bw != null)
  206. {
  207. t.Stop();
  208. bw = null;
  209. }
  210. reader.Close();
  211. }
  212. private void timer_ReadWorld(object sender, ElapsedEventArgs e)
  213. {
  214. progress = (Int32)(((Single)progressPosition / stream.Length) * readWorldPerc);
  215. bw.ReportProgress(progress);
  216. }
  217. private void ReadHeader()
  218. {
  219. //reader.ReadBytes(8);
  220. //var hello = reader.ReadString();
  221. //byte[] bytes = reader.ReadBytes(10);
  222. //var test = Encoding.Unicode.GetString(bytes);
  223. int version = reader.ReadInt32();
  224. if (version < 94)
  225. throw new Exception("Must use version 1.2.3.1 or higher!");
  226. short sectionCount = reader.ReadInt16();
  227. sectionPointers = new int[sectionCount];
  228. for (int j = 0; j < sectionCount; j++)
  229. {
  230. sectionPointers[j] = reader.ReadInt32();
  231. }
  232. short tiletypeCount = reader.ReadInt16();
  233. tileImportant = new bool[tiletypeCount];
  234. byte flags = 0;
  235. byte mask = 0x80;
  236. for (int k = 0; k < tiletypeCount; k++)
  237. {
  238. if (mask == 0x80)
  239. {
  240. flags = reader.ReadByte();
  241. mask = 0x01;
  242. }
  243. else
  244. {
  245. mask <<= 1;
  246. }
  247. if ((flags & mask) == mask)
  248. tileImportant[k] = true;
  249. }
  250. Int32 x, y, w, h;
  251. Int32 i;
  252. if (bw != null)
  253. bw.ReportProgress((Int32)(((Single)progressPosition / stream.Length) * readWorldPerc)
  254. , "Reading Header");
  255. header = new WorldHeader();
  256. header.sectionPointers = sectionPointers;
  257. header.ReleaseNumber = version;
  258. header.Name = reader.ReadString();
  259. header.Id = reader.ReadInt32();
  260. x = reader.ReadInt32();
  261. w = reader.ReadInt32();
  262. y = reader.ReadInt32();
  263. h = reader.ReadInt32();
  264. header.WorldCoords = new Rect(x, w, y, h);
  265. MaxY = reader.ReadInt32();
  266. MaxX = reader.ReadInt32();
  267. header.MaxTiles = new Point(MaxX, MaxY);
  268. header.TreeX = new int[3];
  269. header.TreeStyle = new int[4];
  270. header.CaveBackX = new int[3];
  271. header.CaveBackStyle = new int[4];
  272. if (version >= 66)
  273. {
  274. header.MoonType = reader.ReadByte();
  275. for (i = 0; i < 3; i++)
  276. {
  277. header.TreeX[i] = reader.ReadInt32();
  278. }
  279. for (i = 0; i < 4; i++)
  280. {
  281. header.TreeStyle[i] = reader.ReadInt32();
  282. }
  283. for (i = 0; i < 3; i++)
  284. {
  285. header.CaveBackX[i] = reader.ReadInt32();
  286. }
  287. for (i = 0; i < 4; i++)
  288. {
  289. header.CaveBackStyle[i] = reader.ReadInt32();
  290. }
  291. header.IceBackStyle = reader.ReadInt32();
  292. header.JungleBackStyle = reader.ReadInt32();
  293. header.HellBackStyle = reader.ReadInt32();
  294. }
  295. header.SpawnPoint = new Point(reader.ReadInt32(), reader.ReadInt32());
  296. header.SurfaceLevel = reader.ReadDouble();
  297. header.RockLayer = reader.ReadDouble();
  298. header.TemporaryTime = reader.ReadDouble();
  299. header.IsDayTime = reader.ReadBoolean();
  300. header.MoonPhase = reader.ReadInt32();
  301. header.IsBloodMoon = reader.ReadBoolean();
  302. if (version >= 70)
  303. header.IsEclipse = reader.ReadBoolean();
  304. header.DungeonPoint = new Point(reader.ReadInt32(), reader.ReadInt32());
  305. if (version >= 66)
  306. {
  307. header.Crimson = reader.ReadBoolean();
  308. }
  309. header.IsBoss1Dead = reader.ReadBoolean();
  310. header.IsBoss2Dead = reader.ReadBoolean();
  311. header.IsBoss3Dead = reader.ReadBoolean();
  312. if (version >= 66)
  313. {
  314. header.IsQueenBeeDead = reader.ReadBoolean();
  315. header.IsMechBoss1Dead = reader.ReadBoolean();
  316. header.IsMechBoss2Dead = reader.ReadBoolean();
  317. header.IsMechBoss3Dead = reader.ReadBoolean();
  318. header.IsMechBossAnyDead = reader.ReadBoolean();
  319. header.IsPlantBossDead = reader.ReadBoolean();
  320. header.IsGolemBossDead = reader.ReadBoolean();
  321. }
  322. if (version >= 0x24)
  323. {
  324. header.IsGoblinSaved = reader.ReadBoolean();
  325. header.IsWizardSaved = reader.ReadBoolean();
  326. header.IsMechanicSaved = reader.ReadBoolean();
  327. header.IsGoblinArmyDefeated = reader.ReadBoolean();
  328. header.IsClownDefeated = reader.ReadBoolean();
  329. }
  330. if (version >= 0x25)
  331. {
  332. header.IsFrostDefeated = reader.ReadBoolean();
  333. }
  334. if (version >= 66)
  335. {
  336. header.IsPiratesDefeated = reader.ReadBoolean();
  337. }
  338. header.IsShadowOrbSmashed = reader.ReadBoolean();
  339. header.IsMeteorSpawned = reader.ReadBoolean();
  340. header.ShadowOrbsSmashed = reader.ReadByte();
  341. if (version >= 0x24)
  342. {
  343. header.AltarsDestroyed = reader.ReadInt32();
  344. header.HardMode = reader.ReadBoolean();
  345. }
  346. header.InvasionDelay = reader.ReadInt32();
  347. header.InvasionSize = reader.ReadInt32();
  348. header.InvasionType = reader.ReadInt32();
  349. header.InvasionPointX = reader.ReadDouble();
  350. header.OreTiers = new int[3];
  351. header.Styles = new byte[8];
  352. if (version >= 66)
  353. {
  354. header.IsRaining = reader.ReadBoolean();
  355. header.RainTime = reader.ReadInt32();
  356. header.MaxRain = reader.ReadSingle();
  357. for (i = 0; i < 3; i++)
  358. {
  359. header.OreTiers[i] = reader.ReadInt32();
  360. }
  361. for (i = 0; i < 8; i++)
  362. {
  363. header.Styles[i] = reader.ReadByte();
  364. }
  365. header.CloudsActive = reader.ReadInt32();
  366. header.NumClouds = reader.ReadInt16();
  367. header.WindSpeed = reader.ReadSingle();
  368. List<string> anglerWhoFinishedToday = new List<string>();
  369. for (int index = reader.ReadInt32(); index > 0; --index)
  370. anglerWhoFinishedToday.Add(reader.ReadString());
  371. if (version < 99)
  372. return;
  373. var savedAngler = reader.ReadBoolean();
  374. if (version < 101)
  375. return;
  376. var anglerQuest = reader.ReadInt32();
  377. }
  378. else if (version >= 24)
  379. {
  380. if (header.AltarsDestroyed == 0)
  381. {
  382. for (i = 0; i < 3; i++)
  383. {
  384. header.OreTiers[i] = -1;
  385. }
  386. }
  387. else
  388. {
  389. header.OreTiers[1] = 107;
  390. header.OreTiers[1] = 108;
  391. header.OreTiers[1] = 111;
  392. }
  393. }
  394. posTiles = stream.Position;
  395. progressPosition = stream.Position;
  396. }
  397. private void ReadWorldTiles()
  398. {
  399. Boolean theB;
  400. Byte theI;
  401. Tile theTile;
  402. Int32 i, j;
  403. if (bw != null)
  404. bw.ReportProgress((Int32)(((Single)progressPosition / stream.Length) * readWorldPerc)
  405. , "Reading Tiles");
  406. tiles = new Tile[MaxX, MaxY];
  407. for (i = 0; i < MaxX; i++)
  408. {
  409. for (j = 0; j < MaxY; j++)
  410. {
  411. theTile = new Tile();
  412. theB = reader.ReadBoolean();
  413. theTile.Active = theB;
  414. if (theB == true)
  415. {
  416. theI = reader.ReadByte();
  417. if (theI > 85)
  418. theTile.TileType = theI;
  419. theTile.TileType = theI;
  420. if (tileImportant[theI] == true)
  421. {
  422. theTile.Important = true;
  423. theTile.Frame = new PointInt16(reader.ReadInt16() ,reader.ReadInt16());
  424. }
  425. else
  426. theTile.Important = false;
  427. }
  428. // /dev/null the Lighted Flag
  429. reader.ReadBoolean();
  430. theB = reader.ReadBoolean();
  431. theTile.Wall = theB;
  432. if (theB == true)
  433. theTile.WallType = reader.ReadByte();
  434. if (theTile.WallType == 0 && theTile.Wall == true)
  435. theTile.Wall = true;
  436. theB = reader.ReadBoolean();
  437. if (theB == true)
  438. {
  439. theTile.LiquidLevel = reader.ReadByte();
  440. theTile.Lava = reader.ReadBoolean();
  441. }
  442. tiles[i, j] = theTile;
  443. }
  444. progressPosition = stream.Position;
  445. }
  446. posChests = stream.Position;
  447. }
  448. private void ReadChests()
  449. {
  450. Boolean isChest;
  451. Int16 itemCount;
  452. Chest theChest = null;
  453. Item theItem;
  454. Int32 i, j;
  455. Int32 maxChests;
  456. int maxItems;
  457. chests = new List<Chest>();
  458. if (bw != null)
  459. bw.ReportProgress((Int32)(((Single)progressPosition / stream.Length) * readWorldPerc)
  460. , "Reading Chests");
  461. maxChests = reader.ReadInt16();
  462. maxItems = reader.ReadInt16();
  463. for (i = 0; i < maxChests; i++)
  464. {
  465. theChest = new Chest();
  466. theChest.ChestId = i;
  467. theChest.Active = true;
  468. theChest.Coordinates = new Point(reader.ReadInt32(), reader.ReadInt32());
  469. theChest.Name = reader.ReadString();
  470. if (chestTypeList != null)
  471. {
  472. if (chestTypeList.ContainsKey(theChest.Coordinates))
  473. theChest.Type = chestTypeList[theChest.Coordinates];
  474. }
  475. else
  476. {
  477. theChest.Type = ChestType.Chest;
  478. }
  479. for (j = 0; j < maxItems; j++)
  480. {
  481. if (header.ReleaseNumber > 68)
  482. itemCount = reader.ReadInt16();
  483. else
  484. itemCount = reader.ReadByte();
  485. if (itemCount > 0)
  486. {
  487. theItem = new Item();
  488. theItem.Id = j;
  489. theItem.Count = itemCount;
  490. if (header.ReleaseNumber >= 0x26)
  491. {
  492. theItem.Name = Global.Instance.Info.GetItemName(reader.ReadInt32());
  493. }
  494. else
  495. {
  496. theItem.Name = reader.ReadString();
  497. }
  498. if (header.ReleaseNumber >= 0x24)
  499. theItem.Prefix = reader.ReadByte();
  500. theChest.Items.Add(theItem);
  501. }
  502. }
  503. chests.Add(theChest);
  504. progressPosition = stream.Position;
  505. }
  506. posSigns = stream.Position;
  507. }
  508. private void ReadSigns()
  509. {
  510. Boolean isSign;
  511. Sign theSign;
  512. signs = new List<Sign>(1000);
  513. if (bw != null)
  514. bw.ReportProgress((Int32)(((Single)progressPosition / stream.Length) * readWorldPerc)
  515. , "Reading Signs");
  516. int maxSigns = reader.ReadInt16();
  517. for (Int32 i = 0; i < maxSigns; i++)
  518. {
  519. //isSign = reader.ReadBoolean();
  520. theSign = new Sign();
  521. theSign.Id = i;
  522. theSign.Active = true;
  523. theSign.Text = reader.ReadString();
  524. theSign.Position = new Point(reader.ReadInt32(), reader.ReadInt32());
  525. signs.Add(theSign);
  526. progressPosition = stream.Position;
  527. }
  528. posNpcs = stream.Position;
  529. }
  530. private void ReadNPCs()
  531. {
  532. Boolean nextNPC;
  533. NPC theNPC;
  534. String nameCrunch;
  535. String[] nameArray;
  536. NPCType npcType;
  537. Int32 i;
  538. npcs = new List<NPC>(20);
  539. i = 0;
  540. if (bw != null)
  541. bw.ReportProgress((Int32)(((Single)progressPosition / stream.Length) * readWorldPerc)
  542. , "Reading NPCs");
  543. nextNPC = reader.ReadBoolean();
  544. while (nextNPC == true)
  545. {
  546. theNPC = new NPC();
  547. theNPC.Id = i;
  548. theNPC.Active = nextNPC;
  549. if (Enum.TryParse(reader.ReadString().Replace(" ", ""), true, out npcType))
  550. theNPC.Type = npcType;
  551. else
  552. theNPC.Type = NPCType.Unknown;
  553. theNPC.Name = reader.ReadString();
  554. theNPC.Position = new PointSingle(reader.ReadSingle(), reader.ReadSingle());
  555. theNPC.Homeless = reader.ReadBoolean();
  556. theNPC.HomeTile = new Point(reader.ReadInt32(), reader.ReadInt32());
  557. npcs.Add(theNPC);
  558. i++;
  559. nextNPC = reader.ReadBoolean();
  560. progressPosition = stream.Position;
  561. }
  562. posFooter = stream.Position;
  563. }
  564. private void ReadNPCNames()
  565. {
  566. if (header.ReleaseNumber >= 0x24)
  567. {
  568. header.MerchantsName = reader.ReadString();
  569. header.NursesName = reader.ReadString();
  570. header.ArmsDealersName = reader.ReadString();
  571. header.DryadsName = reader.ReadString();
  572. header.GuidesName = reader.ReadString();
  573. header.ClothiersName = reader.ReadString();
  574. header.DemolitionistsName = reader.ReadString();
  575. header.TinkerersName = reader.ReadString();
  576. header.WizardsName = reader.ReadString();
  577. header.MechanicsName = reader.ReadString();
  578. header.TrufflesName = reader.ReadString();
  579. header.SteamPunkersName = reader.ReadString();
  580. header.DyeTradersName = reader.ReadString();
  581. header.PartyGirlsName = reader.ReadString();
  582. header.CyborgsName = reader.ReadString();
  583. header.PaintersName = reader.ReadString();
  584. header.WitchDoctorsName = reader.ReadString();
  585. header.PiratesName = reader.ReadString();
  586. }
  587. else
  588. {
  589. header.MerchantsName = "Not set";
  590. header.NursesName = "Not Set";
  591. header.ArmsDealersName = "Not Set";
  592. header.DryadsName = "Not Set";
  593. header.GuidesName = "Not Set";
  594. header.ClothiersName = "Not Set";
  595. header.DemolitionistsName = "Not Set";
  596. header.TinkerersName = "Not Set";
  597. header.WizardsName = "Not Set";
  598. header.MechanicsName = "Not Set";
  599. }
  600. }
  601. private void ReadFooter()
  602. {
  603. footer = new Footer();
  604. if (bw != null)
  605. bw.ReportProgress((Int32)(((Single)progressPosition / stream.Length) * readWorldPerc)
  606. , "Reading Footer");
  607. footer.Active = reader.ReadBoolean();
  608. footer.Name = reader.ReadString();
  609. footer.Id = reader.ReadInt32();
  610. posEnd = stream.Position;
  611. progressPosition = stream.Position;
  612. }
  613. public Int16[,] ReadAndProcessWorld(String worldPath, BackgroundWorker worker)
  614. {
  615. Int16[,] retTiles;
  616. byte wallType;
  617. Timer t = null;
  618. try
  619. {
  620. if (worker != null)
  621. {
  622. bw = worker;
  623. progressPosition = 0;
  624. t = new Timer(333);
  625. t.Elapsed += new ElapsedEventHandler(timer_ReadWorld);
  626. t.Start();
  627. }
  628. if (SettingsManager.Instance.ShowChestTypes == true)
  629. chestTypeList = new Dictionary<Point, ChestType>();
  630. else
  631. chestTypeList = null;
  632. readWorldPerc = 45;
  633. stream = new FileStream(worldPath, FileMode.Open, FileAccess.Read);
  634. reader = new BinaryReader(stream,Encoding.Default);
  635. ReadHeader();
  636. MaxX = header.MaxTiles.X;
  637. MaxY = header.MaxTiles.Y;
  638. // Reset MapTile List
  639. retTiles = new Int16[MaxX, MaxY];
  640. // WorldFile wf = new WorldFile();
  641. if (bw != null)
  642. bw.ReportProgress(0, "Reading and Processing Tiles");
  643. byte firstHeader, secondHeader, thirdHeader = 0;
  644. short ntileType = TileProperties.BackgroundOffset;
  645. // reader.BaseStream.Seek(sectionPointers[1],SeekOrigin.Begin);
  646. int run = 0;
  647. chestTypeList = new Dictionary<Point, ChestType>();
  648. for (int ncolumn = 0; ncolumn < header.MaxTiles.X; ncolumn++)
  649. {
  650. for (int nrow = 0; nrow < header.MaxTiles.Y; nrow++)
  651. {
  652. if (run > 0)
  653. {
  654. retTiles[ncolumn, nrow] = ntileType;
  655. run--;
  656. continue;
  657. }
  658. if (nrow < header.SurfaceLevel)
  659. ntileType = TileProperties.BackgroundOffset;
  660. else if (nrow == header.SurfaceLevel)
  661. ntileType = (Int16)(TileProperties.BackgroundOffset + 1); // Dirt Transition
  662. else if (nrow < (header.RockLayer + 38))
  663. ntileType = (Int16)(TileProperties.BackgroundOffset + 2); // Dirt
  664. else if (nrow == (header.RockLayer + 38))
  665. ntileType = (Int16)(TileProperties.BackgroundOffset + 4); // Rock Transition
  666. else if (nrow < (header.MaxTiles.Y - 202))
  667. ntileType = (Int16)(TileProperties.BackgroundOffset + 3); // Rock
  668. else if (nrow == (header.MaxTiles.Y - 202))
  669. ntileType = (Int16)(TileProperties.BackgroundOffset + 6); // Underworld Transition
  670. else
  671. ntileType = (Int16)(TileProperties.BackgroundOffset + 5); // Underworld
  672. secondHeader = 0;
  673. thirdHeader = 0;
  674. firstHeader = reader.ReadByte();
  675. if ((firstHeader & 1) == 1)
  676. {
  677. secondHeader = reader.ReadByte();
  678. if((secondHeader & 1) == 1)
  679. thirdHeader = reader.ReadByte();
  680. }
  681. if ((firstHeader & 2) == 2)
  682. {
  683. if((firstHeader & 32) == 32)
  684. ntileType = reader.ReadInt16();
  685. else
  686. ntileType = reader.ReadByte();
  687. if (tileImportant[ntileType])
  688. {
  689. var typeX = reader.ReadInt16();
  690. var typeY = reader.ReadInt16();
  691. if (ntileType == TileProperties.ExposedGems)
  692. {
  693. if (typeX == 0)
  694. ntileType = TileProperties.Amethyst;
  695. else if (typeX == 18)
  696. ntileType = TileProperties.Topaz;
  697. else if (typeX == 36)
  698. ntileType = TileProperties.Sapphire;
  699. else if (typeX == 54)
  700. ntileType = TileProperties.Emerald;
  701. else if (typeX == 72)
  702. ntileType = TileProperties.Ruby;
  703. else if (typeX == 90)
  704. ntileType = TileProperties.Diamond;
  705. else if (typeX == 108)
  706. ntileType = TileProperties.ExposedGems;
  707. // If it's 108 we keep it as ExposedGems so it get the Amber marker.
  708. }
  709. else if (ntileType == TileProperties.SmallDetritus)
  710. {
  711. if ((typeX % 36 == 0) && (typeY == 18))
  712. {
  713. int type = typeX / 36;
  714. if (type == 16)
  715. ntileType = TileProperties.CopperCache;
  716. else if (type == 17)
  717. ntileType = TileProperties.SilverCache;
  718. else if (type == 18)
  719. ntileType = TileProperties.GoldCache;
  720. else if (type == 19)
  721. ntileType = TileProperties.Amethyst;
  722. else if (type == 20)
  723. ntileType = TileProperties.Topaz;
  724. else if (type == 21)
  725. ntileType = TileProperties.Sapphire;
  726. else if (type == 22)
  727. ntileType = TileProperties.Emerald;
  728. else if (type == 23)
  729. ntileType = TileProperties.Ruby;
  730. else if (type == 24)
  731. ntileType = TileProperties.Diamond;
  732. }
  733. }
  734. else if (ntileType == TileProperties.LargeDetritus)
  735. {
  736. if ((typeX % 54 == 0) && (typeY == 0))
  737. {
  738. int type = typeX / 54;
  739. if (type == 16 || type == 17)
  740. ntileType = TileProperties.CopperCache;
  741. else if (type == 18 || type == 19)
  742. ntileType = TileProperties.SilverCache;
  743. else if (type == 20 || type == 21)
  744. ntileType = TileProperties.GoldCache;
  745. }
  746. }
  747. else if (ntileType == TileProperties.LargeDetritus2)
  748. {
  749. if ((typeX % 54 == 0) && (typeY == 0))
  750. {
  751. int type = typeX / 54;
  752. if (type == 17)
  753. ntileType = TileProperties.EnchantedSword;
  754. }
  755. }
  756. if ((ntileType == TileProperties.Chest) && (typeX % 36 == 0) && (typeY == 0))
  757. {
  758. if ((typeX / 36) <= (Int32)ChestType.LockedFrozenChest)
  759. chestTypeList.Add(new Point(ncolumn, nrow), (ChestType)(typeX / 36));
  760. else
  761. chestTypeList.Add(new Point(ncolumn, nrow), ChestType.Unknown);
  762. }
  763. }
  764. if ((thirdHeader & 8) == 8)
  765. reader.ReadByte();
  766. }
  767. if ((firstHeader & 4) == 4)
  768. {
  769. wallType = reader.ReadByte();
  770. if (ntileType >= TileProperties.Unknown)
  771. ntileType = (Int16)(wallType + TileProperties.WallOffset);
  772. if ((thirdHeader & 16) == 16)
  773. reader.ReadByte();
  774. }
  775. if ((firstHeader & 8) == 8)
  776. {
  777. ntileType = TileProperties.Water;
  778. reader.ReadByte();
  779. }
  780. else if ((firstHeader & 16) == 16)
  781. {
  782. ntileType = TileProperties.Lava;
  783. reader.ReadByte();
  784. }
  785. if ((firstHeader & 64) == 64)
  786. {
  787. run = reader.ReadByte();
  788. }
  789. if ((firstHeader & 128) == 128)
  790. run = reader.ReadInt16();
  791. retTiles[ncolumn, nrow] = ntileType;
  792. }
  793. }
  794. // reader.BaseStream.Seek(sectionPointers[2], SeekOrigin.Begin);
  795. ReadChests();
  796. ReadSigns();
  797. ReadNPCs();
  798. //ReadNPCNames();
  799. ReadFooter();
  800. }
  801. catch (Exception e)
  802. {
  803. if (bw != null)
  804. {
  805. t.Stop();
  806. bw = null;
  807. }
  808. reader.Close();
  809. retTiles = null;
  810. throw e;
  811. }
  812. if (bw != null)
  813. {
  814. t.Stop();
  815. bw = null;
  816. }
  817. reader.Close();
  818. return retTiles;
  819. }
  820. private void ScanPastWorldTiles()
  821. {
  822. Boolean theB;
  823. Byte theI;
  824. Int32 i, j;
  825. Int16 RLE = 0;
  826. if (bw != null)
  827. bw.ReportProgress((Int32)(((Single)progressPosition / stream.Length) * readWorldPerc)
  828. , "Skipping Tiles");
  829. if (header.ReleaseNumber < 0x24)
  830. {
  831. for (i = 0; i < MaxX; i++)
  832. {
  833. for (j = 0; j < MaxY; j++)
  834. {
  835. theB = reader.ReadBoolean();
  836. if (theB == true)
  837. {
  838. theI = reader.ReadByte();
  839. if (tileImportant[theI] == true)
  840. {
  841. reader.ReadInt16();
  842. reader.ReadInt16();
  843. }
  844. }
  845. reader.ReadBoolean();
  846. theB = reader.ReadBoolean();
  847. if (theB == true)
  848. reader.ReadByte();
  849. theB = reader.ReadBoolean();
  850. if (theB == true)
  851. {
  852. reader.ReadByte();
  853. reader.ReadBoolean();
  854. }
  855. }
  856. progressPosition = stream.Position;
  857. }
  858. }
  859. else
  860. {
  861. for (i = 0; i < MaxX; i++)
  862. {
  863. for (j = 0; j < MaxY; j++)
  864. {
  865. if (RLE == 0)
  866. {
  867. theB = reader.ReadBoolean();
  868. if (theB == true)
  869. {
  870. theI = reader.ReadByte();
  871. if (tileImportant[theI] == true)
  872. {
  873. reader.ReadInt16();
  874. reader.ReadInt16();
  875. }
  876. }
  877. theB = reader.ReadBoolean();
  878. if (theB == true)
  879. reader.ReadByte();
  880. theB = reader.ReadBoolean();
  881. if (theB == true)
  882. {
  883. reader.ReadByte();
  884. reader.ReadBoolean();
  885. }
  886. reader.ReadBoolean();
  887. RLE = reader.ReadInt16();
  888. }
  889. else
  890. {
  891. RLE--;
  892. }
  893. }
  894. progressPosition = stream.Position;
  895. }
  896. }
  897. posChests = stream.Position;
  898. }
  899. // This is used to get only the chests from the file. For the LoadInformation button.
  900. public List<Chest> GetChests(String world, BackgroundWorker worker = null)
  901. {
  902. Timer t = null;
  903. if (worker != null)
  904. {
  905. bw = worker;
  906. t = new Timer(333);
  907. t.Elapsed += new ElapsedEventHandler(timer_ReadWorld);
  908. t.Start();
  909. progressPosition = 0;
  910. }
  911. readWorldPerc = 100;
  912. stream = new FileStream(world, FileMode.Open, FileAccess.Read);
  913. reader = new BinaryReader(stream);
  914. #if (DEBUG == false)
  915. try
  916. {
  917. #endif
  918. ReadHeader();
  919. posChests = new BackwardsScanner(stream, header).SeekToChestsBackwards();
  920. if (posChests != 0)
  921. {
  922. ReadChests();
  923. }
  924. else
  925. {
  926. stream.Seek(posTiles, SeekOrigin.Begin);
  927. ScanPastWorldTiles();
  928. ReadChests();
  929. }
  930. #if (DEBUG == false)
  931. }
  932. catch (Exception e)
  933. {
  934. if (bw != null)
  935. {
  936. t.Stop();
  937. bw = null;
  938. }
  939. throw e;
  940. }
  941. #endif
  942. reader.Close();
  943. if (bw != null)
  944. {
  945. t.Stop();
  946. bw = null;
  947. }
  948. reader.Close();
  949. return chests;
  950. }
  951. #endregion
  952. #region SaveFunctions
  953. public void SaveWorld(String world)
  954. {
  955. FileStream stream = new FileStream(world, FileMode.Create, FileAccess.Write);
  956. BinaryWriter writer = new BinaryWriter(stream);
  957. SaveHeader(writer);
  958. SaveWorldTiles(writer);
  959. SaveChests(writer);
  960. SaveSigns(writer);
  961. SaveNPCs(writer);
  962. SaveFooter(writer);
  963. writer.Close();
  964. }
  965. private void SaveHeader(BinaryWriter writer)
  966. {
  967. writer.Write(header.ReleaseNumber);
  968. writer.Write(header.Name);
  969. writer.Write(header.Id);
  970. writer.Write(header.WorldCoords.TopLeft.X);
  971. writer.Write(header.WorldCoords.TopLeft.Y);
  972. writer.Write(header.WorldCoords.BottomRight.X);
  973. writer.Write(header.WorldCoords.BottomRight.Y);
  974. writer.Write(header.MaxTiles.Y);
  975. writer.Write(header.MaxTiles.X);
  976. writer.Write(header.SpawnPoint.X);
  977. writer.Write(header.SpawnPoint.Y);
  978. writer.Write(header.SurfaceLevel);
  979. writer.Write(header.RockLayer);
  980. writer.Write(header.TemporaryTime);
  981. writer.Write(header.IsDayTime);
  982. writer.Write(header.MoonPhase);
  983. writer.Write(header.IsBloodMoon);
  984. writer.Write(header.DungeonPoint.X);
  985. writer.Write(header.DungeonPoint.Y);
  986. writer.Write(header.IsBoss1Dead);
  987. writer.Write(header.IsBoss2Dead);
  988. writer.Write(header.IsBoss3Dead);
  989. writer.Write(header.IsShadowOrbSmashed);
  990. writer.Write(header.IsMeteorSpawned);
  991. writer.Write(header.ShadowOrbsSmashed);
  992. writer.Write(header.InvasionDelay);
  993. writer.Write(header.InvasionSize);
  994. writer.Write(header.InvasionType);
  995. writer.Write(header.InvasionPointX);
  996. }
  997. private void SaveWorldTiles(BinaryWriter writer)
  998. {
  999. Tile theTile;
  1000. Int32 i, j;
  1001. for (i = 0; i < MaxX; i++)
  1002. {
  1003. for (j = 0; j < MaxY; j++)
  1004. {
  1005. theTile = tiles[i, j];
  1006. writer.Write(theTile.Active);
  1007. if (theTile.Active)
  1008. {
  1009. writer.Write(theTile.TileType);
  1010. if (tileImportant[theTile.TileType] == true)
  1011. {
  1012. writer.Write(theTile.Frame.X);
  1013. writer.Write(theTile.Frame.Y);
  1014. }
  1015. }
  1016. writer.Write(theTile.Wall);
  1017. if (theTile.Wall)
  1018. writer.Write(theTile.WallType);
  1019. if (theTile.LiquidLevel > 0)
  1020. {
  1021. writer.Write(true);
  1022. writer.Write(theTile.LiquidLevel);
  1023. writer.Write(theTile.Lava);
  1024. }
  1025. else
  1026. {
  1027. writer.Write(false);
  1028. }
  1029. }
  1030. }
  1031. }
  1032. private void SaveChests(BinaryWriter writer)
  1033. {
  1034. Chest nextChest;
  1035. Item nextItem;
  1036. Int32 i, j;
  1037. List<Item>.Enumerator iEnum;
  1038. List<Chest>.Enumerator cEnum;
  1039. cEnum = chests.GetEnumerator();
  1040. cEnum.MoveNext();
  1041. nextChest = cEnum.Current;
  1042. for (i = 0; i < 1000; i++)
  1043. {
  1044. if (nextChest != null && i == nextChest.ChestId)
  1045. {
  1046. writer.Write(nextChest.Active);
  1047. writer.Write(nextChest.Coordinates.X);
  1048. writer.Write(nextChest.Coordinates.Y);
  1049. iEnum = nextChest.Items.GetEnumerator();
  1050. iEnum.MoveNext();
  1051. nextItem = iEnum.Current;
  1052. for (j = 0; j < 20; j++)
  1053. {
  1054. if (nextItem != null && j == nextItem.Id)
  1055. {
  1056. writer.Write(nextItem.Count);
  1057. writer.Write(nextItem.Name);
  1058. iEnum.MoveNext();
  1059. nextItem = iEnum.Current;
  1060. }
  1061. else
  1062. {
  1063. writer.Write((Int16)0);
  1064. }
  1065. }
  1066. cEnum.MoveNext();
  1067. nextChest = cEnum.Current;
  1068. }
  1069. else
  1070. {
  1071. writer.Write(false);
  1072. }
  1073. }
  1074. }
  1075. private void SaveSigns(BinaryWriter writer)
  1076. {
  1077. Sign theSign;
  1078. Int32 i;
  1079. for (i = 0; i < 1000; i++)
  1080. {
  1081. theSign = signs[i];
  1082. writer.Write(theSign.Active);
  1083. if (theSign.Active == true)
  1084. {
  1085. writer.Write(theSign.Text);
  1086. writer.Write(theSign.Position.X);
  1087. writer.Write(theSign.Position.Y);
  1088. }
  1089. }
  1090. }
  1091. private void SaveNPCs(BinaryWriter writer)
  1092. {
  1093. Int32 i = 0;
  1094. NPC theNPC = npcs[i];
  1095. while (theNPC != null)
  1096. {
  1097. writer.Write(theNPC.Active);
  1098. writer.Write(theNPC.Name);
  1099. writer.Write(theNPC.Position.X);
  1100. writer.Write(theNPC.Position.Y);
  1101. writer.Write(theNPC.Homeless);
  1102. writer.Write(theNPC.HomeTile.X);
  1103. writer.Write(theNPC.HomeTile.Y);
  1104. i++;
  1105. theNPC = npcs[i];
  1106. }
  1107. writer.Write(false);
  1108. }
  1109. private void SaveFooter(BinaryWriter writer)
  1110. {
  1111. writer.Write(footer.Active);
  1112. writer.Write(footer.Name);
  1113. writer.Write(footer.Id);
  1114. }
  1115. #endregion
  1116. #region ScanningFunctions
  1117. // Helper function to help parse through the world loading a tile run at a time.
  1118. // Lots of bounds checking to make sure we catch when the first errors happen.
  1119. // Designed for 1.2.0.1
  1120. public bool SanityCheckWorld(String world)
  1121. {
  1122. String error;
  1123. int strictbool;
  1124. int i,j;
  1125. String byteStringOld;
  1126. byte[] byteStreamOld;
  1127. int byteStreamOldLength;
  1128. String byteString;
  1129. byte[] byteStream;
  1130. int byteStreamPos;
  1131. Tile curTile = new Tile();
  1132. int RLEValue;
  1133. byteStream = new byte[40];
  1134. byteStreamPos = 0;
  1135. byteStreamOld = new byte[40];
  1136. byteStreamOldLength = 0;
  1137. Int32 tilesRead = 0;
  1138. stream = new FileStream(world, FileMode.Open, FileAccess.Read);
  1139. reader = new BinaryReader(stream);
  1140. ReadHeader();
  1141. RLEValue = 0;
  1142. for (i = 0; i < MaxX; i++)
  1143. {
  1144. for (j = 0; j < MaxY; j++)
  1145. {
  1146. if (RLEValue == 0)
  1147. {
  1148. if (tilesRead == 1773)
  1149. tilesRead = 1773;
  1150. byteStreamPos = 0;
  1151. curTile.Reset();
  1152. strictbool = reader.ReadByte();
  1153. byteStream[byteStreamPos] = (byte)strictbool;
  1154. byteStreamPos++;
  1155. if (strictbool > 1)
  1156. {
  1157. error = String.Format("Failed on the Activate Boolean read: 0x{1:X2}", (byte)strictbool);
  1158. }
  1159. curTile.Active = (strictbool == 0) ? false : true;
  1160. if (curTile.Active)
  1161. {
  1162. curTile.TileType = reader.ReadByte();
  1163. byteStream[byteStreamPos] = curTile.TileType;
  1164. byteStreamPos++;
  1165. if (curTile.TileType >= TileProperties.Unknown)
  1166. {
  1167. error = String.Format("Failed on the TileType Byte read: 0x{1:X2}", curTile.TileType);
  1168. }
  1169. if (Global.Instance.Info.Tiles[(int)curTile.TileType].colorName == "FindImportant")
  1170. {
  1171. error = String.Format("TileType {0} has unknown importance.", curTile.TileType);
  1172. }
  1173. if (TileProperties.tileTypeDefs[curTile.TileType].IsImportant)
  1174. {
  1175. curTile.Important = true;
  1176. PointInt16 p = curTile.Frame;
  1177. p.X = reader.ReadInt16();
  1178. byteStream[byteStreamPos] = (byte)(p.X & 0xFF);
  1179. byteStreamPos++;
  1180. byteStream[byteStreamPos] = (byte)((p.X & 0xFF00) >> 8);
  1181. byteStreamPos++;
  1182. p.Y = reader.ReadInt16();
  1183. byteStream[byteStreamPos] = (byte)(p.Y & 0xFF);
  1184. byteStreamPos++;
  1185. byteStream[byteStreamPos] = (byte)((p.Y & 0xFF00) >> 8);
  1186. byteStreamPos++;
  1187. curTile.Frame = p;
  1188. }
  1189. else
  1190. {
  1191. curTile.Important = false;
  1192. }
  1193. strictbool = reader.ReadByte();
  1194. byteStream[byteStreamPos] = (byte)strictbool;
  1195. byteStreamPos++;
  1196. if (strictbool > 1)
  1197. {
  1198. error = String.Format("Failed on the Tile Color Boolean read: 0x{0:X2}", (byte)strictbool);
  1199. }
  1200. if (strictbool >= 1)
  1201. {
  1202. curTile.TileColor = reader.ReadByte();
  1203. byteStream[byteStreamPos] = curTile.TileColor;
  1204. byteStreamPos++;
  1205. if (curTile.TileColor == 0)
  1206. {
  1207. error = String.Format("Failed on the Tile Color Byte read: 0x{0:X2}", curTile.TileColor);
  1208. }
  1209. }
  1210. }
  1211. strictbool = reader.ReadByte();
  1212. byteStream[byteStreamPos] = (byte)(strictbool);
  1213. byteStreamPos++;
  1214. if (strictbool > 1)
  1215. {
  1216. error = String.Format("Failed in the Wall Active Boolean read: 0x{0:X2}", (byte)strictbool);
  1217. }
  1218. if (strictbool >= 1)
  1219. {
  1220. curTile.WallType = reader.ReadByte();
  1221. byteStream[byteStreamPos] = curTile.WallType;
  1222. byteStreamPos++;
  1223. if (curTile.WallType == 0 || curTile.WallType > Global.Instance.Info.Walls.Count)
  1224. {
  1225. error = String.Format("Failed in the Wall Type Byte read: 0x{0:X2}", curTile.WallType);
  1226. }
  1227. strictbool = reader.ReadByte();
  1228. byteStream[byteStreamPos] = (byte)(strictbool);
  1229. byteStreamPos++;
  1230. if (strictbool > 1)
  1231. {
  1232. error = String.Format("Failed in the Wall Color Boolean read: 0x{0:X2}", (byte)strictbool);
  1233. }
  1234. if (strictbool >= 1)
  1235. {
  1236. curTile.WallColor = reader.ReadByte();
  1237. byteStream[byteStreamPos] = curTile.WallColor;
  1238. byteStreamPos++;
  1239. if (curTile.WallColor == 0)
  1240. {
  1241. error = String.Format("Failed in the Wall Color Byte read: 0x{0:X2}", (byte)strictbool);
  1242. }
  1243. }
  1244. }
  1245. strictbool = reader.ReadByte();
  1246. byteStream[byteStreamPos] = (byte)(strictbool);
  1247. byteStreamPos++;
  1248. if (strictbool > 1)
  1249. {
  1250. error = String.Format("Failed in the Liquid Active Boolean read: 0x{0:X2}", (byte)strictbool);
  1251. }
  1252. if (strictbool >= 1)
  1253. {
  1254. curTile.LiquidLevel = reader.ReadByte();
  1255. byteStream[byteStreamPos] = curTile.LiquidLevel;
  1256. byteStreamPos++;
  1257. strictbool = reader.ReadByte();
  1258. byteStream[byteStreamPos] = (byte)(strictbool);
  1259. byteStreamPos++;
  1260. if (strictbool > 1)
  1261. {
  1262. error = String.Format("Failed in the IsLava Boolean read: 0x{0:X2}", (byte)strictbool);
  1263. }
  1264. curTile.Lava = (strictbool == 0) ? false : true;
  1265. strictbool = reader.ReadByte();
  1266. byteStream[byteStreamPos] = (byte)(strictbool);
  1267. byteStreamPos++;
  1268. if (strictbool > 1)
  1269. {
  1270. error = String.Format("Failed in the IsHoney Boolean read: 0x{0:X2}", (byte)strictbool);
  1271. }
  1272. curTile.Honey = (strictbool == 0) ? false : true;
  1273. }
  1274. strictbool = reader.ReadByte();
  1275. byteStream[byteStreamPos] = (byte)(strictbool);
  1276. byteStreamPos++;
  1277. if (strictbool > 1)
  1278. {
  1279. error = String.Format("Failed in the Red Wire Boolean read: 0x{0:X2}", (byte)strictbool);
  1280. }
  1281. curTile.RedWire = (strictbool == 0) ? false : true;
  1282. strictbool = reader.ReadByte();
  1283. byteStream[byteStreamPos] = (byte)(strictbool);
  1284. byteStreamPos++;
  1285. if (strictbool > 1)
  1286. {
  1287. error = String.Format("Failed in the Blue Wire Boolean read: 0x{0:X2}", (byte)strictbool);
  1288. }
  1289. curTile.BlueWire = (strictbool == 0) ? false : true;
  1290. strictbool = reader.ReadByte();
  1291. byteStream[byteStreamPos] = (byte)(strictbool);
  1292. byteStreamPos++;
  1293. if (strictbool > 1)
  1294. {
  1295. error = String.Format("Failed in the Halftile Boolean read: 0x{0:X2}", (byte)strictbool);
  1296. }
  1297. curTile.GreenWire = (strictbool == 0) ? false : true;
  1298. strictbool = reader.ReadByte();
  1299. byteStream[byteStreamPos] = (byte)(strictbool);
  1300. byteStreamPos++;
  1301. if (strictbool > 1)
  1302. {
  1303. error = String.Format("Failed in the Halftile Boolean read: 0x{0:X2}", (byte)strictbool);
  1304. }
  1305. curTile.Halftile = (strictbool == 0) ? false : true;
  1306. curTile.Slope = reader.ReadByte();
  1307. strictbool = reader.ReadByte();
  1308. byteStream[byteStreamPos] = (byte)(strictbool);
  1309. byteStreamPos++;
  1310. if (strictbool > 1)
  1311. {
  1312. error = String.Format("Failed in the Actuator Boolean read: 0x{0:X2}", (byte)strictbool);
  1313. }
  1314. curTile.Actuator = (strictbool == 0) ? false : true;
  1315. strictbool = reader.ReadByte();
  1316. byteStream[byteStreamPos] = (byte)(strictbool);
  1317. byteStreamPos++;
  1318. if (strictbool > 1)
  1319. {
  1320. error = String.Format("Failed in the Inactive Boolean read: 0x{0:X2}", (byte)strictbool);
  1321. }
  1322. curTile.Inactive = (strictbool == 0) ? false : true;
  1323. RLEValue = reader.ReadInt16();
  1324. byteStream[byteStreamPos] = (byte)(RLEValue & 0xFF);
  1325. byteStreamPos++;
  1326. byteStream[byteStreamPos] = (byte)((RLEValue & 0xFF00) >> 8);
  1327. byteStreamPos++;
  1328. for (int k = byteStreamPos; k < byteStream.Length; k++)
  1329. byteStream[k] = 0;
  1330. for (int k = 0; k < byteStream.Length; k++)
  1331. byteStreamOld[k] = byteStream[k];
  1332. byteStreamOldLength = byteStreamPos;
  1333. byteString = "";
  1334. for (int k = 0; k < byteStreamPos; k++)
  1335. byteString = byteString + String.Format("{0:X2} ", byteStream[k]);
  1336. byteStringOld = byteString;
  1337. tilesRead++;
  1338. }
  1339. else
  1340. {
  1341. RLEValue--;
  1342. continue;
  1343. }
  1344. }
  1345. }
  1346. ReadChests();
  1347. ReadSigns();
  1348. ReadNPCs();
  1349. ReadNPCNames();
  1350. ReadFooter();
  1351. return true;
  1352. }
  1353. // Ok so this is how this works.
  1354. // It starts out by walking the file backwards to find the ending offset.
  1355. // It then sets up the original path and starts scanning along the tiles.
  1356. // When it finds an unknown tile type the program duplicates the current
  1357. // path and makes one follow the path of it being non-important while
  1358. // the other follows the path of being important.
  1359. // When a path turns out not to fit the data it gets removed from the list.
  1360. // All paths get checked in parallel.
  1361. public TileImportance[] ScanWorld(String world, BackgroundWorker worker = null)
  1362. {
  1363. Timer t = null;
  1364. TileImportance[] retList;
  1365. if (worker != null)
  1366. {
  1367. bw = worker;
  1368. t = new Timer(333);
  1369. t.Elapsed += new ElapsedEventHandler(timer_ScanWorld);
  1370. t.Enabled = true;
  1371. t.Start();
  1372. }
  1373. stream = new FileStream(world, FileMode.Open, FileAccess.Read);
  1374. reader = new BinaryReader(stream);
  1375. buffReader = new BufferedBinaryReader(stream, 5000, 1000);
  1376. posChests = new BackwardsScanner(stream, header).SeekToChestsBackwards();
  1377. stream.Seek(0, SeekOrigin.Begin);
  1378. ReadHeader();
  1379. retList = ScanWorldTiles();
  1380. if (bw != null)
  1381. {
  1382. t.Stop();
  1383. bw = null;
  1384. }
  1385. reader.Close();
  1386. return retList;
  1387. }
  1388. private void timer_ScanWorld(object sender, ElapsedEventArgs e)
  1389. {
  1390. bw.ReportProgress(progress);
  1391. }
  1392. private TileImportance[] ScanWorldTiles()
  1393. {
  1394. Byte tryByte;
  1395. Byte tileType;
  1396. Tile curTile;
  1397. Int32 i, j, k;
  1398. tileReader curReader;
  1399. tileReader splitReader;
  1400. TileImportance curList;
  1401. TileImportance[] returnList;
  1402. List<tileReader> readerList = new List<tileReader>();
  1403. buffReader.Seek(stream.Position);
  1404. // We set up the lookup we can change here and we'll simply change it.
  1405. // We might not even need this lookup at all. Work the logic later.
  1406. curReader = new tileReader(stream.Position);
  1407. curReader.startAt = new Point(0, 0);
  1408. curReader.splitAt = 255;
  1409. curList = curReader.tileLookup;
  1410. curTile = curReader.tile;
  1411. readerList.Add(curReader);
  1412. for (i = 0; i < MaxX; i++)
  1413. {
  1414. progress = (Int32)(((i * MaxY) / (double)(MaxX * MaxY)) * 100);
  1415. for (j = 0; j < MaxY; j++)
  1416. {
  1417. // If somehow we manage to knock out every reader as bad then we need to quit.
  1418. if (readerList.Count == 0)
  1419. return null;
  1420. for (k = 0; k < readerList.Count; k++)
  1421. {
  1422. // No reason to keep resetting these if we only have one path going.
  1423. if (readerList.Count > 1)
  1424. {
  1425. curReader = readerList[k];
  1426. curList = curReader.tileLookup;
  1427. curTile = curReader.tile;
  1428. buffReader.Seek(curReader.filePos);
  1429. }
  1430. tryByte = buffReader.ReadByte();
  1431. if (tryByte > 1)
  1432. goto badPath;
  1433. if (tryByte == 1)
  1434. {
  1435. curTile.Active = true;
  1436. tileType = buffReader.ReadByte();
  1437. curTile.TileType = tileType;
  1438. if (curList.isKnown(tileType) == false)
  1439. {
  1440. // Here we need to split the lists.
  1441. curReader.tileOrder.Add(tileType);
  1442. curList.setKnown(tileType, true);
  1443. splitReader = new tileReader(curReader);
  1444. splitReader.startAt = new Point(i, j);
  1445. splitReader.splitAt = tileType;
  1446. curList.setImportant(tileType, false);
  1447. splitReader.tileLookup.setImportant(tileType, true);
  1448. readerList.Add(splitReader);
  1449. bw.ReportProgress(progress, String.Format("Split #{0} {1}", splitReader.id, readerList.Count));
  1450. curTile.Important = false;
  1451. }
  1452. else
  1453. {
  1454. curTile.Important = curList.isImportant(tileType);
  1455. }
  1456. }
  1457. else
  1458. {
  1459. curTile.Active = false;
  1460. curTile.Important = false;
  1461. }
  1462. if (curTile.Important == true)
  1463. {
  1464. curTile.Frame = new PointInt16(buffReader.ReadInt16(), buffReader.ReadInt16());
  1465. }
  1466. // isLighted
  1467. tryByte = buffReader.ReadByte();
  1468. if (tryByte > 1)
  1469. goto badPath;
  1470. // isWall
  1471. tryByte = buffReader.ReadByte();
  1472. if (tryByte > 1)
  1473. goto badPath;
  1474. if (tryByte == 1)
  1475. {
  1476. curTile.Wall = true;
  1477. // wallType
  1478. tryByte = buffReader.ReadByte();
  1479. // It turns out there will never be a wall type 0.
  1480. if (tryByte == 0)
  1481. goto badPath;
  1482. curTile.WallType = tryByte;
  1483. }
  1484. else
  1485. {
  1486. curTile.Wall = false;
  1487. }
  1488. // isWater
  1489. tryByte = buffReader.ReadByte();
  1490. if (tryByte > 1)
  1491. goto badPath;
  1492. if (tryByte == 1)
  1493. {
  1494. // waterLevel
  1495. tryByte = buffReader.ReadByte();
  1496. curTile.LiquidLevel = tryByte;
  1497. // We can have any water value besides zero, if the isWater bit is set.
  1498. if (tryByte == 0)
  1499. goto badPath;
  1500. // isLava
  1501. tryByte = buffReader.ReadByte();
  1502. if (tryByte > 1)
  1503. goto badPath;
  1504. if (tryByte == 1)
  1505. curTile.Lava = true;
  1506. else
  1507. curTile.Lava = false;
  1508. }
  1509. curReader.filePos = buffReader.Position;
  1510. // This path passed over the end of the tile range. Bad path.
  1511. // We might not always have a valid chest position though, if they
  1512. // have changed something in a new version.
  1513. if (posChests != 0 && curReader.filePos > posChests)
  1514. goto badPath;
  1515. curReader.tilesRead++;
  1516. continue;
  1517. badPath:
  1518. bw.ReportProgress(progress, String.Format("Path #{0} Terminated {1}", readerList[k].id, readerList.Count-1));
  1519. // Erase the bad path from the list to process.
  1520. readerList.RemoveAt(k);
  1521. // Now that we removed one we need to move the loop back one to
  1522. // compensate for how it shifts them over. Otherwise we could
  1523. // have a 0,1,2 then remove 1 which leaves 0,1 and our next
  1524. // loop is for 2 so the old 2 (new 1) gets skipped.
  1525. k--;
  1526. // If we took it back to one we'll need to set up for the next loop
  1527. // as we put the skip in to speed it up.
  1528. if (readerList.Count == 1)
  1529. {
  1530. curReader = readerList[0];
  1531. curList = curReader.tileLookup;
  1532. curTile = curReader.tile;
  1533. buffReader.Seek(curReader.filePos);
  1534. }
  1535. }
  1536. }
  1537. }
  1538. // Time to prep for the return.
  1539. returnList = new TileImportance[readerList.Count];
  1540. // Find the first one that matched up with the end of the tile position.
  1541. for (k = 0; k < readerList.Count; k++)
  1542. {
  1543. if (readerList[k].filePos == posChests)
  1544. break;
  1545. }
  1546. // Now generate the list but put the one that matched first, if one existed.
  1547. if (readerList.Count == k)
  1548. {
  1549. for (i = 0; i < readerList.Count; i++)
  1550. returnList[i] = readerList[i].tileLookup;
  1551. } else {
  1552. returnList[0] = readerList[k].tileLookup;
  1553. j = 1;
  1554. for (i = 0; i < readerList.Count; i++)
  1555. {
  1556. if (i != k)
  1557. {
  1558. returnList[j] = readerList[k].tileLookup;
  1559. j++;
  1560. }
  1561. }
  1562. }
  1563. //bw.ReportProgress(progress, String.Format("Path #{0} Terminated {1}", readerList[k].id, readerList.Count - 1));
  1564. return returnList;
  1565. }
  1566. #endregion
  1567. #region GetSet Functions
  1568. public WorldHeader Header
  1569. {
  1570. get
  1571. {
  1572. return header;
  1573. }
  1574. set
  1575. {
  1576. header = value;
  1577. }
  1578. }
  1579. public Dictionary<Point, ChestType> ChestTypeList
  1580. {
  1581. get
  1582. {
  1583. return chestTypeList;
  1584. }
  1585. set
  1586. {
  1587. this.chestTypeList = value;
  1588. }
  1589. }
  1590. public Tile[,] Tiles
  1591. {
  1592. get
  1593. {
  1594. return tiles;
  1595. }
  1596. }
  1597. public List<Chest> Chests
  1598. {
  1599. get
  1600. {
  1601. return chests;
  1602. }
  1603. set
  1604. {
  1605. this.chests = value;
  1606. }
  1607. }
  1608. public List<Sign> Signs
  1609. {
  1610. get
  1611. {
  1612. return signs;
  1613. }
  1614. set
  1615. {
  1616. this.signs = value;
  1617. }
  1618. }
  1619. public List<NPC> Npcs
  1620. {
  1621. get
  1622. {
  1623. return npcs;
  1624. }
  1625. set
  1626. {
  1627. this.npcs = value;
  1628. }
  1629. }
  1630. public Footer Footer
  1631. {
  1632. get
  1633. {
  1634. return footer;
  1635. }
  1636. }
  1637. #endregion
  1638. public String GetWorldName(String worldFile)
  1639. {
  1640. String worldName;
  1641. String headerName;
  1642. int headerId;
  1643. try
  1644. {
  1645. stream = new FileStream(worldFile, FileMode.Open, FileAccess.Read);
  1646. reader = new BinaryReader(stream);
  1647. backReader = new BackwardsBinaryReader(stream);
  1648. }
  1649. catch (Exception e)
  1650. {
  1651. e.ToString();
  1652. return "Error loading worldname";
  1653. }
  1654. // Skip the release number.
  1655. reader.ReadInt32();
  1656. headerName = reader.ReadString();
  1657. headerId = reader.ReadInt32();
  1658. if (CompareFooter(headerName, headerId) == true)
  1659. worldName = headerName;
  1660. else
  1661. worldName = "Not a valid World file";
  1662. reader.Close();
  1663. return worldName;
  1664. }
  1665. private Boolean CompareFooter(String worldName, Int32 worldId)
  1666. {
  1667. Boolean returnVal = false;
  1668. long position = this.stream.Position;
  1669. this.stream.Seek(0, SeekOrigin.End);
  1670. #if (DEBUG == false)
  1671. try
  1672. {
  1673. #endif
  1674. footer = new Footer();
  1675. footer.Id = backReader.ReadBackwardsInt32();
  1676. footer.Name = backReader.ReadBackwardsString();
  1677. footer.Active = backReader.ReadBackwardsBoolean();
  1678. if (footer.Active == true && footer.Name == worldName && footer.Id == worldId)
  1679. returnVal = true;
  1680. #if (DEBUG == false)
  1681. }
  1682. catch (EndOfStreamException e)
  1683. {
  1684. // We don't need to do this but I do just so the compiler will not throw an warning
  1685. // for never using it.
  1686. e.GetType();
  1687. // If we read past the end of the stream we know it did not match.
  1688. returnVal = false;
  1689. }
  1690. #endif
  1691. // We set the position back to where it was when we were called.
  1692. this.stream.Seek(position, SeekOrigin.Begin);
  1693. return returnVal;
  1694. }
  1695. }
  1696. }