Esempio n. 1
0
    public void Reset(
        Vector2 worldSize, byte[] terrainV2Data,
        bool loadingDataFromBeforeDigging,
        byte[] legacyData,
        ulong[] customStyleWorkshopIds = null,
        string simpleData = null)
    {
        Debug.Assert(worldSize.magnitude > 0f);
        Util.Log($"Resetting terrain!");

        float groundSizeX = worldSize.x;
        float groundSizeZ = worldSize.y;

        var newDims = new Int3(
            Mathf.CeilToInt(groundSizeX / BLOCK_SIZE.x),
            BlocksYCount,
            Mathf.CeilToInt(groundSizeZ / BLOCK_SIZE.z));

        Debug.Assert(newDims >= new Int3(10, 10, 10));

        Int3 newBotCenter = new Int3(newDims.x / 2, 0, newDims.z / 2);

        // If old data exists, make sure we restore it. This is the resize use case.
        byte[] restoreData = null;
        Int3   restoreDims = Int3.zero();

        if (terrainV2 != null)
        {
            var oldDims = terrainV2.GetWorldDimensions();
            restoreDims = Int3.Min(oldDims, newDims);
            Int3 start = oldDims / 2 - restoreDims / 2;
            Int3 end   = start + restoreDims;
            Debug.Assert(start >= Int3.zero());
            Debug.Assert(end <= oldDims);
            restoreData = terrainV2.Serialize(start, end);

            Destroy(terrainV2.gameObject);
            terrainV2 = null;
        }

        using (Util.Profile("terrainV2 instantiate"))
            terrainV2 = Instantiate(terrainV2Prefab, Vector3.zero, Quaternion.identity, this.transform);

        using (Util.Profile("terrainV2 SetWorldDimensions"))
            terrainV2.SetWorldDimensions(newDims);

        terrainV2.SetRootOffset(new Vector3(
                                    -newDims.x / 2 * 2.5f,
                                    BlocksYStart * BlockHeight + BlockHeight / 2f,
                                    -newDims.z / 2 * 2.5f));

        using (Util.Profile("Create color terrain textures"))
        {
            int texSize = terrainV2.GetStyleTextureResolution();
            // Color32 way faster in general than Color.
            for (int i = 0; i < NumSolidColorStyles; i++)
            {
                Color32[] pixels  = new Color32[texSize * texSize];
                Color32   color32 = rendering.blockColors[i];
                for (int j = 0; j < pixels.Length; j++)
                {
                    pixels[j] = color32;
                }
                terrainV2.SetStyleTextures(i, pixels); // color

                // 10 is orange
                if (i == (int)BlockStyle.SolidColor10)
                {
                    fallbackTexture = pixels;
                }
            }
        }

        Debug.Assert(fallbackTexture != null, "Could not find fallbackTexture?");

        // TODO why do we do these specifically? Are they not read in via the loop below?
        terrainV2.SetStyleTextures((int)BlockStyle.Stone, terrainV2Textures[4].GetPixels32());                                                                              // stone
        terrainV2.SetStyleTextures((int)BlockStyle.Space, terrainV2Textures[1].GetPixels32());                                                                              // metal
        terrainV2.SetStyleTextures((int)BlockStyle.Grass, terrainV2Textures[8].GetPixels32(), terrainV2Textures[7].GetPixels32(), terrainV2Textures[6].GetPixels32());      // grass
        terrainV2.SetStyleTextures((int)BlockStyle.SnowRock, terrainV2Textures[11].GetPixels32(), terrainV2Textures[10].GetPixels32(), terrainV2Textures[9].GetPixels32()); // snow

        foreach (object obj in Enum.GetValues(typeof(BlockStyle)))
        {
            BlockStyle style = (BlockStyle)obj;
            if ((int)style <= (int)BlockStyle.SnowRock)
            {
                // We hard code this above for now.
                continue;
            }
            Color32[] topOrAtlas = null;
            Color32[] side       = null;
            Color32[] overflow   = null;
            foreach (var tex in terrainV2Textures)
            {
                if (tex == null)
                {
                    continue;
                }
                if (!tex.name.StartsWith(style.ToString().ToLowerInvariant()))
                {
                    continue;
                }

                if (tex.name.EndsWith("-top") || tex.name == style.ToString().ToLowerInvariant())
                {
                    topOrAtlas = tex.GetPixels32();
                }
                else if (tex.name.EndsWith("-side-ceiling"))
                {
                    side = tex.GetPixels32();
                }
                else if (tex.name.EndsWith("-overflow"))
                {
                    overflow = tex.GetPixels32();
                }
            }

            if (topOrAtlas == null)
            {
                Util.LogWarning($"Had to use fallback texture for terrain style {style}. side={side}, overflow={overflow}");
                topOrAtlas = fallbackTexture;
            }

            if (side != null)
            {
#if UNITY_EDITOR
                Debug.Assert(overflow != null, $"{style.ToString()} style has a side texture but not an overflow?");
#endif
            }
            else
            {
                if (overflow != null)
                {
                    Util.LogWarning($"Style {style} had an overflow texture but not a side? IGNORING overflow.");
                    overflow = null;
                }
            }

            terrainV2.SetStyleTextures((int)style, topOrAtlas, side, overflow);
        }

        // Custom styles
        this.customStyleWorkshopIds.Clear();
        if (customStyleWorkshopIds != null)
        {
            this.customStyleWorkshopIds.AddRange(customStyleWorkshopIds);
        }
        UpdateCustomStyleWorkshopIds();

        if (restoreData != null)
        {
            terrainV2.Deserialize(restoreData, (newDims / 2 - restoreDims / 2));
        }

        if (legacyData != null)
        {
            LoadLegacyTerrainData(legacyData);

            // But move all the blocks to our new system.
            using (Util.Profile("legacySync"))
            {
                foreach (var args in database.EnumerateBlocks())
                {
                    terrainV2.SetCell(args.cell.ToInt3() + GetV2Offset(), (int)args.value.style, (int)args.value.blockType - 1, (int)args.value.direction);
                }
            }
        }

        if (terrainV2Data != null)
        {
            Util.Log($"loading v2 data of {terrainV2Data.Length} bytes");
            using (Util.Profile("terrainV2 Deserialize"))
                terrainV2.Deserialize(terrainV2Data);

            // Legacy upgrade
            if (loadingDataFromBeforeDigging)
            {
                // The serialized data was before digging. We need to move it up, effectively.
                Debug.Assert(BlocksYStart < 0);
                // Copy...
                byte[] temp = terrainV2.Serialize(
                    Int3.zero(),
                    newDims.WithY(newDims.y + BlocksYStart));
                // Move up..
                terrainV2.Deserialize(
                    temp,
                    Int3.zero().WithY(-BlocksYStart));

                // At this point, we actually have 2 copies of the terrain, offset by
                // some Y! heh. But the SetSlices call below will deal with that.
            }
        }

        if (loadingDataFromBeforeDigging)
        {
            // Fill in the ground.
            BlockStyle style = BlockStyle.Grass;
            switch (stage.GetGroundType())
            {
            case GameBuilderStage.GroundType.Snow:
                style = BlockStyle.SnowRock;
                break;

            case GameBuilderStage.GroundType.SolidColor:
            case GameBuilderStage.GroundType.Space:
            case GameBuilderStage.GroundType.Grass:
            default:
                style = BlockStyle.Grass;
                break;
            }
            terrainV2.SetSlices(0, (0 - BlocksYStart), (int)style, 0, 0);
        }

        if (!simpleData.IsNullOrEmpty())
        {
            byte[] zippedBytes = System.Convert.FromBase64String(simpleData);
            using (var zippedStream = new System.IO.MemoryStream(zippedBytes, 0, zippedBytes.Length))
                using (var unzipped = new System.IO.Compression.GZipStream(zippedStream, System.IO.Compression.CompressionMode.Decompress))
                    using (System.IO.BinaryReader reader = new System.IO.BinaryReader(unzipped))
                    {
                        int version = reader.ReadUInt16(); // Unused.
                        Debug.Assert(version == 0, $"Unknown simpleData version: {version}");
                        uint numBlocks = reader.ReadUInt32();
                        Util.Log($"reading in {numBlocks} from simpleData");
                        for (int i = 0; i < numBlocks; i++)
                        {
                            short  x         = reader.ReadInt16();
                            short  y         = reader.ReadInt16();
                            short  z         = reader.ReadInt16();
                            byte   shape     = reader.ReadByte();
                            byte   direction = reader.ReadByte();
                            ushort style     = reader.ReadUInt16();
                            this.SetCellValue(
                                new Cell(x, y, z),
                                new CellValue
                            {
                                blockType = (BlockShape)shape,
                                direction = (BlockDirection)direction,
                                style     = (BlockStyle)style
                            });
                        }
                    }
        }

        // Now mark chunks with actors in them as important
        foreach (var actor in engine.EnumerateActors())
        {
            // Non-dynamic-physics actors don't need terrain to exist...well, less so.
            if (!actor.GetEnablePhysics())
            {
                continue;
            }
            var  pos  = actor.GetSpawnPosition();
            Int3 cell = GetContainingCell(pos).ToInt3();
            terrainV2.ReportRigidbodyAt((cell + GetV2Offset()));
        }
    }