minecraft-src/net/minecraft/world/scores/PlayerTeam.java
2025-07-04 03:45:38 +03:00

268 lines
8.4 KiB
Java

package net.minecraft.world.scores;
import com.google.common.collect.Sets;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.ComponentSerialization;
import net.minecraft.network.chat.ComponentUtils;
import net.minecraft.network.chat.HoverEvent;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.Style;
import org.jetbrains.annotations.Nullable;
public class PlayerTeam extends Team {
private static final int BIT_FRIENDLY_FIRE = 0;
private static final int BIT_SEE_INVISIBLES = 1;
private final Scoreboard scoreboard;
private final String name;
private final Set<String> players = Sets.<String>newHashSet();
private Component displayName;
private Component playerPrefix = CommonComponents.EMPTY;
private Component playerSuffix = CommonComponents.EMPTY;
private boolean allowFriendlyFire = true;
private boolean seeFriendlyInvisibles = true;
private Team.Visibility nameTagVisibility = Team.Visibility.ALWAYS;
private Team.Visibility deathMessageVisibility = Team.Visibility.ALWAYS;
private ChatFormatting color = ChatFormatting.RESET;
private Team.CollisionRule collisionRule = Team.CollisionRule.ALWAYS;
private final Style displayNameStyle;
public PlayerTeam(Scoreboard scoreboard, String name) {
this.scoreboard = scoreboard;
this.name = name;
this.displayName = Component.literal(name);
this.displayNameStyle = Style.EMPTY.withInsertion(name).withHoverEvent(new HoverEvent.ShowText(Component.literal(name)));
}
public PlayerTeam.Packed pack() {
return new PlayerTeam.Packed(
this.name,
Optional.of(this.displayName),
this.color != ChatFormatting.RESET ? Optional.of(this.color) : Optional.empty(),
this.allowFriendlyFire,
this.seeFriendlyInvisibles,
this.playerPrefix,
this.playerSuffix,
this.nameTagVisibility,
this.deathMessageVisibility,
this.collisionRule,
List.copyOf(this.players)
);
}
public Scoreboard getScoreboard() {
return this.scoreboard;
}
@Override
public String getName() {
return this.name;
}
/**
* Gets the display name for this team.
*/
public Component getDisplayName() {
return this.displayName;
}
public MutableComponent getFormattedDisplayName() {
MutableComponent mutableComponent = ComponentUtils.wrapInSquareBrackets(this.displayName.copy().withStyle(this.displayNameStyle));
ChatFormatting chatFormatting = this.getColor();
if (chatFormatting != ChatFormatting.RESET) {
mutableComponent.withStyle(chatFormatting);
}
return mutableComponent;
}
/**
* Sets the display name for this team.
*/
public void setDisplayName(Component name) {
if (name == null) {
throw new IllegalArgumentException("Name cannot be null");
} else {
this.displayName = name;
this.scoreboard.onTeamChanged(this);
}
}
public void setPlayerPrefix(@Nullable Component playerPrefix) {
this.playerPrefix = playerPrefix == null ? CommonComponents.EMPTY : playerPrefix;
this.scoreboard.onTeamChanged(this);
}
public Component getPlayerPrefix() {
return this.playerPrefix;
}
public void setPlayerSuffix(@Nullable Component playerSuffix) {
this.playerSuffix = playerSuffix == null ? CommonComponents.EMPTY : playerSuffix;
this.scoreboard.onTeamChanged(this);
}
public Component getPlayerSuffix() {
return this.playerSuffix;
}
@Override
public Collection<String> getPlayers() {
return this.players;
}
@Override
public MutableComponent getFormattedName(Component formattedName) {
MutableComponent mutableComponent = Component.empty().append(this.playerPrefix).append(formattedName).append(this.playerSuffix);
ChatFormatting chatFormatting = this.getColor();
if (chatFormatting != ChatFormatting.RESET) {
mutableComponent.withStyle(chatFormatting);
}
return mutableComponent;
}
public static MutableComponent formatNameForTeam(@Nullable Team playerTeam, Component playerName) {
return playerTeam == null ? playerName.copy() : playerTeam.getFormattedName(playerName);
}
@Override
public boolean isAllowFriendlyFire() {
return this.allowFriendlyFire;
}
/**
* Sets whether friendly fire (PVP between members of the team) is allowed.
*/
public void setAllowFriendlyFire(boolean friendlyFire) {
this.allowFriendlyFire = friendlyFire;
this.scoreboard.onTeamChanged(this);
}
@Override
public boolean canSeeFriendlyInvisibles() {
return this.seeFriendlyInvisibles;
}
/**
* Sets whether members of this team can see other members that are invisible.
*/
public void setSeeFriendlyInvisibles(boolean friendlyInvisibles) {
this.seeFriendlyInvisibles = friendlyInvisibles;
this.scoreboard.onTeamChanged(this);
}
@Override
public Team.Visibility getNameTagVisibility() {
return this.nameTagVisibility;
}
@Override
public Team.Visibility getDeathMessageVisibility() {
return this.deathMessageVisibility;
}
/**
* Sets the visibility flags for player name tags.
*/
public void setNameTagVisibility(Team.Visibility visibility) {
this.nameTagVisibility = visibility;
this.scoreboard.onTeamChanged(this);
}
/**
* Sets the visibility flags for player death messages.
*/
public void setDeathMessageVisibility(Team.Visibility visibility) {
this.deathMessageVisibility = visibility;
this.scoreboard.onTeamChanged(this);
}
@Override
public Team.CollisionRule getCollisionRule() {
return this.collisionRule;
}
/**
* Sets the rule to be used for handling collisions with members of this team.
*/
public void setCollisionRule(Team.CollisionRule rule) {
this.collisionRule = rule;
this.scoreboard.onTeamChanged(this);
}
/**
* Gets a bitmask containing the friendly fire and invisibles flags.
*/
public int packOptions() {
int i = 0;
if (this.isAllowFriendlyFire()) {
i |= 1;
}
if (this.canSeeFriendlyInvisibles()) {
i |= 2;
}
return i;
}
/**
* Sets friendly fire and invisibles flags based off of the given bitmask.
*/
public void unpackOptions(int flags) {
this.setAllowFriendlyFire((flags & 1) > 0);
this.setSeeFriendlyInvisibles((flags & 2) > 0);
}
/**
* Sets the color for this team. The team color is used mainly for team kill objectives and team-specific setDisplay usage. It does _not_ affect all situations (for instance, the prefix is used for the glowing effect).
*/
public void setColor(ChatFormatting color) {
this.color = color;
this.scoreboard.onTeamChanged(this);
}
@Override
public ChatFormatting getColor() {
return this.color;
}
public record Packed(
String name,
Optional<Component> displayName,
Optional<ChatFormatting> color,
boolean allowFriendlyFire,
boolean seeFriendlyInvisibles,
Component memberNamePrefix,
Component memberNameSuffix,
Team.Visibility nameTagVisibility,
Team.Visibility deathMessageVisibility,
Team.CollisionRule collisionRule,
List<String> players
) {
public static final Codec<PlayerTeam.Packed> CODEC = RecordCodecBuilder.create(
instance -> instance.group(
Codec.STRING.fieldOf("Name").forGetter(PlayerTeam.Packed::name),
ComponentSerialization.CODEC.optionalFieldOf("DisplayName").forGetter(PlayerTeam.Packed::displayName),
ChatFormatting.COLOR_CODEC.optionalFieldOf("TeamColor").forGetter(PlayerTeam.Packed::color),
Codec.BOOL.optionalFieldOf("AllowFriendlyFire", true).forGetter(PlayerTeam.Packed::allowFriendlyFire),
Codec.BOOL.optionalFieldOf("SeeFriendlyInvisibles", true).forGetter(PlayerTeam.Packed::seeFriendlyInvisibles),
ComponentSerialization.CODEC.optionalFieldOf("MemberNamePrefix", CommonComponents.EMPTY).forGetter(PlayerTeam.Packed::memberNamePrefix),
ComponentSerialization.CODEC.optionalFieldOf("MemberNameSuffix", CommonComponents.EMPTY).forGetter(PlayerTeam.Packed::memberNameSuffix),
Team.Visibility.CODEC.optionalFieldOf("NameTagVisibility", Team.Visibility.ALWAYS).forGetter(PlayerTeam.Packed::nameTagVisibility),
Team.Visibility.CODEC.optionalFieldOf("DeathMessageVisibility", Team.Visibility.ALWAYS).forGetter(PlayerTeam.Packed::deathMessageVisibility),
Team.CollisionRule.CODEC.optionalFieldOf("CollisionRule", Team.CollisionRule.ALWAYS).forGetter(PlayerTeam.Packed::collisionRule),
Codec.STRING.listOf().optionalFieldOf("Players", List.of()).forGetter(PlayerTeam.Packed::players)
)
.apply(instance, PlayerTeam.Packed::new)
);
}
}