public Chunk(World world, ChunkPos chunkPos) { World = world; Pos = chunkPos; _storageKey = StorageKey.Get("ChunkData", chunkPos); var saveFile = world?.Universe?.SaveFile; var savedValue = saveFile?.ReadAsync(_storageKey)?.Result; if (savedValue != null) { var chunkData = savedValue.Deserialize <ChunkData>(); if (chunkData != null) { try { PasteChunkData(chunkData); } catch { _data = null; _isCreated = false; _chunkData = null; ContentHash = 0; } } } _saveFile = saveFile; }
// override public void SectionDeleted(ChunkPos pos) { if (basement == null && !TryToRebasement()) { Annihilate(StructureAnnihilationOrder.blockHaveNoSupport); } }
// Reads header from a chunk // leaves rdf file at Seek Position ready to read blockdata private void ReadHeader(ChunkPos pos) { long code = GetLinearRegionCoords(pos); this.pool[ConvertToRegion(pos)].file.Seek(this.pool[ConvertToRegion(pos)].index[code], SeekOrigin.Begin); this.pool[ConvertToRegion(pos)].file.Read(headerBuffer, 0, chunkHeaderSize); }
override public void Annihilate(bool clearFromSurface, bool returnResources, bool leaveRuins) { if (destroyed) { return; } else { destroyed = true; } bool initiateCheckRequest = true; ChunkPos cpos = ChunkPos.zer0; if (basement != null) { cpos = basement.pos; } else { initiateCheckRequest = false; } PrepareBuildingForDestruction(clearFromSurface, returnResources, leaveRuins); if (initiateCheckRequest) { AddonCheckRequest(cpos); } Destroy(gameObject); }
public Chunk GetChunk(int x, int z, ChunkStatus status, bool nonnull) { if (Thread.CurrentThread != _mainThread) { throw new Exception("Wrong Thread"); } var positionHash = ChunkPos.AsLong(x, z); for (int i = 0; i < 4; i++) { if (_recentPositions[i] != positionHash || _recentStatuses[i] != status) { continue; } var recentChunk = _recentChunks[i]; if (recentChunk != null || !nonnull) { return(recentChunk); } } var task = ProvideChunk(x, z, status, nonnull); var chunk = task.GetAwaiter().GetResult(); if (chunk == null && nonnull) { throw new Exception("Chunk not there when requested"); } UpdateCache(positionHash, chunk, status); return(chunk); }
// Start is called before the first frame update void Start() { this.renderDistance = World.renderDistance; regionHandler = new RegionFileHandler(renderDistance, newChunk); worldSeed = regionHandler.GetRealSeed(); biomeHandler = new BiomeHandler(BiomeSeedFunction(worldSeed)); this.worldGen = new WorldGenerator(worldSeed, BiomeSeedFunction(worldSeed), OffsetHashFunction(worldSeed), GenerationSeedFunction(worldSeed), biomeHandler, structHandler, this); // If character has been loaded if (regionHandler.playerFile.Length > 0) { player.position = regionHandler.LoadPlayer(); PLAYERSPAWNED = true; } int playerX = Mathf.FloorToInt(player.position.x / Chunk.chunkWidth); int playerZ = Mathf.FloorToInt(player.position.z / Chunk.chunkWidth); newChunk = new ChunkPos(playerX, playerZ); GetChunks(true); }
// Checks if RegionFile represents ChunkPos, and loads correct RegionFile if not public void GetCorrectRegion(ChunkPos pos) { if (!CheckUsage(pos)) { LoadRegionFile(pos); } }
// override public void SectionDeleted(ChunkPos pos) { if (basement == null && !TryToRebasement()) { Annihilate(false, false, false); } }
/// <summary> /// Returns whether a chunk is generated /// </summary> /// <param name="pos"></param> /// <returns></returns> public bool IsChunkGenerated(ChunkPos pos) { lock (_chunkMeshes) { return(_chunkMeshes.Exists(c => c.Chunk.Position.Equals(pos) && c.IsGenerated)); } }
public Chunk(ChunkPos _pos) { //references pos = _pos; //object instantiation chunkObj = new GameObject(); meshFilter = chunkObj.AddComponent <MeshFilter>(); meshRenderer = chunkObj.AddComponent <MeshRenderer>(); //material assignment materials[0] = World.Instance.material; materials[1] = World.Instance.transparentMaterial; meshRenderer.materials = materials; //setting transfroms chunkObj.transform.SetParent(World.Instance.transform); chunkObj.transform.position = new Vector3(pos.x * VoxelData.chunkWidth, 0f, pos.z * VoxelData.chunkWidth); chunkObj.name = "Chunk " + pos.x + ", " + pos.z; position = chunkObj.transform.position; chunkData = World.Instance.worldData.RequestChunk(new Vector2Int((int)position.x, (int)position.z), true); chunkData.chunk = this; World.Instance.AddChunkToUpdate(this); if (World.Instance.settings.enableAnimatedChunkLoading) { chunkObj.AddComponent <AnimateChunkLoading>(); } }
public static void AddBlockRepresentation(IPlanable s, Plane basement, ref Block myBlock, bool checkPlanes) { var chunk = basement.myChunk; ChunkPos cpos = basement.pos; switch (basement.faceIndex) { case Block.FWD_FACE_INDEX: cpos = cpos.OneBlockForward(); break; case Block.RIGHT_FACE_INDEX: cpos = cpos.OneBlockRight(); break; case Block.BACK_FACE_INDEX: cpos = cpos.OneBlockBack(); break; case Block.LEFT_FACE_INDEX: cpos = cpos.OneBlockLeft(); break; case Block.UP_FACE_INDEX: cpos = cpos.OneBlockHigher(); break; case Block.DOWN_FACE_INDEX: cpos = cpos.OneBlockDown(); break; } myBlock = chunk.AddBlock(cpos, s, false, checkPlanes); if (myBlock == null) { s.Delete(true, true, false); return; } else { chunk.RecalculateVisibilityAtPoint(myBlock.pos, s.GetAffectionMask()); } }
private BlockDistribution GenerateBlockDistribution(ChunkPos pos) { var rnd = new System.Random(persistor.GetSeed() - pos.x * 31 - pos.z * 23); double height; BlockDistribution blocks = new BlockDistribution(); bool hasTree = false; for (int x = 0; x < TerrainChunk.CHUNK_SIZE + 2; x++) { for (int z = 0; z < TerrainChunk.CHUNK_SIZE + 2; z++) { height = Math.Floor(ComputeHeightAt(pos.x + x - 1, pos.z + z - 1)); for (int y = 0; y < TerrainChunk.CHUNK_HEIGHT; y++) { blocks[x, y, z] = GetForHeight(y, height); } if (!hasTree && x > 4 && x < 12 && z > 4 && z < 12) { int r = rnd.Next(1, 115 + (int)Math.Pow(height, height / 65.0)); if (r == 2) { hasTree = true; GenerateTree(rnd, blocks, x, (int)height + 1, z); } } } } return(blocks); }
public void addLoadChunk(ChunkPos chunkIdx, ushort loadPri, Asset.LOAD_LEVEL level) { if (chunkIdx.x < 0 || chunkIdx.y < 0 || chunkIdx.x >= chunkSplit || chunkIdx.y >= chunkSplit) { return; } Common.DEBUG_MSG("WorldManager::addLoadChunk: load(" + (chunkIdx.x + 1) + "," + (chunkIdx.y + 1) + "), loaded=" + hasTerrainObjs[chunkIdx.x, chunkIdx.y, 0]); if (hasTerrainObjs[chunkIdx.x, chunkIdx.y, 0] == true) { return; } addLoadWorldObj(chunkIdx); Asset asset = new Asset(); asset.type = Asset.TYPE.TERRAIN; asset.loadPri = loadPri; asset.loadLevel = level; asset.source = getChunkName(chunkIdx) + ".unity3d"; loader.inst.loadPool.addLoad(asset); hasTerrainObjs[chunkIdx.x, chunkIdx.y, 0] = true; }
// Receives a Chunk private void SendChunk(byte[] data) { ChunkPos pos = NetDecoder.ReadChunkPos(data, 1); this.cl.toLoad.Add(data); this.cl.toLoadChunk.Add(pos); }
public Chunk PeekChunk(ChunkPos chunkPos) { Chunk chunk; _chunkMap.TryGetValue(chunkPos, out chunk); return(chunk); }
/// <summary> /// Gets the <c>DataChunk</c> from the given <paramref name="pos"/>. /// </summary> /// <param name="pos">Chunk position.</param> /// <returns><c>DataChunk</c> that exists at <paramref name="pos"/>.</returns> public static DataChunk GetChunk(ChunkPos pos) { DataChunk chunk; _chunks.TryGetValue(pos, out chunk); return(chunk); }
private bool IsInViewingFrustum(GameClient gameClient, EntityOffset offset, ChunkPos chunkPos) { /* Check if the bounding sphere of the chunk is in the viewing frustum. */ var df = (double)GeometryConstants.ChunkSize; // Determine the chunk center relative to the viewer. double dx = (chunkPos.X + 0.5) * df - offset.X; double dy = (chunkPos.Y + 0.5) * df - offset.Y; double dz = (chunkPos.Z + 0.5) * df - offset.Z; double t0, t1; // Perform mouselook rotation double ha = gameClient.PositionData.Placement.Orientation.Horizontal; double hc = Math.Cos(ha), hs = Math.Sin(ha); t0 = dx * hc - dz * hs; t1 = dz * hc + dx * hs; dx = t0; dz = t1; double va = -gameClient.PositionData.Placement.Orientation.Vertical; double vc = Math.Cos(va), vs = Math.Sin(va); t0 = dz * vc - dy * vs; t1 = dy * vc + dz * vs; dz = t0; dy = t1; // Check if the chunk is behind the viewer. if (dz > ChunkRadius && dz > ChunkRadius) { return(false); } /* TODO: We can discard even more chunks by taking the left, right, top and bottom planes into account. */ return(true); }
// Turns on and off Torch public override int OnInteract(ChunkPos pos, int blockX, int blockY, int blockZ, ChunkLoader_Server cl) { ushort state = cl.chunks[pos].metadata.GetState(blockX, blockY, blockZ); ushort newState = 0; if (state == ushort.MaxValue) { return(0); } else if (state >= 4) { cl.chunks[pos].metadata.AddToState(blockX, blockY, blockZ, -4); newState = (ushort)(state - 4); } else if (state >= 0 && state < 4) { cl.chunks[pos].metadata.AddToState(blockX, blockY, blockZ, 4); newState = (ushort)(state + 4); } NetMessage message = new NetMessage(NetCode.VFXCHANGE); message.VFXChange(pos, blockX, blockY, blockZ, 0, ushort.MaxValue, newState); cl.server.SendToClients(pos, message); return(2); }
//note i dont want this to be a co-routine because... well... its fairly simple /// <summary> /// create a chunk if it doesn't exist /// </summary> /// <param name="pos">position of the chunk</param> public void CreateChunk(ChunkPos pos) { generatingChunk = true; ChunkGenerator chunkGen = null; chunkDictionary.TryGetValue(pos, out chunkGen); if (chunkGen == null) { //instantiate a chunk at the calculated position GameObject chunkObj = (GameObject)Instantiate(chunk, new Vector3(pos.x * chunkSize, 0f, pos.z * chunkSize), Quaternion.identity); chunkObj.transform.parent = transform; int actualChunkX = pos.x * chunkSize; int actualChunkZ = pos.z * chunkSize; //add the chunk object spawned to the dictionary... well the ChunkGenerator script part of the object anyways chunkDictionary.Add(pos, chunkObj.GetComponent<ChunkGenerator>()); chunkObj.GetComponent<ChunkGenerator>().init(chunkSize, actualChunkX, actualChunkZ); chunkObj.name = "chunk_x" + pos.x + "_z" + pos.z; // set the name property to know where it is in the world through the inspector // Debug.Log("derped out around here, name:" + chunkObj.name); } generatingChunk = false; }
// Re-acquires every chunk that is possibly not loaded and adds all chunks that need redraw (except borders) to redraw list private void FixUnloaded() { ChunkPos newChunk; this.message = new NetMessage(NetCode.REQUESTCHUNKLOAD); for (int x = -World.renderDistance; x < World.renderDistance; x++) { for (int z = -World.renderDistance; z < World.renderDistance; z++) { newChunk = new ChunkPos(this.currentChunk.x + x, this.currentChunk.z + z); if (!this.chunks.ContainsKey(newChunk) && !this.toLoadChunk.Contains(newChunk)) { this.message.RequestChunkLoad(newChunk); client.Send(this.message.GetMessage(), this.message.size); continue; } if (this.chunks.ContainsKey(newChunk)) { if (!this.chunks[newChunk].drawMain && !this.toDraw.Contains(newChunk)) { this.toDraw.Add(newChunk); } } } } }
// Client handling the creation of the VFX public override int OnVFXBuild(ChunkPos pos, int blockX, int blockY, int blockZ, int facing, ushort state, ChunkLoader cl) { Vector3 fireOffset; if (facing == 0) { fireOffset = new Vector3(0.15f, 0f, 0f); } else if (facing == 1) { fireOffset = new Vector3(0f, 0f, -0.15f); } else if (facing == 2) { fireOffset = new Vector3(-0.15f, 0f, 0f); } else if (facing == 3) { fireOffset = new Vector3(0f, 0f, 0.15f); } else { fireOffset = new Vector3(0f, 0f, 0f); } GameObject fire = GameObject.Instantiate(this.fireVFX, new Vector3(pos.x * Chunk.chunkWidth + blockX, blockY + 0.35f, pos.z * Chunk.chunkWidth + blockZ) + fireOffset, Quaternion.identity); fire.name = BuildVFXName(pos, blockX, blockY, blockZ); this.vfx.Add(pos, fire, active: true, isOnDemandLight: true); ControlFire(pos, blockX, blockY, blockZ, state); return(0); }
// Loads the chunk into the Chunkloader private void LoadChunk() { if (toLoad.Count > 0) { int min; // Sets the current iteration amount if (3 <= toLoad.Count) { min = 3; } else { min = toLoad.Count; } for (int i = 0; i < min; i++) { byte[] data = toLoad[0]; int headerSize = RegionFileHandler.chunkHeaderSize; ChunkPos cp = NetDecoder.ReadChunkPos(data, 1); // Prevention if (this.chunks.ContainsKey(cp)) { this.chunks[cp].Destroy(); this.chunks.Remove(cp); } int blockDataSize = NetDecoder.ReadInt(data, 9); int hpDataSize = NetDecoder.ReadInt(data, 13); int stateDataSize = NetDecoder.ReadInt(data, 17); this.chunks[cp] = new Chunk(cp, this.rend, this.blockBook, this); this.chunks[cp].biomeName = BiomeHandler.ByteToBiome(data[21]); Compression.DecompressBlocksClient(this.chunks[cp], data, initialPos: 21 + headerSize); Compression.DecompressMetadataHPClient(this.chunks[cp], data, initialPos: 21 + headerSize + blockDataSize); Compression.DecompressMetadataStateClient(this.chunks[cp], data, initialPos: 21 + headerSize + blockDataSize + hpDataSize); if (this.vfx.data.ContainsKey(cp)) { this.vfx.RemoveChunk(cp); } this.vfx.NewChunk(cp); if (!this.toDraw.Contains(cp)) { this.toDraw.Add(cp); } toLoad.RemoveAt(0); toLoadChunk.RemoveAt(0); } } }
// Adds chunk to Update queue public void AddToUpdate(ChunkPos pos, bool noLight = false) { if (!noLight) { if (!toUpdate.Contains(pos)) { toUpdate.Add(pos); } else { toUpdate.Remove(pos); toUpdate.Add(pos); } } else { if (!toUpdateNoLight.Contains(pos)) { toUpdateNoLight.Add(pos); } else { toUpdateNoLight.Remove(pos); toUpdateNoLight.Add(pos); } } }
public void onNewTerrain(ChunkPos currpos, UnityEngine.GameObject go) { Common.DEBUG_MSG("WorldManager::onNewTerrain: " + go.name + ", pos=" + go.transform.position + ", dir=" + go.transform.rotation + ", scale=" + go.transform.localScale); autoSetNeighbors(currpos); }
protected override void loadChunks(ChunkPos occupiedChunkPos) { int x, y, z; bool flagX, flagY, flagZ, isReadOnly; for (x = -this.loadRadius; x <= this.loadRadius; x++) { for (y = -this.loadRadius; y <= this.loadRadius; y++) { for (z = -this.loadRadius; z <= this.loadRadius; z++) { flagX = Math.Abs(x) == loadRadius; flagY = Math.Abs(y) == loadRadius; flagZ = Math.Abs(z) == loadRadius; isReadOnly = flagX || flagY || flagZ; NewChunkInstructions instructions = new NewChunkInstructions(x + occupiedChunkPos.x, y + occupiedChunkPos.y, z + occupiedChunkPos.z, isReadOnly); Chunk chunk = world.getChunk(instructions.chunkPos); if (chunk == null) { if (!this.buildQueue.Contains(instructions)) { this.buildQueue.Enqueue(instructions); } } else { chunk.isReadOnly = isReadOnly; } } } } }
private void RemoveBlockVisualisers(ChunkPos cpos) // удаление всей рендер-информации для данного блока { bool corrections = false; MeshVisualizeInfo mvi; int i = 0; while (i < blockVisualizersList.Count) { if (blockVisualizersList[i].pos == cpos) { mvi = blockVisualizersList[i].meshInfo; if (!redrawRequiredTypes.Contains(mvi)) { redrawRequiredTypes.Add(mvi); } blockVisualizersList.RemoveAt(i); corrections = true; continue; } else { i++; } } if (corrections) { chunkRenderUpdateRequired = true; } }
// Redraws lights in current and adjascent chunks in scene on Demand public void UpdateLights(ChunkPos pos, bool adjascent = true) { if (!VFXLoader.EXTRALIGHTSHADOWS) { return; } // Updates all lights in current chunk foreach (HDAdditionalLightData light in this.lightReference[pos]) { light.RequestShadowMapRendering(); } if (adjascent) { ChunkPos[] neighbors = { new ChunkPos(pos.x - 1, pos.z - 1), new ChunkPos(pos.x - 1, pos.z), new ChunkPos(pos.x - 1, pos.z + 1), new ChunkPos(pos.x, pos.z - 1), new ChunkPos(pos.x, pos.z + 1), new ChunkPos(pos.x + 1, pos.z - 1), new ChunkPos(pos.x + 1, pos.z), new ChunkPos(pos.x + 1, pos.z + 1) }; // Updates all lights in neighbor chunks foreach (ChunkPos iterPos in neighbors) { if (ContainsLight(iterPos)) { foreach (HDAdditionalLightData light in this.lightReference[iterPos]) { light.RequestShadowMapRendering(); } } } } }
/* * BiomeHandler's main function * Used to assign a biome to a new chunk. * Play arround with the seed value in each of the 4 biome features to change the behaviour * of the biome distribution. */ public byte Assign(ChunkPos pos) { float currentAltitude = Perlin.Noise(pos.x * BiomeHandlerData.featureModificationConstant * BiomeHandlerData.ax + ((dispersionSeed * BiomeHandlerData.ss) % 1000), pos.z * BiomeHandlerData.featureModificationConstant * BiomeHandlerData.az + ((dispersionSeed * BiomeHandlerData.sx) % 1000)); float currentHumidity = Perlin.Noise(pos.x * BiomeHandlerData.featureModificationConstant * BiomeHandlerData.bx + ((dispersionSeed * BiomeHandlerData.ss) % 1000), pos.z * BiomeHandlerData.featureModificationConstant * BiomeHandlerData.bz + ((dispersionSeed * BiomeHandlerData.sy) % 1000)); float currentTemperature = Perlin.Noise(pos.x * BiomeHandlerData.featureModificationConstant * BiomeHandlerData.cx + ((dispersionSeed * BiomeHandlerData.ss) % 1000), pos.z * BiomeHandlerData.featureModificationConstant * BiomeHandlerData.cz + ((dispersionSeed * BiomeHandlerData.sz) % 1000)); float currentLightning = Perlin.Noise(pos.x * BiomeHandlerData.featureModificationConstant * BiomeHandlerData.dx + ((dispersionSeed * BiomeHandlerData.ss) % 1000), pos.z * BiomeHandlerData.featureModificationConstant * BiomeHandlerData.dz + ((dispersionSeed * BiomeHandlerData.sw) % 1000)); float lowestDistance = 99; byte lowestBiome = 255; float distance; float4 currentSettings = new float4(currentAltitude, currentHumidity, currentTemperature, currentLightning); for (byte s = 0; s < amountOfBiomes; s++) { distance = BiomeHandler.Distance(currentSettings, BiomeHandlerData.codeToStats[s]); if (distance <= lowestDistance) { lowestDistance = distance; lowestBiome = s; } } return(lowestBiome); }
private void SendChunkDataTo(EndPoint ep, GenericMessage msg) { var chp = new ChunkPos((int)msg.ReadSignedInteger(), (int)msg.ReadSignedInteger()); var chunk = _world.GetChunk(chp); if (!chunk.HasData) { _world.LoadChunk(chp); } var raw = chunk.GetRaw(); var m = new GenericMessage(); m.WriteUnsignedInteger(1); m.WriteSignedInteger((uint)chp.x); m.WriteSignedInteger((uint)chp.z); var data = new byte[raw.Length]; Buffer.BlockCopy(raw, 0, data, 0, data.Length); m.WriteUnsignedInteger((uint)data.Length); m.WriteByteArray(data); _server.SendToAsync(ep, m); }
public void DeleteBlock(ChunkPos pos, bool compensateStructures) { // в сиквеле стоит пересмотреть всю иерархию классов >< //12.06 нет, я так не думаю // 24.04.2019 фига сколько времени прошло // 26.01.2020 ну привет Block b = GetBlock(pos); if (b == null) { return; } int x = pos.x, y = pos.y, z = pos.z; if (b.ContainSurface()) { needSurfacesUpdate = true; } var affectionMask = b.GetAffectionMask(); b.Annihilate(compensateStructures); blocks.Remove(b.pos); RemoveBlockVisualisers(b.pos); if (PoolMaster.useIlluminationSystem) { RecalculateIlluminationAtPoint(pos); } if (affectionMask != 0) { if ((affectionMask & (1 << Block.FWD_FACE_INDEX)) != 0) { GetBlock(pos.OneBlockForward())?.InitializePlane(Block.BACK_FACE_INDEX); } if ((affectionMask & (1 << Block.RIGHT_FACE_INDEX)) != 0) { GetBlock(pos.OneBlockRight())?.InitializePlane(Block.LEFT_FACE_INDEX); } if ((affectionMask & (1 << Block.BACK_FACE_INDEX)) != 0) { GetBlock(pos.OneBlockBack())?.InitializePlane(Block.FWD_FACE_INDEX); } if ((affectionMask & (1 << Block.UP_FACE_INDEX)) != 0) { GetBlock(pos.OneBlockHigher())?.InitializePlane(Block.DOWN_FACE_INDEX); } if ((affectionMask & (1 << Block.LEFT_FACE_INDEX)) != 0) { GetBlock(pos.OneBlockLeft())?.InitializePlane(Block.RIGHT_FACE_INDEX); } if ((affectionMask & (1 << Block.DOWN_FACE_INDEX)) != 0) { GetBlock(pos.OneBlockDown())?.InitializePlane(Block.UP_FACE_INDEX); } RecalculateVisibilityAtPoint(pos, affectionMask); } shadowsUpdateRequired = true; chunkDataUpdateRequired = true; // chunkRenderUpdateRequired = true; < в свитче }
private void LateUpdate() { var position = tf.position; //get the terrain chunk (can't just use collider) int chunkPosX = Mathf.FloorToInt((position.x + offset.x) / 16f) * 16; int chunkPosZ = Mathf.FloorToInt((position.z + offset.z) / 16f) * 16; ChunkPos cp = new ChunkPos(chunkPosX, chunkPosZ); int bix = Mathf.FloorToInt(position.x + offset.x) - chunkPosX; int biy = Mathf.FloorToInt(position.y + offset.y); int biz = Mathf.FloorToInt(position.z + offset.z) - chunkPosZ; inBlock = TerrainGenerator.getBlock(cp, bix, biy, biz); if (text != null) { text.text = "" + inBlock; } /*if (Input.GetKeyDown(KeyCode.LeftControl)) * { * TerrainGenerator.updateChunk(cp, (blocks, updateBlock) => * { * updateBlock(bix+1, biy, biz+1, BlockType.Dirt); * }); * }*/ }
public IChunk this[ChunkPos pos] { get { TerrainChunk chunk; return (_chunks.TryGetValue(pos, out chunk) ? (IChunk)chunk : new EmptyChunk(this, pos, default(BlockData))); } }
public TerrainChunk CreateChunk(ChunkPos pos) { if (_chunks.ContainsKey(pos)) throw new InvalidOperationException(string.Format( "Chunk at {0} already exists", pos)); var chunkObject = new GameObject("Chunk: " + pos) { hideFlags = HideFlags.HideInHierarchy }; var chunk = chunkObject.AddComponent<TerrainChunk>(); chunk.terrain = this; chunk.position = pos; chunk.transform.parent = transform; chunk.transform.localPosition = pos.ToVector3(); chunk.transform.localRotation = Quaternion.identity; chunk.transform.localScale = Vector3.one; _chunks[pos] = chunk; return chunk; }
/// <summary> /// render the chunk at the given position, this assumes that the chunk has been generated beforehand, /// if not it will call CreateChunk on it... as a safeguard... /// and it will create the chunks on each side of this, to be able to render the edges of this chunk properly /// </summary> /// <param name="pos">position of the chunk</param> public IEnumerator RenderChunk(ChunkPos pos) { generatingChunk = true; ChunkGenerator chunk = null; chunkDictionary.TryGetValue(pos, out chunk); if (chunk == null) { CreateChunk(pos); chunkDictionary.TryGetValue(pos, out chunk); } //generate the chunks on each side of the chunk, no need to render them, just generate, this is needed to calculate the edges of a chunk List<ChunkPos> positionsAroundTheChunk = new List<ChunkPos>();//why a list? why not, faster than arrays, and pretty syntax positionsAroundTheChunk.Add(new ChunkPos(pos.x+1, pos.z)); positionsAroundTheChunk.Add(new ChunkPos(pos.x-1, pos.z)); positionsAroundTheChunk.Add(new ChunkPos(pos.x, pos.z+1)); positionsAroundTheChunk.Add(new ChunkPos(pos.x, pos.z-1)); foreach (ChunkPos posToGen in positionsAroundTheChunk) { //make a new thread for each chunk needed to be generated CreateChunk(posToGen); yield return new WaitForSeconds(0.1f); } yield return new WaitForSeconds(0.05f); //wait a short while chunk.Render(); generatingChunk = false; }
IEnumerator GenerateChunksInASpiral() { generatingWorld = true; Vector3 playerPos = player.transform.position; //position of the player in "Chunk coords" int playerChunkXPos = (int)(playerPos.x / chunkSize); int playerChunkZPos = (int)(playerPos.z / chunkSize); //spiral loop variables Vector2 loopPos = new Vector2(playerChunkXPos, playerChunkZPos); dir currentDir = dir.xUp; bool addAnotherIteration = false; //loop that every time it runs through changes direction, every 2nd time it runs through adds another block to the end of the line, //and every 4th time ( thisloop/2 ) knows its made another layer //this results in something like http://gyazo.com/c8daf4c2a000e11d4ac004e00d9ad21b ... hopefully //gif from before fuckup #86 http://gyazo.com/1d8ffa8b586a99576c44f41491146eee int maxInARow = 5; for (int thisLoop = 0; (thisLoop/2) <= radiusToGenerateAroundPlayer; ) { //create lines of chunks in the direction of 'currentDir', this is results in a spiral and player didn't change pos for (int delta = 0; delta <= thisLoop && !PlayerPosHasChanged; delta++) { #region generateChunkAtPos //wait while it finishes generating chunks while(generatingChunk) { yield return new WaitForSeconds(2f); } ChunkPos pos = new ChunkPos((int)loopPos.x, (int)loopPos.y); if (loadedUp)// load the world up before rendering CreateChunkAndRender(pos); else CreateChunk(pos); //yield return new WaitForEndOfFrame(); #endregion //change position of next chunk depending on the direction the loop wants it to spawn in switch (currentDir) { case dir.xDown: loopPos.x--; break; case dir.xUp: loopPos.x++; break; case dir.yDown: loopPos.y--; break; case dir.yUp: loopPos.y++; break; } if (maxInARow <= 0) { yield return new WaitForSeconds(0.3f); maxInARow = 2; } maxInARow--; } yield return new WaitForSeconds(0.5f); //add another iteration to this loop every 2nd time it runs through if (addAnotherIteration) { thisLoop++; addAnotherIteration = false; } else { addAnotherIteration = true; } //switch direction of the loop if ((int)currentDir == 3) currentDir = 0; else currentDir++; } deleteOldChunks(playerChunkXPos, playerChunkZPos); yield return new WaitForSeconds(1f); //when the world has been generated around the player wait for a second before attempting to create it again if (!loadedUp) PlayerPosHasChanged = true;//make it re-run the loadworld when the map has been generated loadedUp = true; generatingWorld = false; spiralsInProgress--; }
/// <summary> /// create and render the chunk /// </summary> /// <param name="pos">position of the chunk to create & render</param> public void CreateChunkAndRender(ChunkPos pos) { CreateChunk(pos); StartCoroutine(RenderChunk(pos)); }
/// <summary> /// finds the name of the file of where to put/get the chunk /// </summary> /// <param name="pos">position of the chunk</param> /// <returns></returns> public static string saveFileName(ChunkPos pos) { string fileName = pos.x + "," + pos.z + ".bin"; return fileName; }
public EmptyChunk(Terrain terrain, ChunkPos pos, BlockData @default) { this.terrain = terrain; position = pos; _default = @default; }
public void loadCurrentViewChunks() { if(RPG_Animation.instance == null) { Common.DEBUG_MSG("WorldManager::loadCurrentViewChunks: RPG_Animation=" + RPG_Animation.instance); return; } ChunkPos currentPos = atChunk(); if(lastChunkPos.x == currentPos.x && lastChunkPos.y == currentPos.y) return; Vector3 playerpos = RPG_Animation.instance.transform.position; playerpos.y = 0.0f; Common.DEBUG_MSG("WorldManager::loadCurrentViewChunks: pos(" + playerpos + "), changeChunk(" + (lastChunkPos.x + 1) + "," + (lastChunkPos.y + 1) + ") ==> (" + (currentPos.x + 1) + "," + (currentPos.y + 1) + ")"); lastChunkPos = currentPos; // center addLoadChunk(currentPos, 0, Asset.LOAD_LEVEL.LEVEL_ENTER_AFTER); for(int i=0; i<chunkSplit; i++) { for(int ii=0; ii<chunkSplit; ii++) { int xdiff = Math.Abs(i - currentPos.x); int ydiff = Math.Abs(ii - currentPos.y); if(xdiff <= 1 && ydiff <= 1) { if(hasTerrainObjs[i, ii, 0] == true) { continue; } ChunkPos cpos; cpos.x = i; cpos.y = ii; addLoadChunk(cpos, 1, Asset.LOAD_LEVEL.LEVEL_ENTER_AFTER); } else { if(xdiff <= 2 && ydiff <= 2) { continue; } if(canUnloadChunk == false) continue; if(hasTerrainObjs[i, ii, 0] == true) { Common.DEBUG_MSG("WorldManager::loadCurrentViewChunks: unload(" + (i + 1) + "," + (ii + 1) + ")"); hasTerrainObjs[i, ii, 0] = false; UnityEngine.GameObject obj = terrainObjs[i, ii, 0]; if(obj != null) { allterrainObjs.Remove(obj); UnityEngine.GameObject.Destroy(obj); } terrainObjs[i, ii, 0] = null; Asset asset = terrainAssetBundles[i, ii, 0]; if(asset != null) { asset.bundle.Unload(true); terrainAssetBundles[i, ii, 0] = null; } clearSceneObjAtPoint(i, ii, false); } } } } loader.inst.loadPool.start(); }
public void init(int chunkSize, int actualChunkX, int actualChunkZ, bool generateColumnsPerFrame = false) { tallestPoint = 0; solid = new BlockData(BlockData.BlockType.stone, new Vector3(),20); this.chunkSize = chunkSize; actualChunkCoords = new ChunkPos(actualChunkX, actualChunkZ); filter = gameObject.GetComponent<MeshFilter>(); collider = gameObject.GetComponent<MeshCollider>(); WG = GetComponentInParent<WorldGenerator>(); bool loaded = WorldSaver.LoadChunk(this); if (!loaded) { Blocks = new BlockData[chunkSize, airLimit, chunkSize]; //fill the entire array of blocks with air for (int x = 0; x < chunkSize; x++) { for (int y = 0; y < airLimit; y++) { for (int z = 0; z < chunkSize; z++) { Blocks[x, y, z] = new BlockData(BlockData.BlockType.air, new Vector3((actualChunkX + x), y, (actualChunkZ + z)),20); } } } CalculateChunk(actualChunkX, actualChunkZ); } }
public bool hasChunk(ChunkPos chunkIdx) { if(chunkIdx.x <= 0 || chunkIdx.y <= 0) return false; return hasTerrainObjs[chunkIdx.x, chunkIdx.y, 0]; }
void autoSetNeighbors(ChunkPos pos) { int arrayPos = 0; int terrainsLong = chunkSplit; int terrainsWide = chunkSplit; Terrain[] terrains = new Terrain[terrainsLong * terrainsWide]; for(int y = 0; y < terrainsLong ; y++) { for(int x = 0; x < terrainsWide; x++) { if(terrainObjs[x, y, 0] != null) terrains[arrayPos] = terrainObjs[x, y, 0].GetComponent<Terrain>(); else terrains[arrayPos] = null; arrayPos++; } } arrayPos = 0; for(int y = 0; y < terrainsLong ; y++) { for(int x = 0; x < terrainsWide; x++) { if(terrains[arrayPos] == null) { arrayPos++; continue; } if(y == 0) { if(x == 0) terrains[arrayPos].SetNeighbors(null, terrains[arrayPos + terrainsWide], terrains[arrayPos + 1], null); else if(x == terrainsWide - 1) terrains[arrayPos].SetNeighbors(terrains[arrayPos - 1], terrains[arrayPos + terrainsWide], null, null); else terrains[arrayPos].SetNeighbors(terrains[arrayPos - 1], terrains[arrayPos + terrainsWide], terrains[arrayPos + 1], null); } else if(y == terrainsLong - 1) { if(x == 0) terrains[arrayPos].SetNeighbors(null, null, terrains[arrayPos + 1], terrains[arrayPos - terrainsWide]); else if(x == terrainsWide - 1) terrains[arrayPos].SetNeighbors(terrains[arrayPos - 1], null, null, terrains[arrayPos - terrainsWide]); else terrains[arrayPos].SetNeighbors(terrains[arrayPos - 1], null, terrains[arrayPos + 1], terrains[arrayPos - terrainsWide]); } else { if(x == 0) terrains[arrayPos].SetNeighbors(null, terrains[arrayPos + terrainsWide], terrains[arrayPos + 1], terrains[arrayPos - terrainsWide]); else if(x == terrainsWide - 1) terrains[arrayPos].SetNeighbors(terrains[arrayPos - 1], terrains[arrayPos + terrainsWide], null, terrains[arrayPos - terrainsWide]); else terrains[arrayPos].SetNeighbors(terrains[arrayPos - 1], terrains[arrayPos + terrainsWide], terrains[arrayPos + 1], terrains[arrayPos - terrainsWide]); } arrayPos++; } } /* for(int i = 0; i < terrainsWide*terrainsLong ; i++) { if(terrains[i] != null) terrains[i].Flush(); } */ }
public void addLoadChunk(ChunkPos chunkIdx, ushort loadPri, Asset.LOAD_LEVEL level) { if(chunkIdx.x < 0 || chunkIdx.y < 0 || chunkIdx.x >= chunkSplit || chunkIdx.y >= chunkSplit) return; Common.DEBUG_MSG("WorldManager::addLoadChunk: load(" + (chunkIdx.x + 1) + "," + (chunkIdx.y + 1) + "), loaded=" + hasTerrainObjs[chunkIdx.x, chunkIdx.y, 0]); if(hasTerrainObjs[chunkIdx.x, chunkIdx.y, 0] == true) return; addLoadWorldObj(chunkIdx); Asset asset = new Asset(); asset.type = Asset.TYPE.TERRAIN; asset.loadPri = loadPri; asset.loadLevel = level; asset.source = getChunkName(chunkIdx) + ".unity3d"; loader.inst.loadPool.addLoad(asset); hasTerrainObjs[chunkIdx.x, chunkIdx.y, 0] = true; }
public bool loadedChunk(ChunkPos chunkIdx) { if(chunkIdx.x <= 0 || chunkIdx.y <= 0) return false; UnityEngine.GameObject obj = terrainObjs[chunkIdx.x, chunkIdx.y, 0]; if(obj != null) { return obj.GetComponent<Terrain>().enabled; } return false; }
public void addLoadWorldObj(ChunkPos chunkIdx) { Vector3 currpos = RPG_Animation.instance.transform.position; currpos.y = 0.0f; worldObjs[chunkIdx.x, chunkIdx.y, 0].Sort(delegate(WorldSceneObject x, WorldSceneObject y) { Vector3 pos1 = new Vector3(x.position.x, 0.0f, y.position.z); Vector3 pos2 = new Vector3(x.position.x, 0.0f, y.position.z); float dist1 = Vector3.Distance(pos1, currpos); float dist2 = Vector3.Distance(pos2, currpos); if(dist1 < dist2) return -1; if(dist1 > dist2) return 1; return 0; } ); foreach(WorldSceneObject obj in worldObjs[chunkIdx.x, chunkIdx.y, 0]) { Common.DEBUG_MSG("WorldManager::addLoadWorldObj:" + obj.asset.source + ", isLoaded:" + obj.asset.isLoaded + ", loading:" + obj.asset.loading); if(obj.asset.isLoaded == false && obj.asset.loading == false) { SceneObject hasObj = null; if(parentScene.objs.TryGetValue(obj.idkey, out hasObj)) { continue; } obj.asset.loadLevel = Asset.LOAD_LEVEL.LEVEL_ENTER_AFTER; parentScene.addSceneObject(obj.idkey, obj); obj.asset.refs.Add(obj.idkey); loader.inst.loadPool.addLoad(obj.asset); } else { if(obj.gameObject == null && obj.asset.isLoaded == true) { obj.Instantiate(); obj.asset.refs.Remove(obj.idkey); } } } }
public string getChunkName(ChunkPos chunkIdx) { return terrainName + "_" + (chunkIdx.y + 1) + "_" + (chunkIdx.x + 1); }