void ExpandWidth(int newWidth)
    {
        ChunkSet[] newMap = new ChunkSet[currentHeight * newWidth];

        if (map != null)
        {
            int upperBound = currentWidth;

            if (currentWidth > newWidth)
            {
                upperBound = newWidth;
            }

            for (int x = 0; x < upperBound; x++)
            {
                for (int y = 0; y < currentHeight; y++)
                {
                    int index = y * currentWidth + x;

                    ChunkSet n = map[index];

                    index = y * newWidth + x;

                    newMap[index] = n;
                }
            }
        }

        map = newMap;

        currentWidth = newWidth;
    }
    void ExpandHeight(int newHeight)
    {
        ChunkSet[] newMap = new ChunkSet[newHeight * currentWidth];

        if (map != null)
        {
            int upperBound = currentHeight;

            if (currentHeight > newHeight)
            {
                upperBound = newHeight;
            }

            //When expanding height, we don't need to do any tricky mathematics to cater for one-dimensional array storage
            for (int x = 0; x < currentWidth; x++)
            {
                for (int y = 0; y < upperBound; y++)
                {
                    int index = y * currentWidth + x;

                    ChunkSet n = map[index];

                    newMap[index] = n;
                }
            }
        }
        map = newMap;

        currentHeight = newHeight;
    }
    void SetNodeAt(ChunkSet node, int x, int y)
    {
        int index = y * currentWidth + x;

        map[index] = node;

        node.SetCoordinates(x, y);
    }
Exemple #4
0
 public void Build_ThrowsException_IfNotEnoughTilesets()
 {
     Assert.Throws <ChunkSet.ChunkSetBuilder.InvalidTilesetCountException>(
         () => ChunkSet.NewBuilder()
         .Add(new Chunk(new Tile[1][][]))
         .Add(new Chunk(new Tile[1][][]))
         .Build(),
         "found 2");
 }
Exemple #5
0
 public LevelTemplate(ChunkSet chunks, int width, int height, bool sky, string background, LevelTemplate destination, string theme)
 {
     Chunks      = chunks;
     Width       = width;
     Height      = height;
     Sky         = sky;
     Background  = background;
     Destination = destination;
     Theme       = theme;
 }
Exemple #6
0
        protected override void LoadContent()
        {
            TowerTemplate    = new LevelTemplate(ChunkSet.FromTexture(Content.Load <Texture2D>("Levels/tower"), 1), 1, 1, false, "bg_entrance", null, null);
            VillageTemplate  = new LevelTemplate(ChunkSet.FromTexture(Content.Load <Texture2D>("Levels/village"), 15), 12, 3, false, "bg_entrance", TowerTemplate, null);
            FountainTemplate = new LevelTemplate(ChunkSet.FromTexture(Content.Load <Texture2D>("Levels/fountain"), 2), 2, 1, false, "bg_fountain", VillageTemplate, "Sounds/fountain");
            JungleTemplate   = new LevelTemplate(ChunkSet.FromTexture(Content.Load <Texture2D>("Levels/jungle2"), 15), 8, 3, false, "bg_jungle", FountainTemplate, "Sounds/jungle");
            TunnelTemplate   = new LevelTemplate(ChunkSet.FromTexture(Content.Load <Texture2D>("Levels/tunnel"), 2), 2, 1, false, "bg_tunnel", JungleTemplate, null);
            EntranceTemplate = new LevelTemplate(ChunkSet.FromTexture(Content.Load <Texture2D>("Levels/entrance"), 2), 2, 1, true, "bg_entrance", TunnelTemplate, null);

            _screens.Push(new StartScreen(this));
        }
Exemple #7
0
    public void Build_ThrowsException_IfNullTileset()
    {
        int numTilesets = 9;

        ChunkSet.ChunkSetBuilder builder = ChunkSet.NewBuilder();
        for (int i = 0; i < numTilesets; i++)
        {
            builder.Add(null);
        }

        Assert.Throws <NullReferenceException>(
            () => builder.Build(),
            "null");
    }
