Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a42f011de | ||
|
|
106214c8ea |
2
.gitattributes
vendored
@@ -1 +1 @@
|
||||
src/gui/** linguist-vendored
|
||||
gui-src/** linguist-vendored
|
||||
|
||||
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -11,13 +11,13 @@ assignees: ''
|
||||
A clear and concise description of what the bug is and what you expected to happen.
|
||||
|
||||
**Used bbox area**
|
||||
Please provide your input parameters (BBOX) so we can reproduce the issue. *(For example: 48.133444 11.569462 48.142609 11.584740)*
|
||||
Please provide your input parameters so we can reproduce the issue. *(For example: 48.133444 11.569462 48.142609 11.584740)*
|
||||
|
||||
**Arnis and Minecraft version**
|
||||
Please tell us what version of Arnis and Minecraft you used, as well as if you are on Windows, Linux or MacOS.
|
||||
Please tell us what version of Arnis and Minecraft you used.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here. If you used any more custom settings, please provide them here too. Please provide the log file if possible as well, which can be found at C:\Users\USERNAME\AppData\Local\com.louisdev.arnis\logs
|
||||
Add any other context about the problem here. If you used any more custom settings, please provide them here too. If you experienced any issue with the application itself like a crash, please provide the log file which can be found at C:\Users\USERNAME\AppData\Local\com.louisdev.arnis\logs
|
||||
|
||||
58
.github/workflows/ci-build.yml
vendored
@@ -1,32 +1,43 @@
|
||||
name: CI Build
|
||||
|
||||
# Trigger CI on pull requests when relevant files change, and pushes to main
|
||||
# Trigger CI on pull requests and pushes to main, when relevant files change
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- '.github/**'
|
||||
- 'src/**'
|
||||
- 'Cargo.toml'
|
||||
- 'Cargo.lock'
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'src/**'
|
||||
- 'Cargo.toml'
|
||||
- 'Cargo.lock'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Rust
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
components: clippy, rustfmt
|
||||
targets: ${{ matrix.os == 'windows-latest' && 'x86_64-pc-windows-msvc' || 'x86_64-unknown-linux-gnu' || 'x86_64-apple-darwin' }}
|
||||
components: clippy
|
||||
|
||||
- name: Install Linux dependencies
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y software-properties-common
|
||||
@@ -36,7 +47,16 @@ jobs:
|
||||
sudo apt install -y libgtk-3-dev build-essential pkg-config libglib2.0-dev libsoup-3.0-dev libwebkit2gtk-4.1-dev
|
||||
echo "PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig" >> $GITHUB_ENV
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: Set up cache for Cargo
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cargo-
|
||||
|
||||
- name: Check formatting
|
||||
run: cargo fmt -- --check
|
||||
@@ -44,28 +64,8 @@ jobs:
|
||||
- name: Check clippy lints
|
||||
run: cargo clippy --all-targets --all-features -- -D warnings
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Rust
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Install Linux dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y software-properties-common
|
||||
sudo add-apt-repository universe
|
||||
echo "deb http://archive.ubuntu.com/ubuntu $(lsb_release -sc)-backports main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list
|
||||
sudo apt update
|
||||
sudo apt install -y libgtk-3-dev build-essential pkg-config libglib2.0-dev libsoup-3.0-dev libwebkit2gtk-4.1-dev
|
||||
echo "PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig" >> $GITHUB_ENV
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: Install Rust dependencies
|
||||
run: cargo fetch
|
||||
|
||||
- name: Build (all targets, all features)
|
||||
run: cargo build --all-targets --all-features --release
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
name: PR Benchmark
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened]
|
||||
@@ -20,22 +16,18 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Rust
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
components: clippy
|
||||
|
||||
- name: Create dummy Minecraft world directory
|
||||
run: |
|
||||
mkdir -p "./world/region"
|
||||
|
||||
- name: Build for release
|
||||
run: cargo build --release --no-default-features
|
||||
|
||||
- name: Start timer
|
||||
id: start_time
|
||||
run: echo "start_time=$(date +%s)" >> $GITHUB_OUTPUT
|
||||
@@ -43,7 +35,7 @@ jobs:
|
||||
- name: Run benchmark command with memory tracking
|
||||
id: benchmark
|
||||
run: |
|
||||
/usr/bin/time -v ./target/release/arnis --path="./world" --terrain --bbox="48.101470,11.517792,48.168375,11.626968" 2> benchmark_log.txt
|
||||
/usr/bin/time -v cargo run --release --no-default-features -- --path="./world" --terrain --bbox="48.117861,11.541996,48.154520,11.604824" 2> benchmark_log.txt
|
||||
grep "Maximum resident set size" benchmark_log.txt | awk '{print $6}' > peak_mem_kb.txt
|
||||
peak_kb=$(cat peak_mem_kb.txt)
|
||||
peak_mb=$((peak_kb / 1024))
|
||||
@@ -65,21 +57,21 @@ jobs:
|
||||
seconds=$((duration % 60))
|
||||
peak_mem=${{ steps.benchmark.outputs.peak_memory }}
|
||||
|
||||
baseline_time=135
|
||||
baseline_time=130
|
||||
diff=$((duration - baseline_time))
|
||||
abs_diff=${diff#-}
|
||||
|
||||
if [ "$diff" -lt -5 ]; then
|
||||
if [ "$diff" -lt -10 ]; then
|
||||
verdict="✅ This PR **improves generation time**."
|
||||
elif [ "$abs_diff" -le 4 ]; then
|
||||
elif [ "$abs_diff" -le 7 ]; then
|
||||
verdict="🟢 Generation time is unchanged."
|
||||
elif [ "$diff" -le 15 ]; then
|
||||
verdict="⚠️ This PR **worsens generation time**."
|
||||
elif [ "$diff" -le 25 ]; then
|
||||
verdict="⚠️ This PR **slightly worsens generation time**."
|
||||
else
|
||||
verdict="🚨 This PR **drastically worsens generation time**."
|
||||
fi
|
||||
|
||||
baseline_mem=5865
|
||||
baseline_mem=1960
|
||||
mem_annotation=""
|
||||
if [ "$peak_mem" -gt 2000 ]; then
|
||||
mem_diff=$((peak_mem - baseline_mem))
|
||||
@@ -108,4 +100,4 @@ jobs:
|
||||
message: ${{ steps.comment_body.outputs.summary }}
|
||||
comment-tag: benchmark-report
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.BENCHMARK_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
69
.github/workflows/release.yml
vendored
@@ -17,20 +17,16 @@ jobs:
|
||||
target: x86_64-unknown-linux-gnu
|
||||
binary_name: arnis
|
||||
asset_name: arnis-linux
|
||||
- os: macos-13 # Intel runner for x86_64 builds
|
||||
- os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
binary_name: arnis
|
||||
asset_name: arnis-mac-intel
|
||||
- os: macos-latest # ARM64 runner for ARM64 builds
|
||||
target: aarch64-apple-darwin
|
||||
binary_name: arnis
|
||||
asset_name: arnis-mac-arm64
|
||||
asset_name: arnis-mac
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Rust
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
@@ -53,10 +49,10 @@ jobs:
|
||||
run: cargo fetch
|
||||
|
||||
- name: Build
|
||||
run: cargo build --release --target ${{ matrix.target }}
|
||||
run: cargo build --release
|
||||
|
||||
- name: Rename binary for release
|
||||
run: mv target/${{ matrix.target }}/release/${{ matrix.binary_name }} target/release/${{ matrix.asset_name }}
|
||||
run: mv target/release/${{ matrix.binary_name }} target/release/${{ matrix.asset_name }}
|
||||
|
||||
- name: Install Windows SDK
|
||||
if: matrix.os == 'windows-latest'
|
||||
@@ -87,74 +83,47 @@ jobs:
|
||||
shell: powershell
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.os }}-${{ matrix.target }}-build
|
||||
name: ${{ matrix.os }}-build
|
||||
path: target/release/${{ matrix.asset_name }}
|
||||
|
||||
create-universal-macos:
|
||||
needs: build
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Download macOS Intel build
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: macos-13-x86_64-apple-darwin-build
|
||||
path: ./intel
|
||||
|
||||
- name: Download macOS ARM64 build
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: macos-latest-aarch64-apple-darwin-build
|
||||
path: ./arm64
|
||||
|
||||
- name: Create universal binary
|
||||
run: |
|
||||
lipo -create -output arnis-mac-universal ./intel/arnis-mac-intel ./arm64/arnis-mac-arm64
|
||||
chmod +x arnis-mac-universal
|
||||
|
||||
- name: Upload universal binary
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: macos-universal-build
|
||||
path: arnis-mac-universal
|
||||
|
||||
release:
|
||||
needs: [build, create-universal-macos]
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Download Windows build artifact
|
||||
uses: actions/download-artifact@v5
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-latest-x86_64-pc-windows-msvc-build
|
||||
name: windows-latest-build
|
||||
path: ./builds/windows
|
||||
|
||||
- name: Download Linux build artifact
|
||||
uses: actions/download-artifact@v5
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ubuntu-latest-x86_64-unknown-linux-gnu-build
|
||||
name: ubuntu-latest-build
|
||||
path: ./builds/linux
|
||||
|
||||
- name: Download macOS universal build artifact
|
||||
uses: actions/download-artifact@v5
|
||||
- name: Download macOS build artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: macos-universal-build
|
||||
name: macos-latest-build
|
||||
path: ./builds/macos
|
||||
|
||||
- name: Make Linux and macOS binaries executable
|
||||
run: |
|
||||
chmod +x ./builds/linux/arnis-linux
|
||||
chmod +x ./builds/macos/arnis-mac-universal
|
||||
chmod +x ./builds/macos/arnis-mac
|
||||
|
||||
- name: Create GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: |
|
||||
builds/windows/arnis-windows.exe
|
||||
builds/linux/arnis-linux
|
||||
builds/macos/arnis-mac-universal
|
||||
builds/macos/arnis-mac
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
100
.github/workflows/test-macos-build.yml.disabled
vendored
@@ -1,100 +0,0 @@
|
||||
name: Test macOS Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- '.github/workflows/release.yml'
|
||||
- 'src/**'
|
||||
- 'Cargo.toml'
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
workflow_dispatch: # Allow manual triggering
|
||||
|
||||
jobs:
|
||||
test-macos-builds:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- target: x86_64-apple-darwin
|
||||
asset_name: arnis-mac-intel
|
||||
- target: aarch64-apple-darwin
|
||||
asset_name: arnis-mac-arm64
|
||||
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Rust
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: cargo fetch
|
||||
|
||||
- name: Build for ${{ matrix.target }}
|
||||
run: cargo build --release --target ${{ matrix.target }}
|
||||
|
||||
- name: Rename binary
|
||||
run: mv target/${{ matrix.target }}/release/arnis target/${{ matrix.target }}/release/${{ matrix.asset_name }}
|
||||
|
||||
- name: Check binary architecture
|
||||
run: |
|
||||
file target/${{ matrix.target }}/release/${{ matrix.asset_name }}
|
||||
lipo -info target/${{ matrix.target }}/release/${{ matrix.asset_name }}
|
||||
|
||||
- name: Test binary execution (basic check)
|
||||
run: |
|
||||
chmod +x target/${{ matrix.target }}/release/${{ matrix.asset_name }}
|
||||
# Test that it at least shows help/version (don't run full generation)
|
||||
target/${{ matrix.target }}/release/${{ matrix.asset_name }} --help || echo "Help command completed"
|
||||
|
||||
- name: Upload test artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-${{ matrix.target }}-build
|
||||
path: target/${{ matrix.target }}/release/${{ matrix.asset_name }}
|
||||
|
||||
test-universal-binary:
|
||||
needs: test-macos-builds
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Download Intel build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: test-x86_64-apple-darwin-build
|
||||
path: ./intel
|
||||
|
||||
- name: Download ARM64 build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: test-aarch64-apple-darwin-build
|
||||
path: ./arm64
|
||||
|
||||
- name: Create and test universal binary
|
||||
run: |
|
||||
lipo -create -output arnis-mac-universal ./intel/arnis-mac-intel ./arm64/arnis-mac-arm64
|
||||
chmod +x arnis-mac-universal
|
||||
|
||||
# Verify it's actually universal
|
||||
echo "=== Universal Binary Info ==="
|
||||
file arnis-mac-universal
|
||||
lipo -info arnis-mac-universal
|
||||
|
||||
# Test execution
|
||||
echo "=== Testing Universal Binary ==="
|
||||
./arnis-mac-universal --help || echo "Universal binary help command completed"
|
||||
|
||||
# Check file size (should be sum of both architectures roughly)
|
||||
echo "=== File Sizes ==="
|
||||
ls -lah ./intel/arnis-mac-intel ./arm64/arnis-mac-arm64 arnis-mac-universal
|
||||
|
||||
- name: Upload universal binary
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-universal-build
|
||||
path: arnis-mac-universal
|
||||
5
.gitignore
vendored
@@ -1,7 +1,6 @@
|
||||
/wiki
|
||||
|
||||
# Environment files
|
||||
.env
|
||||
.envrc
|
||||
/.direnv
|
||||
|
||||
# Build artifacts
|
||||
@@ -29,8 +28,6 @@ Thumbs.db
|
||||
/export.json
|
||||
/parsed_osm_data.txt
|
||||
/elevation_debug.png
|
||||
/terrain-tile-cache
|
||||
/arnis-tile-cache
|
||||
/gen/
|
||||
/build/
|
||||
*.rmeta
|
||||
|
||||
1622
Cargo.lock
generated
28
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "arnis"
|
||||
version = "2.3.1"
|
||||
version = "2.2.0"
|
||||
edition = "2021"
|
||||
description = "Arnis - Generate real life cities in Minecraft"
|
||||
homepage = "https://github.com/louis-e/arnis"
|
||||
@@ -10,7 +10,6 @@ readme = "README.md"
|
||||
|
||||
[profile.release]
|
||||
lto = "thin"
|
||||
overflow-checks = true
|
||||
|
||||
[features]
|
||||
default = ["gui"]
|
||||
@@ -20,34 +19,31 @@ gui = ["tauri", "tauri-plugin-log", "tauri-plugin-shell", "tokio", "rfd", "dirs"
|
||||
tauri-build = {version = "2", optional = true}
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5", features = ["derive", "env"] }
|
||||
clap = { version = "4.1", features = ["derive"] }
|
||||
colored = "3.0.0"
|
||||
dirs = {version = "6.0.0", optional = true }
|
||||
fastanvil = "0.32.0"
|
||||
fastnbt = "2.6.0"
|
||||
fastanvil = "0.31.0"
|
||||
fastnbt = "2.5.0"
|
||||
flate2 = "1.1"
|
||||
fnv = "1.0.7"
|
||||
fs2 = "0.4"
|
||||
geo = "0.30.0"
|
||||
image = "0.25"
|
||||
indicatif = "0.17.11"
|
||||
geo = "0.29.3"
|
||||
image = "0.24"
|
||||
indicatif = "0.17.8"
|
||||
itertools = "0.14.0"
|
||||
log = "0.4.27"
|
||||
once_cell = "1.21.3"
|
||||
rand = "0.8.5"
|
||||
rayon = "1.10.0"
|
||||
reqwest = { version = "0.12.15", features = ["blocking", "json"] }
|
||||
rfd = { version = "0.15.4", optional = true }
|
||||
semver = "1.0.26"
|
||||
reqwest = { version = "0.12.7", features = ["blocking", "json"] }
|
||||
rfd = { version = "0.15.1", optional = true }
|
||||
semver = "1.0.23"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tauri = { version = "2", optional = true }
|
||||
tauri-plugin-log = { version = "2.6.0", optional = true }
|
||||
tauri-plugin-log = { version = "2.2.2", optional = true }
|
||||
tauri-plugin-shell = { version = "2", optional = true }
|
||||
tokio = { version = "1.47.0", features = ["full"], optional = true }
|
||||
tokio = { version = "1.44.2", features = ["full"], optional = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows = { version = "0.61.1", features = ["Win32_System_Console"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.23.0"
|
||||
|
||||
116
README.md
@@ -1,27 +1,95 @@
|
||||
<img src="assets/git/banner.png" width="100%" alt="Banner">
|
||||
<p align="center">
|
||||
<img width="456" height="125" src="https://github.com/louis-e/arnis/blob/main/gui-src/images/logo.png?raw=true">
|
||||
</p>
|
||||
|
||||
# Arnis [](https://github.com/louis-e/arnis/actions) [<img alt="GitHub Release" src="https://img.shields.io/github/v/release/louis-e/arnis" />](https://github.com/louis-e/arnis/releases) [<img alt="GitHub Downloads (all assets, all releases" src="https://img.shields.io/github/downloads/louis-e/arnis/total" />](https://github.com/louis-e/arnis/releases) [](https://github.com/louis-e/arnis/releases) [](https://discord.gg/mA2g69Fhxq)
|
||||
# Arnis [](https://github.com/louis-e/arnis/actions) [<img alt="GitHub Release" src="https://img.shields.io/github/v/release/louis-e/arnis" />](https://github.com/louis-e/arnis/releases) [<img alt="GitHub Downloads (all assets, all releases" src="https://img.shields.io/github/downloads/louis-e/arnis/total" />](https://github.com/louis-e/arnis/releases)
|
||||
|
||||
Arnis creates complex and accurate Minecraft Java Edition worlds that reflect real-world geography, topography, and architecture.
|
||||
Arnis creates complex and accurate Minecraft Java Edition worlds that reflect real-world geography and architecture using OpenStreetMap.
|
||||
|
||||
This free and open source project is designed to handle large-scale geographic data from the real world and generate detailed Minecraft worlds. The algorithm processes geospatial data from OpenStreetMap as well as elevation data to create an accurate Minecraft representation of terrain and architecture.
|
||||
Generate your hometown, big cities, and natural landscapes with ease!
|
||||
###### ⚠️ This Github page is the official project website. Do not download Arnis from any other website.
|
||||
|
||||

|
||||
<i>This Github page and [arnismc.com](https://arnismc.com) are the only official project websites. Do not download Arnis from any other website.</i>
|
||||
## :desktop_computer: Example
|
||||

|
||||
|
||||
Arnis is designed to handle large-scale data and generate rich, immersive environments that bring real-world cities, landmarks, and natural features into Minecraft. Whether you're looking to replicate your hometown, explore urban environments, or simply build something unique and realistic, Arnis generates your vision.
|
||||
|
||||
## :keyboard: Usage
|
||||
<img width="60%" src="assets/git/gui.png"><br>
|
||||
<img width="60%" src="https://github.com/louis-e/arnis/blob/main/gitassets/gui.png?raw=true"><br>
|
||||
Download the [latest release](https://github.com/louis-e/arnis/releases/) or [compile](#trophy-open-source) the project on your own.
|
||||
|
||||
Choose your area using the rectangle tool and select your Minecraft world - then simply click on 'Start Generation'!
|
||||
|
||||
Choose your area on the map using the rectangle tool and select your Minecraft world - then simply click on <i>Start Generation</i>!
|
||||
Additionally, you can customize various generation settings, such as world scale, spawn point, or building interior generation.
|
||||
> The world will always be generated starting from the Minecraft coordinates 0 0 0 (/tp 0 0 0). This is the top left of your selected area.
|
||||
Minecraft version 1.16.5 and below is currently not supported, but we are working on it! For the best results, use Minecraft version 1.21.4 or above.
|
||||
If you choose to select an own world, be aware that Arnis will overwrite certain areas.
|
||||
|
||||
## 📚 Documentation
|
||||
[[Arch Linux AUR package](https://aur.archlinux.org/packages/arnis)]
|
||||
|
||||
<img src="assets/git/documentation.png" width="100%" alt="Banner">
|
||||
## :floppy_disk: How it works
|
||||

|
||||
|
||||
Full documentation is available in the [GitHub Wiki](https://github.com/louis-e/arnis/wiki/), covering topics such as technical explanations, FAQs, contribution guidelines and roadmaps.
|
||||
The raw data obtained from the API *[(see FAQ)](#question-faq)* includes each element (buildings, walls, fountains, farmlands, etc.) with its respective corner coordinates (nodes) and descriptive tags. When you run Arnis, the following steps are performed automatically to generate a Minecraft world:
|
||||
|
||||
#### Processing Pipeline
|
||||
1. **Fetching Data from the Overpass API:** The script retrieves geospatial data for the desired bounding box from the Overpass API.
|
||||
2. **Parsing Raw Data:** The raw data is parsed to extract essential information like nodes, ways, and relations. Nodes are converted into Minecraft coordinates, and relations are handled similarly to ways, ensuring all relevant elements are processed correctly. Relations and ways cluster several nodes into one specific object.
|
||||
3. **Prioritizing and Sorting Elements:** The elements (nodes, ways, relations) are sorted by priority to establish a layering system, which ensures that certain types of elements (e.g., entrances and buildings) are generated in the correct order to avoid conflicts and overlapping structures.
|
||||
4. **Generating Minecraft World:** The Minecraft world is generated using a series of element processors (generate_buildings, generate_highways, generate_landuse, etc.) that interpret the tags and nodes of each element to place the appropriate blocks in the Minecraft world. These processors handle the logic for creating 3D structures, roads, natural formations, and more, as specified by the processed data.
|
||||
5. **Generating Ground Layer:** A ground layer is generated based on the provided scale factors to provide a base for the entire Minecraft world. This step ensures all areas have an appropriate foundation (e.g., grass and dirt layers).
|
||||
6. **Saving the Minecraft World:** All the modified chunks are saved back to the Minecraft region files.
|
||||
|
||||
## :question: FAQ
|
||||
- *Wasn't this written in Python before?*<br>
|
||||
Yes! Arnis was initially developed in Python, which benefited from Python's open-source friendliness and ease of readability. This is why we strive for clear, well-documented code in the Rust port of this project to find the right balance. I decided to port the project to Rust to learn more about the language and push the algorithm's performance further. We were nearing the limits of optimization in Python, and Rust's capabilities allow for even better performance and efficiency. The old Python implementation is still available in the python-legacy branch.
|
||||
- *Where does the data come from?*<br>
|
||||
The geographic data is sourced from OpenStreetMap (OSM)[^1], a free, collaborative mapping project that serves as an open-source alternative to commercial mapping services. The data is accessed via the Overpass API, which queries OSM's database. Other services like Google Maps do not provide data like this, which makes OSM perfect for this project.
|
||||
- *How does the Minecraft world generation work?*<br>
|
||||
The script uses the [fastnbt](https://github.com/owengage/fastnbt) cargo package to interact with Minecraft's world format. This library allows Arnis to manipulate Minecraft region files, enabling the generation of real-world locations. The section 'Processing Pipeline' goes a bit further into the details and steps of the generation process itself.
|
||||
- *Where does the name come from?*<br>
|
||||
The project is named after the smallest city in Germany, Arnis[^2]. The city's small size made it an ideal test case for developing and debugging the algorithm efficiently.
|
||||
- *I don't have Minecraft installed but want to generate a world for my kids. How?*<br>
|
||||
When selecting a world, click on 'Select existing world' and choose a directory. The world will be generated there.
|
||||
- *Arnis instantly closes again or the window is empty!*<br>
|
||||
If you're on Windows, please install the [Evergreen Bootstrapper from Microsoft](https://developer.microsoft.com/en-us/microsoft-edge/webview2/?form=MA13LH#download).
|
||||
|
||||
If you're on Linux, your system might be missing the webkit2gtk-4.1 library, install the corresponding package using your distro's package manager.
|
||||
- *What Minecraft version should I use?*<br>
|
||||
Please use Minecraft version 1.21.4 for the best results. Minecraft version 1.16.5 and below is currently not supported, but we are working on it!
|
||||
- *The generation did finish, but there's nothing in the world!*<br>
|
||||
Make sure to teleport to the generation starting point (/tp 0 0 0). If there is still nothing, you might need to travel a bit further into the positive X and positive Z direction.
|
||||
- *What features are in the world generation settings?*<br>
|
||||
**Terrain:** Make sure to enable this feature to generate your world with elevation data included.<br>
|
||||
**Scale Factor:** The scale factor determines the size of the generated world.<br>
|
||||
**Custom BBOX Input:** This setting allows you to manually input the bounding box coordinates for the area you want to generate.<br>
|
||||
**Floodfill-Timeout (Sec):** This setting determines the maximum time the floodfill algorithm is allowed to run before being terminated. Increasing this value may improve the generation of large water areas but may also increase processing time.<br>
|
||||
**Ground Height:** This setting determines the base height of the generated world and can be adjusted to create different terrain types.
|
||||
|
||||
## :memo: ToDo and Known Bugs
|
||||
Feel free to choose an item from the To-Do or Known Bugs list, or bring your own idea to the table. Bug reports shall be raised as a Github issue. Contributions are highly welcome and appreciated!
|
||||
- [ ] Fix compilation for Linux and Mac
|
||||
- [ ] Fix coastal cities generation duration time (water_areas.rs)
|
||||
- [ ] Rotate maps (https://github.com/louis-e/arnis/issues/97)
|
||||
- [ ] Add support for older Minecraft versions (<=1.16.5) (https://github.com/louis-e/arnis/issues/124, https://github.com/louis-e/arnis/issues/137)
|
||||
- [ ] Mapping real coordinates to Minecraft coordinates (https://github.com/louis-e/arnis/issues/29)
|
||||
- [ ] Add interior to buildings
|
||||
- [ ] Implement house roof types
|
||||
- [ ] Add street names as signs
|
||||
- [ ] Add support for inner attribute in multipolygons and multipolygon elements other than buildings
|
||||
- [ ] Refactor bridges implementation
|
||||
- [ ] Better code documentation
|
||||
- [ ] Refactor fountain structure implementation
|
||||
- [ ] Luanti Support (https://github.com/louis-e/arnis/issues/120)
|
||||
- [ ] Minecraft Bedrock Edition Support (https://github.com/louis-e/arnis/issues/148)
|
||||
- [x] Evaluate and implement elevation (https://github.com/louis-e/arnis/issues/66)
|
||||
- [x] Refactor railway implementation
|
||||
- [x] Evaluate and implement faster region saving
|
||||
- [x] Support multipolygons (https://github.com/louis-e/arnis/issues/112, https://github.com/louis-e/arnis/issues/114)
|
||||
- [x] Memory optimization
|
||||
- [x] Fix Github Action Workflow for releasing MacOS Binary
|
||||
- [x] Design and implement a GUI
|
||||
- [x] Automatic new world creation instead of using an existing world
|
||||
- [x] Fix faulty empty chunks ([https://github.com/owengage/fastnbt/issues/120](https://github.com/owengage/fastnbt/issues/120)) (workaround found)
|
||||
- [x] Setup fork of [https://github.com/aaronr/bboxfinder.com](https://github.com/aaronr/bboxfinder.com) for easy bbox picking
|
||||
|
||||
## :trophy: Open Source
|
||||
#### Key objectives of this project
|
||||
@@ -34,8 +102,10 @@ Full documentation is available in the [GitHub Wiki](https://github.com/louis-e/
|
||||
#### How to contribute
|
||||
This project is open source and welcomes contributions from everyone! Whether you're interested in fixing bugs, improving performance, adding new features, or enhancing documentation, your input is valuable. Simply fork the repository, make your changes, and submit a pull request. Please respect the above mentioned key objectives. Contributions of all levels are appreciated, and your efforts help improve this tool for everyone.
|
||||
|
||||
Command line Build: ```cargo run --no-default-features -- --terrain --path="C:/YOUR_PATH/.minecraft/saves/worldname" --bbox="min_lat,min_lng,max_lat,max_lng"```<br>
|
||||
GUI Build: ```cargo run```<br>
|
||||
Build and run it using: ```cargo run --release --no-default-features -- --path="C:/YOUR_PATH/.minecraft/saves/worldname" --bbox="min_lng,min_lat,max_lng,max_lat"```<br>
|
||||
For the GUI: ```cargo run --release```<br>
|
||||
|
||||
> You can use the parameter --debug to get a more detailed output of the processed values, which can be helpful for debugging and development.
|
||||
|
||||
After your pull request was merged, I will take care of regularly creating update releases which will include your changes.
|
||||
|
||||
@@ -49,20 +119,6 @@ After your pull request was merged, I will take care of regularly creating updat
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## :newspaper: Academic & Press Recognition
|
||||
|
||||
<img src="assets/git/recognition.png" width="100%" alt="Banner">
|
||||
|
||||
Arnis has been recognized in various academic and press publications after gaining a lot of attention in December 2024.
|
||||
|
||||
[Floodcraft: Game-based Interactive Learning Environment using Minecraft for Flood Mitigation and Preparedness for K-12 Education](https://www.researchgate.net/publication/384644535_Floodcraft_Game-based_Interactive_Learning_Environment_using_Minecraft_for_Flood_Mitigation_and_Preparedness_for_K-12_Education)
|
||||
|
||||
[Hackaday: Bringing OpenStreetMap Data into Minecraft](https://hackaday.com/2024/12/30/bringing-openstreetmap-data-into-minecraft/)
|
||||
|
||||
[TomsHardware: Minecraft Tool Lets You Create Scale Replicas of Real-World Locations](https://www.tomshardware.com/video-games/pc-gaming/minecraft-tool-lets-you-create-scale-replicas-of-real-world-locations-arnis-uses-geospatial-data-from-openstreetmap-to-generate-minecraft-maps)
|
||||
|
||||
[XDA Developers: Hometown Minecraft Map: Arnis](https://www.xda-developers.com/hometown-minecraft-map-arnis/)
|
||||
|
||||
## :copyright: License Information
|
||||
Copyright (c) 2022-2025 Louis Erbkamm (louis-e)
|
||||
|
||||
@@ -78,7 +134,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.[^3]
|
||||
|
||||
Download Arnis only from the official source https://arnismc.com or https://github.com/louis-e/arnis/. Every other website providing a download and claiming to be affiliated with the project is unofficial and may be malicious.
|
||||
Download Arnis only from the official source (https://github.com/louis-e/arnis/). Every other website providing a download and claiming to be affiliated with the project is unofficial and may be malicious.
|
||||
|
||||
The logo was made by @nxfx21.
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 790 KiB |
|
Before Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 258 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
60
flake.lock
generated
@@ -1,60 +0,0 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1755615617,
|
||||
"narHash": "sha256-HMwfAJBdrr8wXAkbGhtcby1zGFvs+StOp19xNsbqdOg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "20075955deac2583bb12f07151c2df830ef346b4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-unstable",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
36
flake.nix
@@ -1,36 +0,0 @@
|
||||
{
|
||||
inputs = {
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
nixpkgs.url = "nixpkgs/nixos-unstable";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
flake-utils,
|
||||
nixpkgs,
|
||||
...
|
||||
}:
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
|
||||
stdenv = if pkgs.stdenv.isLinux then pkgs.stdenvAdapters.useMoldLinker pkgs.stdenv else pkgs.stdenv;
|
||||
in
|
||||
{
|
||||
devShell = pkgs.mkShell.override { inherit stdenv; } {
|
||||
buildInputs = with pkgs; [
|
||||
openssl.dev
|
||||
pkg-config
|
||||
wayland
|
||||
glib
|
||||
gdk-pixbuf
|
||||
pango
|
||||
gtk3
|
||||
libsoup_3.dev
|
||||
webkitgtk_4_1.dev
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
99
flake/flake.lock
generated
Normal file
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"nodes": {
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1724653830,
|
||||
"narHash": "sha256-88f0KK8h6tGIP4Na5RJDKs0S+7WsGGaCGNkLj/bPV3g=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "9ecf5e7d800ace001320da8acadd4a3deb872a83",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1724479785,
|
||||
"narHash": "sha256-pP3Azj5d6M5nmG68Fu4JqZmdGt4S4vqI5f8te+E/FTw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d0e1602ddde669d5beb01aec49d71a51937ed7be",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-unstable",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"fenix": "fenix",
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1724586512,
|
||||
"narHash": "sha256-mrfwk6nO8N2WtCq3sB2zhd2QN1HMKzeSESzOA6lSsQg=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "7106cd3be50b2a43c1d9f2787bf22d4369c2b25b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
34
flake/flake.nix
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
inputs = {
|
||||
fenix = {
|
||||
url = "github:nix-community/fenix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
nixpkgs.url = "nixpkgs/nixos-unstable";
|
||||
};
|
||||
|
||||
outputs = { self, fenix, flake-utils, nixpkgs }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
fenixPkgs = (fenix.packages.${system}.stable);
|
||||
in
|
||||
{
|
||||
devShell = pkgs.mkShell
|
||||
{
|
||||
buildInputs = with pkgs; [
|
||||
openssl.dev
|
||||
pkg-config
|
||||
fenixPkgs.toolchain
|
||||
wayland
|
||||
glib
|
||||
gdk-pixbuf
|
||||
pango
|
||||
gtk3
|
||||
libsoup_3.dev
|
||||
webkitgtk_4_1.dev
|
||||
];
|
||||
};
|
||||
});
|
||||
}
|
||||
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
BIN
gitassets/gui.png
Normal file
|
After Width: | Height: | Size: 198 KiB |
BIN
gitassets/mc.gif
Normal file
|
After Width: | Height: | Size: 9.7 MiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 418 B |
|
Before Width: | Height: | Size: 312 B After Width: | Height: | Size: 312 B |
|
Before Width: | Height: | Size: 205 B After Width: | Height: | Size: 205 B |
|
Before Width: | Height: | Size: 262 B After Width: | Height: | Size: 262 B |
|
Before Width: | Height: | Size: 348 B After Width: | Height: | Size: 348 B |
|
Before Width: | Height: | Size: 207 B After Width: | Height: | Size: 207 B |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 278 B |
|
Before Width: | Height: | Size: 328 B After Width: | Height: | Size: 328 B |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 849 B After Width: | Height: | Size: 849 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 847 B After Width: | Height: | Size: 847 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
BIN
gui-src/css/maps/images/spritesheet.png
vendored
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
49
gui-src/css/maps/leaflet.draw.ie.css
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/* Conditional stylesheet for IE. */
|
||||
|
||||
.leaflet-draw-toolbar {
|
||||
border: 3px solid #999;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar a {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar a:hover {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions {
|
||||
left: 32px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions li {
|
||||
display: inline;
|
||||
zoom: 1;
|
||||
}
|
||||
|
||||
.leaflet-edit-marker-selected {
|
||||
border: 4px dashed #fe93c2;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions a {
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions a:hover {
|
||||
background-color: #a5a5a5;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions-top a {
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions-bottom a {
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions-top.leaflet-draw-actions-bottom a {
|
||||
height: 27px;
|
||||
line-height: 27px;
|
||||
}
|
||||
51
gui-src/css/maps/leaflet.ie.css
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
.leaflet-vml-shape {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
.lvml {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.leaflet-control {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.leaflet-popup-tip {
|
||||
width: 21px;
|
||||
_width: 27px;
|
||||
margin: 0 auto;
|
||||
_margin-top: -3px;
|
||||
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
margin-top: -1px;
|
||||
}
|
||||
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
zoom: 1;
|
||||
}
|
||||
|
||||
.leaflet-control-zoom,
|
||||
.leaflet-control-layers {
|
||||
border: 3px solid #999;
|
||||
}
|
||||
.leaflet-control-layers-toggle {
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-layers,
|
||||
.leaflet-control-scale-line {
|
||||
background: white;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
filter: alpha(opacity=50);
|
||||
}
|
||||
.leaflet-control-attribution {
|
||||
border-top: 1px solid #bbb;
|
||||
border-left: 1px solid #bbb;
|
||||
}
|
||||
757
gui-src/css/maps/mapbox.standalone.css
vendored
Normal file
@@ -0,0 +1,757 @@
|
||||
/* general typography */
|
||||
.leaflet-container {
|
||||
background:#fff;
|
||||
font:15px/25px 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||
color:#404040;
|
||||
color:rgba(0,0,0,0.75);
|
||||
outline:0;
|
||||
overflow:hidden;
|
||||
-ms-touch-action:none;
|
||||
}
|
||||
.leaflet-container *,
|
||||
.leaflet-container *:after,
|
||||
.leaflet-container *:before {
|
||||
-webkit-box-sizing:border-box;
|
||||
-moz-box-sizing:border-box;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
|
||||
.leaflet-container h1,
|
||||
.leaflet-container h2,
|
||||
.leaflet-container h3,
|
||||
.leaflet-container h4,
|
||||
.leaflet-container h5,
|
||||
.leaflet-container h6,
|
||||
.leaflet-container p {
|
||||
font-size:15px;
|
||||
line-height:25px;
|
||||
margin:0 0 10px;
|
||||
}
|
||||
.mapbox-small,
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale,
|
||||
.leaflet-container input,
|
||||
.leaflet-container textarea,
|
||||
.leaflet-container label,
|
||||
.leaflet-container small {
|
||||
font-size:12px;
|
||||
line-height:20px;
|
||||
}
|
||||
|
||||
.leaflet-container a {
|
||||
color:#3887BE;
|
||||
font-weight:normal;
|
||||
text-decoration:none;
|
||||
}
|
||||
.leaflet-container a:hover { color:#63b6e5; }
|
||||
.leaflet-container.dark a { color:#63b6e5; }
|
||||
.leaflet-container.dark a:hover { color:#8fcaec; }
|
||||
|
||||
.leaflet-container.dark .mapbox-button,
|
||||
.leaflet-container .mapbox-button {
|
||||
background-color:#3887be;
|
||||
display:inline-block;
|
||||
height:40px;
|
||||
line-height:40px;
|
||||
text-decoration:none;
|
||||
color:#fff;
|
||||
font-size:12px;
|
||||
white-space:nowrap;
|
||||
text-overflow:ellipsis;
|
||||
}
|
||||
.leaflet-container.dark .mapbox-button:hover,
|
||||
.leaflet-container .mapbox-button:hover {
|
||||
color:#fff;
|
||||
background-color:#3bb2d0;
|
||||
}
|
||||
|
||||
/* Base Leaflet
|
||||
------------------------------------------------------- */
|
||||
.leaflet-map-pane,
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-tile-pane,
|
||||
.leaflet-tile-container,
|
||||
.leaflet-overlay-pane,
|
||||
.leaflet-shadow-pane,
|
||||
.leaflet-marker-pane,
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-overlay-pane svg,
|
||||
.leaflet-zoom-box,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-layer {
|
||||
position:absolute;
|
||||
left:0;
|
||||
top:0;
|
||||
}
|
||||
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
-webkit-user-drag:none;
|
||||
-webkit-user-select:none;
|
||||
-moz-user-select:none;
|
||||
user-select:none;
|
||||
}
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.leaflet-tile {
|
||||
filter:inherit;
|
||||
visibility:hidden;
|
||||
}
|
||||
.leaflet-tile-loaded {
|
||||
visibility:inherit;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
width:0;
|
||||
height:0;
|
||||
}
|
||||
|
||||
.leaflet-tile-pane { z-index:2; }
|
||||
.leaflet-objects-pane { z-index:3; }
|
||||
.leaflet-overlay-pane { z-index:4; }
|
||||
.leaflet-shadow-pane { z-index:5; }
|
||||
.leaflet-marker-pane { z-index:6; }
|
||||
.leaflet-popup-pane { z-index:7; }
|
||||
|
||||
.leaflet-control {
|
||||
position:relative;
|
||||
z-index:7;
|
||||
pointer-events:auto;
|
||||
float:left;
|
||||
clear:both;
|
||||
}
|
||||
.leaflet-right .leaflet-control { float:right; }
|
||||
.leaflet-top .leaflet-control { margin-top:10px; }
|
||||
.leaflet-bottom .leaflet-control { margin-bottom:10px; }
|
||||
.leaflet-left .leaflet-control { margin-left:10px; }
|
||||
.leaflet-right .leaflet-control { margin-right:10px; }
|
||||
|
||||
.leaflet-top,
|
||||
.leaflet-bottom {
|
||||
position:absolute;
|
||||
z-index:1000;
|
||||
pointer-events:none;
|
||||
}
|
||||
.leaflet-top { top:0; }
|
||||
.leaflet-right { right:0; }
|
||||
.leaflet-bottom { bottom:0; }
|
||||
.leaflet-left { left:0; }
|
||||
|
||||
/* zoom and fade animations */
|
||||
.leaflet-fade-anim .leaflet-tile,
|
||||
.leaflet-fade-anim .leaflet-popup {
|
||||
opacity:0;
|
||||
-webkit-transition:opacity 0.2s linear;
|
||||
-moz-transition:opacity 0.2s linear;
|
||||
-o-transition:opacity 0.2s linear;
|
||||
transition:opacity 0.2s linear;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-tile-loaded,
|
||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
-webkit-transition:-webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-tile,
|
||||
.leaflet-pan-anim .leaflet-tile,
|
||||
.leaflet-touching .leaflet-zoom-animated {
|
||||
-webkit-transition:none;
|
||||
-moz-transition:none;
|
||||
-o-transition:none;
|
||||
transition:none;
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-zoom-hide { visibility: hidden; }
|
||||
|
||||
/* cursors */
|
||||
.map-clickable,
|
||||
.leaflet-clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-control {
|
||||
cursor:auto;
|
||||
}
|
||||
.leaflet-container {
|
||||
cursor:-webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
}
|
||||
.leaflet-dragging,
|
||||
.leaflet-dragging .map-clickable,
|
||||
.leaflet-dragging .leaflet-clickable,
|
||||
.leaflet-dragging .leaflet-container {
|
||||
cursor:move;
|
||||
cursor:-webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
}
|
||||
|
||||
.leaflet-zoom-box {
|
||||
background:#fff;
|
||||
border:2px dotted #202020;
|
||||
opacity:0.5;
|
||||
}
|
||||
|
||||
/* general toolbar styles */
|
||||
.leaflet-control-layers,
|
||||
.leaflet-bar {
|
||||
background-color:#fff;
|
||||
border:1px solid #999;
|
||||
border-color:rgba(0,0,0,0.4);
|
||||
border-radius:3px;
|
||||
box-shadow:none;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-bar a:hover {
|
||||
color:#404040;
|
||||
color:rgba(0,0,0,0.75);
|
||||
border-bottom:1px solid #ddd;
|
||||
border-bottom-color:rgba(0,0,0,0.10);
|
||||
}
|
||||
.leaflet-bar a:hover,
|
||||
.leaflet-bar a:active {
|
||||
background-color:#f8f8f8;
|
||||
cursor:pointer;
|
||||
}
|
||||
.leaflet-bar a:first-child {
|
||||
border-radius:3px 3px 0 0;
|
||||
}
|
||||
.leaflet-bar a:last-child {
|
||||
border-bottom:none;
|
||||
border-radius:0 0 3px 3px;
|
||||
}
|
||||
.leaflet-bar a:only-of-type {
|
||||
border-radius:3px;
|
||||
}
|
||||
|
||||
.leaflet-bar .leaflet-disabled {
|
||||
cursor:default;
|
||||
opacity:0.75;
|
||||
}
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out {
|
||||
display:block;
|
||||
content:'';
|
||||
text-indent:-999em;
|
||||
}
|
||||
|
||||
.leaflet-control-layers .leaflet-control-layers-list,
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
|
||||
display:none;
|
||||
}
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-list {
|
||||
display:block;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.leaflet-control-layers-expanded {
|
||||
background:#fff;
|
||||
padding:6px 10px 6px 6px;
|
||||
color:#404040;
|
||||
color:rgba(0,0,0,0.75);
|
||||
}
|
||||
.leaflet-control-layers-selector {
|
||||
margin-top:2px;
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
.leaflet-control-layers label {
|
||||
display: block;
|
||||
}
|
||||
.leaflet-control-layers-separator {
|
||||
height:0;
|
||||
border-top:1px solid #ddd;
|
||||
border-top-color:rgba(0,0,0,0.10);
|
||||
margin:5px -10px 5px -6px;
|
||||
}
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
background-color:rgba(255,255,255,0.25);
|
||||
margin:0;
|
||||
box-shadow:none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover,
|
||||
.map-info-container a:hover {
|
||||
color:inherit;
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding:0 5px;
|
||||
}
|
||||
.leaflet-left .leaflet-control-scale { margin-left:5px; }
|
||||
.leaflet-bottom .leaflet-control-scale { margin-bottom:5px; }
|
||||
|
||||
.leaflet-control-scale-line {
|
||||
background-color:rgba(255,255,255,0.5);
|
||||
border:1px solid #999;
|
||||
border-color:rgba(0,0,0,0.4);
|
||||
border-top:none;
|
||||
padding:2px 5px 1px;
|
||||
white-space:nowrap;
|
||||
overflow:hidden;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top:2px solid #ddd;
|
||||
border-top-color:rgba(0,0,0,0.10);
|
||||
border-bottom:none;
|
||||
margin-top:-2px;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
|
||||
border-bottom:2px solid #777;
|
||||
}
|
||||
|
||||
/* popup */
|
||||
.leaflet-popup {
|
||||
position:absolute;
|
||||
text-align:center;
|
||||
pointer-events:none;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
padding:1px;
|
||||
text-align:left;
|
||||
pointer-events:all;
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
padding:10px 10px 15px;
|
||||
margin:0;
|
||||
line-height:inherit;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
width:20px;
|
||||
height:20px;
|
||||
margin:0 auto;
|
||||
position:relative;
|
||||
}
|
||||
.leaflet-popup-tip {
|
||||
width:0;
|
||||
height:0;
|
||||
margin:0;
|
||||
border-left:10px solid transparent;
|
||||
border-right:10px solid transparent;
|
||||
border-top:10px solid #fff;
|
||||
box-shadow:none;
|
||||
}
|
||||
.leaflet-popup-close-button {
|
||||
text-indent:-999em;
|
||||
position:absolute;
|
||||
top:0;right:0;
|
||||
pointer-events:all;
|
||||
}
|
||||
.leaflet-popup-close-button:hover {
|
||||
background-color:#f8f8f8;
|
||||
}
|
||||
|
||||
.leaflet-popup-scrolled {
|
||||
overflow:auto;
|
||||
border-bottom:1px solid #ddd;
|
||||
border-top:1px solid #ddd;
|
||||
}
|
||||
|
||||
/* div icon */
|
||||
.leaflet-div-icon {
|
||||
background:#fff;
|
||||
border:1px solid #999;
|
||||
border-color:rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-editing-icon {
|
||||
border-radius:3px;
|
||||
}
|
||||
|
||||
/* Leaflet + Mapbox
|
||||
------------------------------------------------------- */
|
||||
.leaflet-bar a,
|
||||
.mapbox-icon,
|
||||
.map-tooltip.closable .close,
|
||||
.leaflet-control-layers-toggle,
|
||||
.leaflet-popup-close-button,
|
||||
.mapbox-button-icon:before {
|
||||
content:'';
|
||||
display:inline-block;
|
||||
width:26px;
|
||||
height:26px;
|
||||
vertical-align:middle;
|
||||
background-repeat:no-repeat;
|
||||
}
|
||||
.leaflet-bar a {
|
||||
display:block;
|
||||
}
|
||||
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out,
|
||||
.leaflet-popup-close-button,
|
||||
.leaflet-control-layers-toggle,
|
||||
.leaflet-container.dark .map-tooltip .close,
|
||||
.map-tooltip .close,
|
||||
.mapbox-icon {
|
||||
background-image:url(./images/icons-404040.png);
|
||||
background-repeat:no-repeat;
|
||||
background-size:26px 260px;
|
||||
}
|
||||
.mapbox-button-icon:before,
|
||||
.leaflet-container.dark .leaflet-control-zoom-in,
|
||||
.leaflet-container.dark .leaflet-control-zoom-out,
|
||||
.leaflet-container.dark .leaflet-control-layers-toggle,
|
||||
.leaflet-container.dark .mapbox-icon {
|
||||
background-image:url(./images/icons-ffffff.png);
|
||||
background-size:26px 260px;
|
||||
}
|
||||
.leaflet-bar .leaflet-control-zoom-in { background-position:0 0; }
|
||||
.leaflet-bar .leaflet-control-zoom-out { background-position:0 -26px; }
|
||||
.map-tooltip .close, .leaflet-popup-close-button { background-position:0 -52px; }
|
||||
.mapbox-icon-info { background-position:0 -78px; }
|
||||
.leaflet-control-layers-toggle { background-position:0 -104px; }
|
||||
.mapbox-icon-share:before, .mapbox-icon-share { background-position:0 -130px; }
|
||||
.mapbox-icon-geocoder:before, .mapbox-icon-geocoder { background-position:0 -156px; }
|
||||
.mapbox-icon-facebook:before, .mapbox-icon-facebook { background-position:0 -182px; }
|
||||
.mapbox-icon-twitter:before, .mapbox-icon-twitter { background-position:0 -208px; }
|
||||
.mapbox-icon-pinterest:before, .mapbox-icon-pinterest { background-position:0 -234px; }
|
||||
|
||||
@media
|
||||
(-webkit-min-device-pixel-ratio:2),
|
||||
(min-resolution:192dpi) {
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out,
|
||||
.leaflet-popup-close-button,
|
||||
.leaflet-control-layers-toggle,
|
||||
.mapbox-icon {
|
||||
background-image:url(./images/icons-404040@2x.png);
|
||||
}
|
||||
.mapbox-button-icon:before,
|
||||
.leaflet-container.dark .leaflet-control-zoom-in,
|
||||
.leaflet-container.dark .leaflet-control-zoom-out,
|
||||
.leaflet-container.dark .leaflet-control-layers-toggle,
|
||||
.leaflet-container.dark .mapbox-icon {
|
||||
background-image:url(./images/icons-ffffff@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.leaflet-popup-content-wrapper,
|
||||
.map-legends,
|
||||
.map-tooltip {
|
||||
background:#fff;
|
||||
border-radius:3px;
|
||||
box-shadow:0 1px 2px rgba(0,0,0,0.10);
|
||||
}
|
||||
.map-legends,
|
||||
.map-tooltip {
|
||||
max-width:300px;
|
||||
}
|
||||
.map-legends .map-legend {
|
||||
padding:10px;
|
||||
}
|
||||
.map-tooltip {
|
||||
z-index:999999;
|
||||
padding:10px;
|
||||
min-width:180px;
|
||||
max-height:400px;
|
||||
overflow:auto;
|
||||
opacity:1;
|
||||
-webkit-transition:opacity 150ms;
|
||||
-moz-transition:opacity 150ms;
|
||||
-o-transition:opacity 150ms;
|
||||
transition:opacity 150ms;
|
||||
}
|
||||
|
||||
.map-tooltip .close {
|
||||
text-indent:-999em;
|
||||
overflow:hidden;
|
||||
display:none;
|
||||
}
|
||||
.map-tooltip.closable .close {
|
||||
position:absolute;
|
||||
top:0;right:0;
|
||||
border-radius:3px;
|
||||
}
|
||||
.map-tooltip.closable .close:active {
|
||||
background-color:#f8f8f8;
|
||||
}
|
||||
|
||||
.leaflet-control-interaction {
|
||||
position:absolute;
|
||||
top:10px;
|
||||
right:10px;
|
||||
width:300px;
|
||||
}
|
||||
.leaflet-popup-content .marker-title {
|
||||
font-weight:bold;
|
||||
}
|
||||
.leaflet-control .mapbox-button {
|
||||
background-color:#fff;
|
||||
border:1px solid #ddd;
|
||||
border-color:rgba(0,0,0,0.10);
|
||||
padding:5px 10px;
|
||||
border-radius:3px;
|
||||
}
|
||||
|
||||
/* Share modal
|
||||
------------------------------------------------------- */
|
||||
.mapbox-modal > div {
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
width:100%;
|
||||
height:100%;
|
||||
z-index:-1;
|
||||
overflow-y:auto;
|
||||
}
|
||||
.mapbox-modal.active > div {
|
||||
z-index:99999;
|
||||
transition:all .2s, z-index 0 0;
|
||||
}
|
||||
|
||||
.mapbox-modal .mapbox-modal-mask {
|
||||
background:rgba(0,0,0,0.5);
|
||||
opacity:0;
|
||||
}
|
||||
.mapbox-modal.active .mapbox-modal-mask { opacity:1; }
|
||||
|
||||
.mapbox-modal .mapbox-modal-content {
|
||||
-webkit-transform:translateY(-100%);
|
||||
-moz-transform:translateY(-100%);
|
||||
-ms-transform:translateY(-100%);
|
||||
transform:translateY(-100%);
|
||||
}
|
||||
.mapbox-modal.active .mapbox-modal-content {
|
||||
-webkit-transform:translateY(0);
|
||||
-moz-transform:translateY(0);
|
||||
-ms-transform:translateY(0);
|
||||
transform:translateY(0);
|
||||
}
|
||||
|
||||
.mapbox-modal-body {
|
||||
position:relative;
|
||||
background:#fff;
|
||||
padding:20px;
|
||||
z-index:1000;
|
||||
width:50%;
|
||||
margin:20px 0 20px 25%;
|
||||
}
|
||||
.mapbox-share-buttons {
|
||||
margin:0 0 20px;
|
||||
}
|
||||
.mapbox-share-buttons a {
|
||||
width:33.3333%;
|
||||
border-left:1px solid #fff;
|
||||
text-align:center;
|
||||
border-radius:0;
|
||||
}
|
||||
.mapbox-share-buttons a:last-child { border-radius:0 3px 3px 0; }
|
||||
.mapbox-share-buttons a:first-child { border:none; border-radius:3px 0 0 3px; }
|
||||
|
||||
.mapbox-modal input {
|
||||
width:100%;
|
||||
height:40px;
|
||||
padding:10px;
|
||||
border:1px solid #ddd;
|
||||
border-color:rgba(0,0,0,0.10);
|
||||
color:rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
/* Info Control
|
||||
------------------------------------------------------- */
|
||||
.leaflet-control.mapbox-control-info {
|
||||
margin:5px 30px 10px 10px;
|
||||
min-height:26px;
|
||||
}
|
||||
.leaflet-control.mapbox-control-info-right {
|
||||
margin:5px 10px 10px 30px;
|
||||
}
|
||||
|
||||
.mapbox-info-toggle {
|
||||
background-color:#fff;
|
||||
background-color:rgba(255,255,255,0.25);
|
||||
border-radius:50%;
|
||||
position:absolute;
|
||||
bottom:0;left:0;
|
||||
z-index:1;
|
||||
}
|
||||
.mapbox-control-info-right .mapbox-info-toggle { left:auto; right:0; }
|
||||
.mapbox-control-info.active .mapbox-info-toggle { background-color:#fff; }
|
||||
.mapbox-info-toggle:hover { background-color:rgba(255,255,255,0.5); }
|
||||
|
||||
.map-info-container {
|
||||
background:#fff;
|
||||
background:rgba(255,255,255,0.75);
|
||||
padding:3px 5px 3px 15px;
|
||||
display:none;
|
||||
position:relative;
|
||||
bottom:0;
|
||||
left:13px;
|
||||
border-radius:3px;
|
||||
}
|
||||
.mapbox-control-info.active .map-info-container { display:inline-block; }
|
||||
.mapbox-control-info-right .map-info-container {
|
||||
left:auto;
|
||||
right:13px;
|
||||
padding:3px 15px 3px 5px;
|
||||
}
|
||||
|
||||
/* Geocoder
|
||||
------------------------------------------------------- */
|
||||
.leaflet-control-mapbox-geocoder {
|
||||
position:relative;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder.searching {
|
||||
opacity:0.75;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder .leaflet-control-mapbox-geocoder-wrap {
|
||||
background:#fff;
|
||||
position:absolute;
|
||||
border:1px solid #999;
|
||||
border-color:rgba(0,0,0,0.4);
|
||||
border-bottom-width:0;
|
||||
overflow:hidden;
|
||||
left:26px;
|
||||
height:27px;
|
||||
width:0;
|
||||
top:-1px;
|
||||
border-radius:0 3px 3px 0;
|
||||
opacity:0;
|
||||
-webkit-transition:opacity 100ms;
|
||||
-moz-transition:opacity 100ms;
|
||||
-o-transition:opacity 100ms;
|
||||
transition:opacity 100ms;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder.active .leaflet-control-mapbox-geocoder-wrap {
|
||||
width:180px;
|
||||
opacity:1;
|
||||
}
|
||||
.leaflet-bar .leaflet-control-mapbox-geocoder-toggle,
|
||||
.leaflet-bar .leaflet-control-mapbox-geocoder-toggle:hover {
|
||||
border-bottom:none;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder-toggle {
|
||||
border-radius:3px;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder.active,
|
||||
.leaflet-control-mapbox-geocoder.active .leaflet-control-mapbox-geocoder-toggle {
|
||||
border-top-right-radius:0;
|
||||
border-bottom-right-radius:0;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder .leaflet-control-mapbox-geocoder-form input {
|
||||
background:transparent;
|
||||
border:0;
|
||||
width:180px;
|
||||
padding:0 0 0 10px;
|
||||
height:26px;
|
||||
outline:none;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder-results {
|
||||
width:180px;
|
||||
position:absolute;
|
||||
left:26px;
|
||||
top:25px;
|
||||
border-radius:0 0 3px 3px;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder.active .leaflet-control-mapbox-geocoder-results {
|
||||
background:#fff;
|
||||
border:1px solid #999;
|
||||
border-color:rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.leaflet-control-mapbox-geocoder-results a,
|
||||
.leaflet-control-mapbox-geocoder-results span {
|
||||
padding:0 10px;
|
||||
text-overflow:ellipsis;
|
||||
white-space:nowrap;
|
||||
display:block;
|
||||
width:100%;
|
||||
font-size:12px;
|
||||
line-height:26px;
|
||||
text-align:left;
|
||||
overflow:hidden;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder-results a:first-child {
|
||||
border-top:1px solid #999;
|
||||
border-top-color:rgba(0,0,0,0.4);
|
||||
border-radius:0;
|
||||
}
|
||||
.leaflet-container.dark .leaflet-control .leaflet-control-mapbox-geocoder-results a:hover,
|
||||
.leaflet-control-mapbox-geocoder-results a:hover {
|
||||
background:#f8f8f8;
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
/* Dark Theme
|
||||
------------------------------------------------------- */
|
||||
.leaflet-container.dark .leaflet-bar {
|
||||
background-color:#404040;
|
||||
border-color:#202020;
|
||||
border-color:rgba(0,0,0,0.75);
|
||||
}
|
||||
.leaflet-container.dark .leaflet-bar a {
|
||||
color:#404040;
|
||||
border-color:rgba(0,0,0,0.5);
|
||||
}
|
||||
.leaflet-container.dark .leaflet-bar a:active,
|
||||
.leaflet-container.dark .leaflet-bar a:hover {
|
||||
background-color:#505050;
|
||||
}
|
||||
|
||||
.leaflet-container.dark .mapbox-info-toggle,
|
||||
.leaflet-container.dark .map-info-container,
|
||||
.leaflet-container.dark .leaflet-control-attribution {
|
||||
background-color:rgba(0,0,0,0.25);
|
||||
color:#f8f8f8;
|
||||
}
|
||||
.leaflet-container.dark .leaflet-bar a.leaflet-disabled,
|
||||
.leaflet-container.dark .leaflet-control .mapbox-button.disabled {
|
||||
background-color:#252525;
|
||||
color:#404040;
|
||||
}
|
||||
.leaflet-container.dark .leaflet-control-mapbox-geocoder > div {
|
||||
border-color:#202020;
|
||||
border-color:rgba(0,0,0,0.75);
|
||||
}
|
||||
.leaflet-container.dark .leaflet-control .leaflet-control-mapbox-geocoder-results a {
|
||||
border-color:#ddd #202020;
|
||||
border-color:rgba(0,0,0,0.10) rgba(0,0,0,0.75);
|
||||
}
|
||||
.leaflet-container.dark .leaflet-control .leaflet-control-mapbox-geocoder-results span {
|
||||
border-color:#202020;
|
||||
border-color:rgba(0,0,0,0.75);
|
||||
}
|
||||
|
||||
/* Larger Screens
|
||||
------------------------------------------------------- */
|
||||
@media only screen and (max-width:800px) {
|
||||
.mapbox-modal-body {
|
||||
width:83.3333%;
|
||||
margin-left:8.3333%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Smaller Screens
|
||||
------------------------------------------------------- */
|
||||
@media only screen and (max-width:640px) {
|
||||
.mapbox-modal-body {
|
||||
width:100%;
|
||||
height:100%;
|
||||
margin:0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Browser Fixes
|
||||
------------------------------------------------------- */
|
||||
/* Map is broken in FF if you have max-width: 100% on tiles */
|
||||
.leaflet-container img { max-width:none!important; }
|
||||
/* Stupid Android 2 doesn't understand "max-width: none" properly */
|
||||
.leaflet-container img.leaflet-image-layer { max-width:15000px!important; }
|
||||
/* Android chrome makes tiles disappear without this */
|
||||
.leaflet-tile-container img { -webkit-backface-visibility:hidden; }
|
||||
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
|
||||
.leaflet-overlay-pane svg { -moz-user-select:none; }
|
||||
/* Older IEs don't support the translateY property for display animation */
|
||||
.leaflet-oldie .mapbox-modal .mapbox-modal-content { display:none; }
|
||||
.leaflet-oldie .mapbox-modal.active .mapbox-modal-content { display:block; }
|
||||
.map-tooltip { width:280px\8; /* < IE9 */ }
|
||||
1
gui-src/css/maps/mapbox.v3.2.0.css
vendored
Normal file
192
src/gui/css/styles.css → gui-src/css/styles.css
vendored
@@ -10,11 +10,6 @@
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
|
||||
/* CSS Variables for consistent theming */
|
||||
--primary-accent: #fecc44;
|
||||
--primary-accent-dark: #e6b73d;
|
||||
--primary-accent-light: #fff2cc;
|
||||
}
|
||||
|
||||
p {
|
||||
@@ -48,13 +43,12 @@ p {
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: var(--primary-accent);
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--primary-accent-dark);
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
.flex-container {
|
||||
@@ -265,22 +259,6 @@ button:hover {
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
#interior-toggle {
|
||||
accent-color: #fecc44;
|
||||
}
|
||||
|
||||
.interior-toggle-container, .scale-slider-container {
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
#roof-toggle {
|
||||
accent-color: #fecc44;
|
||||
}
|
||||
|
||||
.roof-toggle-container, .scale-slider-container {
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.scale-slider-container label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
@@ -318,160 +296,6 @@ button:hover {
|
||||
box-shadow: 0 0 5px #fecc44;
|
||||
}
|
||||
|
||||
/* Settings Modal Layout */
|
||||
.settings-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.settings-row label {
|
||||
text-align: left;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.settings-control {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.settings-control input[type="range"] {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.settings-control input[type="text"],
|
||||
.settings-control input[type="number"] {
|
||||
width: 100%;
|
||||
max-width: 180px;
|
||||
padding: 5px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #fecc44;
|
||||
}
|
||||
|
||||
.license-button-row {
|
||||
justify-content: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.license-button {
|
||||
width: 80% !important;
|
||||
}
|
||||
|
||||
/* Buy Me a Coffee and Discord styling */
|
||||
.buymeacoffee-row {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
|
||||
.buymeacoffee-link,
|
||||
.discord-link {
|
||||
display: inline-block;
|
||||
transition: transform 0.3s ease, opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.buymeacoffee-link:hover,
|
||||
.discord-link:hover {
|
||||
transform: scale(1.05);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.buymeacoffee-logo,
|
||||
.discord-logo {
|
||||
height: 35px;
|
||||
width: auto;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* Generation mode dropdown styling */
|
||||
.generation-mode-dropdown {
|
||||
width: 100%;
|
||||
max-width: 180px;
|
||||
padding: 5px 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #fecc44;
|
||||
background-color: #ffffff;
|
||||
color: #0f0f0f;
|
||||
appearance: menulist;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
.generation-mode-dropdown option {
|
||||
padding: 5px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.generation-mode-dropdown {
|
||||
background-color: #0f0f0f98;
|
||||
color: #ffffff;
|
||||
border: 1px solid #fecc44;
|
||||
}
|
||||
}
|
||||
|
||||
/* Language dropdown styling */
|
||||
.language-dropdown {
|
||||
width: 100%;
|
||||
max-width: 180px;
|
||||
padding: 5px 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #fecc44;
|
||||
background-color: #ffffff;
|
||||
color: #0f0f0f;
|
||||
appearance: menulist;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
.language-dropdown option {
|
||||
padding: 5px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.language-dropdown {
|
||||
background-color: #0f0f0f98;
|
||||
color: #ffffff;
|
||||
border: 1px solid #fecc44;
|
||||
}
|
||||
}
|
||||
|
||||
/* Theme dropdown styling */
|
||||
.theme-dropdown {
|
||||
width: 100%;
|
||||
max-width: 180px;
|
||||
padding: 5px 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #fecc44;
|
||||
background-color: #ffffff;
|
||||
color: #0f0f0f;
|
||||
appearance: menulist;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
.theme-dropdown option {
|
||||
padding: 5px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.theme-dropdown {
|
||||
background-color: #0f0f0f98;
|
||||
color: #ffffff;
|
||||
border: 1px solid #fecc44;
|
||||
}
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: flex;
|
||||
@@ -514,22 +338,18 @@ button:hover {
|
||||
width: 35%;
|
||||
height: auto;
|
||||
opacity: 0;
|
||||
transform: scale(0) rotate(-10deg);
|
||||
animation: zoomInLogo 1.2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
|
||||
transform: scale(0);
|
||||
animation: zoomInLogo 1s ease-out forwards;
|
||||
}
|
||||
|
||||
/* Keyframe Animation */
|
||||
@keyframes zoomInLogo {
|
||||
0% {
|
||||
transform: scale(0) rotate(-10deg);
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
60% {
|
||||
transform: scale(1.05) rotate(2deg);
|
||||
opacity: 0.8;
|
||||
}
|
||||
100% {
|
||||
transform: scale(1) rotate(0deg);
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 487 B After Width: | Height: | Size: 487 B |
|
Before Width: | Height: | Size: 231 KiB After Width: | Height: | Size: 231 KiB |
|
Before Width: | Height: | Size: 811 B After Width: | Height: | Size: 811 B |
128
src/gui/index.html → gui-src/index.html
vendored
@@ -8,14 +8,13 @@
|
||||
<title>Arnis</title>
|
||||
<script type="module" src="./js/main.js" defer></script>
|
||||
<script type="module" src="./js/license.js" defer></script>
|
||||
<script type="module" src="./js/language-selector.js" defer></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main class="container">
|
||||
<div class="row">
|
||||
<a href="https://arnismc.com" target="_blank">
|
||||
<img src="./images/logo.png" id="arnis-logo" class="logo arnis" alt="Arnis Logo" style="width: 35%; height: auto;">
|
||||
<a href="https://github.com/louis-e/arnis" target="_blank">
|
||||
<img src="./images/logo.png" id="arnis-logo" class="logo arnis" alt="Arnis Logo" style="width: 35%; height: auto;" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -87,119 +86,44 @@
|
||||
<span class="close-button" onclick="closeSettings()">×</span>
|
||||
<h2 data-localize="customization_settings">Customization Settings</h2>
|
||||
|
||||
<!-- Generation Mode Dropdown -->
|
||||
<div class="settings-row">
|
||||
<label for="generation-mode-select" data-localize="generation_mode">Generation Mode</label>
|
||||
<div class="settings-control">
|
||||
<select id="generation-mode-select" name="generation-mode-select" class="generation-mode-dropdown">
|
||||
<option value="geo-terrain" data-localize="mode_geo_terrain">Objects + Terrain</option>
|
||||
<option value="geo-only" data-localize="mode_geo_only">Objects only</option>
|
||||
<option value="terrain-only" data-localize="mode_terrain_only">Terrain only</option>
|
||||
</select>
|
||||
</div>
|
||||
<!-- Terrain Toggle Button -->
|
||||
<div class="terrain-toggle-container">
|
||||
<label for="terrain-toggle" data-localize="terrain">Terrain:</label>
|
||||
<input type="checkbox" id="terrain-toggle" name="terrain-toggle" checked>
|
||||
</div>
|
||||
|
||||
<!-- Interior Toggle Button -->
|
||||
<div class="settings-row">
|
||||
<label for="interior-toggle" data-localize="interior">Interior Generation</label>
|
||||
<div class="settings-control">
|
||||
<input type="checkbox" id="interior-toggle" name="interior-toggle" checked>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Roof Toggle Button -->
|
||||
<div class="settings-row">
|
||||
<label for="roof-toggle" data-localize="roof">Roof Generation</label>
|
||||
<div class="settings-control">
|
||||
<input type="checkbox" id="roof-toggle" name="roof-toggle" checked>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Fill ground Toggle Button -->
|
||||
<div class="settings-row">
|
||||
<label for="fillground-toggle" data-localize="fillground">Fill Ground</label>
|
||||
<div class="settings-control">
|
||||
<input type="checkbox" id="fillground-toggle" name="fillground-toggle">
|
||||
</div>
|
||||
<div class="fillground-toggle-container">
|
||||
<label for="fillground-toggle" data-localize="fillground">Fill Ground:</label>
|
||||
<input type="checkbox" id="fillground-toggle" name="fillground-toggle">
|
||||
</div>
|
||||
|
||||
<!-- World Scale Slider -->
|
||||
<div class="settings-row">
|
||||
<label for="scale-value-slider" data-localize="world_scale">World Scale</label>
|
||||
<div class="settings-control">
|
||||
<input type="range" id="scale-value-slider" name="scale-value-slider" min="0.30" max="2.5" step="0.1" value="1">
|
||||
<span id="slider-value">1.00</span>
|
||||
</div>
|
||||
<div class="scale-slider-container">
|
||||
<label for="scale-value-slider" data-localize="world_scale">World Scale:</label>
|
||||
<input type="range" id="scale-value-slider" name="scale-value-slider" min="0.30" max="2.5" step="0.1" value="1">
|
||||
<span id="slider-value">1.00</span>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Bounding Box Input -->
|
||||
<div class="settings-row">
|
||||
<label for="bbox-coords" data-localize="custom_bounding_box">Custom Bounding Box</label>
|
||||
<div class="settings-control">
|
||||
<input type="text" id="bbox-coords" name="bbox-coords" maxlength="55" placeholder="Format: lat,lng,lat,lng">
|
||||
</div>
|
||||
<div class="bbox-input-container">
|
||||
<label for="bbox-coords" data-localize="custom_bounding_box">Custom Bounding Box:</label>
|
||||
<input type="text" id="bbox-coords" name="bbox-coords" maxlength="55" style="width: 280px;" placeholder="Format: lat,lng,lat,lng">
|
||||
</div>
|
||||
|
||||
<!-- Floodfill Timeout Input -->
|
||||
<div class="settings-row">
|
||||
<label for="floodfill-timeout" data-localize="floodfill_timeout">Floodfill Timeout (sec)</label>
|
||||
<div class="settings-control">
|
||||
<input type="number" id="floodfill-timeout" name="floodfill-timeout" min="0" step="1" value="20" placeholder="Seconds">
|
||||
</div>
|
||||
</div>
|
||||
<div class="timeout-input-container">
|
||||
<label for="floodfill-timeout" data-localize="floodfill_timeout">Floodfill Timeout (sec):</label>
|
||||
<input type="number" id="floodfill-timeout" name="floodfill-timeout" min="0" step="1" value="20" style="width: 100px;" placeholder="Seconds">
|
||||
</div><br>
|
||||
|
||||
<!-- Map Theme Selector -->
|
||||
<div class="settings-row">
|
||||
<label for="tile-theme-select" data-localize="map_theme">Map Theme</label>
|
||||
<div class="settings-control">
|
||||
<select id="tile-theme-select" name="tile-theme-select" class="theme-dropdown">
|
||||
<option value="osm">Standard</option>
|
||||
<option value="esri-imagery">Satellite</option>
|
||||
<option value="opentopomap">Topographic</option>
|
||||
<option value="stadia-bright">Smooth Bright</option>
|
||||
<option value="stadia-dark">Smooth Dark</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Language Selector -->
|
||||
<div class="settings-row">
|
||||
<label for="language-select" data-localize="language">Language</label>
|
||||
<div class="settings-control">
|
||||
<select id="language-select" name="language-select" class="language-dropdown">
|
||||
<option value="en">English</option>
|
||||
<option value="de">Deutsch</option>
|
||||
<option value="es">Español</option>
|
||||
<option value="fr-FR">Français</option>
|
||||
<option value="ru">Русский</option>
|
||||
<option value="zh-CN">中文 (简体)</option>
|
||||
<option value="ko">한국어</option>
|
||||
<option value="pl">Polski</option>
|
||||
<option value="lv">Latviešu</option>
|
||||
<option value="sv">Svenska</option>
|
||||
<option value="ar">العربية</option>
|
||||
<option value="fi">Suomi</option>
|
||||
<option value="hu">Magyar</option>
|
||||
<option value="lt">Lietuvių</option>
|
||||
<option value="ua">Українська</option>
|
||||
</select>
|
||||
</div>
|
||||
<!-- Ground Level Input -->
|
||||
<div class="ground-level-input-container">
|
||||
<label for="ground-level" data-localize="ground_level">Ground Level:</label>
|
||||
<input type="number" id="ground-level" name="ground-level" min="-64" max="290" value="-62" style="width: 100px;" placeholder="Ground Level">
|
||||
</div>
|
||||
|
||||
<!-- License and Credits Button -->
|
||||
<div class="settings-row license-button-row">
|
||||
<button type="button" id="license-button" class="license-button" onclick="openLicense()" data-localize="license_and_credits">License and Credits</button>
|
||||
</div>
|
||||
|
||||
<!-- Buy Me a Coffee and Discord -->
|
||||
<div class="settings-row buymeacoffee-row">
|
||||
<a href="https://buymeacoffee.com/louisdev" target="_blank" class="buymeacoffee-link">
|
||||
<img src="./images/buymeacoffee.png" alt="Buy Me a Coffee" class="buymeacoffee-logo">
|
||||
</a>
|
||||
<a href="https://discord.gg/mA2g69Fhxq" target="_blank" class="discord-link">
|
||||
<img src="./images/discord.png" alt="Discord" class="discord-logo">
|
||||
</a>
|
||||
</div>
|
||||
<button type="button" id="license-button" class="license-button" onclick="openLicense()" data-localize="license_and_credits">License and Credits</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
280
src/gui/js/bbox.js → gui-src/js/bbox.js
vendored
@@ -322,7 +322,7 @@ function addLayer(layer, name, title, zIndex, on) {
|
||||
}
|
||||
link.innerHTML = name;
|
||||
link.title = title;
|
||||
link.onclick = function (e) {
|
||||
link.onclick = function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -429,7 +429,7 @@ function formatPoint(point, proj) {
|
||||
formattedBounds = y + ' ' + x;
|
||||
}
|
||||
}
|
||||
return formattedPoint
|
||||
return formattedBounds
|
||||
}
|
||||
|
||||
function validateStringAsBounds(bounds) {
|
||||
@@ -456,122 +456,13 @@ $(document).ready(function () {
|
||||
** on top of your DOM
|
||||
**
|
||||
*/
|
||||
|
||||
// init the projection input box as it is used to format the initial values
|
||||
$('input[type="textarea"]').on('click', function (evt) { this.select() });
|
||||
|
||||
// Have to init the projection input box as it is used to format the initial values
|
||||
$("#projection").val(currentproj);
|
||||
|
||||
// Initialize map
|
||||
map = L.map('map').setView([50.114768, 8.687322], 4);
|
||||
|
||||
// Define available tile themes
|
||||
var tileThemes = {
|
||||
'osm': {
|
||||
url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
||||
maxZoom: 19
|
||||
}
|
||||
},
|
||||
'esri-imagery': {
|
||||
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
|
||||
options: {
|
||||
attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community',
|
||||
maxZoom: 18
|
||||
}
|
||||
},
|
||||
'opentopomap': {
|
||||
url: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
attribution: 'Map data: © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="http://viewfinderpanoramas.org">SRTM</a> | Map style: © <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)',
|
||||
maxZoom: 17
|
||||
}
|
||||
},
|
||||
'stadia-bright': {
|
||||
url: 'https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}.{ext}',
|
||||
options: {
|
||||
minZoom: 0,
|
||||
maxZoom: 19,
|
||||
attribution: '© <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a> © <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a> © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
||||
ext: 'png'
|
||||
}
|
||||
},
|
||||
'stadia-dark': {
|
||||
url: 'https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}.{ext}',
|
||||
options: {
|
||||
minZoom: 0,
|
||||
maxZoom: 19,
|
||||
attribution: '© <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a> © <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a> © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
||||
ext: 'png'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Global variable to store current tile layer
|
||||
var currentTileLayer = null;
|
||||
|
||||
// Function to change tile theme with automatic HTTP fallback
|
||||
function changeTileTheme(themeKey) {
|
||||
// Remove current tile layer if it exists
|
||||
if (currentTileLayer) {
|
||||
map.removeLayer(currentTileLayer);
|
||||
}
|
||||
|
||||
// Get the theme configuration
|
||||
var theme = tileThemes[themeKey];
|
||||
if (theme) {
|
||||
// Create and add new tile layer
|
||||
currentTileLayer = L.tileLayer(theme.url, theme.options);
|
||||
|
||||
// Add automatic HTTP fallback for HTTPS failures
|
||||
var failureCount = 0;
|
||||
currentTileLayer.on('tileerror', function(error) {
|
||||
failureCount++;
|
||||
|
||||
// After a few failures, try HTTP fallback
|
||||
if (failureCount >= 3 && !this._httpFallbackAttempted && theme.url.startsWith('https://')) {
|
||||
console.log('HTTPS tile loading failed, attempting HTTP fallback for', themeKey);
|
||||
this._httpFallbackAttempted = true;
|
||||
|
||||
// Create HTTP version of the URL
|
||||
var httpUrl = theme.url.replace('https://', 'http://');
|
||||
|
||||
// Remove the failed HTTPS layer
|
||||
map.removeLayer(this);
|
||||
|
||||
// Create new layer with HTTP URL
|
||||
var httpLayer = L.tileLayer(httpUrl, theme.options);
|
||||
httpLayer._httpFallbackAttempted = true;
|
||||
httpLayer.addTo(map);
|
||||
currentTileLayer = httpLayer;
|
||||
}
|
||||
});
|
||||
|
||||
currentTileLayer.addTo(map);
|
||||
|
||||
// Save preference to localStorage
|
||||
localStorage.setItem('selectedTileTheme', themeKey);
|
||||
}
|
||||
}
|
||||
|
||||
// Load saved theme or default to OSM
|
||||
var savedTheme = localStorage.getItem('selectedTileTheme') || 'osm';
|
||||
changeTileTheme(savedTheme);
|
||||
|
||||
// Listen for theme changes from parent window (settings modal)
|
||||
window.addEventListener('message', function(event) {
|
||||
if (event.data && event.data.type === 'changeTileTheme') {
|
||||
changeTileTheme(event.data.theme);
|
||||
}
|
||||
});
|
||||
|
||||
// Set the dropdown value in parent window if it exists
|
||||
if (window.parent && window.parent.document) {
|
||||
var dropdown = window.parent.document.getElementById('tile-theme-select');
|
||||
if (dropdown) {
|
||||
dropdown.value = savedTheme;
|
||||
}
|
||||
}
|
||||
L.mapbox.accessToken = 'pk.eyJ1IjoiY3Vnb3MiLCJhIjoiY2p4Nm43MzA3MDFmZDQwcGxsMjB4Z3hnNiJ9.SQbnMASwdqZe6G4n6OMvVw';
|
||||
map = L.mapbox.map('map').setView([50.114768, 8.687322], 4).addLayer(L.mapbox.styleLayer('mapbox://styles/mapbox/streets-v11'));
|
||||
|
||||
rsidebar = L.control.sidebar('rsidebar', {
|
||||
position: 'right',
|
||||
@@ -605,53 +496,24 @@ $(document).ready(function () {
|
||||
crosshair = new L.marker(map.getCenter(), { icon: crosshairIcon, clickable: false });
|
||||
crosshair.addTo(map);
|
||||
|
||||
// Override default tooltips
|
||||
L.drawLocal = L.drawLocal || {};
|
||||
L.drawLocal.draw = L.drawLocal.draw || {};
|
||||
L.drawLocal.draw.toolbar = L.drawLocal.draw.toolbar || {};
|
||||
L.drawLocal.draw.toolbar.buttons = L.drawLocal.draw.toolbar.buttons || {};
|
||||
L.drawLocal.draw.toolbar.buttons.rectangle = 'Choose area';
|
||||
L.drawLocal.draw.toolbar.buttons.marker = 'Set spawnpoint';
|
||||
|
||||
// Initialize the FeatureGroup to store editable layers
|
||||
drawnItems = new L.FeatureGroup();
|
||||
map.addLayer(drawnItems);
|
||||
|
||||
// Custom icon for drawn markers
|
||||
var customMarkerIcon = L.icon({
|
||||
iconUrl: 'images/marker-icon.png',
|
||||
iconSize: [20, 20],
|
||||
iconAnchor: [10, 10],
|
||||
popupAnchor: [0, -10]
|
||||
});
|
||||
|
||||
// Initialize the draw control and pass it the FeatureGroup of editable layers
|
||||
drawControl = new L.Control.Draw({
|
||||
edit: {
|
||||
featureGroup: drawnItems
|
||||
},
|
||||
draw: {
|
||||
rectangle: {
|
||||
shapeOptions: {
|
||||
color: '#fe57a1',
|
||||
opacity: 0.6,
|
||||
weight: 3,
|
||||
fillColor: '#fe57a1',
|
||||
fillOpacity: 0.1,
|
||||
dashArray: '10, 10',
|
||||
lineCap: 'round',
|
||||
lineJoin: 'round'
|
||||
},
|
||||
repeatMode: false
|
||||
},
|
||||
polyline: false,
|
||||
polygon: false,
|
||||
circle: false,
|
||||
marker: {
|
||||
icon: customMarkerIcon
|
||||
}
|
||||
marker: false
|
||||
}
|
||||
});
|
||||
map.addControl(drawControl);
|
||||
|
||||
/*
|
||||
**
|
||||
** create bounds layer
|
||||
@@ -661,22 +523,17 @@ $(document).ready(function () {
|
||||
**
|
||||
*/
|
||||
startBounds = new L.LatLngBounds([0.0, 0.0], [0.0, 0.0]);
|
||||
var bounds = new L.Rectangle(startBounds, {
|
||||
color: '#3778d4',
|
||||
opacity: 1.0,
|
||||
weight: 3,
|
||||
fill: '#3778d4',
|
||||
lineCap: 'round',
|
||||
lineJoin: 'round'
|
||||
});
|
||||
|
||||
bounds.on('bounds-set', function (e) {
|
||||
// move it to the end of the parent if renderer exists
|
||||
if (e.target._renderer && e.target._renderer._container) {
|
||||
var parent = e.target._renderer._container.parentElement;
|
||||
$(parent).append(e.target._renderer._container);
|
||||
var bounds = new L.Rectangle(startBounds,
|
||||
{
|
||||
fill: false,
|
||||
opacity: 1.0,
|
||||
color: '#000'
|
||||
}
|
||||
|
||||
);
|
||||
bounds.on('bounds-set', function (e) {
|
||||
// move it to the end of the parent
|
||||
var parent = e.target._renderer._container.parentElement;
|
||||
$(parent).append(e.target._renderer._container);
|
||||
// Set the hash
|
||||
var southwest = this.getBounds().getSouthWest();
|
||||
var northeast = this.getBounds().getNorthEast();
|
||||
@@ -686,55 +543,13 @@ $(document).ready(function () {
|
||||
var ymax = northeast.lat.toFixed(6);
|
||||
location.hash = ymin + ',' + xmin + ',' + ymax + ',' + xmax;
|
||||
});
|
||||
map.addLayer(bounds);
|
||||
|
||||
map.addLayer(bounds)
|
||||
map.on('draw:created', function (e) {
|
||||
// If it's a marker, make sure we only have one
|
||||
if (e.layerType === 'marker') {
|
||||
// Remove any existing markers
|
||||
drawnItems.eachLayer(function(layer) {
|
||||
if (layer instanceof L.Marker) {
|
||||
drawnItems.removeLayer(layer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Check if it's a rectangle and set proper styles before adding it to the layer
|
||||
if (e.layerType === 'rectangle') {
|
||||
e.layer.setStyle({
|
||||
color: '#3778d4',
|
||||
opacity: 1.0,
|
||||
weight: 3,
|
||||
fill: '#3778d4',
|
||||
lineCap: 'round',
|
||||
lineJoin: 'round'
|
||||
});
|
||||
}
|
||||
|
||||
drawnItems.addLayer(e.layer);
|
||||
|
||||
// Only update the bounds based on non-marker layers
|
||||
if (e.layerType !== 'marker') {
|
||||
// Calculate bounds only from non-marker layers
|
||||
const nonMarkerBounds = new L.LatLngBounds();
|
||||
let hasNonMarkerLayers = false;
|
||||
|
||||
drawnItems.eachLayer(function(layer) {
|
||||
if (!(layer instanceof L.Marker)) {
|
||||
hasNonMarkerLayers = true;
|
||||
nonMarkerBounds.extend(layer.getBounds());
|
||||
}
|
||||
});
|
||||
|
||||
// Only update bounds if there are non-marker layers
|
||||
if (hasNonMarkerLayers) {
|
||||
bounds.setBounds(nonMarkerBounds);
|
||||
$('#boxbounds').text(formatBounds(bounds.getBounds(), '4326'));
|
||||
$('#boxboundsmerc').text(formatBounds(bounds.getBounds(), currentproj));
|
||||
notifyBboxUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
bounds.setBounds(drawnItems.getBounds())
|
||||
$('#boxbounds').text(formatBounds(bounds.getBounds(), '4326'));
|
||||
$('#boxboundsmerc').text(formatBounds(bounds.getBounds(), currentproj));
|
||||
notifyBboxUpdate();
|
||||
if (!e.geojson &&
|
||||
!((drawnItems.getLayers().length == 1) && (drawnItems.getLayers()[0] instanceof L.Marker))) {
|
||||
map.fitBounds(bounds.getBounds());
|
||||
@@ -768,22 +583,7 @@ $(document).ready(function () {
|
||||
});
|
||||
|
||||
map.on('draw:edited', function (e) {
|
||||
// Calculate bounds only from non-marker layers
|
||||
const nonMarkerBounds = new L.LatLngBounds();
|
||||
let hasNonMarkerLayers = false;
|
||||
|
||||
drawnItems.eachLayer(function(layer) {
|
||||
if (!(layer instanceof L.Marker)) {
|
||||
hasNonMarkerLayers = true;
|
||||
nonMarkerBounds.extend(layer.getBounds());
|
||||
}
|
||||
});
|
||||
|
||||
// Only update bounds if there are non-marker layers
|
||||
if (hasNonMarkerLayers) {
|
||||
bounds.setBounds(nonMarkerBounds);
|
||||
}
|
||||
|
||||
bounds.setBounds(drawnItems.getBounds())
|
||||
$('#boxbounds').text(formatBounds(bounds.getBounds(), '4326'));
|
||||
$('#boxboundsmerc').text(formatBounds(bounds.getBounds(), currentproj));
|
||||
notifyBboxUpdate();
|
||||
@@ -829,14 +629,7 @@ $(document).ready(function () {
|
||||
var splitBounds = initialBBox.split(',');
|
||||
startBounds = new L.LatLngBounds([splitBounds[0], splitBounds[1]],
|
||||
[splitBounds[2], splitBounds[3]]);
|
||||
var lyr = new L.Rectangle(startBounds, {
|
||||
color: '#3778d4',
|
||||
opacity: 1.0,
|
||||
weight: 3,
|
||||
fill: '#3778d4',
|
||||
lineCap: 'round',
|
||||
lineJoin: 'round'
|
||||
});
|
||||
var lyr = new L.Rectangle(startBounds);
|
||||
var evt = {
|
||||
layer: lyr,
|
||||
layerType: "polygon",
|
||||
@@ -862,24 +655,3 @@ function notifyBboxUpdate() {
|
||||
const bboxText = document.getElementById('boxbounds').textContent;
|
||||
window.parent.postMessage({ bboxText: bboxText }, '*');
|
||||
}
|
||||
|
||||
// Expose marker coordinates to the parent window
|
||||
function getSpawnPointCoords() {
|
||||
// Check if there are any markers in drawn items
|
||||
const markers = [];
|
||||
drawnItems.eachLayer(function(layer) {
|
||||
if (layer instanceof L.Marker) {
|
||||
const latLng = layer.getLatLng();
|
||||
markers.push({
|
||||
lat: latLng.lat,
|
||||
lng: latLng.lng
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Return the first marker found or null if none exists
|
||||
return markers.length > 0 ? markers[0] : null;
|
||||
}
|
||||
|
||||
// Expose the function to the parent window
|
||||
window.getSpawnPointCoords = getSpawnPointCoords;
|
||||
36
src/gui/js/license.js → gui-src/js/license.js
vendored
@@ -1,28 +1,18 @@
|
||||
export const licenseText = `
|
||||
<b>Made with ♥️ in Munich by Louis Erbkamm</b>
|
||||
<p><b>Contributors:</b></p>
|
||||
louis-e (Louis Erbkamm)<br>
|
||||
scd31<br>
|
||||
amir16yp<br>
|
||||
vfosnar<br>
|
||||
TheComputerGuy96<br>
|
||||
zer0-dev<br>
|
||||
RedAuburn<br>
|
||||
daniil2327<br>
|
||||
benjamin051000<br>
|
||||
|
||||
<p>For a full list of contributors, please refer to the <a href="https://github.com/louis-e/arnis/graphs/contributors" style="color: inherit;" target="_blank">Github contributors page</a>. Logo made by nxfx21.
|
||||
<p>For a full list of contributors, please refer to the <a href="https://github.com/louis-e/arnis" style="color: inherit;" target="_blank">Github page</a>. Logo made by nxfx21.</p>
|
||||
|
||||
<p style="color: #ff8686;"><b>Download Arnis only from the official source:</b> <a href="https://arnismc.com" style="color: inherit;" target="_blank">https://arnismc.com</a> or <a href="https://github.com/louis-e/arnis" style="color: inherit;" target="_blank">https://github.com/louis-e/arnis/</a>. Every other website providing a download and claiming to be affiliated with the project is unofficial and may be malicious.</p>
|
||||
|
||||
<p><b>Third-Party Map Data and Tile Services:</b></p>
|
||||
<p>This application uses map tiles from multiple providers, each with their own licensing requirements:</p>
|
||||
|
||||
<b>OpenStreetMap:</b><br> © <a href="https://www.openstreetmap.org/copyright" style="color: inherit;" target="_blank">OpenStreetMap</a> contributors
|
||||
<br><br>
|
||||
|
||||
<b>Esri:</b><br> Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community
|
||||
<br><br>
|
||||
|
||||
<b>OpenTopoMap:</b><br> Map style: © <a href="https://opentopomap.org" style="color: inherit;" target="_blank">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/" style="color: inherit;" target="_blank">CC-BY-SA</a>), Map data: © OpenStreetMap contributors, <a href="http://viewfinderpanoramas.org" style="color: inherit;" target="_blank">SRTM</a>
|
||||
<br><br>
|
||||
|
||||
<b>Stadia Maps:</b><br> © <a href="https://www.stadiamaps.com/" style="color: inherit;" target="_blank">Stadia Maps</a> © <a href="https://openmaptiles.org/" style="color: inherit;" target="_blank">OpenMapTiles</a> © OpenStreetMap contributors
|
||||
<p>Users of this software must comply with the respective licensing terms of these map data providers when using the application.</p>
|
||||
|
||||
<b>AWS Terrain Tiles:</b><br>
|
||||
Elevation data derived from the <a href="https://registry.opendata.aws/terrain-tiles/" style="color: inherit;" target="_blank">AWS Terrain Tiles</a> dataset.
|
||||
<br><br>
|
||||
<p style="color: #ff7070;"><b>Download Arnis only from the official source:</b> <a href="https://github.com/louis-e/arnis" style="color: inherit;" target="_blank">https://github.com/louis-e/arnis/</a>. Every other website providing a download and claiming to be affiliated with the project is unofficial and may be malicious.</p>
|
||||
|
||||
<p><b>License:</b></p>
|
||||
<pre style="white-space: pre-wrap; font-family: inherit;">
|
||||
@@ -36,7 +26,7 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
"Licensor" shall mean the copyright owner or entity authorized bythe copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and allother entities that control, are controlled by, or are under commoncontrol with that entity. For the purposes of this definition,"control" means (i) the power, direct or indirect, to cause thedirection or management of such entity, whether by contract orotherwise, or (ii) ownership of fifty percent (50%) or more of theoutstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
309
src/gui/js/main.js → gui-src/js/main.js
vendored
@@ -1,11 +1,10 @@
|
||||
import { licenseText } from './license.js';
|
||||
import { fetchLanguage, invalidJSON } from './language.js';
|
||||
|
||||
let invoke;
|
||||
if (window.__TAURI__) {
|
||||
invoke = window.__TAURI__.core.invoke;
|
||||
} else {
|
||||
function dummyFunc() { }
|
||||
function dummyFunc() {}
|
||||
window.__TAURI__ = { event: { listen: dummyFunc } };
|
||||
invoke = dummyFunc;
|
||||
}
|
||||
@@ -27,10 +26,15 @@ window.addEventListener("DOMContentLoaded", async () => {
|
||||
await checkForUpdates();
|
||||
});
|
||||
|
||||
// Expose language functions to window for use by language-selector.js
|
||||
window.fetchLanguage = fetchLanguage;
|
||||
window.applyLocalization = applyLocalization;
|
||||
window.initFooter = initFooter;
|
||||
/**
|
||||
* Checks if a JSON response is invalid or falls back to HTML
|
||||
* @param {Response} response - The fetch response object
|
||||
* @returns {boolean} True if the response is invalid JSON
|
||||
*/
|
||||
function invalidJSON(response) {
|
||||
// Workaround for Tauri always falling back to index.html for asset loading
|
||||
return !response.ok || response.headers.get("Content-Type") === "text/html";
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches and returns localization data based on user's language
|
||||
@@ -38,17 +42,21 @@ window.initFooter = initFooter;
|
||||
* @returns {Promise<Object>} The localization JSON object
|
||||
*/
|
||||
async function getLocalization() {
|
||||
// Check if user has a saved language preference
|
||||
const savedLanguage = localStorage.getItem('arnis-language');
|
||||
const lang = navigator.language;
|
||||
let response = await fetch(`./locales/${lang}.json`);
|
||||
|
||||
// If there's a saved preference, use it
|
||||
if (savedLanguage) {
|
||||
return await fetchLanguage(savedLanguage);
|
||||
// Try with only first part of language code
|
||||
if (invalidJSON(response)) {
|
||||
response = await fetch(`./locales/${lang.split('-')[0]}.json`);
|
||||
|
||||
// Fallback to default English localization
|
||||
if (invalidJSON(response)) {
|
||||
response = await fetch(DEFAULT_LOCALE_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise use the browser's language
|
||||
const lang = navigator.language;
|
||||
return await fetchLanguage(lang);
|
||||
const localization = await response.json();
|
||||
return localization;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,7 +68,7 @@ async function getLocalization() {
|
||||
async function localizeElement(json, elementObject, localizedStringKey) {
|
||||
const element =
|
||||
(!elementObject.element || elementObject.element === "")
|
||||
? document.querySelector(elementObject.selector) : elementObject.element;
|
||||
? document.querySelector(elementObject.selector) : elementObject.element;
|
||||
const attribute = localizedStringKey.startsWith("placeholder_") ? "placeholder" : "textContent";
|
||||
|
||||
if (element) {
|
||||
@@ -68,7 +76,8 @@ async function localizeElement(json, elementObject, localizedStringKey) {
|
||||
element[attribute] = json[localizedStringKey];
|
||||
} else {
|
||||
// Fallback to default (English) string
|
||||
const defaultJson = await fetchLanguage('en');
|
||||
const response = await fetch(DEFAULT_LOCALE_PATH);
|
||||
const defaultJson = await response.json();
|
||||
element[attribute] = defaultJson[localizedStringKey];
|
||||
}
|
||||
}
|
||||
@@ -90,18 +99,7 @@ async function applyLocalization(localization) {
|
||||
"label[data-localize='world_scale']": "world_scale",
|
||||
"label[data-localize='custom_bounding_box']": "custom_bounding_box",
|
||||
"label[data-localize='floodfill_timeout']": "floodfill_timeout",
|
||||
// DEPRECATED: Ground level localization removed
|
||||
// "label[data-localize='ground_level']": "ground_level",
|
||||
"label[data-localize='language']": "language",
|
||||
"label[data-localize='generation_mode']": "generation_mode",
|
||||
"option[data-localize='mode_geo_terrain']": "mode_geo_terrain",
|
||||
"option[data-localize='mode_geo_only']": "mode_geo_only",
|
||||
"option[data-localize='mode_terrain_only']": "mode_terrain_only",
|
||||
"label[data-localize='terrain']": "terrain",
|
||||
"label[data-localize='interior']": "interior",
|
||||
"label[data-localize='roof']": "roof",
|
||||
"label[data-localize='fillground']": "fillground",
|
||||
"label[data-localize='map_theme']": "map_theme",
|
||||
"label[data-localize='ground_level']": "ground_level",
|
||||
".footer-link": "footer_text",
|
||||
"button[data-localize='license_and_credits']": "license_and_credits",
|
||||
"h2[data-localize='license_and_credits']": "license_and_credits",
|
||||
@@ -109,8 +107,7 @@ async function applyLocalization(localization) {
|
||||
// Placeholder strings
|
||||
"input[id='bbox-coords']": "placeholder_bbox",
|
||||
"input[id='floodfill-timeout']": "placeholder_floodfill",
|
||||
// DEPRECATED: Ground level placeholder removed
|
||||
// "input[id='ground-level']": "placeholder_ground"
|
||||
"input[id='ground-level']": "placeholder_ground"
|
||||
};
|
||||
|
||||
for (const selector in localizationElements) {
|
||||
@@ -134,18 +131,10 @@ async function initFooter() {
|
||||
|
||||
const footerElement = document.querySelector(".footer-link");
|
||||
if (footerElement) {
|
||||
// Get the original text from localization if available, or use the current text
|
||||
let footerText = footerElement.textContent;
|
||||
|
||||
// Check if the text is from localization and contains placeholders
|
||||
if (window.localization && window.localization.footer_text) {
|
||||
footerText = window.localization.footer_text;
|
||||
}
|
||||
|
||||
// Replace placeholders with actual values
|
||||
footerElement.textContent = footerText
|
||||
.replace("{year}", currentYear)
|
||||
.replace("{version}", version);
|
||||
footerElement.textContent =
|
||||
footerElement.textContent
|
||||
.replace("{year}", currentYear)
|
||||
.replace("{version}", version);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +209,7 @@ function initSettings() {
|
||||
const settingsModal = document.getElementById("settings-modal");
|
||||
const slider = document.getElementById("scale-value-slider");
|
||||
const sliderValue = document.getElementById("slider-value");
|
||||
|
||||
|
||||
// Open settings modal
|
||||
function openSettings() {
|
||||
settingsModal.style.display = "flex";
|
||||
@@ -232,7 +221,7 @@ function initSettings() {
|
||||
function closeSettings() {
|
||||
settingsModal.style.display = "none";
|
||||
}
|
||||
|
||||
|
||||
window.openSettings = openSettings;
|
||||
window.closeSettings = closeSettings;
|
||||
|
||||
@@ -241,70 +230,6 @@ function initSettings() {
|
||||
sliderValue.textContent = parseFloat(slider.value).toFixed(2);
|
||||
});
|
||||
|
||||
// Language selector
|
||||
const languageSelect = document.getElementById("language-select");
|
||||
const availableOptions = Array.from(languageSelect.options).map(opt => opt.value);
|
||||
|
||||
// Check for saved language preference first
|
||||
const savedLanguage = localStorage.getItem('arnis-language');
|
||||
let languageToSet = 'en'; // Default to English
|
||||
|
||||
if (savedLanguage && availableOptions.includes(savedLanguage)) {
|
||||
// Use saved language if it exists and is available
|
||||
languageToSet = savedLanguage;
|
||||
} else {
|
||||
// Otherwise use browser language
|
||||
const currentLang = navigator.language;
|
||||
|
||||
// Try to match the exact language code first
|
||||
if (availableOptions.includes(currentLang)) {
|
||||
languageToSet = currentLang;
|
||||
}
|
||||
// Try to match just the base language code
|
||||
else if (availableOptions.includes(currentLang.split('-')[0])) {
|
||||
languageToSet = currentLang.split('-')[0];
|
||||
}
|
||||
// languageToSet remains 'en' as default
|
||||
}
|
||||
|
||||
languageSelect.value = languageToSet;
|
||||
|
||||
// Handle language change
|
||||
languageSelect.addEventListener("change", async () => {
|
||||
const selectedLanguage = languageSelect.value;
|
||||
|
||||
// Store the selected language in localStorage for persistence
|
||||
localStorage.setItem('arnis-language', selectedLanguage);
|
||||
|
||||
// Reload localization with the new language
|
||||
const localization = await fetchLanguage(selectedLanguage);
|
||||
await applyLocalization(localization);
|
||||
});
|
||||
|
||||
// Tile theme selector
|
||||
const tileThemeSelect = document.getElementById("tile-theme-select");
|
||||
|
||||
// Load saved tile theme preference
|
||||
const savedTileTheme = localStorage.getItem('selectedTileTheme') || 'osm';
|
||||
tileThemeSelect.value = savedTileTheme;
|
||||
|
||||
// Handle tile theme change
|
||||
tileThemeSelect.addEventListener("change", () => {
|
||||
const selectedTheme = tileThemeSelect.value;
|
||||
|
||||
// Store the selected theme in localStorage for persistence
|
||||
localStorage.setItem('selectedTileTheme', selectedTheme);
|
||||
|
||||
// Send message to map iframe to change tile theme
|
||||
const mapIframe = document.querySelector('iframe[src="maps.html"]');
|
||||
if (mapIframe && mapIframe.contentWindow) {
|
||||
mapIframe.contentWindow.postMessage({
|
||||
type: 'changeTileTheme',
|
||||
theme: selectedTheme
|
||||
}, '*');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/// License and Credits
|
||||
function openLicense() {
|
||||
@@ -332,7 +257,7 @@ function initSettings() {
|
||||
function initWorldPicker() {
|
||||
// World Picker
|
||||
const worldPickerModal = document.getElementById("world-modal");
|
||||
|
||||
|
||||
// Open world picker modal
|
||||
function openWorldPicker() {
|
||||
worldPickerModal.style.display = "flex";
|
||||
@@ -344,7 +269,7 @@ function initWorldPicker() {
|
||||
function closeWorldPicker() {
|
||||
worldPickerModal.style.display = "none";
|
||||
}
|
||||
|
||||
|
||||
window.openWorldPicker = openWorldPicker;
|
||||
window.closeWorldPicker = closeWorldPicker;
|
||||
}
|
||||
@@ -359,81 +284,58 @@ function handleBboxInput() {
|
||||
const bboxInfo = document.getElementById("bbox-info");
|
||||
|
||||
inputBox.addEventListener("input", function () {
|
||||
const input = inputBox.value.trim();
|
||||
const input = inputBox.value.trim();
|
||||
|
||||
if (input === "") {
|
||||
// Empty input - revert to map selection if available
|
||||
customBBoxValid = false;
|
||||
selectedBBox = mapSelectedBBox;
|
||||
|
||||
// Clear the info text only if no map selection exists
|
||||
if (!mapSelectedBBox) {
|
||||
bboxInfo.textContent = "";
|
||||
bboxInfo.style.color = "";
|
||||
} else {
|
||||
// Restore map selection display
|
||||
displayBboxInfoText(mapSelectedBBox);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Regular expression to validate bbox input (supports both comma and space-separated formats)
|
||||
const bboxPattern = /^(-?\d+(\.\d+)?)[,\s](-?\d+(\.\d+)?)[,\s](-?\d+(\.\d+)?)[,\s](-?\d+(\.\d+)?)$/;
|
||||
|
||||
if (bboxPattern.test(input)) {
|
||||
const matches = input.match(bboxPattern);
|
||||
|
||||
// Extract coordinates (Lat / Lng order expected)
|
||||
const lat1 = parseFloat(matches[1]);
|
||||
const lng1 = parseFloat(matches[3]);
|
||||
const lat2 = parseFloat(matches[5]);
|
||||
const lng2 = parseFloat(matches[7]);
|
||||
|
||||
// Validate latitude and longitude ranges in the expected Lat / Lng order
|
||||
if (
|
||||
lat1 >= -90 && lat1 <= 90 &&
|
||||
lng1 >= -180 && lng1 <= 180 &&
|
||||
lat2 >= -90 && lat2 <= 90 &&
|
||||
lng2 >= -180 && lng2 <= 180
|
||||
) {
|
||||
// Input is valid; trigger the event with consistent comma-separated format
|
||||
const bboxText = `${lat1},${lng1},${lat2},${lng2}`;
|
||||
window.dispatchEvent(new MessageEvent('message', { data: { bboxText } }));
|
||||
|
||||
// Show custom bbox on the map
|
||||
let map_container = document.querySelector('.map-container');
|
||||
map_container.setAttribute('src', `maps.html#${lat1},${lng1},${lat2},${lng2}`);
|
||||
map_container.contentWindow.location.reload();
|
||||
|
||||
// Update the info text and mark custom input as valid
|
||||
customBBoxValid = true;
|
||||
selectedBBox = bboxText.replace(/,/g, ' '); // Convert to space format for consistency
|
||||
localizeElement(window.localization, { element: bboxInfo }, "custom_selection_confirmed");
|
||||
bboxInfo.style.color = "#7bd864";
|
||||
} else {
|
||||
// Valid numbers but invalid order or range
|
||||
customBBoxValid = false;
|
||||
// Don't clear selectedBBox - keep map selection if available
|
||||
if (!mapSelectedBBox) {
|
||||
if (input === "") {
|
||||
bboxInfo.textContent = "";
|
||||
bboxInfo.style.color = "";
|
||||
selectedBBox = "";
|
||||
} else {
|
||||
selectedBBox = mapSelectedBBox;
|
||||
}
|
||||
localizeElement(window.localization, { element: bboxInfo }, "error_coordinates_out_of_range");
|
||||
bboxInfo.style.color = "#fecc44";
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Input doesn't match the required format
|
||||
customBBoxValid = false;
|
||||
// Don't clear selectedBBox - keep map selection if available
|
||||
if (!mapSelectedBBox) {
|
||||
selectedBBox = "";
|
||||
|
||||
// Regular expression to validate bbox input (supports both comma and space-separated formats)
|
||||
const bboxPattern = /^(-?\d+(\.\d+)?)[,\s](-?\d+(\.\d+)?)[,\s](-?\d+(\.\d+)?)[,\s](-?\d+(\.\d+)?)$/;
|
||||
|
||||
if (bboxPattern.test(input)) {
|
||||
const matches = input.match(bboxPattern);
|
||||
|
||||
// Extract coordinates (Lat / Lng order expected)
|
||||
const lat1 = parseFloat(matches[1]);
|
||||
const lng1 = parseFloat(matches[3]);
|
||||
const lat2 = parseFloat(matches[5]);
|
||||
const lng2 = parseFloat(matches[7]);
|
||||
|
||||
// Validate latitude and longitude ranges in the expected Lat / Lng order
|
||||
if (
|
||||
lat1 >= -90 && lat1 <= 90 &&
|
||||
lng1 >= -180 && lng1 <= 180 &&
|
||||
lat2 >= -90 && lat2 <= 90 &&
|
||||
lng2 >= -180 && lng2 <= 180
|
||||
) {
|
||||
// Input is valid; trigger the event with consistent comma-separated format
|
||||
const bboxText = `${lat1},${lng1},${lat2},${lng2}`;
|
||||
window.dispatchEvent(new MessageEvent('message', { data: { bboxText } }));
|
||||
|
||||
// Show custom bbox on the map
|
||||
let map_container = document.querySelector('.map-container');
|
||||
map_container.setAttribute('src', `maps.html#${lat1},${lng1},${lat2},${lng2}`);
|
||||
map_container.contentWindow.location.reload();
|
||||
|
||||
// Update the info text
|
||||
localizeElement(window.localization, { element: bboxInfo }, "custom_selection_confirmed");
|
||||
bboxInfo.style.color = "#7bd864";
|
||||
} else {
|
||||
// Valid numbers but invalid order or range
|
||||
localizeElement(window.localization, { element: bboxInfo }, "error_coordinates_out_of_range");
|
||||
bboxInfo.style.color = "#fecc44";
|
||||
selectedBBox = "";
|
||||
}
|
||||
} else {
|
||||
selectedBBox = mapSelectedBBox;
|
||||
// Input doesn't match the required format
|
||||
localizeElement(window.localization, { element: bboxInfo }, "invalid_format");
|
||||
bboxInfo.style.color = "#fecc44";
|
||||
selectedBBox = "";
|
||||
}
|
||||
localizeElement(window.localization, { element: bboxInfo }, "invalid_format");
|
||||
bboxInfo.style.color = "#fecc44";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -478,8 +380,6 @@ function normalizeLongitude(lon) {
|
||||
const threshold1 = 30000000.00;
|
||||
const threshold2 = 45000000.00;
|
||||
let selectedBBox = "";
|
||||
let mapSelectedBBox = ""; // Tracks bbox from map selection
|
||||
let customBBoxValid = false; // Tracks if custom input is valid
|
||||
|
||||
// Function to handle incoming bbox data
|
||||
function displayBboxInfoText(bboxText) {
|
||||
@@ -488,21 +388,14 @@ function displayBboxInfoText(bboxText) {
|
||||
// Normalize longitudes
|
||||
lat1 = parseFloat(normalizeLongitude(lat1).toFixed(6));
|
||||
lat2 = parseFloat(normalizeLongitude(lat2).toFixed(6));
|
||||
mapSelectedBBox = `${lng1} ${lat1} ${lng2} ${lat2}`;
|
||||
|
||||
// Map selection always takes priority - clear custom input and update selectedBBox
|
||||
selectedBBox = mapSelectedBBox;
|
||||
customBBoxValid = false;
|
||||
selectedBBox = `${lng1} ${lat1} ${lng2} ${lat2}`;
|
||||
|
||||
const bboxInfo = document.getElementById("bbox-info");
|
||||
|
||||
// Reset the info text if the bbox is 0,0,0,0
|
||||
if (lng1 === 0 && lat1 === 0 && lng2 === 0 && lat2 === 0) {
|
||||
bboxInfo.textContent = "";
|
||||
mapSelectedBBox = "";
|
||||
if (!customBBoxValid) {
|
||||
selectedBBox = "";
|
||||
}
|
||||
selectedBBox = "";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -526,7 +419,7 @@ let isNewWorld = false;
|
||||
|
||||
async function selectWorld(generate_new_world) {
|
||||
try {
|
||||
const worldName = await invoke('gui_select_world', { generateNew: generate_new_world });
|
||||
const worldName = await invoke('gui_select_world', { generateNew: generate_new_world } );
|
||||
if (worldName) {
|
||||
worldPath = worldName;
|
||||
isNewWorld = generate_new_world;
|
||||
@@ -587,37 +480,17 @@ async function startGeneration() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the map iframe reference
|
||||
const mapFrame = document.querySelector('.map-container');
|
||||
// Get spawn point coordinates if marker exists
|
||||
let spawnPoint = null;
|
||||
if (mapFrame && mapFrame.contentWindow && mapFrame.contentWindow.getSpawnPointCoords) {
|
||||
const coords = mapFrame.contentWindow.getSpawnPointCoords();
|
||||
// Convert object format to tuple format if coordinates exist
|
||||
if (coords) {
|
||||
spawnPoint = [coords.lat, coords.lng];
|
||||
}
|
||||
}
|
||||
|
||||
// Get generation mode from dropdown
|
||||
var generationMode = document.getElementById("generation-mode-select").value;
|
||||
var terrain = (generationMode === "geo-terrain" || generationMode === "terrain-only");
|
||||
var skipOsmObjects = (generationMode === "terrain-only");
|
||||
|
||||
var interior = document.getElementById("interior-toggle").checked;
|
||||
var roof = document.getElementById("roof-toggle").checked;
|
||||
var terrain = document.getElementById("terrain-toggle").checked;
|
||||
var fill_ground = document.getElementById("fillground-toggle").checked;
|
||||
var scale = parseFloat(document.getElementById("scale-value-slider").value);
|
||||
var floodfill_timeout = parseInt(document.getElementById("floodfill-timeout").value, 10);
|
||||
// var ground_level = parseInt(document.getElementById("ground-level").value, 10);
|
||||
// DEPRECATED: Ground level input removed from UI
|
||||
var ground_level = -62;
|
||||
var ground_level = parseInt(document.getElementById("ground-level").value, 10);
|
||||
|
||||
// Validate floodfill_timeout and ground_level
|
||||
floodfill_timeout = isNaN(floodfill_timeout) || floodfill_timeout < 0 ? 20 : floodfill_timeout;
|
||||
ground_level = isNaN(ground_level) || ground_level < -62 ? 20 : ground_level;
|
||||
|
||||
// Pass the selected options to the Rust backend
|
||||
// Pass the bounding box and selected world to the Rust backend
|
||||
await invoke("gui_start_generation", {
|
||||
bboxText: selectedBBox,
|
||||
selectedWorld: worldPath,
|
||||
@@ -625,12 +498,8 @@ async function startGeneration() {
|
||||
groundLevel: ground_level,
|
||||
floodfillTimeout: floodfill_timeout,
|
||||
terrainEnabled: terrain,
|
||||
skipOsmObjects: skipOsmObjects,
|
||||
interiorEnabled: interior,
|
||||
roofEnabled: roof,
|
||||
fillgroundEnabled: fill_ground,
|
||||
isNewWorld: isNewWorld,
|
||||
spawnPoint: spawnPoint
|
||||
isNewWorld: isNewWorld
|
||||
});
|
||||
|
||||
console.log("Generation process started.");
|
||||
9180
gui-src/js/maps/leaflet-src.js
vendored
Normal file
2766
gui-src/js/maps/leaflet.draw-src.js
vendored
Normal file
3
gui-src/js/maps/mapbox.standalone.js
vendored
Normal file
66
gui-src/js/maps/mapbox.v3.2.0.js
vendored
Normal file
3
gui-src/js/maps/proj4.js
vendored
Normal file
158
gui-src/js/maps/test.runner.js
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
(function( definition ) { // execute immeidately
|
||||
|
||||
if ( typeof module !== 'undefined' &&
|
||||
typeof module.exports !== 'undefined' ) {
|
||||
module.exports = definition();
|
||||
}
|
||||
else if ( typeof window === "object" ) {
|
||||
// example run syntax: BBOX_T( { 'url' : '/js/maps/testdata.js' } );
|
||||
window.BBOX_T = definition();
|
||||
}
|
||||
|
||||
|
||||
})( function() {
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
**
|
||||
** constructor
|
||||
**
|
||||
*/
|
||||
var TestRunner = function( options ) {
|
||||
options || ( options = {} );
|
||||
|
||||
if( !this || !(this instanceof TestRunner )){
|
||||
return new TestRunner( options );
|
||||
}
|
||||
|
||||
this.test_url = options.url || "";
|
||||
|
||||
this.global_setup(); // execute immediately
|
||||
};
|
||||
|
||||
/*
|
||||
**
|
||||
** functions
|
||||
**
|
||||
*/
|
||||
TestRunner.prototype.global_setup = function() {
|
||||
|
||||
var self = this; // hold ref to instance
|
||||
|
||||
$.ajax({
|
||||
'url' : this.test_url ,
|
||||
'dataType' : 'json'
|
||||
})
|
||||
.done( function( json_data ) {
|
||||
self.run_this_mother.call( self, json_data );
|
||||
})
|
||||
.fail( function( error ) {
|
||||
console.log( "The test data didn't load: ", error );
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
TestRunner.prototype.single_setup = function() {
|
||||
this.get_layer_count();
|
||||
};
|
||||
|
||||
TestRunner.prototype.tear_down = function() {
|
||||
if( this._draw_delete_handler ){
|
||||
this._draw_delete_handler.off('draw:deleted');
|
||||
}
|
||||
};
|
||||
|
||||
TestRunner.prototype.run_this_mother = function( json_data ) {
|
||||
for( var key in json_data ){
|
||||
console.log( "[ RUNNING ]: test " + json_data[key]['type'] + "->" + "simple=" + json_data[key]['simple'] );
|
||||
var data = json_data[key]['data'];
|
||||
if( json_data[key]['type'] === 'geojson' ) {
|
||||
data = JSON.stringify( data );
|
||||
}
|
||||
|
||||
/*
|
||||
** run different tests
|
||||
** the context here is jQuery, so change
|
||||
** to reference the instance
|
||||
*/
|
||||
this.single_setup();
|
||||
|
||||
this.test_parsing( data, json_data );
|
||||
this.test_add2map( json_data );
|
||||
this.test_deletable( json_data );
|
||||
|
||||
this.tear_down();
|
||||
}
|
||||
};
|
||||
|
||||
TestRunner.prototype.test_deletable = function(identifier){ // TODO: this needs work
|
||||
var toolbar = null;
|
||||
// get the right toolbar, depending on attributes
|
||||
for( var key in drawControl._toolbars ){
|
||||
var tbar = drawControl._toolbars[key];
|
||||
if ( !(tbar instanceof L.EditToolbar ) ){
|
||||
continue;
|
||||
}
|
||||
|
||||
toolbar = tbar; // set the right one;
|
||||
}
|
||||
|
||||
// create delete handler that makes sure things are deleted
|
||||
this._draw_delete_handler = map.on('draw:deleted', function (e) {
|
||||
try {
|
||||
e.layers.eachLayer(function (l) {
|
||||
drawnItems.removeLayer(l);
|
||||
});
|
||||
console.warn( "[ PASSED ]: test_deletable" );
|
||||
}
|
||||
catch ( err ) {
|
||||
console.error( "[ DELETE TEST FAIL ]: ", err.message, identifier );
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// loop through this toolbars featureGroup, delete layers
|
||||
if ( !toolbar._activeMode ) {
|
||||
toolbar._modes['remove'].button.click(); // enable deletable
|
||||
}
|
||||
for( var indx in toolbar.options['featureGroup']._layers ) {
|
||||
try {
|
||||
var lyr = toolbar.options['featureGroup']._layers[indx];
|
||||
lyr.fire( 'click' ); // triggers delete
|
||||
}
|
||||
catch ( err ){
|
||||
console.error( "[ DELETE TEST FAIL ]: ", err.message, identifier );
|
||||
}
|
||||
}
|
||||
// WTF?
|
||||
$('a[title="Save changes."]')[0].click(); // disable deletable
|
||||
|
||||
};
|
||||
|
||||
TestRunner.prototype.test_add2map = function(identifier){
|
||||
var current_num = Object.keys( map._layers ).length;
|
||||
if( current_num <= this.num_layers_before_parse ){
|
||||
console.error( "[ ADD2MAP TEST FAIL ]: ", identifier );
|
||||
}
|
||||
else {
|
||||
console.warn( "[ PASSED ]: test_add2map" );
|
||||
}
|
||||
};
|
||||
|
||||
TestRunner.prototype.get_layer_count = function(){
|
||||
this.num_layers_before_parse = Object.keys( map._layers ).length;
|
||||
};
|
||||
|
||||
TestRunner.prototype.test_parsing = function( data, identifier ){
|
||||
var is_valid = FormatSniffer( { data : data } ).sniff();
|
||||
if ( !is_valid ) {
|
||||
console.error( "[ PARSE TEST FAIL ]: ", identifier );
|
||||
}
|
||||
else {
|
||||
console.warn( "[ PASSED ]: test_parsing" );
|
||||
}
|
||||
};
|
||||
|
||||
return TestRunner; // return class def
|
||||
|
||||
});
|
||||
@@ -10,11 +10,11 @@
|
||||
"error_coordinates_out_of_range": "خطأ: الإحداثيات خارج النطاق أو مرتبة بشكل غير صحيح (مطلوب خط العرض قبل خط الطول).",
|
||||
"invalid_format": "تنسيق غير صالح. استخدم 'lat,lng,lat,lng' أو 'lat lng lat lng'.",
|
||||
"generation_process_started": "بدأت عملية البناء.",
|
||||
"winter_mode": "وضع الشتاء",
|
||||
"world_scale": "مقياس العالم",
|
||||
"custom_bounding_box": "مربع الحدود المخصص",
|
||||
"floodfill_timeout": "مهلة ملء الفيضان (ثواني)",
|
||||
"ground_level": "مستوى الأرض",
|
||||
"winter_mode": "وضع الشتاء:",
|
||||
"world_scale": "مقياس العالم:",
|
||||
"custom_bounding_box": "مربع الحدود المخصص:",
|
||||
"floodfill_timeout": "مهلة ملء الفيضان (ثواني):",
|
||||
"ground_level": "مستوى الأرض:",
|
||||
"choose_world_modal_title": "اختيار عالم",
|
||||
"select_existing_world": "اختيار عالم موجود مسبقًا",
|
||||
"generate_new_world": "إنشاء عالم جديد",
|
||||
@@ -34,15 +34,5 @@
|
||||
"license_and_credits": "الرخصة والمساهمون",
|
||||
"placeholder_bbox": "الصيغة: lat,lng,lat,lng",
|
||||
"placeholder_floodfill": "ثوانٍ",
|
||||
"placeholder_ground": "مستوى الأرض",
|
||||
"language": "اللغة",
|
||||
"map_theme": "موضوع الخريطة",
|
||||
"terrain": "التضاريس",
|
||||
"generation_mode": "وضع الإنشاء",
|
||||
"mode_geo_terrain": "كائنات + تضاريس",
|
||||
"mode_geo_only": "كائنات فقط",
|
||||
"mode_terrain_only": "تضاريس فقط",
|
||||
"interior": "توليد الداخلية",
|
||||
"roof": "توليد السقف",
|
||||
"fillground": "ملء الأرض"
|
||||
"placeholder_ground": "مستوى الأرض"
|
||||
}
|
||||
@@ -10,15 +10,15 @@
|
||||
"error_coordinates_out_of_range": "Fehler: Koordinaten sind außerhalb des Bereichs oder falsch geordnet (Lat vor Lng erforderlich).",
|
||||
"invalid_format": "Ungültiges Format. Bitte verwende 'lat,lng,lat,lng' oder 'lat lng lat lng'.",
|
||||
"generation_process_started": "Generierungsprozess gestartet.",
|
||||
"winter_mode": "Wintermodus",
|
||||
"world_scale": "Weltmaßstab",
|
||||
"custom_bounding_box": "Benutzerdefinierte BBOX",
|
||||
"floodfill_timeout": "Floodfill-Timeout (Sek)",
|
||||
"ground_level": "Bodenhöhe",
|
||||
"winter_mode": "Wintermodus:",
|
||||
"world_scale": "Weltmaßstab:",
|
||||
"custom_bounding_box": "Benutzerdefinierte BBOX:",
|
||||
"floodfill_timeout": "Floodfill-Timeout (Sek):",
|
||||
"ground_level": "Bodenhöhe:",
|
||||
"choose_world_modal_title": "Welt wählen",
|
||||
"select_existing_world": "Vorhandene Welt auswählen",
|
||||
"generate_new_world": "Neue Welt generieren",
|
||||
"customization_settings": "Einstellungen",
|
||||
"customization_settings": "Anpassungseinstellungen",
|
||||
"footer_text": "© {year} Arnis v{version} von louis-e",
|
||||
"new_version_available": "Eine neue Version ist verfügbar! Klicke hier, um sie herunterzuladen.",
|
||||
"minecraft_directory_not_found": "Minecraft Verzeichnis nicht gefunden",
|
||||
@@ -30,19 +30,9 @@
|
||||
"area_too_large": "Dieses Gebiet ist sehr groß und könnte das Berechnungslimit überschreiten.",
|
||||
"area_extensive": "Diese Gebietsgröße könnte längere Zeit für die Generierung benötigen.",
|
||||
"selection_confirmed": "Auswahl bestätigt!",
|
||||
"unknown_error": "Unbekannter Fehler",
|
||||
"license_and_credits": "Lizenz und Credits",
|
||||
"unknown_error": "Unknown error",
|
||||
"license_and_credits": "License and Credits",
|
||||
"placeholder_bbox": "Format: lat,lng,lat,lng",
|
||||
"placeholder_floodfill": "Sekunden",
|
||||
"placeholder_ground": "Bodenhöhe",
|
||||
"language": "Sprache",
|
||||
"map_theme": "Kartenstil",
|
||||
"terrain": "Terrain",
|
||||
"generation_mode": "Generierungsmodus",
|
||||
"mode_geo_terrain": "Objekte + Terrain",
|
||||
"mode_geo_only": "Nur Objekte",
|
||||
"mode_terrain_only": "Nur Terrain",
|
||||
"interior": "Innenraum Generierung",
|
||||
"roof": "Dach Generierung",
|
||||
"fillground": "Boden füllen"
|
||||
"placeholder_ground": "Bodenhöhe"
|
||||
}
|
||||
@@ -10,11 +10,11 @@
|
||||
"error_coordinates_out_of_range": "Error: Coordinates are out of range or incorrectly ordered (Lat before Lng required).",
|
||||
"invalid_format": "Invalid format. Please use 'lat,lng,lat,lng' or 'lat lng lat lng'.",
|
||||
"generation_process_started": "Generation process started.",
|
||||
"winter_mode": "Winter Mode",
|
||||
"world_scale": "World Scale",
|
||||
"custom_bounding_box": "Custom Bounding Box",
|
||||
"floodfill_timeout": "Floodfill Timeout (sec)",
|
||||
"ground_level": "Ground Level",
|
||||
"winter_mode": "Winter Mode:",
|
||||
"world_scale": "World Scale:",
|
||||
"custom_bounding_box": "Custom Bounding Box:",
|
||||
"floodfill_timeout": "Floodfill Timeout (sec):",
|
||||
"ground_level": "Ground Level:",
|
||||
"choose_world_modal_title": "Choose World",
|
||||
"select_existing_world": "Select existing world",
|
||||
"generate_new_world": "Generate new world",
|
||||
@@ -34,15 +34,5 @@
|
||||
"license_and_credits": "License and Credits",
|
||||
"placeholder_bbox": "Format: lat,lng,lat,lng",
|
||||
"placeholder_floodfill": "Seconds",
|
||||
"placeholder_ground": "Ground Level",
|
||||
"language": "Language",
|
||||
"map_theme": "Map Theme",
|
||||
"terrain": "Terrain",
|
||||
"generation_mode": "Generation Mode",
|
||||
"mode_geo_terrain": "Objects + Terrain",
|
||||
"mode_geo_only": "Objects only",
|
||||
"mode_terrain_only": "Terrain only",
|
||||
"interior": "Interior Generation",
|
||||
"roof": "Roof Generation",
|
||||
"fillground": "Fill Ground"
|
||||
"placeholder_ground": "Ground Level"
|
||||
}
|
||||
@@ -10,11 +10,11 @@
|
||||
"error_coordinates_out_of_range": "Error: Las coordenadas están fuera de rango o están ordenadas incorrectamente (Lat antes de Lng requerido).",
|
||||
"invalid_format": "Formato inválido. Por favor, use 'lat,lng,lat,lng' o 'lat lng lat lng'.",
|
||||
"generation_process_started": "Proceso de generación iniciado.",
|
||||
"winter_mode": "Modo invierno",
|
||||
"world_scale": "Escala del mundo",
|
||||
"custom_bounding_box": "Caja delimitadora personalizada",
|
||||
"floodfill_timeout": "Tiempo de espera de relleno (seg)",
|
||||
"ground_level": "Nivel del suelo",
|
||||
"winter_mode": "Modo invierno:",
|
||||
"world_scale": "Escala del mundo:",
|
||||
"custom_bounding_box": "Caja delimitadora personalizada:",
|
||||
"floodfill_timeout": "Tiempo de espera de relleno (seg):",
|
||||
"ground_level": "Nivel del suelo:",
|
||||
"choose_world_modal_title": "Elegir mundo",
|
||||
"select_existing_world": "Seleccionar mundo existente",
|
||||
"generate_new_world": "Generar nuevo mundo",
|
||||
@@ -34,15 +34,5 @@
|
||||
"license_and_credits": "License and Credits",
|
||||
"placeholder_bbox": "Format: lat,lng,lat,lng",
|
||||
"placeholder_floodfill": "Seconds",
|
||||
"placeholder_ground": "Ground Level",
|
||||
"language": "Idioma",
|
||||
"map_theme": "Tema del Mapa",
|
||||
"terrain": "Terreno",
|
||||
"generation_mode": "Modo de Generación",
|
||||
"mode_geo_terrain": "Objetos + Terreno",
|
||||
"mode_geo_only": "Solo Objetos",
|
||||
"mode_terrain_only": "Solo Terreno",
|
||||
"interior": "Generación Interior",
|
||||
"roof": "Generación de Tejado",
|
||||
"fillground": "Rellenar Suelo"
|
||||
"placeholder_ground": "Ground Level"
|
||||
}
|
||||
@@ -10,11 +10,11 @@
|
||||
"error_coordinates_out_of_range": "Virhe: Koordinaatit ovat kantaman ulkopuolella tai vääriin aseteltu (Lat ennen Lng vaadittu).",
|
||||
"invalid_format": "Väärä formaatti. Käytä 'lat,lng,lat,lng' tai 'lat lng lat lng'.",
|
||||
"generation_process_started": "Luontiprosessi aloitettu.",
|
||||
"winter_mode": "Talvitila",
|
||||
"world_scale": "Maailmanskaalaus",
|
||||
"custom_bounding_box": "Mukautettu rajoituslaatikko",
|
||||
"floodfill_timeout": "Täytön aikakatkaisu (sec)",
|
||||
"ground_level": "Maataso",
|
||||
"winter_mode": "Talvitila:",
|
||||
"world_scale": "Maailmanskaalaus:",
|
||||
"custom_bounding_box": "Mukautettu rajoituslaatikko:",
|
||||
"floodfill_timeout": "Täytön aikakatkaisu (sec):",
|
||||
"ground_level": "Maataso:",
|
||||
"choose_world_modal_title": "Valitse maailma",
|
||||
"select_existing_world": "Valitse olemassa oleva maailma",
|
||||
"generate_new_world": "Luo uusi maailma",
|
||||
@@ -34,15 +34,5 @@
|
||||
"license_and_credits": "Lisenssi ja krediitit",
|
||||
"placeholder_bbox": "Formaatti: lat,lng,lat,lng",
|
||||
"placeholder_floodfill": "Sekuntia",
|
||||
"placeholder_ground": "Maataso",
|
||||
"language": "Kieli",
|
||||
"map_theme": "Karttateema",
|
||||
"terrain": "Maasto",
|
||||
"generation_mode": "Luontitila",
|
||||
"mode_geo_terrain": "Kohteet + Maasto",
|
||||
"mode_geo_only": "Vain kohteet",
|
||||
"mode_terrain_only": "Vain maasto",
|
||||
"interior": "Sisätilan luonti",
|
||||
"roof": "Katon luonti",
|
||||
"fillground": "Täytä maa"
|
||||
"placeholder_ground": "Maataso"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"select_location": "Sélectionner une localisation",
|
||||
"zoom_in_and_choose": "Zoomez et choisissez votre zone avec l'outil rectangle",
|
||||
"zoom_in_and_choose": "Zoomez et choisissez une zone avec l'outil de sélection rectangulaire",
|
||||
"select_world": "Sélectionner un monde",
|
||||
"choose_world": "Choisir un monde",
|
||||
"no_world_selected": "Aucun monde sélectionné",
|
||||
@@ -10,11 +10,11 @@
|
||||
"error_coordinates_out_of_range": "Erreur: Coordonnées hors de portée ou dans un ordre incorrect (besoin de la latitude avant la longitude).",
|
||||
"invalid_format": "Format invalide. Utilisez 'lat,lng,lat,lng' ou 'lat lng lat lng'.",
|
||||
"generation_process_started": "Processus de génération commencé.",
|
||||
"winter_mode": "Mode hiver",
|
||||
"world_scale": "Échelle du monde",
|
||||
"custom_bounding_box": "Cadre de délimitation personnalisé",
|
||||
"floodfill_timeout": "Expiration du délai de remplissage (en secondes)",
|
||||
"ground_level": "Niveau du sol",
|
||||
"winter_mode": "Mode hiver:",
|
||||
"world_scale": "Échelle du monde:",
|
||||
"custom_bounding_box": "Cadre de délimitation personnalisé:",
|
||||
"floodfill_timeout": "Expiration du délai de remplissage (en secondes):",
|
||||
"ground_level": "Niveau du sol:",
|
||||
"choose_world_modal_title": "Choisir un monde",
|
||||
"select_existing_world": "Sélectionner un monde existant",
|
||||
"generate_new_world": "Générer un nouveau monde",
|
||||
@@ -34,15 +34,5 @@
|
||||
"license_and_credits": "Licence et crédits",
|
||||
"placeholder_bbox": "Format: lat,lng,lat,lng",
|
||||
"placeholder_floodfill": "Secondes",
|
||||
"placeholder_ground": "Niveau du sol",
|
||||
"language": "Langue",
|
||||
"map_theme": "Thème de carte",
|
||||
"terrain": "Terrain",
|
||||
"generation_mode": "Mode de génération",
|
||||
"mode_geo_terrain": "Objets + Terrain",
|
||||
"mode_geo_only": "Objets uniquement",
|
||||
"mode_terrain_only": "Terrain uniquement",
|
||||
"interior": "Génération d'intérieur",
|
||||
"roof": "Génération de toit",
|
||||
"fillground": "Remplir le sol"
|
||||
"placeholder_ground": "Niveau du sol"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"select_location": "Hely kiválasztása",
|
||||
"zoom_in_and_choose": "Nagyíts és jelöld ki a területet a kijelölő eszközzel",
|
||||
"zoom_in_and_choose": "Közelíts és válaszd ki a területet a téglalap eszköz segítségével",
|
||||
"select_world": "Világ kijelölése",
|
||||
"choose_world": "Világ kiválasztása",
|
||||
"no_world_selected": "Nincs világ kiválasztva",
|
||||
@@ -13,7 +13,7 @@
|
||||
"winter_mode": "Téli mód",
|
||||
"world_scale": "Világ nagysága",
|
||||
"custom_bounding_box": "Egyéni határoló keret",
|
||||
"floodfill_timeout": "Floodfill Timeout (sec)",
|
||||
"floodfill_timeout": "Floodfill Timeout (sec):",
|
||||
"ground_level": "Földszint",
|
||||
"choose_world_modal_title": "Világ kiválasztása",
|
||||
"select_existing_world": "Már létező világ kiválasztása",
|
||||
@@ -34,15 +34,5 @@
|
||||
"license_and_credits": "Licenc és elismerés.",
|
||||
"placeholder_bbox": "Formátum: lat,lng,lat,lng",
|
||||
"placeholder_floodfill": "Másodpercek",
|
||||
"placeholder_ground": "Földszint",
|
||||
"language": "Nyelv",
|
||||
"map_theme": "Térkép téma",
|
||||
"terrain": "Terep",
|
||||
"generation_mode": "Generálási mód",
|
||||
"mode_geo_terrain": "Objektumok + Terep",
|
||||
"mode_geo_only": "Csak objektumok",
|
||||
"mode_terrain_only": "Csak terep",
|
||||
"interior": "Belső generálás",
|
||||
"roof": "Tető generálás",
|
||||
"fillground": "Talaj feltöltése"
|
||||
"placeholder_ground": "Földszint"
|
||||
}
|
||||