function SimSet::generateChunk(%this) {
	%this.generateBaseTerrain();
}

function SimSet::generateBaseTerrain(%this, %x, %y) {
	cancel(%this.generateBaseTerrain);

	if (%x $= "") {
		%x = 0;
	}

	if (%y $= "") {
		%y = 0;
	}

	if (%x >= 16) {
		%this.generateFeatures();
		return;
	}

	%usage = 0;
	// %limit = 8;
	%limit = 16;
	%rate = 250;

	if (%x == 0 && %y == 0 && vectorDist(%this.position, "0 0 0") < 3) {
		%limit = 32;
		// %rate = 0;
	}

	while (%usage < %limit)
	{
		if (%x >= 16) {
			break;
		}

		if (%y >= 16) {
			%y = 0;
			%x++;
		}

		%height = mFloor(%this.getTerrainHeight(%x, %y));
		%this.createTerrainRow(%x, %y, %height);

		%usage++;
		%y++;
	}

	%this.generateBaseTerrain = %this.schedule(%rate, generateBaseTerrain, %x, %y);
}

function SimSet::createTerrainRow(%this, %x, %y, %height) {
	%lowest = %height - 1;

	for (%xi = -1; %xi <= 1; %xi++) {
		for (%yi = -1; %yi <= 1; %yi++) {
			%test = %this.getTerrainHeight(%x + %xi, %y + %yi);

			if (%test < %lowest) {
				%lowest = %test;
			}
		}
	}

	if (%height < $EnvGuiServer::WaterHeight) {
		%block = Sand;
	}
	else {
		%block = getBiomeGroundMaterial(%this.getBiome(%x, %y));
	}

	if (%block $= GrassBlock && getRandom() <= 0.25) {
		if (getRandom() > 0.5) {
			%this.setBlock(%x, %y, %height + 1, Grass);
		}
		else {
			%this.setBlock(%x, %y, %height + 1, Gras2);
		}
	}

	if (%block $= Snow) {
		%this.setBlock(%x, %y, %height + 1, SnowCover);
	}

	if (%lowest == %height - 1) {
		%this.setBlock(%x, %y, %height, %block);
		return;
	}

	for (%z = %lowest + 1; %z <= %height + 1; %z++) {
		if (%z <= %height + 1) {
			%this.setBlock(%x, %y, %z, %block);
		}
		else {
			%this.setBlock(%x, %y, %z, Dirt);
		}
	}
}

function SimSet::generateFeatures(%this) {
	%limits = getBiomeTreeLimits(%this.getBiome(0, 0));
	%treeCount = getRandom(getWord(%limits, 0), getWords(%limits, 1));

	for (%i = 0; %i < %treeCount; %i++) {
		%x = getRandom(4, 12);
		%y = getRandom(4, 12);

		%x = mFloor(%x / 2) * 2;
		%y = mFloor(%y / 2) * 2;

		if (%madeTree[%x, %y]) {
			continue;
		}

		if (%this.getTerrainHeight(%x, %y) < $EnvGuiServer::WaterHeight) {
			continue;
		}

		%madeTree[%x, %y] = true;
		%this.schedule(250 * %i, "generateTree", %x, %y);
	}
}

function SimSet::generateTree(%this, %x, %y) {
	%type = getRandom(0, 3);

	switch (%type) {
		case 0: %trunk = "Wood"; %canopy = "Leaves"; %hl = 4; %hh = 10; %wl = 3; %wh = 5;
		case 2: %trunk = "PineWood"; %canopy = "PineLeaves"; %hl = 4; %hh = 10; %wl = 3; %wh = 5;
		case 3: %trunk = "BirchWood"; %canopy = "BirchLeaves"; %hl = 4; %hh = 10; %wl = 3; %wh = 5;
		case 1: %trunk = "JungleWood"; %canopy = "JungleLeaves"; %hl = 4; %hh = 10; %wl = 3; %wh = 5;
	}

	%terr = mFloor(%this.getTerrainHeight(%x, %y));

	%height = getRandom(%hl, %hh);
	%width = getRandom(%wl, %wh);

	if (%width >= %height) {
		%width = %height - 1;
	}

	for (%z = 1; %z <= %height; %z++)
	{
		%this.setBlock(%x, %y, %terr + %z, %trunk);
	}

	%trp = %x SPC %y SPC %terr + %height;

	for ( %xi = %x - %width ; %xi <= %x + %width ; %xi++ )
	{
		for ( %yi = %y - %width ; %yi <= %y + %width ; %yi++ )
		{
			for ( %zi = %terr + 1 ; %zi <= %terr + %height + %width ; %zi++ )
			{
				if ( %xi == %x && %yi == %y && %zi <= %terr + %height )
				{
					continue;
				}

				if ( vectorDist( %xi SPC %yi SPC %zi, %trp ) > %width )
				{
					continue;
				}

				%this.setBlock( %xi, %yi, %zi, %canopy );
			}
		}
	}
}