Exemple #8
0
    public void Build_ThrowsException_IfTooManyTilesets()
    {
        int numTilesets = 15;

        ChunkSet.ChunkSetBuilder builder = ChunkSet.NewBuilder();
        for (int i = 0; i < numTilesets; i++)
        {
            builder.Add(new Chunk(new Tile[1][][]));
        }

        Assert.Throws <ChunkSet.ChunkSetBuilder.InvalidTilesetCountException>(
            () => builder.Build(),
            "found 15.");
    }
Exemple #9
0
 public void Reload(ChunkSet chunk)
 {
     for (int i = 0; i < mapRows; i++)
     {
         for (int j = 0; j < mapColumns; j++)
         {
             int idx = i * mapRows + j;
             m_maps[idx].MakeMap(chunk.m_chunks[idx].m_tiles);
             m_maps[idx].transform.position =
                 new Vector3(
                     i * m_maps[idx].controller.WorldWidth,
                     0,
                     j * m_maps[idx].controller.WorldHeight);
         }
     }
 }
    /// <summary>
    ///Adds a chunk at the given coordinates and expands the map
    /// </summary>
    /// <param name="node">
    ///The chunk you wish to add to the map
    /// </param>
    /// <param name="x">
    ///The x target coordinate
    /// </param>
    /// <param name="y">
    ///The y target coordinate
    /// </param>
    public void AddNodeAt(ChunkSet node, int x, int y)
    {
        node.SetCoordinates(x, y);

        if (x < 0)
        {
            //Debug.Log("ABS X: " + x);

            //expand and shuffle by Mathf.Abs(x)
            ExpandWidth(currentWidth + Mathf.Abs(x));
            ShuffleMap(Mathf.Abs(x), 0);

            node.SetCoordinates(0, node.GetY());
        }
        else if (x >= currentWidth)
        {
            //we just need to expand out by x - (currentWidth - 1), no need to shuffle

            if (currentWidth == 0)
            {
                ExpandWidth(x + 1);
            }
            else
            {
                ExpandWidth(x + 1);
            }
        }

        if (y < 0)
        {
            //Debug.Log("ABS Y: " + x);

            //expand and shuffle by Mathf.Abs(y)
            ExpandHeight(currentHeight + Mathf.Abs(y));
            ShuffleMap(0, Mathf.Abs(y));
            node.SetCoordinates(node.GetX(), 0);
        }
        else if (y >= currentHeight)
        {
            //we just need to expand up by y - (currentHeight - 1), no need to shuffle
            ExpandHeight(y + 1);
        }

        SetNodeAt(node, node.GetX(), node.GetY());
    }
Exemple #11
0
    // Use this for initialization
    void Start()
    {
        Tile[][][] map = new Tile[32][][];
        for (int i = 0; i < 32; i++)
        {
            map[i] = new Tile[16][];
            for (int j = 0; j < 16; j++)
            {
                map[i][j] = new Tile[16];
                for (int k = 0; k < 16; k++)
                {
                    map[i][j][k] = new Tile();
                    if ((j + k) % 2 == 0)
                    {
                        map[i][j][k].ID = 1;
                    }
                    else
                    {
                        map[i][j][k].ID = 2;
                    }
                }
            }
        }
        Chunk    chunk = new Chunk(map);
        ChunkSet c     = ChunkSet.NewBuilder()
                         .Add(chunk)
                         .Add(chunk)
                         .Add(chunk)
                         .Add(chunk)
                         .Add(chunk)
                         .Add(chunk)
                         .Add(chunk)
                         .Add(chunk)
                         .Add(chunk)
                         .Build();

        MapManager.instance.Reload(c);
    }
