mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'zesterer/small-fixes' into 'master'
Caverns See merge request veloren/veloren!2763
This commit is contained in:
commit
3357008601
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -6275,6 +6275,7 @@ dependencies = [
|
|||||||
"ordered-float 2.8.0",
|
"ordered-float 2.8.0",
|
||||||
"profiling",
|
"profiling",
|
||||||
"rand 0.8.4",
|
"rand 0.8.4",
|
||||||
|
"rand_chacha 0.3.1",
|
||||||
"rayon",
|
"rayon",
|
||||||
"rodio",
|
"rodio",
|
||||||
"ron",
|
"ron",
|
||||||
|
@ -131,6 +131,9 @@ void main() {
|
|||||||
|
|
||||||
vec3 emitted_light, reflected_light;
|
vec3 emitted_light, reflected_light;
|
||||||
|
|
||||||
|
// Prevent the sky affecting light when underground
|
||||||
|
float not_underground = clamp((f_pos.z - f_alt) / 128.0 + 1.0, 0.0, 1.0);
|
||||||
|
|
||||||
// float point_shadow = shadow_at(f_pos, f_norm);
|
// float point_shadow = shadow_at(f_pos, f_norm);
|
||||||
// vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
// vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
||||||
// vec3 emitted_light, reflected_light;
|
// vec3 emitted_light, reflected_light;
|
||||||
@ -143,6 +146,11 @@ void main() {
|
|||||||
// vec3 surf_color = /*srgb_to_linear*/(vec3(0.4, 0.7, 2.0));
|
// vec3 surf_color = /*srgb_to_linear*/(vec3(0.4, 0.7, 2.0));
|
||||||
float max_light = 0.0;
|
float max_light = 0.0;
|
||||||
max_light += get_sun_diffuse2(sun_info, moon_info, f_norm, /*time_of_day.x*//*-cam_to_frag*/sun_view_dir/*view_dir*/, f_pos, mu, cam_attenuation, fluid_alt, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, /*vec3(0.0)*/k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
max_light += get_sun_diffuse2(sun_info, moon_info, f_norm, /*time_of_day.x*//*-cam_to_frag*/sun_view_dir/*view_dir*/, f_pos, mu, cam_attenuation, fluid_alt, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, /*vec3(0.0)*/k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
||||||
|
emitted_light *= not_underground;
|
||||||
|
reflected_light *= not_underground;
|
||||||
|
|
||||||
|
// Global illumination when underground (silly)
|
||||||
|
emitted_light += (1.0 - not_underground) * 0.05;
|
||||||
// reflected_light *= f_light * point_shadow * shade_frac;
|
// reflected_light *= f_light * point_shadow * shade_frac;
|
||||||
// emitted_light *= f_light * point_shadow * max(shade_frac, MIN_SHADOW);
|
// emitted_light *= f_light * point_shadow * max(shade_frac, MIN_SHADOW);
|
||||||
// max_light *= f_light * point_shadow * shade_frac;
|
// max_light *= f_light * point_shadow * shade_frac;
|
||||||
|
@ -179,6 +179,10 @@ void main() {
|
|||||||
vec3 reflect_color = get_sky_color(/*reflect_ray_dir*/beam_view_dir, time_of_day.x, f_pos, vec3(-100000), 0.125, true);
|
vec3 reflect_color = get_sky_color(/*reflect_ray_dir*/beam_view_dir, time_of_day.x, f_pos, vec3(-100000), 0.125, true);
|
||||||
reflect_color = get_cloud_color(reflect_color, reflect_ray_dir, cam_pos.xyz, time_of_day.x, 100000.0, 0.1);
|
reflect_color = get_cloud_color(reflect_color, reflect_ray_dir, cam_pos.xyz, time_of_day.x, 100000.0, 0.1);
|
||||||
reflect_color *= f_light;
|
reflect_color *= f_light;
|
||||||
|
|
||||||
|
// Prevent the sky affecting light when underground
|
||||||
|
float not_underground = clamp((f_pos.z - f_alt) / 128.0 + 1.0, 0.0, 1.0);
|
||||||
|
reflect_color *= not_underground;
|
||||||
// /*const */vec3 water_color = srgb_to_linear(vec3(0.2, 0.5, 1.0));
|
// /*const */vec3 water_color = srgb_to_linear(vec3(0.2, 0.5, 1.0));
|
||||||
// /*const */vec3 water_color = srgb_to_linear(vec3(0.8, 0.9, 1.0));
|
// /*const */vec3 water_color = srgb_to_linear(vec3(0.8, 0.9, 1.0));
|
||||||
// NOTE: Linear RGB, attenuation coefficients for water at roughly R, G, B wavelengths.
|
// NOTE: Linear RGB, attenuation coefficients for water at roughly R, G, B wavelengths.
|
||||||
@ -254,6 +258,11 @@ void main() {
|
|||||||
|
|
||||||
float max_light = 0.0;
|
float max_light = 0.0;
|
||||||
max_light += get_sun_diffuse2(sun_info, moon_info, norm, /*time_of_day.x*/sun_view_dir, f_pos, mu, cam_attenuation, fluid_alt, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, vec3(k_d), /*vec3(f_light * point_shadow)*//*reflect_color*/k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
max_light += get_sun_diffuse2(sun_info, moon_info, norm, /*time_of_day.x*/sun_view_dir, f_pos, mu, cam_attenuation, fluid_alt, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, vec3(k_d), /*vec3(f_light * point_shadow)*//*reflect_color*/k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
||||||
|
emitted_light *= not_underground;
|
||||||
|
reflected_light *= not_underground;
|
||||||
|
|
||||||
|
// Global illumination when underground (silly)
|
||||||
|
emitted_light += (1.0 - not_underground) * 0.05;
|
||||||
// Apply cloud layer to sky
|
// Apply cloud layer to sky
|
||||||
// reflected_light *= /*water_color_direct * */reflect_color * f_light * point_shadow * shade_frac;
|
// reflected_light *= /*water_color_direct * */reflect_color * f_light * point_shadow * shade_frac;
|
||||||
// emitted_light *= /*water_color_direct*//*ambient_attenuation * */f_light * point_shadow * max(shade_frac, MIN_SHADOW);
|
// emitted_light *= /*water_color_direct*//*ambient_attenuation * */f_light * point_shadow * max(shade_frac, MIN_SHADOW);
|
||||||
|
@ -16,7 +16,7 @@ float cloud_broad(vec3 pos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns vec4(r, g, b, density)
|
// Returns vec4(r, g, b, density)
|
||||||
vec4 cloud_at(vec3 pos, float dist, out vec3 emission) {
|
vec4 cloud_at(vec3 pos, float dist, out vec3 emission, out float not_underground) {
|
||||||
// Natural attenuation of air (air naturally attenuates light that passes through it)
|
// Natural attenuation of air (air naturally attenuates light that passes through it)
|
||||||
// Simulate the atmosphere thinning as you get higher. Not physically accurate, but then
|
// Simulate the atmosphere thinning as you get higher. Not physically accurate, but then
|
||||||
// it can't be since Veloren's world is flat, not spherical.
|
// it can't be since Veloren's world is flat, not spherical.
|
||||||
@ -134,7 +134,7 @@ vec4 cloud_at(vec3 pos, float dist, out vec3 emission) {
|
|||||||
//moon_access *= suppress_mist;
|
//moon_access *= suppress_mist;
|
||||||
|
|
||||||
// Prevent clouds and mist appearing underground (but fade them out gently)
|
// Prevent clouds and mist appearing underground (but fade them out gently)
|
||||||
float not_underground = clamp(1.0 - (alt - (pos.z - focus_off.z)) / 80.0 + dist * 0.001, 0, 1);
|
not_underground = clamp(1.0 - (alt - (pos.z - focus_off.z)) / 80.0 + dist * 0.001, 0, 1);
|
||||||
sun_access *= not_underground;
|
sun_access *= not_underground;
|
||||||
moon_access *= not_underground;
|
moon_access *= not_underground;
|
||||||
float vapor_density = (mist + cloud) * not_underground;
|
float vapor_density = (mist + cloud) * not_underground;
|
||||||
@ -220,8 +220,9 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of
|
|||||||
cdist = step_to_dist(trunc(dist_to_step(cdist - 0.25, quality)), quality);
|
cdist = step_to_dist(trunc(dist_to_step(cdist - 0.25, quality)), quality);
|
||||||
|
|
||||||
vec3 emission;
|
vec3 emission;
|
||||||
|
float not_underground; // Used to prevent sunlight leaking underground
|
||||||
// `sample` is a reserved keyword
|
// `sample` is a reserved keyword
|
||||||
vec4 sample_ = cloud_at(origin + dir * ldist * splay, ldist, emission);
|
vec4 sample_ = cloud_at(origin + dir * ldist * splay, ldist, emission, not_underground);
|
||||||
|
|
||||||
vec2 density_integrals = max(sample_.zw, vec2(0));
|
vec2 density_integrals = max(sample_.zw, vec2(0));
|
||||||
|
|
||||||
@ -239,7 +240,7 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of
|
|||||||
// Add the directed light light scattered into the camera by the clouds and the atmosphere (global illumination)
|
// Add the directed light light scattered into the camera by the clouds and the atmosphere (global illumination)
|
||||||
sun_color * sun_scatter * get_sun_brightness() * (sun_access * (1.0 - cloud_darken) /*+ sky_color * global_scatter_factor*/) +
|
sun_color * sun_scatter * get_sun_brightness() * (sun_access * (1.0 - cloud_darken) /*+ sky_color * global_scatter_factor*/) +
|
||||||
moon_color * moon_scatter * get_moon_brightness() * (moon_access * (1.0 - cloud_darken) /*+ sky_color * global_scatter_factor*/) +
|
moon_color * moon_scatter * get_moon_brightness() * (moon_access * (1.0 - cloud_darken) /*+ sky_color * global_scatter_factor*/) +
|
||||||
sky_light * (1.0 - global_darken) +
|
sky_light * (1.0 - global_darken) * not_underground +
|
||||||
emission * density_integrals.y;
|
emission * density_integrals.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ vec3 glow_light(vec3 pos) {
|
|||||||
#if (SHADOW_MODE <= SHADOW_MODE_NONE)
|
#if (SHADOW_MODE <= SHADOW_MODE_NONE)
|
||||||
return GLOW_COLOR;
|
return GLOW_COLOR;
|
||||||
#else
|
#else
|
||||||
return GLOW_COLOR * (1.0 + (noise_3d(vec3(pos.xy * 0.005, tick.x * 0.5)) - 0.5) * 1.0);
|
return GLOW_COLOR * (1.0 + (noise_3d(vec3(pos.xy * 0.005, tick.x * 0.5)) - 0.5) * 0.5);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,8 +253,12 @@ void main() {
|
|||||||
|
|
||||||
// Computing light attenuation from water.
|
// Computing light attenuation from water.
|
||||||
vec3 emitted_light, reflected_light;
|
vec3 emitted_light, reflected_light;
|
||||||
|
|
||||||
|
// Prevent the sky affecting light when underground
|
||||||
|
float not_underground = clamp((f_pos.z - f_alt) / 128.0 + 1.0, 0.0, 1.0);
|
||||||
|
|
||||||
// To account for prior saturation
|
// To account for prior saturation
|
||||||
/*float */f_light = faces_fluid ? 1.0 : f_light * sqrt(f_light);
|
/*float */f_light = faces_fluid ? not_underground : f_light * sqrt(f_light);
|
||||||
|
|
||||||
emitted_light = vec3(1.0);
|
emitted_light = vec3(1.0);
|
||||||
reflected_light = vec3(1.0);
|
reflected_light = vec3(1.0);
|
||||||
@ -268,7 +272,7 @@ void main() {
|
|||||||
max_light *= f_light;
|
max_light *= f_light;
|
||||||
|
|
||||||
// TODO: Apply AO after this
|
// TODO: Apply AO after this
|
||||||
vec3 glow = glow_light(f_pos) * (pow(f_glow, 6) * 5 + pow(f_glow, 1.5) * 2);
|
vec3 glow = glow_light(f_pos) * (pow(f_glow, 3) * 5 + pow(f_glow, 2.0) * 2);
|
||||||
reflected_light += glow;
|
reflected_light += glow;
|
||||||
|
|
||||||
max_light += lights_at(f_pos, f_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
max_light += lights_at(f_pos, f_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
||||||
|
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-0.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-0.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-2.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-2.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-3.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-3.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-4.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-4.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-5.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-5.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-6.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-6.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-7.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_long-7.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_med-0.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_med-0.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_med-1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_med-1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_med-2.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_med-2.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_med-3.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_med-3.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_short-0.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_short-0.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_short-1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_short-1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_short-2.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_short-2.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_short-3.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_short-3.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/grass_short-4.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/grass_short-4.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/lillypad-0.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/lillypad-0.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/lillypad-1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/lillypad-1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/lillypad-2.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/lillypad-2.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/lillypad-3.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/lillypad-3.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/lillypad-4.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/lillypad-4.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/mycel-0.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/mycel-0.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/mycel-1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/mycel-1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/mycel-2.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/mycel-2.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cavern/mycel-3.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cavern/mycel-3.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -3258,6 +3258,7 @@ CookingPot: Some((
|
|||||||
],
|
],
|
||||||
wind_sway: 0.0,
|
wind_sway: 0.0,
|
||||||
)),
|
)),
|
||||||
|
// Ensnaring Vines
|
||||||
EnsnaringVines: Some((
|
EnsnaringVines: Some((
|
||||||
variations: [
|
variations: [
|
||||||
(
|
(
|
||||||
@ -3310,4 +3311,164 @@ Bones: Some((
|
|||||||
],
|
],
|
||||||
wind_sway: 0.0,
|
wind_sway: 0.0,
|
||||||
)),
|
)),
|
||||||
|
// Short Cavern Grass Blue
|
||||||
|
CavernGrassBlueShort: Some((
|
||||||
|
variations: [
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_short-0",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_short-1",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_short-2",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_short-3",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_short-4",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
wind_sway: 0.0,
|
||||||
|
)),
|
||||||
|
// Medium Cavern Grass Blue
|
||||||
|
CavernGrassBlueMedium: Some((
|
||||||
|
variations: [
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_med-0",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_med-1",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_med-2",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_med-3",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
wind_sway: 0.0,
|
||||||
|
)),
|
||||||
|
// Long Cavern Grass Blue
|
||||||
|
CavernGrassBlueLong: Some((
|
||||||
|
variations: [
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_long-0",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_long-1",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_long-2",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_long-3",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_long-4",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_long-5",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_long-6",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.grass_long-7",
|
||||||
|
offset: (-5.5, -5.5, 0.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
wind_sway: 0.0,
|
||||||
|
)),
|
||||||
|
// Cavern Lillypads Blue
|
||||||
|
CavernLillypadBlue: Some((
|
||||||
|
variations: [
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.lillypad-0",
|
||||||
|
offset: (-5.5, -5.5, -1.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.lillypad-1",
|
||||||
|
offset: (-5.5, -5.5, -1.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.lillypad-2",
|
||||||
|
offset: (-5.5, -5.5, -1.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.lillypad-3",
|
||||||
|
offset: (-5.5, -5.5, -1.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.lillypad-4",
|
||||||
|
offset: (-5.5, -5.5, -1.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
wind_sway: 0.0,
|
||||||
|
)),
|
||||||
|
// Cavern Hanging Mycel Blue
|
||||||
|
CavernMycelBlue: Some((
|
||||||
|
variations: [
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.mycel-0",
|
||||||
|
offset: (-0.5, -0.5, -21.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.mycel-1",
|
||||||
|
offset: (-0.5, -0.5, -31.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.mycel-2",
|
||||||
|
offset: (-0.5, -0.5, -14.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
model: "voxygen.voxel.sprite.cavern.mycel-3",
|
||||||
|
offset: (-0.5, -0.5, -40.0),
|
||||||
|
lod_axes: (0.0, 0.0, 0.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
wind_sway: 0.1,
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
|
12
assets/world/features.ron
Normal file
12
assets/world/features.ron
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#![enable(unwrap_newtypes)]
|
||||||
|
#![enable(implicit_some)]
|
||||||
|
|
||||||
|
(
|
||||||
|
caverns: false, // TODO: Disabled by default until cave overhaul
|
||||||
|
caves: true,
|
||||||
|
shrubs: true,
|
||||||
|
trees: true,
|
||||||
|
scatter: true,
|
||||||
|
paths: true,
|
||||||
|
spots: true,
|
||||||
|
)
|
@ -67,7 +67,7 @@
|
|||||||
deep_stone_color: (125, 120, 130),
|
deep_stone_color: (125, 120, 130),
|
||||||
layer: (
|
layer: (
|
||||||
bridge: (80, 80, 100),
|
bridge: (80, 80, 100),
|
||||||
stalagtite: (90, 71, 112),
|
stalactite: (90, 71, 112),
|
||||||
cave_floor: (42, 39, 82),
|
cave_floor: (42, 39, 82),
|
||||||
cave_roof: (38, 21, 79),
|
cave_roof: (38, 21, 79),
|
||||||
dirt: (69, 48, 15),
|
dirt: (69, 48, 15),
|
||||||
|
@ -644,6 +644,11 @@ impl<const AVERAGE_PALETTE: bool> VoxelImageDecoding for TriPngEncoding<AVERAGE_
|
|||||||
g: 206,
|
g: 206,
|
||||||
b: 64,
|
b: 64,
|
||||||
},
|
},
|
||||||
|
GlowingMushroom => Rgb {
|
||||||
|
r: 50,
|
||||||
|
g: 250,
|
||||||
|
b: 250,
|
||||||
|
},
|
||||||
Misc => Rgb {
|
Misc => Rgb {
|
||||||
r: 255,
|
r: 255,
|
||||||
g: 0,
|
g: 0,
|
||||||
|
@ -48,7 +48,8 @@ make_case_elim!(
|
|||||||
// 0x32 <= x < 0x40 is reserved for future earths/muds/gravels/sands/etc.
|
// 0x32 <= x < 0x40 is reserved for future earths/muds/gravels/sands/etc.
|
||||||
Wood = 0x40,
|
Wood = 0x40,
|
||||||
Leaves = 0x41,
|
Leaves = 0x41,
|
||||||
// 0x42 <= x < 0x50 is reserved for future tree parts
|
GlowingMushroom = 0x42,
|
||||||
|
// 0x43 <= x < 0x50 is reserved for future tree parts
|
||||||
// Covers all other cases (we sometimes have bizarrely coloured misc blocks, and also we
|
// Covers all other cases (we sometimes have bizarrely coloured misc blocks, and also we
|
||||||
// often want to experiment with new kinds of block without allocating them a
|
// often want to experiment with new kinds of block without allocating them a
|
||||||
// dedicated block kind.
|
// dedicated block kind.
|
||||||
@ -177,7 +178,8 @@ impl Block {
|
|||||||
pub fn get_glow(&self) -> Option<u8> {
|
pub fn get_glow(&self) -> Option<u8> {
|
||||||
match self.kind() {
|
match self.kind() {
|
||||||
BlockKind::Lava => Some(24),
|
BlockKind::Lava => Some(24),
|
||||||
BlockKind::GlowingRock | BlockKind::GlowingWeakRock => Some(12),
|
BlockKind::GlowingRock | BlockKind::GlowingWeakRock => Some(10),
|
||||||
|
BlockKind::GlowingMushroom => Some(20),
|
||||||
_ => match self.get_sprite()? {
|
_ => match self.get_sprite()? {
|
||||||
SpriteKind::StreetLamp | SpriteKind::StreetLampTall => Some(24),
|
SpriteKind::StreetLamp | SpriteKind::StreetLampTall => Some(24),
|
||||||
SpriteKind::Ember => Some(20),
|
SpriteKind::Ember => Some(20),
|
||||||
@ -188,7 +190,11 @@ impl Block {
|
|||||||
| SpriteKind::Orb => Some(16),
|
| SpriteKind::Orb => Some(16),
|
||||||
SpriteKind::Velorite
|
SpriteKind::Velorite
|
||||||
| SpriteKind::VeloriteFrag
|
| SpriteKind::VeloriteFrag
|
||||||
| SpriteKind::Cauldron
|
| SpriteKind::CavernGrassBlueShort
|
||||||
|
| SpriteKind::CavernGrassBlueMedium
|
||||||
|
| SpriteKind::CavernGrassBlueLong
|
||||||
|
| SpriteKind::CavernLillypadBlue
|
||||||
|
| SpriteKind::CavernMycelBlue
|
||||||
| SpriteKind::CeilingMushroom => Some(6),
|
| SpriteKind::CeilingMushroom => Some(6),
|
||||||
SpriteKind::CaveMushroom
|
SpriteKind::CaveMushroom
|
||||||
| SpriteKind::CookingPot
|
| SpriteKind::CookingPot
|
||||||
|
@ -71,6 +71,22 @@ impl<V, S: RectVolSize, M: Clone> Chonk<V, S, M> {
|
|||||||
self.sub_chunks.iter().map(SubChunk::num_groups).sum()
|
self.sub_chunks.iter().map(SubChunk::num_groups).sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterate through the voxels in this chunk, attempting to avoid those that
|
||||||
|
/// are unchanged (i.e: match the `below` and `above` voxels). This is
|
||||||
|
/// generally useful for performance reasons.
|
||||||
|
pub fn iter_changed(&self) -> impl Iterator<Item = (Vec3<i32>, &V)> + '_ {
|
||||||
|
self.sub_chunks
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, sc)| sc.num_groups() > 0)
|
||||||
|
.map(move |(i, sc)| {
|
||||||
|
let z_offset = self.z_offset + i as i32 * SubChunkSize::<S>::SIZE.z as i32;
|
||||||
|
sc.vol_iter(Vec3::zero(), SubChunkSize::<S>::SIZE.map(|e| e as i32))
|
||||||
|
.map(move |(pos, vox)| (pos + Vec3::unit_z() * z_offset, vox))
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the index (in self.sub_chunks) of the SubChunk that contains
|
// Returns the index (in self.sub_chunks) of the SubChunk that contains
|
||||||
// layer z; note that this index changes when more SubChunks are prepended
|
// layer z; note that this index changes when more SubChunks are prepended
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -177,6 +177,11 @@ make_case_elim!(
|
|||||||
WitchWindow = 0x96,
|
WitchWindow = 0x96,
|
||||||
SmokeDummy = 0x97,
|
SmokeDummy = 0x97,
|
||||||
Bones = 0x98,
|
Bones = 0x98,
|
||||||
|
CavernGrassBlueShort = 0x99,
|
||||||
|
CavernGrassBlueMedium = 0x9A,
|
||||||
|
CavernGrassBlueLong = 0x9B,
|
||||||
|
CavernLillypadBlue = 0x9C,
|
||||||
|
CavernMycelBlue = 0x9D,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -263,7 +268,7 @@ impl SpriteKind {
|
|||||||
| SpriteKind::Tin
|
| SpriteKind::Tin
|
||||||
| SpriteKind::Silver
|
| SpriteKind::Silver
|
||||||
| SpriteKind::Gold => 0.6,
|
| SpriteKind::Gold => 0.6,
|
||||||
SpriteKind::EnsnaringVines => 0.1,
|
SpriteKind::EnsnaringVines | SpriteKind::CavernLillypadBlue => 0.1,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -851,7 +851,7 @@ impl Server {
|
|||||||
let ecs = self.state.ecs_mut();
|
let ecs = self.state.ecs_mut();
|
||||||
let slow_jobs = ecs.write_resource::<SlowJobPool>();
|
let slow_jobs = ecs.write_resource::<SlowJobPool>();
|
||||||
|
|
||||||
index.reload_colors_if_changed(|index| {
|
index.reload_if_changed(|index| {
|
||||||
let mut chunk_generator = ecs.write_resource::<ChunkGenerator>();
|
let mut chunk_generator = ecs.write_resource::<ChunkGenerator>();
|
||||||
let client = ecs.read_storage::<Client>();
|
let client = ecs.read_storage::<Client>();
|
||||||
let mut terrain = ecs.write_resource::<common::terrain::TerrainGrid>();
|
let mut terrain = ecs.write_resource::<common::terrain::TerrainGrid>();
|
||||||
|
@ -106,6 +106,7 @@ native-dialog = { version = "0.5.2", optional = true }
|
|||||||
num = "0.4"
|
num = "0.4"
|
||||||
ordered-float = { version = "2.0.1", default-features = false }
|
ordered-float = { version = "2.0.1", default-features = false }
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
|
rand_chacha = "0.3"
|
||||||
rayon = "1.5"
|
rayon = "1.5"
|
||||||
rodio = {version = "0.14", default-features = false, features = ["vorbis"]}
|
rodio = {version = "0.14", default-features = false, features = ["vorbis"]}
|
||||||
ron = {version = "0.6", default-features = false}
|
ron = {version = "0.6", default-features = false}
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
use crate::hud::CraftingTab;
|
use crate::hud::CraftingTab;
|
||||||
use common::{
|
use common::terrain::{BlockKind, SpriteKind, TerrainChunk};
|
||||||
terrain::{BlockKind, SpriteKind, TerrainChunk},
|
|
||||||
vol::{IntoVolIterator, RectRasterableVol},
|
|
||||||
};
|
|
||||||
use common_base::span;
|
use common_base::span;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
use rand_chacha::ChaCha8Rng;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
@ -60,61 +58,46 @@ impl BlocksOfInterest {
|
|||||||
let mut cricket3 = Vec::new();
|
let mut cricket3 = Vec::new();
|
||||||
let mut frogs = Vec::new();
|
let mut frogs = Vec::new();
|
||||||
|
|
||||||
chunk
|
let mut rng = ChaCha8Rng::from_seed(thread_rng().gen());
|
||||||
.vol_iter(
|
|
||||||
Vec3::new(0, 0, chunk.get_min_z()),
|
chunk.iter_changed().for_each(|(pos, block)| {
|
||||||
Vec3::new(
|
|
||||||
TerrainChunk::RECT_SIZE.x as i32,
|
|
||||||
TerrainChunk::RECT_SIZE.y as i32,
|
|
||||||
chunk.get_max_z(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.for_each(|(pos, block)| {
|
|
||||||
match block.kind() {
|
match block.kind() {
|
||||||
BlockKind::Leaves if thread_rng().gen_range(0..16) == 0 => leaves.push(pos),
|
BlockKind::Leaves if rng.gen_range(0..16) == 0 => leaves.push(pos),
|
||||||
BlockKind::WeakRock if thread_rng().gen_range(0..6) == 0 => drip.push(pos),
|
BlockKind::WeakRock if rng.gen_range(0..6) == 0 => drip.push(pos),
|
||||||
BlockKind::Grass => {
|
BlockKind::Grass => {
|
||||||
if thread_rng().gen_range(0..16) == 0 {
|
if rng.gen_range(0..16) == 0 {
|
||||||
grass.push(pos);
|
grass.push(pos);
|
||||||
}
|
}
|
||||||
match thread_rng().gen_range(0..8192) {
|
match rng.gen_range(0..8192) {
|
||||||
1 => cricket1.push(pos),
|
1 => cricket1.push(pos),
|
||||||
2 => cricket2.push(pos),
|
2 => cricket2.push(pos),
|
||||||
3 => cricket3.push(pos),
|
3 => cricket3.push(pos),
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
BlockKind::Water
|
BlockKind::Water if chunk.meta().contains_river() && rng.gen_range(0..16) == 0 => {
|
||||||
if chunk.meta().contains_river() && thread_rng().gen_range(0..16) == 0 =>
|
|
||||||
{
|
|
||||||
river.push(pos)
|
river.push(pos)
|
||||||
},
|
},
|
||||||
BlockKind::Lava if thread_rng().gen_range(0..5) == 0 => {
|
BlockKind::Snow if rng.gen_range(0..16) == 0 => snow.push(pos),
|
||||||
fires.push(pos + Vec3::unit_z())
|
BlockKind::Lava if rng.gen_range(0..5) == 0 => fires.push(pos + Vec3::unit_z()),
|
||||||
},
|
BlockKind::Snow if rng.gen_range(0..16) == 0 => snow.push(pos),
|
||||||
BlockKind::Snow if thread_rng().gen_range(0..16) == 0 => snow.push(pos),
|
|
||||||
_ => match block.get_sprite() {
|
_ => match block.get_sprite() {
|
||||||
Some(SpriteKind::Ember) => {
|
Some(SpriteKind::Ember) => {
|
||||||
fires.push(pos);
|
fires.push(pos);
|
||||||
smokers.push(pos);
|
smokers.push(pos);
|
||||||
},
|
},
|
||||||
Some(SpriteKind::SmokeDummy) => {
|
|
||||||
smokers.push(pos);
|
|
||||||
},
|
|
||||||
// Offset positions to account for block height.
|
// Offset positions to account for block height.
|
||||||
// TODO: Is this a good idea?
|
// TODO: Is this a good idea?
|
||||||
Some(SpriteKind::StreetLamp) => fire_bowls.push(pos + Vec3::unit_z() * 2),
|
Some(SpriteKind::StreetLamp) => fire_bowls.push(pos + Vec3::unit_z() * 2),
|
||||||
Some(SpriteKind::FireBowlGround) => fire_bowls.push(pos + Vec3::unit_z()),
|
Some(SpriteKind::FireBowlGround) => fire_bowls.push(pos + Vec3::unit_z()),
|
||||||
Some(SpriteKind::StreetLampTall) => {
|
Some(SpriteKind::StreetLampTall) => fire_bowls.push(pos + Vec3::unit_z() * 4),
|
||||||
fire_bowls.push(pos + Vec3::unit_z() * 3);
|
|
||||||
},
|
|
||||||
Some(SpriteKind::WallSconce) => fire_bowls.push(pos + Vec3::unit_z()),
|
Some(SpriteKind::WallSconce) => fire_bowls.push(pos + Vec3::unit_z()),
|
||||||
Some(SpriteKind::Beehive) => beehives.push(pos),
|
Some(SpriteKind::Beehive) => beehives.push(pos),
|
||||||
Some(SpriteKind::CrystalHigh) => fireflies.push(pos),
|
Some(SpriteKind::CrystalHigh) => fireflies.push(pos),
|
||||||
Some(SpriteKind::Reed) => {
|
Some(SpriteKind::Reed) => {
|
||||||
reeds.push(pos);
|
reeds.push(pos);
|
||||||
fireflies.push(pos);
|
fireflies.push(pos);
|
||||||
if thread_rng().gen_range(0..12) == 0 {
|
if rng.gen_range(0..12) == 0 {
|
||||||
frogs.push(pos);
|
frogs.push(pos);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -128,6 +111,9 @@ impl BlocksOfInterest {
|
|||||||
Some(SpriteKind::CraftingBench) => {
|
Some(SpriteKind::CraftingBench) => {
|
||||||
interactables.push((pos, Interaction::Craft(CraftingTab::All)))
|
interactables.push((pos, Interaction::Craft(CraftingTab::All)))
|
||||||
},
|
},
|
||||||
|
Some(SpriteKind::SmokeDummy) => {
|
||||||
|
smokers.push(pos);
|
||||||
|
},
|
||||||
Some(SpriteKind::Forge) => {
|
Some(SpriteKind::Forge) => {
|
||||||
interactables.push((pos, Interaction::Craft(CraftingTab::Dismantle)))
|
interactables.push((pos, Interaction::Craft(CraftingTab::Dismantle)))
|
||||||
},
|
},
|
||||||
|
@ -17,7 +17,12 @@ fn main() {
|
|||||||
let mut focus = Vec2::<f32>::zero();
|
let mut focus = Vec2::<f32>::zero();
|
||||||
let mut zoom = 1.0;
|
let mut zoom = 1.0;
|
||||||
let colors = &**index.colors().read();
|
let colors = &**index.colors().read();
|
||||||
let index = IndexRef { colors, index };
|
let features = &**index.features().read();
|
||||||
|
let index = IndexRef {
|
||||||
|
colors,
|
||||||
|
features,
|
||||||
|
index,
|
||||||
|
};
|
||||||
|
|
||||||
while win.is_open() {
|
while win.is_open() {
|
||||||
let mut buf = vec![0; W * H];
|
let mut buf = vec![0; W * H];
|
||||||
|
@ -414,7 +414,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
downhill_chunk.river.river_kind,
|
downhill_chunk.river.river_kind,
|
||||||
Some(RiverKind::Lake { .. })
|
Some(RiverKind::Lake { .. })
|
||||||
))
|
))
|
||||||
&& (river_chunk.water_alt > downhill_chunk.water_alt + 8.0)
|
&& (river_chunk.water_alt > downhill_chunk.water_alt + 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine the altitude of a river based on the altitude of the
|
/// Determine the altitude of a river based on the altitude of the
|
||||||
@ -452,7 +452,14 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
// they do not result in artifacts, even in edge cases. The exact configuration
|
// they do not result in artifacts, even in edge cases. The exact configuration
|
||||||
// of this code is the product of hundreds of hours of testing and
|
// of this code is the product of hundreds of hours of testing and
|
||||||
// refinement and I ask that you do not take that effort lightly.
|
// refinement and I ask that you do not take that effort lightly.
|
||||||
let (river_water_level, in_river, lake_water_level, lake_dist, water_dist, unbounded_water_level) = neighbor_river_data.iter().copied().fold(
|
let (
|
||||||
|
river_water_level,
|
||||||
|
in_river,
|
||||||
|
lake_water_level,
|
||||||
|
lake_dist,
|
||||||
|
water_dist,
|
||||||
|
unbounded_water_level,
|
||||||
|
) = neighbor_river_data.iter().copied().fold(
|
||||||
(
|
(
|
||||||
WeightedSum::default().with_max(base_sea_level),
|
WeightedSum::default().with_max(base_sea_level),
|
||||||
false,
|
false,
|
||||||
@ -461,7 +468,18 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
None,
|
None,
|
||||||
WeightedSum::default().with_max(base_sea_level),
|
WeightedSum::default().with_max(base_sea_level),
|
||||||
),
|
),
|
||||||
|(mut river_water_level, mut in_river, mut lake_water_level, mut lake_dist, water_dist, mut unbounded_water_level), (river_chunk_idx, river_chunk, river, dist_info)| match (river.river_kind, dist_info) {
|
|(
|
||||||
|
mut river_water_level,
|
||||||
|
mut in_river,
|
||||||
|
lake_water_level,
|
||||||
|
mut lake_dist,
|
||||||
|
water_dist,
|
||||||
|
mut unbounded_water_level,
|
||||||
|
),
|
||||||
|
(river_chunk_idx, river_chunk, river, dist_info)| match (
|
||||||
|
river.river_kind,
|
||||||
|
dist_info,
|
||||||
|
) {
|
||||||
(
|
(
|
||||||
Some(kind),
|
Some(kind),
|
||||||
Some((_, _, river_width, (river_t, (river_pos, _), downhill_chunk))),
|
Some((_, _, river_width, (river_t, (river_pos, _), downhill_chunk))),
|
||||||
@ -480,7 +498,8 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
RiverKind::River { .. } => {
|
RiverKind::River { .. } => {
|
||||||
// Alt of river water *is* the alt of land (ignoring gorge, which gets applied later)
|
// Alt of river water *is* the alt of land (ignoring gorge, which gets
|
||||||
|
// applied later)
|
||||||
let river_water_alt = river_water_alt(
|
let river_water_alt = river_water_alt(
|
||||||
river_chunk.alt.max(river_chunk.water_alt),
|
river_chunk.alt.max(river_chunk.water_alt),
|
||||||
downhill_chunk.alt.max(downhill_chunk.water_alt),
|
downhill_chunk.alt.max(downhill_chunk.water_alt),
|
||||||
@ -488,14 +507,15 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
is_waterfall(river_chunk_idx, river_chunk, downhill_chunk),
|
is_waterfall(river_chunk_idx, river_chunk, downhill_chunk),
|
||||||
);
|
);
|
||||||
|
|
||||||
river_water_level = river_water_level
|
river_water_level =
|
||||||
.with(river_water_alt, near_center);
|
river_water_level.with(river_water_alt, near_center);
|
||||||
|
|
||||||
if river_edge_dist <= 0.0 {
|
if river_edge_dist <= 0.0 {
|
||||||
in_river = true;
|
in_river = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Slightly wider threshold is chosen in case the lake bounds are a bit wrong
|
// Slightly wider threshold is chosen in case the lake bounds are a bit
|
||||||
|
// wrong
|
||||||
RiverKind::Lake { .. } | RiverKind::Ocean => {
|
RiverKind::Lake { .. } | RiverKind::Ocean => {
|
||||||
let lake_water_alt = if matches!(kind, RiverKind::Ocean) {
|
let lake_water_alt = if matches!(kind, RiverKind::Ocean) {
|
||||||
base_sea_level
|
base_sea_level
|
||||||
@ -509,32 +529,63 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if river_edge_dist > 0.0 && river_width > lake_width * 0.99 {
|
if river_edge_dist > 0.0 && river_width > lake_width * 0.99 {
|
||||||
let unbounded_water_alt = lake_water_alt - ((river_edge_dist - 8.0).max(0.0) / 5.0).powf(2.0);
|
let unbounded_water_alt = lake_water_alt
|
||||||
|
- ((river_edge_dist - 8.0).max(0.0) / 5.0).powf(2.0);
|
||||||
unbounded_water_level = unbounded_water_level
|
unbounded_water_level = unbounded_water_level
|
||||||
.with(unbounded_water_alt, 1.0 / (1.0 + river_edge_dist * 5.0))
|
.with(unbounded_water_alt, 1.0 / (1.0 + river_edge_dist * 5.0));
|
||||||
.with_max(unbounded_water_alt);
|
//.with_max(unbounded_water_alt);
|
||||||
}
|
}
|
||||||
|
|
||||||
river_water_level = river_water_level
|
river_water_level = river_water_level.with(lake_water_alt, near_center);
|
||||||
.with(lake_water_alt, near_center);
|
|
||||||
|
|
||||||
lake_dist = lake_dist.min(river_edge_dist);
|
lake_dist = lake_dist.min(river_edge_dist);
|
||||||
|
|
||||||
// Lake border prevents a lake failing to propagate its altitude to nearby rivers
|
// Lake border prevents a lake failing to propagate its altitude to
|
||||||
if river_edge_dist <= 0.0 {
|
// nearby rivers
|
||||||
lake_water_level = lake_water_level
|
let off = 0.0;
|
||||||
// Make sure the closest lake is prioritised
|
let len = 3.0;
|
||||||
.with(lake_water_alt, near_center + 0.1 / (1.0 + river_edge_dist));
|
if river_edge_dist <= off {
|
||||||
|
// lake_water_level = lake_water_level
|
||||||
|
// // Make sure the closest lake is prioritised
|
||||||
|
// .with(lake_water_alt, near_center + 0.1 / (1.0 +
|
||||||
|
// river_edge_dist)); // .with_min(lake_water_alt);
|
||||||
|
//
|
||||||
|
river_water_level = river_water_level.with_min(
|
||||||
|
lake_water_alt
|
||||||
|
+ ((((river_dist - river_width * 0.5) as f32 + len - off)
|
||||||
|
.max(0.0))
|
||||||
|
/ len)
|
||||||
|
.powf(1.5)
|
||||||
|
* 32.0,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let river_edge_dist_unclamped = (river_dist - river_width * 0.5) as f32;
|
let river_edge_dist_unclamped = (river_dist - river_width * 0.5) as f32;
|
||||||
let water_dist = Some(water_dist.unwrap_or(river_edge_dist_unclamped).min(river_edge_dist_unclamped));
|
let water_dist = Some(
|
||||||
|
water_dist
|
||||||
|
.unwrap_or(river_edge_dist_unclamped)
|
||||||
|
.min(river_edge_dist_unclamped),
|
||||||
|
);
|
||||||
|
|
||||||
(river_water_level, in_river, lake_water_level, lake_dist, water_dist, unbounded_water_level)
|
(
|
||||||
|
river_water_level,
|
||||||
|
in_river,
|
||||||
|
lake_water_level,
|
||||||
|
lake_dist,
|
||||||
|
water_dist,
|
||||||
|
unbounded_water_level,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
(_, _) => (river_water_level, in_river, lake_water_level, lake_dist, water_dist, unbounded_water_level),
|
(_, _) => (
|
||||||
|
river_water_level,
|
||||||
|
in_river,
|
||||||
|
lake_water_level,
|
||||||
|
lake_dist,
|
||||||
|
water_dist,
|
||||||
|
unbounded_water_level,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let unbounded_water_level = unbounded_water_level.eval_or(base_sea_level);
|
let unbounded_water_level = unbounded_water_level.eval_or(base_sea_level);
|
||||||
@ -679,7 +730,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
)
|
)
|
||||||
.with_min(min_alt.unwrap_or(riverbed_alt).min(riverbed_alt))
|
.with_min(min_alt.unwrap_or(riverbed_alt).min(riverbed_alt))
|
||||||
} else {
|
} else {
|
||||||
const GORGE: f32 = 0.5;
|
const GORGE: f32 = 0.25;
|
||||||
const BANK_SCALE: f32 = 24.0;
|
const BANK_SCALE: f32 = 24.0;
|
||||||
// Weighting of this riverbank on nearby terrain (higher when closer to
|
// Weighting of this riverbank on nearby terrain (higher when closer to
|
||||||
// the river). This 'pulls' the riverbank
|
// the river). This 'pulls' the riverbank
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
use common::assets;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub sea_level: f32,
|
pub sea_level: f32,
|
||||||
pub mountain_scale: f32,
|
pub mountain_scale: f32,
|
||||||
@ -69,3 +72,20 @@ pub const CONFIG: Config = Config {
|
|||||||
river_min_height: 0.25,
|
river_min_height: 0.25,
|
||||||
river_width_to_depth: 8.0,
|
river_width_to_depth: 8.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct Features {
|
||||||
|
pub caverns: bool,
|
||||||
|
pub caves: bool,
|
||||||
|
pub shrubs: bool,
|
||||||
|
pub trees: bool,
|
||||||
|
pub scatter: bool,
|
||||||
|
pub paths: bool,
|
||||||
|
pub spots: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl assets::Asset for Features {
|
||||||
|
type Loader = assets::RonLoader;
|
||||||
|
|
||||||
|
const EXTENSION: &'static str = "ron";
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
layer::wildlife::{self, DensityFn, SpawnEntry},
|
layer::wildlife::{self, DensityFn, SpawnEntry},
|
||||||
site::{economy::TradeInformation, Site},
|
site::{economy::TradeInformation, Site},
|
||||||
Colors,
|
Colors, Features,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
assets::{AssetExt, AssetHandle},
|
assets::{AssetExt, AssetHandle},
|
||||||
@ -13,6 +13,7 @@ use noise::{Seedable, SuperSimplex};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
const WORLD_COLORS_MANIFEST: &str = "world.style.colors";
|
const WORLD_COLORS_MANIFEST: &str = "world.style.colors";
|
||||||
|
const WORLD_FEATURES_MANIFEST: &str = "world.features";
|
||||||
|
|
||||||
pub struct Index {
|
pub struct Index {
|
||||||
pub seed: u32,
|
pub seed: u32,
|
||||||
@ -22,6 +23,7 @@ pub struct Index {
|
|||||||
pub trade: TradeInformation,
|
pub trade: TradeInformation,
|
||||||
pub wildlife_spawns: Vec<(AssetHandle<SpawnEntry>, DensityFn)>,
|
pub wildlife_spawns: Vec<(AssetHandle<SpawnEntry>, DensityFn)>,
|
||||||
colors: AssetHandle<Arc<Colors>>,
|
colors: AssetHandle<Arc<Colors>>,
|
||||||
|
features: AssetHandle<Arc<Features>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An owned reference to indexed data.
|
/// An owned reference to indexed data.
|
||||||
@ -32,6 +34,7 @@ pub struct Index {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct IndexOwned {
|
pub struct IndexOwned {
|
||||||
colors: Arc<Colors>,
|
colors: Arc<Colors>,
|
||||||
|
features: Arc<Features>,
|
||||||
index: Arc<Index>,
|
index: Arc<Index>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +50,7 @@ impl Deref for IndexOwned {
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct IndexRef<'a> {
|
pub struct IndexRef<'a> {
|
||||||
pub colors: &'a Colors,
|
pub colors: &'a Colors,
|
||||||
|
pub features: &'a Features,
|
||||||
pub index: &'a Index,
|
pub index: &'a Index,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +64,7 @@ impl Index {
|
|||||||
/// NOTE: Panics if the color manifest cannot be loaded.
|
/// NOTE: Panics if the color manifest cannot be loaded.
|
||||||
pub fn new(seed: u32) -> Self {
|
pub fn new(seed: u32) -> Self {
|
||||||
let colors = Arc::<Colors>::load_expect(WORLD_COLORS_MANIFEST);
|
let colors = Arc::<Colors>::load_expect(WORLD_COLORS_MANIFEST);
|
||||||
|
let features = Arc::<Features>::load_expect(WORLD_FEATURES_MANIFEST);
|
||||||
let wildlife_spawns = wildlife::spawn_manifest()
|
let wildlife_spawns = wildlife::spawn_manifest()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(e, f)| (SpawnEntry::load_expect(e), f))
|
.map(|(e, f)| (SpawnEntry::load_expect(e), f))
|
||||||
@ -73,11 +78,14 @@ impl Index {
|
|||||||
trade: Default::default(),
|
trade: Default::default(),
|
||||||
wildlife_spawns,
|
wildlife_spawns,
|
||||||
colors,
|
colors,
|
||||||
|
features,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn colors(&self) -> AssetHandle<Arc<Colors>> { self.colors }
|
pub fn colors(&self) -> AssetHandle<Arc<Colors>> { self.colors }
|
||||||
|
|
||||||
|
pub fn features(&self) -> AssetHandle<Arc<Features>> { self.features }
|
||||||
|
|
||||||
pub fn get_site_prices(&self, site_id: SiteId) -> Option<SitePrices> {
|
pub fn get_site_prices(&self, site_id: SiteId) -> Option<SitePrices> {
|
||||||
self.sites
|
self.sites
|
||||||
.recreate_id(site_id)
|
.recreate_id(site_id)
|
||||||
@ -89,10 +97,12 @@ impl Index {
|
|||||||
impl IndexOwned {
|
impl IndexOwned {
|
||||||
pub fn new(index: Index) -> Self {
|
pub fn new(index: Index) -> Self {
|
||||||
let colors = index.colors.cloned();
|
let colors = index.colors.cloned();
|
||||||
|
let features = index.features.cloned();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
index: Arc::new(index),
|
index: Arc::new(index),
|
||||||
colors,
|
colors,
|
||||||
|
features,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,13 +113,12 @@ impl IndexOwned {
|
|||||||
/// solution.
|
/// solution.
|
||||||
///
|
///
|
||||||
/// Ideally, this should be called about once per tick.
|
/// Ideally, this should be called about once per tick.
|
||||||
pub fn reload_colors_if_changed<R>(
|
pub fn reload_if_changed<R>(&mut self, reload: impl FnOnce(&mut Self) -> R) -> Option<R> {
|
||||||
&mut self,
|
let reloaded = self.index.colors.reloaded_global() || self.index.features.reloaded_global();
|
||||||
reload: impl FnOnce(&mut Self) -> R,
|
reloaded.then(move || {
|
||||||
) -> Option<R> {
|
// Reload the fields from the asset handle, which is updated automatically
|
||||||
self.index.colors.reloaded_global().then(move || {
|
|
||||||
// Reload the color from the asset handle, which is updated automatically
|
|
||||||
self.colors = self.index.colors.cloned();
|
self.colors = self.index.colors.cloned();
|
||||||
|
self.features = self.index.features.cloned();
|
||||||
reload(self)
|
reload(self)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -117,6 +126,7 @@ impl IndexOwned {
|
|||||||
pub fn as_index_ref(&self) -> IndexRef {
|
pub fn as_index_ref(&self) -> IndexRef {
|
||||||
IndexRef {
|
IndexRef {
|
||||||
colors: &self.colors,
|
colors: &self.colors,
|
||||||
|
features: &self.features,
|
||||||
index: &self.index,
|
index: &self.index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,8 @@ pub use self::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
column::ColumnSample,
|
column::ColumnSample,
|
||||||
util::{FastNoise, RandomField, Sampler},
|
config::CONFIG,
|
||||||
|
util::{FastNoise, RandomField, RandomPerm, Sampler},
|
||||||
Canvas, IndexRef,
|
Canvas, IndexRef,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
@ -20,19 +21,20 @@ use common::{
|
|||||||
terrain::{Block, BlockKind, SpriteKind},
|
terrain::{Block, BlockKind, SpriteKind},
|
||||||
vol::{BaseVol, ReadVol, RectSizedVol, WriteVol},
|
vol::{BaseVol, ReadVol, RectSizedVol, WriteVol},
|
||||||
};
|
};
|
||||||
|
use hashbrown::HashMap;
|
||||||
use noise::NoiseFn;
|
use noise::NoiseFn;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{
|
use std::{
|
||||||
f32,
|
f32,
|
||||||
ops::{Mul, Range, Sub},
|
ops::{Add, Mul, Range, Sub},
|
||||||
};
|
};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct Colors {
|
pub struct Colors {
|
||||||
pub bridge: (u8, u8, u8),
|
pub bridge: (u8, u8, u8),
|
||||||
pub stalagtite: (u8, u8, u8),
|
pub stalactite: (u8, u8, u8),
|
||||||
pub cave_floor: (u8, u8, u8),
|
pub cave_floor: (u8, u8, u8),
|
||||||
pub cave_roof: (u8, u8, u8),
|
pub cave_roof: (u8, u8, u8),
|
||||||
pub dirt: (u8, u8, u8),
|
pub dirt: (u8, u8, u8),
|
||||||
@ -170,11 +172,11 @@ pub fn apply_caves_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
|||||||
let floor_dist = pit_condition as i32 * pit_depth as i32;
|
let floor_dist = pit_condition as i32 * pit_depth as i32;
|
||||||
let vein_condition =
|
let vein_condition =
|
||||||
cave_depth % 12.0 > 11.5 && cave_x > 0.1 && cave_x < 0.6 && cave_depth > 200.0;
|
cave_depth % 12.0 > 11.5 && cave_x > 0.1 && cave_x < 0.6 && cave_depth > 200.0;
|
||||||
let stalagtite_condition = cave_depth > 150.0;
|
let stalactite_condition = cave_depth > 150.0;
|
||||||
let vein_depth = 3;
|
let vein_depth = 3;
|
||||||
let vein_floor = cave_base - vein_depth;
|
let vein_floor = cave_base - vein_depth;
|
||||||
// Stalagtites
|
// Stalagtites
|
||||||
let stalagtites = info
|
let stalactites = info
|
||||||
.index()
|
.index()
|
||||||
.noise
|
.noise
|
||||||
.cave_nz
|
.cave_nz
|
||||||
@ -188,18 +190,18 @@ pub fn apply_caves_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
|||||||
)
|
)
|
||||||
.mul(45.0) as i32;
|
.mul(45.0) as i32;
|
||||||
|
|
||||||
// Generate stalagtites if there's something for them to hold on to
|
// Generate stalactites if there's something for them to hold on to
|
||||||
if canvas
|
if canvas
|
||||||
.get(Vec3::new(wpos2d.x, wpos2d.y, cave_roof))
|
.get(Vec3::new(wpos2d.x, wpos2d.y, cave_roof))
|
||||||
.is_filled()
|
.is_filled()
|
||||||
&& stalagtite_condition
|
&& stalactite_condition
|
||||||
{
|
{
|
||||||
for z in cave_roof - stalagtites..cave_roof {
|
for z in cave_roof - stalactites..cave_roof {
|
||||||
canvas.set(
|
canvas.set(
|
||||||
Vec3::new(wpos2d.x, wpos2d.y, z),
|
Vec3::new(wpos2d.x, wpos2d.y, z),
|
||||||
Block::new(
|
Block::new(
|
||||||
BlockKind::WeakRock,
|
BlockKind::WeakRock,
|
||||||
noisy_color(info.index().colors.layer.stalagtite.into(), 8),
|
noisy_color(info.index().colors.layer.stalactite.into(), 8),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -570,3 +572,396 @@ pub fn apply_coral_to(canvas: &mut Canvas) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn apply_caverns_to<R: Rng>(canvas: &mut Canvas, dynamic_rng: &mut R) {
|
||||||
|
let info = canvas.info();
|
||||||
|
|
||||||
|
let canvern_nz_at = |wpos2d: Vec2<i32>| {
|
||||||
|
// Horizontal average scale of caverns
|
||||||
|
let scale = 2048.0;
|
||||||
|
// How common should they be? (0.0 - 1.0)
|
||||||
|
let common = 0.15;
|
||||||
|
|
||||||
|
let cavern_nz = info
|
||||||
|
.index()
|
||||||
|
.noise
|
||||||
|
.cave_nz
|
||||||
|
.get((wpos2d.map(|e| e as f64) / scale).into_array()) as f32;
|
||||||
|
((cavern_nz * 0.5 + 0.5 - (1.0 - common)).max(0.0) / common).powf(common * 2.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get cavern attributes at a position
|
||||||
|
let cavern_at = |wpos2d| {
|
||||||
|
let alt = info.land().get_alt_approx(wpos2d);
|
||||||
|
|
||||||
|
// Range of heights for the caverns
|
||||||
|
let height_range = 16.0..250.0;
|
||||||
|
// Minimum distance below the surface
|
||||||
|
let surface_clearance = 64.0;
|
||||||
|
|
||||||
|
let cavern_avg_height = Lerp::lerp(
|
||||||
|
height_range.start,
|
||||||
|
height_range.end,
|
||||||
|
info.index()
|
||||||
|
.noise
|
||||||
|
.cave_nz
|
||||||
|
.get((wpos2d.map(|e| e as f64) / 300.0).into_array()) as f32
|
||||||
|
* 0.5
|
||||||
|
+ 0.5,
|
||||||
|
);
|
||||||
|
|
||||||
|
let cavern_avg_alt =
|
||||||
|
CONFIG.sea_level.min(alt * 0.25) - height_range.end - surface_clearance;
|
||||||
|
|
||||||
|
let cavern = canvern_nz_at(wpos2d);
|
||||||
|
let cavern_height = cavern * cavern_avg_height;
|
||||||
|
|
||||||
|
// Stalagtites
|
||||||
|
let stalactite = info
|
||||||
|
.index()
|
||||||
|
.noise
|
||||||
|
.cave_nz
|
||||||
|
.get(wpos2d.map(|e| e as f64 * 0.015).into_array())
|
||||||
|
.sub(0.5)
|
||||||
|
.max(0.0)
|
||||||
|
.mul((cavern_height as f64 - 5.0).mul(0.15).clamped(0.0, 1.0))
|
||||||
|
.mul(32.0 + cavern_avg_height as f64);
|
||||||
|
|
||||||
|
let hill = info
|
||||||
|
.index()
|
||||||
|
.noise
|
||||||
|
.cave_nz
|
||||||
|
.get((wpos2d.map(|e| e as f64) / 96.0).into_array()) as f32
|
||||||
|
* cavern
|
||||||
|
* 24.0;
|
||||||
|
let rugged = 0.4; // How bumpy should the floor be relative to the ceiling?
|
||||||
|
let cavern_bottom = (cavern_avg_alt - cavern_height * rugged + hill) as i32;
|
||||||
|
let cavern_avg_bottom =
|
||||||
|
(cavern_avg_alt - ((height_range.start + height_range.end) * 0.5) * rugged) as i32;
|
||||||
|
let cavern_top = (cavern_avg_alt + cavern_height) as i32;
|
||||||
|
let cavern_avg_top = (cavern_avg_alt + cavern_avg_height) as i32;
|
||||||
|
|
||||||
|
// Stalagmites rise up to meet stalactites
|
||||||
|
let stalagmite = stalactite;
|
||||||
|
|
||||||
|
let floor = stalagmite as i32;
|
||||||
|
|
||||||
|
(
|
||||||
|
cavern_bottom,
|
||||||
|
cavern_top,
|
||||||
|
cavern_avg_bottom,
|
||||||
|
cavern_avg_top,
|
||||||
|
floor,
|
||||||
|
stalactite,
|
||||||
|
cavern_avg_bottom as i32 + 16, // Water level
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut mushroom_cache = HashMap::new();
|
||||||
|
|
||||||
|
struct Mushroom {
|
||||||
|
pos: Vec3<i32>,
|
||||||
|
stalk: f32,
|
||||||
|
head_color: Rgb<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get mushroom block, if any, at a position
|
||||||
|
let mut get_mushroom = |wpos: Vec3<i32>, dynamic_rng: &mut R| {
|
||||||
|
for (wpos2d, seed) in info.chunks().gen_ctx.structure_gen.get(wpos.xy()) {
|
||||||
|
let mushroom = if let Some(mushroom) =
|
||||||
|
mushroom_cache.entry(wpos2d).or_insert_with(|| {
|
||||||
|
let mut rng = RandomPerm::new(seed);
|
||||||
|
let (cavern_bottom, cavern_top, _, _, floor, _, water_level) =
|
||||||
|
cavern_at(wpos2d);
|
||||||
|
let pos = wpos2d.with_z(cavern_bottom + floor);
|
||||||
|
if rng.gen_bool(0.15)
|
||||||
|
&& cavern_top - cavern_bottom > 32
|
||||||
|
&& pos.z as i32 > water_level - 2
|
||||||
|
{
|
||||||
|
Some(Mushroom {
|
||||||
|
pos,
|
||||||
|
stalk: 12.0 + rng.gen::<f32>().powf(2.0) * 35.0,
|
||||||
|
head_color: Rgb::new(
|
||||||
|
50,
|
||||||
|
rng.gen_range(70..110),
|
||||||
|
rng.gen_range(100..200),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
mushroom
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let wposf = wpos.map(|e| e as f64);
|
||||||
|
let warp_freq = 1.0 / 32.0;
|
||||||
|
let warp_amp = Vec3::new(12.0, 12.0, 12.0);
|
||||||
|
let wposf_warped = wposf.map(|e| e as f32)
|
||||||
|
+ Vec3::new(
|
||||||
|
FastNoise::new(seed).get(wposf * warp_freq) as f32,
|
||||||
|
FastNoise::new(seed + 1).get(wposf * warp_freq) as f32,
|
||||||
|
FastNoise::new(seed + 2).get(wposf * warp_freq) as f32,
|
||||||
|
) * warp_amp
|
||||||
|
* (wposf.z as f32 - mushroom.pos.z as f32)
|
||||||
|
.mul(0.1)
|
||||||
|
.clamped(0.0, 1.0);
|
||||||
|
|
||||||
|
let rpos = wposf_warped - mushroom.pos.map(|e| e as f32).map(|e| e as f32);
|
||||||
|
|
||||||
|
let stalk_radius = 2.5f32;
|
||||||
|
let head_radius = 18.0f32;
|
||||||
|
let head_height = 16.0;
|
||||||
|
|
||||||
|
let dist_sq = rpos.xy().magnitude_squared();
|
||||||
|
if dist_sq < head_radius.powi(2) {
|
||||||
|
let dist = dist_sq.sqrt();
|
||||||
|
let head_dist = ((rpos - Vec3::unit_z() * mushroom.stalk)
|
||||||
|
/ Vec2::broadcast(head_radius).with_z(head_height))
|
||||||
|
.magnitude();
|
||||||
|
|
||||||
|
let stalk = mushroom.stalk + Lerp::lerp(head_height * 0.5, 0.0, dist / head_radius);
|
||||||
|
|
||||||
|
// Head
|
||||||
|
if rpos.z > stalk
|
||||||
|
&& rpos.z <= mushroom.stalk + head_height
|
||||||
|
&& dist
|
||||||
|
< head_radius * (1.0 - (rpos.z - mushroom.stalk) / head_height).powf(0.125)
|
||||||
|
{
|
||||||
|
if head_dist < 0.85 {
|
||||||
|
let radial = (rpos.x.atan2(rpos.y) * 10.0).sin() * 0.5 + 0.5;
|
||||||
|
return Some(Block::new(
|
||||||
|
BlockKind::GlowingMushroom,
|
||||||
|
Rgb::new(30, 50 + (radial * 100.0) as u8, 100 - (radial * 50.0) as u8),
|
||||||
|
));
|
||||||
|
} else if head_dist < 1.0 {
|
||||||
|
return Some(Block::new(BlockKind::Wood, mushroom.head_color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rpos.z <= mushroom.stalk + head_height - 1.0
|
||||||
|
&& dist_sq
|
||||||
|
< (stalk_radius * Lerp::lerp(1.5, 0.75, rpos.z / mushroom.stalk)).powi(2)
|
||||||
|
{
|
||||||
|
// Stalk
|
||||||
|
return Some(Block::new(BlockKind::Wood, Rgb::new(25, 60, 90)));
|
||||||
|
} else if ((mushroom.stalk - 0.1)..(mushroom.stalk + 0.9)).contains(&rpos.z) // Hanging orbs
|
||||||
|
&& dist > head_radius * 0.85
|
||||||
|
&& dynamic_rng.gen_bool(0.1)
|
||||||
|
{
|
||||||
|
use SpriteKind::*;
|
||||||
|
let sprites = if dynamic_rng.gen_bool(0.1) {
|
||||||
|
&[Beehive, Lantern] as &[_]
|
||||||
|
} else {
|
||||||
|
&[Orb, CavernMycelBlue, CavernMycelBlue] as &[_]
|
||||||
|
};
|
||||||
|
return Some(Block::air(*sprites.choose(dynamic_rng).unwrap()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
canvas.foreach_col(|canvas, wpos2d, _col| {
|
||||||
|
if canvern_nz_at(wpos2d) <= 0.0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (
|
||||||
|
cavern_bottom,
|
||||||
|
cavern_top,
|
||||||
|
cavern_avg_bottom,
|
||||||
|
cavern_avg_top,
|
||||||
|
floor,
|
||||||
|
stalactite,
|
||||||
|
water_level,
|
||||||
|
) = cavern_at(wpos2d);
|
||||||
|
|
||||||
|
let mini_stalactite = info
|
||||||
|
.index()
|
||||||
|
.noise
|
||||||
|
.cave_nz
|
||||||
|
.get(wpos2d.map(|e| e as f64 * 0.08).into_array())
|
||||||
|
.sub(0.5)
|
||||||
|
.max(0.0)
|
||||||
|
.mul(
|
||||||
|
((cavern_top - cavern_bottom) as f64 - 5.0)
|
||||||
|
.mul(0.15)
|
||||||
|
.clamped(0.0, 1.0),
|
||||||
|
)
|
||||||
|
.mul(24.0 + (cavern_avg_top - cavern_avg_bottom) as f64 * 0.2);
|
||||||
|
let stalactite_height = (stalactite + mini_stalactite) as i32;
|
||||||
|
|
||||||
|
let moss_common = 1.5;
|
||||||
|
let moss = info
|
||||||
|
.index()
|
||||||
|
.noise
|
||||||
|
.cave_nz
|
||||||
|
.get(wpos2d.map(|e| e as f64 * 0.035).into_array())
|
||||||
|
.sub(1.0 - moss_common)
|
||||||
|
.max(0.0)
|
||||||
|
.mul(1.0 / moss_common)
|
||||||
|
.powf(8.0 * moss_common)
|
||||||
|
.mul(
|
||||||
|
((cavern_top - cavern_bottom) as f64)
|
||||||
|
.mul(0.15)
|
||||||
|
.clamped(0.0, 1.0),
|
||||||
|
)
|
||||||
|
.mul(16.0 + (cavern_avg_top - cavern_avg_bottom) as f64 * 0.35);
|
||||||
|
|
||||||
|
let plant_factor = info
|
||||||
|
.index()
|
||||||
|
.noise
|
||||||
|
.cave_nz
|
||||||
|
.get(wpos2d.map(|e| e as f64 * 0.015).into_array())
|
||||||
|
.add(1.0)
|
||||||
|
.mul(0.5)
|
||||||
|
.powf(2.0);
|
||||||
|
|
||||||
|
let is_vine = |wpos: Vec3<f32>, dynamic_rng: &mut R| {
|
||||||
|
let wpos = wpos + wpos.xy().yx().with_z(0.0) * 0.2; // A little twist
|
||||||
|
let dims = Vec2::new(7.0, 256.0); // Long and thin
|
||||||
|
let vine_posf = (wpos + Vec2::new(0.0, (wpos.x / dims.x).floor() * 733.0)) / dims; // ~Random offset
|
||||||
|
let vine_pos = vine_posf.map(|e| e.floor() as i32);
|
||||||
|
let mut rng = RandomPerm::new(((vine_pos.x << 16) | vine_pos.y) as u32); // Rng for vine attributes
|
||||||
|
if rng.gen_bool(0.2) {
|
||||||
|
let vine_height = (cavern_avg_top - cavern_avg_bottom).max(64) as f32;
|
||||||
|
let vine_base = cavern_avg_bottom as f32 + rng.gen_range(48.0..vine_height);
|
||||||
|
let vine_y = (vine_posf.y.fract() - 0.5).abs() * 2.0 * dims.y;
|
||||||
|
let vine_reach = (vine_y * 0.05).powf(2.0).min(1024.0);
|
||||||
|
let vine_z = vine_base + vine_reach;
|
||||||
|
if Vec2::new(vine_posf.x.fract() * 2.0 - 1.0, (wpos.z - vine_z) / 5.0)
|
||||||
|
.magnitude_squared()
|
||||||
|
< 1.0f32
|
||||||
|
{
|
||||||
|
let kind = if dynamic_rng.gen_bool(0.025) {
|
||||||
|
BlockKind::GlowingRock
|
||||||
|
} else {
|
||||||
|
BlockKind::Leaves
|
||||||
|
};
|
||||||
|
Some(Block::new(
|
||||||
|
kind,
|
||||||
|
Rgb::new(
|
||||||
|
85,
|
||||||
|
(vine_y + vine_reach).mul(0.05).sin().mul(35.0).add(85.0) as u8,
|
||||||
|
20,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let cavern_top = cavern_top as i32;
|
||||||
|
let mut last_kind = BlockKind::Rock;
|
||||||
|
for z in cavern_bottom - 1..cavern_top {
|
||||||
|
use SpriteKind::*;
|
||||||
|
|
||||||
|
let wpos = wpos2d.with_z(z);
|
||||||
|
let wposf = wpos.map(|e| e as f32);
|
||||||
|
|
||||||
|
let block = if z < cavern_bottom {
|
||||||
|
if z > water_level + dynamic_rng.gen_range(4..16) {
|
||||||
|
Block::new(BlockKind::Grass, Rgb::new(10, 75, 90))
|
||||||
|
} else {
|
||||||
|
Block::new(BlockKind::Rock, Rgb::new(50, 40, 10))
|
||||||
|
}
|
||||||
|
} else if z < cavern_bottom + floor {
|
||||||
|
Block::new(BlockKind::WeakRock, Rgb::new(110, 120, 150))
|
||||||
|
} else if z > cavern_top - stalactite_height {
|
||||||
|
if dynamic_rng.gen_bool(0.0035) {
|
||||||
|
// Glowing rock in stalactites
|
||||||
|
Block::new(BlockKind::GlowingRock, Rgb::new(30, 150, 120))
|
||||||
|
} else {
|
||||||
|
Block::new(BlockKind::WeakRock, Rgb::new(110, 120, 150))
|
||||||
|
}
|
||||||
|
} else if let Some(mushroom_block) = get_mushroom(wpos, dynamic_rng) {
|
||||||
|
mushroom_block
|
||||||
|
} else if z > cavern_top - moss as i32 {
|
||||||
|
let kind = if dynamic_rng
|
||||||
|
.gen_bool(0.05 / (1.0 + ((cavern_top - z).max(0) as f64).mul(0.1)))
|
||||||
|
{
|
||||||
|
BlockKind::GlowingMushroom
|
||||||
|
} else {
|
||||||
|
BlockKind::Leaves
|
||||||
|
};
|
||||||
|
Block::new(kind, Rgb::new(50, 120, 160))
|
||||||
|
} else if z < water_level {
|
||||||
|
Block::water(SpriteKind::Empty).with_sprite(
|
||||||
|
if z == cavern_bottom + floor && dynamic_rng.gen_bool(0.01) {
|
||||||
|
*[
|
||||||
|
SpriteKind::Seagrass,
|
||||||
|
SpriteKind::SeaGrapes,
|
||||||
|
SpriteKind::SeaweedTemperate,
|
||||||
|
SpriteKind::StonyCoral,
|
||||||
|
]
|
||||||
|
.choose(dynamic_rng)
|
||||||
|
.unwrap()
|
||||||
|
} else {
|
||||||
|
SpriteKind::Empty
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else if z == water_level
|
||||||
|
&& dynamic_rng.gen_bool(Lerp::lerp(0.0, 0.05, plant_factor))
|
||||||
|
&& last_kind == BlockKind::Water
|
||||||
|
{
|
||||||
|
Block::air(SpriteKind::CavernLillypadBlue)
|
||||||
|
} else if z == cavern_bottom + floor
|
||||||
|
&& dynamic_rng.gen_bool(Lerp::lerp(0.0, 0.5, plant_factor))
|
||||||
|
&& last_kind == BlockKind::Grass
|
||||||
|
{
|
||||||
|
Block::air(
|
||||||
|
*if dynamic_rng.gen_bool(0.9) {
|
||||||
|
// High density
|
||||||
|
&[
|
||||||
|
CavernGrassBlueShort,
|
||||||
|
CavernGrassBlueMedium,
|
||||||
|
CavernGrassBlueLong,
|
||||||
|
] as &[_]
|
||||||
|
} else if dynamic_rng.gen_bool(0.5) {
|
||||||
|
// Medium density
|
||||||
|
&[CaveMushroom] as &[_]
|
||||||
|
} else {
|
||||||
|
// Low density
|
||||||
|
&[LeafyPlant, Fern, Pyrebloom, Moonbell, Welwitch, GrassBlue] as &[_]
|
||||||
|
}
|
||||||
|
.choose(dynamic_rng)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
} else if z == cavern_top - 1 && dynamic_rng.gen_bool(0.001) {
|
||||||
|
Block::air(
|
||||||
|
*[CrystalHigh, CeilingMushroom, Orb, CavernMycelBlue]
|
||||||
|
.choose(dynamic_rng)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
} else if let Some(vine) = is_vine(wposf, dynamic_rng)
|
||||||
|
.or_else(|| is_vine(wposf.xy().yx().with_z(wposf.z), dynamic_rng))
|
||||||
|
{
|
||||||
|
vine
|
||||||
|
} else {
|
||||||
|
Block::empty()
|
||||||
|
};
|
||||||
|
|
||||||
|
last_kind = block.kind();
|
||||||
|
|
||||||
|
let block = if block.is_filled() {
|
||||||
|
Block::new(
|
||||||
|
block.kind(),
|
||||||
|
block.get_color().unwrap_or_default().map(|e| {
|
||||||
|
(e as f32 * dynamic_rng.gen_range(0.95..1.05)).clamped(0.0, 255.0) as u8
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
block
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = canvas.set(wpos, block);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -28,7 +28,7 @@ pub mod util;
|
|||||||
// Reexports
|
// Reexports
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
canvas::{Canvas, CanvasInfo},
|
canvas::{Canvas, CanvasInfo},
|
||||||
config::CONFIG,
|
config::{Features, CONFIG},
|
||||||
land::Land,
|
land::Land,
|
||||||
};
|
};
|
||||||
pub use block::BlockGen;
|
pub use block::BlockGen;
|
||||||
@ -52,7 +52,8 @@ use common::{
|
|||||||
vol::{ReadVol, RectVolSize, WriteVol},
|
vol::{ReadVol, RectVolSize, WriteVol},
|
||||||
};
|
};
|
||||||
use common_net::msg::{world_msg, WorldMapMsg};
|
use common_net::msg::{world_msg, WorldMapMsg};
|
||||||
use rand::Rng;
|
use rand::{prelude::*, Rng};
|
||||||
|
use rand_chacha::ChaCha8Rng;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -329,7 +330,7 @@ impl World {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Only use for rng affecting dynamic elements like chests and entities!
|
// Only use for rng affecting dynamic elements like chests and entities!
|
||||||
let mut dynamic_rng = rand::thread_rng();
|
let mut dynamic_rng = ChaCha8Rng::from_seed(thread_rng().gen());
|
||||||
|
|
||||||
// Apply layers (paths, caves, etc.)
|
// Apply layers (paths, caves, etc.)
|
||||||
let mut canvas = Canvas {
|
let mut canvas = Canvas {
|
||||||
@ -346,12 +347,27 @@ impl World {
|
|||||||
entities: Vec::new(),
|
entities: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if index.features.caverns {
|
||||||
|
layer::apply_caverns_to(&mut canvas, &mut dynamic_rng);
|
||||||
|
}
|
||||||
|
if index.features.caves {
|
||||||
layer::apply_caves_to(&mut canvas, &mut dynamic_rng);
|
layer::apply_caves_to(&mut canvas, &mut dynamic_rng);
|
||||||
|
}
|
||||||
|
if index.features.shrubs {
|
||||||
layer::apply_shrubs_to(&mut canvas, &mut dynamic_rng);
|
layer::apply_shrubs_to(&mut canvas, &mut dynamic_rng);
|
||||||
|
}
|
||||||
|
if index.features.trees {
|
||||||
layer::apply_trees_to(&mut canvas, &mut dynamic_rng);
|
layer::apply_trees_to(&mut canvas, &mut dynamic_rng);
|
||||||
|
}
|
||||||
|
if index.features.scatter {
|
||||||
layer::apply_scatter_to(&mut canvas, &mut dynamic_rng);
|
layer::apply_scatter_to(&mut canvas, &mut dynamic_rng);
|
||||||
|
}
|
||||||
|
if index.features.paths {
|
||||||
layer::apply_paths_to(&mut canvas);
|
layer::apply_paths_to(&mut canvas);
|
||||||
|
}
|
||||||
|
if index.features.spots {
|
||||||
layer::apply_spots_to(&mut canvas, &mut dynamic_rng);
|
layer::apply_spots_to(&mut canvas, &mut dynamic_rng);
|
||||||
|
}
|
||||||
// layer::apply_coral_to(&mut canvas);
|
// layer::apply_coral_to(&mut canvas);
|
||||||
|
|
||||||
// Apply site generation
|
// Apply site generation
|
||||||
@ -364,7 +380,7 @@ impl World {
|
|||||||
entities: canvas.entities,
|
entities: canvas.entities,
|
||||||
};
|
};
|
||||||
|
|
||||||
let gen_entity_pos = |dynamic_rng: &mut rand::rngs::ThreadRng| {
|
let gen_entity_pos = |dynamic_rng: &mut ChaCha8Rng| {
|
||||||
let lpos2d = TerrainChunkSize::RECT_SIZE
|
let lpos2d = TerrainChunkSize::RECT_SIZE
|
||||||
.map(|sz| dynamic_rng.gen::<u32>().rem_euclid(sz) as i32);
|
.map(|sz| dynamic_rng.gen::<u32>().rem_euclid(sz) as i32);
|
||||||
let mut lpos = Vec3::new(
|
let mut lpos = Vec3::new(
|
||||||
|
Loading…
Reference in New Issue
Block a user