/// <summary> /// Returns true if all chunks that belong to the given area master chunk, extended by the given value, are currently loaded. /// </summary> /// <param name="areaMasterChunk">The area master chunk to use as basis</param> /// <param name="extendBy">Number of chunks to extend the check area in all directions, additionally to the 5x5 area master</param> private bool AllChunksLoaded([NotNull] Chunk areaMasterChunk, int extendBy) { if (World.ChunkCache == null) { return(false); } if (!areaMasterChunk.IsAreaMaster()) { throw new ArgumentException("Given chunk is not an area master chunk.", nameof(areaMasterChunk)); } lock (World.ChunkCache.GetSyncRoot()) { for (int x = areaMasterChunk.X - extendBy; x < areaMasterChunk.X + Chunk.cAreaMasterSizeChunks + extendBy; x++) { for (int z = areaMasterChunk.Z - extendBy; z < areaMasterChunk.Z + Chunk.cAreaMasterSizeChunks + extendBy; z++) { if (!World.ChunkCache.ContainsChunkSync(WorldChunkCache.MakeChunkKey(x, z, areaMasterChunk.ClrIdx))) { return(false); } } } } return(true); }
public static bool Execute(ClientInfo sender, List <string> arguments) { World world = GameManager.Instance.World; EntityPlayer entityPlayer = world.Players.dict[sender.entityId]; Vector3 position = entityPlayer.position; PrefabInstance prefab = world.GetPOIAtPosition(position); // If no arguments just show POI info if (arguments.Count == 0) { if (prefab == null) { ChatManager.Message(sender, "[FF0000]No POI found!"); } else { ChatManager.Message(sender, string.Format("[FFCC00]POI: [DDDDDD]{0}", prefab.name)); } return(false); } // Fix everything around player int num = World.toChunkXZ((int)position.x) - 1; int num2 = World.toChunkXZ((int)position.z) - 1; int num3 = num + 2; int num4 = num2 + 2; HashSetLong hashSetLong = new HashSetLong(); for (int k = num; k <= num3; k++) { for (int l2 = num2; l2 <= num4; l2++) { hashSetLong.Add(WorldChunkCache.MakeChunkKey(k, l2)); } } ChunkCluster chunkCache = world.ChunkCache; ChunkProviderGenerateWorld chunkProviderGenerateWorld = world.ChunkCache.ChunkProvider as ChunkProviderGenerateWorld; foreach (long key in hashSetLong) { if (!chunkProviderGenerateWorld.GenerateSingleChunk(chunkCache, key, true)) { ChatManager.Message(sender, string.Format("Failed regenerating chunk at position {0}/{1}", WorldChunkCache.extractX(key) << 4, WorldChunkCache.extractZ(key) << 4)); } } world.m_ChunkManager.ResendChunksToClients(hashSetLong); if (prefab != null) { prefab.Reset(world); } ChatManager.Message(sender, "[44FF44]Reseted"); return(false); }
private void DoReload() { if (Params.Count != 5 && Params.Count != 3) { SendOutput("Incorrect params count for reload"); SendOutput(GetHelp()); return; } int cx; int cy; int cz; int cw; if (Params.Count == 3) { if (!int.TryParse(Params[1], out cx) || !int.TryParse(Params[2], out cy)) { SendOutput("Unable to parse chunk co-ords from params"); SendOutput(GetHelp()); return; } cz = cx; cw = cy; } else { if (!int.TryParse(Params[1], out cx) || !int.TryParse(Params[2], out cy) || !int.TryParse(Params[3], out cz) || !int.TryParse(Params[4], out cw)) { SendOutput("Unable to parse chunk co-ords from params"); SendOutput(GetHelp()); return; } } var x1 = Math.Min(cx, cz); var x2 = Math.Max(cx, cz); var z1 = Math.Min(cy, cw); var z2 = Math.Max(cy, cw); var chunks = new Dictionary <long, Chunk>(); for (var x = x1; x <= x2; x++) { for (var z = z1; z <= z2; z++) { var chunkKey = WorldChunkCache.MakeChunkKey(x, z); chunks[chunkKey] = null; } } var count = BCChunks.ReloadForClients(chunks); SendOutput($"Chunks reloaded for {count} clients in area: {x1},{z1} to {x2},{z2}"); }
/// <summary> /// Returns all chunk keys that are located (also partly) in the given area. /// </summary> /// <param name="pos1">South-West corner of area; y is ignored</param> /// <param name="pos2">North-East corner of area; y is ignored</param> /// <param name="expand">Allows expanding (or with negative value contracting) the area by the given number of chunks. /// For example with +1 it returns also neighbouring chunks.</param> /// <returns>Collection of chunk keys; chunks may or may not be loaded</returns> private static ICollection <long> GetChunksForArea(Vector3i pos1, Vector3i pos2, int expand = 0) { expand *= Constants.ChunkSize; // expand is now in blocks var chunkKeys = new List <long>(); for (var x = pos1.x - expand; x <= pos2.x + expand; x += Constants.ChunkSize) { for (var z = pos1.z - expand; z <= pos2.z + expand; z += Constants.ChunkSize) { chunkKeys.Add(WorldChunkCache.MakeChunkKey(World.toChunkXZ(x), World.toChunkXZ(z))); } } return(chunkKeys); }
private static bool GetChunkKey(World world, out long chunkKey) { chunkKey = long.MinValue; switch (Params.Count) { case 3: { if (!int.TryParse(Params[1], out var x) || !int.TryParse(Params[2], out var z)) { SendOutput("Unable to parse x z for numbers"); return(false); } chunkKey = WorldChunkCache.MakeChunkKey(x, z); return(true); } default: { if (SenderInfo.RemoteClientInfo == null) { SendOutput("Unable to get location from player position"); return(false); } var entityId = SenderInfo.RemoteClientInfo.entityId; if (!world.Players.dict.ContainsKey(entityId)) { SendOutput("Unable to get location from player position"); return(false); } var ep = world.Players.dict[entityId]; chunkKey = WorldChunkCache.MakeChunkKey((int)Math.Floor(ep.position.x) >> 4, (int)Math.Floor(ep.position.z) >> 4); return(true); } } }
public override void Process() { if (Params.Count != 2) { SendOutput(GetHelp()); return; } if (!int.TryParse(Params[0], out var x)) { SendOutput("x was not a number"); return; } if (!int.TryParse(Params[1], out var z)) { SendOutput("z was not a number"); return; } if (GameManager.Instance.World == null) { SendOutput("The world isn't loaded"); return; } var world = GameManager.Instance.World; var x2 = World.toChunkXZ(x); var z2 = World.toChunkXZ(z); var i = 0; Chunk chunk = null; world.ChunkCache.ChunkProvider.RequestChunk(x2, z2); var chunkKey = WorldChunkCache.MakeChunkKey(x2, z2); while (i < 100) { chunk = world.GetChunkSync(chunkKey) as Chunk; if (chunk != null) { break; } System.Threading.Thread.Sleep(10); i++; } //todo: allow for /timeout to increase limit? if (chunk == null) { SendOutput("Unable to get chunk"); return; } var heights = new List <string>(); if (Options.ContainsKey("ch")) { for (var x3 = 0; x3 < 16; x3++) { for (var z3 = 0; z3 < 16; z3++) { heights.Add(chunk.GetHeight(x3, z3).ToString()); } } SendOutput("ChunkHeights:" + string.Join(",", heights.ToArray())); } else { var cx = x & 15; var cz = z & 15; if (Options.ContainsKey("ph")) { SendOutput("PointHeight:" + chunk.GetHeight(cx, cz)); } else { if (chunk.FindSpawnPointAtXZ(cx, cz, out var y, 15, 0, 3, 251, true)) { SendOutput("SpawnPoint:" + x + " " + y + " " + z); }
public override void Process() { if (Params.Count == 0) { SendOutput(GetHelp()); return; } var world = GameManager.Instance.World; if (world == null) { return; } switch (Params[0]) { //case "region": // { // var chunkCache = world.ChunkCache; // if (!(chunkCache.ChunkProvider is ChunkProviderGenerateWorld chunkProvider)) // { // SendOutput("Unable to load chunk provider"); // return; // } // var field = typeof(ChunkProviderGenerateWorld).GetField("m_regionFileManager", BindingFlags.NonPublic | BindingFlags.Instance); // var rfm = (RegionFileManager)field?.GetValue(chunkProvider); // if (rfm == null) // { // SendOutput("Region Manager is null"); // return; // } // if (!int.TryParse(Params[1], out var cx) || !int.TryParse(Params[2], out var cz)) // { // SendOutput("Unable to parse cx or cz as numbers"); // return; // } // var chunkKey = WorldChunkCache.MakeChunkKey(cx, cz); // //do stuff // rfm.RemoveChunkSync(chunkKey); // break; // } case "chunk": { //CHUNK - Resets the chunk to the original state it was created in if (Params.Count != 3) { SendOutput("Incorrect Params"); SendOutput(GetHelp()); return; } if (!int.TryParse(Params[1], out var cx) || !int.TryParse(Params[2], out var cz)) { SendOutput("Unable to parse cx or cz as numbers"); return; } var chunkKey = WorldChunkCache.MakeChunkKey(cx, cz); //todo: make unloaded chunk option //todo: deferred load var chunkCache = world.ChunkCache; if (!(chunkCache.ChunkProvider is ChunkProviderGenerateWorld chunkProvider)) { SendOutput("Unable to load chunk provider"); return; } //todo: deferred load var chunkSync = chunkCache.GetChunkSync(chunkKey); if (chunkSync == null) { SendOutput("Chunk not loaded"); return; } //create reset chunk var chunk = MemoryPools.PoolChunks.AllocSync(true); if (chunk == null) { SendOutput("Couldn't allocate chunk from memory pool"); return; } chunk.X = cx; chunk.Z = cz; if (!(chunkProvider.GetTerrainGenerator() is TerrainGeneratorWithBiomeResource terrainGenerator)) { SendOutput("Couldn't load terrain generator"); return; } var random = Utils.RandomFromSeedOnPos(cx, cz, world.Seed); terrainGenerator.GenerateTerrain(world, chunk, random); chunk.NeedsDecoration = true; chunk.NeedsLightCalculation = true; DoPrefabDecorations(world, chunkProvider, chunk, random); DeEntityDecoration(world, chunkProvider, chunk, random); DoSpawnerDecorations(world, chunkProvider, chunk, random); //UPDATE CHUNK var syncRoot = chunkCache.GetSyncRoot(); lock (syncRoot) { //remove old chunk if (chunkCache.ContainsChunkSync(chunkKey)) { chunkCache.RemoveChunkSync(chunkKey); } if (chunkCache.ContainsChunkSync(chunk.Key)) { SendOutput("Reset chunk still exists in chunk cache"); return; } if (!chunkCache.AddChunkSync(chunk)) { MemoryPools.PoolChunks.FreeSync(chunk); SendOutput("Unable to add new chunk to cache"); return; } } var decorateWithNeigbours = typeof(ChunkProviderGenerateWorld).GetMethod(_decorateFunction, BindingFlags.NonPublic | BindingFlags.Instance); if (decorateWithNeigbours == null) { SendOutput("Couldn't access method for DecorateWithNeigbours"); return; } decorateWithNeigbours.Invoke(chunkProvider, new object[] { chunk }); chunk.InProgressRegeneration = false; chunk.NeedsCopying = true; chunk.isModified = true; SendOutput($"Chunk reset @ {cx},{cz}"); Log.Out($"{Config.ModPrefix} Chunk reset @ {cx},{cz}"); //RELOAD CHUNKS if (!(Options.ContainsKey("noreload") || Options.ContainsKey("nr"))) { BCChunks.ReloadForClients(new Dictionary <long, Chunk> { { chunkKey, chunk } }); } break; } //case "player": // { // //resets the player by kicking them if online and then backing up player files before deleting // break; // } default: SendOutput(GetHelp()); break; } }
internal static void PlayerSpawnedInWorld(ClientInfo player, RespawnType respawnReason, Vector3i _pos) { string pId = player.playerId; ModState playerState = VariableContainer.GetPlayerState(pId); World world = GameManager.Instance.World; if (respawnReason.Equals(RespawnType.Died)) { if (playerState.Equals(ModState.RECONNECTING_TO_GAME) || playerState.Equals(ModState.IN_GAME) || playerState.Equals(ModState.START_GAME)) { if (playerState.Equals(ModState.RECONNECTING_TO_GAME)) { Team.Member member = new Team.Member { entityId = player.entityId, nick = player.playerName, pId = pId }; VariableContainer.SetPlayerState(pId, ModState.IN_GAME); TeamMaker.AddPlayerToTeam(member, VariableContainer.GetPlayerLastTeam(pId)); } // Has no items, teleport to team spawn and give items Map map = VariableContainer.GetMap(VariableContainer.selectedMap); Vector3 spawn = TeamMaker.GetPlayerTeam(pId).spawn; Log.Out(string.Format("Spawn for {0} is {1}", player.playerName, spawn.ToString())); // Find random spor around spawn Vector3 destination = Vector3.zero; //if (!world.GetRandomSpawnPositionMinMaxToPosition(spawn, 0, 2, 2, false, out destination, true)) // { destination = spawn; //} player.SendPackage(NetPackageManager.GetPackage <NetPackageTeleportPlayer>().Setup(destination, null, false)); // ReGen // Rebuild terrain around spawn if (!refubrishedCords.Contains(spawn)) { // But only once refubrishedCords.Add(spawn); PrefabInstance prefab = GameManager.Instance.World.GetPOIAtPosition(spawn); int num = World.toChunkXZ((int)spawn.x) - 1; int num2 = World.toChunkXZ((int)spawn.z) - 1; int num3 = num + 2; int num4 = num2 + 2; HashSetLong hashSetLong = new HashSetLong(); for (int k = num; k <= num3; k++) { for (int l2 = num2; l2 <= num4; l2++) { hashSetLong.Add(WorldChunkCache.MakeChunkKey(k, l2)); } } ChunkCluster chunkCache = world.ChunkCache; ChunkProviderGenerateWorld chunkProviderGenerateWorld = world.ChunkCache.ChunkProvider as ChunkProviderGenerateWorld; foreach (long key in hashSetLong) { if (!chunkProviderGenerateWorld.GenerateSingleChunk(chunkCache, key, true)) { ChatManager.Message(player, string.Format("[FF4136]Failed regenerating chunk at position [FF851B]{0}[FF4136]/[FF851B]{1}", WorldChunkCache.extractX(key) << 4, WorldChunkCache.extractZ(key) << 4)); } } world.m_ChunkManager.ResendChunksToClients(hashSetLong); if (prefab != null) { prefab.Reset(world); } } // Give items ClassManager.ApplyClass(player); if (VariableContainer.GetPlayerState(pId).Equals(ModState.START_GAME)) { VariableContainer.SetPlayerState(pId, ModState.IN_GAME); } else { HandleDiedInGame(player); } return; } else { VariableContainer.SetPlayerState(pId, ModState.IN_LOBBY); player.SendPackage(NetPackageManager.GetPackage <NetPackageTeleportPlayer>().Setup(VariableContainer.GetLobbyPosition(), null, false)); return; } } if (respawnReason.Equals(RespawnType.Teleport)) { return; } if (VariableContainer.GetPlayerState(pId).Equals(ModState.RECONNECTING_TO_GAME)) { // Have to kill reconected player Log.Out("Killing bc of reconnect: " + player.playerName); world.Players.dict[player.entityId].DamageEntity(new DamageSource(EnumDamageSource.Internal, EnumDamageTypes.Suicide), 99999, false, 1f); return; } if (VariableContainer.selectedMap == "null") { VariableContainer.SetPlayerState(pId, ModState.IN_LOBBY); player.SendPackage(NetPackageManager.GetPackage <NetPackageTeleportPlayer>().Setup(VariableContainer.GetLobbyPosition(), null, false)); } }
public static Dictionary <long, Chunk> GetAffectedChunks(BCMCmdArea command, World world) { var modifiedChunks = new Dictionary <long, Chunk>(); var timeout = 2000; if (command.Opts.ContainsKey("timeout")) { if (command.Opts["timeout"] != null) { int.TryParse(command.Opts["timeout"], out timeout); } } ChunkObserver(command, world, timeout / 2000); //request any unloaded chunks in area for (var x = command.ChunkBounds.x; x <= command.ChunkBounds.z; x++) { for (var z = command.ChunkBounds.y; z <= command.ChunkBounds.w; z++) { var chunkKey = WorldChunkCache.MakeChunkKey(x, z); modifiedChunks.Add(chunkKey, null); } } var chunkCount = (command.ChunkBounds.z - command.ChunkBounds.x + 1) * (command.ChunkBounds.w - command.ChunkBounds.y + 1); var count = 0; var sw = Stopwatch.StartNew(); while (count < chunkCount && sw.ElapsedMilliseconds < timeout) { for (var x = command.ChunkBounds.x; x <= command.ChunkBounds.z; x++) { for (var z = command.ChunkBounds.y; z <= command.ChunkBounds.w; z++) { //check if already in list var chunkKey = WorldChunkCache.MakeChunkKey(x, z); if (modifiedChunks.ContainsKey(chunkKey) && modifiedChunks[chunkKey] != null) { continue; } //check if chunk has loaded if (!world.ChunkCache.ContainsChunkSync(chunkKey)) { continue; } modifiedChunks[chunkKey] = world.GetChunkSync(chunkKey) as Chunk; if (modifiedChunks[chunkKey] != null) { count++; } } } } sw.Stop(); if (count < chunkCount) { BCCommandAbstract.SendOutput($"Unable to load {chunkCount - count}/{chunkCount} chunks"); return(null); } BCCommandAbstract.SendOutput($"Loading {chunkCount} chunks took {Math.Round(sw.ElapsedMilliseconds / 1000f, 2)} seconds"); return(modifiedChunks); }
protected override void Process() { if (!BCUtils.CheckWorld(out var world)) { return; } //Resets the chunk to the original state it was created in if (Params.Count != 2) { SendOutput("Incorrect Params"); SendOutput(GetHelp()); return; } if (!int.TryParse(Params[0], out var cx) || !int.TryParse(Params[1], out var cz)) { SendOutput("Unable to parse cx or cz as numbers"); return; } var chunkKey = WorldChunkCache.MakeChunkKey(cx, cz); //todo: make unloaded chunk option //todo: deferred load var chunkCache = world.ChunkCache; if (!(chunkCache.ChunkProvider is ChunkProviderGenerateWorld chunkProvider)) { SendOutput("Unable to load chunk provider"); return; } //todo: deferred load var chunkSync = chunkCache.GetChunkSync(chunkKey); if (chunkSync == null) { SendOutput("Chunk not loaded"); return; } //create reset chunk var chunk = MemoryPools.PoolChunks.AllocSync(true); if (chunk == null) { SendOutput("Couldn't allocate chunk from memory pool"); return; } chunk.X = cx; chunk.Z = cz; if (!(chunkProvider.GetTerrainGenerator() is TerrainGeneratorWithBiomeResource terrainGenerator)) { SendOutput("Couldn't load terrain generator"); return; } var random = Utils.RandomFromSeedOnPos(cx, cz, world.Seed); terrainGenerator.GenerateTerrain(world, chunk, random); chunk.NeedsDecoration = true; chunk.NeedsLightCalculation = true; DoPrefabDecorations(world, chunkProvider, chunk, random); DoEntityDecoration(world, chunkProvider, chunk, random); DoSpawnerDecorations(world, chunkProvider, chunk, random); //UPDATE CHUNK var syncRoot = chunkCache.GetSyncRoot(); lock (syncRoot) { //todo: instead of remove and add, generate the chunk then use regular setblockrpc calls to update chunk blocks //remove old chunk if (chunkCache.ContainsChunkSync(chunkKey)) { chunkCache.RemoveChunkSync(chunkKey); } if (chunkCache.ContainsChunkSync(chunk.Key)) { SendOutput("Reset chunk still exists in chunk cache"); return; } if (!chunkCache.AddChunkSync(chunk)) { MemoryPools.PoolChunks.FreeSync(chunk); SendOutput("Unable to add new chunk to cache"); return; } } var decorateWithNeigbours = typeof(ChunkProviderGenerateWorld).GetMethod(_decorateFunction, BindingFlags.NonPublic | BindingFlags.Instance); if (decorateWithNeigbours == null) { SendOutput("Couldn't access method for DecorateWithNeigbours"); return; } decorateWithNeigbours.Invoke(chunkProvider, new object[] { chunk }); chunk.InProgressRegeneration = false; chunk.NeedsCopying = true; chunk.isModified = true; SendOutput($"Chunk reset @ {cx},{cz}"); Log.Out($"{Config.ModPrefix} Chunk reset @ {cx},{cz}"); //RELOAD CHUNKS if (!(Options.ContainsKey("noreload") || Options.ContainsKey("nr"))) { BCChunks.ReloadForClients(new Dictionary <long, Chunk> { { chunkKey, chunk } }); } }