From 0df7b797a3b08e0252689955503817df87f56da8 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 29 Aug 2018 14:00:44 -0700 Subject: [PATCH 01/21] Fixed parsing TAGame.PRI_TA:SpectatorShortcut --- library/Rattletrap/Data.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/Rattletrap/Data.hs b/library/Rattletrap/Data.hs index 011c0106..53ac5f04 100644 --- a/library/Rattletrap/Data.hs +++ b/library/Rattletrap/Data.hs @@ -292,6 +292,7 @@ rawAttributeTypes = , ("TAGame.PRI_TA:ReplicatedGameEvent", AttributeTypeFlaggedInt) , ("TAGame.PRI_TA:ReplicatedWorstNetQualityBeyondLatency", AttributeTypeByte) , ("TAGame.PRI_TA:SecondaryTitle", AttributeTypeTitle) + , ("TAGame.PRI_TA:SpectatorShortcut", AttributeTypeInt) , ("TAGame.PRI_TA:SteeringSensitivity", AttributeTypeFloat) , ("TAGame.PRI_TA:TimeTillItem", AttributeTypeInt) , ("TAGame.PRI_TA:Title", AttributeTypeInt) From dde0e5488eb73648455a17e82127e7ba11cb7ad8 Mon Sep 17 00:00:00 2001 From: Barbosicks Date: Thu, 30 Aug 2018 03:03:22 +0100 Subject: [PATCH 02/21] Try this --- library/Rattletrap/Decode/ProductAttribute.hs | 5 +++++ library/Rattletrap/Type/ProductAttribute.hs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/library/Rattletrap/Decode/ProductAttribute.hs b/library/Rattletrap/Decode/ProductAttribute.hs index 26a1a2b1..def36b36 100644 --- a/library/Rattletrap/Decode/ProductAttribute.hs +++ b/library/Rattletrap/Decode/ProductAttribute.hs @@ -36,6 +36,7 @@ decodeProductAttributeBits version objectMap = do Just name -> case fromStr name of "TAGame.ProductAttribute_Painted_TA" -> Just <$> decodePainted version "TAGame.ProductAttribute_UserColor_TA" -> decodeColor + "TAGame.ProductAttribute_TitleID_TA" -> decodeTitle _ -> fail ( "unknown object name " @@ -55,3 +56,7 @@ decodeColor :: DecodeBits (Maybe (Either CompressedWord Word32)) decodeColor = do hasValue <- getBool decodeWhen hasValue (Right <$> getWord32be 31) + +decodeTitle :: DecodeBits (Maybe Str) +decodeTitle = do + decodeStr \ No newline at end of file diff --git a/library/Rattletrap/Type/ProductAttribute.hs b/library/Rattletrap/Type/ProductAttribute.hs index 85848efe..a249a6fe 100644 --- a/library/Rattletrap/Type/ProductAttribute.hs +++ b/library/Rattletrap/Type/ProductAttribute.hs @@ -14,7 +14,7 @@ data ProductAttribute = ProductAttribute , productAttributeObjectId :: Word32le , productAttributeObjectName :: Maybe Str -- ^ read-only - , productAttributeValue :: Maybe (Either CompressedWord Word32) + , productAttributeValue :: Maybe (Either CompressedWord Word32 Str) } deriving (Eq, Ord, Show) $(deriveJson ''ProductAttribute) From 984bf7c1c01b86b9585cf84e0d4b8a17b3fe9acf Mon Sep 17 00:00:00 2001 From: Barbosicks Date: Thu, 30 Aug 2018 03:04:40 +0100 Subject: [PATCH 03/21] woops --- library/Rattletrap/Decode/ProductAttribute.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/Rattletrap/Decode/ProductAttribute.hs b/library/Rattletrap/Decode/ProductAttribute.hs index def36b36..31a8d68d 100644 --- a/library/Rattletrap/Decode/ProductAttribute.hs +++ b/library/Rattletrap/Decode/ProductAttribute.hs @@ -57,6 +57,5 @@ decodeColor = do hasValue <- getBool decodeWhen hasValue (Right <$> getWord32be 31) -decodeTitle :: DecodeBits (Maybe Str) -decodeTitle = do - decodeStr \ No newline at end of file +decodeTitle :: Decode Str +decodeTitle = decodeStr \ No newline at end of file From cbbab171252587ecdb611e39a3804c118b723103 Mon Sep 17 00:00:00 2001 From: Barbosicks Date: Thu, 30 Aug 2018 03:05:22 +0100 Subject: [PATCH 04/21] Import missing --- library/Rattletrap/Decode/ProductAttribute.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/Rattletrap/Decode/ProductAttribute.hs b/library/Rattletrap/Decode/ProductAttribute.hs index 31a8d68d..ce21fdfc 100644 --- a/library/Rattletrap/Decode/ProductAttribute.hs +++ b/library/Rattletrap/Decode/ProductAttribute.hs @@ -8,6 +8,7 @@ import Rattletrap.Decode.Common import Rattletrap.Decode.CompressedWord import Rattletrap.Decode.Word32le import Rattletrap.Decode.Word8le +import Rattletrap.Decode.Str import Rattletrap.Type.Common import Rattletrap.Type.CompressedWord import Rattletrap.Type.ProductAttribute From bdcd4b9601801ba670e4f75fa092d45cd89c33ce Mon Sep 17 00:00:00 2001 From: Barbosicks Date: Thu, 30 Aug 2018 03:27:47 +0100 Subject: [PATCH 05/21] Int64 --- library/Rattletrap/Data.hs | 2 ++ library/Rattletrap/Decode/Int64Attribute.hs | 10 ++++++++++ library/Rattletrap/Decode/Int64le.hs | 13 +++++++++++++ library/Rattletrap/Decode/ProductAttribute.hs | 2 +- library/Rattletrap/Type/AttributeType.hs | 1 + library/Rattletrap/Type/ProductAttribute.hs | 2 +- 6 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 library/Rattletrap/Decode/Int64Attribute.hs create mode 100644 library/Rattletrap/Decode/Int64le.hs diff --git a/library/Rattletrap/Data.hs b/library/Rattletrap/Data.hs index 53ac5f04..e98cd12f 100644 --- a/library/Rattletrap/Data.hs +++ b/library/Rattletrap/Data.hs @@ -319,6 +319,8 @@ rawAttributeTypes = , ("TAGame.Vehicle_TA:ReplicatedThrottle", AttributeTypeByte) , ("TAGame.VehiclePickup_TA:bNoPickup", AttributeTypeBoolean) , ("TAGame.VehiclePickup_TA:ReplicatedPickupData", AttributeTypePickup) + , ("TAGame.Team_TA:ClubID", AttributeTypeInt64) + , ("TAGame.PRI_TA:ClubID", AttributeTypeInt64) ] rawCrc32Table :: Integral a => [a] diff --git a/library/Rattletrap/Decode/Int64Attribute.hs b/library/Rattletrap/Decode/Int64Attribute.hs new file mode 100644 index 00000000..941ac55f --- /dev/null +++ b/library/Rattletrap/Decode/Int64Attribute.hs @@ -0,0 +1,10 @@ +module Rattletrap.Decode.IntAttribute + ( decodeIntAttributeBits + ) where + +import Rattletrap.Decode.Common +import Rattletrap.Decode.Int64le +import Rattletrap.Type.IntAttribute + +decodeIntAttributeBits :: DecodeBits IntAttribute +decodeIntAttributeBits = IntAttribute <$> decodeInt64leBits diff --git a/library/Rattletrap/Decode/Int64le.hs b/library/Rattletrap/Decode/Int64le.hs new file mode 100644 index 00000000..75061b9b --- /dev/null +++ b/library/Rattletrap/Decode/Int64le.hs @@ -0,0 +1,13 @@ +module Rattletrap.Decode.Int64le + ( decodeInt64le + , decodeInt64leBits + ) where + +import Rattletrap.Decode.Common +import Rattletrap.Type.Int64le + +decodeInt64le :: Decode Int64le +decodeInt64le = Int64le <$> getInt64le + +decodeInt64leBits :: DecodeBits Int64le +decodeInt64leBits = toBits decodeInt64le 8 diff --git a/library/Rattletrap/Decode/ProductAttribute.hs b/library/Rattletrap/Decode/ProductAttribute.hs index ce21fdfc..a7f22e8a 100644 --- a/library/Rattletrap/Decode/ProductAttribute.hs +++ b/library/Rattletrap/Decode/ProductAttribute.hs @@ -59,4 +59,4 @@ decodeColor = do decodeWhen hasValue (Right <$> getWord32be 31) decodeTitle :: Decode Str -decodeTitle = decodeStr \ No newline at end of file +decodeTitle = Right <$> decodeStr \ No newline at end of file diff --git a/library/Rattletrap/Type/AttributeType.hs b/library/Rattletrap/Type/AttributeType.hs index 216af915..d2d33ec5 100644 --- a/library/Rattletrap/Type/AttributeType.hs +++ b/library/Rattletrap/Type/AttributeType.hs @@ -21,6 +21,7 @@ data AttributeType | AttributeTypeFloat | AttributeTypeGameMode | AttributeTypeInt + | AttributeTypeInt64 | AttributeTypeLoadout | AttributeTypeLoadoutOnline | AttributeTypeLoadouts diff --git a/library/Rattletrap/Type/ProductAttribute.hs b/library/Rattletrap/Type/ProductAttribute.hs index a249a6fe..85848efe 100644 --- a/library/Rattletrap/Type/ProductAttribute.hs +++ b/library/Rattletrap/Type/ProductAttribute.hs @@ -14,7 +14,7 @@ data ProductAttribute = ProductAttribute , productAttributeObjectId :: Word32le , productAttributeObjectName :: Maybe Str -- ^ read-only - , productAttributeValue :: Maybe (Either CompressedWord Word32 Str) + , productAttributeValue :: Maybe (Either CompressedWord Word32) } deriving (Eq, Ord, Show) $(deriveJson ''ProductAttribute) From 21697bbaff64954c68486fd93b133f80cdcea01f Mon Sep 17 00:00:00 2001 From: Barbosicks Date: Thu, 30 Aug 2018 03:28:55 +0100 Subject: [PATCH 06/21] Fix --- library/Rattletrap/Decode/Int64Attribute.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Rattletrap/Decode/Int64Attribute.hs b/library/Rattletrap/Decode/Int64Attribute.hs index 941ac55f..b4c08a98 100644 --- a/library/Rattletrap/Decode/Int64Attribute.hs +++ b/library/Rattletrap/Decode/Int64Attribute.hs @@ -1,4 +1,4 @@ -module Rattletrap.Decode.IntAttribute +module Rattletrap.Decode.Int64Attribute ( decodeIntAttributeBits ) where From ce39a101ef024962bb9123d4a4ddd100e354baa0 Mon Sep 17 00:00:00 2001 From: Barbosicks Date: Thu, 30 Aug 2018 03:33:37 +0100 Subject: [PATCH 07/21] now --- library/Rattletrap/Decode/ProductAttribute.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Rattletrap/Decode/ProductAttribute.hs b/library/Rattletrap/Decode/ProductAttribute.hs index a7f22e8a..ce21fdfc 100644 --- a/library/Rattletrap/Decode/ProductAttribute.hs +++ b/library/Rattletrap/Decode/ProductAttribute.hs @@ -59,4 +59,4 @@ decodeColor = do decodeWhen hasValue (Right <$> getWord32be 31) decodeTitle :: Decode Str -decodeTitle = Right <$> decodeStr \ No newline at end of file +decodeTitle = decodeStr \ No newline at end of file From 18b806ffb5f42ddbf10715d0725854863d978cd7 Mon Sep 17 00:00:00 2001 From: Barbosicks Date: Thu, 30 Aug 2018 03:35:20 +0100 Subject: [PATCH 08/21] again --- library/Rattletrap/Decode/ProductAttribute.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/Rattletrap/Decode/ProductAttribute.hs b/library/Rattletrap/Decode/ProductAttribute.hs index ce21fdfc..44571fa9 100644 --- a/library/Rattletrap/Decode/ProductAttribute.hs +++ b/library/Rattletrap/Decode/ProductAttribute.hs @@ -59,4 +59,5 @@ decodeColor = do decodeWhen hasValue (Right <$> getWord32be 31) decodeTitle :: Decode Str -decodeTitle = decodeStr \ No newline at end of file +decodeTitle = do + uselessString <- decodeStr \ No newline at end of file From 2f9826a2de9e6e99ebd768714ff3eee7035b2e8b Mon Sep 17 00:00:00 2001 From: Barbosicks Date: Thu, 30 Aug 2018 03:39:09 +0100 Subject: [PATCH 09/21] fixed --- library/Rattletrap/Decode/Int64Attribute.hs | 8 ++++---- library/Rattletrap/Type/Int64Attribute.hs | 14 ++++++++++++++ library/Rattletrap/Type/Int64le.hs | 13 +++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 library/Rattletrap/Type/Int64Attribute.hs create mode 100644 library/Rattletrap/Type/Int64le.hs diff --git a/library/Rattletrap/Decode/Int64Attribute.hs b/library/Rattletrap/Decode/Int64Attribute.hs index b4c08a98..0414d3d5 100644 --- a/library/Rattletrap/Decode/Int64Attribute.hs +++ b/library/Rattletrap/Decode/Int64Attribute.hs @@ -1,10 +1,10 @@ module Rattletrap.Decode.Int64Attribute - ( decodeIntAttributeBits + ( decodeInt64AttributeBits ) where import Rattletrap.Decode.Common import Rattletrap.Decode.Int64le -import Rattletrap.Type.IntAttribute +import Rattletrap.Type.Int64Attribute -decodeIntAttributeBits :: DecodeBits IntAttribute -decodeIntAttributeBits = IntAttribute <$> decodeInt64leBits +decodeInt64AttributeBits :: DecodeBits Int64Attribute +decodeInt64AttributeBits = Int64Attribute <$> decodeInt64leBits diff --git a/library/Rattletrap/Type/Int64Attribute.hs b/library/Rattletrap/Type/Int64Attribute.hs new file mode 100644 index 00000000..de60ceff --- /dev/null +++ b/library/Rattletrap/Type/Int64Attribute.hs @@ -0,0 +1,14 @@ +{-# LANGUAGE TemplateHaskell #-} + +module Rattletrap.Type.Int64Attribute + ( Int64Attribute(..) + ) where + +import Rattletrap.Type.Common +import Rattletrap.Type.Int64le + +newtype Int64Attribute = Int64Attribute + { int64AttributeValue :: Int64le + } deriving (Eq, Ord, Show) + +$(deriveJson ''IntAttribute) diff --git a/library/Rattletrap/Type/Int64le.hs b/library/Rattletrap/Type/Int64le.hs new file mode 100644 index 00000000..955a252a --- /dev/null +++ b/library/Rattletrap/Type/Int64le.hs @@ -0,0 +1,13 @@ +{-# LANGUAGE TemplateHaskell #-} + +module Rattletrap.Type.Int64le + ( Int64le(..) + ) where + +import Rattletrap.Type.Common + +newtype Int64le = Int64le + { int64leValue :: Int64 + } deriving (Eq, Ord, Show) + +$(deriveJson ''Int64le) From be456db80ccc54b9eaf581bcf743b5f11a76cceb Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 29 Aug 2018 19:42:22 -0700 Subject: [PATCH 10/21] Big fix --- library/Rattletrap/Type/Int64Attribute.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Rattletrap/Type/Int64Attribute.hs b/library/Rattletrap/Type/Int64Attribute.hs index de60ceff..9090e58e 100644 --- a/library/Rattletrap/Type/Int64Attribute.hs +++ b/library/Rattletrap/Type/Int64Attribute.hs @@ -11,4 +11,4 @@ newtype Int64Attribute = Int64Attribute { int64AttributeValue :: Int64le } deriving (Eq, Ord, Show) -$(deriveJson ''IntAttribute) +$(deriveJson ''Int64Attribute) From fc1c382c7569d62518aecf75c29aeb6ccb20935c Mon Sep 17 00:00:00 2001 From: Barbosicks Date: Thu, 30 Aug 2018 03:46:23 +0100 Subject: [PATCH 11/21] Fixed that --- library/Rattletrap/Decode/Common.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/Rattletrap/Decode/Common.hs b/library/Rattletrap/Decode/Common.hs index 6f8a1978..9b897362 100644 --- a/library/Rattletrap/Decode/Common.hs +++ b/library/Rattletrap/Decode/Common.hs @@ -11,6 +11,7 @@ module Rattletrap.Decode.Common , Binary.getLazyByteString , Binary.getInt8 , Binary.getInt32le + , Binary.getInt64le , Binary.getWord8 , Binary.getWord32le , Binary.getWord64le From 9423d5dc388ac93eeb16ba67c16f7d08a2876c7f Mon Sep 17 00:00:00 2001 From: Barbosicks Date: Thu, 30 Aug 2018 03:49:09 +0100 Subject: [PATCH 12/21] try this --- library/Rattletrap/Decode/ProductAttribute.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/Rattletrap/Decode/ProductAttribute.hs b/library/Rattletrap/Decode/ProductAttribute.hs index 44571fa9..ce21fdfc 100644 --- a/library/Rattletrap/Decode/ProductAttribute.hs +++ b/library/Rattletrap/Decode/ProductAttribute.hs @@ -59,5 +59,4 @@ decodeColor = do decodeWhen hasValue (Right <$> getWord32be 31) decodeTitle :: Decode Str -decodeTitle = do - uselessString <- decodeStr \ No newline at end of file +decodeTitle = decodeStr \ No newline at end of file From cc2e21678967a0769ad688328c264cddfc93040d Mon Sep 17 00:00:00 2001 From: Barbosicks Date: Thu, 30 Aug 2018 03:52:34 +0100 Subject: [PATCH 13/21] this??????? --- library/Rattletrap/Decode/ProductAttribute.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/Rattletrap/Decode/ProductAttribute.hs b/library/Rattletrap/Decode/ProductAttribute.hs index ce21fdfc..14472e0f 100644 --- a/library/Rattletrap/Decode/ProductAttribute.hs +++ b/library/Rattletrap/Decode/ProductAttribute.hs @@ -58,5 +58,6 @@ decodeColor = do hasValue <- getBool decodeWhen hasValue (Right <$> getWord32be 31) -decodeTitle :: Decode Str -decodeTitle = decodeStr \ No newline at end of file +decodeTitle :: DecodeBits Str +decodeTitle = decodeStr + \ No newline at end of file From a51b62fb8e2ffa0f39f7125cb191acf14f6ff951 Mon Sep 17 00:00:00 2001 From: Barbosicks Date: Thu, 30 Aug 2018 04:34:16 +0100 Subject: [PATCH 14/21] OMFG DID I DO IT? --- library/Rattletrap/Decode/ProductAttribute.hs | 18 +++++++----------- library/Rattletrap/Type/ProductAttribute.hs | 1 + 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/library/Rattletrap/Decode/ProductAttribute.hs b/library/Rattletrap/Decode/ProductAttribute.hs index 14472e0f..1fc39138 100644 --- a/library/Rattletrap/Decode/ProductAttribute.hs +++ b/library/Rattletrap/Decode/ProductAttribute.hs @@ -37,16 +37,11 @@ decodeProductAttributeBits version objectMap = do Just name -> case fromStr name of "TAGame.ProductAttribute_Painted_TA" -> Just <$> decodePainted version "TAGame.ProductAttribute_UserColor_TA" -> decodeColor + + value2 <- case objectName of + Just name -> case fromStr name of "TAGame.ProductAttribute_TitleID_TA" -> decodeTitle - _ -> - fail - ( "unknown object name " - <> show objectName - <> " for ID " - <> show objectId - ) - Nothing -> fail ("missing object name for ID " <> show objectId) - pure (ProductAttribute flag objectId objectName value) + pure (ProductAttribute flag objectId objectName value value2) decodePainted :: (Int, Int, Int) -> DecodeBits (Either CompressedWord Word32) decodePainted version = if version >= (868, 18, 0) @@ -58,6 +53,7 @@ decodeColor = do hasValue <- getBool decodeWhen hasValue (Right <$> getWord32be 31) -decodeTitle :: DecodeBits Str -decodeTitle = decodeStr +decodeTitle :: DecodeBits (Maybe Str) +decodeTitle = do + decodeWhen True (decodeStrBits) \ No newline at end of file diff --git a/library/Rattletrap/Type/ProductAttribute.hs b/library/Rattletrap/Type/ProductAttribute.hs index 85848efe..256ed055 100644 --- a/library/Rattletrap/Type/ProductAttribute.hs +++ b/library/Rattletrap/Type/ProductAttribute.hs @@ -15,6 +15,7 @@ data ProductAttribute = ProductAttribute , productAttributeObjectName :: Maybe Str -- ^ read-only , productAttributeValue :: Maybe (Either CompressedWord Word32) + , productAttributeValue2 :: Maybe Str } deriving (Eq, Ord, Show) $(deriveJson ''ProductAttribute) From 1acdcd47c42e1161bfe8700aaf248d68f66e8a7e Mon Sep 17 00:00:00 2001 From: Barbosicks Date: Thu, 30 Aug 2018 04:53:43 +0100 Subject: [PATCH 15/21] FIXED --- library/Rattletrap/Decode/ProductAttribute.hs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/Rattletrap/Decode/ProductAttribute.hs b/library/Rattletrap/Decode/ProductAttribute.hs index 1fc39138..4a85ad38 100644 --- a/library/Rattletrap/Decode/ProductAttribute.hs +++ b/library/Rattletrap/Decode/ProductAttribute.hs @@ -15,7 +15,6 @@ import Rattletrap.Type.ProductAttribute import Rattletrap.Type.Str import Rattletrap.Type.Word32le import Rattletrap.Type.Word8le - import qualified Control.Monad as Monad import qualified Data.Map as Map @@ -37,10 +36,13 @@ decodeProductAttributeBits version objectMap = do Just name -> case fromStr name of "TAGame.ProductAttribute_Painted_TA" -> Just <$> decodePainted version "TAGame.ProductAttribute_UserColor_TA" -> decodeColor - + _ -> decodeWhen False (Right <$> getWord32be 31) + Nothing -> fail ("missing object name for ID " <> show objectId) value2 <- case objectName of Just name -> case fromStr name of "TAGame.ProductAttribute_TitleID_TA" -> decodeTitle + _ -> decodeWhen False (decodeStrBits) + Nothing -> fail ("missing object name for ID " <> show objectId) pure (ProductAttribute flag objectId objectName value value2) decodePainted :: (Int, Int, Int) -> DecodeBits (Either CompressedWord Word32) From 1caf9320b69c12bb0cc7e44d6a2e8620146259cc Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 29 Aug 2018 22:55:58 -0700 Subject: [PATCH 16/21] Added 64 bit int attribute values --- library/Rattletrap/Decode/AttributeValue.hs | 2 ++ library/Rattletrap/Type/AttributeValue.hs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/library/Rattletrap/Decode/AttributeValue.hs b/library/Rattletrap/Decode/AttributeValue.hs index fed15052..57515d26 100644 --- a/library/Rattletrap/Decode/AttributeValue.hs +++ b/library/Rattletrap/Decode/AttributeValue.hs @@ -19,6 +19,7 @@ import Rattletrap.Decode.FlaggedIntAttribute import Rattletrap.Decode.FloatAttribute import Rattletrap.Decode.GameModeAttribute import Rattletrap.Decode.IntAttribute +import Rattletrap.Decode.Int64Attribute import Rattletrap.Decode.LoadoutAttribute import Rattletrap.Decode.LoadoutOnlineAttribute import Rattletrap.Decode.LoadoutsAttribute @@ -78,6 +79,7 @@ decodeAttributeValueBits version objectMap name = do AttributeTypeGameMode -> AttributeValueGameMode <$> decodeGameModeAttributeBits version AttributeTypeInt -> AttributeValueInt <$> decodeIntAttributeBits + AttributeTypeInt64 -> AttributeValueInt64 <$> decodeInt64AttributeBits AttributeTypeLoadout -> AttributeValueLoadout <$> decodeLoadoutAttributeBits AttributeTypeLoadoutOnline -> diff --git a/library/Rattletrap/Type/AttributeValue.hs b/library/Rattletrap/Type/AttributeValue.hs index a80a4098..a7d80b1c 100644 --- a/library/Rattletrap/Type/AttributeValue.hs +++ b/library/Rattletrap/Type/AttributeValue.hs @@ -19,6 +19,7 @@ import Rattletrap.Type.FlaggedIntAttribute import Rattletrap.Type.FloatAttribute import Rattletrap.Type.GameModeAttribute import Rattletrap.Type.IntAttribute +import Rattletrap.Type.Int64Attribute import Rattletrap.Type.LoadoutAttribute import Rattletrap.Type.LoadoutOnlineAttribute import Rattletrap.Type.LoadoutsAttribute @@ -54,6 +55,7 @@ data AttributeValue | AttributeValueFloat FloatAttribute | AttributeValueGameMode GameModeAttribute | AttributeValueInt IntAttribute + | AttributeValueInt64 Int64Attribute | AttributeValueLoadout LoadoutAttribute | AttributeValueLoadoutOnline LoadoutOnlineAttribute | AttributeValueLoadouts LoadoutsAttribute From 1bf6a6123c5a08a9ba94c860a87cd05e2ec5f1ce Mon Sep 17 00:00:00 2001 From: Alex Shafer Date: Thu, 30 Aug 2018 21:18:25 -0400 Subject: [PATCH 17/21] Add encoder for TitleID attribute. --- library/Rattletrap/Encode/AttributeValue.hs | 2 ++ library/Rattletrap/Encode/Int64Attribute.hs | 11 ++++++++++ library/Rattletrap/Encode/Int64le.hs | 20 ++++++++++++++++++ library/Rattletrap/Encode/ProductAttribute.hs | 5 +++++ replays/aa70.replay | Bin 0 -> 29818 bytes tests/Main.hs | 1 + 6 files changed, 39 insertions(+) create mode 100644 library/Rattletrap/Encode/Int64Attribute.hs create mode 100644 library/Rattletrap/Encode/Int64le.hs create mode 100644 replays/aa70.replay diff --git a/library/Rattletrap/Encode/AttributeValue.hs b/library/Rattletrap/Encode/AttributeValue.hs index 136597fe..de68bc61 100644 --- a/library/Rattletrap/Encode/AttributeValue.hs +++ b/library/Rattletrap/Encode/AttributeValue.hs @@ -16,6 +16,7 @@ import Rattletrap.Encode.FlaggedIntAttribute import Rattletrap.Encode.FloatAttribute import Rattletrap.Encode.GameModeAttribute import Rattletrap.Encode.IntAttribute +import Rattletrap.Encode.Int64Attribute import Rattletrap.Encode.LoadoutAttribute import Rattletrap.Encode.LoadoutOnlineAttribute import Rattletrap.Encode.LoadoutsAttribute @@ -55,6 +56,7 @@ putAttributeValue value = case value of AttributeValueFloat x -> putFloatAttribute x AttributeValueGameMode x -> putGameModeAttribute x AttributeValueInt x -> putIntAttribute x + AttributeValueInt64 x -> putInt64Attribute x AttributeValueLoadout x -> putLoadoutAttribute x AttributeValueLoadoutOnline x -> putLoadoutOnlineAttribute x AttributeValueLoadouts x -> putLoadoutsAttribute x diff --git a/library/Rattletrap/Encode/Int64Attribute.hs b/library/Rattletrap/Encode/Int64Attribute.hs new file mode 100644 index 00000000..d4bbc10a --- /dev/null +++ b/library/Rattletrap/Encode/Int64Attribute.hs @@ -0,0 +1,11 @@ +module Rattletrap.Encode.Int64Attribute + ( putInt64Attribute + ) where + +import Rattletrap.Encode.Int64le +import Rattletrap.Type.Int64Attribute + +import qualified Data.Binary.Bits.Put as BinaryBits + +putInt64Attribute :: Int64Attribute -> BinaryBits.BitPut () +putInt64Attribute int64Attribute = putInt64Bits (int64AttributeValue int64Attribute) diff --git a/library/Rattletrap/Encode/Int64le.hs b/library/Rattletrap/Encode/Int64le.hs new file mode 100644 index 00000000..69c04862 --- /dev/null +++ b/library/Rattletrap/Encode/Int64le.hs @@ -0,0 +1,20 @@ +module Rattletrap.Encode.Int64le + ( putInt64 + , putInt64Bits + ) where + +import Rattletrap.Type.Int64le +import Rattletrap.Utility.Bytes + +import qualified Data.Binary as Binary +import qualified Data.Binary.Bits.Put as BinaryBits +import qualified Data.Binary.Put as Binary +import qualified Data.ByteString.Lazy as LazyBytes + +putInt64 :: Int64le -> Binary.Put +putInt64 int64 = Binary.putInt64le (int64leValue int64) + +putInt64Bits :: Int64le -> BinaryBits.BitPut () +putInt64Bits int64 = do + let bytes = Binary.runPut (putInt64 int64) + BinaryBits.putByteString (LazyBytes.toStrict (reverseBytes bytes)) diff --git a/library/Rattletrap/Encode/ProductAttribute.hs b/library/Rattletrap/Encode/ProductAttribute.hs index 03a6df81..6d6cc049 100644 --- a/library/Rattletrap/Encode/ProductAttribute.hs +++ b/library/Rattletrap/Encode/ProductAttribute.hs @@ -7,6 +7,7 @@ import Data.Semigroup ((<>)) import Rattletrap.Encode.CompressedWord import Rattletrap.Encode.Word32le import Rattletrap.Encode.Word8le +import Rattletrap.Encode.Str import Rattletrap.Type.ProductAttribute import Rattletrap.Type.Str import Rattletrap.Type.Word8le @@ -37,6 +38,10 @@ putProductAttribute attribute = do case value of Left x -> putCompressedWord x Right x -> BinaryBits.putWord32be 31 x + "TAGame.ProductAttribute_TitleID_TA" -> + case productAttributeValue2 attribute of + Nothing -> pure () + Just x -> putTextBits x _ -> fail ("unknown object name for product attribute " <> show attribute) Nothing -> diff --git a/replays/aa70.replay b/replays/aa70.replay new file mode 100644 index 0000000000000000000000000000000000000000..0d812cc7faa7c6fe7de4d6e09f9dbcbbdd1adf34 GIT binary patch literal 29818 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 literal 0 HcmV?d00001 diff --git a/tests/Main.hs b/tests/Main.hs index 93ae8acf..9a35394d 100644 --- a/tests/Main.hs +++ b/tests/Main.hs @@ -106,6 +106,7 @@ replays = , ("a671", "a waiting player") , ("a7f0", "a ready attribute") , ("a9df", "salty shores patch 1.45") + , ("aa70", "patch 1.50 - TitleID attribute") , ("afb1", "patch 1.37") , ("b9f9", "a party leader") , ("c14f", "some mutators") From 53a24982d12bb85981b8a56bc530571139a52e25 Mon Sep 17 00:00:00 2001 From: Taylor Fausak Date: Mon, 3 Sep 2018 08:32:16 -0400 Subject: [PATCH 18/21] Fix some formatting stuff --- library/Rattletrap/Data.hs | 6 +++--- library/Rattletrap/Decode/AttributeValue.hs | 10 +++++----- library/Rattletrap/Encode/AttributeValue.hs | 2 +- library/Rattletrap/Encode/Int64Attribute.hs | 3 ++- library/Rattletrap/Type/AttributeValue.hs | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/library/Rattletrap/Data.hs b/library/Rattletrap/Data.hs index e98cd12f..8f7c1fd3 100644 --- a/library/Rattletrap/Data.hs +++ b/library/Rattletrap/Data.hs @@ -127,8 +127,8 @@ rawObjectClasses = , ("Archetypes.GameEvent.GameEvent_HockeyPrivate", "TAGame.GameEvent_SoccarPrivate_TA") , ("Archetypes.GameEvent.GameEvent_HockeySplitscreen", "TAGame.GameEvent_SoccarSplitscreen_TA") , ("Archetypes.GameEvent.GameEvent_Items", "TAGame.GameEvent_Soccar_TA") - , ("Archetypes.GameEvent.GameEvent_Season:CarArchetype", "TAGame.Car_TA") , ("Archetypes.GameEvent.GameEvent_Season", "TAGame.GameEvent_Season_TA") + , ("Archetypes.GameEvent.GameEvent_Season:CarArchetype", "TAGame.Car_TA") , ("Archetypes.GameEvent.GameEvent_Soccar", "TAGame.GameEvent_Soccar_TA") , ("Archetypes.GameEvent.GameEvent_SoccarLan", "TAGame.GameEvent_Soccar_TA") , ("Archetypes.GameEvent.GameEvent_SoccarPrivate", "TAGame.GameEvent_SoccarPrivate_TA") @@ -276,6 +276,7 @@ rawAttributeTypes = , ("TAGame.PRI_TA:ClientLoadoutOnline", AttributeTypeLoadoutOnline) , ("TAGame.PRI_TA:ClientLoadouts", AttributeTypeLoadouts) , ("TAGame.PRI_TA:ClientLoadoutsOnline", AttributeTypeLoadoutsOnline) + , ("TAGame.PRI_TA:ClubID", AttributeTypeInt64) , ("TAGame.PRI_TA:MatchAssists", AttributeTypeInt) , ("TAGame.PRI_TA:MatchBreakoutDamage", AttributeTypeInt) , ("TAGame.PRI_TA:MatchGoals", AttributeTypeInt) @@ -310,6 +311,7 @@ rawAttributeTypes = , ("TAGame.SpecialPickup_Targeted_TA:Targeted", AttributeTypeFlaggedInt) , ("TAGame.Team_Soccar_TA:GameScore", AttributeTypeInt) , ("TAGame.Team_TA:ClubColors", AttributeTypeClubColors) + , ("TAGame.Team_TA:ClubID", AttributeTypeInt64) , ("TAGame.Team_TA:CustomTeamName", AttributeTypeString) , ("TAGame.Team_TA:GameEvent", AttributeTypeFlaggedInt) , ("TAGame.Team_TA:LogoData", AttributeTypeFlaggedInt) @@ -319,8 +321,6 @@ rawAttributeTypes = , ("TAGame.Vehicle_TA:ReplicatedThrottle", AttributeTypeByte) , ("TAGame.VehiclePickup_TA:bNoPickup", AttributeTypeBoolean) , ("TAGame.VehiclePickup_TA:ReplicatedPickupData", AttributeTypePickup) - , ("TAGame.Team_TA:ClubID", AttributeTypeInt64) - , ("TAGame.PRI_TA:ClubID", AttributeTypeInt64) ] rawCrc32Table :: Integral a => [a] diff --git a/library/Rattletrap/Decode/AttributeValue.hs b/library/Rattletrap/Decode/AttributeValue.hs index 57515d26..90f67c54 100644 --- a/library/Rattletrap/Decode/AttributeValue.hs +++ b/library/Rattletrap/Decode/AttributeValue.hs @@ -18,8 +18,8 @@ import Rattletrap.Decode.ExtendedExplosionAttribute import Rattletrap.Decode.FlaggedIntAttribute import Rattletrap.Decode.FloatAttribute import Rattletrap.Decode.GameModeAttribute -import Rattletrap.Decode.IntAttribute import Rattletrap.Decode.Int64Attribute +import Rattletrap.Decode.IntAttribute import Rattletrap.Decode.LoadoutAttribute import Rattletrap.Decode.LoadoutOnlineAttribute import Rattletrap.Decode.LoadoutsAttribute @@ -71,8 +71,8 @@ decodeAttributeValueBits version objectMap name = do AttributeTypeEnum -> AttributeValueEnum <$> decodeEnumAttributeBits AttributeTypeExplosion -> AttributeValueExplosion <$> decodeExplosionAttributeBits version - AttributeTypeExtendedExplosion -> - AttributeValueExtendedExplosion <$> decodeExtendedExplosionAttributeBits version + AttributeTypeExtendedExplosion -> AttributeValueExtendedExplosion + <$> decodeExtendedExplosionAttributeBits version AttributeTypeFlaggedInt -> AttributeValueFlaggedInt <$> decodeFlaggedIntAttributeBits AttributeTypeFloat -> AttributeValueFloat <$> decodeFloatAttributeBits @@ -105,8 +105,8 @@ decodeAttributeValueBits version objectMap name = do AttributeTypeQWord -> AttributeValueQWord <$> decodeQWordAttributeBits AttributeTypeReservation -> AttributeValueReservation <$> decodeReservationAttributeBits version - AttributeTypeRigidBodyState -> - AttributeValueRigidBodyState <$> decodeRigidBodyStateAttributeBits version + AttributeTypeRigidBodyState -> AttributeValueRigidBodyState + <$> decodeRigidBodyStateAttributeBits version AttributeTypeStatEvent -> AttributeValueStatEvent <$> decodeStatEventAttributeBits AttributeTypeString -> AttributeValueString <$> decodeStringAttributeBits diff --git a/library/Rattletrap/Encode/AttributeValue.hs b/library/Rattletrap/Encode/AttributeValue.hs index de68bc61..2a1953fa 100644 --- a/library/Rattletrap/Encode/AttributeValue.hs +++ b/library/Rattletrap/Encode/AttributeValue.hs @@ -15,8 +15,8 @@ import Rattletrap.Encode.ExtendedExplosionAttribute import Rattletrap.Encode.FlaggedIntAttribute import Rattletrap.Encode.FloatAttribute import Rattletrap.Encode.GameModeAttribute -import Rattletrap.Encode.IntAttribute import Rattletrap.Encode.Int64Attribute +import Rattletrap.Encode.IntAttribute import Rattletrap.Encode.LoadoutAttribute import Rattletrap.Encode.LoadoutOnlineAttribute import Rattletrap.Encode.LoadoutsAttribute diff --git a/library/Rattletrap/Encode/Int64Attribute.hs b/library/Rattletrap/Encode/Int64Attribute.hs index d4bbc10a..b41b6d34 100644 --- a/library/Rattletrap/Encode/Int64Attribute.hs +++ b/library/Rattletrap/Encode/Int64Attribute.hs @@ -8,4 +8,5 @@ import Rattletrap.Type.Int64Attribute import qualified Data.Binary.Bits.Put as BinaryBits putInt64Attribute :: Int64Attribute -> BinaryBits.BitPut () -putInt64Attribute int64Attribute = putInt64Bits (int64AttributeValue int64Attribute) +putInt64Attribute int64Attribute = + putInt64Bits (int64AttributeValue int64Attribute) diff --git a/library/Rattletrap/Type/AttributeValue.hs b/library/Rattletrap/Type/AttributeValue.hs index a7d80b1c..703a6986 100644 --- a/library/Rattletrap/Type/AttributeValue.hs +++ b/library/Rattletrap/Type/AttributeValue.hs @@ -18,8 +18,8 @@ import Rattletrap.Type.ExtendedExplosionAttribute import Rattletrap.Type.FlaggedIntAttribute import Rattletrap.Type.FloatAttribute import Rattletrap.Type.GameModeAttribute -import Rattletrap.Type.IntAttribute import Rattletrap.Type.Int64Attribute +import Rattletrap.Type.IntAttribute import Rattletrap.Type.LoadoutAttribute import Rattletrap.Type.LoadoutOnlineAttribute import Rattletrap.Type.LoadoutsAttribute From 9ef4b5f7f3e65d812c46607971d08854141c35db Mon Sep 17 00:00:00 2001 From: Taylor Fausak Date: Mon, 3 Sep 2018 08:57:11 -0400 Subject: [PATCH 19/21] Clean up product attribute values --- library/Rattletrap/Decode/ProductAttribute.hs | 48 +++++++++---------- library/Rattletrap/Encode/ProductAttribute.hs | 35 ++++---------- library/Rattletrap/Type/ProductAttribute.hs | 13 ++++- 3 files changed, 45 insertions(+), 51 deletions(-) diff --git a/library/Rattletrap/Decode/ProductAttribute.hs b/library/Rattletrap/Decode/ProductAttribute.hs index 4a85ad38..85db6633 100644 --- a/library/Rattletrap/Decode/ProductAttribute.hs +++ b/library/Rattletrap/Decode/ProductAttribute.hs @@ -10,11 +10,11 @@ import Rattletrap.Decode.Word32le import Rattletrap.Decode.Word8le import Rattletrap.Decode.Str import Rattletrap.Type.Common -import Rattletrap.Type.CompressedWord import Rattletrap.Type.ProductAttribute import Rattletrap.Type.Str import Rattletrap.Type.Word32le import Rattletrap.Type.Word8le + import qualified Control.Monad as Monad import qualified Data.Map as Map @@ -31,31 +31,31 @@ decodeProductAttributeBits decodeProductAttributeBits version objectMap = do flag <- getBool objectId <- decodeWord32leBits - let objectName = Map.lookup objectId objectMap - value <- case objectName of - Just name -> case fromStr name of - "TAGame.ProductAttribute_Painted_TA" -> Just <$> decodePainted version - "TAGame.ProductAttribute_UserColor_TA" -> decodeColor - _ -> decodeWhen False (Right <$> getWord32be 31) - Nothing -> fail ("missing object name for ID " <> show objectId) - value2 <- case objectName of - Just name -> case fromStr name of - "TAGame.ProductAttribute_TitleID_TA" -> decodeTitle - _ -> decodeWhen False (decodeStrBits) - Nothing -> fail ("missing object name for ID " <> show objectId) - pure (ProductAttribute flag objectId objectName value value2) + let maybeObjectName = Map.lookup objectId objectMap + value <- case fromStr <$> maybeObjectName of + Just "TAGame.ProductAttribute_Painted_TA" -> + Just <$> decodePainted version + Just "TAGame.ProductAttribute_TitleID_TA" -> Just <$> decodeTitle + Just "TAGame.ProductAttribute_UserColor_TA" -> Just <$> decodeColor + Just objectName -> + fail + ("unknown object name " + <> show objectName + <> " for ID " + <> show objectId + ) + Nothing -> fail ("missing object name for ID " <> show objectId) + pure (ProductAttribute flag objectId maybeObjectName value) -decodePainted :: (Int, Int, Int) -> DecodeBits (Either CompressedWord Word32) +decodePainted :: (Int, Int, Int) -> DecodeBits ProductAttributeValue decodePainted version = if version >= (868, 18, 0) - then Right <$> getWord32be 31 - else Left <$> decodeCompressedWordBits 13 + then ProductAttributeValuePaintedNew <$> getWord32be 31 + else ProductAttributeValuePaintedOld <$> decodeCompressedWordBits 13 -decodeColor :: DecodeBits (Maybe (Either CompressedWord Word32)) +decodeColor :: DecodeBits ProductAttributeValue decodeColor = do hasValue <- getBool - decodeWhen hasValue (Right <$> getWord32be 31) - -decodeTitle :: DecodeBits (Maybe Str) -decodeTitle = do - decodeWhen True (decodeStrBits) - \ No newline at end of file + ProductAttributeValueUserColor <$> decodeWhen hasValue (getWord32be 31) + +decodeTitle :: DecodeBits ProductAttributeValue +decodeTitle = ProductAttributeValueTitleId <$> decodeStrBits diff --git a/library/Rattletrap/Encode/ProductAttribute.hs b/library/Rattletrap/Encode/ProductAttribute.hs index 6d6cc049..cd45db8c 100644 --- a/library/Rattletrap/Encode/ProductAttribute.hs +++ b/library/Rattletrap/Encode/ProductAttribute.hs @@ -3,13 +3,11 @@ module Rattletrap.Encode.ProductAttribute , putProductAttribute ) where -import Data.Semigroup ((<>)) import Rattletrap.Encode.CompressedWord import Rattletrap.Encode.Word32le import Rattletrap.Encode.Word8le import Rattletrap.Encode.Str import Rattletrap.Type.ProductAttribute -import Rattletrap.Type.Str import Rattletrap.Type.Word8le import qualified Data.Binary.Bits.Put as BinaryBits @@ -23,26 +21,13 @@ putProductAttribute :: ProductAttribute -> BinaryBits.BitPut () putProductAttribute attribute = do BinaryBits.putBool (productAttributeUnknown attribute) putWord32Bits (productAttributeObjectId attribute) - case productAttributeObjectName attribute of - Just name -> case fromStr name of - "TAGame.ProductAttribute_Painted_TA" -> - case productAttributeValue attribute of - Nothing -> pure () - Just (Left x) -> putCompressedWord x - Just (Right x) -> BinaryBits.putWord32be 31 x - "TAGame.ProductAttribute_UserColor_TA" -> - case productAttributeValue attribute of - Nothing -> BinaryBits.putBool False - Just value -> do - BinaryBits.putBool True - case value of - Left x -> putCompressedWord x - Right x -> BinaryBits.putWord32be 31 x - "TAGame.ProductAttribute_TitleID_TA" -> - case productAttributeValue2 attribute of - Nothing -> pure () - Just x -> putTextBits x - _ -> - fail ("unknown object name for product attribute " <> show attribute) - Nothing -> - fail ("missing object name for product attribute " <> show attribute) + case productAttributeValue attribute of + Nothing -> pure () + Just (ProductAttributeValuePaintedOld x) -> putCompressedWord x + Just (ProductAttributeValuePaintedNew x) -> BinaryBits.putWord32be 31 x + Just (ProductAttributeValueUserColor x) -> case x of + Nothing -> BinaryBits.putBool False + Just y -> do + BinaryBits.putBool True + BinaryBits.putWord32be 31 y + Just (ProductAttributeValueTitleId x) -> putTextBits x diff --git a/library/Rattletrap/Type/ProductAttribute.hs b/library/Rattletrap/Type/ProductAttribute.hs index 256ed055..bfc357fb 100644 --- a/library/Rattletrap/Type/ProductAttribute.hs +++ b/library/Rattletrap/Type/ProductAttribute.hs @@ -2,6 +2,7 @@ module Rattletrap.Type.ProductAttribute ( ProductAttribute(..) + , ProductAttributeValue(..) ) where import Rattletrap.Type.Common @@ -9,13 +10,21 @@ import Rattletrap.Type.CompressedWord import Rattletrap.Type.Str import Rattletrap.Type.Word32le +data ProductAttributeValue + = ProductAttributeValuePaintedOld CompressedWord + | ProductAttributeValuePaintedNew Word32 + | ProductAttributeValueUserColor (Maybe Word32) + | ProductAttributeValueTitleId Str + deriving (Eq, Ord, Show) + +$(deriveJson ''ProductAttributeValue) + data ProductAttribute = ProductAttribute { productAttributeUnknown :: Bool , productAttributeObjectId :: Word32le , productAttributeObjectName :: Maybe Str -- ^ read-only - , productAttributeValue :: Maybe (Either CompressedWord Word32) - , productAttributeValue2 :: Maybe Str + , productAttributeValue :: Maybe ProductAttributeValue } deriving (Eq, Ord, Show) $(deriveJson ''ProductAttribute) From d64ab9ab1c8efa0e665ef3c93d09bae50a5fdce3 Mon Sep 17 00:00:00 2001 From: Taylor Fausak Date: Mon, 3 Sep 2018 09:20:17 -0400 Subject: [PATCH 20/21] Handle new user color product attribute values --- library/Rattletrap/Decode/ProductAttribute.hs | 13 ++++++++----- library/Rattletrap/Encode/ProductAttribute.hs | 3 ++- library/Rattletrap/Type/ProductAttribute.hs | 3 ++- replays/92a6.replay | Bin replays/a676.replay | Bin 0 -> 60183 bytes tests/Main.hs | 1 + 6 files changed, 13 insertions(+), 7 deletions(-) mode change 100755 => 100644 replays/92a6.replay create mode 100644 replays/a676.replay diff --git a/library/Rattletrap/Decode/ProductAttribute.hs b/library/Rattletrap/Decode/ProductAttribute.hs index 85db6633..bec4b92b 100644 --- a/library/Rattletrap/Decode/ProductAttribute.hs +++ b/library/Rattletrap/Decode/ProductAttribute.hs @@ -36,7 +36,8 @@ decodeProductAttributeBits version objectMap = do Just "TAGame.ProductAttribute_Painted_TA" -> Just <$> decodePainted version Just "TAGame.ProductAttribute_TitleID_TA" -> Just <$> decodeTitle - Just "TAGame.ProductAttribute_UserColor_TA" -> Just <$> decodeColor + Just "TAGame.ProductAttribute_UserColor_TA" -> + Just <$> decodeColor version Just objectName -> fail ("unknown object name " @@ -52,10 +53,12 @@ decodePainted version = if version >= (868, 18, 0) then ProductAttributeValuePaintedNew <$> getWord32be 31 else ProductAttributeValuePaintedOld <$> decodeCompressedWordBits 13 -decodeColor :: DecodeBits ProductAttributeValue -decodeColor = do - hasValue <- getBool - ProductAttributeValueUserColor <$> decodeWhen hasValue (getWord32be 31) +decodeColor :: (Int, Int, Int) -> DecodeBits ProductAttributeValue +decodeColor version = if version >= (868, 23, 8) + then ProductAttributeValueUserColorNew <$> decodeWord32leBits + else do + hasValue <- getBool + ProductAttributeValueUserColorOld <$> decodeWhen hasValue (getWord32be 31) decodeTitle :: DecodeBits ProductAttributeValue decodeTitle = ProductAttributeValueTitleId <$> decodeStrBits diff --git a/library/Rattletrap/Encode/ProductAttribute.hs b/library/Rattletrap/Encode/ProductAttribute.hs index cd45db8c..2f65eb7e 100644 --- a/library/Rattletrap/Encode/ProductAttribute.hs +++ b/library/Rattletrap/Encode/ProductAttribute.hs @@ -25,9 +25,10 @@ putProductAttribute attribute = do Nothing -> pure () Just (ProductAttributeValuePaintedOld x) -> putCompressedWord x Just (ProductAttributeValuePaintedNew x) -> BinaryBits.putWord32be 31 x - Just (ProductAttributeValueUserColor x) -> case x of + Just (ProductAttributeValueUserColorOld x) -> case x of Nothing -> BinaryBits.putBool False Just y -> do BinaryBits.putBool True BinaryBits.putWord32be 31 y + Just (ProductAttributeValueUserColorNew x) -> putWord32Bits x Just (ProductAttributeValueTitleId x) -> putTextBits x diff --git a/library/Rattletrap/Type/ProductAttribute.hs b/library/Rattletrap/Type/ProductAttribute.hs index bfc357fb..c4883e1c 100644 --- a/library/Rattletrap/Type/ProductAttribute.hs +++ b/library/Rattletrap/Type/ProductAttribute.hs @@ -13,7 +13,8 @@ import Rattletrap.Type.Word32le data ProductAttributeValue = ProductAttributeValuePaintedOld CompressedWord | ProductAttributeValuePaintedNew Word32 - | ProductAttributeValueUserColor (Maybe Word32) + | ProductAttributeValueUserColorOld (Maybe Word32) + | ProductAttributeValueUserColorNew Word32le | ProductAttributeValueTitleId Str deriving (Eq, Ord, Show) diff --git a/replays/92a6.replay b/replays/92a6.replay old mode 100755 new mode 100644 diff --git a/replays/a676.replay b/replays/a676.replay new file mode 100644 index 0000000000000000000000000000000000000000..8291ab00ff3e4ed592b1543a8d7239ff351a80c8 GIT binary patch literal 60183 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 Date: Mon, 3 Sep 2018 09:23:05 -0400 Subject: [PATCH 21/21] Make product attribute values required --- library/Rattletrap/Decode/ProductAttribute.hs | 8 +++----- library/Rattletrap/Encode/ProductAttribute.hs | 11 +++++------ library/Rattletrap/Type/ProductAttribute.hs | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/library/Rattletrap/Decode/ProductAttribute.hs b/library/Rattletrap/Decode/ProductAttribute.hs index bec4b92b..77ec0f79 100644 --- a/library/Rattletrap/Decode/ProductAttribute.hs +++ b/library/Rattletrap/Decode/ProductAttribute.hs @@ -33,11 +33,9 @@ decodeProductAttributeBits version objectMap = do objectId <- decodeWord32leBits let maybeObjectName = Map.lookup objectId objectMap value <- case fromStr <$> maybeObjectName of - Just "TAGame.ProductAttribute_Painted_TA" -> - Just <$> decodePainted version - Just "TAGame.ProductAttribute_TitleID_TA" -> Just <$> decodeTitle - Just "TAGame.ProductAttribute_UserColor_TA" -> - Just <$> decodeColor version + Just "TAGame.ProductAttribute_Painted_TA" -> decodePainted version + Just "TAGame.ProductAttribute_TitleID_TA" -> decodeTitle + Just "TAGame.ProductAttribute_UserColor_TA" -> decodeColor version Just objectName -> fail ("unknown object name " diff --git a/library/Rattletrap/Encode/ProductAttribute.hs b/library/Rattletrap/Encode/ProductAttribute.hs index 2f65eb7e..5ba6e4fa 100644 --- a/library/Rattletrap/Encode/ProductAttribute.hs +++ b/library/Rattletrap/Encode/ProductAttribute.hs @@ -22,13 +22,12 @@ putProductAttribute attribute = do BinaryBits.putBool (productAttributeUnknown attribute) putWord32Bits (productAttributeObjectId attribute) case productAttributeValue attribute of - Nothing -> pure () - Just (ProductAttributeValuePaintedOld x) -> putCompressedWord x - Just (ProductAttributeValuePaintedNew x) -> BinaryBits.putWord32be 31 x - Just (ProductAttributeValueUserColorOld x) -> case x of + ProductAttributeValuePaintedOld x -> putCompressedWord x + ProductAttributeValuePaintedNew x -> BinaryBits.putWord32be 31 x + ProductAttributeValueUserColorOld x -> case x of Nothing -> BinaryBits.putBool False Just y -> do BinaryBits.putBool True BinaryBits.putWord32be 31 y - Just (ProductAttributeValueUserColorNew x) -> putWord32Bits x - Just (ProductAttributeValueTitleId x) -> putTextBits x + ProductAttributeValueUserColorNew x -> putWord32Bits x + ProductAttributeValueTitleId x -> putTextBits x diff --git a/library/Rattletrap/Type/ProductAttribute.hs b/library/Rattletrap/Type/ProductAttribute.hs index c4883e1c..e3764eea 100644 --- a/library/Rattletrap/Type/ProductAttribute.hs +++ b/library/Rattletrap/Type/ProductAttribute.hs @@ -25,7 +25,7 @@ data ProductAttribute = ProductAttribute , productAttributeObjectId :: Word32le , productAttributeObjectName :: Maybe Str -- ^ read-only - , productAttributeValue :: Maybe ProductAttributeValue + , productAttributeValue :: ProductAttributeValue } deriving (Eq, Ord, Show) $(deriveJson ''ProductAttribute)