summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main/java/net/minecraft/server/EntityHuman.java34
-rw-r--r--src/main/java/net/minecraft/server/EntityPlayer.java16
-rw-r--r--src/main/java/net/minecraft/server/MinecraftServer.java2
-rw-r--r--src/main/java/net/minecraft/server/PlayerList.java4
-rw-r--r--src/main/java/net/minecraft/server/ScoreboardServer.java32
-rw-r--r--src/main/java/org/bukkit/craftbukkit/CraftServer.java8
-rw-r--r--src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java13
-rw-r--r--src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java68
-rw-r--r--src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java104
-rw-r--r--src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java56
-rw-r--r--src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java135
-rw-r--r--src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardComponent.java27
-rw-r--r--src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java118
-rw-r--r--src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardTranslations.java26
-rw-r--r--src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java145
15 files changed, 756 insertions, 32 deletions
diff --git a/src/main/java/net/minecraft/server/EntityHuman.java b/src/main/java/net/minecraft/server/EntityHuman.java
index 101c2a0d..91b44a03 100644
--- a/src/main/java/net/minecraft/server/EntityHuman.java
+++ b/src/main/java/net/minecraft/server/EntityHuman.java
@@ -436,11 +436,13 @@ public abstract class EntityHuman extends EntityLiving implements ICommandListen
public void c(Entity entity, int i) {
this.addScore(i);
- Collection collection = this.getScoreboard().getObjectivesForCriteria(IScoreboardCriteria.e);
+ // CraftBukkit - Get our scores instead
+ Collection<ScoreboardScore> collection = this.world.getServer().getScoreboardManager().getScoreboardScores(IScoreboardCriteria.e, this.getLocalizedName(), new java.util.ArrayList<ScoreboardScore>());
if (entity instanceof EntityHuman) {
this.a(StatisticList.A, 1);
- collection.addAll(this.getScoreboard().getObjectivesForCriteria(IScoreboardCriteria.d));
+ // CraftBukkit - Get our scores instead
+ this.world.getServer().getScoreboardManager().getScoreboardScores(IScoreboardCriteria.d, this.getLocalizedName(), collection);
} else {
this.a(StatisticList.z, 1);
}
@@ -448,8 +450,7 @@ public abstract class EntityHuman extends EntityLiving implements ICommandListen
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
- ScoreboardObjective scoreboardobjective = (ScoreboardObjective) iterator.next();
- ScoreboardScore scoreboardscore = this.getScoreboard().getPlayerScoreForObjective(this.getLocalizedName(), scoreboardobjective);
+ ScoreboardScore scoreboardscore = (ScoreboardScore) iterator.next(); // CraftBukkit - Use our scores instead
scoreboardscore.incrementScore();
}
@@ -687,10 +688,28 @@ public abstract class EntityHuman extends EntityLiving implements ICommandListen
}
public boolean a(EntityHuman entityhuman) {
- ScoreboardTeam scoreboardteam = this.getScoreboardTeam();
- ScoreboardTeam scoreboardteam1 = entityhuman.getScoreboardTeam();
+ // CraftBukkit start - Change to check player's scoreboard team according to API reference to this (or main) scoreboard
+ org.bukkit.scoreboard.Team team;
+ if (this instanceof EntityPlayer) {
+ EntityPlayer thisPlayer = (EntityPlayer) this;
+ team = thisPlayer.getBukkitEntity().getScoreboard().getPlayerTeam(thisPlayer.getBukkitEntity());
+ if (team == null || team.allowFriendlyFire()) {
+ return true;
+ }
+ } else {
+ // This should never be called, but is implemented anyway
+ org.bukkit.OfflinePlayer thisPlayer = this.world.getServer().getOfflinePlayer(this.name);
+ team = this.world.getServer().getScoreboardManager().getMainScoreboard().getPlayerTeam(thisPlayer);
+ if (team == null || team.allowFriendlyFire()) {
+ return true;
+ }
+ }
- return scoreboardteam != scoreboardteam1 ? true : (scoreboardteam != null ? scoreboardteam.allowFriendlyFire() : true);
+ if (entityhuman instanceof EntityPlayer) {
+ return team.hasPlayer(((EntityPlayer) entityhuman).getBukkitEntity());
+ }
+ return team.hasPlayer(this.world.getServer().getOfflinePlayer(entityhuman.name));
+ // CraftBukkit end
}
protected void a(EntityLiving entityliving, boolean flag) {
@@ -1494,6 +1513,7 @@ public abstract class EntityHuman extends EntityLiving implements ICommandListen
}
public String getScoreboardDisplayName() {
+ // TODO: fun
return ScoreboardTeam.getPlayerDisplayName(this.getScoreboardTeam(), this.name);
}
}
diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java
index 14f2521e..eb07d8e0 100644
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
@@ -201,14 +201,8 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
public void setHealth(int i) {
super.setHealth(i);
- Collection collection = this.getScoreboard().getObjectivesForCriteria(IScoreboardCriteria.f);
- Iterator iterator = collection.iterator();
-
- while (iterator.hasNext()) {
- ScoreboardObjective scoreboardobjective = (ScoreboardObjective) iterator.next();
-
- this.getScoreboard().getPlayerScoreForObjective(this.getLocalizedName(), scoreboardobjective).updateForList(Arrays.asList(new EntityHuman[] { this}));
- }
+ // CraftBukkit - Update ALL the scores!
+ this.world.getServer().getScoreboardManager().updateAllScoresForList(IScoreboardCriteria.f, this.getLocalizedName(), com.google.common.collect.ImmutableList.of(this));
}
public void g() {
@@ -304,12 +298,12 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
this.closeInventory();
// CraftBukkit end
- Collection collection = this.world.getScoreboard().getObjectivesForCriteria(IScoreboardCriteria.c);
+ // CraftBukkit - Get our scores instead
+ Collection<ScoreboardScore> collection = this.world.getServer().getScoreboardManager().getScoreboardScores(IScoreboardCriteria.c, this.getLocalizedName(), new java.util.ArrayList<ScoreboardScore>());
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
- ScoreboardObjective scoreboardobjective = (ScoreboardObjective) iterator.next();
- ScoreboardScore scoreboardscore = this.getScoreboard().getPlayerScoreForObjective(this.getLocalizedName(), scoreboardobjective);
+ ScoreboardScore scoreboardscore = (ScoreboardScore) iterator.next(); // CraftBukkit - Use our scores instead
scoreboardscore.incrementScore();
}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 5bf5fdc2..64d58825 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -225,6 +225,8 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IMo
world.getWorld().getPopulators().addAll(gen.getDefaultPopulators(world.getWorld()));
}
+ this.server.scoreboardManager = new org.bukkit.craftbukkit.scoreboard.CraftScoreboardManager(this, world.getScoreboard());
+
this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldInitEvent(world.getWorld()));
world.addIWorldAccess(new WorldManager(this, world));
diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
index 464b2509..ed670d92 100644
--- a/src/main/java/net/minecraft/server/PlayerList.java
+++ b/src/main/java/net/minecraft/server/PlayerList.java
@@ -126,7 +126,7 @@ public abstract class PlayerList {
}
}
- protected void a(ScoreboardServer scoreboardserver, EntityPlayer entityplayer) {
+ public void a(ScoreboardServer scoreboardserver, EntityPlayer entityplayer) { // CraftBukkit - protected -> public
HashSet hashset = new HashSet();
Iterator iterator = scoreboardserver.getTeams().iterator();
@@ -277,6 +277,8 @@ public abstract class PlayerList {
entityplayer1.playerConnection.sendPacket(packet);
}
}
+ // This removes the scoreboard (and player reference) for the specific player in the manager
+ this.cserver.getScoreboardManager().removePlayer(entityplayer.getBukkitEntity());
return playerQuitEvent.getQuitMessage();
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/server/ScoreboardServer.java b/src/main/java/net/minecraft/server/ScoreboardServer.java
index 0f28b328..863b4db1 100644
--- a/src/main/java/net/minecraft/server/ScoreboardServer.java
+++ b/src/main/java/net/minecraft/server/ScoreboardServer.java
@@ -20,7 +20,7 @@ public class ScoreboardServer extends Scoreboard {
public void handleScoreChanged(ScoreboardScore scoreboardscore) {
super.handleScoreChanged(scoreboardscore);
if (this.b.contains(scoreboardscore.getObjective())) {
- this.a.getPlayerList().sendAll(new Packet207SetScoreboardScore(scoreboardscore, 0));
+ this.sendAll(new Packet207SetScoreboardScore(scoreboardscore, 0)); // CraftBukkit - Internal packet method
}
this.b();
@@ -28,7 +28,7 @@ public class ScoreboardServer extends Scoreboard {
public void handlePlayerRemoved(String s) {
super.handlePlayerRemoved(s);
- this.a.getPlayerList().sendAll(new Packet207SetScoreboardScore(s));
+ this.sendAll(new Packet207SetScoreboardScore(s)); // CraftBukkit - Internal packet method
this.b();
}
@@ -38,7 +38,7 @@ public class ScoreboardServer extends Scoreboard {
super.setDisplaySlot(i, scoreboardobjective);
if (scoreboardobjective1 != scoreboardobjective && scoreboardobjective1 != null) {
if (this.h(scoreboardobjective1) > 0) {
- this.a.getPlayerList().sendAll(new Packet208SetScoreboardDisplayObjective(i, scoreboardobjective));
+ this.sendAll(new Packet208SetScoreboardDisplayObjective(i, scoreboardobjective)); // CraftBukkit - Internal packet method
} else {
this.g(scoreboardobjective1);
}
@@ -46,7 +46,7 @@ public class ScoreboardServer extends Scoreboard {
if (scoreboardobjective != null) {
if (this.b.contains(scoreboardobjective)) {
- this.a.getPlayerList().sendAll(new Packet208SetScoreboardDisplayObjective(i, scoreboardobjective));
+ this.sendAll(new Packet208SetScoreboardDisplayObjective(i, scoreboardobjective)); // CraftBukkit - Internal packet method
} else {
this.e(scoreboardobjective);
}
@@ -57,13 +57,13 @@ public class ScoreboardServer extends Scoreboard {
public void addPlayerToTeam(String s, ScoreboardTeam scoreboardteam) {
super.addPlayerToTeam(s, scoreboardteam);
- this.a.getPlayerList().sendAll(new Packet209SetScoreboardTeam(scoreboardteam, Arrays.asList(new String[] { s}), 3));
+ this.sendAll(new Packet209SetScoreboardTeam(scoreboardteam, Arrays.asList(new String[] { s}), 3)); // CraftBukkit - Internal packet method
this.b();
}
public void removePlayerFromTeam(String s, ScoreboardTeam scoreboardteam) {
super.removePlayerFromTeam(s, scoreboardteam);
- this.a.getPlayerList().sendAll(new Packet209SetScoreboardTeam(scoreboardteam, Arrays.asList(new String[] { s}), 4));
+ this.sendAll(new Packet209SetScoreboardTeam(scoreboardteam, Arrays.asList(new String[] { s}), 4)); // CraftBukkit - Internal packet method
this.b();
}
@@ -75,7 +75,7 @@ public class ScoreboardServer extends Scoreboard {
public void handleObjectiveChanged(ScoreboardObjective scoreboardobjective) {
super.handleObjectiveChanged(scoreboardobjective);
if (this.b.contains(scoreboardobjective)) {
- this.a.getPlayerList().sendAll(new Packet206SetScoreboardObjective(scoreboardobjective, 2));
+ this.sendAll(new Packet206SetScoreboardObjective(scoreboardobjective, 2)); // CraftBukkit - Internal packet method
}
this.b();
@@ -92,19 +92,19 @@ public class ScoreboardServer extends Scoreboard {
public void handleTeamAdded(ScoreboardTeam scoreboardteam) {
super.handleTeamAdded(scoreboardteam);
- this.a.getPlayerList().sendAll(new Packet209SetScoreboardTeam(scoreboardteam, 0));
+ this.sendAll(new Packet209SetScoreboardTeam(scoreboardteam, 0)); // CraftBukkit - Internal packet method
this.b();
}
public void handleTeamChanged(ScoreboardTeam scoreboardteam) {
super.handleTeamChanged(scoreboardteam);
- this.a.getPlayerList().sendAll(new Packet209SetScoreboardTeam(scoreboardteam, 2));
+ this.sendAll(new Packet209SetScoreboardTeam(scoreboardteam, 2)); // CraftBukkit - Internal packet method
this.b();
}
public void handleTeamRemoved(ScoreboardTeam scoreboardteam) {
super.handleTeamRemoved(scoreboardteam);
- this.a.getPlayerList().sendAll(new Packet209SetScoreboardTeam(scoreboardteam, 1));
+ this.sendAll(new Packet209SetScoreboardTeam(scoreboardteam, 1)); // CraftBukkit - Internal packet method
this.b();
}
@@ -146,6 +146,7 @@ public class ScoreboardServer extends Scoreboard {
while (iterator.hasNext()) {
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
+ if (entityplayer.getBukkitEntity().getScoreboard().getHandle() != this) continue; // CraftBukkit - Only players on this board
Iterator iterator1 = list.iterator();
while (iterator1.hasNext()) {
@@ -178,6 +179,7 @@ public class ScoreboardServer extends Scoreboard {
while (iterator.hasNext()) {
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
+ if (entityplayer.getBukkitEntity().getScoreboard().getHandle() != this) continue; // CraftBukkit - Only players on this board
Iterator iterator1 = list.iterator();
while (iterator1.hasNext()) {
@@ -201,4 +203,14 @@ public class ScoreboardServer extends Scoreboard {
return i;
}
+
+ // CraftBukkit start - Send to players
+ private void sendAll(Packet packet) {
+ for (EntityPlayer entityplayer : (List<EntityPlayer>) this.a.getPlayerList().players) {
+ if (entityplayer.getBukkitEntity().getScoreboard().getHandle() == this) {
+ entityplayer.playerConnection.sendPacket(packet);
+ }
+ }
+ }
+ // CraftBukkit end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 7b9c7877..5baed258 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -32,8 +32,6 @@ import net.minecraft.server.EnumGamemode;
import net.minecraft.server.ExceptionWorldConflict;
import net.minecraft.server.PlayerList;
import net.minecraft.server.RecipesFurnace;
-import net.minecraft.server.IProgressUpdate;
-import net.minecraft.server.IWorldAccess;
import net.minecraft.server.Item;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.MobEffectList;
@@ -82,6 +80,7 @@ import org.bukkit.craftbukkit.metadata.PlayerMetadataStore;
import org.bukkit.craftbukkit.metadata.WorldMetadataStore;
import org.bukkit.craftbukkit.potion.CraftPotionBrewer;
import org.bukkit.craftbukkit.scheduler.CraftScheduler;
+import org.bukkit.craftbukkit.scoreboard.CraftScoreboardManager;
import org.bukkit.craftbukkit.updater.AutoUpdater;
import org.bukkit.craftbukkit.updater.BukkitDLUpdaterService;
import org.bukkit.craftbukkit.util.DatFileFilter;
@@ -162,6 +161,7 @@ public final class CraftServer implements Server {
private File container;
private WarningState warningState = WarningState.DEFAULT;
private final BooleanWrapper online = new BooleanWrapper();
+ public CraftScoreboardManager scoreboardManager;
private final class BooleanWrapper {
private boolean value = true;
@@ -1358,4 +1358,8 @@ public final class CraftServer implements Server {
public CraftItemFactory getItemFactory() {
return CraftItemFactory.instance();
}
+
+ public CraftScoreboardManager getScoreboardManager() {
+ return scoreboardManager;
+ }
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index d37d719a..a93625c4 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -24,7 +24,6 @@ import org.bukkit.*;
import org.bukkit.Achievement;
import org.bukkit.Material;
import org.bukkit.Statistic;
-import org.bukkit.WeatherType;
import org.bukkit.World;
import org.bukkit.configuration.serialization.DelegateDeserialization;
import org.bukkit.conversations.Conversation;
@@ -38,6 +37,7 @@ import org.bukkit.craftbukkit.CraftSound;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.map.CraftMapView;
import org.bukkit.craftbukkit.map.RenderData;
+import org.bukkit.craftbukkit.scoreboard.CraftScoreboard;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerGameModeChangeEvent;
@@ -50,6 +50,7 @@ import org.bukkit.metadata.MetadataValue;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.messaging.Messenger;
import org.bukkit.plugin.messaging.StandardMessenger;
+import org.bukkit.scoreboard.Scoreboard;
@DelegateDeserialization(CraftOfflinePlayer.class)
public class CraftPlayer extends CraftHumanEntity implements Player {
@@ -420,6 +421,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
server.getHandle().playerFileData.save(getHandle());
}
+ @Deprecated
public void updateInventory() {
getHandle().updateInventory(getHandle().activeContainer);
}
@@ -974,4 +976,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
super.resetMaxHealth();
getHandle().triggerHealthUpdate();
}
+
+ public CraftScoreboard getScoreboard() {
+ return this.server.getScoreboardManager().getPlayerBoard(this);
+ }
+
+ public void setScoreboard(Scoreboard scoreboard) {
+ Validate.notNull(scoreboard, "Scoreboard cannot be null");
+ this.server.getScoreboardManager().setPlayerBoard(this, scoreboard);
+ }
}
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java
new file mode 100644
index 00000000..d2e30967
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java
@@ -0,0 +1,68 @@
+package org.bukkit.craftbukkit.scoreboard;
+
+import java.util.Map;
+
+import net.minecraft.server.IScoreboardCriteria;
+import net.minecraft.server.ScoreboardObjective;
+
+import com.google.common.collect.ImmutableMap;
+
+final class CraftCriteria {
+ static final Map<String, CraftCriteria> DEFAULTS;
+ static final CraftCriteria DUMMY;
+
+ static {
+ ImmutableMap.Builder<String, CraftCriteria> defaults = ImmutableMap.builder();
+
+ for (Map.Entry<?, ?> entry : ((Map<?,?> ) IScoreboardCriteria.a).entrySet()) {
+ String name = entry.getKey().toString();
+ IScoreboardCriteria criteria = (IScoreboardCriteria) entry.getValue();
+ if (!criteria.getName().equals(name)) {
+ throw new AssertionError("Unexpected entry " + name + " to criteria " + criteria + "(" + criteria.getName() + ")");
+ }
+
+ defaults.put(name, new CraftCriteria(criteria));
+ }
+
+ DEFAULTS = defaults.build();
+ DUMMY = DEFAULTS.get("dummy");
+ }
+
+ final IScoreboardCriteria criteria;
+ final String bukkitName;
+
+ private CraftCriteria(String bukkitName) {
+ this.bukkitName = bukkitName;
+ this.criteria = DUMMY.criteria;
+ }
+
+ private CraftCriteria(IScoreboardCriteria criteria) {
+ this.criteria = criteria;
+ this.bukkitName = criteria.getName();
+ }
+
+ static CraftCriteria getFromNMS(ScoreboardObjective objective) {
+ return DEFAULTS.get(objective.getCriteria().getName());
+ }
+
+ static CraftCriteria getFromBukkit(String name) {
+ final CraftCriteria criteria = DEFAULTS.get(name);
+ if (criteria != null) {
+ return criteria;
+ }
+ return new CraftCriteria(name);
+ }
+
+ @Override
+ public boolean equals(Object that) {
+ if (!(that instanceof CraftCriteria)) {
+ return false;
+ }
+ return ((CraftCriteria) that).bukkitName.equals(this.bukkitName);
+ }
+
+ @Override
+ public int hashCode() {
+ return this.bukkitName.hashCode() ^ CraftCriteria.class.hashCode();
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
new file mode 100644
index 00000000..431807a8
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
@@ -0,0 +1,104 @@
+package org.bukkit.craftbukkit.scoreboard;
+
+import net.minecraft.server.Scoreboard;
+import net.minecraft.server.ScoreboardObjective;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.scoreboard.DisplaySlot;
+import org.bukkit.scoreboard.Objective;
+import org.bukkit.scoreboard.Score;
+
+final class CraftObjective extends CraftScoreboardComponent implements Objective {
+ private final ScoreboardObjective objective;
+ private final CraftCriteria criteria;
+
+ CraftObjective(CraftScoreboard scoreboard, ScoreboardObjective objective) {
+ super(scoreboard);
+ this.objective = objective;
+ this.criteria = CraftCriteria.getFromNMS(objective);
+
+ scoreboard.objectives.put(objective.getName(), this);
+ }
+
+ ScoreboardObjective getHandle() {
+ return objective;
+ }
+
+ public String getName() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ return objective.getName();
+ }
+
+ public String getDisplayName() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ return objective.getDisplayName();
+ }
+
+ public void setDisplayName(String displayName) throws IllegalStateException, IllegalArgumentException {
+ Validate.notNull(displayName, "Display name cannot be null");
+ Validate.isTrue(displayName.length() <= 32, "Display name '" + displayName + "' is longer than the limit of 32 characters");
+ CraftScoreboard scoreboard = checkState();
+
+ objective.setDisplayName(displayName);
+ }
+
+ public String getCriteria() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ return criteria.bukkitName;
+ }
+
+ public boolean isModifiable() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ return !criteria.criteria.isReadOnly();
+ }
+
+ public void setDisplaySlot(DisplaySlot slot) throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+ Scoreboard board = scoreboard.board;
+ ScoreboardObjective objective = this.objective;
+
+ for (int i = 0; i < CraftScoreboardTranslations.MAX_DISPLAY_SLOT; i++) {
+ if (board.getObjectiveForSlot(i) == objective) {
+ board.setDisplaySlot(i, null);
+ }
+ }
+ if (slot != null) {
+ int slotNumber = CraftScoreboardTranslations.fromBukkitSlot(slot);
+ board.setDisplaySlot(slotNumber, getHandle());
+ }
+ }
+
+ public DisplaySlot getDisplaySlot() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+ Scoreboard board = scoreboard.board;
+ ScoreboardObjective objective = this.objective;
+
+ for (int i = 0; i < CraftScoreboardTranslations.MAX_DISPLAY_SLOT; i++) {
+ if (board.getObjectiveForSlot(i) == objective) {
+ return CraftScoreboardTranslations.toBukkitSlot(i);
+ }
+ }
+ return null;
+ }
+
+ public Score getScore(OfflinePlayer player) throws IllegalArgumentException, IllegalStateException {
+ Validate.notNull(player, "Player cannot be null");
+ CraftScoreboard scoreboard = checkState();
+
+ return new CraftScore(this, player.getName());
+ }
+
+ @Override
+ public void unregister() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ scoreboard.objectives.remove(this.getName());
+ scoreboard.board.unregisterObjective(objective);
+ setUnregistered();
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java
new file mode 100644
index 00000000..0ffbe9b0
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java
@@ -0,0 +1,56 @@
+package org.bukkit.craftbukkit.scoreboard;
+
+import java.util.Map;
+
+import net.minecraft.server.Scoreboard;
+import net.minecraft.server.ScoreboardScore;
+
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.scoreboard.Objective;
+import org.bukkit.scoreboard.Score;
+
+/**
+ * TL;DR: This class is special and lazily grabs a handle...
+ * ...because a handle is a full fledged (I think permanent) hashMap for the associated name.
+ * <p>
+ * Also, as an added perk, a CraftScore will (intentionally) stay a valid reference so long as objective is valid.
+ */
+final class CraftScore implements Score {
+ private final String playerName;
+ private final CraftObjective objective;
+
+ CraftScore(CraftObjective objective, String playerName) {
+ this.objective = objective;
+ this.playerName = playerName;
+ }
+
+ public OfflinePlayer getPlayer() {
+ return Bukkit.getOfflinePlayer(playerName);
+ }
+
+ public Objective getObjective() {
+ return objective;
+ }
+
+ public int getScore() throws IllegalStateException {
+ Scoreboard board = objective.checkState().board;
+
+ if (board.getPlayers().contains(playerName)) { // Lazy
+ Map<String, ScoreboardScore> scores = board.getPlayerObjectives(playerName);
+ ScoreboardScore score = scores.get(objective.getHandle());
+ if (score != null) { // Lazy
+ return score.getScore();
+ }
+ }
+ return 0; // Lazy
+ }
+
+ public void setScore(int score) throws IllegalStateException {
+ objective.checkState().board.getPlayerScoreForObjective(playerName, objective.getHandle()).setScore(score);
+ }
+
+ public CraftScoreboard getScoreboard() {
+ return objective.getScoreboard();
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
new file mode 100644
index 00000000..63b80853
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
@@ -0,0 +1,135 @@
+package org.bukkit.craftbukkit.scoreboard;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import net.minecraft.server.Scoreboard;
+import net.minecraft.server.ScoreboardObjective;
+import net.minecraft.server.ScoreboardTeam;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.scoreboard.DisplaySlot;
+import org.bukkit.scoreboard.Objective;
+import org.bukkit.scoreboard.Score;
+import org.bukkit.scoreboard.Team;
+
+import com.google.common.collect.ImmutableSet;
+
+public final class CraftScoreboard implements org.bukkit.scoreboard.Scoreboard {
+ final Scoreboard board;
+ final Map<String, CraftObjective> objectives = new HashMap<String, CraftObjective>();
+ final Map<String, CraftTeam> teams = new HashMap<String, CraftTeam>();
+
+ CraftScoreboard(Scoreboard board) {
+ this.board = board;
+
+ for (ScoreboardObjective objective : (Iterable<ScoreboardObjective>) board.getObjectives()) {
+ new CraftObjective(this, objective); // It adds itself to map
+ }
+ for (ScoreboardTeam team : (Iterable<ScoreboardTeam>) board.getTeams()) {
+ new CraftTeam(this, team); // It adds itself to map
+ }
+ }
+
+ public CraftObjective registerNewObjective(String name, String criteria) throws IllegalArgumentException {
+ Validate.notNull(name, "Objective name cannot be null");
+ Validate.notNull(criteria, "Criteria cannot be null");
+ Validate.isTrue(name.length() <= 16, "The name '" + name + "' is longer than the limit of 16 characters");
+ Validate.isTrue(board.getObjective(name) == null, "An objective of name '" + name + "' already exists");
+
+ CraftCriteria craftCriteria = CraftCriteria.getFromBukkit(criteria);
+ ScoreboardObjective objective = board.registerObjective(name, craftCriteria.criteria);
+ return new CraftObjective(this, objective);
+ }
+
+ public Objective getObjective(String name) throws IllegalArgumentException {
+ Validate.notNull(name, "Name cannot be null");
+ return objectives.get(name);
+ }
+
+ public ImmutableSet<Objective> getObjectivesByCriteria(String criteria) throws IllegalArgumentException {
+ Validate.notNull(criteria, "Criteria cannot be null");
+
+ ImmutableSet.Builder<Objective> objectives = ImmutableSet.builder();
+ for (CraftObjective objective : this.objectives.values()) {
+ if (objective.getCriteria().equals(criteria)) {
+ objectives.add(objective);
+ }
+ }
+ return objectives.build();
+ }
+
+ public ImmutableSet<Objective> getObjectives() {
+ return ImmutableSet.copyOf((Collection<? extends Objective>) objectives.values());
+ }
+
+ public Objective getObjective(DisplaySlot slot) throws IllegalArgumentException {
+ Validate.notNull(slot, "Display slot cannot be null");
+ ScoreboardObjective objective = board.getObjectiveForSlot(CraftScoreboardTranslations.fromBukkitSlot(slot));
+ if (objective == null) {
+ return null;
+ }
+ return this.objectives.get(objective.getName());
+ }
+
+ public ImmutableSet<Score> getScores(OfflinePlayer player) throws IllegalArgumentException {
+ Validate.notNull(player, "OfflinePlayer cannot be null");
+
+ ImmutableSet.Builder<Score> scores = ImmutableSet.builder();
+ for (CraftObjective objective : objectives.values()) {
+ scores.add(objective.getScore(player));
+ }
+ return scores.build();
+ }
+
+ public void resetScores(OfflinePlayer player) throws IllegalArgumentException {
+ Validate.notNull(player, "OfflinePlayer cannot be null");
+
+ board.resetPlayerScores(player.getName());
+ }
+
+ public Team getPlayerTeam(OfflinePlayer player) throws IllegalArgumentException {
+ Validate.notNull(player, "OfflinePlayer cannot be null");
+
+ ScoreboardTeam team = board.getTeam(player.getName());
+ return team == null ? null : teams.get(team.getName());
+ }
+
+ public Team getTeam(String teamName) throws IllegalArgumentException {
+ Validate.notNull(teamName, "Team name cannot be null");
+
+ return teams.get(teamName);
+ }
+
+ public ImmutableSet<Team> getTeams() {
+ return ImmutableSet.copyOf((Collection<? extends Team>) teams.values());
+ }
+
+ public Team registerNewTeam(String name) throws IllegalArgumentException {
+ Validate.notNull(name, "Team name cannot be null");
+ Validate.isTrue(name.length() <= 16, "Team name '" + name + "' is longer than the limit of 16 characters");
+ Validate.isTrue(board.getTeam(name) == null, "Team name '" + name + "' is already in use");
+
+ return new CraftTeam(this, board.createTeam(name));
+ }
+
+ public ImmutableSet<OfflinePlayer> getPlayers() {
+ ImmutableSet.Builder<OfflinePlayer> players = ImmutableSet.builder();
+ for (Object playerName : board.getPlayers()) {
+ players.add(Bukkit.getOfflinePlayer(playerName.toString()));
+ }
+ return players.build();
+ }
+
+ public void clearSlot(DisplaySlot slot) throws IllegalArgumentException {
+ Validate.notNull(slot, "Slot cannot be null");
+ board.setDisplaySlot(CraftScoreboardTranslations.fromBukkitSlot(slot), null);
+ }
+
+ // CraftBukkit method
+ public Scoreboard getHandle() {
+ return board;
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardComponent.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardComponent.java
new file mode 100644
index 00000000..3855a2b7
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardComponent.java
@@ -0,0 +1,27 @@
+package org.bukkit.craftbukkit.scoreboard;
+
+abstract class CraftScoreboardComponent {
+ private CraftScoreboard scoreboard;
+
+ CraftScoreboardComponent(CraftScoreboard scoreboard) {
+ this.scoreboard = scoreboard;
+ }
+
+ CraftScoreboard checkState() throws IllegalStateException {
+ CraftScoreboard scoreboard = this.scoreboard;
+ if (scoreboard == null) {
+ throw new IllegalStateException("Unregistered scoreboard component");
+ }
+ return scoreboard;
+ }
+
+ public CraftScoreboard getScoreboard() {
+ return scoreboard;
+ }
+
+ abstract void unregister() throws IllegalStateException;
+
+ final void setUnregistered() {
+ scoreboard = null;
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java
new file mode 100644
index 00000000..c435e3a0
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java
@@ -0,0 +1,118 @@
+package org.bukkit.craftbukkit.scoreboard;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import net.minecraft.server.EntityPlayer;
+import net.minecraft.server.IScoreboardCriteria;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.Packet206SetScoreboardObjective;
+import net.minecraft.server.Packet209SetScoreboardTeam;
+import net.minecraft.server.Scoreboard;
+import net.minecraft.server.ScoreboardObjective;
+import net.minecraft.server.ScoreboardScore;
+import net.minecraft.server.ScoreboardServer;
+import net.minecraft.server.ScoreboardTeam;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.craftbukkit.util.WeakCollection;
+import org.bukkit.entity.Player;
+import org.bukkit.scoreboard.ScoreboardManager;
+
+public final class CraftScoreboardManager implements ScoreboardManager {
+ private final CraftScoreboard mainScoreboard;
+ private final MinecraftServer server;
+ private final Collection<CraftScoreboard> scoreboards = new WeakCollection<CraftScoreboard>();
+ private final Map<CraftPlayer, CraftScoreboard> playerBoards = new HashMap<CraftPlayer, CraftScoreboard>();
+
+ public CraftScoreboardManager(MinecraftServer minecraftserver, net.minecraft.server.Scoreboard scoreboardServer) {
+ mainScoreboard = new CraftScoreboard(scoreboardServer);
+ server = minecraftserver;
+ scoreboards.add(mainScoreboard);
+ }
+
+ public CraftScoreboard getMainScoreboard() {
+ return mainScoreboard;
+ }
+
+ public CraftScoreboard getNewScoreboard() {
+ CraftScoreboard scoreboard = new CraftScoreboard(new ScoreboardServer(server));
+ scoreboards.add(scoreboard);
+ return scoreboard;
+ }
+
+ // CraftBukkit method
+ public CraftScoreboard getPlayerBoard(CraftPlayer player) {
+ CraftScoreboard board = playerBoards.get(player);
+ return (CraftScoreboard) (board == null ? getMainScoreboard() : board);
+ }
+
+ // CraftBukkit method
+ public void setPlayerBoard(CraftPlayer player, org.bukkit.scoreboard.Scoreboard bukkitScoreboard) throws IllegalArgumentException {
+ Validate.isTrue(bukkitScoreboard instanceof CraftScoreboard, "Cannot set player scoreboard to an unregistered Scoreboard");
+
+ CraftScoreboard scoreboard = (CraftScoreboard) bukkitScoreboard;
+ net.minecraft.server.Scoreboard oldboard = getPlayerBoard(player).getHandle();
+ net.minecraft.server.Scoreboard newboard = scoreboard.getHandle();
+ EntityPlayer entityplayer = player.getHandle();
+
+ if (oldboard == newboard) {
+ return;
+ }
+
+ if (scoreboard == mainScoreboard) {
+ playerBoards.remove(player);
+ } else {
+ playerBoards.put(player, (CraftScoreboard) scoreboard);
+ }
+
+ // Old objective tracking
+ HashSet<ScoreboardObjective> removed = new HashSet<ScoreboardObjective>();
+ for (int i = 0; i < 3; ++i) {
+ ScoreboardObjective scoreboardobjective = oldboard.getObjectiveForSlot(i);
+ if (scoreboardobjective != null && !removed.contains(scoreboardobjective)) {
+ entityplayer.playerConnection.sendPacket(new Packet206SetScoreboardObjective(scoreboardobjective, 1));
+ removed.add(scoreboardobjective);
+ }
+ }
+
+ // Old team tracking
+ Iterator<?> iterator = oldboard.getTeams().iterator();
+ while (iterator.hasNext()) {
+ ScoreboardTeam scoreboardteam = (ScoreboardTeam) iterator.next();
+ entityplayer.playerConnection.sendPacket(new Packet209SetScoreboardTeam(scoreboardteam, 1));
+ }
+
+ // The above is the reverse of the below method.
+ server.getPlayerList().a((ScoreboardServer) newboard, player.getHandle());
+ }
+
+ // CraftBukkit method
+ public void removePlayer(Player player) {
+ playerBoards.remove(player);
+ }
+
+ // CraftBukkit method
+ public Collection<ScoreboardScore> getScoreboardScores(IScoreboardCriteria criteria, String name, Collection<ScoreboardScore> collection) {
+ for (CraftScoreboard scoreboard : scoreboards) {
+ Scoreboard board = scoreboard.board;
+ for (ScoreboardObjective objective : (Iterable<ScoreboardObjective>) board.getObjectivesForCriteria(criteria)) {
+ collection.add(board.getPlayerScoreForObjective(name, objective));
+ }
+ }
+ return collection;
+ }
+
+ // CraftBukkit method
+ public void updateAllScoresForList(IScoreboardCriteria criteria, String name, List<EntityPlayer> of) {
+ for (ScoreboardScore score : getScoreboardScores(criteria, name, new ArrayList<ScoreboardScore>())) {
+ score.updateForList(of);
+ }
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardTranslations.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardTranslations.java
new file mode 100644
index 00000000..d08e5a28
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardTranslations.java
@@ -0,0 +1,26 @@
+package org.bukkit.craftbukkit.scoreboard;
+
+import net.minecraft.server.Scoreboard;
+
+import org.bukkit.scoreboard.DisplaySlot;
+
+import com.google.common.collect.ImmutableBiMap;
+
+class CraftScoreboardTranslations {
+ static final int MAX_DISPLAY_SLOT = 3;
+ static ImmutableBiMap<DisplaySlot, String> SLOTS = ImmutableBiMap.of(
+ DisplaySlot.BELOW_NAME, "belowName",
+ DisplaySlot.PLAYER_LIST, "list",
+ DisplaySlot.SIDEBAR, "sidebar");
+
+ private CraftScoreboardTranslations() {}
+
+ static DisplaySlot toBukkitSlot(int i) {
+ return SLOTS.inverse().get(Scoreboard.getSlotName(i));
+ }
+
+ static int fromBukkitSlot(DisplaySlot slot) {
+ return Scoreboard.getSlotForName(SLOTS.get(slot));
+ }
+
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
new file mode 100644
index 00000000..03a32078
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
@@ -0,0 +1,145 @@
+package org.bukkit.craftbukkit.scoreboard;
+
+import java.util.Set;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.scoreboard.Team;
+
+import com.google.common.collect.ImmutableSet;
+
+import net.minecraft.server.ScoreboardTeam;
+
+final class CraftTeam extends CraftScoreboardComponent implements Team {
+ private final ScoreboardTeam team;
+
+ CraftTeam(CraftScoreboard scoreboard, ScoreboardTeam team) {
+ super(scoreboard);
+ this.team = team;
+ scoreboard.teams.put(team.getName(), this);
+ }
+
+ public String getName() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ return team.getName();
+ }
+
+ public String getDisplayName() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ return team.getDisplayName();
+ }
+
+ public void setDisplayName(String displayName) throws IllegalStateException {
+ Validate.notNull(displayName, "Display name cannot be null");
+ Validate.isTrue(displayName.length() <= 32, "Display name '" + displayName + "' is longer than the limit of 32 characters");
+ CraftScoreboard scoreboard = checkState();
+
+ team.setDisplayName(displayName);
+ }
+
+ public String getPrefix() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ return team.getPrefix();
+ }
+
+ public void setPrefix(String prefix) throws IllegalStateException, IllegalArgumentException {
+ Validate.notNull(prefix, "Prefix cannot be null");
+ Validate.isTrue(prefix.length() <= 32, "Prefix '" + prefix + "' is longer than the limit of 32 characters");
+ CraftScoreboard scoreboard = checkState();
+
+ team.setPrefix(prefix);
+ }
+
+ public String getSuffix() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ return team.getSuffix();
+ }
+
+ public void setSuffix(String suffix) throws IllegalStateException, IllegalArgumentException {
+ Validate.notNull(suffix, "Suffix cannot be null");
+ Validate.isTrue(suffix.length() <= 32, "Suffix '" + suffix + "' is longer than the limit of 32 characters");
+ CraftScoreboard scoreboard = checkState();
+
+ team.setSuffix(suffix);
+ }
+
+ public boolean allowFriendlyFire() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ return team.allowFriendlyFire();
+ }
+
+ public void setAllowFriendlyFire(boolean enabled) throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ team.setAllowFriendlyFire(enabled);
+ }
+
+ public boolean canSeeFriendlyInvisibles() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ return team.canSeeFriendlyInvisibles();
+ }
+
+ public void setCanSeeFriendlyInvisibles(boolean enabled) throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ team.setCanSeeFriendlyInvisibles(enabled);
+ }
+
+ public Set<OfflinePlayer> getPlayers() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ ImmutableSet.Builder<OfflinePlayer> players = ImmutableSet.builder();
+ for (Object o : team.getPlayerNameSet()) {
+ players.add(Bukkit.getOfflinePlayer(o.toString()));
+ }
+ return players.build();
+ }
+
+ public int getSize() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ return team.getPlayerNameSet().size();
+ }
+
+ public void addPlayer(OfflinePlayer player) throws IllegalStateException, IllegalArgumentException {
+ Validate.notNull(player, "OfflinePlayer cannot be null");
+ CraftScoreboard scoreboard = checkState();
+
+ scoreboard.board.addPlayerToTeam(player.getName(), team);
+ }
+
+ public boolean removePlayer(OfflinePlayer player) throws IllegalStateException, IllegalArgumentException {
+ Validate.notNull(player, "OfflinePlayer cannot be null");
+ CraftScoreboard scoreboard = checkState();
+
+ if (!team.getPlayerNameSet().contains(player.getName())) {
+ return false;
+ }
+
+ scoreboard.board.removePlayerFromTeam(player.getName(), team);
+ return true;
+ }
+
+ public boolean hasPlayer(OfflinePlayer player) throws IllegalArgumentException, IllegalStateException {
+ Validate.notNull(player, "OfflinePlayer cannot be null");
+ CraftScoreboard scoreboard = checkState();
+
+ return team.getPlayerNameSet().contains(player.getName());
+ }
+
+ @Override
+ public void unregister() throws IllegalStateException {
+ CraftScoreboard scoreboard = checkState();
+
+ scoreboard.board.removeTeam(team);
+ scoreboard.teams.remove(team.getName());
+ setUnregistered();
+ }
+}