mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Feat: Day duration slider on map creation UI (#1909)
This commit is contained in:
parent
c37f0d4c90
commit
0ecfbce4d2
@ -40,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Added hit_timing to BasicMelee abilities
|
- Added hit_timing to BasicMelee abilities
|
||||||
- A tavern building where npcs go to relax.
|
- A tavern building where npcs go to relax.
|
||||||
- Toggle for walking instead of running (Default: `I`).
|
- Toggle for walking instead of running (Default: `I`).
|
||||||
|
- Added day duration slider configuration on map creation UI.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -7,30 +7,30 @@ main-tip = Tip:
|
|||||||
main-unbound_key_tip = unbound
|
main-unbound_key_tip = unbound
|
||||||
main-notice =
|
main-notice =
|
||||||
Welcome to the alpha version of Veloren!
|
Welcome to the alpha version of Veloren!
|
||||||
|
|
||||||
Before you dive into the fun, please keep a few things in mind:
|
Before you dive into the fun, please keep a few things in mind:
|
||||||
|
|
||||||
- This is a very early alpha. Expect bugs, extremely unfinished gameplay, unpolished mechanics, and missing features.
|
- This is a very early alpha. Expect bugs, extremely unfinished gameplay, unpolished mechanics, and missing features.
|
||||||
|
|
||||||
- If you have constructive feedback or bug reports, you can contact us via Reddit, GitLab, or our community Discord server.
|
- If you have constructive feedback or bug reports, you can contact us via Reddit, GitLab, or our community Discord server.
|
||||||
|
|
||||||
- Veloren is licensed under the GPL 3 open-source licence. That means you're free to play, modify, and redistribute the game however
|
- Veloren is licensed under the GPL 3 open-source licence. That means you're free to play, modify, and redistribute the game however
|
||||||
you wish (provided derived work is also under GPL 3).
|
you wish (provided derived work is also under GPL 3).
|
||||||
|
|
||||||
- Veloren is a non-profit community project, and everybody working on it is a volunteer.
|
- Veloren is a non-profit community project, and everybody working on it is a volunteer.
|
||||||
If you like what you see, you're welcome to join the development or art teams!
|
If you like what you see, you're welcome to join the development or art teams!
|
||||||
|
|
||||||
Thanks for taking the time to read this notice, we hope you enjoy the game!
|
Thanks for taking the time to read this notice, we hope you enjoy the game!
|
||||||
|
|
||||||
~ The Veloren Devs
|
~ The Veloren Devs
|
||||||
main-login_process =
|
main-login_process =
|
||||||
Information on the Login Process:
|
Information on the Login Process:
|
||||||
|
|
||||||
Please note that you need an account
|
Please note that you need an account
|
||||||
to play on auth-enabled servers.
|
to play on auth-enabled servers.
|
||||||
|
|
||||||
You can create an account over at
|
You can create an account over at
|
||||||
|
|
||||||
https://veloren.net/account/.
|
https://veloren.net/account/.
|
||||||
main-singleplayer-new = New
|
main-singleplayer-new = New
|
||||||
main-singleplayer-delete = Delete
|
main-singleplayer-delete = Delete
|
||||||
@ -38,6 +38,7 @@ main-singleplayer-regenerate = Regenerate
|
|||||||
main-singleplayer-create_custom = Create Custom
|
main-singleplayer-create_custom = Create Custom
|
||||||
main-singleplayer-invalid_name = Error: Invalid name
|
main-singleplayer-invalid_name = Error: Invalid name
|
||||||
main-singleplayer-seed = Seed
|
main-singleplayer-seed = Seed
|
||||||
|
main-singleplayer-day_length = Day duration
|
||||||
main-singleplayer-random_seed = Random
|
main-singleplayer-random_seed = Random
|
||||||
main-singleplayer-size_lg = Logarithmic size
|
main-singleplayer-size_lg = Logarithmic size
|
||||||
main-singleplayer-map_large_warning = Warning: Large worlds will take a long time to start for the first time
|
main-singleplayer-map_large_warning = Warning: Large worlds will take a long time to start for the first time
|
||||||
|
@ -35,3 +35,6 @@ pub const ENERGY_PER_LEVEL: u16 = 5;
|
|||||||
pub const HP_PER_LEVEL: u16 = 5;
|
pub const HP_PER_LEVEL: u16 = 5;
|
||||||
|
|
||||||
pub const TELEPORTER_RADIUS: f32 = 3.;
|
pub const TELEPORTER_RADIUS: f32 = 3.;
|
||||||
|
|
||||||
|
// Map settings
|
||||||
|
pub const DAY_LENGTH_DEFAULT: f64 = 30.0;
|
||||||
|
@ -16,6 +16,7 @@ pub use whitelist::{Whitelist, WhitelistInfo, WhitelistRecord};
|
|||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use common::{
|
use common::{
|
||||||
calendar::{Calendar, CalendarEvent},
|
calendar::{Calendar, CalendarEvent},
|
||||||
|
consts::DAY_LENGTH_DEFAULT,
|
||||||
resources::BattleMode,
|
resources::BattleMode,
|
||||||
rtsim::WorldSettings,
|
rtsim::WorldSettings,
|
||||||
};
|
};
|
||||||
@ -205,7 +206,7 @@ impl Default for Settings {
|
|||||||
world_seed: DEFAULT_WORLD_SEED,
|
world_seed: DEFAULT_WORLD_SEED,
|
||||||
server_name: "Veloren Server".into(),
|
server_name: "Veloren Server".into(),
|
||||||
max_players: 100,
|
max_players: 100,
|
||||||
day_length: 30.0,
|
day_length: DAY_LENGTH_DEFAULT,
|
||||||
start_time: 9.0 * 3600.0,
|
start_time: 9.0 * 3600.0,
|
||||||
map_file: None,
|
map_file: None,
|
||||||
max_view_distance: Some(65),
|
max_view_distance: Some(65),
|
||||||
|
@ -92,6 +92,7 @@ const BG_IMGS: [&str; 14] = [
|
|||||||
pub enum WorldChange {
|
pub enum WorldChange {
|
||||||
Name(String),
|
Name(String),
|
||||||
Seed(u32),
|
Seed(u32),
|
||||||
|
DayLength(f64),
|
||||||
SizeX(u32),
|
SizeX(u32),
|
||||||
SizeY(u32),
|
SizeY(u32),
|
||||||
Scale(f64),
|
Scale(f64),
|
||||||
@ -108,6 +109,7 @@ impl WorldChange {
|
|||||||
match self {
|
match self {
|
||||||
WorldChange::Name(name) => world.name = name,
|
WorldChange::Name(name) => world.name = name,
|
||||||
WorldChange::Seed(seed) => world.seed = seed,
|
WorldChange::Seed(seed) => world.seed = seed,
|
||||||
|
WorldChange::DayLength(d) => world.day_length = d,
|
||||||
WorldChange::SizeX(s) => gen_opts.x_lg = s,
|
WorldChange::SizeX(s) => gen_opts.x_lg = s,
|
||||||
WorldChange::SizeY(s) => gen_opts.y_lg = s,
|
WorldChange::SizeY(s) => gen_opts.y_lg = s,
|
||||||
WorldChange::Scale(scale) => gen_opts.scale = scale,
|
WorldChange::Scale(scale) => gen_opts.scale = scale,
|
||||||
|
@ -47,6 +47,7 @@ pub struct Screen {
|
|||||||
|
|
||||||
world_name: text_input::State,
|
world_name: text_input::State,
|
||||||
map_seed: text_input::State,
|
map_seed: text_input::State,
|
||||||
|
day_length: slider::State,
|
||||||
random_seed_button: button::State,
|
random_seed_button: button::State,
|
||||||
world_size_x: slider::State,
|
world_size_x: slider::State,
|
||||||
world_size_y: slider::State,
|
world_size_y: slider::State,
|
||||||
@ -196,6 +197,9 @@ impl Screen {
|
|||||||
const SLIDER_BAR_PAD: u16 = 0;
|
const SLIDER_BAR_PAD: u16 = 0;
|
||||||
// Height of interactable area
|
// Height of interactable area
|
||||||
const SLIDER_HEIGHT: u16 = 30;
|
const SLIDER_HEIGHT: u16 = 30;
|
||||||
|
// Day length slider values
|
||||||
|
pub const DAY_LENGTH_MIN: f64 = 10.0;
|
||||||
|
pub const DAY_LENGTH_MAX: f64 = 60.0;
|
||||||
|
|
||||||
let mut gen_content = vec![
|
let mut gen_content = vec![
|
||||||
BackgroundContainer::new(
|
BackgroundContainer::new(
|
||||||
@ -288,6 +292,42 @@ impl Screen {
|
|||||||
gen_content.push(Row::with_children(seed_content).into());
|
gen_content.push(Row::with_children(seed_content).into());
|
||||||
|
|
||||||
if let Some(gen_opts) = world.gen_opts.as_ref() {
|
if let Some(gen_opts) = world.gen_opts.as_ref() {
|
||||||
|
// Day length setting label
|
||||||
|
gen_content.push(
|
||||||
|
Text::new(format!(
|
||||||
|
"{}: {}",
|
||||||
|
i18n.get_msg("main-singleplayer-day_length"),
|
||||||
|
world.day_length
|
||||||
|
))
|
||||||
|
.size(SLIDER_TEXT_SIZE)
|
||||||
|
.horizontal_alignment(iced::HorizontalAlignment::Center)
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Day length setting slider
|
||||||
|
if can_edit {
|
||||||
|
gen_content.push(
|
||||||
|
Row::with_children(vec![
|
||||||
|
Slider::new(
|
||||||
|
&mut self.day_length,
|
||||||
|
DAY_LENGTH_MIN..=DAY_LENGTH_MAX,
|
||||||
|
world.day_length,
|
||||||
|
move |d| message(WorldChange::DayLength(d)),
|
||||||
|
)
|
||||||
|
.height(SLIDER_HEIGHT)
|
||||||
|
.style(style::slider::Style::images(
|
||||||
|
imgs.slider_indicator,
|
||||||
|
imgs.slider_range,
|
||||||
|
SLIDER_BAR_PAD,
|
||||||
|
SLIDER_CURSOR_SIZE,
|
||||||
|
SLIDER_BAR_HEIGHT,
|
||||||
|
))
|
||||||
|
.into(),
|
||||||
|
])
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
gen_content.push(
|
gen_content.push(
|
||||||
Text::new(format!(
|
Text::new(format!(
|
||||||
"{}: x: {}, y: {}",
|
"{}: x: {}, y: {}",
|
||||||
|
@ -87,6 +87,7 @@ impl SingleplayerState {
|
|||||||
|
|
||||||
settings.map_file = Some(file_opts);
|
settings.map_file = Some(file_opts);
|
||||||
settings.world_seed = world.seed;
|
settings.world_seed = world.seed;
|
||||||
|
settings.day_length = world.day_length;
|
||||||
|
|
||||||
let (stop_server_s, stop_server_r) = unbounded();
|
let (stop_server_s, stop_server_r) = unbounded();
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use std::{
|
use std::{
|
||||||
fs,
|
fs,
|
||||||
|
io::Read,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use common::assets::ASSETS_PATH;
|
use common::{assets::ASSETS_PATH, consts::DAY_LENGTH_DEFAULT};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use server::{FileOpts, GenOpts, DEFAULT_WORLD_MAP};
|
use server::{FileOpts, GenOpts, DEFAULT_WORLD_MAP};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
@ -18,6 +19,7 @@ struct World0 {
|
|||||||
pub struct SingleplayerWorld {
|
pub struct SingleplayerWorld {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub gen_opts: Option<GenOpts>,
|
pub gen_opts: Option<GenOpts>,
|
||||||
|
pub day_length: f64,
|
||||||
pub seed: u32,
|
pub seed: u32,
|
||||||
pub is_generated: bool,
|
pub is_generated: bool,
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
@ -40,7 +42,12 @@ fn load_map(path: &Path) -> Option<SingleplayerWorld> {
|
|||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
version::try_load(&f, path)
|
let Ok(bytes) = f.bytes().collect::<Result<Vec<u8>, _>>() else {
|
||||||
|
error!("Failed to read {}", meta_path.to_string_lossy());
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
version::try_load(std::io::Cursor::new(bytes), path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_world_meta(world: &SingleplayerWorld) {
|
fn write_world_meta(world: &SingleplayerWorld) {
|
||||||
@ -78,11 +85,13 @@ fn migrate_old_singleplayer(from: &Path, to: &Path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut seed = 0;
|
let mut seed = 0;
|
||||||
|
let mut day_length = DAY_LENGTH_DEFAULT;
|
||||||
let (map_file, gen_opts) = fs::read_to_string(to.join("server_config/settings.ron"))
|
let (map_file, gen_opts) = fs::read_to_string(to.join("server_config/settings.ron"))
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|settings| {
|
.and_then(|settings| {
|
||||||
let settings: server::Settings = ron::from_str(&settings).ok()?;
|
let settings: server::Settings = ron::from_str(&settings).ok()?;
|
||||||
seed = settings.world_seed;
|
seed = settings.world_seed;
|
||||||
|
day_length = settings.day_length;
|
||||||
Some(match settings.map_file? {
|
Some(match settings.map_file? {
|
||||||
FileOpts::LoadOrGenerate { name, opts, .. } => {
|
FileOpts::LoadOrGenerate { name, opts, .. } => {
|
||||||
(Some(PathBuf::from(name)), Some(opts))
|
(Some(PathBuf::from(name)), Some(opts))
|
||||||
@ -107,6 +116,7 @@ fn migrate_old_singleplayer(from: &Path, to: &Path) {
|
|||||||
name: "singleplayer world".to_string(),
|
name: "singleplayer world".to_string(),
|
||||||
gen_opts,
|
gen_opts,
|
||||||
seed,
|
seed,
|
||||||
|
day_length,
|
||||||
path: to.to_path_buf(),
|
path: to.to_path_buf(),
|
||||||
// Isn't persisted so doesn't matter what it's set to.
|
// Isn't persisted so doesn't matter what it's set to.
|
||||||
is_generated: false,
|
is_generated: false,
|
||||||
@ -226,6 +236,7 @@ impl SingleplayerWorlds {
|
|||||||
let new_world = SingleplayerWorld {
|
let new_world = SingleplayerWorld {
|
||||||
name: "New World".to_string(),
|
name: "New World".to_string(),
|
||||||
gen_opts: None,
|
gen_opts: None,
|
||||||
|
day_length: DAY_LENGTH_DEFAULT,
|
||||||
seed: 0,
|
seed: 0,
|
||||||
is_generated: false,
|
is_generated: false,
|
||||||
map_path: path.join("map.bin"),
|
map_path: path.join("map.bin"),
|
||||||
@ -251,13 +262,13 @@ mod version {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub type Current = V1;
|
pub type Current = V2;
|
||||||
|
|
||||||
type LoadWorldFn<R> =
|
type LoadWorldFn<R> =
|
||||||
fn(R, &Path) -> Result<SingleplayerWorld, (&'static str, ron::de::SpannedError)>;
|
fn(R, &Path) -> Result<SingleplayerWorld, (&'static str, ron::de::SpannedError)>;
|
||||||
fn loaders<'a, R: std::io::Read + Clone>() -> &'a [LoadWorldFn<R>] {
|
fn loaders<'a, R: std::io::Read + Clone>() -> &'a [LoadWorldFn<R>] {
|
||||||
// Step [4]
|
// Step [4]
|
||||||
&[load_raw::<V1, _>]
|
&[load_raw::<V2, _>, load_raw::<V1, _>]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
@ -269,18 +280,6 @@ mod version {
|
|||||||
seed: u32,
|
seed: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl V1 {
|
|
||||||
/// This function is only needed for the current version
|
|
||||||
pub fn from_world(world: &SingleplayerWorld) -> Self {
|
|
||||||
V1 {
|
|
||||||
version: 1,
|
|
||||||
name: world.name.clone(),
|
|
||||||
gen_opts: world.gen_opts.clone(),
|
|
||||||
seed: world.seed,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToWorld for V1 {
|
impl ToWorld for V1 {
|
||||||
fn to_world(self, path: PathBuf) -> SingleplayerWorld {
|
fn to_world(self, path: PathBuf) -> SingleplayerWorld {
|
||||||
let map_path = path.join("map.bin");
|
let map_path = path.join("map.bin");
|
||||||
@ -290,6 +289,46 @@ mod version {
|
|||||||
name: self.name,
|
name: self.name,
|
||||||
gen_opts: self.gen_opts,
|
gen_opts: self.gen_opts,
|
||||||
seed: self.seed,
|
seed: self.seed,
|
||||||
|
day_length: DAY_LENGTH_DEFAULT,
|
||||||
|
is_generated,
|
||||||
|
path,
|
||||||
|
map_path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct V2 {
|
||||||
|
#[serde(deserialize_with = "version::<_, 2>")]
|
||||||
|
version: u64,
|
||||||
|
name: String,
|
||||||
|
gen_opts: Option<GenOpts>,
|
||||||
|
seed: u32,
|
||||||
|
day_length: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl V2 {
|
||||||
|
pub fn from_world(world: &SingleplayerWorld) -> Self {
|
||||||
|
V2 {
|
||||||
|
version: 2,
|
||||||
|
name: world.name.clone(),
|
||||||
|
gen_opts: world.gen_opts.clone(),
|
||||||
|
seed: world.seed,
|
||||||
|
day_length: world.day_length,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToWorld for V2 {
|
||||||
|
fn to_world(self, path: PathBuf) -> SingleplayerWorld {
|
||||||
|
let map_path = path.join("map.bin");
|
||||||
|
let is_generated = fs::metadata(&map_path).is_ok_and(|f| f.is_file());
|
||||||
|
|
||||||
|
SingleplayerWorld {
|
||||||
|
name: self.name,
|
||||||
|
gen_opts: self.gen_opts,
|
||||||
|
seed: self.seed,
|
||||||
|
day_length: self.day_length,
|
||||||
is_generated,
|
is_generated,
|
||||||
path,
|
path,
|
||||||
map_path,
|
map_path,
|
||||||
|
Loading…
Reference in New Issue
Block a user