diff options
author | WlodekM <[email protected]> | 2024-06-16 10:35:45 +0300 |
---|---|---|
committer | WlodekM <[email protected]> | 2024-06-16 10:35:45 +0300 |
commit | abef6da56913f1c55528103e60a50451a39628b1 (patch) | |
tree | b3c8092471ecbb73e568cd0d336efa0e7871ee8d /src/World.c |
initial commit
Diffstat (limited to 'src/World.c')
-rw-r--r-- | src/World.c | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/src/World.c b/src/World.c new file mode 100644 index 0000000..b01563d --- /dev/null +++ b/src/World.c @@ -0,0 +1,326 @@ +#include "World.h" +#include "Logger.h" +#include "String.h" +#include "Platform.h" +#include "Event.h" +#include "Block.h" +#include "Entity.h" +#include "ExtMath.h" +#include "Physics.h" +#include "Game.h" +#include "TexturePack.h" +#include "Window.h" + +struct _WorldData World; +static char nameBuffer[STRING_SIZE]; +/*########################################################################################################################* +*----------------------------------------------------------World----------------------------------------------------------* +*#########################################################################################################################*/ +static void GenerateNewUuid(void) { + RNGState rnd; + int i; + Random_SeedFromCurrentTime(&rnd); + + /* seed a bit more randomness for uuid */ + for (i = 0; i < Game_Username.length; i++) { + Random_Next(&rnd, Game_Username.buffer[i] + 3); + } + + for (i = 0; i < WORLD_UUID_LEN; i++) { + World.Uuid[i] = Random_Next(&rnd, 256); + } + + /* Set version and variant bits */ + World.Uuid[6] &= 0x0F; + World.Uuid[6] |= 0x40; /* version 4*/ + World.Uuid[8] &= 0x3F; + World.Uuid[8] |= 0x80; /* variant 2*/ +} + +void World_Reset(void) { +#ifdef EXTENDED_BLOCKS + if (World.Blocks != World.Blocks2) Mem_Free(World.Blocks2); + World.Blocks2 = NULL; + World.IDMask = 0xFF; +#endif + Mem_Free(World.Blocks); + World.Blocks = NULL; + String_InitArray(World.Name, nameBuffer); + + World_SetDimensions(0, 0, 0); + World.Loaded = false; + World.LastSave = -200; + World.Seed = 0; + Env_Reset(); +} + +void World_NewMap(void) { + World_Reset(); + Event_RaiseVoid(&WorldEvents.NewMap); +} + +void World_SetNewMap(BlockRaw* blocks, int width, int height, int length) { + /* TODO: TEMP HACK */ + if (!blocks) { width = 0; height = 0; length = 0; } + + World_SetDimensions(width, height, length); + World.Blocks = blocks; + World.Name.length = 0; + + if (!World.Volume) World.Blocks = NULL; +#ifdef EXTENDED_BLOCKS + /* .cw maps may have set this to a non-NULL when importing */ + if (!World.Blocks2) { + World.Blocks2 = World.Blocks; + World.IDMask = 0xFF; + } +#endif + + if (Env.EdgeHeight == -1) { Env.EdgeHeight = height / 2; } + if (Env.CloudsHeight == -1) { Env.CloudsHeight = height + 2; } + + GenerateNewUuid(); + World.Loaded = true; + Event_RaiseVoid(&WorldEvents.MapLoaded); +} + +CC_NOINLINE void World_SetDimensions(int width, int height, int length) { + World.Width = width; World.Height = height; World.Length = length; + World.Volume = width * height * length; + + World.OneY = width * length; + World.MaxX = width - 1; + World.MaxY = height - 1; + World.MaxZ = length - 1; + + World.ChunksX = (width + CHUNK_MAX) >> CHUNK_SHIFT; + World.ChunksY = (height + CHUNK_MAX) >> CHUNK_SHIFT; + World.ChunksZ = (length + CHUNK_MAX) >> CHUNK_SHIFT; + + World.ChunksCount = World.ChunksX * World.ChunksY * World.ChunksZ; +} + +#ifdef EXTENDED_BLOCKS +void World_SetMapUpper(BlockRaw* blocks) { + World.Blocks2 = blocks; + World.IDMask = 0x3FF; +} +#endif + +void World_OutOfMemory(void) { + Window_ShowDialog("Out of memory", "Not enough free memory to load the map.\nTry joining a different map."); + World_Reset(); +} + + +#ifdef EXTENDED_BLOCKS +static CC_NOINLINE void LazyInitUpper(int i, BlockID block) { + BlockRaw* data = (BlockRaw*)Mem_TryAllocCleared(World.Volume, 1); + if (!data) { World_OutOfMemory(); return; } + + World_SetMapUpper(data); + World.Blocks2[i] = (BlockRaw)(block >> 8); +} + +void World_SetBlock(int x, int y, int z, BlockID block) { + int i = World_Pack(x, y, z); + World.Blocks[i] = (BlockRaw)block; + + /* defer allocation of second map array if possible */ + if (World.Blocks == World.Blocks2) { + if (block < 256) return; + LazyInitUpper(i, block); + return; + } + World.Blocks2[i] = (BlockRaw)(block >> 8); +} +#else +void World_SetBlock(int x, int y, int z, BlockID block) { + World.Blocks[World_Pack(x, y, z)] = block; +} +#endif + +BlockID World_GetPhysicsBlock(int x, int y, int z) { + if (y < 0 || !World_ContainsXZ(x, z)) return BLOCK_BEDROCK; + if (y >= World.Height) return BLOCK_AIR; + + return World_GetBlock(x, y, z); +} + +BlockID World_SafeGetBlock(int x, int y, int z) { + return World_Contains(x, y, z) ? World_GetBlock(x, y, z) : BLOCK_AIR; +} + + +/*########################################################################################################################* +*-------------------------------------------------------Environment-------------------------------------------------------* +*#########################################################################################################################*/ +#define Env_Set(src, dst, var) \ +if (src != dst) { dst = src; Event_RaiseInt(&WorldEvents.EnvVarChanged, var); } + +struct _EnvData Env; +const char* const Weather_Names[3] = { "Sunny", "Rainy", "Snowy" }; + +void Env_Reset(void) { + Env.EdgeHeight = -1; + Env.SidesOffset = -2; + Env.CloudsHeight = -1; + + Env.EdgeBlock = BLOCK_STILL_WATER; + Env.SidesBlock = BLOCK_BEDROCK; + + Env.CloudsSpeed = 1.0f; + Env.WeatherSpeed = 1.0f; + Env.WeatherFade = 1.0f; + Env.SkyboxHorSpeed = 0.0f; + Env.SkyboxVerSpeed = 0.0f; + + Env.ShadowCol = ENV_DEFAULT_SHADOW_COLOR; + PackedCol_GetShaded(Env.ShadowCol, &Env.ShadowXSide, + &Env.ShadowZSide, &Env.ShadowYMin); + + Env.SunCol = ENV_DEFAULT_SUN_COLOR; + PackedCol_GetShaded(Env.SunCol, &Env.SunXSide, + &Env.SunZSide, &Env.SunYMin); + + Env.SkyCol = ENV_DEFAULT_SKY_COLOR; + Env.FogCol = ENV_DEFAULT_FOG_COLOR; + Env.CloudsCol = ENV_DEFAULT_CLOUDS_COLOR; + Env.SkyboxCol = ENV_DEFAULT_SKYBOX_COLOR; + Env.LavaLightCol = ENV_DEFAULT_LAVALIGHT_COLOR; + Env.LampLightCol = ENV_DEFAULT_LAMPLIGHT_COLOR; + Env.Weather = WEATHER_SUNNY; + Env.ExpFog = false; +} + + +void Env_SetEdgeBlock(BlockID block) { + /* some server software wrongly uses this value */ + if (block == 255 && !Block_IsCustomDefined(255)) block = BLOCK_STILL_WATER; + Env_Set(block, Env.EdgeBlock, ENV_VAR_EDGE_BLOCK); +} +void Env_SetSidesBlock(BlockID block) { + /* some server software wrongly uses this value */ + if (block == 255 && !Block_IsCustomDefined(255)) block = BLOCK_BEDROCK; + Env_Set(block, Env.SidesBlock, ENV_VAR_SIDES_BLOCK); +} + +void Env_SetEdgeHeight(int height) { + Env_Set(height, Env.EdgeHeight, ENV_VAR_EDGE_HEIGHT); +} +void Env_SetSidesOffset(int offset) { + Env_Set(offset, Env.SidesOffset, ENV_VAR_SIDES_OFFSET); +} +void Env_SetCloudsHeight(int height) { + Env_Set(height, Env.CloudsHeight, ENV_VAR_CLOUDS_HEIGHT); +} +void Env_SetCloudsSpeed(float speed) { + Env_Set(speed, Env.CloudsSpeed, ENV_VAR_CLOUDS_SPEED); +} + +void Env_SetWeatherSpeed(float speed) { + Env_Set(speed, Env.WeatherSpeed, ENV_VAR_WEATHER_SPEED); +} +void Env_SetWeatherFade(float rate) { + Env_Set(rate, Env.WeatherFade, ENV_VAR_WEATHER_FADE); +} +void Env_SetWeather(int weather) { + Env_Set(weather, Env.Weather, ENV_VAR_WEATHER); +} +void Env_SetExpFog(cc_bool expFog) { + Env_Set(expFog, Env.ExpFog, ENV_VAR_EXP_FOG); +} +void Env_SetSkyboxHorSpeed(float speed) { + Env_Set(speed, Env.SkyboxHorSpeed, ENV_VAR_SKYBOX_HOR_SPEED); +} +void Env_SetSkyboxVerSpeed(float speed) { + Env_Set(speed, Env.SkyboxVerSpeed, ENV_VAR_SKYBOX_VER_SPEED); +} + +void Env_SetSkyCol(PackedCol color) { + Env_Set(color, Env.SkyCol, ENV_VAR_SKY_COLOR); +} +void Env_SetFogCol(PackedCol color) { + Env_Set(color, Env.FogCol, ENV_VAR_FOG_COLOR); +} +void Env_SetCloudsCol(PackedCol color) { + Env_Set(color, Env.CloudsCol, ENV_VAR_CLOUDS_COLOR); +} +void Env_SetSkyboxCol(PackedCol color) { + Env_Set(color, Env.SkyboxCol, ENV_VAR_SKYBOX_COLOR); +} +void Env_SetLavaLightCol(PackedCol color) { + Env_Set(color, Env.LavaLightCol, ENV_VAR_LAVALIGHT_COLOR); +} +void Env_SetLampLightCol(PackedCol color) { + Env_Set(color, Env.LampLightCol, ENV_VAR_LAMPLIGHT_COLOR); +} +void Env_SetSunCol(PackedCol color) { + PackedCol_GetShaded(color, &Env.SunXSide, &Env.SunZSide, &Env.SunYMin); + Env_Set(color, Env.SunCol, ENV_VAR_SUN_COLOR); +} +void Env_SetShadowCol(PackedCol color) { + PackedCol_GetShaded(color, &Env.ShadowXSide, &Env.ShadowZSide, &Env.ShadowYMin); + Env_Set(color, Env.ShadowCol, ENV_VAR_SHADOW_COLOR); +} + + +/*########################################################################################################################* +*-------------------------------------------------------Respawning--------------------------------------------------------* +*#########################################################################################################################*/ +float Respawn_HighestSolidY(struct AABB* bb) { + int minX = Math_Floor(bb->Min.x), maxX = Math_Floor(bb->Max.x); + int minY = Math_Floor(bb->Min.y), maxY = Math_Floor(bb->Max.y); + int minZ = Math_Floor(bb->Min.z), maxZ = Math_Floor(bb->Max.z); + float highestY = RESPAWN_NOT_FOUND; + + BlockID block; + struct AABB blockBB; + Vec3 v; + int x, y, z; + + for (y = minY; y <= maxY; y++) { v.y = (float)y; + for (z = minZ; z <= maxZ; z++) { v.z = (float)z; + for (x = minX; x <= maxX; x++) { v.x = (float)x; + + /* TODO: Maybe use how picking gets blocks, so the bedrock */ + /* just below and just on borders of the map is treated as such */ + /* Not sure if this is really necessary though, it seems to work */ + /* just fine already when you're standing on the bottom of the map. */ + block = World_SafeGetBlock(x, y, z); + Vec3_Add(&blockBB.Min, &v, &Blocks.MinBB[block]); + Vec3_Add(&blockBB.Max, &v, &Blocks.MaxBB[block]); + + if (Blocks.Collide[block] != COLLIDE_SOLID) continue; + if (!AABB_Intersects(bb, &blockBB)) continue; + if (blockBB.Max.y > highestY) highestY = blockBB.Max.y; + } + } + } + return highestY; +} + +Vec3 Respawn_FindSpawnPosition(float x, float z, Vec3 modelSize) { + Vec3 spawn; + struct AABB bb; + float highestY; + int y; + + Vec3_Set(spawn, x, World.Height + ENTITY_ADJUSTMENT, z); + AABB_Make(&bb, &spawn, &modelSize); + spawn.y = 0.0f; + + for (y = World.Height; y >= 0; y--) { + highestY = Respawn_HighestSolidY(&bb); + if (highestY != RESPAWN_NOT_FOUND) { + spawn.y = highestY; break; + } + bb.Min.y -= 1.0f; bb.Max.y -= 1.0f; + } + return spawn; +} + +struct IGameComponent World_Component = { + World_Reset, /* Init */ + World_Reset /* Free */ +}; |