Repository: rojo-rbx/rbx-dom
Pull request #65 (2019-07-11 01:33:06)

Fix BrickColor
BrickColor is pretty much totally broken.

This tries to... fix it.

LPGhatguy: I'm compiling locally with 1.31.1 and the test suite is passing. I wonder what difference between 1.31.1 on my machine and 1.31.0 on the CI machine is that's causing this!
LPGhatguy: It was a Linux-only dependency (getrandom), and it supports 1.32 and newer. Bumping the minimum compiler from 1.31.1 to 1.32.0 now.

Patch:
diff --git a/.travis.yml b/.travis.yml
index a783490..accbf0f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,5 @@
 language: rust
-rust: [1.31.0, stable]
+rust: [1.32.0, stable]
 cache: cargo
 
 script:
diff --git a/README.md b/README.md
index 37211c7..be5a431 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ Roblox reflection information for working with Instances in external tooling.
 | Axes               | `ArcHandles.Axes`               | ❌ | ❌ | ❌ | ❌ |
 | BinaryString       | `Terrain.MaterialColors`        | ✔ | ➖ | ✔ | ❌ |
 | Bool               | `Part.Anchored`                 | ✔ | ✔ | ✔ | ✔ |
-| BrickColor         | `Part.BrickColor`               | ✔ | ❌ | ❌ | ❌ |
+| BrickColor         | `Part.BrickColor`               | ✔ | ❌ | ✔ | ❌ |
 | CFrame             | `Camera.CFrame`                 | ✔ | ✔ | ✔ | ❌ |
 | Color3             | `Lighting.Ambient`              | ✔ | ✔ | ✔ | ❌ |
 | Color3uint8        | `N/A`                           | ✔ | ✔ | ✔ | ❌ |
@@ -87,5 +87,8 @@ This project has unveiled a handful of interesting bugs and quirks in Roblox!
 - `Color3` properties not serialized as `Color3uint8` would have their colors mistakenly clamped in the XML place format. This was bad for properties on `Lighting`.
 - `ColorSequence`'s XML serialization contains an extra value per keypoint that was intended to be used as an envelope value, but was never implemented.
 
+## Minimum Rust Version
+This project tries (via CI) to support Rust 1.32.0 and newer.
+
 ## License
 rbx-dom is available under the MIT license. See [LICENSE.txt](LICENSE.txt) for details.
\ No newline at end of file
diff --git a/rbx_dom_weak/CHANGELOG.md b/rbx_dom_weak/CHANGELOG.md
index 2e51b7f..4a5c3ac 100644
--- a/rbx_dom_weak/CHANGELOG.md
+++ b/rbx_dom_weak/CHANGELOG.md
@@ -1,6 +1,14 @@
 # rbx\_dom\_weak Changelog
 
 ## Unreleased Changes
+* Changed `BrickColor` to be much more correct
+	* All BrickColor values are now correctly available instead of just palette colors
+	* Enum values now align with the `BrickColor.Number` property and `BrickColor.new` constructor
+	* `BrickColor` no longer serializes to strings in human-readable Serde formats to avoid information loss. These colors have colliding names:
+		* Rust
+		* Lilac
+		* Gold
+		* Deep orange
 
 ## 1.8.2 (2019-07-10)
 * Added conversion from `Int32` to `BrickColor`. This should fix serialization of `SpawnLocation` instances, which use `int` instead of `BrickColor` in at least the XML model format.
diff --git a/rbx_dom_weak/Cargo.toml b/rbx_dom_weak/Cargo.toml
index 98c74ee..f2e3750 100644
--- a/rbx_dom_weak/Cargo.toml
+++ b/rbx_dom_weak/Cargo.toml
@@ -15,6 +15,7 @@ lazy_static = "1.3.0"
 md5 = "0.6.1"
 serde = "1.0"
 serde_derive = "1.0"
+serde_repr = "0.1"
 uuid = { version = "0.7", features = ["v4", "serde"] }
 
 [dev-dependencies]
diff --git a/rbx_dom_weak/src/brick_color.rs b/rbx_dom_weak/src/brick_color.rs
index a12840f..e6fbb10 100644
--- a/rbx_dom_weak/src/brick_color.rs
+++ b/rbx_dom_weak/src/brick_color.rs
@@ -1,15 +1,43 @@
-use serde::{Serialize, Serializer, Deserialize, Deserializer};
 use std::fmt;
 
