/// <summary> /// Instantiates the singleton of the <see cref="MmoWorld"/>. If it has already been instantiated returns the old instance. /// </summary> public static MmoWorld Instantiate(IWorldServer server, GameConfig gameConfiguration, WorldDescription worldDescription) { lock (typeof(MmoWorld)) return(Instance ?? (Instance = new MmoWorld(server, gameConfiguration, worldDescription))); }
/// <summary> /// Creates a new instance of the <see cref="MmoZone"/> class. /// </summary> /// <param name="world"> The world </param> /// <param name="name"> The name of the <see cref="MmoZone"/>. Does not have to be unique, this will be sent to the client. </param> /// <param name="id"> A unique id used to distinguish between other <see cref="MmoZone"/>s. Must be unique in order to avoid id conflicts. </param> /// <param name="tileDimentions"> </param> /// <param name="zoneDescription"> The zone data which contains data of the current zone </param> /// <param name="bounds"> </param> /// <param name="configuration"> </param> /// <remarks> /// The <see cref="MmoZone"/> uses an actual coordinate system, meaning x is right, z is forward and y is up always. /// </remarks> internal MmoZone(MmoWorld world, short id, string name, Bounds bounds, Vector3 tileDimentions, ZoneDescription zoneDescription, GameConfig configuration) : base(bounds, tileDimentions) { this.world = world; this.name = name; this.id = id; this.objectCache = new WorldObjectCache(PeerSettings.MaxLockWaitTime); this.dynamicObjectPool = new ObjectPool <short, Dynamic>(); this.localChatChannel = Chat.MmoChat.INVALID_CHAT_CHANNEL; this.tradeChatChannel = Chat.MmoChat.INVALID_CHAT_CHANNEL; var physicsEngineConfig = configuration.physics.engine; switch (physicsEngineConfig.type.ToLower()) { case "digitalrune": this.physics = new RunePhysicsWorld(Bounds, physicsEngineConfig.userObject); break; default: this.physics = new QuantumPhysicsWorld(Bounds, this); break; } var terrainWidthX = zoneDescription.TerrainWidthX; var terrainWidthZ = zoneDescription.TerrainWidthZ; var heights = new float[terrainWidthX, terrainWidthZ]; for (var z = 0; z < terrainWidthZ; z++) { for (var x = 0; x < terrainWidthX; x++) { // we need to load it in reverse order heights[x, z] = zoneDescription.Heights[z * terrainWidthX + x]; } } var heightFieldDescription = new HeightFieldDescription { Heights = heights, Position = Vector3.Zero, WidthX = terrainWidthX, WidthZ = terrainWidthZ }; this.heightField = physics.CreateHeightField(heightFieldDescription).Shape as IHeightField; if (heightField == null) { throw new NullReferenceException("heightField"); } // loading all box colliders var boxColliders = zoneDescription.Colliders.BoxColliders; if (boxColliders != null) { foreach (var boxCollider in boxColliders) { physics.CreateWorldObject(boxCollider, CollisionHelper.WorldObjectColliderDescription); } } // loading all sphere colliders var sphereColliders = zoneDescription.Colliders.SphereColliders; if (sphereColliders != null) { foreach (var sphereCollider in sphereColliders) { physics.CreateWorldObject(sphereCollider, CollisionHelper.WorldObjectColliderDescription); } } // loading all capsule colliders var capsuleColliders = zoneDescription.Colliders.CapsuleColliders; if (capsuleColliders != null) { foreach (var capsuleCollider in capsuleColliders) { physics.CreateWorldObject(capsuleCollider, CollisionHelper.WorldObjectColliderDescription); } } #if USE_PHYSICS // setting up the physics thread new Thread(o => { var timer = System.Diagnostics.Stopwatch.StartNew(); timer.Start(); while (true) { // sleeping for 16 ms ~ 1 / 60 s Thread.Sleep(16); // updating the physics engine this.physics.Update(timer.Elapsed); timer.Restart(); } }) { Priority = ThreadPriority.AboveNormal, IsBackground = true }.Start(this); #endif // load all npc, objects, items, quest, loot, etc this.PrimaryFiber.Enqueue(LoadZone); #if MMO_DEBUG Utils.Logger.DebugFormat("Zone (Name={0}:Min={1}:Max={2}) created in World (Min={3}:Max={4}", this.Name, Bounds.Min, Bounds.Max, World.Bounds.Min, World.Bounds.Max); #endif }