MIT License

项目介绍

vytskalt/scoreboard-library 是一个托管在 GitHub 上的开源项目,主要使用 Java 编写,采用 MIT License 许可证,目前获得 236 个 Star、21 次 Fork。

仓库全名
vytskalt/scoreboard-library
开源许可证
MIT License
Star 数
236
Fork 数
21
未关闭 Issue
4

README 摘要

scoreboard-library Powerful scoreboard library for Minecraft Paper/Spigot servers using the adventure component library Join the Discord or create an issue for support Features Sidebars. Up to 42 characters (depends on the formatting) for 1.12.2-, no limit for newer versions Teams. Supports showing different properties (display name, prefix, entries etc.) of the same team to different players Objectives. Full…

完整内容见 GitHub 原始 README 或本页 。

常见问题

scoreboard-library 用什么语言开发?

主要使用 Java 编写,采用 MIT License 许可证,目前有 236 个 Star。

scoreboard-library 可以免费商用吗?

仓库采用 MIT License 许可证,可免费使用与修改,商业使用请遵守许可证条款(例如保留版权声明与许可声明)。

如何获取 scoreboard-library 的源码?

可以直接克隆仓库:git clone https://github.com/vytskalt/scoreboard-library.git,默认分支为 main;安装与运行步骤见仓库 README。

scoreboard-library 最近还在维护吗?

仓库最近一次更新为 4 周前,当前有 4 个未关闭 Issue;Star 数为 236,可作为社区活跃度的参考。

关于

Powerful packet-level scoreboard library for Minecraft Paper/Spigot servers

描述取自 GitHub 官方 API,中文内容由 GitRead 中文社区 编辑团队整理。

简要分析

热度分
279
价值分
147
活跃状态
活跃

语言占比

Java
Kotlin
Nix
Shell

Release

README

scoreboard-library

Powerful scoreboard library for Minecraft Paper/Spigot servers using the adventure component library

Join the Discord or create an issue for support

Features

  • Sidebars. Up to 42 characters (depends on the formatting) for 1.12.2-, no limit for newer versions
  • Teams. Supports showing different properties (display name, prefix, entries etc.) of the same team to different players
  • Objectives.
  • Full support for new 1.20.4 features (score display names, custom score formats)
  • No extra dependencies (assuming you’re targeting modern versions of Paper)
  • Packet-level, meaning it works with other scoreboard plugins
  • Supports Folia
  • Fully async. All packet work is done asynchronously, so you can use the library from the main thread without sacrificing any performance
  • Automatically works with TranslatableComponents. All components are translated using GlobalTranslator for each player’s client locale and automatically update whenever the player changes it in their settings
  • ViaVersion awareness: automatically detects 1.12.2- on 1.13+ servers connected through ViaVersion and sends them the optimal packets to maximise sidebar line lengths

Supported server versions

All Paper and Spigot versions from 1.7.10 to 26.3 are natively supported.

Installation

See installation instructions here

Getting started

ScoreboardLibrary scoreboardLibrary;
try {
  scoreboardLibrary = ScoreboardLibrary.loadScoreboardLibrary(plugin);
} catch (NoPacketAdapterAvailableException e) {
  // If server version is not yet supported, you can fallback to the no-op implementation:
  scoreboardLibrary = new NoopScoreboardLibrary();
  plugin.getLogger().warning("Server version unsupported, scoreboard functionality will not be visible!");
}

// On plugin shutdown:
scoreboardLibrary.close();

Thread safety warning (Folia)

Sidebars and TeamManagers are not thread safe, so you will need to add some synchronisation to make sure you’re using them from only one thread at a time.

Sidebar sidebar = scoreboardLibrary.createSidebar();

sidebar.title(Component.text("Sidebar Title"));
sidebar.line(0, Component.empty());
sidebar.line(1, Component.text("Line 1"));
sidebar.line(2, Component.text("Line 2"));
sidebar.line(2, Component.empty());
sidebar.line(3, Component.text("epicserver.net"));

sidebar.addPlayer(player); // Add the player to the sidebar

// Don't forget to call sidebar.close() once you don't need it anymore!

Component sidebars

Component sidebars are an abstraction over the low-level Sidebar. They allow you to design sidebars in a clean way. Here’s how you create a SidebarComponent with a static line:

SidebarComponent staticLine = SidebarComponent.staticLine(Component.text("A static line"));

You can chain multiple SidebarComponents together using SidebarComponent.builder():

SidebarComponent lines = SidebarComponent.builder()
  .addComponent(SidebarComponent.staticLine(Component.text("A static line")))
  .addStaticLine(Component.text("Another static line")) // Shorthand for line above
  .build();

To use these components, create a ComponentSidebarLayout:

ComponentSidebarLayout layout = new ComponentSidebarLayout(
  SidebarComponent.staticLine(Component.text("Sidebar Title")),
  lines
);

Sidebar sidebar = scoreboardLibrary.createSidebar();

// Apply the title & lines components to the Sidebar
// Do this every time the title or any line needs to be updated
layout.apply(sidebar);

You can make animations with SidebarAnimation:

Component lineComponent = Component.text("Line that changes colors");
Set<NamedTextColor> colors = NamedTextColor.NAMES.values();
List<Component> frames = new ArrayList<>(colors.size());
for (NamedTextColor color : colors) {
  frames.add(lineComponent.color(color));
}

SidebarAnimation<Component> animation = new CollectionSidebarAnimation<>(frames);
// You can also implement SidebarAnimation yourself

