Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ pub struct Args {
#[arg(long = "output-dir", alias = "path")]
pub path: Option<PathBuf>,

/// Custom name for the generated world (optional, default: auto-generated).
/// A counter suffix is appended if a world with that name already exists.
#[arg(long)]
pub world_name: Option<String>,

/// Generate a Bedrock Edition world (.mcworld) instead of Java Edition
#[arg(long)]
pub bedrock: bool,
Expand Down
31 changes: 16 additions & 15 deletions src/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ fn gui_pick_save_directory(start_path: String) -> Result<String, String> {
/// Creates a new Java Edition world in the given base save directory.
/// Called when the user clicks "Create World".
#[tauri::command]
fn gui_create_world(save_path: String) -> Result<String, i32> {
fn gui_create_world(save_path: String, world_name: Option<String>) -> Result<String, i32> {
let trimmed = save_path.trim();
if trimmed.is_empty() {
return Err(3);
Expand All @@ -288,11 +288,11 @@ fn gui_create_world(save_path: String) -> Result<String, i32> {
if !base.is_dir() {
return Err(3); // Error code 3: Failed to create new world
}
create_new_world(&base).map_err(|_| 3)
create_new_world(&base, world_name.as_deref()).map_err(|_| 3)
}

fn create_new_world(base_path: &Path) -> Result<String, String> {
crate::world_utils::create_new_world(base_path)
fn create_new_world(base_path: &Path, custom_name: Option<&str>) -> Result<String, String> {
crate::world_utils::create_new_world(base_path, custom_name)
}

/// Adds localized area name to the world name in level.dat
Expand Down Expand Up @@ -932,6 +932,7 @@ fn gui_start_generation(
gamemode: String,
world_time: i64,
map_item: bool,
world_name: Option<String>,
) -> Result<(), String> {
use progress::emit_gui_error;
use LLBBox;
Expand Down Expand Up @@ -1107,24 +1108,21 @@ fn gui_start_generation(
(updated_path, None)
}
WorldFormat::BedrockMcWorld => {
// Bedrock: generate .mcworld on Desktop with location-based name
// Bedrock: generate .mcworld on Desktop with custom or location-based name
let output_dir = crate::world_utils::get_bedrock_output_directory();
let (output_path, lvl_name) =
crate::world_utils::build_bedrock_output(&bbox, output_dir);
let (output_path, lvl_name) = crate::world_utils::build_bedrock_output(
&bbox,
output_dir,
world_name.as_deref(),
);
progress::emit_world_name_update(&lvl_name);
(output_path, Some(lvl_name))
}
WorldFormat::LuantiWorld => {
let worlds_dir = crate::world_utils::get_luanti_worlds_directory();
let _ = std::fs::create_dir_all(&worlds_dir);
let mut counter = 1;
let world_name = loop {
let candidate = format!("Arnis Luanti World {counter}");
if !worlds_dir.join(&candidate).exists() {
break candidate;
}
counter += 1;
};
let world_name =
crate::world_utils::luanti_world_name(&worlds_dir, world_name.as_deref());
let luanti_path = worlds_dir.join(&world_name);
println!(
"Creating Luanti world at: {}",
Expand Down Expand Up @@ -1180,6 +1178,9 @@ fn gui_start_generation(
} else {
world_path
}),
// World naming is already resolved above (create_new_world /
// build_bedrock_output / luanti_world_name), so Args doesn't need it.
world_name: None,
bedrock: world_format == WorldFormat::BedrockMcWorld,
luanti: world_format == WorldFormat::LuantiWorld,
downloader: "requests".to_string(),
Expand Down
11 changes: 11 additions & 0 deletions src/gui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,17 @@ <h2 data-localize="customization_settings">Settings</h2>
<!-- Section: World -->
<div class="settings-section-header" data-localize="settings_section_world">World</div>

<!-- World Name Input -->
<div class="settings-row">
<label for="world-name-input">
<span data-localize="world_name">World Name</span>
<span class="tooltip-icon" data-tooltip="Custom name for the generated world. Leave empty for an auto-generated name.">?</span>
</label>
<div class="settings-control">
<input type="text" id="world-name-input" name="world-name-input" maxlength="64" placeholder="Arnis World (auto)">
</div>
</div>

<!-- Game Mode -->
<div class="settings-row">
<label>
Expand Down
26 changes: 24 additions & 2 deletions src/gui/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ async function applyLocalization(localization) {
"span[data-localize='map_theme']": "map_theme",
"span[data-localize='save_path']": "save_path",
"span[data-localize='rotation_angle']": "rotation_angle",
"span[data-localize='world_name']": "world_name",
"span[data-localize='gamemode']": "gamemode",
"button[data-localize='gamemode_survival']": "gamemode_survival",
"button[data-localize='gamemode_creative']": "gamemode_creative",
Expand Down Expand Up @@ -752,6 +753,21 @@ function initSettings() {
timeValue.textContent = formatClock(720);
});

// World name input: preview the upcoming name under the Start button so
// it's visible that the custom name applies without a save step
const worldNameInput = document.getElementById("world-name-input");
worldNameInput.addEventListener("input", () => {
const custom = worldNameInput.value.trim();
const label = document.getElementById("world-name-label");
if (!label) return;
if (custom) {
label.removeAttribute("data-placeholder");
label.textContent = custom;
} else {
setWorldNameLabel(lastGeneratedWorldName);
}
});

// Rotation angle input
const rotationInput = document.getElementById("rotation-angle-input");

Expand Down Expand Up @@ -1513,8 +1529,10 @@ function displayBboxInfoText(bboxText) {
}

let worldPath = "";
let lastGeneratedWorldName = "";

function setWorldNameLabel(text) {
lastGeneratedWorldName = text || "";
const label = document.getElementById('world-name-label');
if (!label) return;
if (text) {
Expand Down Expand Up @@ -1571,14 +1589,17 @@ async function startGeneration() {
return;
}

// Custom world name (empty input means auto-generated name)
const customWorldName = (document.getElementById('world-name-input')?.value || '').trim() || null;

// Auto-create world for Java format
if (selectedWorldFormat === 'java') {
if (!savePath) {
console.warn("Cannot create world: save path not set");
return;
}
try {
const worldName = await invoke('gui_create_world', { savePath: savePath });
const worldName = await invoke('gui_create_world', { savePath: savePath, worldName: customWorldName });
if (worldName) {
worldPath = worldName;
setWorldNameLabel(basenameFromPath(worldName));
Expand Down Expand Up @@ -1661,7 +1682,8 @@ async function startGeneration() {
rotationAngle: rotationAngle,
gamemode: gamemode,
worldTime: worldTime,
mapItem: mapItem
mapItem: mapItem,
worldName: customWorldName
});

console.log("Generation process started.");
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "بدأت عملية البناء.",
"winter_mode": "وضع الشتاء",
"world_scale": "مقياس العالم",
"world_name": "اسم العالم",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "مهلة ملء الفيضان (ثواني)",
"ground_level": "مستوى الأرض",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "Generierungsprozess gestartet.",
"winter_mode": "Wintermodus",
"world_scale": "Weltmaßstab",
"world_name": "Weltname",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "Floodfill-Timeout (Sek)",
"ground_level": "Bodenhöhe",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "Generation process started.",
"winter_mode": "Winter Mode",
"world_scale": "World Scale",
"world_name": "World Name",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "Floodfill Timeout (sec)",
"ground_level": "Ground Level",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "Proceso de generación iniciado.",
"winter_mode": "Modo invierno",
"world_scale": "Escala del mundo",
"world_name": "Nombre del mundo",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "Tiempo de espera de relleno (seg)",
"ground_level": "Nivel del suelo",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "Luontiprosessi aloitettu.",
"winter_mode": "Talvitila",
"world_scale": "Maailmanskaalaus",
"world_name": "Maailman nimi",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "Täytön aikakatkaisu (sec)",
"ground_level": "Maataso",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "Processus de génération commencé.",
"winter_mode": "Mode hiver",
"world_scale": "Échelle du monde",
"world_name": "Nom du monde",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "Expiration du délai de remplissage (en secondes)",
"ground_level": "Niveau du sol",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/hu.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "Generálási folyamat elkezdődött",
"winter_mode": "Téli mód",
"world_scale": "Világ nagysága",
"world_name": "Világ neve",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "Floodfill Timeout (sec)",
"ground_level": "Földszint",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "生成処理を開始しました。",
"winter_mode": "冬モード",
"world_scale": "ワールド倍率",
"world_name": "ワールド名",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "フラッドフィルのタイムアウト(秒)",
"ground_level": "地面レベル",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "생성 프로세스가 시작되었습니다.",
"winter_mode": "겨울 모드",
"world_scale": "세계 규모",
"world_name": "월드 이름",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "채우기 시간 초과 (초)",
"ground_level": "지면 레벨",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/lt.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "Generacijos procesas pradėtas.",
"winter_mode": "Žiemos režimas",
"world_scale": "Pasaulio mastelis",
"world_name": "Pasaulio pavadinimas",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "Užpildymo laiko limitas (sek.)",
"ground_level": "Žemės lygis",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/lv.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "Ģenerēšanas process uzsākts",
"winter_mode": "Ziemas režīms",
"world_scale": "Pasaules mērogs",
"world_name": "Pasaules nosaukums",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "Aizpildes noildze (sek.)",
"ground_level": "Zemes līmenis",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "Proces generowania rozpoczęty.",
"winter_mode": "Tryb Zimowy",
"world_scale": "Skala świata",
"world_name": "Nazwa świata",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "Limit czasu wypełniania (sek)",
"ground_level": "Wysokość obszaru",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/pt-BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "Processo de geração iniciado.",
"winter_mode": "Modo inverno",
"world_scale": "Escala do mundo",
"world_name": "Nome do mundo",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "Tempo limite do floodfill (seg)",
"ground_level": "Nível do solo",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "Процесс генерации начат",
"winter_mode": "Зимний режим",
"world_scale": "Масштаб мира",
"world_name": "Название мира",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "Тайм-аут заливки (сек)",
"ground_level": "Уровень земли",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/sl.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "Postopek generiranja se je začel.",
"winter_mode": "Zimski način",
"world_scale": "Merilo sveta",
"world_name": "Ime sveta",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "Časovna omejitev zapolnjevanja (sek)",
"ground_level": "Nivo tal",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "Genereringsprocessen startad.",
"winter_mode": "Vinterläge",
"world_scale": "Världsskala",
"world_name": "Världens namn",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "Floodfill-tidsgräns (sek)",
"ground_level": "Marknivå",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/ua.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "Процес генерації розпочато",
"winter_mode": "Зимовий режим",
"world_scale": "Масштаб світу",
"world_name": "Назва світу",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "Тайм-аут заливки (сек)",
"ground_level": "Рівень землі",
Expand Down
1 change: 1 addition & 0 deletions src/gui/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generation_process_started": "生成过程已开始。",
"winter_mode": "冬季模式",
"world_scale": "世界比例",
"world_name": "世界名称",
"custom_bounding_box": "Bounding Box",
"floodfill_timeout": "填充超时(秒)",
"ground_level": "地面高度",
Expand Down
15 changes: 5 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,22 +168,16 @@ fn run_cli() {
.path
.clone()
.unwrap_or_else(world_utils::get_bedrock_output_directory);
let (output_path, lvl_name) = world_utils::build_bedrock_output(&args.bbox, output_dir);
let (output_path, lvl_name) =
world_utils::build_bedrock_output(&args.bbox, output_dir, args.world_name.as_deref());
(output_path, Some(lvl_name))
} else if args.luanti {
let base_dir = args
.path
.clone()
.unwrap_or_else(world_utils::get_luanti_worlds_directory);
let _ = std::fs::create_dir_all(&base_dir);
let mut counter = 1;
let world_name = loop {
let candidate = format!("Arnis Luanti World {counter}");
if !base_dir.join(&candidate).exists() {
break candidate;
}
counter += 1;
};
let world_name = world_utils::luanti_world_name(&base_dir, args.world_name.as_deref());
let world_path = base_dir.join(&world_name);
println!(
"Creating Luanti world at: {}",
Expand All @@ -193,7 +187,8 @@ fn run_cli() {
} else {
// Java: create a new world in the provided output directory
let base_dir = args.path.clone().unwrap();
let world_path = match world_utils::create_new_world(&base_dir) {
let world_path = match world_utils::create_new_world(&base_dir, args.world_name.as_deref())
{
Ok(path) => PathBuf::from(path),
Err(e) => {
eprintln!("{} {}", "Error:".red().bold(), e);
Expand Down
Loading
Loading