Exemple #12
0
        public static void Parse <T>(T node, GameBoxReader r, IProgress <GameBoxReadProgress> progress = null) where T : CMwNod
        {
            var stopwatch = Stopwatch.StartNew();

            node.GBX = r.GBX;

            var type = node.GetType();

            var chunks = new ChunkSet {
                Node = node
            };

            node.Chunks = chunks;

            uint?previousChunk = null;

            while (!r.BaseStream.CanSeek || r.BaseStream.Position < r.BaseStream.Length)
            {
                if (r.BaseStream.CanSeek && r.BaseStream.Position + 4 > r.BaseStream.Length)
                {
                    Debug.WriteLine($"Unexpected end of the stream: {r.BaseStream.Position}/{r.BaseStream.Length}");
                    var bytes = r.ReadBytes((int)(r.BaseStream.Length - r.BaseStream.Position));
                    break;
                }

                var chunkID = r.ReadUInt32();

                if (chunkID == 0xFACADE01) // no more chunks
                {
                    break;
                }
                else
                {
                    var logChunk = $"[{node.ClassName}] 0x{chunkID:X8}";
                    if (r.BaseStream.CanSeek)
                    {
                        logChunk += $" ({(float)r.BaseStream.Position / r.BaseStream.Length:0.00%})";
                    }

                    if (node.GBX?.ID.HasValue == true && Remap(node.GBX.ID.Value) == node.ID)
                    {
                        Log.Write(logChunk);
                    }
                    else
                    {
                        Log.Write($"~ {logChunk}");
                    }
                }

                Chunk chunk;

                var chunkRemapped = Chunk.Remap(chunkID);

                Type chunkClass = null;

                var reflected = ((chunkRemapped & 0xFFFFF000) == node.ID || NodeCacheManager.AvailableInheritanceClasses[type].Contains(chunkRemapped & 0xFFFFF000)) &&
                                (NodeCacheManager.AvailableChunkClasses[type].TryGetValue(chunkRemapped, out chunkClass) || NodeCacheManager.AvailableChunkClasses[type].TryGetValue(chunkID & 0xFFF, out chunkClass));

                var skippable = reflected && chunkClass.BaseType.GetGenericTypeDefinition() == typeof(SkippableChunk <>);

                // Unknown or skippable chunk
                if (!reflected || skippable)
                {
                    var skip = r.ReadUInt32();

                    if (skip != 0x534B4950)
                    {
                        if (chunkID != 0 && !reflected)
                        {
                            var logChunkError = $"[{node.ClassName}] 0x{chunkID:X8} ERROR (wrong chunk format or unknown unskippable chunk)";
                            if (node.GBX?.ID.HasValue == true && Remap(node.GBX.ID.Value) == node.ID)
                            {
                                Log.Write(logChunkError, ConsoleColor.Red);
                            }
                            else
                            {
                                Log.Write($"~ {logChunkError}", ConsoleColor.Red);
                            }

                            throw new Exception($"Wrong chunk format or unskippable chunk: 0x{chunkID:X8} (" +
                                                $"{NodeCacheManager.Names.Where(x => x.Key == Chunk.Remap(chunkID & 0xFFFFF000)).Select(x => x.Value).FirstOrDefault() ?? "unknown class"})" +
                                                $"\nPrevious chunk: 0x{previousChunk ?? 0:X8} (" +
                                                $"{(previousChunk.HasValue ? (NodeCacheManager.Names.Where(x => x.Key == Chunk.Remap(previousChunk.Value & 0xFFFFF000)).Select(x => x.Value).FirstOrDefault() ?? "unknown class") : "not a class")})");

                            /* Usually breaks in the current state and causes confusion
                             *
                             * var buffer = BitConverter.GetBytes(chunkID);
                             * using (var restMs = new MemoryStream(ushort.MaxValue))
                             * {
                             *  restMs.Write(buffer, 0, buffer.Length);
                             *
                             *  while (r.PeekUInt32() != 0xFACADE01)
                             *      restMs.WriteByte(r.ReadByte());
                             *
                             *  node.Rest = restMs.ToArray();
                             * }
                             * Debug.WriteLine("FACADE found.");*/
                        }
                        break;
                    }

                    var chunkDataSize = r.ReadInt32();
                    var chunkData     = new byte[chunkDataSize];
                    if (chunkDataSize > 0)
                    {
                        r.Read(chunkData, 0, chunkDataSize);
                    }

                    if (reflected)
                    {
                        var ignoreChunkAttribute = chunkClass.GetCustomAttribute <IgnoreChunkAttribute>();

                        var constructor = Array.Find(chunkClass.GetConstructors(), x => x.GetParameters().Length == 0);
                        if (constructor == null)
                        {
                            throw new ArgumentException($"{type.FullName} doesn't have a parameterless constructor.");
                        }

                        var c = (Chunk)constructor.Invoke(new object[0]);
                        c.Node = node;
                        c.GBX  = node.GBX;
                        ((ISkippableChunk)c).Data = chunkData;
                        if (chunkData == null || chunkData.Length == 0)
                        {
                            ((ISkippableChunk)c).Discovered = true;
                        }
                        chunks.Add(c);

                        if (ignoreChunkAttribute == null)
                        {
                            c.OnLoad();

                            if (chunkClass.GetCustomAttribute <ChunkAttribute>().ProcessSync)
                            {
                                ((ISkippableChunk)c).Discover();
                            }
                        }

                        chunk = c;
                    }
                    else
                    {
                        Debug.WriteLine("Unknown skippable chunk: " + chunkID.ToString("X"));
                        chunk     = (Chunk)Activator.CreateInstance(typeof(SkippableChunk <>).MakeGenericType(type), node, chunkRemapped, chunkData);
                        chunk.GBX = node.GBX;
                        chunks.Add(chunk);
                    }
                }
                else // Known or unskippable chunk
                {
                    var constructor = Array.Find(chunkClass.GetConstructors(), x => x.GetParameters().Length == 0);

                    if (constructor == null)
                    {
                        throw new ArgumentException($"{type.FullName} doesn't have a parameterless constructor.");
                    }

                    var c = (Chunk)constructor.Invoke(new object[0]);
                    c.Node = node;

                    c.OnLoad();

                    chunks.Add(c);

                    //r.Chunk = (Chunk)c; // Set chunk temporarily for reading

                    var posBefore = r.BaseStream.Position;

                    GameBoxReaderWriter gbxrw = new GameBoxReaderWriter(r);

                    var attributes                  = chunkClass.GetCustomAttributes();
                    var ignoreChunkAttribute        = default(IgnoreChunkAttribute);
                    var autoReadWriteChunkAttribute = default(AutoReadWriteChunkAttribute);

                    foreach (var att in attributes)
                    {
                        if (att is IgnoreChunkAttribute ignoreChunkAtt)
                        {
                            ignoreChunkAttribute = ignoreChunkAtt;
                        }
                        if (att is AutoReadWriteChunkAttribute autoReadWriteChunkAtt)
                        {
                            autoReadWriteChunkAttribute = autoReadWriteChunkAtt;
                        }
                    }

                    try
                    {
                        if (ignoreChunkAttribute == null)
                        {
                            if (autoReadWriteChunkAttribute == null)
                            {
                                c.ReadWrite(node, gbxrw);
                            }
                            else
                            {
                                var unknown     = new GameBoxWriter(c.Unknown, r.Lookbackable);
                                var unknownData = r.ReadUntilFacade();
                                unknown.Write(unknownData, 0, unknownData.Length);
                            }
                        }
                        else
                        {
                            throw new Exception($"Chunk 0x{chunkID & 0xFFF:x3} from class {node.ClassName} is known but its content is unknown to read.");
                        }
                    }
                    catch (EndOfStreamException)
                    {
                        Debug.WriteLine($"Unexpected end of the stream while reading the chunk.");
                    }

                    c.Progress = (int)(r.BaseStream.Position - posBefore);

                    chunk = c;
                }

                progress?.Report(new GameBoxReadProgress(GameBoxReadProgressStage.Body, (float)r.BaseStream.Position / r.BaseStream.Length, node.GBX, chunk));

                previousChunk = chunkID;
            }

            stopwatch.Stop();

            var logNodeCompletion = $"[{node.ClassName}] DONE! ({stopwatch.Elapsed.TotalMilliseconds}ms)";

            if (node.GBX.ID.HasValue == true && Remap(node.GBX.ID.Value) == node.ID)
            {
                Log.Write(logNodeCompletion, ConsoleColor.Green);
            }
            else
            {
                Log.Write($"~ {logNodeCompletion}", ConsoleColor.Green);
            }
        }