aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World/OreFeature.cpp
blob: c057511bf7bc7230ede75572643e025e07063ec6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include "stdafx.h"
#include "net.minecraft.world.level.h"
#include "net.minecraft.world.level.tile.h"
#include "OreFeature.h"

void OreFeature::_init(int tile, int count, int targetTile)
{
	this->tile = tile;
	this->count = count;
	this->targetTile = targetTile;
}

OreFeature::OreFeature(int tile, int count)
{
	_init(tile, count, Tile::stone_Id);
}

OreFeature::OreFeature(int tile, int count, int targetTile)
{
	_init(tile, count, targetTile);
}

bool OreFeature::place(Level *level, Random *random, int x, int y, int z)
{
	PIXBeginNamedEvent(0,"Place Ore Feature");
	float dir = random->nextFloat() * PI;

	double x0 = x + 8 + Mth::sin(dir) * count / 8;
	double x1 = x + 8 - Mth::sin(dir) * count / 8;
	double z0 = z + 8 + Mth::cos(dir) * count / 8;
	double z1 = z + 8 - Mth::cos(dir) * count / 8;

	double y0 = y + random->nextInt(3) - 2;
	double y1 = y + random->nextInt(3) - 2;

	bool collisionsExpected = false;

	LevelGenerationOptions *levelGenOptions = NULL;
	if( app.getLevelGenerationOptions() != NULL )
	{
		levelGenOptions = app.getLevelGenerationOptions();

		// 4J Stu - Optimise schematic intersection checks by first checking the max possible bounding box of this place call
		int minX = x0 - 1;
		int minY = y0 - 1;
		int minZ = z0 - 1;

		double maxss = count / 16;
		double maxr = (Mth::sin(PI) + 1) * maxss + 1;
		double maxhr = (Mth::sin(PI) + 1) * maxss + 1;
		int maxX = Mth::floor(x1 + maxr / 2);
		int maxY = Mth::floor(y1 + maxhr / 2);
		int maxZ = Mth::floor(z1 + maxr / 2);

		collisionsExpected = levelGenOptions->checkIntersects(minX, minY, minZ, maxX, maxY, maxZ);
	}

	bool doEarlyRejectTest = false;
	if( y0 > level->getSeaLevel() )
	{
		doEarlyRejectTest = true;
	}

	for (int d = 0; d <= count; d++)
	{
		double xx = x0 + (x1 - x0) * d / count;
		double yy = y0 + (y1 - y0) * d / count;
		double zz = z0 + (z1 - z0) * d / count;

        double ss = random->nextDouble() * count / 16;
        double r = (Mth::sin(d * PI / count) + 1) * ss + 1;
		double hr = r; //(Mth::sin(d * PI / count) + 1) * ss + 1;

		double halfR = r/2;
		double halfHR = halfR; //hr/2;

		int xt0 = Mth::floor(xx - halfR);
		int yt0 = Mth::floor(yy - halfHR);
		int zt0 = Mth::floor(zz - halfR);

		int xt1 = Mth::floor(xx + halfR);
		int yt1 = Mth::floor(yy + halfHR);
		int zt1 = Mth::floor(zz + halfR);

		// 4J Stu Added to stop ore features generating areas previously place by game rule generation
		if(collisionsExpected && levelGenOptions != NULL)
		{
			bool intersects = levelGenOptions->checkIntersects(xt0, yt0, zt0, xt1, yt1, zt1);
			if(intersects)
			{
				//app.DebugPrintf("Skipping ore feature generation as it overlaps a game rule structure\n");
				continue;
			}
		}

		// A large % of ore placement is entirely into the air. Attempt to identify some of these early, by check the corners
		// of the area we are placing in to see if we are going to (very probably) be entirely above the height stored in the heightmap

		if( doEarlyRejectTest )
		{
			bool earlyReject = true;
			if     ( level->getHeightmap(xt0, zt0) >= yt0 ) earlyReject = false;
			else if( level->getHeightmap(xt1, zt0) >= yt0 ) earlyReject = false;
			else if( level->getHeightmap(xt0, zt1) >= yt0 ) earlyReject = false;
			else if( level->getHeightmap(xt1, zt1) >= yt0 ) earlyReject = false;

			if( earlyReject ) continue;
		}

		double xdxd,ydyd;

		double xd0 = ((xt0 + 0.5) - xx);
		double yd0 = ((yt0 + 0.5) - yy);
		double zd0 = ((zt0 + 0.5) - zz);

		double halfRSq = halfR * halfR;

		double xd = xd0;
        for (int x2 = xt0; x2 <= xt1; x2++, xd++)
		{
			xdxd = xd * xd;
            if (xdxd < halfRSq)
			{
				double yd = yd0;
                for (int y2 = yt0; y2 <= yt1; y2++, yd++)
				{
					ydyd = yd * yd;
                    if (xdxd + ydyd < halfRSq)
					{
						double zd = zd0;
                        for (int z2 = zt0; z2 <= zt1; z2++, zd++)
						{
                           	if (xdxd + ydyd + zd * zd < halfRSq)
							{
                                if ( level->getTile(x2, y2, z2) == targetTile)
								{									
									level->setTileAndData(x2, y2, z2, tile, 0, Tile::UPDATE_INVISIBLE_NO_LIGHT);
								}
                            }
                        }
					}
                }
            }
        }
    }

	PIXEndNamedEvent();
    return true;
}