// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System;
using ClassicalSharp.Events;
using ClassicalSharp.Renderers;
using OpenTK;
namespace ClassicalSharp.Map {
/// Represents a fixed size map of blocks. Stores the raw block data,
/// heightmap, dimensions and various metadata such as environment settings.
public sealed partial class World {
Game game;
BlockInfo info;
public byte[] blocks;
public int Width, Height, Length;
/// Contains the environment metadata for this world.
public WorldEnv Env;
/// Unique uuid/guid of this particular world.
public Guid Uuid;
/// Whether this map is empty.
public bool IsNotLoaded = true;
/// Current terrain.png or texture pack url of this map.
public string TextureUrl = null;
public World(Game game) {
Env = new WorldEnv(game);
this.game = game;
info = game.BlockInfo;
}
/// Resets all of the properties to their defaults and raises the 'OnNewMap' event.
public void Reset() {
Env.Reset();
Width = Height = Length = 0;
IsNotLoaded = true;
Uuid = Guid.NewGuid();
game.WorldEvents.RaiseOnNewMap();
}
/// Updates the underlying block array, heightmap, and dimensions of this map.
public void SetNewMap(byte[] blocks, int width, int height, int length) {
this.blocks = blocks;
this.Width = width;
this.Height = height;
this.Length = length;
IsNotLoaded = width == 0 || length == 0 || height == 0;
if (blocks.Length != (width * height * length))
throw new InvalidOperationException("Blocks array length does not match volume of map.");
if (Env.EdgeHeight == -1) Env.EdgeHeight = height / 2;
if (Env.CloudHeight == -1) Env.CloudHeight = height + 2;
}
/// Sets the block at the given world coordinates without bounds checking,
/// and also recalculates the heightmap for the given (x,z) column.
public void SetBlock(int x, int y, int z, byte blockId) {
int index = (y * Length + z) * Width + x;
byte oldBlock = blocks[index];
blocks[index] = blockId;
game.Lighting.UpdateLight(x, y, z, oldBlock, blockId);
WeatherRenderer weather = game.WeatherRenderer;
if (weather.heightmap != null && !IsNotLoaded)
weather.UpdateHeight(x, y, z, oldBlock, blockId);
}
/// Sets the block at the given world coordinates without bounds checking,
/// and also recalculates the heightmap for the given (x,z) column.
public void SetBlock(Vector3I p, byte blockId) {
SetBlock(p.X, p.Y, p.Z, blockId);
}
/// Returns the block at the given world coordinates without bounds checking.
public byte GetBlock(int x, int y, int z) {
return blocks[(y * Length + z) * Width + x];
}
/// Returns the block at the given world coordinates without bounds checking.
public byte GetBlock(Vector3I p) {
return blocks[(p.Y * Length + p.Z) * Width + p.X];
}
/// Returns the block at the given world coordinates with bounds checking,
/// returning 0 is the coordinates were outside the map.
public byte SafeGetBlock(int x, int y, int z) {
return IsValidPos(x, y, z) ?
blocks[(y * Length + z) * Width + x] : Block.Air;
}
/// Returns the block at the given world coordinates with bounds checking,
/// returning 0 is the coordinates were outside the map.
public byte SafeGetBlock(Vector3I p) {
return IsValidPos(p.X, p.Y, p.Z) ?
blocks[(p.Y * Length + p.Z) * Width + p.X] : Block.Air;
}
/// Returns whether the given world coordinates are contained
/// within the dimensions of the map.
public bool IsValidPos(int x, int y, int z) {
return x >= 0 && y >= 0 && z >= 0 &&
x < Width && y < Height && z < Length;
}
/// Returns whether the given world coordinates are contained
/// within the dimensions of the map.
public bool IsValidPos(Vector3I p) {
return p.X >= 0 && p.Y >= 0 && p.Z >= 0 &&
p.X < Width && p.Y < Height && p.Z < Length;
}
/// Unpacks the given index into the map's block array into its original world coordinates.
public Vector3I GetCoords(int index) {
if (index < 0 || index >= blocks.Length)
return new Vector3I(-1);
int x = index % Width;
int y = index / (Width * Length);
int z = (index / Width) % Length;
return new Vector3I(x, y, z);
}
public byte GetPhysicsBlock(int x, int y, int z) {
if (x < 0 || x >= Width || z < 0 || z >= Length || y < 0) return Block.Bedrock;
if (y >= Height) return Block.Air;
return blocks[(y * Length + z) * Width + x];
}
}
}