Example #1
0
        /// <summary>
        /// Gets the description bytes of a single tile of the map in behalf of a given player at a given location.
        /// </summary>
        /// <param name="player">The player for which the description is being retrieved for.</param>
        /// <param name="location">The location from which the description of the tile is being retrieved.</param>
        /// <returns>A tuple containing the description metadata: a map of string to objects, and the description data: a sequence of bytes representing the tile's description.</returns>
        public (IDictionary <string, object> descriptionMetadata, ReadOnlySequence <byte> descriptionData) DescribeTile(IPlayer player, Location location)
        {
            player.ThrowIfNull(nameof(player));

            if (location.Type != LocationType.Map)
            {
                throw new ArgumentException($"Invalid location {location}.", nameof(location));
            }

            var firstSegment = new MapDescriptionSegment(ReadOnlyMemory <byte> .Empty);

            MapDescriptionSegment lastSegment = firstSegment;

            var segmentsFromTile = this.tileDescriptor.DescribeTileForPlayer(player, this.map.GetTileAt(location), out ISet <uint> creatureIdsToLearn, out ISet <uint> creatureIdsToForget);

            // See if we actually have segments to append.
            if (segmentsFromTile != null && segmentsFromTile.Any())
            {
                foreach (var segment in segmentsFromTile)
                {
                    lastSegment.Append(segment);
                    lastSegment = segment;
                }
            }

            return(
                new Dictionary <string, object>()
            {
                { IMapDescriptor.CreatureIdsToLearnMetadataKeyName, creatureIdsToLearn },
                { IMapDescriptor.CreatureIdsToForgetMetadataKeyName, creatureIdsToForget },
            },
                new ReadOnlySequence <byte>(firstSegment, 0, lastSegment, lastSegment.Memory.Length));
        }
Example #2
0
        /// <summary>
        /// Gets the description bytes of the map in behalf of a given player for the specified window.
        /// </summary>
        /// <param name="player">The player for which the description is being retrieved for.</param>
        /// <param name="fromX">The starting X coordinate of the window.</param>
        /// <param name="fromY">The starting Y coordinate of the window.</param>
        /// <param name="fromZ">The starting Z coordinate of the window.</param>
        /// <param name="toZ">The ending Z coordinate of the window.</param>
        /// <param name="windowSizeX">The size of the window in X.</param>
        /// <param name="windowSizeY">The size of the window in Y.</param>
        /// <param name="customOffsetZ">Optional. A custom Z offset value used mainly for partial floor changing windows. Defaults to 0.</param>
        /// <returns>A tuple containing the description metadata: a map of string to objects, and the description data: a sequence of bytes representing the description.</returns>
        public (IDictionary <string, object> descriptionMetadata, ReadOnlySequence <byte> descriptionData) DescribeWindow(IPlayer player, ushort fromX, ushort fromY, sbyte fromZ, sbyte toZ, byte windowSizeX = MapConstants.DefaultWindowSizeX, byte windowSizeY = MapConstants.DefaultWindowSizeY, sbyte customOffsetZ = 0)
        {
            player.ThrowIfNull(nameof(player));

            ushort toX = (ushort)(fromX + windowSizeX);
            ushort toY = (ushort)(fromY + windowSizeY);

            var firstSegment = new MapDescriptionSegment(ReadOnlyMemory <byte> .Empty);

            MapDescriptionSegment lastSegment = firstSegment;

            sbyte stepZ            = 1;
            byte  currentSkipCount = byte.MaxValue;

            if (fromZ > toZ)
            {
                // we're going up!
                stepZ = -1;
            }

            customOffsetZ = customOffsetZ != 0 ? customOffsetZ : (sbyte)(player.Location.Z - fromZ);

            if (windowSizeX > MapConstants.DefaultWindowSizeX)
            {
                this.Logger.LogWarning($"{nameof(this.DescribeWindow)} {nameof(windowSizeX)} is over {nameof(MapConstants.DefaultWindowSizeX)} ({MapConstants.DefaultWindowSizeX}).");
            }

            if (windowSizeY > MapConstants.DefaultWindowSizeY)
            {
                this.Logger.LogWarning($"{nameof(this.DescribeWindow)} {nameof(windowSizeY)} is over {nameof(MapConstants.DefaultWindowSizeY)} ({MapConstants.DefaultWindowSizeY}).");
            }

            var allCreatureIdsToLearn  = new List <uint>();
            var allCreatureIdsToForget = new List <uint>();

            for (sbyte currentZ = fromZ; currentZ != toZ + stepZ; currentZ += stepZ)
            {
                var zOffset = fromZ - currentZ + customOffsetZ;

                for (var nx = 0; nx < windowSizeX; nx++)
                {
                    for (var ny = 0; ny < windowSizeY; ny++)
                    {
                        Location targetLocation = new Location
                        {
                            X = (ushort)(fromX + nx + zOffset),
                            Y = (ushort)(fromY + ny + zOffset),
                            Z = currentZ,
                        };

                        var segmentsFromTile = this.tileDescriptor.DescribeTileForPlayer(player, this.map.GetTileAt(targetLocation), out ISet <uint> creatureIdsToLearn, out ISet <uint> creatureIdsToForget);

                        allCreatureIdsToLearn.AddRange(creatureIdsToLearn);
                        allCreatureIdsToForget.AddRange(creatureIdsToForget);

                        // See if we actually have segments to append.
                        if (segmentsFromTile != null && segmentsFromTile.Any())
                        {
                            if (currentSkipCount < byte.MaxValue)
                            {
                                lastSegment = lastSegment.Append(new byte[] { currentSkipCount, byte.MaxValue });
                            }

                            foreach (var segment in segmentsFromTile)
                            {
                                lastSegment.Append(segment);
                                lastSegment = segment;
                            }

                            currentSkipCount = byte.MinValue;
                            continue;
                        }

                        if (++currentSkipCount == byte.MaxValue)
                        {
                            lastSegment = lastSegment.Append(new byte[] { byte.MaxValue, byte.MaxValue });
                        }
                    }
                }
            }

            if (++currentSkipCount < byte.MaxValue)
            {
                lastSegment = lastSegment.Append(new byte[] { currentSkipCount, byte.MaxValue });
            }

            return(
                new Dictionary <string, object>()
            {
                { IMapDescriptor.CreatureIdsToLearnMetadataKeyName, allCreatureIdsToLearn.ToHashSet() },
                { IMapDescriptor.CreatureIdsToForgetMetadataKeyName, allCreatureIdsToForget.ToHashSet() },
            },
                new ReadOnlySequence <byte>(firstSegment, 0, lastSegment, lastSegment.Memory.Length));
        }