+use serde_repr::{Serialize_repr, Deserialize_repr};
+
 macro_rules! make_brick_color {
-    ({$([$enum:ident, $name:tt, $value:tt, ($color3_r:tt, $color3_g:tt, $color3_b:tt)],)+}) => {
-        #[derive(Debug, Clone, Copy, PartialEq)]
+    ({
+        $([
+            $enum: ident,
+            $name: expr,
+            $value: expr,
+            ($color3_r: expr, $color3_g: expr, $color3_b: expr)
+        ],)+
+    }) => {
+        /// BrickColor values were the old, palette-based system of defining
+        /// colors in Roblox. As of the time of writing, they're still used for
+        /// some old systems like SpawnLocation and Team objects.
+        ///
+        /// Parts no longer use BrickColor, but we have conversions here to
+        /// support older models.
+        #[derive(Debug, Clone, Copy, PartialEq, Serialize_repr, Deserialize_repr)]
+        #[repr(u16)]
         pub enum BrickColor {
             $($enum = $value,)+
         }
 
         impl BrickColor {
+            /// Find the first BrickColor with the given name, if it exists.
+            ///
+            /// Note that some colors (Lilac, Rust, Gold, and Deep orange) have
+            /// name collisions and can only have one of their variants
+            /// constructed from this function.
+            ///
+            /// This is roughly equivalent to `BrickColor.new(string)` from
+            /// within Roblox, except unknown values will yield `None` instead
+            /// of `Medium stone grey`.
             pub fn from_name(name: &str) -> Option<BrickColor> {
+                // There are collisions in names of some colors. This should
+                // work the same way that Roblox works when mapping names to
+                // BrickColors!
+                #[allow(unreachable_patterns)]
                 match name {
                     $(
                         $name => Some(BrickColor::$enum),
@@ -19,7 +47,14 @@ macro_rules! make_brick_color {
                 }
             }
 
-            pub fn from_palette(value: u8) -> Option<BrickColor> {
+            /// Finds the BrickColor from its associated value. This is
+            /// different from a BrickColor's _palette_ number, which not all
+            /// colors have.
+            ///
+            /// This is roughly equivalent to `BrickColor.new(number)` from
+            /// within Roblox, except unknown values will yield `None` instead
+            /// of `Medium stone grey`.
+            pub fn from_number(value: u16) -> Option<BrickColor> {
                 match value {
                     $(
                         $value => Some(BrickColor::$enum),
@@ -59,211 +94,384 @@ macro_rules! make_brick_color {
                 }
             }
         }
-
-        impl<'de> Deserialize<'de> for BrickColor {
-            fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
-                struct NameVisitor;
-
-                impl<'de> serde::de::Visitor<'de> for NameVisitor {
-                    type Value = BrickColor;
-
-                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-                        formatter.write_str("the name of a brick color")
-                    }
-
-                    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
-                    where
-                        E: serde::de::Error,
-                    {
-                        BrickColor::from_name(value)
-                            .ok_or_else(||
-                                E::custom(format!("unknown brick color name: {}", &value))
-                            )
-                    }
-                }
-
-                struct PaletteVisitor;
-
-                impl<'de> serde::de::Visitor<'de> for PaletteVisitor {
-                    type Value = BrickColor;
-
-                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-                        formatter.write_str("the palette of a brick color")
-                    }
-
-                    fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E>
-                    where
-                        E: serde::de::Error,
-                    {
-                        BrickColor::from_palette(value)
-                            .ok_or_else(||
-                                E::custom(format!("unknown brick color value: {}", &value))
-                            )
-                    }
-                }
-
-                if deserializer.is_human_readable() {
-                    deserializer.deserialize_str(NameVisitor)
-                } else {
-                    deserializer.deserialize_u8(PaletteVisitor)
-                }
-            }
-        }
-
-        impl Serialize for BrickColor {
-            fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
-                if serializer.is_human_readable() {
-                    serializer.serialize_str(&self.to_string())
-                } else {
-                    serializer.serialize_u8(*self as u8)
-                }
-            }
-        }
     };
 }
 
 make_brick_color!({
-    [SlimeGreen, "Slime green", 1, (80, 109, 84)],
-    [BrightBluishGreen, "Bright bluish green", 2, (0, 143, 156)],
-    [Black, "Black", 3, (27, 42, 53)],
-    [DeepBlue, "Deep blue", 4, (33, 84, 185)],
-    [DarkBlue, "Dark blue", 5, (0, 16, 176)],
-    [NavyBlue, "Navy blue", 6, (0, 32, 96)],
-    [ParsleyGreen, "Parsley green", 7, (44, 101, 29)],
-    [DarkGreen, "Dark green", 8, (40, 127, 71)],
-    [Teal, "Teal", 9, (18, 238, 212)],
-    [SmokyGrey, "Smoky grey", 10, (91, 93, 105)],
-    [SteelBlue, "Steel blue", 11, (82, 124, 174)],
-    [StormBlue, "Storm blue", 12, (51, 88, 130)],
-    [Lapis, "Lapis", 13, (16, 42, 220)],
-    [DarkIndigo, "Dark indigo", 14, (61, 21, 133)],
-    [Camo, "Camo", 15, (58, 125, 21)],
-    [SeaGreen, "Sea green", 16, (52, 142, 64)],
-    [Shamrock, "Shamrock", 17, (91, 154, 76)],
-    [Toothpaste, "Toothpaste", 18, (0, 255, 255)],
-    [SandBlue, "Sand blue", 19, (116, 134, 157)],
-    [MediumBlue, "Medium blue", 20, (110, 153, 202)],
-    [BrightBlue, "Bright blue", 21, (13, 105, 172)],
-    [ReallyBlue, "Really blue", 22, (0, 0, 255)],
-    [Mulberry, "Mulberry", 23, (89, 34, 89)],
-    [ForestGreen, "Forest green", 24, (31, 128, 29)],
-    [BrightGreen, "Bright green", 25, (75, 151, 75)],
-    [Grime, "Grime", 26, (127, 142, 100)],
-    [LimeGreen, "Lime green", 27, (0, 255, 0)],
-    [PastelBlueGreen, "Pastel blue-green", 28, (159, 243, 233)],
-    [Fossil, "Fossil", 29, (159, 161, 172)],
-    [ElectricBlue, "Electric blue", 30, (9, 137, 207)],
-    [Lavender, "Lavender", 31, (140, 91, 159)],
-    [RoyalPurple, "Royal purple", 32, (98, 37, 209)],
-    [Eggplant, "Eggplant", 33, (123, 0, 123)],
-    [SandGreen, "Sand green", 34, (120, 144, 130)],
-    [Moss, "Moss", 35, (124, 156, 107)],
-    [Artichoke, "Artichoke", 36, (138, 171, 133)],
-    [SageGreen, "Sage green", 37, (185, 196, 177)],
-    [PastelLightBlue, "Pastel light blue", 38, (175, 221, 255)],
-    [CadetBlue, "Cadet blue", 39, (159, 173, 192)],
-    [Cyan, "Cyan", 40, (4, 175, 236)],
-    [Alder, "Alder", 41, (180, 128, 255)],
-    [Lilac, "Lilac", 42, (167, 94, 155)],
-    [Plum, "Plum", 43, (123, 47, 123)],
-    [BrightViolet, "Bright violet", 44, (107, 50, 124)],
-    [Olive, "Olive", 45, (193, 190, 66)],
-    [BrightYellowishGreen, "Br. yellowish green", 46, (164, 189, 71)],
-    [Olivine, "Olivine", 47, (148, 190, 129)],
-    [LaurelGreen, "Laurel green", 48, (168, 189, 153)],
-    [QuillGrey, "Quill grey", 49, (223, 223, 222)],
-    [GhostGrey, "Ghost grey", 50, (202, 203, 209)],
-    [PastelBlue, "Pastel Blue", 51, (128, 187, 219)],
-    [PastelViolet, "Pastel violet", 52, (177, 167, 255)],
-    [Pink, "Pink", 53, (255, 102, 204)],
-    [HotPink, "Hot pink", 54, (255, 0, 191)],
-    [Magenta, "Magenta", 55, (170, 0, 170)],
-    [Crimson, "Crimson", 56, (151, 0, 0)],
-    [DeepOrange, "Deep orange", 57, (255, 176, 0)],
-    [NewYeller, "New Yeller", 58, (255, 255, 0)],
-    [MediumGreen, "Medium green", 59, (161, 196, 140)],
-    [Mint, "Mint", 60, (177, 229, 166)],
-    [PastelGreen, "Pastel green", 61, (204, 255, 204)],
-    [LightStoneGrey, "Light stone grey", 62, (229, 228, 223)],
-    [LightBlue, "Light blue", 63, (180, 210, 228)],
-    [BabyBlue, "Baby blue", 64, (152, 194, 219)],
-    [CarnationPink, "Carnation pink", 65, (255, 152, 220)],
-    [Persimmon, "Persimmon", 66, (255, 89, 89)],
-    [ReallyRed, "Really red", 67, (255, 0, 0)],
-    [BrightRed, "Bright red", 68, (196, 40, 28)],
-    [Maroon, "Maroon", 69, (117, 0, 0)],
-    [Gold, "Gold", 70, (239, 184, 56)],
-    [BrightYellow, "Bright yellow", 71, (245, 205, 48)],
-    [DaisyOrange, "Daisy orange", 72, (248, 217, 109)],
-    [CoolYellow, "Cool yellow", 73, (253, 234, 141)],
-    [PastelYellow, "Pastel yellow", 74, (255, 255, 204)],
-    [Pearl, "Pearl", 75, (231, 231, 236)],
-    [Fog, "Fog", 76, (199, 212, 228)],
-    [Mauve, "Mauve", 77, (224, 178, 208)],
-    [Sunrise, "Sunrise", 78, (212, 144, 189)],
-    [TerraCotta, "Terra Cotta", 79, (190, 104, 98)],
-    [DustyRose, "Dusty Rose", 80, (163, 75, 75)],
-    [Cocoa, "Cocoa", 81, (86, 36, 36)],
-    [NeonOrange, "Neon orange", 82, (213, 115, 61)],
-    [BrightOrange, "Bright orange", 83, (218, 133, 65)],
-    [Wheat, "Wheat", 84, (241, 231, 199)],
-    [Buttermilk, "Buttermilk", 85, (254, 243, 187)],
-    [InstitutionalWhite, "Institutional white", 86, (248, 248, 248)],
-    [White, "White", 87, (242, 243, 243)],
-    [LightReddishViolet, "Light reddish violet", 88, (232, 186, 200)],
-    [PastelOrange, "Pastel orange", 89, (255, 201, 201)],
-    [Salmon, "Salmon", 90, (255, 148, 148)],
-    [Tawny, "Tawny", 91, (150, 85, 85)],
-    [Rust, "Rust", 92, (143, 76, 42)],
-    [CgaBrown, "CGA brown", 93, (170, 85, 0)],
-    [BrightYellowishOrange, "Br. yellowish orange", 94, (226, 155, 64)],
-    [Cashmere, "Cashmere", 95, (211, 190, 150)],
-    [Khaki, "Khaki", 96, (226, 220, 188)],
-    [LilyWhite, "Lily white", 97, (237, 234, 234)],
-    [Seashell, "Seashell", 98, (233, 218, 218)],
-    [PastelBrown, "Pastel brown", 99, (255, 204, 153)],
-    [LightOrange, "Light orange", 100, (234, 184, 146)],
+    [White, "White", 1, (242, 243, 243)],
+    [Grey, "Grey", 2, (161, 165, 162)],
+    [LightYellow, "Light yellow", 3, (249, 233, 153)],
+    [BrickYellow, "Brick yellow", 5, (215, 197, 154)],
+    [LightGreenMint, "Light green (Mint)", 6, (194, 218, 184)],
+    [LightReddishViolet, "Light reddish violet", 9, (232, 186, 200)],
+    [PastelBlue, "Pastel Blue", 11, (128, 187, 219)],
+    [LightOrangeBrown, "Light orange brown", 12, (203, 132, 66)],
+    [Nougat, "Nougat", 18, (204, 142, 105)],
+    [BrightRed, "Bright red", 21, (196, 40, 28)],
+    [MedReddishViolet, "Med. reddish violet", 22, (196, 112, 160)],
+    [BrightBlue, "Bright blue", 23, (13, 105, 172)],
+    [BrightYellow, "Bright yellow", 24, (245, 205, 48)],
+    [EarthOrange, "Earth orange", 25, (98, 71, 50)],
+    [Black, "Black", 26, (27, 42, 53)],
+    [DarkGrey, "Dark grey", 27, (109, 110, 108)],
+    [DarkGreen, "Dark green", 28, (40, 127, 71)],
+    [MediumGreen, "Medium green", 29, (161, 196, 140)],
+    [LigYellowichOrange, "Lig. Yellowich orange", 36, (243, 207, 155)],
+    [BrightGreen, "Bright green", 37, (75, 151, 75)],
+    [DarkOrange, "Dark orange", 38, (160, 95, 53)],
+    [LightBluishViolet, "Light bluish violet", 39, (193, 202, 222)],
+    [Transparent, "Transparent", 40, (236, 236, 236)],
+    [TrRed, "Tr. Red", 41, (205, 84, 75)],
+    [TrLgBlue, "Tr. Lg blue", 42, (193, 223, 240)],
+    [TrBlue, "Tr. Blue", 43, (123, 182, 232)],
+    [TrYellow, "Tr. Yellow", 44, (247, 241, 141)],
+    [LightBlue, "Light blue", 45, (180, 210, 228)],
+    [TrFluReddishOrange, "Tr. Flu. Reddish orange", 47, (217, 133, 108)],
+    [TrGreen, "Tr. Green", 48, (132, 182, 141)],
+    [TrFluGreen, "Tr. Flu. Green", 49, (248, 241, 132)],
+    [PhosphWhite, "Phosph. White", 50, (236, 232, 222)],
+    [LightRed, "Light red", 100, (238, 196, 182)],
     [MediumRed, "Medium red", 101, (218, 134, 122)],
-    [Burgundy, "Burgundy", 102, (136, 62, 62)],
-    [ReddishBrown, "Reddish brown", 103, (105, 64, 40)],
-    [Cork, "Cork", 104, (188, 155, 93)],
-    [Burlap, "Burlap", 105, (199, 172, 120)],
-    [Beige, "Beige", 106, (202, 191, 163)],
-    [Oyster, "Oyster", 107, (187, 179, 178)],
-    [MidGray, "Mid gray", 108, (205, 205, 205)],
-    [BrickYellow, "Brick yellow", 109, (215, 197, 154)],
-    [Nougat, "Nougat", 110, (204, 142, 105)],
-    [Brown, "Brown", 111, (124, 92, 70)],
-    [PineCone, "Pine Cone", 112, (108, 88, 75)],
-    [FawnBrown, "Fawn brown", 113, (160, 132, 79)],
-    [SandRed, "Sand red", 114, (149, 121, 119)],
-    [HurricaneGrey, "Hurricane grey", 115, (149, 137, 136)],
-    [CloudyGrey, "Cloudy grey", 116, (171, 168, 158)],
-    [Linen, "Linen", 117, (175, 148, 131)],
-    [Copper, "Copper", 118, (150, 103, 102)],
-    [DarkOrange, "Dark orange", 119, (160, 95, 53)],
-    [DirtBrown, "Dirt brown", 120, (86, 66, 54)],
-    [Bronze, "Bronze", 121, (126, 104, 63)],
-    [DarkStoneGrey, "Dark stone grey", 122, (99, 95, 98)],
-    [MediumStoneGrey, "Medium stone grey", 123, (163, 162, 165)],
-    [Flint, "Flint", 124, (105, 102, 92)],
-    [DarkTaupe, "Dark taupe", 125, (90, 76, 66)],
-    [BurntSienna, "Burnt Sienna", 126, (106, 57, 9)],
-    [ReallyBlack, "Really black", 127, (17, 17, 17)],
+    [MediumBlue, "Medium blue", 102, (110, 153, 202)],
+    [LightGrey, "Light grey", 103, (199, 193, 183)],
+    [BrightViolet, "Bright violet", 104, (107, 50, 124)],
+    [BrYellowishOrange, "Br. yellowish orange", 105, (226, 155, 64)],
+    [BrightOrange, "Bright orange", 106, (218, 133, 65)],
+    [BrightBluishGreen, "Bright bluish green", 107, (0, 143, 156)],
+    [EarthYellow, "Earth yellow", 108, (104, 92, 67)],
+    [BrightBluishViolet, "Bright bluish violet", 110, (67, 84, 147)],
+    [TrBrown, "Tr. Brown", 111, (191, 183, 177)],
+    [MediumBluishViolet, "Medium bluish violet", 112, (104, 116, 172)],
+    [TrMediReddishViolet, "Tr. Medi. reddish violet", 113, (229, 173, 200)],
+    [MedYellowishGreen, "Med. yellowish green", 115, (199, 210, 60)],
+    [MedBluishGreen, "Med. bluish green", 116, (85, 165, 175)],
+    [LightBluishGreen, "Light bluish green", 118, (183, 215, 213)],
+    [BrYellowishGreen, "Br. yellowish green", 119, (164, 189, 71)],
+    [LigYellowishGreen, "Lig. yellowish green", 120, (217, 228, 167)],
+    [MedYellowishOrange, "Med. yellowish orange", 121, (231, 172, 88)],
+    [BrReddishOrange, "Br. reddish orange", 123, (211, 111, 76)],
+    [BrightReddishViolet, "Bright reddish violet", 124, (146, 57, 120)],
+    [LightOrange, "Light orange", 125, (234, 184, 146)],
+    [TrBrightBluishViolet, "Tr. Bright bluish violet", 126, (165, 165, 203)],
+    [Gold, "Gold", 127, (220, 188, 129)],
+    [DarkNougat, "Dark nougat", 128, (174, 122, 89)],
+    [Silver, "Silver", 131, (156, 163, 168)],
+    [NeonOrange, "Neon orange", 133, (213, 115, 61)],
+    [NeonGreen, "Neon green", 134, (216, 221, 86)],
+    [SandBlue, "Sand blue", 135, (116, 134, 157)],
+    [SandViolet, "Sand violet", 136, (135, 124, 144)],
+    [MediumOrange, "Medium orange", 137, (224, 152, 100)],
+    [SandYellow, "Sand yellow", 138, (149, 138, 115)],
+    [EarthBlue, "Earth blue", 140, (32, 58, 86)],
+    [EarthGreen, "Earth green", 141, (39, 70, 45)],
+    [TrFluBlue, "Tr. Flu. Blue", 143, (207, 226, 247)],
+    [SandBlueMetallic, "Sand blue metallic", 145, (121, 136, 161)],
+    [SandVioletMetallic, "Sand violet metallic", 146, (149, 142, 163)],
+    [SandYellowMetallic, "Sand yellow metallic", 147, (147, 135, 103)],
+    [DarkGreyMetallic, "Dark grey metallic", 148, (87, 88, 87)],
+    [BlackMetallic, "Black metallic", 149, (22, 29, 50)],
+    [LightGreyMetallic, "Light grey metallic", 150, (171, 173, 172)],
+    [SandGreen, "Sand green", 151, (120, 144, 130)],
+    [SandRed, "Sand red", 153, (149, 121, 119)],
+    [DarkRed, "Dark red", 154, (123, 46, 47)],
+    [TrFluYellow, "Tr. Flu. Yellow", 157, (255, 246, 123)],
+    [TrFluRed, "Tr. Flu. Red", 158, (225, 164, 194)],
+    [GunMetallic, "Gun metallic", 168, (117, 108, 98)],
+    [RedFlipFlop, "Red flip/flop", 176, (151, 105, 91)],
+    [YellowFlipFlop, "Yellow flip/flop", 178, (180, 132, 85)],
+    [SilverFlipFlop, "Silver flip/flop", 179, (137, 135, 136)],
+    [Curry, "Curry", 180, (215, 169, 75)],
+    [FireYellow, "Fire Yellow", 190, (249, 214, 46)],
+    [FlameYellowishOrange, "Flame yellowish orange", 191, (232, 171, 45)],
+    [ReddishBrown, "Reddish brown", 192, (105, 64, 40)],
+    [FlameReddishOrange, "Flame reddish orange", 193, (207, 96, 36)],
+    [MediumStoneGrey, "Medium stone grey", 194, (163, 162, 165)],
+    [RoyalBlue, "Royal blue", 195, (70, 103, 164)],
+    [DarkRoyalBlue, "Dark Royal blue", 196, (35, 71, 139)],
+    [BrightReddishLilac, "Bright reddish lilac", 198, (142, 66, 133)],
+    [DarkStoneGrey, "Dark stone grey", 199, (99, 95, 98)],
+    [LemonMetalic, "Lemon metalic", 200, (130, 138, 93)],
+    [LightStoneGrey, "Light stone grey", 208, (229, 228, 223)],
+    [DarkCurry, "Dark Curry", 209, (176, 142, 68)],
+    [FadedGreen, "Faded green", 210, (112, 149, 120)],
+    [Turquoise, "Turquoise", 211, (121, 181, 181)],
+    [LightRoyalBlue, "Light Royal blue", 212, (159, 195, 233)],
+    [MediumRoyalBlue, "Medium Royal blue", 213, (108, 129, 183)],
+    [Rust, "Rust", 216, (144, 76, 42)],
+    [Brown, "Brown", 217, (124, 92, 70)],
+    [ReddishLilac, "Reddish lilac", 218, (150, 112, 159)],
+    [Lilac2, "Lilac", 219, (107, 98, 155)],
+    [LightLilac, "Light lilac", 220, (167, 169, 206)],
+    [BrightPurple, "Bright purple", 221, (205, 98, 152)],
+    [LightPurple, "Light purple", 222, (228, 173, 200)],
+    [LightPink, "Light pink", 223, (220, 144, 149)],
+    [LightBrickYellow, "Light brick yellow", 224, (240, 213, 160)],
+    [WarmYellowishOrange, "Warm yellowish orange", 225, (235, 184, 127)],
+    [CoolYellow, "Cool yellow", 226, (253, 234, 141)],
+    [DoveBlue, "Dove blue", 232, (125, 187, 221)],
+    [MediumLilac, "Medium lilac", 268, (52, 43, 117)],
+    [SlimeGreen, "Slime green", 301, (80, 109, 84)],
+    [SmokyGrey, "Smoky grey", 302, (91, 93, 105)],
+    [DarkBlue, "Dark blue", 303, (0, 16, 176)],
+    [ParsleyGreen, "Parsley green", 304, (44, 101, 29)],
+    [SteelBlue, "Steel blue", 305, (82, 124, 174)],
+    [StormBlue, "Storm blue", 306, (51, 88, 130)],
+    [Lapis, "Lapis", 307, (16, 42, 220)],
+    [DarkIndigo, "Dark indigo", 308, (61, 21, 133)],
+    [SeaGreen, "Sea green", 309, (52, 142, 64)],
+    [Shamrock, "Shamrock", 310, (91, 154, 76)],
+    [Fossil, "Fossil", 311, (159, 161, 172)],
+    [Mulberry, "Mulberry", 312, (89, 34, 89)],
+    [ForestGreen, "Forest green", 313, (31, 128, 29)],
+    [CadetBlue, "Cadet blue", 314, (159, 173, 192)],
+    [ElectricBlue, "Electric blue", 315, (9, 137, 207)],
+    [Eggplant, "Eggplant", 316, (123, 0, 123)],
+    [Moss, "Moss", 317, (124, 156, 107)],
+    [Artichoke, "Artichoke", 318, (138, 171, 133)],
+    [SageGreen, "Sage green", 319, (185, 196, 177)],
+    [GhostGrey, "Ghost grey", 320, (202, 203, 209)],
+    [Lilac, "Lilac", 321, (167, 94, 155)],
+    [Plum, "Plum", 322, (123, 47, 123)],
+    [Olivine, "Olivine", 323, (148, 190, 129)],
+    [LaurelGreen, "Laurel green", 324, (168, 189, 153)],
+    [QuillGrey, "Quill grey", 325, (223, 223, 222)],
+    [Crimson, "Crimson", 327, (151, 0, 0)],
+    [Mint, "Mint", 328, (177, 229, 166)],
+    [BabyBlue, "Baby blue", 329, (152, 194, 219)],
+    [CarnationPink, "Carnation pink", 330, (255, 152, 220)],
+    [Persimmon, "Persimmon", 331, (255, 89, 89)],
+    [Maroon, "Maroon", 332, (117, 0, 0)],
+    [Gold2, "Gold", 333, (239, 184, 56)],
+    [DaisyOrange, "Daisy orange", 334, (248, 217, 109)],
+    [Pearl, "Pearl", 335, (231, 231, 236)],
+    [Fog, "Fog", 336, (199, 212, 228)],
+    [Salmon, "Salmon", 337, (255, 148, 148)],
+    [TerraCotta, "Terra Cotta", 338, (190, 104, 98)],
+    [Cocoa, "Cocoa", 339, (86, 36, 36)],
+    [Wheat, "Wheat", 340, (241, 231, 199)],
+    [Buttermilk, "Buttermilk", 341, (254, 243, 187)],
+    [Mauve, "Mauve", 342, (224, 178, 208)],
+    [Sunrise, "Sunrise", 343, (212, 144, 189)],
+    [Tawny, "Tawny", 344, (150, 85, 85)],
+    [Rust2, "Rust", 345, (143, 76, 42)],
+    [Cashmere, "Cashmere", 346, (211, 190, 150)],
+    [Khaki, "Khaki", 347, (226, 220, 188)],
+    [LilyWhite, "Lily white", 348, (237, 234, 234)],
+    [Seashell, "Seashell", 349, (233, 218, 218)],
+    [Burgundy, "Burgundy", 350, (136, 62, 62)],
+    [Cork, "Cork", 351, (188, 155, 93)],
+    [Burlap, "Burlap", 352, (199, 172, 120)],
+    [Beige, "Beige", 353, (202, 191, 163)],
+    [Oyster, "Oyster", 354, (187, 179, 178)],
+    [PineCone, "Pine Cone", 355, (108, 88, 75)],
+    [FawnBrown, "Fawn brown", 356, (160, 132, 79)],
+    [HurricaneGrey, "Hurricane grey", 357, (149, 137, 136)],
+    [CloudyGrey, "Cloudy grey", 358, (171, 168, 158)],
+    [Linen, "Linen", 359, (175, 148, 131)],
+    [Copper, "Copper", 360, (150, 103, 102)],
+    [DirtBrown, "Dirt brown", 361, (86, 66, 54)],
+    [Bronze, "Bronze", 362, (126, 104, 63)],
+    [Flint, "Flint", 363, (105, 102, 92)],
+    [DarkTaupe, "Dark taupe", 364, (90, 76, 66)],
+    [BurntSienna, "Burnt Sienna", 365, (106, 57, 9)],
+    [InstitutionalWhite, "Institutional white", 1001, (248, 248, 248)],
+    [MidGray, "Mid gray", 1002, (205, 205, 205)],
+    [ReallyBlack, "Really black", 1003, (17, 17, 17)],
+    [ReallyRed, "Really red", 1004, (255, 0, 0)],
+    [DeepOrange, "Deep orange", 1005, (255, 176, 0)],
+    [Alder, "Alder", 1006, (180, 128, 255)],
+    [DustyRose, "Dusty Rose", 1007, (163, 75, 75)],
+    [Olive, "Olive", 1008, (193, 190, 66)],
+    [NewYeller, "New Yeller", 1009, (255, 255, 0)],
+    [ReallyBlue, "Really blue", 1010, (0, 0, 255)],
+    [NavyBlue, "Navy blue", 1011, (0, 32, 96)],
+    [DeepBlue, "Deep blue", 1012, (33, 84, 185)],
+    [Cyan, "Cyan", 1013, (4, 175, 236)],
+    [CGABrown, "CGA brown", 1014, (170, 85, 0)],
+    [Magenta, "Magenta", 1015, (170, 0, 170)],
+    [Pink, "Pink", 1016, (255, 102, 204)],
+    [DeepOrange2, "Deep orange", 1017, (255, 175, 0)],
+    [Teal, "Teal", 1018, (18, 238, 212)],
+    [Toothpaste, "Toothpaste", 1019, (0, 255, 255)],
+    [LimeGreen, "Lime green", 1020, (0, 255, 0)],
+    [Camo, "Camo", 1021, (58, 125, 21)],
+    [Grime, "Grime", 1022, (127, 142, 100)],
+    [Lavender, "Lavender", 1023, (140, 91, 159)],
+    [PastelLightBlue, "Pastel light blue", 1024, (175, 221, 255)],
+    [PastelOrange, "Pastel orange", 1025, (255, 201, 201)],
+    [PastelViolet, "Pastel violet", 1026, (177, 167, 255)],
+    [PastelBlueGreen, "Pastel blue-green", 1027, (159, 243, 233)],
+    [PastelGreen, "Pastel green", 1028, (204, 255, 204)],
+    [PastelYellow, "Pastel yellow", 1029, (255, 255, 204)],
+    [PastelBrown, "Pastel brown", 1030, (255, 204, 153)],
+    [RoyalPurple, "Royal purple", 1031, (98, 37, 209)],
+    [HotPink, "Hot pink", 1032, (255, 0, 191)],
 });
 
+impl BrickColor {
+    /// Convert from a BrickColor palette number to a BrickColor.
+    ///
+    /// This function should not be used for new code, it only exists because of
+    /// a misunderstanding of the range of valid BrickColor values.
+    ///
+    /// This function operates like `BrickColor.palette` within Roblox.
+    #[deprecated(
+        since = "1.9.0",
+        note = "Please use BrickColor::from_number instead"
+    )]
+    pub fn from_palette(value: u8) -> Option<BrickColor> {
+        match value {
+            1 => Some(BrickColor::SlimeGreen),
+            2 => Some(BrickColor::BrightBluishGreen),
+            3 => Some(BrickColor::Black),
+            4 => Some(BrickColor::DeepBlue),
+            5 => Some(BrickColor::DarkBlue),
+            6 => Some(BrickColor::NavyBlue),
+            7 => Some(BrickColor::ParsleyGreen),
+            8 => Some(BrickColor::DarkGreen),
+            9 => Some(BrickColor::Teal),
+            10 => Some(BrickColor::SmokyGrey),
+            11 => Some(BrickColor::SteelBlue),
+            12 => Some(BrickColor::StormBlue),
+            13 => Some(BrickColor::Lapis),
+            14 => Some(BrickColor::DarkIndigo),
+            15 => Some(BrickColor::Camo),
+            16 => Some(BrickColor::SeaGreen),
+            17 => Some(BrickColor::Shamrock),
+            18 => Some(BrickColor::Toothpaste),
+            19 => Some(BrickColor::SandBlue),
+            20 => Some(BrickColor::MediumBlue),
+            21 => Some(BrickColor::BrightBlue),
+            22 => Some(BrickColor::ReallyBlue),
+            23 => Some(BrickColor::Mulberry),
+            24 => Some(BrickColor::ForestGreen),
+            25 => Some(BrickColor::BrightGreen),
+            26 => Some(BrickColor::Grime),
+            27 => Some(BrickColor::LimeGreen),
+            28 => Some(BrickColor::PastelBlueGreen),
+            29 => Some(BrickColor::Fossil),
+            30 => Some(BrickColor::ElectricBlue),
+            31 => Some(BrickColor::Lavender),
+            32 => Some(BrickColor::RoyalPurple),
+            33 => Some(BrickColor::Eggplant),
+            34 => Some(BrickColor::SandGreen),
+            35 => Some(BrickColor::Moss),
+            36 => Some(BrickColor::Artichoke),
+            37 => Some(BrickColor::SageGreen),
+            38 => Some(BrickColor::PastelLightBlue),
+            39 => Some(BrickColor::CadetBlue),
+            40 => Some(BrickColor::Cyan),
+            41 => Some(BrickColor::Alder),
+            42 => Some(BrickColor::Lilac),
+            43 => Some(BrickColor::Plum),
+            44 => Some(BrickColor::BrightViolet),
+            45 => Some(BrickColor::Olive),
+            46 => Some(BrickColor::BrYellowishGreen),
+            47 => Some(BrickColor::Olivine),
+            48 => Some(BrickColor::LaurelGreen),
+            49 => Some(BrickColor::QuillGrey),
+            50 => Some(BrickColor::GhostGrey),
+            51 => Some(BrickColor::PastelBlue),
+            52 => Some(BrickColor::PastelViolet),
+            53 => Some(BrickColor::Pink),
+            54 => Some(BrickColor::HotPink),
+            55 => Some(BrickColor::Magenta),
+            56 => Some(BrickColor::Crimson),
+            57 => Some(BrickColor::DeepOrange),
+            58 => Some(BrickColor::NewYeller),
+            59 => Some(BrickColor::MediumGreen),
+            60 => Some(BrickColor::Mint),
+            61 => Some(BrickColor::PastelGreen),
+            62 => Some(BrickColor::LightStoneGrey),
+            63 => Some(BrickColor::LightBlue),
+            64 => Some(BrickColor::BabyBlue),
+            65 => Some(BrickColor::CarnationPink),
+            66 => Some(BrickColor::Persimmon),
+            67 => Some(BrickColor::ReallyRed),
+            68 => Some(BrickColor::BrightRed),
+            69 => Some(BrickColor::Maroon),
+            70 => Some(BrickColor::Gold),
+            71 => Some(BrickColor::BrightYellow),
+            72 => Some(BrickColor::DaisyOrange),
+            73 => Some(BrickColor::CoolYellow),
+            74 => Some(BrickColor::PastelYellow),
+            75 => Some(BrickColor::Pearl),
+            76 => Some(BrickColor::Fog),
+            77 => Some(BrickColor::Mauve),
+            78 => Some(BrickColor::Sunrise),
+            79 => Some(BrickColor::TerraCotta),
+            80 => Some(BrickColor::DustyRose),
+            81 => Some(BrickColor::Cocoa),
+            82 => Some(BrickColor::NeonOrange),
+            83 => Some(BrickColor::BrightOrange),
+            84 => Some(BrickColor::Wheat),
+            85 => Some(BrickColor::Buttermilk),
+            86 => Some(BrickColor::InstitutionalWhite),
+            87 => Some(BrickColor::White),
+            88 => Some(BrickColor::LightReddishViolet),
+            89 => Some(BrickColor::PastelOrange),
+            90 => Some(BrickColor::Salmon),
+            91 => Some(BrickColor::Tawny),
+            92 => Some(BrickColor::Rust),
+            93 => Some(BrickColor::CGABrown),
+            94 => Some(BrickColor::BrYellowishOrange),
+            95 => Some(BrickColor::Cashmere),
+            96 => Some(BrickColor::Khaki),
+            97 => Some(BrickColor::LilyWhite),
+            98 => Some(BrickColor::Seashell),
+            99 => Some(BrickColor::PastelBrown),
+            100 => Some(BrickColor::LightOrange),
+            101 => Some(BrickColor::MediumRed),
+            102 => Some(BrickColor::Burgundy),
+            103 => Some(BrickColor::ReddishBrown),
+            104 => Some(BrickColor::Cork),
+            105 => Some(BrickColor::Burlap),
+            106 => Some(BrickColor::Beige),
+            107 => Some(BrickColor::Oyster),
+            108 => Some(BrickColor::MidGray),
+            109 => Some(BrickColor::BrickYellow),
+            110 => Some(BrickColor::Nougat),
+            111 => Some(BrickColor::Brown),
+            112 => Some(BrickColor::PineCone),
+            113 => Some(BrickColor::FawnBrown),
+            114 => Some(BrickColor::SandRed),
+            115 => Some(BrickColor::HurricaneGrey),
+            116 => Some(BrickColor::CloudyGrey),
+            117 => Some(BrickColor::Linen),
+            118 => Some(BrickColor::Copper),
+            119 => Some(BrickColor::DarkOrange),
+            120 => Some(BrickColor::DirtBrown),
+            121 => Some(BrickColor::Bronze),
+            122 => Some(BrickColor::DarkStoneGrey),
+            123 => Some(BrickColor::MediumStoneGrey),
+            124 => Some(BrickColor::Flint),
+            125 => Some(BrickColor::DarkTaupe),
+            126 => Some(BrickColor::BurntSienna),
+            127 => Some(BrickColor::ReallyBlack),
+
+            _ => None,
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
 
     #[test]
     fn from_name() {
-        assert_eq!(BrickColor::from_name("Pastel brown").unwrap().to_string(), "Pastel brown");
+        assert_eq!(BrickColor::from_name("Pastel brown"), Some(BrickColor::PastelBrown));
     }
 
     #[test]
+    #[allow(deprecated)]
     fn from_palette() {
-        assert_eq!(BrickColor::from_palette(99).unwrap().to_string(), "Pastel brown");
+        assert_eq!(BrickColor::from_palette(99), Some(BrickColor::PastelBrown));
+    }
+
+    #[test]
+    fn from_number() {
+        assert_eq!(BrickColor::from_number(1030), Some(BrickColor::PastelBrown));
     }
 
     #[test]
@@ -273,12 +481,12 @@ mod tests {
 
     #[test]
     fn test_round_trip() {
-        let value = BrickColor::from_name("Pastel brown").unwrap();
+        let value = BrickColor::PastelBrown;
 
         let serialized = serde_json::to_string(&value).unwrap();
-        assert_eq!(serialized, "\"Pastel brown\"");
+        assert_eq!(serialized, "1030");
 
-        let deserialized = serde_json::from_str(&serialized).unwrap();
-        assert_eq!(value, deserialized);
+        let deserialized: BrickColor = serde_json::from_str(&serialized).unwrap();
+        assert_eq!(deserialized, value);
     }
 }
diff --git a/rbx_dom_weak/src/value.rs b/rbx_dom_weak/src/value.rs
index afa7ad6..081bf83 100644
--- a/rbx_dom_weak/src/value.rs
+++ b/rbx_dom_weak/src/value.rs
@@ -241,13 +241,15 @@ impl RbxValue {
             // ints for some reason, so we downcast them if they're in range for
             // BrickColor.
             (RbxValue::Int32 { value }, RbxValueType::BrickColor) => {
-                if *value > 255 || *value < 0 {
+                if *value < 0 || *value > std::u16::MAX as i32 {
                     return Failed;
                 }
 
-                match BrickColor::from_palette(*value as u8) {
+                match BrickColor::from_number(*value as u16) {
                     Some(converted) => Converted(RbxValue::BrickColor { value: converted }),
-                    None => Failed,
+                    None => {
+                        Failed
+                    }
                 }
             }
 
diff --git a/rbx_xml/CHANGELOG.md b/rbx_xml/CHANGELOG.md
index 522c311..0a9c85c 100644
--- a/rbx_xml/CHANGELOG.md
+++ b/rbx_xml/CHANGELOG.md
@@ -1,6 +1,7 @@
 # rbx_xml Changelog
 
 ## Unreleased
+* Added support for reading and writing `BrickColor` values.
 
 ## 0.10.0 (2019-06-10)
 * Added support for INF and NAN values in compound types like Vector2 ([#62](https://github.com/LPGhatguy/rbx-dom/pull/62))
diff --git a/rbx_xml/Cargo.toml b/rbx_xml/Cargo.toml
index 0152219..0b87ff1 100644
--- a/rbx_xml/Cargo.toml
+++ b/rbx_xml/Cargo.toml
@@ -12,7 +12,7 @@ edition = "2018"
 [dependencies]
 base64 = "0.10.0"
 log = "0.4.6"
-rbx_dom_weak = { version = "1.8.0", path = "../rbx_dom_weak" }
+rbx_dom_weak = { version = "1.8.2", path = "../rbx_dom_weak" }
 rbx_reflection = { version = "3.1.388", path = "../rbx_reflection" }
 xml-rs = "0.8"
 
diff --git a/rbx_xml/src/types/mod.rs b/rbx_xml/src/types/mod.rs
index 7f9ba75..b21bef2 100644
--- a/rbx_xml/src/types/mod.rs
+++ b/rbx_xml/src/types/mod.rs
@@ -84,6 +84,11 @@ macro_rules! declare_rbx_types {
             match value {
                 $(RbxValue::$rbx_type { value } => <$typedef>::write_xml(writer, xml_property_name, value),)*
 
+                // BrickColor values just encode as 32-bit ints, and have no
+                // unique appearance for reading.
+                RbxValue::BrickColor { value } =>
+                    self::numbers::Int32Type::write_xml(writer, xml_property_name, &(*value as i32)),
+
                 RbxValue::Ref { value } => write_ref(writer, xml_property_name, value, state),
                 RbxValue::SharedString { value } => write_shared_string(writer, xml_property_name, value, state),
 


Test patch:
diff --git a/rbx_dom_weak/tests/value_conversion.rs b/rbx_dom_weak/tests/value_conversion.rs
index d0d50b1..af4565b 100644
--- a/rbx_dom_weak/tests/value_conversion.rs
+++ b/rbx_dom_weak/tests/value_conversion.rs
@@ -52,7 +52,7 @@ fn color3uint8_to_color3() {
 
 #[test]
 fn int_to_brickcolor() {
-    let eggplant = RbxValue::Int32 { value: 33 };
+    let eggplant = RbxValue::Int32 { value: 316 };
     assert_eq!(
         eggplant.try_convert_ref(RbxValueType::BrickColor),
         RbxValueConversion::Converted(RbxValue::BrickColor {
@@ -66,7 +66,7 @@ fn int_to_brickcolor() {
         RbxValueConversion::Failed,
     );
 
-    let out_of_range = RbxValue::Int32 { value: 300 };
+    let out_of_range = RbxValue::Int32 { value: 9999999 };
     assert_eq!(
         out_of_range.try_convert_ref(RbxValueType::BrickColor),
         RbxValueConversion::Failed,
diff --git a/rbx_xml/test-files/spawn-location.rbxmx b/rbx_xml/test-files/spawn-location.rbxmx
new file mode 100644
index 0000000..cd50323
--- /dev/null
+++ b/rbx_xml/test-files/spawn-location.rbxmx
@@ -0,0 +1,85 @@
+<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
+	<Meta name="ExplicitAutoJoints">true</Meta>
+	<External>null</External>
+	<External>nil</External>
+	<Item class="SpawnLocation" referent="RBXC6BFC8C4B4694D44859B118720F305BA">
+		<Properties>
+			<bool name="AllowTeamChangeOnTouch">false</bool>
+			<bool name="Anchored">true</bool>
+			<float name="BackParamA">-0.5</float>
+			<float name="BackParamB">0.5</float>
+			<token name="BackSurface">0</token>
+			<token name="BackSurfaceInput">0</token>
+			<float name="BottomParamA">-0.5</float>
+			<float name="BottomParamB">0.5</float>
+			<token name="BottomSurface">0</token>
+			<token name="BottomSurfaceInput">0</token>
+			<CoordinateFrame name="CFrame">
+				<X>-3</X>
+				<Y>0.500001013</Y>
+				<Z>-12</Z>
+				<R00>1</R00>
+				<R01>0</R01>
+				<R02>0</R02>
+				<R10>0</R10>
+				<R11>1</R11>
+				<R12>0</R12>
+				<R20>0</R20>
+				<R21>0</R21>
+				<R22>1</R22>
+			</CoordinateFrame>
+			<bool name="CanCollide">true</bool>
+			<bool name="CastShadow">true</bool>
+			<int name="CollisionGroupId">0</int>
+			<Color3uint8 name="Color3uint8">4288914085</Color3uint8>
+			<PhysicalProperties name="CustomPhysicalProperties">
+				<CustomPhysics>false</CustomPhysics>
+			</PhysicalProperties>
+			<int name="Duration">10</int>
+			<bool name="Enabled">true</bool>
+			<float name="FrontParamA">-0.5</float>
+			<float name="FrontParamB">0.5</float>
+			<token name="FrontSurface">0</token>
+			<token name="FrontSurfaceInput">0</token>
+			<float name="LeftParamA">-0.5</float>
+			<float name="LeftParamB">0.5</float>
+			<token name="LeftSurface">0</token>
+			<token name="LeftSurfaceInput">0</token>
+			<bool name="Locked">false</bool>
+			<bool name="Massless">false</bool>
+			<token name="Material">256</token>
+			<string name="Name">SpawnLocation</string>
+			<bool name="Neutral">true</bool>
+			<float name="Reflectance">0</float>
+			<float name="RightParamA">-0.5</float>
+			<float name="RightParamB">0.5</float>
+			<token name="RightSurface">0</token>
+			<token name="RightSurfaceInput">0</token>
+			<int name="RootPriority">0</int>
+			<Vector3 name="RotVelocity">
+				<X>0</X>
+				<Y>0</Y>
+				<Z>0</Z>
+			</Vector3>
+			<BinaryString name="Tags"></BinaryString>
+			<int name="TeamColor">194</int>
+			<float name="TopParamA">-0.5</float>
+			<float name="TopParamB">0.5</float>
+			<token name="TopSurface">0</token>
+			<token name="TopSurfaceInput">0</token>
+			<float name="Transparency">0</float>
+			<Vector3 name="Velocity">
+				<X>0</X>
+				<Y>0</Y>
+				<Z>0</Z>
+			</Vector3>
+			<token name="formFactorRaw">1</token>
+			<token name="shape">1</token>
+			<Vector3 name="size">
+				<X>12</X>
+				<Y>1</Y>
+				<Z>12</Z>
+			</Vector3>
+		</Properties>
+	</Item>
+</roblox>
\ No newline at end of file
diff --git a/rbx_xml/test-files/team-lilac.rbxmx b/rbx_xml/test-files/team-lilac.rbxmx
new file mode 100644
index 0000000..9d3c1e4
--- /dev/null
+++ b/rbx_xml/test-files/team-lilac.rbxmx
@@ -0,0 +1,13 @@
+<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
+	<Meta name="ExplicitAutoJoints">true</Meta>
+	<External>null</External>
+	<External>nil</External>
+	<Item class="Team" referent="RBX219DDC7F4241474C955B10FD50F29DFF">
+		<Properties>
+			<bool name="AutoAssignable">true</bool>
+			<string name="Name">Team</string>
+			<BinaryString name="Tags"></BinaryString>
+			<int name="TeamColor">219</int>
+		</Properties>
+	</Item>
+</roblox>
\ No newline at end of file
diff --git a/rbx_xml/test-files/team.rbxmx b/rbx_xml/test-files/team.rbxmx
new file mode 100644
index 0000000..e5d2194
--- /dev/null
+++ b/rbx_xml/test-files/team.rbxmx
@@ -0,0 +1,13 @@
+<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
+	<Meta name="ExplicitAutoJoints">true</Meta>
+	<External>null</External>
+	<External>nil</External>
+	<Item class="Team" referent="RBX219DDC7F4241474C955B10FD50F29DFF">
+		<Properties>
+			<bool name="AutoAssignable">true</bool>
+			<string name="Name">Team</string>
+			<BinaryString name="Tags"></BinaryString>
+			<int name="TeamColor">1020</int>
+		</Properties>
+	</Item>
+</roblox>
\ No newline at end of file
diff --git a/rbx_xml/tests/brick_color.rs b/rbx_xml/tests/brick_color.rs
new file mode 100644
index 0000000..d832105
--- /dev/null
+++ b/rbx_xml/tests/brick_color.rs
@@ -0,0 +1,97 @@
+use rbx_dom_weak::{BrickColor, RbxValue};
+
+static SPAWN_LOCATION: &[u8] = include_bytes!("../test-files/spawn-location.rbxmx");
+static TEAM: &[u8] = include_bytes!("../test-files/team.rbxmx");
+static TEAM_LILAC: &[u8] = include_bytes!("../test-files/team-lilac.rbxmx");
+
+#[test]
+fn spawn_location() {
+    let _ = env_logger::try_init();
+
+    let tree = rbx_xml::from_reader_default(SPAWN_LOCATION).unwrap();
+    let root_id = tree.get_root_id();
+
+    let root_instance = tree.get_instance(root_id).unwrap();
+    let spawn_id = root_instance.get_children_ids()[0];
+    let spawn = tree.get_instance(spawn_id).unwrap();
+
+    assert_eq!(spawn.name, "SpawnLocation");
+    assert_eq!(spawn.class_name, "SpawnLocation");
+    assert_eq!(spawn.properties.get("FormFactor"), Some(&RbxValue::Enum { value: 1 }));
+    assert_eq!(spawn.properties.get("formFactorRaw"), None);
+    assert_eq!(spawn.properties.get("TeamColor"), Some(&RbxValue::BrickColor {
+        value: BrickColor::MediumStoneGrey,
+    }));
+}
+
+/// Asserts that 'Team.TeamColor' deserializes correctly as a BrickColor.
+#[test]
+fn team() {
+    let _ = env_logger::try_init();
+
+    let tree = rbx_xml::from_reader_default(TEAM).unwrap();
+    let root_id = tree.get_root_id();
+
+    let root_instance = tree.get_instance(root_id).unwrap();
+    let team_id = root_instance.get_children_ids()[0];
+    let team = tree.get_instance(team_id).unwrap();
+
+    assert_eq!(team.name, "Team");
+    assert_eq!(team.class_name, "Team");
+    assert_eq!(team.properties.get("TeamColor"), Some(&RbxValue::BrickColor {
+        value: BrickColor::LimeGreen,
+    }));
+}
+
+/// Roblox has name collisions for BrickColors!
+///
+/// This test catches one of them, Lilac and Lilac, but 'Gold', 'Deep
+/// orange', and 'Rust' (haha) also collide.
+///
+/// rbx_dom_weak reserves the enum variant for the version that Roblox picks
+/// when `BrickColor.new("Lilac")` is run. The other variant has '2'
+/// appended.
+#[test]
+fn team_lilac() {
+    let _ = env_logger::try_init();
+
+    let tree = rbx_xml::from_reader_default(TEAM_LILAC).unwrap();
+    let root_id = tree.get_root_id();
+
+    let root_instance = tree.get_instance(root_id).unwrap();
+    let team_id = root_instance.get_children_ids()[0];
+    let team = tree.get_instance(team_id).unwrap();
+
+    assert_eq!(team.name, "Team");
+    assert_eq!(team.class_name, "Team");
+
+    assert_ne!(team.properties.get("TeamColor"), Some(&RbxValue::BrickColor {
+        value: BrickColor::Lilac, // This Lilac has a value of 321
+    }));
+    assert_eq!(team.properties.get("TeamColor"), Some(&RbxValue::BrickColor {
+        value: BrickColor::Lilac2, // This Lilac has a value of 219
+    }));
+}
+
+/// When BrickColor values are deserialized without reflection information, they
+/// should turn into regular Int32 values.
+#[test]
+fn team_no_reflection() {
+    let _ = env_logger::try_init();
+
+    let options = rbx_xml::DecodeOptions::new()
+        .property_behavior(rbx_xml::DecodePropertyBehavior::NoReflection);
+
+    let tree = rbx_xml::from_reader(TEAM, options).unwrap();
+    let root_id = tree.get_root_id();
+
+    let root_instance = tree.get_instance(root_id).unwrap();
+    let team_id = root_instance.get_children_ids()[0];
+    let team = tree.get_instance(team_id).unwrap();
+
+    assert_eq!(team.name, "Team");
+    assert_eq!(team.class_name, "Team");
+    assert_eq!(team.properties.get("TeamColor"), Some(&RbxValue::Int32 {
+        value: 1020,
+    }));
+}
\ No newline at end of file
diff --git a/rbx_xml/tests/round_trip.rs b/rbx_xml/tests/round_trip.rs
index 32882bc..cc4b1d5 100644
--- a/rbx_xml/tests/round_trip.rs
+++ b/rbx_xml/tests/round_trip.rs
@@ -13,6 +13,8 @@ static TEST_MODELS: &[&str] = &[
     include_str!("../test-files/part-referent.rbxmx"),
     include_str!("../test-files/parts.rbxmx"),
     include_str!("../test-files/sound.rbxmx"),
+    include_str!("../test-files/spawn-location.rbxmx"),
+    include_str!("../test-files/team.rbxmx"),
     include_str!("../test-files/terrain.rbxmx"),
     include_str!("../test-files/union.rbxmx"),
 ];
@@ -23,14 +25,18 @@ fn round_trip() {
 
     for (index, model_source) in TEST_MODELS.iter().enumerate() {
         info!("Decoding #{}...", index);
-        let tree = rbx_xml::from_str_default(model_source).unwrap();
+        let tree = rbx_xml::from_str_default(model_source)
+            .expect("Couldn't parse XML model");
+
         let root_id = tree.get_root_id();
 
         info!("Encoding #{}...", index);
         let mut buffer = Vec::new();
-        rbx_xml::to_writer_default(Cursor::new(&mut buffer), &tree, &[root_id]).unwrap();
+        rbx_xml::to_writer_default(Cursor::new(&mut buffer), &tree, &[root_id])
+            .expect("Couldn't write XML model");
 
         info!("Re-Decoding #{}...", index);
-        rbx_xml::from_reader_default(buffer.as_slice()).unwrap();
+        rbx_xml::from_reader_default(buffer.as_slice())
+            .expect("Couldn't re-read XML model");
     }
 }
\ No newline at end of file