SidebarComponent line = SidebarComponent.animatedLine(animation);

// Advance to the next frame of the animation
animation.nextFrame();

Animations can be used for pagination:

Player player = ...;

SidebarComponent firstPage = SidebarComponent.builder()
  .addStaticLine(Component.text("First page"))
  .addDynamicLine(() -> Component.text("Level: " + player.getLevel()))
  .build();

SidebarComponent secondPage = SidebarComponent.builder()
  .addStaticLine(Component.text("Second page"))
  .addDynamicLine(() -> Component.text("Health: " + player.getHealth()))
  .build();

List<SidebarComponent> pages = Arrays.asList(firstPage, secondPage);
SidebarAnimation<SidebarComponent> pageAnimation = new CollectionSidebarAnimation<>(pages);
SidebarComponent paginatedComponent = SidebarComponent.animatedComponent(pageAnimation);

// ...

You can also create your own SidebarComponents:

public class KeyValueSidebarComponent implements SidebarComponent {
  private final Component key;
  private final Supplier<Component> valueSupplier;

  public KeyValueSidebarComponent(@NotNull Component key, @NotNull Supplier<Component> valueSupplier) {
    this.key = key;
    this.valueSupplier = valueSupplier;
  }

  @Override
  public void draw(@NotNull LineDrawable drawable) {
    var value = valueSupplier.get();
    var line = Component.text()
      .append(key)
      .append(Component.text(": "))
      .append(value.colorIfAbsent(NamedTextColor.AQUA))
      .build();

    drawable.drawLine(line);
  }
}

Here’s a full sidebar example:

public class ExampleComponentSidebar {
  private final Sidebar sidebar;
  private final ComponentSidebarLayout componentSidebar;
  private final SidebarAnimation<Component> titleAnimation;

  public ExampleComponentSidebar(@NotNull Plugin plugin, @NotNull Sidebar sidebar) {
    this.sidebar = sidebar;

    this.titleAnimation = createGradientAnimation(Component.text("Sidebar Example", Style.style(TextDecoration.BOLD)));
    var title = SidebarComponent.animatedLine(titleAnimation);

    SimpleDateFormat dtf = new SimpleDateFormat("HH:mm:ss");

    // Custom SidebarComponent, see below for how an implementation might look like
    SidebarComponent KeyValueSidebarComponent(
      Component.text("Online players"),
      () -> Component.text(plugin.getServer().getOnlinePlayers().size())
    );

    SidebarComponent lines = SidebarComponent.builder()
      .addDynamicLine(() -> {
        var time = dtf.format(new Date());
        return Component.text(time, NamedTextColor.GRAY);
      })
      .addBlankLine()
      .addStaticLine(Component.text("A static line"))
      .addComponent(onlinePlayers)
      .addBlankLine()
      .addStaticLine(Component.text("epicserver.net", NamedTextColor.AQUA))
      .build();


    this.componentSidebar = new ComponentSidebarLayout(title, lines);
  }

  // Called every tick
  public void tick() {
    // Advance title animation to the next frame
    titleAnimation.nextFrame();

    // Update sidebar title & lines
    componentSidebar.apply(sidebar);
  }

  private @NotNull SidebarAnimation<Component> createGradientAnimation(@NotNull Component text) {
    float step = 1f / 8f;

    TagResolver.Single textPlaceholder = Placeholder.component("text", text);
    List<Component> frames = new ArrayList<>((int) (2f / step));

    float phase = -1f;
    while (phase < 1) {
      frames.add(MiniMessage.miniMessage().deserialize("<gradient:yellow:gold:" + phase + "><text>", textPlaceholder));
      phase += step;
    }

    return new CollectionSidebarAnimation<>(frames);
  }
}

Sidebar example`

TeamManager

TeamManager teamManager = scoreboardLibrary.createTeamManager();
ScoreboardTeam team = teamManager.createIfAbsent("team_name");

// A TeamDisplay holds all the display properties that a team can have (prefix, suffix etc.).
// You can apply different TeamDisplays for each player so different players can see
// different properties on a single ScoreboardTeam. However if you don't need that you can
// use the default TeamDisplay that is created in every ScoreboardTeam.
TeamDisplay teamDisplay = team.defaultDisplay();
teamDisplay.displayName(Component.text("Team Display Name"));
teamDisplay.prefix(Component.text("[Prefix] "));
teamDisplay.suffix(Component.text(" [Suffix]"));
teamDisplay.playerColor(NamedTextColor.RED);
teamDisplay.addEntry(player.getName());

teamManager.addPlayer(player); // Player will be added to the default TeamDisplay of each ScoreboardTeam

// Create a new TeamDisplay like this:
TeamDisplay newTeamDisplay = team.createDisplay();
newTeamDisplay.displayName(Component.text("Other Team Display Name"));

// Change the TeamDisplay a player sees like this:
team.display(player, newTeamDisplay);

// Don't forget to call teamManager.close() once you don't need it anymore!

ObjectiveManager

ObjectiveManager objectiveManager = scoreboardLibrary.createObjectiveManager();
ScoreboardObjective objective = objectiveManager.create("coolobjective");
objective.value(Component.text("Display name"));
objective.score(player.getName(), 69420);
objectiveManager.display(ObjectiveDisplaySlot.belowName(), objective);

objectiveManager.addPlayer(player); // Make a player see the objectives

// Don't forget to call objectiveManager.close() once you don't need it anymore!

评论

暂无评论