summary refs log tree commit diff
path: root/src/World.h
blob: 942eea7d829c2e9dce2ae49ef8d310ce62e039d9 (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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#ifndef CC_WORLD_H
#define CC_WORLD_H
#include "Vectors.h"
#include "PackedCol.h"
/* 
Represents a fixed size 3D array of blocks and associated metadata
Copyright 2014-2023 ClassiCube | Licensed under BSD-3
*/
struct AABB;
extern struct IGameComponent World_Component;

/* Unpacka an index into x,y,z (slow!) */
#define World_Unpack(idx, x, y, z) x = idx % World.Width; z = (idx / World.Width) % World.Length; y = (idx / World.Width) / World.Length;
/* Packs an x,y,z into a single index */
#define World_Pack(x, y, z) (((y) * World.Length + (z)) * World.Width + (x))
#define WORLD_UUID_LEN 16

#define World_ChunkPack(cx, cy, cz) (((cz) * World.ChunksY + (cy)) * World.ChunksX + (cx))
/* TODO: Swap Y and Z? Make sure to update MapRenderer's ResetChunkCache and ClearChunkCache methods! */


CC_VAR extern struct _WorldData {
	/* The blocks in the world. */
	BlockRaw* Blocks;
#ifdef EXTENDED_BLOCKS
	/* The upper 8 bit of blocks in the world. */
	/* If only 8 bit blocks are used, equals World_Blocks. */
	BlockRaw* Blocks2;
#endif
	/* Volume of the world. */
	int Volume;

	/* Dimensions of the world. */
	int Width, Height, Length;
	/* Maximum X/Y/Z coordinate in the world. */
	/* (i.e. Width - 1, Height - 1, Length - 1) */
	int MaxX, MaxY, MaxZ;
	/* Adds one Y coordinate to a packed index. */
	int OneY;
	/* Unique identifier for this world. */
	cc_uint8 Uuid[WORLD_UUID_LEN];

#ifdef EXTENDED_BLOCKS
	/* Masks access to World.Blocks/World.Blocks2 */
	/* e.g. this will be 255 if only 8 bit blocks are used */
	int IDMask;
#endif
	/* Whether the world has finished loading/generating. */
	/* NOTE: Blocks may still be NULL. (e.g. error during loading) */
	cc_bool Loaded;
	/* Point in time the current world was last saved at */
	double LastSave;
	/* Default name of the world when saving */
	cc_string Name;
	/* Number of chunks on each axis the world is subdivided into */
	int ChunksX, ChunksY, ChunksZ;
	/* Number of chunks in the world, or ChunksX * ChunksY * ChunksZ */
	int ChunksCount;
	/* Seed world was generated with. May be 0 (unknown) */
	int Seed;
} World;

/* Frees the blocks array, sets dimensions to 0, resets environment to default. */
void World_Reset(void);
/* Sets up state and raises WorldEvents.NewMap event */
/* NOTE: This implicitly calls World_Reset. */
CC_API void World_NewMap(void);
/* Sets blocks array/dimensions of the map and raises WorldEvents.MapLoaded event */
/* May also sets some environment settings like border/clouds height, if they are -1 */
CC_API void World_SetNewMap(BlockRaw* blocks, int width, int height, int length);
/* Sets the various dimension and max coordinate related variables. */
/* NOTE: This is an internal API. Use World_SetNewMap instead. */
CC_NOINLINE void World_SetDimensions(int width, int height, int length);
void World_OutOfMemory(void);

#ifdef EXTENDED_BLOCKS
/* Sets World.Blocks2 and updates internal state for more than 256 blocks. */
void World_SetMapUpper(BlockRaw* blocks);

#define World_GetRawBlock(idx) ((World.Blocks[idx] | (World.Blocks2[idx] << 8)) & World.IDMask)

/* Gets the block at the given coordinates. */
/* NOTE: Does NOT check that the coordinates are inside the map. */
static CC_INLINE BlockID World_GetBlock(int x, int y, int z) {
	int i = World_Pack(x, y, z);
	return (BlockID)World_GetRawBlock(i);
}
#else
#define World_GetBlock(x, y, z) World.Blocks[World_Pack(x, y, z)]
#define World_GetRawBlock(idx)  World.Blocks[idx]
#endif

/* If Y is above the map, returns BLOCK_AIR. */
/* If coordinates are outside the map, returns BLOCK_AIR. */
/* Otherwise returns the block at the given coordinates. */
BlockID World_GetPhysicsBlock(int x, int y, int z);
/* Sets the block at the given coordinates. */
/* NOTE: Does NOT check that the coordinates are inside the map. */
void World_SetBlock(int x, int y, int z, BlockID block);
/* If coordinates are outside the map, returns BLOCK_AIR. */
/* Otherwise returns the block at the given coordinates. */
BlockID World_SafeGetBlock(int x, int y, int z);

/* Whether the given coordinates lie inside the map. */
static CC_INLINE cc_bool World_Contains(int x, int y, int z) {
	return (unsigned)x < (unsigned)World.Width
		&& (unsigned)y < (unsigned)World.Height
		&& (unsigned)z < (unsigned)World.Length;
}
/* Whether the given coordinates lie horizontally inside the map. */
static CC_INLINE cc_bool World_ContainsXZ(int x, int z) {
	return (unsigned)x < (unsigned)World.Width 
		&& (unsigned)z < (unsigned)World.Length;
}

enum EnvVar {
	ENV_VAR_EDGE_BLOCK, ENV_VAR_SIDES_BLOCK, ENV_VAR_EDGE_HEIGHT, ENV_VAR_SIDES_OFFSET,
	ENV_VAR_CLOUDS_HEIGHT, ENV_VAR_CLOUDS_SPEED, ENV_VAR_WEATHER_SPEED, ENV_VAR_WEATHER_FADE,
	ENV_VAR_WEATHER, ENV_VAR_EXP_FOG, ENV_VAR_SKYBOX_HOR_SPEED, ENV_VAR_SKYBOX_VER_SPEED,
	ENV_VAR_SKY_COLOR, ENV_VAR_CLOUDS_COLOR, ENV_VAR_FOG_COLOR, 
	ENV_VAR_SUN_COLOR, ENV_VAR_SHADOW_COLOR, ENV_VAR_SKYBOX_COLOR,
	ENV_VAR_LAVALIGHT_COLOR, ENV_VAR_LAMPLIGHT_COLOR
};

CC_VAR extern struct _EnvData {
	BlockID EdgeBlock, SidesBlock;
	int EdgeHeight, SidesOffset;
	int CloudsHeight;
	float CloudsSpeed;

	float WeatherSpeed, WeatherFade;
	int Weather, ExpFog;
	float SkyboxHorSpeed, SkyboxVerSpeed;

	PackedCol SkyCol, FogCol, CloudsCol, SkyboxCol;
	PackedCol SunCol, SunXSide, SunZSide, SunYMin;
	PackedCol ShadowCol, ShadowXSide, ShadowZSide, ShadowYMin;
	PackedCol LavaLightCol, LampLightCol;
} Env;
#define Env_SidesHeight (Env.EdgeHeight + Env.SidesOffset)

enum Weather_ { WEATHER_SUNNY, WEATHER_RAINY, WEATHER_SNOWY };
extern const char* const Weather_Names[3];

#define ENV_DEFAULT_SKY_COLOR       PackedCol_Make(0x99, 0xCC, 0xFF, 0xFF)
#define ENV_DEFAULT_FOG_COLOR       PackedCol_Make(0xFF, 0xFF, 0xFF, 0xFF)
#define ENV_DEFAULT_CLOUDS_COLOR    PackedCol_Make(0xFF, 0xFF, 0xFF, 0xFF)
#define ENV_DEFAULT_SKYBOX_COLOR    PackedCol_Make(0xFF, 0xFF, 0xFF, 0xFF)
#define ENV_DEFAULT_SUN_COLOR       PackedCol_Make(0xFF, 0xFF, 0xFF, 0xFF)
#define ENV_DEFAULT_SHADOW_COLOR    PackedCol_Make(0x9B, 0x9B, 0x9B, 0xFF)
#define ENV_DEFAULT_LAVALIGHT_COLOR PackedCol_Make(0xFF, 0xEB, 0xC6, 0xFF)
#define ENV_DEFAULT_LAMPLIGHT_COLOR PackedCol_Make(0xFF, 0xFF, 0xFF, 0xFF)

/* Resets all environment settings to default. */
/* NOTE: Unlike Env_Set functions, DOES NOT raise EnvVarChanged event. */
CC_API void Env_Reset(void);

/* Sets the edge/horizon block. (default water) */
CC_API void Env_SetEdgeBlock(BlockID block);
/* Sets the sides/border block. (default bedrock) */
CC_API void Env_SetSidesBlock(BlockID block);
/* Sets the edge/horizon height. (default height/2) */
CC_API void Env_SetEdgeHeight(int height);
/* Sets offset of sides/border from horizon. (default -2) */
CC_API void Env_SetSidesOffset(int offset);
/* Sets clouds height. (default height+2)*/
CC_API void Env_SetCloudsHeight(int height);
/* Sets how fast clouds move. (default 1) */
/* Negative speeds move in opposite direction. */
CC_API void Env_SetCloudsSpeed(float speed);

/* Sets how fast rain/snow falls. (default 1) */
/* Negative speeds makes rain/snow fall upwards. */
CC_API void Env_SetWeatherSpeed(float speed);
/* Sets how quickly rain/snow fades over distance. (default 1) */
CC_API void Env_SetWeatherFade(float rate);
/* Sets the weather of the map. (default sun) */
/* Can be sun/rain/snow, see WEATHER_ enum. */
CC_API void Env_SetWeather(int weather);
/* Sets whether exponential/smooth fog is used. (default false) */
CC_API void Env_SetExpFog(cc_bool expFog);
/* Sets how quickly skybox rotates/spins horizontally. (default 0) */
/* speed is in rotations/second, so '2' completes two full spins per second. */
CC_API void Env_SetSkyboxHorSpeed(float speed);
/* Sets how quickly skybox rotates/spins vertically. (default 0) */
/* speed is in rotations/second, so '2' completes two full spins per second. */
CC_API void Env_SetSkyboxVerSpeed(float speed);

/* Sets colour of the sky above clouds. (default #99CCFF) */
CC_API void Env_SetSkyCol(PackedCol color);
/* Sets base colour of the horizon fog. (default #FFFFFF) */
/* Actual fog colour is blended between sky and fog colours, based on view distance. */
CC_API void Env_SetFogCol(PackedCol color);
/* Sets colour of clouds. (default #FFFFFF) */
CC_API void Env_SetCloudsCol(PackedCol color);
/* Sets colour of the skybox. (default #FFFFFF) */
CC_API void Env_SetSkyboxCol(PackedCol color);
/* Sets colour of sunlight. (default #FFFFFF) */
/* This is the colour used for lighting when not underground. */
CC_API void Env_SetSunCol(PackedCol color);
/* Sets colour of shadow. (default #9B9B9B) */
/* This is the colour used for lighting when underground. */
CC_API void Env_SetShadowCol(PackedCol color);
/* Sets colour that bright natural blocks cast with fancy lighting. (default #FFEBC6) */
CC_API void Env_SetLavaLightCol(PackedCol color);
/* Sets colour that bright artificial blocks cast with fancy lighting. (default #FFFFFF) */
CC_API void Env_SetLampLightCol(PackedCol color);

#define RESPAWN_NOT_FOUND -100000.0f
/* Finds the highest Y coordinate of any solid block that intersects the given bounding box */
/* So essentially, means max(Y + Block_MaxBB[block].y) over all solid blocks the AABB touches */
/* Returns RESPAWN_NOT_FOUND when no intersecting solid blocks are found. */
float Respawn_HighestSolidY(struct AABB* bb);
/* Finds a suitable initial spawn position for the entity. */
/* Works by iterating downwards from top of world until solid ground is found. */
Vec3 Respawn_FindSpawnPosition(float x, float z, Vec3 modelSize);
#endif