Skip to content

Commit 9cb2f54

Browse files
author
games647
committed
Add team scoreboard API
1 parent 9dbe5d6 commit 9cb2f54

File tree

12 files changed

+242
-18
lines changed

12 files changed

+242
-18
lines changed

plugin/src/main/java/com/github/games647/scoreboardstats/ScoreboardStats.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public class ScoreboardStats extends JavaPlugin {
3232

3333
private static Logger createLoggerFromJDK(java.util.logging.Logger parent) {
3434
try {
35+
parent.setLevel(Level.ALL);
36+
3537
Class<JDK14LoggerAdapter> adapterClass = JDK14LoggerAdapter.class;
3638
Constructor<JDK14LoggerAdapter> cons = adapterClass.getDeclaredConstructor(java.util.logging.Logger.class);
3739
cons.setAccessible(true);

plugin/src/main/java/com/github/games647/scoreboardstats/scoreboard/Objective.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ public class Objective {
2323

2424
private static final int MAX_ITEM_SIZE = 15;
2525
private static final int SIDEBAR_SLOT = 1;
26+
2627
//A scoreboard can only hold < 16 scores
2728
final Map<String, Integer> scores = Maps.newHashMapWithExpectedSize(MAX_ITEM_SIZE);
29+
2830
private final PlayerScoreboard scoreboard;
2931
private final String objectiveId;
3032
String displayName;

plugin/src/main/java/com/github/games647/scoreboardstats/scoreboard/PacketListener.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.comphenix.protocol.events.PacketEvent;
88
import com.comphenix.protocol.wrappers.EnumWrappers.ScoreboardAction;
99

10+
import java.util.Collection;
1011
import java.util.Optional;
1112

1213
import org.bukkit.Bukkit;
@@ -17,6 +18,7 @@
1718
import static com.comphenix.protocol.PacketType.Play.Server.SCOREBOARD_DISPLAY_OBJECTIVE;
1819
import static com.comphenix.protocol.PacketType.Play.Server.SCOREBOARD_OBJECTIVE;
1920
import static com.comphenix.protocol.PacketType.Play.Server.SCOREBOARD_SCORE;
21+
import static com.comphenix.protocol.PacketType.Play.Server.SCOREBOARD_TEAM;
2022

2123
/**
2224
* Listening all outgoing packets and check + handle for possibly client crash cases. This Listener should only read and
@@ -29,7 +31,7 @@ class PacketListener extends PacketAdapter {
2931
private final PacketManager manager;
3032

3133
PacketListener(Plugin plugin, PacketManager manager) {
32-
super(plugin, SCOREBOARD_DISPLAY_OBJECTIVE, SCOREBOARD_OBJECTIVE, SCOREBOARD_SCORE);
34+
super(plugin, SCOREBOARD_DISPLAY_OBJECTIVE, SCOREBOARD_OBJECTIVE, SCOREBOARD_SCORE, SCOREBOARD_TEAM);
3335

3436
this.manager = manager;
3537
}
@@ -58,6 +60,8 @@ public void onPacketSending(PacketEvent packetEvent) {
5860
handleObjectivePacket(player, packet);
5961
} else if (packetType.equals(SCOREBOARD_DISPLAY_OBJECTIVE)) {
6062
handleDisplayPacket(player, packet);
63+
} else if (packetType.equals(SCOREBOARD_TEAM)) {
64+
handleTeamPacket(player, packet);
6165
}
6266
});
6367
}
@@ -128,4 +132,29 @@ private void handleDisplayPacket(Player player, PacketContainer packet) {
128132
.ifPresent(objective -> scoreboard.sidebarObjective = null);
129133
}
130134
}
135+
136+
private void handleTeamPacket(Player player, PacketContainer packet) {
137+
String teamId = packet.getStrings().read(0);
138+
Optional<TeamMode> optMode = TeamMode.getMode(packet.getIntegers().read(0));
139+
140+
if (!optMode.isPresent() || teamId.length() > 16) {
141+
return;
142+
}
143+
144+
TeamMode mode = optMode.get();
145+
146+
PlayerScoreboard scoreboard = manager.getScoreboard(player);
147+
if (mode == TeamMode.CREATE) {
148+
Collection<String> members = packet.getSpecificModifier(Collection.class).read(0);
149+
scoreboard.teamsByName.put(teamId, new Team(scoreboard, teamId, members));
150+
} else if (mode == TeamMode.REMOVE) {
151+
scoreboard.teamsByName.remove(teamId);
152+
} else if (mode == TeamMode.ADD_MEMBER) {
153+
Collection<String> members = packet.getSpecificModifier(Collection.class).read(0);
154+
scoreboard.getTeam(teamId).ifPresent(team -> team.members.addAll(members));
155+
} else if (mode == TeamMode.REMOVE_MEMBER) {
156+
Collection<String> members = packet.getSpecificModifier(Collection.class).read(0);
157+
scoreboard.getTeam(teamId).ifPresent(team -> team.members.removeAll(members));
158+
}
159+
}
131160
}

plugin/src/main/java/com/github/games647/scoreboardstats/scoreboard/PlayerScoreboard.java

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
public class PlayerScoreboard {
2020

2121
final Map<String, Objective> objectivesByName = Maps.newHashMap();
22+
final Map<String, Team> teamsByName = Maps.newHashMap();
23+
2224
private final Player player;
2325
Objective sidebarObjective;
2426

@@ -27,12 +29,7 @@ public PlayerScoreboard(Player player) {
2729
}
2830

2931
public Objective getOrCreateObjective(String objectiveId) {
30-
Objective objective = objectivesByName.get(objectiveId);
31-
if (objective == null) {
32-
objective = addObjective(objectiveId);
33-
}
34-
35-
return objective;
32+
return objectivesByName.computeIfAbsent(objectiveId, this::addObjective);
3633
}
3734

3835
public Optional<Objective> getObjective(String objectiveId) {
@@ -63,7 +60,32 @@ public Optional<Objective> getSidebarObjective() {
6360

6461
public void removeObjective(String objectiveId) {
6562
Objective objective = objectivesByName.remove(objectiveId);
66-
objective.sendObjectivePacket(State.REMOVE);
63+
if (objective != null) {
64+
objective.sendObjectivePacket(State.REMOVE);
65+
}
66+
}
67+
68+
public Optional<Team> getTeam(String teamId) {
69+
return Optional.ofNullable(teamsByName.get(teamId));
70+
}
71+
72+
public Team addTeam(String teamId) {
73+
Team team = new Team(this, teamId);
74+
teamsByName.put(teamId, team);
75+
76+
team.sendCreatePacket();
77+
return team;
78+
}
79+
80+
public Collection<Team> getTeams() {
81+
return teamsByName.values();
82+
}
83+
84+
public void removeTeam(String teamId) {
85+
Team team = teamsByName.remove(teamId);
86+
if (team != null) {
87+
team.sendRemovePacket();
88+
}
6789
}
6890

6991
public Player getOwner() {
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package com.github.games647.scoreboardstats.scoreboard;
2+
3+
import com.comphenix.protocol.PacketType.Play.Server;
4+
import com.comphenix.protocol.events.PacketContainer;
5+
import com.google.common.collect.ImmutableSet;
6+
import com.google.common.collect.Sets;
7+
8+
import java.util.Collection;
9+
import java.util.Set;
10+
11+
public class Team {
12+
13+
private final PlayerScoreboard scoreboard;
14+
private final String teamId;
15+
16+
final Set<String> members = Sets.newHashSet();
17+
String prefix;
18+
String suffix;
19+
20+
public Team(PlayerScoreboard scoreboard, String teamId) {
21+
this.scoreboard = scoreboard;
22+
this.teamId = teamId;
23+
}
24+
25+
public Team(PlayerScoreboard scoreboard, String teamId, Collection<String> members) {
26+
this(scoreboard, teamId);
27+
28+
this.members.addAll(members);
29+
}
30+
31+
public String getId() {
32+
return teamId;
33+
}
34+
35+
public boolean hasMember(String member) {
36+
return members.contains(member);
37+
}
38+
39+
public boolean addMember(String member) {
40+
return members.add(member);
41+
}
42+
43+
public boolean removeMember(String member) {
44+
return members.remove(member);
45+
}
46+
47+
public Set<String> getMembers() {
48+
return ImmutableSet.copyOf(members);
49+
}
50+
51+
public String getPrefix() {
52+
return prefix;
53+
}
54+
55+
public void setPrefix(String prefix) {
56+
this.prefix = prefix;
57+
}
58+
59+
public String getSuffix() {
60+
return suffix;
61+
}
62+
63+
public void setSuffix(String suffix) {
64+
this.suffix = suffix;
65+
}
66+
67+
void sendCreatePacket() {
68+
PacketContainer packet = newPacket(TeamMode.CREATE);
69+
packet.getSpecificModifier(Collection.class).write(0, ImmutableSet.copyOf(members));
70+
scoreboard.sendPacket(packet);
71+
}
72+
73+
void sendMemberUpdatePacket(boolean add) {
74+
PacketContainer packet = newPacket(add ? TeamMode.ADD_MEMBER : TeamMode.REMOVE_MEMBER);
75+
packet.getSpecificModifier(Collection.class).write(0, ImmutableSet.copyOf(members));
76+
scoreboard.sendPacket(packet);
77+
}
78+
79+
void sendRemovePacket() {
80+
PacketContainer packet = newPacket(TeamMode.REMOVE);
81+
scoreboard.sendPacket(packet);
82+
}
83+
84+
private PacketContainer newPacket(TeamMode mode) {
85+
PacketContainer packet = new PacketContainer(Server.SCOREBOARD_TEAM);
86+
packet.getStrings().write(0, teamId);
87+
88+
packet.getIntegers().write(1, mode.ordinal());
89+
return packet;
90+
}
91+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.github.games647.scoreboardstats.scoreboard;
2+
3+
import java.util.Optional;
4+
5+
public enum TeamMode {
6+
7+
CREATE,
8+
9+
REMOVE,
10+
11+
UPDATE,
12+
13+
ADD_MEMBER,
14+
15+
REMOVE_MEMBER;
16+
17+
public static Optional<TeamMode> getMode(int id) {
18+
TeamMode[] values = TeamMode.values();
19+
if (id < 0 || id >= values.length) {
20+
return Optional.empty();
21+
}
22+
23+
return Optional.of(values[id]);
24+
}
25+
}

pvp/src/main/java/com/github/games647/scoreboardstats/pvp/SignListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ private Optional<String> replace(Player player, String line) {
5656
if (line.contains(entry.getKey())) {
5757
Function<PlayerStats, Integer> fct = entry.getValue();
5858
return Optional.of(database.getStats(player)
59-
.map(fct::apply)
59+
.map(fct)
6060
.map(value -> Integer.toString(value))
6161
.orElse("Not loaded"));
6262
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
package com.github.games647.scoreboardstats.scoreboard;
22

3+
/**
4+
* Represents a scoreboard score item or "line"
5+
*/
36
public interface Score {
47

8+
/**
9+
* Get the current display name for the scoreboard score
10+
*
11+
* @return display name
12+
*/
513
String getName();
614

15+
/**
16+
* Score value that is displayed next to the item
17+
*
18+
* @return the current score
19+
*/
720
int getScore();
821
}

variables/src/main/java/com/github/games647/scoreboardstats/variables/DefaultReplacer.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,31 @@
66
import java.lang.annotation.RetentionPolicy;
77
import java.lang.annotation.Target;
88

9+
/**
10+
* Represents that a replacer that is added to this plugin by this plugin itself.
11+
*/
912
@Documented
1013
@Target(ElementType.TYPE)
1114
@Retention(RetentionPolicy.RUNTIME)
1215
public @interface DefaultReplacer {
1316

14-
String plugin() default "";
17+
/**
18+
* Returns the required plugin that is needed to activate this variables. It defaults to
19+
* this scoreboard plugin itself.
20+
*
21+
* @return the required plugin dependency for this variables
22+
*/
23+
String plugin() default "ScoreboardStats";
1524

25+
/**
26+
* Minimum required version to activate the replacers that will be registered. The version format
27+
* have to be in semVer format major.minor.fix with
28+
* <br>
29+
* 1.2.3 is higher than 1.1.3
30+
* <br>
31+
* 2.5 higher than 1.0.0
32+
*
33+
* @return required version or empty for no required version
34+
*/
1635
String requiredVersion() default "";
1736
}

variables/src/main/java/com/github/games647/scoreboardstats/variables/DefaultReplacers.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
import org.bukkit.plugin.Plugin;
44

5+
/**
6+
* Represents a default replacers instance that will register default variables.
7+
*
8+
* @param <T> plugin class for easier access to the plugin field without casting
9+
*/
510
public abstract class DefaultReplacers<T extends Plugin> {
611

712
protected final ReplacerAPI replaceManager;
@@ -12,9 +17,21 @@ public DefaultReplacers(ReplacerAPI replaceManager, T plugin) {
1217
this.plugin = plugin;
1318
}
1419

20+
/**
21+
* Register all variables that this class can manage
22+
*/
1523
public abstract void register();
1624

25+
/**
26+
* Shortcut method to register the variables without the boilerplate of adding the plugin instance and registering
27+
* it to the manager.
28+
*
29+
* @param variable variable name like "online"
30+
* @return the replacer responsible for this single variable
31+
*/
1732
protected Replacer register(String variable) {
18-
return new Replacer(plugin, variable);
33+
Replacer replacer = new Replacer(plugin, variable);
34+
replaceManager.register(replacer);
35+
return replacer;
1936
}
2037
}

0 commit comments

Comments
 (0)