public IEnumerator SendPlayerToStartupPosition(PlayerStartupPosition startupPosition) { if (mSpawningPlayer) { //whoops yield break; } mSpawningPlayer = true; if (!GUILoading.IsLoading) { //let that go on its own, don't wait for it StartCoroutine(GUILoading.LoadStart(GUILoading.Mode.FullScreenBlack)); } //if the startup position is null //use the character's state as a startup position if (startupPosition == null) { //the player state should be not-null by now Debug.Log("Using player startup position"); startupPosition = Player.Local.GetStartupPosition(); } if (Player.Local.HasSpawned) { Player.Local.Despawn(); } //set the current spawn position CurrentStartupPosition = startupPosition; yield return(null); //set all existing world chunks to unclaimed mLoadingInfo = "Unloading chunks"; //suspend chunk loading so the player's position doesn't get the world confused GameWorld.Get.SuspendChunkLoading = true; for (int i = 0; i < GameWorld.Get.WorldChunks.Count; i++) { if (GameWorld.Get.WorldChunks [i].State.ID != startupPosition.ChunkID) { GameWorld.Get.WorldChunks [i].TargetMode = ChunkMode.Unloaded; } } //suspend worlditem loading so worlditems don't start spawning stuff till we're ready WorldItems.Get.SuspendWorldItemUpdates = true; //WorldItems.Get.SetAllWorldItemsToInvisible(); //wait a moment to let that sink in yield return(null); //put the player in the middle of the chunk to be loaded first WorldChunk startChunk = null; if (GameWorld.Get.ChunkByID(startupPosition.ChunkID, out startChunk)) { Player.Local.Position = startChunk.ChunkOffset + startupPosition.ChunkPosition.Position; } else { mLoadingInfo = "ERROR: Couldn't find startup chunk"; } //we send the player to the chunk / location specified in the world settings mLoadingInfo = "Sending player to startup position"; //re-enable chunk loading so everything can load GameWorld.Get.SuspendChunkLoading = false; WorldItems.Get.SuspendWorldItemUpdates = false; //set the primary chunk and let it load //put the player in the middle of the chunk to be loaded first mLoadingInfo = "Waiting for chunks to load"; while (!GameWorld.Get.ChunksLoaded) { yield return(null); } if (startupPosition.ForceUnloadAllNonPrimaryChunks) { Debug.Log("Force-unloading all primary chunks, structures, worlditems"); //unload all chunks except the primary chunk var unloadChunks = GameWorld.Get.UnloadAllChunks(startupPosition.ChunkID); while (unloadChunks.MoveNext()) { mLoadingInfo = "Unloading all chunks..."; yield return(unloadChunks.Current); } var unloadStructures = Structures.Get.UnloadAllStructures(); while (unloadStructures.MoveNext()) { mLoadingInfo = "Unloading all structures..."; yield return(unloadStructures.Current); } var unloadWorldItems = WorldItems.Get.UnloadAllWorldItems(); while (unloadWorldItems.MoveNext()) { mLoadingInfo = "Unloading all worlditems..."; yield return(unloadWorldItems.Current); } Resources.UnloadUnusedAssets(); } mLoadingInfo = "Chunks unloaded, setting primary chunk"; //set all the non-distant chunks to load GameWorld.Get.SetDistantChunks(Player.Local.Position); if (!GameWorld.Get.SetPrimaryChunk(startupPosition.ChunkID)) { mLoadingInfo = "Couldn't set primary chunk, halting load: " + startupPosition.ChunkID.ToString(); yield break; } //set the startup position so managers know where the player will end up startupPosition.WorldPosition.Position = (GameWorld.Get.PrimaryChunk.ChunkOffset + startupPosition.ChunkPosition.Position); startupPosition.WorldPosition.Rotation = startupPosition.ChunkPosition.Rotation; //set all the non-distant chunks to load GameWorld.Get.SetDistantChunks(startupPosition.WorldPosition.Position); //wait for the rest of the chunk to load while (GameWorld.Get.PrimaryChunk.CurrentMode != ChunkMode.Primary) { //turn on the camera so it starts rendering grass meshes //this will fight with camera FX but that's ok CameraFX.Get.Default.cam.enabled = true; CameraFX.Get.Default.cam.cullingMask = CameraFX.Get.Default.CullingMask; mLoadingInfo = "Waiting for primary chunk to load"; //Debug.Log("waiting for primary chunk to load"); yield return(null); } //initialize time if (startupPosition.RequiresStructure) { mLoadingInfo = "Loading structures"; yield return(StartCoroutine(SendPlayerToStructure( startupPosition.ChunkID, startupPosition.LocationReference, startupPosition.StructureName, startupPosition.Interior, startupPosition.ChunkPosition, startChunk.ChunkOffset))); } else { mLoadingInfo = "Loading location"; yield return(StartCoroutine(SendPlayerToLocation( startupPosition.ChunkID, startupPosition.LocationReference.GroupPath, startupPosition.LocationReference.FileName, startupPosition.ChunkPosition, startChunk.ChunkOffset, 0.1f))); //since we're not inside a structure //we could be standing on something //either a minor structure or chunk prefab if (startupPosition.RequiresMeshTerrain) { //wait for something to show up below the player before letting them go GameWorld.TerrainHeightSearch terrainHit = new GameWorld.TerrainHeightSearch(); terrainHit.feetPosition = startupPosition.WorldPosition.Position; terrainHit.groundedHeight = Globals.DefaultCharacterGroundedHeight; terrainHit.overhangHeight = Globals.DefaultCharacterHeight; bool foundSomethingBelowPlayer = false; double timeOut = WorldClock.RealTime + 30f; mLoadingInfo = "Waiting for mesh below player's feet"; while (WorldClock.RealTime < timeOut) { GameWorld.Get.TerrainHeightAtInGamePosition(ref terrainHit); //see if we hit a mesh if (terrainHit.hitTerrainMesh) { break; } yield return(null); } } } //immediately add the game offset if (startupPosition.AbsoluteTime) { WorldClock.ResetAbsoluteTime(); Profile.Get.CurrentGame.SetWorldTimeOffset( startupPosition.TimeHours, startupPosition.TimeDays, startupPosition.TimeMonths, startupPosition.TimeYears); } else { Profile.Get.CurrentGame.AddWorldTimeOffset( startupPosition.TimeHours, startupPosition.TimeDays, startupPosition.TimeMonths, startupPosition.TimeYears); } //unload anything we're not using //GC.Collect(); //Resources.UnloadUnusedAssets(); //yield return null; yield return(null); if (GUILoading.IsLoading) { StartCoroutine(GUILoading.LoadFinish()); } Player.Local.SpawnAtPosition(startupPosition.WorldPosition); mSpawningPlayer = false; yield break; }
protected IEnumerator SpawnPlayerOverTime(LocalPlayer player) { mWaitingForFade = true; //add a request to spawn a healer character near the player Frontiers.GUI.CameraFade.StartAlphaFade(Color.red, false, 3.0f, 0f, () => { mWaitingForFade = false; }); while (mWaitingForFade) { yield return(null); } //now fade out red Frontiers.GUI.CameraFade.StartAlphaFade(Color.red, true, 3.0f); //now that the screen is covered //move the player GameWorld.TerrainHeightSearch terrainHit = new GameWorld.TerrainHeightSearch(); //search for an appropriate spot within a radius around the player bool foundGoodSpot = false; int maxTries = 50; int numTriesSoFar = 0; while (!foundGoodSpot) { Vector3 randomSpot = (UnityEngine.Random.onUnitSphere * 25f) + player.Surroundings.LastPositionOnland; randomSpot.y += 150; terrainHit.feetPosition = randomSpot; terrainHit.overhangHeight = Globals.DefaultCharacterHeight; terrainHit.groundedHeight = 200f; //we don't care about being grounded, just find the floor terrainHit.feetPosition.y = GameWorld.Get.TerrainHeightAtInGamePosition(ref terrainHit); if (!terrainHit.hitWater && !terrainHit.hitTerrainMesh && terrainHit.hitTerrain) { Debug.Log("Found spot to spawn: " + terrainHit.feetPosition.ToString()); foundGoodSpot = true; break; } else { numTriesSoFar++; if (numTriesSoFar > maxTries) { Debug.Log("Couldn't find good place to spawn, going with last position on land"); terrainHit.feetPosition = player.Surroundings.LastPositionOnland; break; } } } terrainHit.feetPosition.y += 0.25f; player.Position = terrainHit.feetPosition; //spawn the player player.Spawn(); //finally spawn the healer nearby CharacterSpawnRequest spawnRequest = new CharacterSpawnRequest(); spawnRequest.ActionNodeName = "HealerActionNode"; spawnRequest.CharacterName = "Healer"; spawnRequest.UseGenericTemplate = true; spawnRequest.CustomConversation = Globals.HouseOfHealingExteriorConversation; spawnRequest.FinishOnSpawn = true; spawnRequest.SpawnBehindPlayer = true; spawnRequest.MinimumDistanceFromPlayer = 1f; player.CharacterSpawner.AddSpawnRequest(spawnRequest); //take the player's money //take 1/2 (or whatever global value is) reduced by skill value int moneyToTake = Mathf.FloorToInt(player.Inventory.InventoryBank.BaseCurrencyValue * (Globals.HouseOfHealingRevivalCost * (1f - State.NormalizedUsageLevel))); player.Inventory.InventoryBank.TryToRemove(moneyToTake); //and we're done! mSpawningPlayerOverTime = false; yield break; }