diff --git a/rattletrap.cabal b/rattletrap.cabal index f24344cd..a713240a 100644 --- a/rattletrap.cabal +++ b/rattletrap.cabal @@ -129,8 +129,10 @@ library Rattletrap.Type.Attribute.Product Rattletrap.Type.Attribute.ProductValue Rattletrap.Type.Attribute.QWord + Rattletrap.Type.Attribute.RepStatTitle Rattletrap.Type.Attribute.Reservation Rattletrap.Type.Attribute.RigidBodyState + Rattletrap.Type.Attribute.Rotation Rattletrap.Type.Attribute.StatEvent Rattletrap.Type.Attribute.String Rattletrap.Type.Attribute.TeamPaint @@ -174,6 +176,7 @@ library Rattletrap.Type.RemoteId.Epic Rattletrap.Type.RemoteId.PlayStation Rattletrap.Type.RemoteId.PsyNet + Rattletrap.Type.RemoteId.QQ Rattletrap.Type.RemoteId.Splitscreen Rattletrap.Type.RemoteId.Steam Rattletrap.Type.RemoteId.Switch diff --git a/replays/0121.replay b/replays/0121.replay new file mode 100644 index 00000000..526b0548 Binary files /dev/null and b/replays/0121.replay differ diff --git a/replays/0ca5.replay b/replays/0ca5.replay new file mode 100644 index 00000000..634cf5f0 Binary files /dev/null and b/replays/0ca5.replay differ diff --git a/replays/43a9.replay b/replays/43a9.replay new file mode 100644 index 00000000..d7cf2ffe Binary files /dev/null and b/replays/43a9.replay differ diff --git a/replays/5123.replay b/replays/5123.replay new file mode 100644 index 00000000..8bd505ec Binary files /dev/null and b/replays/5123.replay differ diff --git a/replays/54ae.replay b/replays/54ae.replay new file mode 100644 index 00000000..2dc7064c Binary files /dev/null and b/replays/54ae.replay differ diff --git a/replays/7588.replay b/replays/7588.replay new file mode 100644 index 00000000..87182f46 Binary files /dev/null and b/replays/7588.replay differ diff --git a/replays/ae46.replay b/replays/ae46.replay new file mode 100644 index 00000000..1cb82ed3 Binary files /dev/null and b/replays/ae46.replay differ diff --git a/replays/c62c.replay b/replays/c62c.replay new file mode 100644 index 00000000..fa7675fb Binary files /dev/null and b/replays/c62c.replay differ diff --git a/replays/d5d6.replay b/replays/d5d6.replay new file mode 100644 index 00000000..f4ca86c2 Binary files /dev/null and b/replays/d5d6.replay differ diff --git a/replays/e2f9.replay b/replays/e2f9.replay new file mode 100644 index 00000000..d9116a86 Binary files /dev/null and b/replays/e2f9.replay differ diff --git a/src/lib/Rattletrap/Console/Main.hs b/src/lib/Rattletrap/Console/Main.hs index 76a117ee..bfa1e72b 100644 --- a/src/lib/Rattletrap/Console/Main.hs +++ b/src/lib/Rattletrap/Console/Main.hs @@ -46,8 +46,10 @@ import qualified Rattletrap.Type.Attribute.PrivateMatchSettings as Attribute.Pri import qualified Rattletrap.Type.Attribute.Product as Attribute.Product import qualified Rattletrap.Type.Attribute.ProductValue as Attribute.ProductValue import qualified Rattletrap.Type.Attribute.QWord as Attribute.QWord +import qualified Rattletrap.Type.Attribute.RepStatTitle as Attribute.RepStatTitle import qualified Rattletrap.Type.Attribute.Reservation as Attribute.Reservation import qualified Rattletrap.Type.Attribute.RigidBodyState as Attribute.RigidBodyState +import qualified Rattletrap.Type.Attribute.Rotation as Attribute.Rotation import qualified Rattletrap.Type.Attribute.StatEvent as Attribute.StatEvent import qualified Rattletrap.Type.Attribute.String as Attribute.String import qualified Rattletrap.Type.Attribute.TeamPaint as Attribute.TeamPaint @@ -195,8 +197,10 @@ schema = , Attribute.Product.schema , Attribute.ProductValue.schema , Attribute.QWord.schema + , Attribute.RepStatTitle.schema , Attribute.Reservation.schema , Attribute.RigidBodyState.schema + , Attribute.Rotation.schema , Attribute.StatEvent.schema , Attribute.String.schema , Attribute.TeamPaint.schema diff --git a/src/lib/Rattletrap/Data.hs b/src/lib/Rattletrap/Data.hs index 8424aba1..38b1d52d 100644 --- a/src/lib/Rattletrap/Data.hs +++ b/src/lib/Rattletrap/Data.hs @@ -80,6 +80,7 @@ classesWithLocation = Set.fromList $ fmap , "Archetypes.Ball.Ball_Breakout" , "Archetypes.Ball.Ball_Default" , "Archetypes.Ball.Ball_Puck" + , "Archetypes.Ball.Ball_Trajectory" , "Archetypes.Ball.CubeBall" , "Archetypes.Car.Car_Default" , "Archetypes.GameEvent.GameEvent_Season:CarArchetype" @@ -90,6 +91,7 @@ classesWithLocation = Set.fromList $ fmap , "TAGame.Ball_Haunted_TA" , "TAGame.Ball_TA" , "TAGame.CameraSettingsActor_TA" + , "TAGame.Cannon_TA" , "TAGame.Car_Season_TA" , "TAGame.Car_TA" , "TAGame.CarComponent_Boost_TA" @@ -105,6 +107,7 @@ classesWithLocation = Set.fromList $ fmap , "TAGame.GameEvent_Soccar_TA" , "TAGame.GameEvent_SoccarPrivate_TA" , "TAGame.GameEvent_SoccarSplitscreen_TA" + , "TAGame.GameEvent_Tutorial_TA" , "TAGame.GRI_TA" , "TAGame.MaxTimeWarningData_TA" , "TAGame.PickupTimer_TA" @@ -141,6 +144,7 @@ classesWithRotation = Set.fromList $ fmap , "Archetypes.Ball.Ball_Breakout" , "Archetypes.Ball.Ball_Default" , "Archetypes.Ball.Ball_Puck" + , "Archetypes.Ball.Ball_Trajectory" , "Archetypes.Ball.CubeBall" , "Archetypes.Car.Car_Default" , "Archetypes.GameEvent.GameEvent_Season:CarArchetype" @@ -167,6 +171,8 @@ objectClasses = Map.fromList $ fmap , ("Archetypes.Ball.Ball_God", "TAGame.Ball_God_TA") , ("Archetypes.Ball.Ball_Haunted", "TAGame.Ball_Haunted_TA") , ("Archetypes.Ball.Ball_Puck", "TAGame.Ball_TA") + , ("Archetypes.Ball.Ball_Training", "TAGame.Ball_TA") + , ("Archetypes.Ball.Ball_Trajectory", "TAGame.Ball_TA") , ("Archetypes.Ball.CubeBall", "TAGame.Ball_TA") , ("Archetypes.Car.Car_Default", "TAGame.Car_TA") , ("Archetypes.CarComponents.CarComponent_Boost", "TAGame.CarComponent_Boost_TA") @@ -205,6 +211,7 @@ objectClasses = Map.fromList $ fmap , ("Archetypes.SpecialPickups.SpecialPickup_Tornado", "TAGame.SpecialPickup_Tornado_TA") , ("Archetypes.Teams.Team0", "TAGame.Team_Soccar_TA") , ("Archetypes.Teams.Team1", "TAGame.Team_Soccar_TA") + , ("Archetypes.Tutorial.Cannon", "TAGame.Cannon_TA") , ("GameInfo_Basketball.GameInfo.GameInfo_Basketball:GameReplicationInfoArchetype", "TAGame.GRI_TA") , ("GameInfo_Breakout.GameInfo.GameInfo_Breakout:GameReplicationInfoArchetype", "TAGame.GRI_TA") , ("GameInfo_FootBall.GameInfo.GameInfo_FootBall:Archetype", "TAGame.GameEvent_Football_TA") @@ -217,6 +224,8 @@ objectClasses = Map.fromList $ fmap , ("GameInfo_Items.GameInfo.GameInfo_Items:GameReplicationInfoArchetype", "TAGame.GRI_TA") , ("GameInfo_Season.GameInfo.GameInfo_Season:GameReplicationInfoArchetype", "TAGame.GRI_TA") , ("GameInfo_Soccar.GameInfo.GameInfo_Soccar:GameReplicationInfoArchetype", "TAGame.GRI_TA") + , ("GameInfo_Tutorial.GameEvent.GameEvent_Tutorial_Aerial", "TAGame.GameEvent_Tutorial_TA") + , ("GameInfo_Tutorial.GameInfo.GameInfo_Tutorial:GameReplicationInfoArchetype", "TAGame.GRI_TA") , ("Haunted_TrainStation_P.TheWorld:PersistentLevel.HauntedBallTrapTrigger_TA_0", "TAGame.HauntedBallTrapTrigger_TA") , ("Haunted_TrainStation_P.TheWorld:PersistentLevel.HauntedBallTrapTrigger_TA_1", "TAGame.HauntedBallTrapTrigger_TA") , ("ProjectX.Default__NetModeReplicator_X", "ProjectX.NetModeReplicator") @@ -238,12 +247,15 @@ attributeTypes = Map.fromList $ fmap [ ("Engine.Actor:bBlockActors", AttributeType.Boolean) , ("Engine.Actor:bCollideActors", AttributeType.Boolean) , ("Engine.Actor:bHidden", AttributeType.Boolean) + , ("Engine.Actor:bTearOff", AttributeType.Boolean) , ("Engine.Actor:DrawScale", AttributeType.Float) , ("Engine.Actor:RemoteRole", AttributeType.Enum) , ("Engine.Actor:Role", AttributeType.Enum) + , ("Engine.Actor:Rotation", AttributeType.Rotation) , ("Engine.GameReplicationInfo:bMatchIsOver", AttributeType.Boolean) , ("Engine.GameReplicationInfo:GameClass", AttributeType.FlaggedInt) , ("Engine.GameReplicationInfo:ServerName", AttributeType.String) + , ("Engine.Pawn:HealthMax", AttributeType.Int) , ("Engine.Pawn:PlayerReplicationInfo", AttributeType.FlaggedInt) , ("Engine.PlayerReplicationInfo:bBot", AttributeType.Boolean) , ("Engine.PlayerReplicationInfo:bIsSpectator", AttributeType.Boolean) @@ -292,10 +304,13 @@ attributeTypes = Map.fromList $ fmap , ("TAGame.CameraSettingsActor_TA:CameraYaw", AttributeType.Byte) , ("TAGame.CameraSettingsActor_TA:PRI", AttributeType.FlaggedInt) , ("TAGame.CameraSettingsActor_TA:ProfileSettings", AttributeType.CamSettings) + , ("TAGame.Cannon_TA:FireCount", AttributeType.Byte) + , ("TAGame.Cannon_TA:Pitch", AttributeType.Float) , ("TAGame.Car_TA:AddedBallForceMultiplier", AttributeType.Float) , ("TAGame.Car_TA:AddedCarForceMultiplier", AttributeType.Float) , ("TAGame.Car_TA:AttachedPickup", AttributeType.FlaggedInt) , ("TAGame.Car_TA:ClubColors", AttributeType.ClubColors) + , ("TAGame.Car_TA:ReplicatedCarScale", AttributeType.Float) , ("TAGame.Car_TA:ReplicatedDemolish_CustomFX", AttributeType.CustomDemolish) , ("TAGame.Car_TA:ReplicatedDemolish", AttributeType.Demolish) , ("TAGame.Car_TA:ReplicatedDemolishGoalExplosion", AttributeType.CustomDemolish) @@ -325,10 +340,15 @@ attributeTypes = Map.fromList $ fmap , ("TAGame.CrowdManager_TA:ReplicatedGlobalOneShotSound", AttributeType.FlaggedInt) , ("TAGame.GameEvent_Soccar_TA:bBallHasBeenHit", AttributeType.Boolean) , ("TAGame.GameEvent_Soccar_TA:bClubMatch", AttributeType.Boolean) + , ("TAGame.GameEvent_Soccar_TA:bMatchEnded", AttributeType.Boolean) + , ("TAGame.GameEvent_Soccar_TA:bNoContest", AttributeType.Boolean) , ("TAGame.GameEvent_Soccar_TA:bOverTime", AttributeType.Boolean) , ("TAGame.GameEvent_Soccar_TA:bUnlimitedTime", AttributeType.Boolean) , ("TAGame.GameEvent_Soccar_TA:GameTime", AttributeType.Int) + , ("TAGame.GameEvent_Soccar_TA:GameWinner", AttributeType.FlaggedInt) + , ("TAGame.GameEvent_Soccar_TA:MatchWinner", AttributeType.FlaggedInt) , ("TAGame.GameEvent_Soccar_TA:MaxScore", AttributeType.Int) + , ("TAGame.GameEvent_Soccar_TA:MVP", AttributeType.FlaggedInt) , ("TAGame.GameEvent_Soccar_TA:ReplicatedMusicStinger", AttributeType.MusicStinger) , ("TAGame.GameEvent_Soccar_TA:ReplicatedScoredOnTeam", AttributeType.Byte) , ("TAGame.GameEvent_Soccar_TA:ReplicatedServerPerformanceState", AttributeType.Byte) @@ -338,6 +358,7 @@ attributeTypes = Map.fromList $ fmap , ("TAGame.GameEvent_Soccar_TA:SeriesLength", AttributeType.Int) , ("TAGame.GameEvent_Soccar_TA:SubRulesArchetype", AttributeType.FlaggedInt) , ("TAGame.GameEvent_SoccarPrivate_TA:MatchSettings", AttributeType.PrivateMatchSettings) + , ("TAGame.GameEvent_TA:bAllowReadyUp", AttributeType.Boolean) , ("TAGame.GameEvent_TA:bCanVoteToForfeit", AttributeType.Boolean) , ("TAGame.GameEvent_TA:bHasLeaveMatchPenalty", AttributeType.Boolean) , ("TAGame.GameEvent_TA:BotSkill", AttributeType.Int) @@ -385,6 +406,7 @@ attributeTypes = Map.fromList $ fmap , ("TAGame.PRI_TA:PrimaryTitle", AttributeType.Title) , ("TAGame.PRI_TA:ReplicatedGameEvent", AttributeType.FlaggedInt) , ("TAGame.PRI_TA:ReplicatedWorstNetQualityBeyondLatency", AttributeType.Byte) + , ("TAGame.PRI_TA:RepStatTitles", AttributeType.RepStatTitle) , ("TAGame.PRI_TA:SecondaryTitle", AttributeType.Title) , ("TAGame.PRI_TA:SkillTier", AttributeType.FlaggedByte) , ("TAGame.PRI_TA:SpectatorShortcut", AttributeType.Int) @@ -416,6 +438,7 @@ attributeTypes = Map.fromList $ fmap , ("TAGame.Team_TA:GameEvent", AttributeType.FlaggedInt) , ("TAGame.Team_TA:LogoData", AttributeType.FlaggedInt) , ("TAGame.Vehicle_TA:bDriving", AttributeType.Boolean) + , ("TAGame.Vehicle_TA:bPodiumMode", AttributeType.Boolean) , ("TAGame.Vehicle_TA:bReplicatedHandbrake", AttributeType.Boolean) , ("TAGame.Vehicle_TA:ReplicatedSteer", AttributeType.Byte) , ("TAGame.Vehicle_TA:ReplicatedThrottle", AttributeType.Byte) diff --git a/src/lib/Rattletrap/Type/Attribute/RepStatTitle.hs b/src/lib/Rattletrap/Type/Attribute/RepStatTitle.hs new file mode 100644 index 00000000..4d9751ca --- /dev/null +++ b/src/lib/Rattletrap/Type/Attribute/RepStatTitle.hs @@ -0,0 +1,56 @@ +module Rattletrap.Type.Attribute.RepStatTitle where + +import qualified Rattletrap.BitGet as BitGet +import qualified Rattletrap.BitPut as BitPut +import qualified Rattletrap.Schema as Schema +import qualified Rattletrap.Type.Attribute.FlaggedInt as FlaggedInt +import qualified Rattletrap.Type.Str as Str +import qualified Rattletrap.Type.U32 as U32 +import qualified Rattletrap.Utility.Json as Json + +data RepStatTitle = RepStatTitle + { unknown :: Bool + , name :: Str.Str + , target :: FlaggedInt.FlaggedInt + , value :: U32.U32 + } + deriving (Eq, Show) + +instance Json.FromJSON RepStatTitle where + parseJSON = Json.withObject "RepStatTitle" $ \object -> do + unknown <- Json.required object "unknown" + name <- Json.required object "name" + target <- Json.required object "target" + value <- Json.required object "value" + pure RepStatTitle { unknown, name, target, value } + +instance Json.ToJSON RepStatTitle where + toJSON x = Json.object + [ Json.pair "unknown" $ unknown x + , Json.pair "name" $ name x + , Json.pair "target" $ target x + , Json.pair "value" $ value x + ] + +schema :: Schema.Schema +schema = Schema.named "attribute-rep-stat-title" $ Schema.object + [ (Json.pair "unknown" $ Schema.ref Schema.boolean, True) + , (Json.pair "name" $ Schema.ref Str.schema, True) + , (Json.pair "target" $ Schema.ref FlaggedInt.schema, True) + , (Json.pair "value" $ Schema.ref U32.schema, True) + ] + +bitPut :: RepStatTitle -> BitPut.BitPut +bitPut x = + BitPut.bool (unknown x) + <> Str.bitPut (name x) + <> FlaggedInt.bitPut (target x) + <> U32.bitPut (value x) + +bitGet :: BitGet.BitGet RepStatTitle +bitGet = BitGet.label "RepStatTitle" $ do + unknown <- BitGet.label "unknown" BitGet.bool + name <- BitGet.label "name" Str.bitGet + target <- BitGet.label "target" FlaggedInt.bitGet + value <- BitGet.label "value" U32.bitGet + pure RepStatTitle { unknown, name, target, value } diff --git a/src/lib/Rattletrap/Type/Attribute/Rotation.hs b/src/lib/Rattletrap/Type/Attribute/Rotation.hs new file mode 100644 index 00000000..ebc6e989 --- /dev/null +++ b/src/lib/Rattletrap/Type/Attribute/Rotation.hs @@ -0,0 +1,28 @@ +module Rattletrap.Type.Attribute.Rotation where + +import qualified Rattletrap.BitGet as BitGet +import qualified Rattletrap.BitPut as BitPut +import qualified Rattletrap.Schema as Schema +import qualified Rattletrap.Type.Int8Vector as Int8Vector +import qualified Rattletrap.Utility.Json as Json + +newtype Rotation = Rotation + { value :: Int8Vector.Int8Vector + } deriving (Eq, Show) + +instance Json.FromJSON Rotation where + parseJSON = fmap Rotation . Json.parseJSON + +instance Json.ToJSON Rotation where + toJSON = Json.toJSON . value + +schema :: Schema.Schema +schema = Schema.named "attribute-rotation" $ Schema.ref Int8Vector.schema + +bitPut :: Rotation -> BitPut.BitPut +bitPut = Int8Vector.bitPut . value + +bitGet :: BitGet.BitGet Rotation +bitGet = BitGet.label "Rotation" $ do + value <- BitGet.label "value" Int8Vector.bitGet + pure Rotation { value } diff --git a/src/lib/Rattletrap/Type/AttributeType.hs b/src/lib/Rattletrap/Type/AttributeType.hs index 0defa18d..dd232bc2 100644 --- a/src/lib/Rattletrap/Type/AttributeType.hs +++ b/src/lib/Rattletrap/Type/AttributeType.hs @@ -31,8 +31,10 @@ data AttributeType | PlayerHistoryKey | PrivateMatchSettings | QWord + | RepStatTitle | Reservation | RigidBodyState + | Rotation | StatEvent | String | TeamPaint diff --git a/src/lib/Rattletrap/Type/AttributeValue.hs b/src/lib/Rattletrap/Type/AttributeValue.hs index 0f6fbcca..f54e0c9c 100644 --- a/src/lib/Rattletrap/Type/AttributeValue.hs +++ b/src/lib/Rattletrap/Type/AttributeValue.hs @@ -37,8 +37,10 @@ import qualified Rattletrap.Type.Attribute.PickupNew as PickupNew import qualified Rattletrap.Type.Attribute.PlayerHistoryKey as PlayerHistoryKey import qualified Rattletrap.Type.Attribute.PrivateMatchSettings as PrivateMatchSettings import qualified Rattletrap.Type.Attribute.QWord as QWord +import qualified Rattletrap.Type.Attribute.RepStatTitle as RepStatTitle import qualified Rattletrap.Type.Attribute.Reservation as Reservation import qualified Rattletrap.Type.Attribute.RigidBodyState as RigidBodyState +import qualified Rattletrap.Type.Attribute.Rotation as Rotation import qualified Rattletrap.Type.Attribute.StatEvent as StatEvent import qualified Rattletrap.Type.Attribute.String as String import qualified Rattletrap.Type.Attribute.TeamPaint as TeamPaint @@ -82,8 +84,10 @@ data AttributeValue | PlayerHistoryKey PlayerHistoryKey.PlayerHistoryKey | PrivateMatchSettings PrivateMatchSettings.PrivateMatchSettings | QWord QWord.QWord + | RepStatTitle RepStatTitle.RepStatTitle | Reservation Reservation.Reservation | RigidBodyState RigidBodyState.RigidBodyState + | Rotation Rotation.Rotation | StatEvent StatEvent.StatEvent | String String.String | TeamPaint TeamPaint.TeamPaint @@ -124,8 +128,10 @@ instance Json.FromJSON AttributeValue where , fmap PlayerHistoryKey $ Json.required object "player_history_key" , fmap PrivateMatchSettings $ Json.required object "private_match_settings" , fmap QWord $ Json.required object "q_word" + , fmap RepStatTitle $ Json.required object "rep_stat_title" , fmap Reservation $ Json.required object "reservation" , fmap RigidBodyState $ Json.required object "rigid_body_state" + , fmap Rotation $ Json.required object "rotation" , fmap StatEvent $ Json.required object "stat_event" , fmap String $ Json.required object "string" , fmap TeamPaint $ Json.required object "team_paint" @@ -167,8 +173,10 @@ instance Json.ToJSON AttributeValue where PrivateMatchSettings y -> Json.object [Json.pair "private_match_settings" y] QWord y -> Json.object [Json.pair "q_word" y] + RepStatTitle y -> Json.object [Json.pair "rep_stat_title" y] Reservation y -> Json.object [Json.pair "reservation" y] RigidBodyState y -> Json.object [Json.pair "rigid_body_state" y] + Rotation y -> Json.object [Json.pair "rotation" y] StatEvent y -> Json.object [Json.pair "stat_event" y] String y -> Json.object [Json.pair "string" y] TeamPaint y -> Json.object [Json.pair "team_paint" y] @@ -209,8 +217,10 @@ schema = Schema.named "attribute-value" . Schema.oneOf $ fmap , ("player_history_key", PlayerHistoryKey.schema) , ("private_match_settings", PrivateMatchSettings.schema) , ("q_word", QWord.schema) + , ("rep_stat_title", RepStatTitle.schema) , ("reservation", Reservation.schema) , ("rigid_body_state", RigidBodyState.schema) + , ("rotation", Rotation.schema) , ("stat_event", StatEvent.schema) , ("string", String.schema) , ("team_paint", TeamPaint.schema) @@ -251,8 +261,10 @@ bitPut value = case value of PlayerHistoryKey x -> PlayerHistoryKey.bitPut x PrivateMatchSettings x -> PrivateMatchSettings.bitPut x QWord x -> QWord.bitPut x + RepStatTitle x -> RepStatTitle.bitPut x Reservation x -> Reservation.bitPut x RigidBodyState x -> RigidBodyState.bitPut x + Rotation x -> Rotation.bitPut x StatEvent x -> StatEvent.bitPut x String x -> String.bitPut x TeamPaint x -> TeamPaint.bitPut x @@ -308,9 +320,11 @@ bitGet version objectMap name = BitGet.label "AttributeValue" $ do AttributeType.PrivateMatchSettings -> fmap PrivateMatchSettings PrivateMatchSettings.bitGet AttributeType.QWord -> fmap QWord QWord.bitGet + AttributeType.RepStatTitle -> fmap RepStatTitle RepStatTitle.bitGet AttributeType.Reservation -> fmap Reservation $ Reservation.bitGet version AttributeType.RigidBodyState -> fmap RigidBodyState $ RigidBodyState.bitGet version + AttributeType.Rotation -> fmap Rotation Rotation.bitGet AttributeType.StatEvent -> fmap StatEvent StatEvent.bitGet AttributeType.String -> fmap String String.bitGet AttributeType.TeamPaint -> fmap TeamPaint TeamPaint.bitGet diff --git a/src/lib/Rattletrap/Type/Property/Byte.hs b/src/lib/Rattletrap/Type/Property/Byte.hs index fd487e30..d54576ee 100644 --- a/src/lib/Rattletrap/Type/Property/Byte.hs +++ b/src/lib/Rattletrap/Type/Property/Byte.hs @@ -31,7 +31,9 @@ bytePut byte = Str.bytePut (key byte) <> foldMap Str.bytePut (value byte) byteGet :: ByteGet.ByteGet Byte byteGet = ByteGet.label "Byte" $ do key <- ByteGet.label "key" Str.byteGet - value <- ByteGet.label "value" $ Monad.whenMaybe - (Str.toString key /= "OnlinePlatform_Steam") - Str.byteGet + let + isSteam = key == Str.fromString "OnlinePlatform_Steam" + isPlayStation = key == Str.fromString "OnlinePlatform_PS4" + value <- ByteGet.label "value" + $ Monad.whenMaybe (not $ isSteam || isPlayStation) Str.byteGet pure Byte { key, value } diff --git a/src/lib/Rattletrap/Type/RemoteId.hs b/src/lib/Rattletrap/Type/RemoteId.hs index dbfc4eb2..532bd124 100644 --- a/src/lib/Rattletrap/Type/RemoteId.hs +++ b/src/lib/Rattletrap/Type/RemoteId.hs @@ -8,6 +8,7 @@ import qualified Rattletrap.Schema as Schema import qualified Rattletrap.Type.RemoteId.Epic as Epic import qualified Rattletrap.Type.RemoteId.PlayStation as PlayStation import qualified Rattletrap.Type.RemoteId.PsyNet as PsyNet +import qualified Rattletrap.Type.RemoteId.QQ as QQ import qualified Rattletrap.Type.RemoteId.Splitscreen as Splitscreen import qualified Rattletrap.Type.RemoteId.Steam as Steam import qualified Rattletrap.Type.RemoteId.Switch as Switch @@ -19,6 +20,7 @@ import qualified Rattletrap.Utility.Json as Json data RemoteId = PlayStation PlayStation.PlayStation | PsyNet PsyNet.PsyNet + | QQ QQ.QQ | Splitscreen Splitscreen.Splitscreen -- ^ Really only 24 bits. | Steam Steam.Steam @@ -31,6 +33,7 @@ instance Json.FromJSON RemoteId where parseJSON = Json.withObject "RemoteId" $ \object -> Foldable.asum [ fmap PlayStation $ Json.required object "play_station" , fmap PsyNet $ Json.required object "psy_net" + , fmap QQ $ Json.required object "qq" , fmap Splitscreen $ Json.required object "splitscreen" , fmap Steam $ Json.required object "steam" , fmap Switch $ Json.required object "switch" @@ -42,6 +45,7 @@ instance Json.ToJSON RemoteId where toJSON x = case x of PlayStation y -> Json.object [Json.pair "play_station" y] PsyNet y -> Json.object [Json.pair "psy_net" y] + QQ y -> Json.object [Json.pair "qq" y] Splitscreen y -> Json.object [Json.pair "splitscreen" y] Steam y -> Json.object [Json.pair "steam" y] Switch y -> Json.object [Json.pair "switch" y] @@ -53,6 +57,7 @@ schema = Schema.named "remote-id" . Schema.oneOf $ fmap (\(k, v) -> Schema.object [(Json.pair k v, True)]) [ ("play_station", Schema.ref PlayStation.schema) , ("psy_net", Schema.ref PsyNet.schema) + , ("qq", Schema.ref QQ.schema) , ("splitscreen", Schema.ref Splitscreen.schema) , ("steam", Schema.ref Steam.schema) , ("switch", Schema.ref Switch.schema) @@ -64,6 +69,7 @@ bitPut :: RemoteId -> BitPut.BitPut bitPut remoteId = case remoteId of PlayStation x -> PlayStation.bitPut x PsyNet x -> PsyNet.bitPut x + QQ x -> QQ.bitPut x Splitscreen x -> Splitscreen.bitPut x Steam x -> Steam.bitPut x Switch x -> Switch.bitPut x @@ -76,6 +82,7 @@ bitGet version systemId = case U8.toWord8 systemId of 1 -> fmap Steam Steam.bitGet 2 -> fmap PlayStation $ PlayStation.bitGet version 4 -> fmap Xbox Xbox.bitGet + 5 -> fmap QQ QQ.bitGet 6 -> fmap Switch Switch.bitGet 7 -> fmap PsyNet $ PsyNet.bitGet version 11 -> fmap Epic Epic.bitGet diff --git a/src/lib/Rattletrap/Type/RemoteId/QQ.hs b/src/lib/Rattletrap/Type/RemoteId/QQ.hs new file mode 100644 index 00000000..c3c9914d --- /dev/null +++ b/src/lib/Rattletrap/Type/RemoteId/QQ.hs @@ -0,0 +1,32 @@ +module Rattletrap.Type.RemoteId.QQ where + +import qualified Rattletrap.BitGet as BitGet +import qualified Rattletrap.BitPut as BitPut +import qualified Rattletrap.Schema as Schema +import qualified Rattletrap.Type.U64 as U64 +import qualified Rattletrap.Utility.Json as Json + +newtype QQ + = QQ U64.U64 + deriving (Eq, Show) + +instance Json.FromJSON QQ where + parseJSON = fmap fromU64 . Json.parseJSON + +instance Json.ToJSON QQ where + toJSON = Json.toJSON . toU64 + +fromU64 :: U64.U64 -> QQ +fromU64 = QQ + +toU64 :: QQ -> U64.U64 +toU64 (QQ x) = x + +schema :: Schema.Schema +schema = U64.schema + +bitPut :: QQ -> BitPut.BitPut +bitPut = U64.bitPut . toU64 + +bitGet :: BitGet.BitGet QQ +bitGet = BitGet.label "QQ" $ fmap fromU64 U64.bitGet diff --git a/src/lib/Rattletrap/Type/Replication/Spawned.hs b/src/lib/Rattletrap/Type/Replication/Spawned.hs index a1117121..9ae6d588 100644 --- a/src/lib/Rattletrap/Type/Replication/Spawned.hs +++ b/src/lib/Rattletrap/Type/Replication/Spawned.hs @@ -118,7 +118,9 @@ bitGet matchType version classAttributeMap actorId actorMap = hasNameIndex :: Maybe Str.Str -> Version.Version -> Bool hasNameIndex matchType version = - Version.atLeast 868 14 0 version && matchType /= Just (Str.fromString "Lan") + Version.atLeast 868 20 0 version + || Version.atLeast 868 14 0 version + && (matchType /= Just (Str.fromString "Lan")) lookupName :: ClassAttributeMap.ClassAttributeMap diff --git a/src/lib/Rattletrap/Utility/Json.hs b/src/lib/Rattletrap/Utility/Json.hs index d5d12217..0dfad39a 100644 --- a/src/lib/Rattletrap/Utility/Json.hs +++ b/src/lib/Rattletrap/Utility/Json.hs @@ -2,7 +2,6 @@ {-# OPTIONS_GHC -Wno-orphans #-} {- hlint ignore "Avoid restricted extensions" -} -{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} module Rattletrap.Utility.Json @@ -18,32 +17,17 @@ module Rattletrap.Utility.Json import qualified Data.Aeson as Aeson import qualified Data.Aeson.Encode.Pretty as Aeson +import qualified Data.Aeson.Key as Key import qualified Data.Aeson.Types as Aeson import qualified Data.ByteString as ByteString import qualified Data.ByteString.Lazy as LazyByteString -# if MIN_VERSION_aeson(2, 0, 0) - -import qualified Data.Aeson.Key as Key - toKey :: String -> Key.Key toKey = Key.fromString fromKey :: Key.Key -> String fromKey = Key.toString -# else - -import qualified Data.Text as Text - -toKey :: String -> Text.Text -toKey = Text.pack - -fromKey :: Text.Text -> String -fromKey = Text.unpack - -# endif - instance Aeson.KeyValue (String, Aeson.Value) where k .= v = (fromKey k, Aeson.toJSON v) diff --git a/src/test/Main.hs b/src/test/Main.hs index dc2cc6ea..2784383e 100644 --- a/src/test/Main.hs +++ b/src/test/Main.hs @@ -52,9 +52,11 @@ replays :: [(String, String)] replays = [ ("0008", "a flip time") -- https://github.com/tfausak/rattletrap/commit/ee7afa0 , ("000b", "nintendo switch") -- https://github.com/tfausak/rattletrap/pull/60 + , ("0121", "RLCS 2") -- https://github.com/nickbabcock/boxcars/pull/120 , ("0416", "v1.78 demolition") -- https://github.com/tfausak/rattletrap/pull/164 , ("07e9", "a game mode before Neo Tokyo") -- https://github.com/tfausak/rattletrap/commit/b806f9b , ("0ad2", "some Latin-1 text") -- https://github.com/tfausak/rattletrap/commit/13a8b2d + , ("0ca5", "with QQ remote ID") -- https://github.com/nickbabcock/boxcars/pull/69 , ("0e76", "v1.95 rumble") -- https://github.com/tfausak/rattletrap/pull/237 , ("1205", "rumble mode") -- https://github.com/tfausak/rattletrap/commit/5256500 , ("160c", "a dedicated server IP") -- https://github.com/tfausak/rattletrap/commit/5c64a6d @@ -87,12 +89,15 @@ replays = , ("419a", "a club match") -- https://github.com/tfausak/rattletrap/commit/8e35043 , ("42f0", "reservations after Neo Tokyo") -- https://github.com/tfausak/rattletrap/commit/163684f , ("42f2", "anniversary ball") -- https://github.com/tfausak/rattletrap/issues/147 + , ("43a9", "tutorial") -- https://github.com/nickbabcock/boxcars/pull/70 , ("4bc3", "with timed out attribute") -- https://github.com/tfausak/rattletrap/pull/98 , ("504e", "some messages") -- https://github.com/tfausak/rattletrap/commit/1d4a538 + , ("5123", "rep stat title") -- https://github.com/nickbabcock/boxcars/pull/78 , ("520e", "no pickup attribute") -- https://github.com/tfausak/rattletrap/pull/38 , ("524f", "quat edge case") -- https://github.com/tfausak/rattletrap/pull/87 , ("52aa", "a match-ending attribute") -- https://github.com/tfausak/rattletrap/commit/5c64a6d , ("540d", "a demolish attribute") -- https://github.com/tfausak/rattletrap/commit/65ce033 + , ("54ae", "replicated car scale") -- https://github.com/nickbabcock/boxcars/pull/79 , ("551c", "private match settings") -- https://github.com/tfausak/rattletrap/commit/5c9ebfc , ("5a06", "esports items") -- https://github.com/tfausak/rattletrap/pull/114 , ("5e0b", "max channels") -- https://github.com/tfausak/rattletrap/issues/254 @@ -105,6 +110,7 @@ replays = , ("7083", "weird basketball capitalization") -- https://github.com/tfausak/rattletrap/pull/63 , ("7109", "a boost modifier") -- https://github.com/tfausak/rattletrap/commit/ee7afa0 , ("7256", "special edition") -- https://github.com/tfausak/rattletrap/pull/103 + , ("7588", "another malformed byte property") -- https://github.com/nickbabcock/boxcars/pull/68 , ("75ce", "primary and secondary titles") -- https://github.com/tfausak/rattletrap/pull/69 , ("7bf6", "an online loadouts attribute") -- https://github.com/tfausak/rattletrap/commit/89d02f7 , ("81d1", "gridiron") -- https://github.com/tfausak/rattletrap/pull/180 @@ -128,10 +134,12 @@ replays = , ("a7f0", "a ready attribute") -- https://github.com/tfausak/rattletrap/commit/78af1fd , ("a9df", "salty shores patch 1.45") -- https://github.com/tfausak/rattletrap/pull/78 , ("aa70", "patch 1.50 - TitleID attribute") -- https://github.com/tfausak/rattletrap/pull/93 + , ("ae46", "mvp") -- https://github.com/nickbabcock/boxcars/pull/80 , ("afb1", "patch 1.37") -- https://github.com/tfausak/rattletrap/pull/48 , ("b9f9", "a party leader") -- https://github.com/tfausak/rattletrap/commit/bba2cfd , ("c14f", "some mutators") -- https://github.com/tfausak/rattletrap/commit/bba2cfd , ("c23b", "new psynet id") -- https://github.com/tfausak/rattletrap/pull/118 + , ("c62c", "more boolean attributes") -- https://github.com/nickbabcock/boxcars/pull/77 , ("c837", "a spectator") -- https://github.com/tfausak/rattletrap/commit/bba2cfd , ("cc4c", "after Starbase ARC") -- https://github.com/tfausak/rattletrap/pull/20 , ("d044", "hoops mutators") -- https://github.com/tfausak/rattletrap/pull/34 @@ -140,6 +148,7 @@ replays = , ("d428", "a private hockey match") -- https://github.com/tfausak/rattletrap/commit/4c104b2 , ("d44c", "ranked tournament") -- https://github.com/tfausak/rattletrap/pull/167 , ("d52e", "psynet system id") -- https://github.com/tfausak/rattletrap/pull/99 + , ("d5d6", "health max") -- https://github.com/nickbabcock/boxcars/pull/80 , ("d7fb", "an explosion attribute") -- https://github.com/tfausak/rattletrap/commit/c554e3e , ("d818", "heatseeker") -- https://github.com/tfausak/rattletrap/pull/160 , ("db70", "new lag indicator") -- https://github.com/tfausak/rattletrap/pull/69 @@ -147,6 +156,7 @@ replays = , ("dcb3", "a pawn type attribute") -- https://github.com/tfausak/rattletrap/commit/7d7f438 , ("dd14", "v1.88") -- https://github.com/tfausak/rattletrap/pull/170 , ("de56", "a problematic product attribute") -- https://github.com/tfausak/rattletrap/issues/51 + , ("e2f9", "bTearOff") -- https://github.com/nickbabcock/boxcars/pull/76 , ("e80d", "unlimited time") -- https://github.com/tfausak/rattletrap/pull/76 , ("e978", "distracted") -- https://github.com/tfausak/rattletrap/issues/156 , ("eae3", "an actor/object ID collision") -- https://github.com/tfausak/rattletrap/commit/d8fad06