Skip to content

Instantly share code, notes, and snippets.

@TkTech
Created July 21, 2010 01:49
Show Gist options
  • Save TkTech/483909 to your computer and use it in GitHub Desktop.
Save TkTech/483909 to your computer and use it in GitHub Desktop.
//
// Author:
// Tyler Kenendy <tk@tkte.ch>
//
// Copyright (c) 2010, Tyler Kennedy
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the distribution.
// * Neither the name of the [ORGANIZATION] nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
using System;
namespace kyou
{
public class Map
{
/// <summary>
/// Size of the map along the X axis
/// </summary>
private ushort _width;
/// <summary>
/// Size of the map along the Y axis
/// </summary>
private ushort _depth;
/// <summary>
/// Size of the map along the Z axis
/// </summary>
private ushort _height;
/// <summary>
/// Spawn X coordinate
/// </summary>
private ushort _spawnX;
/// <summary>
/// Spawn Y coordinate
/// </summary>
private ushort _spawnY;
/// <summary>
/// Spawn Z coordinate
/// </summary>
private ushort _spawnZ;
/// <summary>
/// Spawn rotation in degrees, scaled to 256
/// </summary>
private byte _spawnRotation;
/// <summary>
/// Spawn pitch in degrees, scaled to 256
/// </summary>
private byte _spawnPitch;
/// <summary>
/// Array of bytes representing the map
/// </summary>
public byte[] _blocks;
/// <summary>
/// Returns the width of the map (along the X axis)
/// </summary>
public ushort Width {
get { return _width; }
}
/// <summary>
/// Returns the depth of the map (along the Y axis)
/// </summary>
public ushort Depth {
get { return _depth; }
}
/// <summary>
/// Returns the height of the map (along the Z axis)
/// </summary>
public ushort Height {
get { return _height; }
}
/// <summary>
/// Returns the total number of blocks on a map
/// </summary>
public int BlockCount {
get { return _width * _depth * _height; }
}
/// <summary>
/// Sets the spawn location along the X axis, checking bounds
/// </summary>
public ushort SpawnX {
get { return _spawnX; }
set {
if (value < 0 || value > _width) {
throw new ArgumentOutOfRangeException ("SpawnX", "Value is greater or less than the width of the map");
}
_spawnX = value;
}
}
/// <summary>
/// Sets the spawn location along the Y axis, checking bounds
/// </summary>
public ushort SpawnY {
get { return _spawnY; }
set {
if (value < 0 || value > _depth) {
throw new ArgumentOutOfRangeException ("SpawnY", "Value is greater or less than the depth of the map");
}
_spawnY = value;
}
}
/// <summary>
/// Sets the spawn location along the Z axis, checking bounds
/// </summary>
public ushort SpawnZ {
get { return _spawnZ; }
set {
if (value < 0 || value > _height) {
throw new ArgumentOutOfRangeException ("SpawnZ", "Value is greater or less than the height of the map");
}
_spawnZ = value;
}
}
/// <summary>
/// Returns the BlockType of the block at <x,y,z>
/// </summary>
/// <param name="x">
/// A <see cref="System.Int32"/>
/// </param>
/// <param name="y">
/// A <see cref="System.Int32"/>
/// </param>
/// <param name="z">
/// A <see cref="System.Int32"/>
/// </param>
/// <returns>
/// A <see cref="BlockType"/>
/// </returns>
public BlockType GetBlock(int x, int y, int z) {
return (BlockType)this[x,y,z];
}
/// <summary>
/// Sets the BlockType of the block at <x,y,z>
/// </summary>
/// <param name="x">
/// A <see cref="System.Int32"/>
/// </param>
/// <param name="y">
/// A <see cref="System.Int32"/>
/// </param>
/// <param name="z">
/// A <see cref="System.Int32"/>
/// </param>
/// <param name="type">
/// A <see cref="BlockType"/>
/// </param>
public void SetBlock(int x, int y, int z, BlockType type) {
this[x,y,z] = (byte)type;
}
/// <summary>
/// Returns a byte representing the block at index
/// </summary>
/// <param name="index">
/// A <see cref="System.Int32"/>
/// </param>
public byte this[int index] {
get {
if (_blocks != null && index <= _blocks.Length && index >= 0)
return _blocks[index];
throw new ArgumentOutOfRangeException ("index", index.ToString ());
}
set {
if (_blocks != null && index <= _blocks.Length && index >= 0)
_blocks[index] = value;
else
throw new ArgumentOutOfRangeException ("index", index.ToString ());
}
}
/// <summary>
/// Returns a byte representing the block at <X,Y,Z>
/// </summary>
/// <param name="x">
/// A <see cref="System.Int32"/>
/// </param>
/// <param name="y">
/// A <see cref="System.Int32"/>
/// </param>
/// <param name="z">
/// A <see cref="System.Int32"/>
/// </param>
public byte this[int x, int y, int z] {
get {
if (_blocks != null && IsValidPoint (x, y, z))
return _blocks[IndexFromXYZ (x, y, z)];
throw new ArgumentOutOfRangeException ();
}
set {
if (_blocks != null && IsValidPoint (x, y, z))
_blocks[IndexFromXYZ (x, y, z)] = value;
}
}
#region Constructors
/// <summary>
/// Creates a new empty map of width by depth by height
/// </summary>
/// <param name="width">
/// A <see cref="System.Int32"/>
/// </param>
/// <param name="depth">
/// A <see cref="System.Int32"/>
/// </param>
/// <param name="height">
/// A <see cref="System.Int32"/>
/// </param>
public Map (ushort width, ushort depth, ushort height)
{
if (IsValidDimension (width)) {
if (IsValidDimension (depth)) {
if (IsValidDimension (height)) {
_width = width;
_depth = depth;
_height = height;
// Redundant, but required to supress needless warnings
_spawnRotation = 0;
_spawnPitch = 0;
_blocks = new byte[width * depth * height];
} else {
throw new ArgumentOutOfRangeException ("height", height.ToString ());
}
} else {
throw new ArgumentOutOfRangeException ("depth", depth.ToString ());
}
} else {
throw new ArgumentOutOfRangeException ("width", width.ToString ());
}
}
/// <summary>
/// Uses an existing block array for internal storage
/// </summary>
/// <param name="width">
/// A <see cref="System.UInt16"/>
/// </param>
/// <param name="depth">
/// A <see cref="System.UInt16"/>
/// </param>
/// <param name="height">
/// A <see cref="System.UInt16"/>
/// </param>
/// <param name="blocks">
/// A <see cref="System.Byte[]"/>
/// </param>
public Map (ushort width, ushort depth, ushort height, byte[] blocks)
{
_width = width;
_depth = depth;
_height = height;
_blocks = blocks;
}
#endregion
#region Functions
/// <summary>
/// Converts the 3D XYZ coordinate into a linear position
/// </summary>
/// <param name="x">
/// A <see cref="System.Int32"/>
/// </param>
/// <param name="y">
/// A <see cref="System.Int32"/>
/// </param>
/// <param name="z">
/// A <see cref="System.Int32"/>
/// </param>
/// <returns>
/// A <see cref="System.Int32"/>
/// </returns>
public int IndexFromXYZ (int x, int y, int z)
{
return ((z * _depth + y) * _width + x);
}
/// <summary>
/// Returns true if the point specified by <X,Y,Z> is within the map
/// </summary>
/// <param name="x">
/// A <see cref="System.Int32"/>
/// </param>
/// <param name="y">
/// A <see cref="System.Int32"/>
/// </param>
/// <param name="z">
/// A <see cref="System.Int32"/>
/// </param>
/// <returns>
/// A <see cref="System.Boolean"/>
/// </returns>
public bool IsValidPoint (int x, int y, int z)
{
if (x >= 0 && x <= _width && y >= 0 && y <= _depth && z >= 0 && z <= _height)
return true;
return false;
}
/// <summary>
/// Returns true if val is a legal value for a map dimension
/// </summary>
/// <param name="dimension">
/// A <see cref="System.Int32"/>
/// </param>
/// <returns>
/// A <see cref="System.Boolean"/>
/// </returns>
public static bool IsValidDimension (int dimension)
{
return dimension > 0 && dimension % 16 == 0 && dimension < 2048;
}
/// <summary>
/// Returns an array representing a heightmap
/// </summary>
/// <returns>
/// A <see cref="System.UInt16[,]"/>
/// </returns>
unsafe public ushort[,] HeightMap ()
{
ushort[,] hm = new ushort[_width,_depth];
for (int x = 0; x < _width; x++) {
for (int y = 0; y < _depth; y++) {
hm[x,y] = GetMaxZForXY(x,y);
}
}
return hm;
}
/// <summary>
/// Get the highest Z given an XY of a block that is not air
/// </summary>
/// <param name="x">
/// A <see cref="System.Int32"/>
/// </param>
/// <param name="y">
/// A <see cref="System.Int32"/>
/// </param>
/// <returns>
/// A <see cref="System.UInt16"/>
/// </returns>
unsafe public ushort GetMaxZForXY(int x, int y)
{
for(int z = _height - 1; z > 0; z--) {
if(this[x,y,z] != 0 /* Air */) {
return (ushort)z;
}
}
return 0;
}
/// <summary>
/// Sets the spawn point to a random location on the map
/// </summary>
public void ResetSpawnRandom()
{
Random rn = new Random();
_spawnX = (ushort)rn.Next(0,_width);
_spawnY = (ushort)rn.Next(0,_depth);
_spawnZ = GetMaxZForXY(_spawnX,_spawnY);
_spawnPitch = 0;
_spawnRotation = 0;
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment