mirror of
https://github.com/neocturne/MinedMap.git
synced 2025-03-04 17:23:33 +01:00
world, viewer: fix sign text colors
- 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.
This commit is contained in:
parent
9375af8d54
commit
ff6e28d381
7 changed files with 192 additions and 27 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -2,6 +2,17 @@
|
||||||
|
|
||||||
## [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
|
||||||
|
|
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"
|
||||||
|
|
|
@ -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