mirror of
https://github.com/neocturne/MinedMap.git
synced 2025-03-04 17:23:33 +01:00
commit
0a3f6d7765
8 changed files with 195 additions and 28 deletions
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -2,8 +2,21 @@
|
||||||
|
|
||||||
## [Unreleased] - ReleaseDate
|
## [Unreleased] - ReleaseDate
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix text colors for signs modified using dye
|
||||||
|
- Fix text colors specified using `#rrggbb` CSS syntax in JSON text
|
||||||
|
|
||||||
|
Only named colors specified via JSON text were working as intended. Dyed signs use different
|
||||||
|
color names.
|
||||||
|
|
||||||
|
The mapping of color names to values is now handled by the generator. Both the generator and the
|
||||||
|
viewer must be updated for sign text colors to work.
|
||||||
|
|
||||||
## [2.3.0] - 2025-01-02
|
## [2.3.0] - 2025-01-02
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
- Added support for Minecraft 1.21.4 block types
|
- Added support for Minecraft 1.21.4 block types
|
||||||
- Added support for Minecraft 1.21.4 Pale Garden biome
|
- Added support for Minecraft 1.21.4 Pale Garden biome
|
||||||
- viewer: added images for pale oak signs
|
- viewer: added images for pale oak signs
|
||||||
|
|
64
Cargo.lock
generated
64
Cargo.lock
generated
|
@ -584,6 +584,7 @@ dependencies = [
|
||||||
"minedmap-types",
|
"minedmap-types",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
|
"phf",
|
||||||
"rayon",
|
"rayon",
|
||||||
"regex",
|
"regex",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
|
@ -717,6 +718,48 @@ dependencies = [
|
||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||||
|
dependencies = [
|
||||||
|
"phf_macros",
|
||||||
|
"phf_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_generator"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
|
||||||
|
dependencies = [
|
||||||
|
"phf_shared",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_macros"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
||||||
|
dependencies = [
|
||||||
|
"phf_generator",
|
||||||
|
"phf_shared",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_shared"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
|
||||||
|
dependencies = [
|
||||||
|
"siphasher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
@ -766,6 +809,21 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.10.0"
|
version = "1.10.0"
|
||||||
|
@ -923,6 +981,12 @@ version = "0.3.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "siphasher"
|
||||||
|
version = "0.3.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
|
|
|
@ -52,6 +52,7 @@ minedmap-resource = { version = "0.5.0", path = "crates/resource" }
|
||||||
minedmap-types = { version = "0.1.2", path = "crates/types" }
|
minedmap-types = { version = "0.1.2", path = "crates/types" }
|
||||||
num-integer = "0.1.45"
|
num-integer = "0.1.45"
|
||||||
num_cpus = "1.16.0"
|
num_cpus = "1.16.0"
|
||||||
|
phf = { version = "0.11.2", features = ["macros"] }
|
||||||
rayon = "1.7.0"
|
rayon = "1.7.0"
|
||||||
regex = "1.10.2"
|
regex = "1.10.2"
|
||||||
rustc-hash = "2.0.0"
|
rustc-hash = "2.0.0"
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub enum BlockFlag {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An RGB color with u8 components
|
/// An RGB color with u8 components
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub struct Color(pub [u8; 3]);
|
pub struct Color(pub [u8; 3]);
|
||||||
|
|
||||||
/// An RGB color with f32 components
|
/// An RGB color with f32 components
|
||||||
|
|
|
@ -46,7 +46,7 @@ pub const MIPMAP_FILE_META_VERSION: FileMetaVersion = FileMetaVersion(0);
|
||||||
/// MinedMap processed entity data version number
|
/// MinedMap processed entity data version number
|
||||||
///
|
///
|
||||||
/// Increase when entity collection changes bacause of code changes.
|
/// Increase when entity collection changes bacause of code changes.
|
||||||
pub const ENTITIES_FILE_META_VERSION: FileMetaVersion = FileMetaVersion(0);
|
pub const ENTITIES_FILE_META_VERSION: FileMetaVersion = FileMetaVersion(1);
|
||||||
|
|
||||||
/// Coordinate pair of a generated tile
|
/// Coordinate pair of a generated tile
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
//! Newtype and helper methods for handling Minecraft Raw JSON Text
|
//! Newtype and helper methods for handling Minecraft Raw JSON Text
|
||||||
|
|
||||||
use std::{collections::VecDeque, fmt::Display, sync::Arc};
|
use std::{collections::VecDeque, fmt::Display};
|
||||||
|
|
||||||
|
use minedmap_resource::Color;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// A span of formatted text
|
/// A span of formatted text
|
||||||
|
@ -17,8 +18,8 @@ pub struct FormattedText {
|
||||||
/// Text content
|
/// Text content
|
||||||
pub text: String,
|
pub text: String,
|
||||||
/// Text color
|
/// Text color
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none", with = "json_color")]
|
||||||
pub color: Option<Arc<String>>,
|
pub color: Option<Color>,
|
||||||
/// Bold formatting
|
/// Bold formatting
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub bold: Option<bool>,
|
pub bold: Option<bool>,
|
||||||
|
@ -41,7 +42,7 @@ impl FormattedText {
|
||||||
pub fn inherit(self, parent: &Self) -> Self {
|
pub fn inherit(self, parent: &Self) -> Self {
|
||||||
FormattedText {
|
FormattedText {
|
||||||
text: self.text,
|
text: self.text,
|
||||||
color: self.color.or_else(|| parent.color.clone()),
|
color: self.color.or(parent.color),
|
||||||
bold: self.bold.or(parent.bold),
|
bold: self.bold.or(parent.bold),
|
||||||
italic: self.italic.or(parent.italic),
|
italic: self.italic.or(parent.italic),
|
||||||
underlined: self.underlined.or(parent.underlined),
|
underlined: self.underlined.or(parent.underlined),
|
||||||
|
@ -175,3 +176,83 @@ impl JSONText {
|
||||||
serde_json::from_str(&self.0).unwrap_or_default()
|
serde_json::from_str(&self.0).unwrap_or_default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod json_color {
|
||||||
|
//! Helpers for serializing and deserializing [FormattedText](super::FormattedText) colors
|
||||||
|
|
||||||
|
use minedmap_resource::Color;
|
||||||
|
use serde::{
|
||||||
|
de::{self, Visitor},
|
||||||
|
ser::Error as _,
|
||||||
|
Deserializer, Serializer,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Named JSON text colors
|
||||||
|
static COLORS: phf::Map<&'static str, Color> = phf::phf_map! {
|
||||||
|
"black" => Color([0x00, 0x00, 0x00]),
|
||||||
|
"dark_blue" => Color([0x00, 0x00, 0xAA]),
|
||||||
|
"dark_green" => Color([0x00, 0xAA, 0x00]),
|
||||||
|
"dark_aqua" => Color([0x00, 0xAA, 0xAA]),
|
||||||
|
"dark_red" => Color([0xAA, 0x00, 0x00]),
|
||||||
|
"dark_purple" => Color([0xAA, 0x00, 0xAA]),
|
||||||
|
"gold" => Color([0xFF, 0xAA, 0x00]),
|
||||||
|
"gray" => Color([0xAA, 0xAA, 0xAA]),
|
||||||
|
"dark_gray" => Color([0x55, 0x55, 0x55]),
|
||||||
|
"blue" => Color([0x55, 0x55, 0xFF]),
|
||||||
|
"green" => Color([0x55, 0xFF, 0x55]),
|
||||||
|
"aqua" => Color([0x55, 0xFF, 0xFF]),
|
||||||
|
"red" => Color([0xFF, 0x55, 0x55]),
|
||||||
|
"light_purple" => Color([0xFF, 0x55, 0xFF]),
|
||||||
|
"yellow" => Color([0xFF, 0xFF, 0x55]),
|
||||||
|
"white" => Color([0xFF, 0xFF, 0xFF]),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// serde serialize function for [FormattedText::color](super::FormattedText::color)
|
||||||
|
pub fn serialize<S>(color: &Option<Color>, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let &Some(color) = color else {
|
||||||
|
return Err(S::Error::custom("serialize called for None sign color"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let text = format!("#{:02x}{:02x}{:02x}", color.0[0], color.0[1], color.0[2]);
|
||||||
|
serializer.serialize_str(&text)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// serde [Visitor] for use by [deserialize]
|
||||||
|
struct ColorVisitor;
|
||||||
|
|
||||||
|
impl Visitor<'_> for ColorVisitor {
|
||||||
|
type Value = Option<Color>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("a string representing a color")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, color: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
if let Some(hex) = color.strip_prefix("#") {
|
||||||
|
if let Ok(value) = u32::from_str_radix(hex, 16) {
|
||||||
|
return Ok(Some(Color([
|
||||||
|
(value >> 16) as u8,
|
||||||
|
(value >> 8) as u8,
|
||||||
|
value as u8,
|
||||||
|
])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(COLORS.get(color).copied())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// serde deserialize function for [FormattedText::color](super::FormattedText::color)
|
||||||
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Color>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_str(ColorVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
//! Processing of sign text
|
//! Processing of sign text
|
||||||
|
|
||||||
use std::{fmt::Display, sync::Arc};
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use minedmap_resource::Color;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -23,10 +24,34 @@ pub struct RawSignText<'a> {
|
||||||
pub color: Option<&'a str>,
|
pub color: Option<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The color to use for signs without a color attribute ("black")
|
||||||
|
const DEFAULT_COLOR: Color = Color([0, 0, 0]);
|
||||||
|
|
||||||
|
/// Map of text colors associated with dyes (except for black)
|
||||||
|
static DYE_COLORS: phf::Map<&'static str, Color> = phf::phf_map! {
|
||||||
|
"white" => Color([255, 255, 255]),
|
||||||
|
"orange" => Color([255, 104, 31]),
|
||||||
|
"magenta" => Color([255, 0, 255]),
|
||||||
|
"light_blue" => Color([154, 192, 205]),
|
||||||
|
"yellow" => Color([255, 255, 0]),
|
||||||
|
"lime" => Color([191, 255, 0]),
|
||||||
|
"pink" => Color([255, 105, 180]),
|
||||||
|
"gray" => Color([128, 128, 128]),
|
||||||
|
"light_gray" => Color([211, 211, 211]),
|
||||||
|
"cyan" => Color([0, 255, 255]),
|
||||||
|
"purple" => Color([160, 32, 240]),
|
||||||
|
"blue" => Color([0, 0, 255]),
|
||||||
|
"brown" => Color([139, 69, 19]),
|
||||||
|
"green" => Color([0, 255, 0]),
|
||||||
|
"red" => Color([255, 0, 0]),
|
||||||
|
};
|
||||||
|
|
||||||
impl RawSignText<'_> {
|
impl RawSignText<'_> {
|
||||||
/// Decodes the [RawSignText] into a [SignText]
|
/// Decodes the [RawSignText] into a [SignText]
|
||||||
pub fn decode(&self) -> SignText {
|
pub fn decode(&self) -> SignText {
|
||||||
let color = self.color.map(|c| Arc::new(c.to_owned()));
|
let color = self
|
||||||
|
.color
|
||||||
|
.map(|c| DYE_COLORS.get(c).copied().unwrap_or(DEFAULT_COLOR));
|
||||||
let parent = FormattedText {
|
let parent = FormattedText {
|
||||||
color,
|
color,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
|
@ -153,25 +153,6 @@ const parseHash = function () {
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
const colors = {
|
|
||||||
black: '#000000',
|
|
||||||
dark_blue: '#0000AA',
|
|
||||||
dark_green: '#00AA00',
|
|
||||||
dark_aqua: '#00AAAA',
|
|
||||||
dark_red: '#AA0000',
|
|
||||||
dark_purple: '#AA00AA',
|
|
||||||
gold: '#FFAA00',
|
|
||||||
gray: '#AAAAAA',
|
|
||||||
dark_gray: '#555555',
|
|
||||||
blue: '#5555FF',
|
|
||||||
green: '#55FF55',
|
|
||||||
aqua: '#55FFFF',
|
|
||||||
red: '#FF5555',
|
|
||||||
light_purple: '#FF55FF',
|
|
||||||
yellow: '#FFFF55',
|
|
||||||
white: '#FFFFFF',
|
|
||||||
};
|
|
||||||
|
|
||||||
function formatSignLine(line) {
|
function formatSignLine(line) {
|
||||||
const el = document.createElement('span');
|
const el = document.createElement('span');
|
||||||
el.style.whiteSpace = 'pre';
|
el.style.whiteSpace = 'pre';
|
||||||
|
@ -180,7 +161,9 @@ function formatSignLine(line) {
|
||||||
const child = document.createElement('span');
|
const child = document.createElement('span');
|
||||||
child.textContent = span.text;
|
child.textContent = span.text;
|
||||||
|
|
||||||
const color = colors[span.color ?? 'black'] || colors['black'];
|
let color = span.color ?? '';
|
||||||
|
if (color[0] !== '#')
|
||||||
|
color = '#000000';
|
||||||
|
|
||||||
if (span.bold)
|
if (span.bold)
|
||||||
child.style.fontWeight = 'bold';
|
child.style.fontWeight = 'bold';
|
||||||
|
|
Loading…
Add table
Reference in a new issue