module Rattletrap.Type.Attribute where import qualified Control.Exception as Exception import qualified Data.Map as Map import qualified Rattletrap.BitGet as BitGet import qualified Rattletrap.BitPut as BitPut import qualified Rattletrap.Exception.MissingAttributeLimit as MissingAttributeLimit import qualified Rattletrap.Exception.MissingAttributeName as MissingAttributeName import qualified Rattletrap.Exception.UnknownActor as UnknownActor import qualified Rattletrap.Schema as Schema import qualified Rattletrap.Type.AttributeValue as AttributeValue import qualified Rattletrap.Type.ClassAttributeMap as ClassAttributeMap import qualified Rattletrap.Type.CompressedWord as CompressedWord import qualified Rattletrap.Type.Str as Str import qualified Rattletrap.Type.U32 as U32 import qualified Rattletrap.Type.Version as Version import qualified Rattletrap.Utility.Json as Json data Attribute = Attribute { id :: CompressedWord.CompressedWord, -- | Read-only! Changing an attribute's name requires editing the class -- attribute map. name :: Str.Str, value :: AttributeValue.AttributeValue } deriving (Eq, Show) instance Json.FromJSON Attribute where parseJSON = Json.withObject "Attribute" $ \object -> do id_ <- Json.required object "id" name <- Json.required object "name" value <- Json.required object "value" pure Attribute {Rattletrap.Type.Attribute.id = id_, name, value} instance Json.ToJSON Attribute where toJSON x = Json.object [ Json.pair "id" $ Rattletrap.Type.Attribute.id x, Json.pair "name" $ name x, Json.pair "value" $ value x ] schema :: Schema.Schema schema = Schema.named "attribute" $ Schema.object [ (Json.pair "id" $ Schema.ref CompressedWord.schema, True), (Json.pair "name" $ Schema.ref Str.schema, True), (Json.pair "value" $ Schema.ref AttributeValue.schema, True) ] bitPut :: Attribute -> BitPut.BitPut bitPut attribute = CompressedWord.bitPut (Rattletrap.Type.Attribute.id attribute) <> AttributeValue.bitPut (value attribute) bitGet :: Version.Version -> Maybe Str.Str -> ClassAttributeMap.ClassAttributeMap -> Map.Map CompressedWord.CompressedWord U32.U32 -> CompressedWord.CompressedWord -> BitGet.BitGet Attribute bitGet version buildVersion classes actors actor = BitGet.label "Attribute" $ do attributes <- lookupAttributeMap classes actors actor limit <- lookupAttributeIdLimit attributes actor id_ <- BitGet.label "id" $ CompressedWord.bitGet limit name <- lookupAttributeName classes attributes id_ value <- BitGet.label "value" $ AttributeValue.bitGet version buildVersion (ClassAttributeMap.objectMap classes) name pure Attribute {Rattletrap.Type.Attribute.id = id_, name, value} lookupAttributeMap :: ClassAttributeMap.ClassAttributeMap -> Map.Map CompressedWord.CompressedWord U32.U32 -> CompressedWord.CompressedWord -> BitGet.BitGet (Map.Map U32.U32 U32.U32) lookupAttributeMap classes actors actor = fromMaybe (UnknownActor.UnknownActor $ CompressedWord.value actor) (ClassAttributeMap.getAttributeMap classes actors actor) lookupAttributeIdLimit :: Map.Map U32.U32 U32.U32 -> CompressedWord.CompressedWord -> BitGet.BitGet Word lookupAttributeIdLimit attributes actor = fromMaybe (MissingAttributeLimit.MissingAttributeLimit $ CompressedWord.value actor) (ClassAttributeMap.getAttributeIdLimit attributes) lookupAttributeName :: ClassAttributeMap.ClassAttributeMap -> Map.Map U32.U32 U32.U32 -> CompressedWord.CompressedWord -> BitGet.BitGet Str.Str lookupAttributeName classes attributes attribute = fromMaybe (MissingAttributeName.MissingAttributeName $ CompressedWord.value attribute) (ClassAttributeMap.getAttributeName classes attributes attribute) fromMaybe :: (Exception.Exception e) => e -> Maybe a -> BitGet.BitGet a fromMaybe message = maybe (BitGet.throw message) pure