diff --git a/.gitignore b/.gitignore index 34dba4da..2f54edb3 100644 --- a/.gitignore +++ b/.gitignore @@ -74,8 +74,8 @@ cellid.txt loginkey.txt sentry.bin server_list.bin -steamapps/ -userfiles/ +/steamapps/ +/userfiles/ # Kotlin 2.0 /.kotlin/sessions/ diff --git a/src/main/java/in/dragonbra/javasteam/steam/handlers/steamapps/AppProcessInfo.kt b/src/main/java/in/dragonbra/javasteam/steam/handlers/steamapps/AppProcessInfo.kt new file mode 100644 index 00000000..5fab7195 --- /dev/null +++ b/src/main/java/in/dragonbra/javasteam/steam/handlers/steamapps/AppProcessInfo.kt @@ -0,0 +1,7 @@ +package `in`.dragonbra.javasteam.steam.handlers.steamapps + +data class AppProcessInfo( + val processId: Int, + val processIdParent: Int, + val parentIsSteam: Boolean, +) diff --git a/src/main/java/in/dragonbra/javasteam/steam/handlers/steamapps/GamePlayedInfo.kt b/src/main/java/in/dragonbra/javasteam/steam/handlers/steamapps/GamePlayedInfo.kt new file mode 100644 index 00000000..4f4a1aee --- /dev/null +++ b/src/main/java/in/dragonbra/javasteam/steam/handlers/steamapps/GamePlayedInfo.kt @@ -0,0 +1,37 @@ +package `in`.dragonbra.javasteam.steam.handlers.steamapps + +@Suppress("ArrayInDataClass") +data class GamePlayedInfo( + val steamIdGs: Long = 0, + val gameId: Long, + val deprecatedGameIpAddress: Int = 0, + val gamePort: Int = 0, + val isSecure: Boolean = false, + val token: ByteArray = byteArrayOf(), + val gameExtraInfo: String = "", + val gameDataBlob: ByteArray? = null, + val processId: Int, + val streamingProviderId: Int = 0, + val gameFlags: Int = 0, + val ownerId: Int, + val vrHmdVendor: String = "", + val vrHmdModel: String = "", + val launchOptionType: Int = 0, + val primaryControllerType: Int = -1, + val primarySteamControllerSerial: String = "", + val totalSteamControllerCount: Int = 0, + val totalNonSteamControllerCount: Int = 0, + val controllerWorkshopFileId: Long = 0, + val launchSource: Int = 0, + val vrHmdRuntime: Int = 0, + val gameIpAddress: ProtoIPAddress<*>? = null, + val controllerConnectionType: Int = 0, + val gameOsPlatform: Int = -1, + val gameBuildId: Int, + val compatToolId: Int = 0, + val compatToolCmd: String = "", + val compatToolBuildId: Int = 0, + val betaName: String = "", + val dlcContext: Int = 0, + val processIdList: List = emptyList(), +) diff --git a/src/main/java/in/dragonbra/javasteam/steam/handlers/steamapps/ProtoIPAddress.kt b/src/main/java/in/dragonbra/javasteam/steam/handlers/steamapps/ProtoIPAddress.kt new file mode 100644 index 00000000..a330c2be --- /dev/null +++ b/src/main/java/in/dragonbra/javasteam/steam/handlers/steamapps/ProtoIPAddress.kt @@ -0,0 +1,20 @@ +package `in`.dragonbra.javasteam.steam.handlers.steamapps + +abstract class ProtoIPAddress { + abstract fun getValue(): T +} +data class ProtoIPv4( + private val ip: Int +) : ProtoIPAddress() { + override fun getValue(): Int { + return ip + } +} +@Suppress("ArrayInDataClass") +data class ProtoIPv6( + private val ip: ByteArray +) : ProtoIPAddress() { + override fun getValue(): ByteArray { + return ip + } +} diff --git a/src/main/java/in/dragonbra/javasteam/steam/handlers/steamapps/SteamApps.kt b/src/main/java/in/dragonbra/javasteam/steam/handlers/steamapps/SteamApps.kt index 7c4d2111..07b8385d 100644 --- a/src/main/java/in/dragonbra/javasteam/steam/handlers/steamapps/SteamApps.kt +++ b/src/main/java/in/dragonbra/javasteam/steam/handlers/steamapps/SteamApps.kt @@ -1,10 +1,14 @@ package `in`.dragonbra.javasteam.steam.handlers.steamapps +import com.google.protobuf.ByteString import `in`.dragonbra.javasteam.base.ClientMsg import `in`.dragonbra.javasteam.base.ClientMsgProtobuf import `in`.dragonbra.javasteam.base.IPacketMsg import `in`.dragonbra.javasteam.enums.EMsg +import `in`.dragonbra.javasteam.enums.EOSType import `in`.dragonbra.javasteam.generated.MsgClientGetLegacyGameKey +import `in`.dragonbra.javasteam.protobufs.steamclient.* +import `in`.dragonbra.javasteam.protobufs.steamclient.SteammessagesClientserver.CMsgClientGamesPlayed import `in`.dragonbra.javasteam.protobufs.steamclient.SteammessagesClientserver.CMsgClientGetAppOwnershipTicket import `in`.dragonbra.javasteam.protobufs.steamclient.SteammessagesClientserver2.CMsgClientCheckAppBetaPassword import `in`.dragonbra.javasteam.protobufs.steamclient.SteammessagesClientserver2.CMsgClientGetDepotDecryptionKey @@ -295,6 +299,87 @@ class SteamApps : ClientMsgHandler() { return AsyncJobSingle(client, request.sourceJobID) } + /** + * Notify Steam of games being played + * TODO: Support appid/non-steam game, [relevant discord msg](https://discord.com/channels/420907597906968586/420907598527594497/464573011274629151) + * + * @param gamesPlayed The list of the different game processes + * @param clientOsType The OS type of the client launching the games + */ + @Suppress("DuplicatedCode", "unused") + @JvmOverloads + // JavaSteam Addition + fun notifyGamesPlayed( + gamesPlayed: List = emptyList(), + clientOsType: EOSType, + cloudGamingPlatform: Int = 0, + recentReAuthentication: Boolean = false, + ) { + val request = ClientMsgProtobuf( + CMsgClientGamesPlayed::class.java, + EMsg.ClientGamesPlayedWithDataBlob + ).apply { + sourceJobID = client.getNextJobID() + + body.addAllGamesPlayed(gamesPlayed.map { gamePlayed -> + CMsgClientGamesPlayed.GamePlayed.newBuilder().apply { + this.steamIdGs = gamePlayed.steamIdGs + this.gameId = gamePlayed.gameId + this.deprecatedGameIpAddress = gamePlayed.deprecatedGameIpAddress + this.gamePort = gamePlayed.gamePort + this.isSecure = gamePlayed.isSecure + this.token = ByteString.copyFrom(gamePlayed.token) + this.gameExtraInfo = gamePlayed.gameExtraInfo + gamePlayed.gameDataBlob?.let { gameDataBlob -> + this.gameDataBlob = ByteString.copyFrom(gameDataBlob) + } + this.processId = gamePlayed.processId + this.streamingProviderId = gamePlayed.streamingProviderId + this.gameFlags = gamePlayed.gameFlags + this.ownerId = gamePlayed.ownerId + this.vrHmdVendor = gamePlayed.vrHmdVendor + this.vrHmdModel = gamePlayed.vrHmdModel + this.launchOptionType = gamePlayed.launchOptionType + this.primaryControllerType = gamePlayed.primaryControllerType + this.primarySteamControllerSerial = gamePlayed.primarySteamControllerSerial + this.totalSteamControllerCount = gamePlayed.totalSteamControllerCount + this.totalNonSteamControllerCount = gamePlayed.totalNonSteamControllerCount + this.controllerWorkshopFileId = gamePlayed.controllerWorkshopFileId + this.launchSource = gamePlayed.launchSource + this.vrHmdRuntime = gamePlayed.vrHmdRuntime + gamePlayed.gameIpAddress?.let { ipAddress -> + this.gameIpAddress = SteammessagesBase.CMsgIPAddress.newBuilder().apply { + when (ipAddress) { + is ProtoIPv4 -> this.v4 = ipAddress.getValue() + is ProtoIPv6 -> this.v6 = ByteString.copyFrom(ipAddress.getValue()) + } + }.build() + } + this.controllerConnectionType = gamePlayed.controllerConnectionType + this.gameOsPlatform = gamePlayed.gameOsPlatform + this.gameBuildId = gamePlayed.gameBuildId + this.compatToolId = gamePlayed.compatToolId + this.compatToolCmd = gamePlayed.compatToolCmd + this.compatToolBuildId = gamePlayed.compatToolBuildId + this.betaName = gamePlayed.betaName + this.dlcContext = gamePlayed.dlcContext + this.addAllProcessIdList(gamePlayed.processIdList.map { processInfo -> + CMsgClientGamesPlayed.ProcessInfo.newBuilder().apply { + this.processId = processInfo.processId + this.processIdParent = processInfo.processIdParent + this.parentIsSteam = processInfo.parentIsSteam + }.build() + }) + }.build() + }) + body.clientOsType = clientOsType.code() + body.cloudGamingPlatform = cloudGamingPlatform + body.recentReauthentication = recentReAuthentication + } + + client.send(request) + } + /** * Handles a client message. This should not be called directly. *