mirror of
https://github.com/neocturne/MinedMap.git
synced 2025-03-04 09:13: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
|
||||
|
||||
### 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
|
||||
|
||||
### Added
|
||||
|
|
64
Cargo.lock
generated
64
Cargo.lock
generated
|
@ -584,6 +584,7 @@ dependencies = [
|
|||
"minedmap-types",
|
||||
"num-integer",
|
||||
"num_cpus",
|
||||
"phf",
|
||||
"rayon",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
|
@ -717,6 +718,48 @@ dependencies = [
|
|||
"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]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.15"
|
||||
|
@ -766,6 +809,21 @@ dependencies = [
|
|||
"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]]
|
||||
name = "rayon"
|
||||
version = "1.10.0"
|
||||
|
@ -923,6 +981,12 @@ version = "0.3.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
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" }
|
||||
num-integer = "0.1.45"
|
||||
num_cpus = "1.16.0"
|
||||
phf = { version = "0.11.2", features = ["macros"] }
|
||||
rayon = "1.7.0"
|
||||
regex = "1.10.2"
|
||||
rustc-hash = "2.0.0"
|
||||
|
|
|
@ -46,7 +46,7 @@ pub const MIPMAP_FILE_META_VERSION: FileMetaVersion = FileMetaVersion(0);
|
|||
/// MinedMap processed entity data version number
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
//! 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};
|
||||
|
||||
/// A span of formatted text
|
||||
|
@ -17,8 +18,8 @@ pub struct FormattedText {
|
|||
/// Text content
|
||||
pub text: String,
|
||||
/// Text color
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub color: Option<Arc<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none", with = "json_color")]
|
||||
pub color: Option<Color>,
|
||||
/// Bold formatting
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub bold: Option<bool>,
|
||||
|
@ -41,7 +42,7 @@ impl FormattedText {
|
|||
pub fn inherit(self, parent: &Self) -> Self {
|
||||
FormattedText {
|
||||
text: self.text,
|
||||
color: self.color.or_else(|| parent.color.clone()),
|
||||
color: self.color.or(parent.color),
|
||||
bold: self.bold.or(parent.bold),
|
||||
italic: self.italic.or(parent.italic),
|
||||
underlined: self.underlined.or(parent.underlined),
|
||||
|
@ -175,3 +176,83 @@ impl JSONText {
|
|||
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
|
||||
|
||||
use std::{fmt::Display, sync::Arc};
|
||||
use std::fmt::Display;
|
||||
|
||||
use minedmap_resource::Color;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{
|
||||
|
@ -23,10 +24,34 @@ pub struct RawSignText<'a> {
|
|||
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<'_> {
|
||||
/// Decodes the [RawSignText] into a [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 {
|
||||
color,
|
||||
..Default::default()
|
||||
|
|
|
@ -153,25 +153,6 @@ const parseHash = function () {
|
|||
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) {
|
||||
const el = document.createElement('span');
|
||||
el.style.whiteSpace = 'pre';
|
||||
|
@ -180,7 +161,9 @@ function formatSignLine(line) {
|
|||
const child = document.createElement('span');
|
||||
child.textContent = span.text;
|
||||
|
||||
const color = colors[span.color ?? 'black'] || colors['black'];
|
||||
let color = span.color ?? '';
|
||||
if (color[0] !== '#')
|
||||
color = '#000000';
|
||||
|
||||
if (span.bold)
|
||||
child.style.fontWeight = 'bold';
|
||||
|
|
Loading…
Add table
Reference in a new issue