rattletrap-10.0.0: src/lib/Rattletrap/Type/PropertyValue.hs
module Rattletrap.Type.PropertyValue where
import qualified Data.Foldable as Foldable
import qualified Data.Text as Text
import qualified Rattletrap.ByteGet as ByteGet
import qualified Rattletrap.BytePut as BytePut
import qualified Rattletrap.Schema as Schema
import qualified Rattletrap.Type.Dictionary as Dictionary
import qualified Rattletrap.Type.F32 as F32
import qualified Rattletrap.Type.I32 as I32
import qualified Rattletrap.Type.List as List
import qualified Rattletrap.Type.Str as Str
import qualified Rattletrap.Type.U64 as U64
import qualified Rattletrap.Type.U8 as U8
import qualified Rattletrap.Utility.Json as Json
import Rattletrap.Utility.Monad
data PropertyValue a
= Array (List.List (Dictionary.Dictionary a))
-- ^ Yes, a list of dictionaries. No, it doesn't make sense. These usually
-- only have one element.
| Bool U8.U8
| Byte Str.Str (Maybe Str.Str)
-- ^ This is a strange name for essentially a key-value pair.
| Float F32.F32
| Int I32.I32
| Name Str.Str
-- ^ It's unclear how exactly this is different than a 'StrProperty'.
| QWord U64.U64
| Str Str.Str
deriving (Eq, Show)
instance Json.FromJSON a => Json.FromJSON (PropertyValue a) where
parseJSON = Json.withObject "PropertyValue" $ \object -> Foldable.asum
[ Array <$> Json.required object "array"
, Bool <$> Json.required object "bool"
, uncurry Byte <$> Json.required object "byte"
, Float <$> Json.required object "float"
, Int <$> Json.required object "int"
, Name <$> Json.required object "name"
, QWord <$> Json.required object "q_word"
, Str <$> Json.required object "str"
]
instance Json.ToJSON a => Json.ToJSON (PropertyValue a) where
toJSON x = case x of
Array y -> Json.object [Json.pair "array" y]
Bool y -> Json.object [Json.pair "bool" y]
Byte y z -> Json.object [Json.pair "byte" (y, z)]
Float y -> Json.object [Json.pair "float" y]
Int y -> Json.object [Json.pair "int" y]
Name y -> Json.object [Json.pair "name" y]
QWord y -> Json.object [Json.pair "q_word" y]
Str y -> Json.object [Json.pair "str" y]
schema :: Schema.Schema -> Schema.Schema
schema s =
Schema.named ("property-value-" <> Text.unpack (Schema.name s))
. Schema.oneOf
$ fmap
(\(k, v) -> Schema.object [(Json.pair k v, True)])
[ ("array", Schema.json . List.schema $ Dictionary.schema s)
, ("bool", Schema.ref U8.schema)
, ( "byte"
, Schema.tuple
[Schema.ref Str.schema, Schema.json $ Schema.maybe Str.schema]
)
, ("float", Schema.ref F32.schema)
, ("int", Schema.ref I32.schema)
, ("name", Schema.ref Str.schema)
, ("q_word", Schema.ref U64.schema)
, ("str", Schema.ref Str.schema)
]
bytePut :: (a -> BytePut.BytePut) -> PropertyValue a -> BytePut.BytePut
bytePut putProperty value = case value of
Array x -> List.bytePut (Dictionary.bytePut putProperty) x
Bool x -> U8.bytePut x
Byte k mv -> Str.bytePut k <> foldMap Str.bytePut mv
Float x -> F32.bytePut x
Int x -> I32.bytePut x
Name x -> Str.bytePut x
QWord x -> U64.bytePut x
Str x -> Str.bytePut x
byteGet :: ByteGet.ByteGet a -> Str.Str -> ByteGet.ByteGet (PropertyValue a)
byteGet getProperty kind = case Str.toString kind of
"ArrayProperty" -> Array <$> List.byteGet (Dictionary.byteGet getProperty)
"BoolProperty" -> Bool <$> U8.byteGet
"ByteProperty" -> do
k <- Str.byteGet
Byte k <$> whenMaybe (Str.toString k /= "OnlinePlatform_Steam") Str.byteGet
"FloatProperty" -> Float <$> F32.byteGet
"IntProperty" -> Int <$> I32.byteGet
"NameProperty" -> Name <$> Str.byteGet
"QWordProperty" -> QWord <$> U64.byteGet
"StrProperty" -> Str <$> Str.byteGet
_ -> fail ("[RT07] don't know how to read property value " <> show kind)