PageRenderTime 64ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/CoreNew/Server/World.cs

https://bitbucket.org/Kel/crepuscule
C# | 1320 lines | 1033 code | 259 blank | 28 comment | 153 complexity | 8df4ca61b90d69e09a9ae0cb24fac75f MD5 | raw file
  1. /***************************************************************************
  2. * World.cs
  3. * -------------------
  4. * begin : May 1, 2002
  5. * copyright : (C) The RunUO Software Team
  6. * email : info@runuo.com
  7. *
  8. * $Id: World.cs,v 1.4 2005/01/22 04:25:04 krrios Exp $
  9. * $Author: krrios $
  10. * $Date: 2005/01/22 04:25:04 $
  11. *
  12. *
  13. ***************************************************************************/
  14. /***************************************************************************
  15. *
  16. * This program is free software; you can redistribute it and/or modify
  17. * it under the terms of the GNU General Public License as published by
  18. * the Free Software Foundation; either version 2 of the License, or
  19. * (at your option) any later version.
  20. *
  21. ***************************************************************************/
  22. using System;
  23. using System.IO;
  24. using System.Collections;
  25. using System.Reflection;
  26. using System.Threading;
  27. using Server;
  28. using Server.Mobiles;
  29. using Server.Accounting;
  30. using Server.Network;
  31. using Server.Guilds;
  32. namespace Server
  33. {
  34. public class World
  35. {
  36. public enum SaveOption
  37. {
  38. Normal,
  39. Threaded
  40. }
  41. public static SaveOption SaveType = SaveOption.Normal;
  42. private static Hashtable m_Mobiles;
  43. private static Hashtable m_Items;
  44. private static bool m_Loading;
  45. private static bool m_Loaded;
  46. private static bool m_Saving;
  47. private static ArrayList m_DeleteList;
  48. public static bool Saving{ get { return m_Saving; } }
  49. public static bool Loaded{ get { return m_Loaded; } }
  50. public static bool Loading{ get { return m_Loading; } }
  51. private static string mobIdxPath = Path.Combine( "Saves/Mobiles/", "Mobiles.idx" );
  52. private static string mobTdbPath = Path.Combine( "Saves/Mobiles/", "Mobiles.tdb" );
  53. private static string mobBinPath = Path.Combine( "Saves/Mobiles/", "Mobiles.bin" );
  54. private static string itemIdxPath = Path.Combine( "Saves/Items/", "Items.idx" );
  55. private static string itemTdbPath = Path.Combine( "Saves/Items/", "Items.tdb" );
  56. private static string itemBinPath = Path.Combine( "Saves/Items/", "Items.bin" );
  57. private static string regionIdxPath = Path.Combine( "Saves/Regions/", "Regions.idx" );
  58. private static string regionBinPath = Path.Combine( "Saves/Regions/", "Regions.bin" );
  59. private static string guildIdxPath = Path.Combine( "Saves/Guilds/", "Guilds.idx" );
  60. private static string guildBinPath = Path.Combine( "Saves/Guilds/", "Guilds.bin" );
  61. //static World()
  62. //{
  63. // Load();
  64. //}
  65. public static Hashtable Mobiles
  66. {
  67. get
  68. {
  69. return m_Mobiles;
  70. }
  71. }
  72. public static Hashtable Items
  73. {
  74. get
  75. {
  76. return m_Items;
  77. }
  78. }
  79. public static bool OnDelete( object o )
  80. {
  81. if ( !m_Loading )
  82. return true;
  83. m_DeleteList.Add( o );
  84. return false;
  85. }
  86. public static void Broadcast( int hue, bool ascii, string text )
  87. {
  88. Packet p;
  89. if ( ascii )
  90. p = new AsciiMessage( Serial.MinusOne, -1, MessageType.Regular, hue, 3, "System", text );
  91. else
  92. p = new UnicodeMessage( Serial.MinusOne, -1, MessageType.Regular, hue, 3, "ENU", "System", text );
  93. var list = NetState.Instances;
  94. for ( int i = 0; i < list.Count; ++i )
  95. {
  96. if ( ((NetState)list[i]).Mobile != null )
  97. ((NetState)list[i]).Send( p );
  98. }
  99. NetState.FlushAll();
  100. }
  101. public static void Broadcast( int hue, bool ascii, string format, params object[] args )
  102. {
  103. Broadcast( hue, ascii, String.Format( format, args ) );
  104. }
  105. private interface IEntityEntry
  106. {
  107. Serial Serial{ get; }
  108. int TypeID{ get; }
  109. long Position{ get; }
  110. int Length{ get; }
  111. object Object{ get; }
  112. }
  113. private sealed class RegionEntry : IEntityEntry
  114. {
  115. private Region m_Region;
  116. private long m_Position;
  117. private int m_Length;
  118. public object Object
  119. {
  120. get
  121. {
  122. return m_Region;
  123. }
  124. }
  125. public Serial Serial
  126. {
  127. get
  128. {
  129. return m_Region == null ? 0 : m_Region.UId;
  130. }
  131. }
  132. public int TypeID
  133. {
  134. get
  135. {
  136. return 0;
  137. }
  138. }
  139. public long Position
  140. {
  141. get
  142. {
  143. return m_Position;
  144. }
  145. }
  146. public int Length
  147. {
  148. get
  149. {
  150. return m_Length;
  151. }
  152. }
  153. public RegionEntry( Region r, long pos, int length )
  154. {
  155. m_Region = r;
  156. m_Position = pos;
  157. m_Length = length;
  158. }
  159. }
  160. private sealed class GuildEntry : IEntityEntry
  161. {
  162. private BaseGuild m_Guild;
  163. private long m_Position;
  164. private int m_Length;
  165. public object Object
  166. {
  167. get
  168. {
  169. return m_Guild;
  170. }
  171. }
  172. public Serial Serial
  173. {
  174. get
  175. {
  176. return m_Guild == null ? 0 : m_Guild.Id;
  177. }
  178. }
  179. public int TypeID
  180. {
  181. get
  182. {
  183. return 0;
  184. }
  185. }
  186. public long Position
  187. {
  188. get
  189. {
  190. return m_Position;
  191. }
  192. }
  193. public int Length
  194. {
  195. get
  196. {
  197. return m_Length;
  198. }
  199. }
  200. public GuildEntry( BaseGuild g, long pos, int length )
  201. {
  202. m_Guild = g;
  203. m_Position = pos;
  204. m_Length = length;
  205. }
  206. }
  207. private sealed class ItemEntry : IEntityEntry
  208. {
  209. private Item m_Item;
  210. private int m_TypeID;
  211. private string m_TypeName;
  212. private long m_Position;
  213. private int m_Length;
  214. public object Object
  215. {
  216. get
  217. {
  218. return m_Item;
  219. }
  220. }
  221. public Serial Serial
  222. {
  223. get
  224. {
  225. return m_Item == null ? Serial.MinusOne : m_Item.Serial;
  226. }
  227. }
  228. public int TypeID
  229. {
  230. get
  231. {
  232. return m_TypeID;
  233. }
  234. }
  235. public string TypeName
  236. {
  237. get
  238. {
  239. return m_TypeName;
  240. }
  241. }
  242. public long Position
  243. {
  244. get
  245. {
  246. return m_Position;
  247. }
  248. }
  249. public int Length
  250. {
  251. get
  252. {
  253. return m_Length;
  254. }
  255. }
  256. public ItemEntry( Item item, int typeID, string typeName, long pos, int length )
  257. {
  258. m_Item = item;
  259. m_TypeID = typeID;
  260. m_TypeName = typeName;
  261. m_Position = pos;
  262. m_Length = length;
  263. }
  264. }
  265. private sealed class MobileEntry : IEntityEntry
  266. {
  267. private Mobile m_Mobile;
  268. private int m_TypeID;
  269. private string m_TypeName;
  270. private long m_Position;
  271. private int m_Length;
  272. public object Object
  273. {
  274. get
  275. {
  276. return m_Mobile;
  277. }
  278. }
  279. public Serial Serial
  280. {
  281. get
  282. {
  283. return m_Mobile == null ? Serial.MinusOne : m_Mobile.Serial;
  284. }
  285. }
  286. public int TypeID
  287. {
  288. get
  289. {
  290. return m_TypeID;
  291. }
  292. }
  293. public string TypeName
  294. {
  295. get
  296. {
  297. return m_TypeName;
  298. }
  299. }
  300. public long Position
  301. {
  302. get
  303. {
  304. return m_Position;
  305. }
  306. }
  307. public int Length
  308. {
  309. get
  310. {
  311. return m_Length;
  312. }
  313. }
  314. public MobileEntry( Mobile mobile, int typeID, string typeName, long pos, int length )
  315. {
  316. m_Mobile = mobile;
  317. m_TypeID = typeID;
  318. m_TypeName = typeName;
  319. m_Position = pos;
  320. m_Length = length;
  321. }
  322. }
  323. private static string m_LoadingType;
  324. public static string LoadingType
  325. {
  326. get{ return m_LoadingType; }
  327. }
  328. public static void Load()
  329. {
  330. if ( m_Loaded )
  331. return;
  332. EventSink.InvokeWorldPreload();
  333. bool deleteAll = false;
  334. m_Loaded = true;
  335. m_LoadingType = null;
  336. Console.Write( "World: Loading..." );
  337. DateTime start = DateTime.Now;
  338. m_Loading = true;
  339. m_DeleteList = new ArrayList();
  340. int mobileCount = 0, itemCount = 0, guildCount = 0, regionCount = 0;
  341. object[] ctorArgs = new object[1];
  342. Type[] ctorTypes = new Type[1]{ typeof( Serial ) };
  343. ArrayList items = new ArrayList();
  344. ArrayList mobiles = new ArrayList();
  345. ArrayList guilds = new ArrayList();
  346. ArrayList regions = new ArrayList();
  347. if ( File.Exists( mobIdxPath ) && File.Exists( mobTdbPath ) )
  348. {
  349. using ( FileStream idx = new FileStream( mobIdxPath, FileMode.Open, FileAccess.Read, FileShare.Read ) )
  350. {
  351. BinaryReader idxReader = new BinaryReader( idx );
  352. using ( FileStream tdb = new FileStream( mobTdbPath, FileMode.Open, FileAccess.Read, FileShare.Read ) )
  353. {
  354. BinaryReader tdbReader = new BinaryReader( tdb );
  355. int count = tdbReader.ReadInt32();
  356. ArrayList types = new ArrayList( count );
  357. for ( int i = 0; i < count; ++i )
  358. {
  359. string typeName = tdbReader.ReadString();
  360. Type t = ScriptCompiler.FindTypeByFullName( typeName );
  361. if ( t == null )
  362. {
  363. if (deleteAll)
  364. {
  365. types.Add(null);
  366. continue;
  367. }
  368. else
  369. {
  370. Console.WriteLine("failed");
  371. Console.WriteLine("Error: Type '{0}' was not found. Delete all of those types? (y/n). Press (a) to delete all types.", typeName);
  372. string reply = Console.ReadLine();
  373. if (reply == "y" || reply == "a")
  374. {
  375. if (reply == "a")
  376. deleteAll = true;
  377. types.Add(null);
  378. Console.Write("World: Loading...");
  379. continue;
  380. }
  381. Console.WriteLine("Types will not be deleted. An exception will be thrown when you press return");
  382. throw new Exception(String.Format("Bad type '{0}'", typeName));
  383. }
  384. }
  385. ConstructorInfo ctor = t.GetConstructor( ctorTypes );
  386. if ( ctor != null )
  387. {
  388. types.Add( new object[]{ ctor, null } );
  389. }
  390. else
  391. {
  392. throw new Exception( String.Format( "Type '{0}' does not have a serialization constructor", t ) );
  393. }
  394. }
  395. deleteAll = false;
  396. mobileCount = idxReader.ReadInt32();
  397. m_Mobiles = new Hashtable( mobileCount );
  398. for ( int i = 0; i < mobileCount; ++i )
  399. {
  400. int typeID = idxReader.ReadInt32();
  401. int serial = idxReader.ReadInt32();
  402. long pos = idxReader.ReadInt64();
  403. int length = idxReader.ReadInt32();
  404. object[] objs = (object[])types[typeID];
  405. if ( objs == null )
  406. continue;
  407. Mobile m = null;
  408. ConstructorInfo ctor = (ConstructorInfo)objs[0];
  409. string typeName = (string)objs[1];
  410. try
  411. {
  412. ctorArgs[0] = (Serial)serial;
  413. m = (Mobile)(ctor.Invoke( ctorArgs ));
  414. }
  415. catch
  416. {
  417. }
  418. if ( m != null )
  419. {
  420. mobiles.Add( new MobileEntry( m, typeID, typeName, pos, length ) );
  421. AddMobile( m );
  422. }
  423. }
  424. tdbReader.Close();
  425. }
  426. idxReader.Close();
  427. }
  428. }
  429. else
  430. {
  431. m_Mobiles = new Hashtable();
  432. }
  433. if ( File.Exists( itemIdxPath ) && File.Exists( itemTdbPath ) )
  434. {
  435. using ( FileStream idx = new FileStream( itemIdxPath, FileMode.Open, FileAccess.Read, FileShare.Read ) )
  436. {
  437. BinaryReader idxReader = new BinaryReader( idx );
  438. using ( FileStream tdb = new FileStream( itemTdbPath, FileMode.Open, FileAccess.Read, FileShare.Read ) )
  439. {
  440. BinaryReader tdbReader = new BinaryReader( tdb );
  441. int count = tdbReader.ReadInt32();
  442. ArrayList types = new ArrayList( count );
  443. for ( int i = 0; i < count; ++i )
  444. {
  445. string typeName = tdbReader.ReadString();
  446. Type t = ScriptCompiler.FindTypeByFullName( typeName );
  447. if ( t == null )
  448. {
  449. if (deleteAll)
  450. {
  451. types.Add(null);
  452. continue;
  453. }
  454. else
  455. {
  456. Console.WriteLine("failed");
  457. Console.WriteLine("Error: Type '{0}' was not found. Delete all of those types? (y/n). Press (a) to delete all types.", typeName);
  458. string reply = Console.ReadLine();
  459. if (reply == "y" || reply == "a")
  460. {
  461. if (reply == "a")
  462. deleteAll = true;
  463. types.Add(null);
  464. Console.Write("World: Loading...");
  465. continue;
  466. }
  467. Console.WriteLine("Types will not be deleted. An exception will be thrown when you press return");
  468. throw new Exception(String.Format("Bad type '{0}'", typeName));
  469. }
  470. }
  471. ConstructorInfo ctor = t.GetConstructor( ctorTypes );
  472. if ( ctor != null )
  473. {
  474. types.Add( new object[]{ ctor, typeName } );
  475. }
  476. else
  477. {
  478. throw new Exception( String.Format( "Type '{0}' does not have a serialization constructor", t ) );
  479. }
  480. }
  481. itemCount = idxReader.ReadInt32();
  482. m_Items = new Hashtable( itemCount );
  483. for ( int i = 0; i < itemCount; ++i )
  484. {
  485. int typeID = idxReader.ReadInt32();
  486. int serial = idxReader.ReadInt32();
  487. long pos = idxReader.ReadInt64();
  488. int length = idxReader.ReadInt32();
  489. object[] objs = (object[])types[typeID];
  490. if ( objs == null )
  491. continue;
  492. Item item = null;
  493. ConstructorInfo ctor = (ConstructorInfo)objs[0];
  494. string typeName = (string)objs[1];
  495. try
  496. {
  497. ctorArgs[0] = (Serial)serial;
  498. item = (Item)(ctor.Invoke( ctorArgs ));
  499. }
  500. catch
  501. {
  502. }
  503. if ( item != null )
  504. {
  505. items.Add( new ItemEntry( item, typeID, typeName, pos, length ) );
  506. AddItem( item );
  507. }
  508. }
  509. tdbReader.Close();
  510. }
  511. idxReader.Close();
  512. }
  513. }
  514. else
  515. {
  516. m_Items = new Hashtable();
  517. }
  518. if ( File.Exists( guildIdxPath ) )
  519. {
  520. using ( FileStream idx = new FileStream( guildIdxPath, FileMode.Open, FileAccess.Read, FileShare.Read ) )
  521. {
  522. BinaryReader idxReader = new BinaryReader( idx );
  523. guildCount = idxReader.ReadInt32();
  524. CreateGuildEventArgs createEventArgs = new CreateGuildEventArgs( -1 );
  525. for ( int i = 0; i < guildCount; ++i )
  526. {
  527. idxReader.ReadInt32();//no typeid for guilds
  528. int id = idxReader.ReadInt32();
  529. long pos = idxReader.ReadInt64();
  530. int length = idxReader.ReadInt32();
  531. createEventArgs.Id = id;
  532. BaseGuild guild = EventSink.InvokeCreateGuild( createEventArgs );//new Guild( id );
  533. if ( guild != null )
  534. guilds.Add( new GuildEntry( guild, pos, length ) );
  535. }
  536. idxReader.Close();
  537. }
  538. }
  539. if ( File.Exists( regionIdxPath ) )
  540. {
  541. using ( FileStream idx = new FileStream( regionIdxPath, FileMode.Open, FileAccess.Read, FileShare.Read ) )
  542. {
  543. BinaryReader idxReader = new BinaryReader( idx );
  544. regionCount = idxReader.ReadInt32();
  545. for ( int i = 0; i < regionCount; ++i )
  546. {
  547. int typeID = idxReader.ReadInt32();
  548. int serial = idxReader.ReadInt32();
  549. long pos = idxReader.ReadInt64();
  550. int length = idxReader.ReadInt32();
  551. Region r = Region.FindByUId( serial );
  552. if ( r != null )
  553. {
  554. regions.Add( new RegionEntry( r, pos, length ) );
  555. Region.AddRegion( r );
  556. regionCount++;
  557. }
  558. }
  559. idxReader.Close();
  560. }
  561. }
  562. bool failedMobiles = false, failedItems = false, failedGuilds = false, failedRegions = false;
  563. Type failedType = null;
  564. Serial failedSerial = Serial.Zero;
  565. Exception failed = null;
  566. int failedTypeID = 0;
  567. if ( File.Exists( mobBinPath ) )
  568. {
  569. using ( FileStream bin = new FileStream( mobBinPath, FileMode.Open, FileAccess.Read, FileShare.Read ) )
  570. {
  571. BinaryFileReader reader = new BinaryFileReader( new BinaryReader( bin ) );
  572. for ( int i = 0; i < mobiles.Count; ++i )
  573. {
  574. MobileEntry entry = (MobileEntry)mobiles[i];
  575. Mobile m = (Mobile)entry.Object;
  576. if ( m != null )
  577. {
  578. reader.Seek( entry.Position, SeekOrigin.Begin );
  579. try
  580. {
  581. m_LoadingType = entry.TypeName;
  582. m.Deserialize( reader );
  583. if ( reader.Position != (entry.Position + entry.Length) )
  584. throw new Exception( String.Format( "***** Bad serialize on {0} *****", m.GetType() ) );
  585. }
  586. catch ( Exception e )
  587. {
  588. mobiles.RemoveAt( i );
  589. failed = e;
  590. failedMobiles = true;
  591. failedType = m.GetType();
  592. failedTypeID = entry.TypeID;
  593. failedSerial = m.Serial;
  594. break;
  595. }
  596. }
  597. }
  598. reader.Close();
  599. }
  600. }
  601. if ( !failedMobiles && File.Exists( itemBinPath ) )
  602. {
  603. using ( FileStream bin = new FileStream( itemBinPath, FileMode.Open, FileAccess.Read, FileShare.Read ) )
  604. {
  605. BinaryFileReader reader = new BinaryFileReader( new BinaryReader( bin ) );
  606. for ( int i = 0; i < items.Count; ++i )
  607. {
  608. ItemEntry entry = (ItemEntry)items[i];
  609. Item item = (Item)entry.Object;
  610. if ( item != null )
  611. {
  612. reader.Seek( entry.Position, SeekOrigin.Begin );
  613. try
  614. {
  615. m_LoadingType = entry.TypeName;
  616. item.Deserialize( reader );
  617. if ( reader.Position != (entry.Position + entry.Length) )
  618. throw new Exception( String.Format( "***** Bad serialize on {0} *****", item.GetType() ) );
  619. }
  620. catch ( Exception e )
  621. {
  622. items.RemoveAt( i );
  623. failed = e;
  624. failedItems = true;
  625. failedType = item.GetType();
  626. failedTypeID = entry.TypeID;
  627. failedSerial = item.Serial;
  628. break;
  629. }
  630. }
  631. }
  632. reader.Close();
  633. }
  634. }
  635. m_LoadingType = null;
  636. if ( !failedMobiles && !failedItems && File.Exists( guildBinPath ) )
  637. {
  638. using ( FileStream bin = new FileStream( guildBinPath, FileMode.Open, FileAccess.Read, FileShare.Read ) )
  639. {
  640. BinaryFileReader reader = new BinaryFileReader( new BinaryReader( bin ) );
  641. for ( int i = 0; i < guilds.Count; ++i )
  642. {
  643. GuildEntry entry = (GuildEntry)guilds[i];
  644. BaseGuild g = (BaseGuild)entry.Object;
  645. if ( g != null )
  646. {
  647. reader.Seek( entry.Position, SeekOrigin.Begin );
  648. try
  649. {
  650. g.Deserialize( reader );
  651. if ( reader.Position != (entry.Position + entry.Length) )
  652. throw new Exception( String.Format( "***** Bad serialize on Guild {0} *****", g.Id ) );
  653. }
  654. catch ( Exception e )
  655. {
  656. guilds.RemoveAt( i );
  657. failed = e;
  658. failedGuilds = true;
  659. failedType = typeof( BaseGuild );
  660. failedTypeID = g.Id;
  661. failedSerial = g.Id;
  662. break;
  663. }
  664. }
  665. }
  666. reader.Close();
  667. }
  668. }
  669. if ( !failedMobiles && !failedItems && File.Exists( regionBinPath ) )
  670. {
  671. using ( FileStream bin = new FileStream( regionBinPath, FileMode.Open, FileAccess.Read, FileShare.Read ) )
  672. {
  673. BinaryFileReader reader = new BinaryFileReader( new BinaryReader( bin ) );
  674. for ( int i = 0; i <regions.Count; ++i )
  675. {
  676. RegionEntry entry = (RegionEntry)regions[i];
  677. Region r = (Region)entry.Object;
  678. if ( r != null )
  679. {
  680. reader.Seek( entry.Position, SeekOrigin.Begin );
  681. try
  682. {
  683. r.Deserialize( reader );
  684. if ( reader.Position != (entry.Position + entry.Length) )
  685. throw new Exception( String.Format( "***** Bad serialize on {0} *****", r.GetType() ) );
  686. }
  687. catch ( Exception e )
  688. {
  689. regions.RemoveAt( i );
  690. failed = e;
  691. failedRegions = true;
  692. failedType = r.GetType();
  693. failedTypeID = entry.TypeID;
  694. failedSerial = r.UId;
  695. break;
  696. }
  697. }
  698. }
  699. reader.Close();
  700. }
  701. }
  702. if ( failedItems || failedMobiles || failedGuilds || failedRegions )
  703. {
  704. Console.WriteLine( "An error was encountered while loading a saved object" );
  705. Console.WriteLine( " - Type: {0}", failedType );
  706. Console.WriteLine( " - Serial: {0}", failedSerial );
  707. Console.WriteLine( "Delete the object? (y/n)" );
  708. if ( Console.ReadLine() == "y" )
  709. {
  710. if ( failedType != typeof( BaseGuild ) && !failedType.IsSubclassOf( typeof( Region ) ) )
  711. {
  712. Console.WriteLine( "Delete all objects of that type? (y/n)" );
  713. if ( Console.ReadLine() == "y" )
  714. {
  715. if ( failedMobiles )
  716. {
  717. for ( int i = 0; i < mobiles.Count; )
  718. {
  719. if ( ((MobileEntry)mobiles[i]).TypeID == failedTypeID )
  720. mobiles.RemoveAt( i );
  721. else
  722. ++i;
  723. }
  724. }
  725. else if ( failedItems )
  726. {
  727. for ( int i = 0; i < items.Count; )
  728. {
  729. if ( ((ItemEntry)items[i]).TypeID == failedTypeID )
  730. items.RemoveAt( i );
  731. else
  732. ++i;
  733. }
  734. }
  735. }
  736. }
  737. SaveIndex( mobiles, mobIdxPath );
  738. SaveIndex( items, itemIdxPath );
  739. SaveIndex( guilds, guildIdxPath );
  740. SaveIndex( regions, regionIdxPath );
  741. }
  742. Console.WriteLine( "After pressing return an exception will be thrown and the server will terminate" );
  743. Console.ReadLine();
  744. throw new Exception( String.Format( "Load failed (items={0}, mobiles={1}, guilds={2}, regions={3}, type={4}, serial={5})", failedItems, failedMobiles, failedGuilds, failedRegions, failedType, failedSerial ), failed );
  745. }
  746. EventSink.InvokeWorldLoad();
  747. m_Loading = false;
  748. for ( int i = 0; i < m_DeleteList.Count; ++i )
  749. {
  750. object o = m_DeleteList[i];
  751. if ( o is Item )
  752. ((Item)o).Delete();
  753. else if ( o is Mobile )
  754. ((Mobile)o).Delete();
  755. }
  756. m_DeleteList.Clear();
  757. foreach ( Item item in m_Items.Values )
  758. {
  759. if ( item.Parent == null )
  760. item.UpdateTotals();
  761. item.ClearProperties();
  762. }
  763. ArrayList list = new ArrayList( m_Mobiles.Values );
  764. foreach ( Mobile m in list )
  765. {
  766. m.ForceRegionReEnter( true );
  767. m.UpdateTotals();
  768. m.ClearProperties();
  769. }
  770. Console.WriteLine( "done ({1} items, {2} mobiles) ({0:F1} seconds)", (DateTime.Now-start).TotalSeconds, m_Items.Count, m_Mobiles.Count );
  771. }
  772. public static void SaveIndex( ArrayList list, string path )
  773. {
  774. if ( !Directory.Exists( "Saves/Mobiles/" ) )
  775. Directory.CreateDirectory( "Saves/Mobiles/" );
  776. if ( !Directory.Exists( "Saves/Items/" ) )
  777. Directory.CreateDirectory( "Saves/Items/" );
  778. if ( !Directory.Exists( "Saves/Guilds/" ) )
  779. Directory.CreateDirectory( "Saves/Guilds/" );
  780. if ( !Directory.Exists( "Saves/Regions/" ) )
  781. Directory.CreateDirectory( "Saves/Regions/" );
  782. using ( FileStream idx = new FileStream( path, FileMode.Create, FileAccess.Write, FileShare.None ) )
  783. {
  784. BinaryWriter idxWriter = new BinaryWriter( idx );
  785. idxWriter.Write( list.Count );
  786. for ( int i = 0; i < list.Count; ++i )
  787. {
  788. IEntityEntry e = (IEntityEntry)list[i];
  789. idxWriter.Write( e.TypeID );
  790. idxWriter.Write( e.Serial );
  791. idxWriter.Write( e.Position );
  792. idxWriter.Write( e.Length );
  793. }
  794. idxWriter.Close();
  795. }
  796. }
  797. internal static int m_Saves;
  798. public static void Save()
  799. {
  800. ++m_Saves;
  801. Save( true );
  802. }
  803. private static bool m_MultiProcessor = false;
  804. public static bool MultiProcessor{ get{ return m_MultiProcessor; } set{ m_MultiProcessor = value; } }
  805. public static void Save( bool message )
  806. {
  807. if ( m_Saving || AsyncWriter.ThreadCount > 0 )
  808. return;
  809. NetState.FlushAll();
  810. m_Saving = true;
  811. if ( message )
  812. Broadcast( 0x35, true, "The world is saving, please wait." );
  813. Console.Write( "World: Saving..." );
  814. DateTime startTime = DateTime.Now;
  815. if ( !Directory.Exists( "Saves/Mobiles/" ) )
  816. Directory.CreateDirectory( "Saves/Mobiles/" );
  817. if ( !Directory.Exists( "Saves/Items/" ) )
  818. Directory.CreateDirectory( "Saves/Items/" );
  819. if ( !Directory.Exists( "Saves/Guilds/" ) )
  820. Directory.CreateDirectory( "Saves/Guilds/" );
  821. if ( !Directory.Exists( "Saves/Regions/" ) )
  822. Directory.CreateDirectory( "Saves/Regions/" );
  823. if ( m_MultiProcessor )
  824. {
  825. Thread saveThread = new Thread( new ThreadStart( SaveItems ) );
  826. saveThread.Name = "Item Save Subset";
  827. saveThread.Start();
  828. SaveMobiles();
  829. SaveGuilds();
  830. SaveRegions();
  831. saveThread.Join();
  832. }
  833. else
  834. {
  835. SaveMobiles();
  836. SaveItems();
  837. SaveGuilds();
  838. SaveRegions();
  839. }
  840. //Accounts.Save();
  841. try
  842. {
  843. EventSink.InvokeWorldSave( new WorldSaveEventArgs( message ) );
  844. }
  845. catch ( Exception e )
  846. {
  847. throw new Exception( "World Save event threw an exception. Save failed!", e );
  848. }
  849. //System.GC.Collect();
  850. DateTime endTime = DateTime.Now;
  851. Console.WriteLine( "done in {0:F1} seconds.", (endTime - startTime).TotalSeconds );
  852. if ( message )
  853. Broadcast( 0x35, true, "World save complete. The entire process took {0:F1} seconds.", (endTime - startTime).TotalSeconds );
  854. m_Saving = false;
  855. }
  856. private static void SaveMobiles()
  857. {
  858. ArrayList restock = new ArrayList();
  859. GenericWriter idx;
  860. GenericWriter tdb;
  861. GenericWriter bin;
  862. if ( SaveType == SaveOption.Normal )
  863. {
  864. idx = new BinaryFileWriter( mobIdxPath, false );
  865. tdb = new BinaryFileWriter( mobTdbPath, false );
  866. bin = new BinaryFileWriter( mobBinPath, true );
  867. }
  868. else
  869. {
  870. idx = new AsyncWriter( mobIdxPath, false );
  871. tdb = new AsyncWriter( mobTdbPath, false );
  872. bin = new AsyncWriter( mobBinPath, true );
  873. }
  874. idx.Write( (int) m_Mobiles.Count );
  875. foreach ( Mobile m in m_Mobiles.Values )
  876. {
  877. Type t = m.GetType();
  878. long start = bin.Position;
  879. idx.Write( (int) m.m_TypeRef );
  880. idx.Write( (int) m.Serial );
  881. idx.Write( (long) start );
  882. m.Serialize( bin );
  883. idx.Write( (int) (bin.Position - start) );
  884. if ( m is IVendor )
  885. {
  886. if ( ((IVendor)m).LastRestock + ((IVendor)m).RestockDelay < DateTime.Now )
  887. restock.Add( m );
  888. }
  889. m.FreeCache();
  890. }
  891. tdb.Write( (int) m_MobileTypes.Count );
  892. for ( int i = 0; i < m_MobileTypes.Count; ++i )
  893. tdb.Write( ((Type)m_MobileTypes[i]).FullName );
  894. for (int i=0;i<restock.Count;i++)
  895. {
  896. IVendor vend = (IVendor)restock[i];
  897. vend.Restock();
  898. vend.LastRestock = DateTime.Now;
  899. }
  900. idx.Close();
  901. tdb.Close();
  902. bin.Close();
  903. }
  904. internal static ArrayList m_ItemTypes = new ArrayList();
  905. internal static ArrayList m_MobileTypes = new ArrayList();
  906. private static void SaveItems()
  907. {
  908. ArrayList decaying = new ArrayList();
  909. GenericWriter idx;
  910. GenericWriter tdb;
  911. GenericWriter bin;
  912. if ( SaveType == SaveOption.Normal )
  913. {
  914. idx = new BinaryFileWriter( itemIdxPath, false );
  915. tdb = new BinaryFileWriter( itemTdbPath, false );
  916. bin = new BinaryFileWriter( itemBinPath, true );
  917. }
  918. else
  919. {
  920. idx = new AsyncWriter( itemIdxPath, false );
  921. tdb = new AsyncWriter( itemTdbPath, false );
  922. bin = new AsyncWriter( itemBinPath, true );
  923. }
  924. idx.Write( (int) m_Items.Count );
  925. foreach ( Item item in m_Items.Values )
  926. {
  927. if ( item.Decays && item.Parent == null && item.Map != Map.Internal && (item.LastMoved + item.DecayTime) <= DateTime.Now )
  928. decaying.Add( item );
  929. long start = bin.Position;
  930. idx.Write( (int) item.m_TypeRef );
  931. idx.Write( (int) item.Serial );
  932. idx.Write( (long) start );
  933. item.Serialize( bin );
  934. idx.Write( (int) (bin.Position - start) );
  935. item.FreeCache();
  936. }
  937. tdb.Write( (int) m_ItemTypes.Count );
  938. for ( int i = 0; i < m_ItemTypes.Count; ++i )
  939. tdb.Write( ((Type)m_ItemTypes[i]).FullName );
  940. idx.Close();
  941. tdb.Close();
  942. bin.Close();
  943. for ( int i = 0; i < decaying.Count; ++i )
  944. {
  945. Item item = (Item)decaying[i];
  946. if ( item.OnDecay() )
  947. item.Delete();
  948. }
  949. }
  950. private static void SaveGuilds()
  951. {
  952. GenericWriter idx;
  953. GenericWriter bin;
  954. if ( SaveType == SaveOption.Normal )
  955. {
  956. idx = new BinaryFileWriter( guildIdxPath, false );
  957. bin = new BinaryFileWriter( guildBinPath, true );
  958. }
  959. else
  960. {
  961. idx = new AsyncWriter( guildIdxPath, false );
  962. bin = new AsyncWriter( guildBinPath, true );
  963. }
  964. idx.Write( (int) BaseGuild.List.Count );
  965. foreach ( BaseGuild guild in BaseGuild.List.Values )
  966. {
  967. long start = bin.Position;
  968. idx.Write( (int)0 );//guilds have no typeid
  969. idx.Write( (int)guild.Id );
  970. idx.Write( (long)start );
  971. guild.Serialize( bin );
  972. idx.Write( (int) (bin.Position - start) );
  973. }
  974. idx.Close();
  975. bin.Close();
  976. }
  977. private static void SaveRegions()
  978. {
  979. int count = 0;
  980. GenericWriter bin;
  981. if ( SaveType == SaveOption.Normal )
  982. bin = new BinaryFileWriter( regionBinPath, true );
  983. else
  984. bin = new AsyncWriter( regionBinPath, true );
  985. MemoryStream mem = new MemoryStream( 4 + (20*Region.Regions.Count) );
  986. BinaryWriter memIdx = new BinaryWriter( mem );
  987. memIdx.Write( (int)0 );
  988. for ( int i = 0; i < Region.Regions.Count; ++i )
  989. {
  990. Region region = (Region)Region.Regions[i];
  991. if ( region.Saves )
  992. {
  993. ++count;
  994. long start = bin.Position;
  995. memIdx.Write( (int)0 );//typeid
  996. memIdx.Write( (int) region.UId );
  997. memIdx.Write( (long) start );
  998. region.Serialize( bin );
  999. memIdx.Write( (int) (bin.Position - start) );
  1000. }
  1001. }
  1002. bin.Close();
  1003. memIdx.Seek( 0, SeekOrigin.Begin );
  1004. memIdx.Write( (int)count );
  1005. if ( SaveType == SaveOption.Threaded )
  1006. {
  1007. AsyncWriter asyncIdx = new AsyncWriter( regionIdxPath, false );
  1008. asyncIdx.MemStream = mem;
  1009. asyncIdx.Close();
  1010. }
  1011. else
  1012. {
  1013. FileStream fs = new FileStream( regionIdxPath, FileMode.Create, FileAccess.Write, FileShare.None );
  1014. mem.WriteTo( fs );
  1015. fs.Close();
  1016. mem.Close();
  1017. }
  1018. // mem is closed only in non threaded saves, as its reference is copied to asyncIdx.MemStream
  1019. memIdx.Close();
  1020. }
  1021. public static IEntity FindEntity( Serial serial )
  1022. {
  1023. if ( serial.IsItem )
  1024. {
  1025. return (Item)m_Items[serial];
  1026. }
  1027. else if ( serial.IsMobile )
  1028. {
  1029. return (Mobile)m_Mobiles[serial];
  1030. }
  1031. else
  1032. {
  1033. return null;
  1034. }
  1035. }
  1036. public static Mobile FindMobile( Serial serial )
  1037. {
  1038. return (Mobile)m_Mobiles[serial];
  1039. }
  1040. public static void AddMobile( Mobile m )
  1041. {
  1042. m_Mobiles[m.Serial] = m;
  1043. }
  1044. public static Item FindItem( Serial serial )
  1045. {
  1046. return (Item)m_Items[serial];
  1047. }
  1048. public static void AddItem( Item item )
  1049. {
  1050. m_Items[item.Serial] = item;
  1051. }
  1052. public static void RemoveMobile( Mobile m )
  1053. {
  1054. m_Mobiles.Remove( m.Serial );
  1055. }
  1056. public static void RemoveItem( Item item )
  1057. {
  1058. m_Items.Remove( item.Serial );
  1059. }
  1060. }
  1061. }