From 22e11a7822dfa83336155734ff1b63fdc35207d7 Mon Sep 17 00:00:00 2001 From: kohlerpop1 Date: Tue, 9 Apr 2024 21:38:04 -0400 Subject: [PATCH] Removed TikTokRoomInfo.getHostUser() in favor of TikTokRoomInfo.getHost(). Major rework of TikTokLinkMicBattleEvent and proto to support it. Addition changes to other files to support! --- .../data/events/TikTokLinkMicArmiesEvent.java | 11 +- .../data/events/TikTokLinkMicBattleEvent.java | 154 ++++++++++++++++-- .../tiktok/data/models/LinkMicArmy.java | 2 +- .../tiktok/data/models/LinkMicBattleTeam.java | 41 ----- .../tiktok/data/models/Picture.java | 4 +- .../tiktok/data/models/users/User.java | 25 ++- .../jwdeveloper/tiktok/live/LiveRoomInfo.java | 2 +- API/src/main/proto/data.proto | 3 +- API/src/main/proto/webcast.proto | 79 +++++++-- .../jwdeveloper/tiktok/TikTokRoomInfo.java | 5 - 10 files changed, 243 insertions(+), 83 deletions(-) delete mode 100644 API/src/main/java/io/github/jwdeveloper/tiktok/data/models/LinkMicBattleTeam.java diff --git a/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLinkMicArmiesEvent.java b/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLinkMicArmiesEvent.java index 3345737..fdd19f1 100644 --- a/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLinkMicArmiesEvent.java +++ b/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLinkMicArmiesEvent.java @@ -32,7 +32,6 @@ import lombok.Getter; import java.util.List; - /** * Triggered every time a battle participant receives points. Contains the current status of the battle and the army that suported the group. */ @@ -54,4 +53,12 @@ public class TikTokLinkMicArmiesEvent extends TikTokHeaderEvent { picture = Picture.map(msg.getImage()); battleStatus = msg.getBattleStatus(); } -} + + /** + battleStatus of 1 is Ongoing battle & 2 is Finished Battle + @return true if battle is finished otherwise false + */ + public boolean isFinished() { + return battleStatus == 2; + } +} \ No newline at end of file diff --git a/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLinkMicBattleEvent.java b/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLinkMicBattleEvent.java index 62c28ad..c8fdd2d 100644 --- a/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLinkMicBattleEvent.java +++ b/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLinkMicBattleEvent.java @@ -22,29 +22,153 @@ */ package io.github.jwdeveloper.tiktok.data.events; -import io.github.jwdeveloper.tiktok.annotations.EventMeta; -import io.github.jwdeveloper.tiktok.annotations.EventType; +import io.github.jwdeveloper.tiktok.annotations.*; import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent; -import io.github.jwdeveloper.tiktok.data.models.LinkMicBattleTeam; +import io.github.jwdeveloper.tiktok.data.models.Picture; +import io.github.jwdeveloper.tiktok.data.models.users.User; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle; import lombok.Getter; -import java.util.List; +import java.util.*; /** - * Triggered every time a battle starts. + * Triggered every time a battle starts & ends */ @Getter @EventMeta(eventType = EventType.Message) public class TikTokLinkMicBattleEvent extends TikTokHeaderEvent { - private final Long battleId; - private final List team1; - private final List team2; + private final Long battleId; + private final Integer battleStatus; + private final List teams; - public TikTokLinkMicBattleEvent(WebcastLinkMicBattle msg) { - super(msg.getCommon()); - battleId = msg.getId(); - team1 = msg.getTeams1List().stream().map(LinkMicBattleTeam::new).toList(); - team2 = msg.getTeams2List().stream().map(LinkMicBattleTeam::new).toList(); - } -} + public TikTokLinkMicBattleEvent(WebcastLinkMicBattle msg) { + super(msg.getCommon()); + battleId = msg.getId(); + battleStatus = msg.getBattleStatus(); + teams = new ArrayList<>(); + if (msg.getHostTeamCount() == 2) { // 1v1 battle + teams.add(new Team1v1(msg.getHostTeam(0), msg)); + teams.add(new Team1v1(msg.getHostTeam(1), msg)); + } else { // 2v2 battle + if (isFinished()) { + teams.add(new Team2v2(msg.getHostData2V2List().stream().filter(data -> data.getTeamNumber() == 1).findFirst().orElse(null), msg)); + teams.add(new Team2v2(msg.getHostData2V2List().stream().filter(data -> data.getTeamNumber() == 2).findFirst().orElse(null), msg)); + } else { + teams.add(new Team2v2(msg.getHostTeam(0), msg.getHostTeam(1), msg)); + teams.add(new Team2v2(msg.getHostTeam(2), msg.getHostTeam(3), msg)); + } + } + + // Info: + // - msg.getDetailsList() & msg.getViewerTeamList() both only have content when battle is finished + // - msg.getDetailsCount() & msg.getViewerTeamCount() always is 2 only when battle is finished + // - msg.getHostTeamCount() always is 2 for 1v1 or 4 for 2v2 + } + + /** + battleStatus of 4 is Ongoing battle & 5 is Finished Battle + @return true if battle is finished otherwise false + */ + public boolean isFinished() { + return battleStatus == 5; + } + + public abstract static class Team { + /** + * Provides a check for verifying if this team represents a 1v1 Team. + * @return true if this team is of type {@link Team1v1}, false otherwise. + */ + public boolean is1v1Team() { + return this instanceof Team1v1; + } + + /** + * Provides a check for verifying if this team represents a 1v1 Team. + * @return true if this team is of type {@link Team1v1}, false otherwise. + */ + public boolean is2v2Team() { + return this instanceof Team2v2; + } + + /** + * Convenience method to get this team as a {@link Team1v1}. If this team is of some + * other type, an {@link IllegalStateException} will result. Hence it is best to use this method + * after ensuring that this element is of the desired type by calling {@link #is1v1Team()} first. + * + * @return this team as a {@link Team1v1}. + * @throws IllegalStateException if this team is of another type. + */ + public Team1v1 getAs1v1Team() { + if (is1v1Team()) + return (Team1v1) this; + throw new IllegalStateException("Not a 1v1Team: " + this); + } + + /** + * Convenience method to get this team as a {@link Team2v2}. If this team is of some + * other type, an {@link IllegalStateException} will result. Hence it is best to use this method + * after ensuring that this element is of the desired type by calling {@link #is2v2Team()} first. + * + * @return this team as a {@link Team2v2}. + * @throws IllegalStateException if this team is of another type. + */ + public Team2v2 getAs2v2Team() { + if (is2v2Team()) + return (Team2v2) this; + throw new IllegalStateException("Not a 2v2Team: " + this); + } + } + + @Getter + public static class Team1v1 extends Team { + /** Value >= 0 when finished otherwise -1 */ + private final int totalPoints; + private final int winStreak; + private final User host; + private final List viewers; + + public Team1v1(WebcastLinkMicBattle.LinkMicBattleHost hostTeam, WebcastLinkMicBattle msg) { + long hostId = hostTeam.getId(); + this.winStreak = msg.getTeamDataList().stream().filter(data -> data.getTeamId() == hostId).map(data -> data.getData().getWinStreak()).findFirst().orElse(-1); + this.totalPoints = msg.getDetailsList().stream().filter(dets -> dets.getId() == hostId).map(dets -> dets.getSummary().getPoints()).findFirst().orElse(-1); + this.host = new User(hostTeam.getHostGroup(0).getHost(0)); + this.viewers = msg.getViewerTeamList().stream().filter(team -> team.getId() == hostId).findFirst().map(topViewers -> + topViewers.getViewerGroup(0).getViewerList().stream().map(Viewer::new).toList()).orElseGet(ArrayList::new); + } + } + + @Getter + public static class Team2v2 extends Team { + /** Value >= 0 when finished otherwise -1 */ + private final int totalPoints; + + private final List hosts; + private final List viewers; + + public Team2v2(WebcastLinkMicBattle.LinkMicBattleHost hostTeam1, WebcastLinkMicBattle.LinkMicBattleHost hostTeam2, WebcastLinkMicBattle msg) { + this.totalPoints = -1; + this.hosts = List.of(new User(hostTeam1.getHostGroup(0).getHost(0)), new User(hostTeam2.getHostGroup(0).getHost(0))); + this.viewers = new ArrayList<>(); + } + + public Team2v2(WebcastLinkMicBattle.Host2v2Data hd, WebcastLinkMicBattle msg) { + this.totalPoints = hd.getTotalPoints(); + var host = new User(msg.getHostTeamList().stream().filter(data -> data.getId() == hd.getHostdata(0).getHostId()).findFirst().orElseThrow().getHostGroup(0).getHost(0)); + var cohost = new User(msg.getHostTeamList().stream().filter(data -> data.getId() == hd.getHostdata(1).getHostId()).findFirst().orElseThrow().getHostGroup(0).getHost(0)); + this.hosts = List.of(host, cohost); + this.viewers = msg.getViewerTeamList().stream().filter(team -> team.getId() == host.getId() || team.getId() == cohost.getId()).findFirst().map(topViewers -> + topViewers.getViewerGroup(0).getViewerList().stream().map(Viewer::new).toList()).orElseGet(ArrayList::new); + } + } + + @Getter + public static class Viewer { + private final User user; + private final int points; + + public Viewer(WebcastLinkMicBattle.LinkMicBattleTopViewers.TopViewerGroup.TopViewer topViewer) { + this.user = new User(topViewer.getId(), null, topViewer.getProfileId(), Picture.map(topViewer.getImages(0))); + this.points = topViewer.getPoints(); + } + } +} \ No newline at end of file diff --git a/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/LinkMicArmy.java b/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/LinkMicArmy.java index 0777172..c679c93 100644 --- a/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/LinkMicArmy.java +++ b/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/LinkMicArmy.java @@ -46,4 +46,4 @@ public class LinkMicArmy { List Users; Integer Points; } -} +} \ No newline at end of file diff --git a/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/LinkMicBattleTeam.java b/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/LinkMicBattleTeam.java deleted file mode 100644 index 59141d8..0000000 --- a/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/LinkMicBattleTeam.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package io.github.jwdeveloper.tiktok.data.models; - - -import io.github.jwdeveloper.tiktok.data.models.users.User; -import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle; -import lombok.Value; - -import java.util.List; - -@Value -public class LinkMicBattleTeam { - Long teamId; - List users; - - public LinkMicBattleTeam(WebcastLinkMicBattle.LinkMicBattleTeam team) { - this.teamId = team.getId(); - this.users = team.getUsersList().stream().map(User::new).toList(); - } -} diff --git a/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/Picture.java b/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/Picture.java index 2f1ef99..c55a053 100644 --- a/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/Picture.java +++ b/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/Picture.java @@ -44,11 +44,11 @@ public class Picture { } public static Picture map(io.github.jwdeveloper.tiktok.messages.data.Image profilePicture) { - var index = profilePicture.getUrlListCount() - 1; + var index = profilePicture.getUrlCount() - 1; if (index < 0) { return new Picture(""); } - var url = profilePicture.getUrlList(index); + var url = profilePicture.getUrl(index); return new Picture(url); } diff --git a/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/users/User.java b/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/users/User.java index 8916799..cab957b 100644 --- a/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/users/User.java +++ b/API/src/main/java/io/github/jwdeveloper/tiktok/data/models/users/User.java @@ -24,7 +24,7 @@ package io.github.jwdeveloper.tiktok.data.models.users; import io.github.jwdeveloper.tiktok.data.models.badges.Badge; import io.github.jwdeveloper.tiktok.data.models.Picture; -import io.github.jwdeveloper.tiktok.messages.webcast.WebcastEnvelopeMessage; +import io.github.jwdeveloper.tiktok.messages.webcast.*; import lombok.AccessLevel; import lombok.Getter; @@ -136,6 +136,14 @@ public class User { this.picture = picture; } + public User(long id, String name, String profileId, Picture picture) { + this(id, name, profileId, picture, 0, 0, List.of(Badge.empty())); + } + + public User(WebcastLinkMicBattle.LinkMicBattleHost.HostGroup.Host host) { + this(host.getId(), host.getName(), host.getProfileId(), Picture.map(host.getImages(0))); + } + public User(io.github.jwdeveloper.tiktok.messages.data.User user) { this(user.getId(), user.getDisplayId(), Picture.map(user.getAvatarThumb())); profileName = user.getNickname(); @@ -159,7 +167,6 @@ public class User { } } - public static User EMPTY = new User(0L, "", Picture.Empty(), @@ -209,4 +216,18 @@ public class User { 0, List.of(Badge.empty())); } + + @Override + public String toString() { + return "User{" + + "id=" + id + + ", name='" + name + "'" + + ", profileName='" + profileName + "'" + + ", picture=" + picture + + ", following=" + following + + ", followers=" + followers + + ", badges=" + badges + + ", attributes=" + attributes + + "}"; + } } \ No newline at end of file diff --git a/API/src/main/java/io/github/jwdeveloper/tiktok/live/LiveRoomInfo.java b/API/src/main/java/io/github/jwdeveloper/tiktok/live/LiveRoomInfo.java index 0f624a5..b3df78c 100644 --- a/API/src/main/java/io/github/jwdeveloper/tiktok/live/LiveRoomInfo.java +++ b/API/src/main/java/io/github/jwdeveloper/tiktok/live/LiveRoomInfo.java @@ -47,7 +47,7 @@ public interface LiveRoomInfo String getRoomId(); String getHostName(); String getTitle(); - User getHostUser(); + User getHost(); List getUsersRanking(); ConnectionState getConnectionState(); } \ No newline at end of file diff --git a/API/src/main/proto/data.proto b/API/src/main/proto/data.proto index acea8e6..f82d407 100644 --- a/API/src/main/proto/data.proto +++ b/API/src/main/proto/data.proto @@ -102,7 +102,8 @@ message Text { // @Image message Image { - repeated string urlList = 1; + repeated string url = 1; + string extras = 2; bool isAnimated = 9; } diff --git a/API/src/main/proto/webcast.proto b/API/src/main/proto/webcast.proto index d1fba54..9b4ed79 100644 --- a/API/src/main/proto/webcast.proto +++ b/API/src/main/proto/webcast.proto @@ -574,11 +574,26 @@ message WebcastLinkMicBattle { Common common = 1; uint64 id = 2; LinkMicBattleConfig battleConfig = 3; - uint32 data2 = 4; + int32 battleStatus = 4; // SHOULD BE AN ENUM repeated LinkMicBattleDetails details = 5; - repeated LinkMicBattleTeam teams1 = 9; - repeated LinkMicBattleTeam teams2 = 10; + repeated LinkMicBattleTopViewers viewerTeam = 9; + repeated LinkMicBattleHost hostTeam = 10; repeated LinkMicBattleTeamData teamData = 13; + uint64 unknownData16 = 16; + repeated Host2v2Data hostData2v2 = 17; + + message Host2v2Data { + uint32 teamNumber = 1; + repeated HostData hostdata = 2; + uint32 unknownData3 = 3; + uint32 totalPoints = 4; + + message HostData { + uint64 hostId = 1; + uint32 points = 2; + string hostIdStr = 3; + } + } message LinkMicBattleConfig { uint64 id1 = 1; @@ -586,29 +601,69 @@ message WebcastLinkMicBattle { uint32 data1 = 3; uint64 id2 = 4; uint32 data2 = 5; + uint32 data3 = 6; + uint32 data4 = 8; + } + + message LinkMicBattleTeamData { + uint64 teamId = 1; + LinkMicBattleData data = 2; } message LinkMicBattleData { uint64 id = 1; uint32 data1 = 2; - uint32 data2 = 3; + uint32 winStreak = 3; uint32 data3 = 5; string url = 6; } message LinkMicBattleDetails { uint64 id = 1; - LinkMicBattleData details = 2; + LinkMicBattleDetailsSummary summary = 2; + + message LinkMicBattleDetailsSummary { + uint64 id = 1; + uint32 unknownData2 = 2; + uint32 points = 3; + } } - message LinkMicBattleTeam { + message LinkMicBattleTopViewers { uint64 id = 1; - repeated User users = 2; + repeated TopViewerGroup viewerGroup = 2; + + message TopViewerGroup { + repeated TopViewer viewer = 1; + uint32 points = 2; + string hostIdOrTeamNum = 3; // 1v1 Battle = HostId | 2v2 Battle = Team # - 1 & 2 + + message TopViewer { + uint64 id = 1; + uint32 points = 2; + string profileId = 3; + repeated Image images = 4; + string stringId = 6; + } + } } - message LinkMicBattleTeamData { - uint64 teamId = 1; - LinkMicBattleData data = 2; + message LinkMicBattleHost { + uint64 id = 1; + repeated HostGroup hostGroup = 2; + + message HostGroup { + repeated Host host = 1; + uint32 points = 2; + string hostId = 3; + + message Host { + uint64 id = 1; + string profileId = 2; + repeated Image images = 3; + string name = 4; + } + } } } @@ -792,6 +847,4 @@ message RoomVerifyMessage { string content = 3; int64 noticeType = 4; bool closeRoom = 5; -} - - +} \ No newline at end of file diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokRoomInfo.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokRoomInfo.java index a2043a2..c02a7e3 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokRoomInfo.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokRoomInfo.java @@ -61,11 +61,6 @@ public class TikTokRoomInfo implements LiveRoomInfo { return connectionState == state; } - @Override - public User getHostUser() { - return host; - } - public void updateRanking(List rankingUsers) { usersRanking.clear(); usersRanking.addAll(rankingUsers);