Skip to content

Commit c0fa95e

Browse files
committed
Improve documentation for scoreboard components
1 parent cba6e72 commit c0fa95e

2 files changed

Lines changed: 117 additions & 5 deletions

File tree

public/wiki/cardinal-components-api/modules/level.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ breadcrumb: Level Properties
66

77
This module allows mods to attach components to WorldProperties objects. Those properties are shared by every world and thus can be used as global data. Level components can be semi-automatically synchronized by implementing `AutoSyncedComponent`. **Note that you must call `LevelComponents#sync(MinecraftServer)` instead of `ComponentKey#sync()`**.
88

9-
## Cardinal-Components Alternative: Scoreboard Components
10-
Scoreboard components are available starting from version 2.5.0 of the API (MC 1.16.2) and offer the same functionality as level components while being easier to synchronize.
9+
## CCA Alternative: [Scoreboard Components](./scoreboard)
10+
[Scoreboard components](./scoreboard) are available starting from version 2.5.0 of the API (MC 1.16.2) and offer the same functionality as level components while being easier to synchronize.
1111

1212
## Vanilla Alternative: Overworld `PersistentState`
1313
Instead of components attached to `WorldProperties`, one can use a `PersistentState` specifically attached to the Overworld.

public/wiki/cardinal-components-api/modules/scoreboard.md

Lines changed: 115 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,131 @@ layout: cca_wiki
44
breadcrumb: Scoreboards and Teams
55
---
66

7-
This module allows mods to attach components to `Scoreboard` and `Team` objects. The former can be used for storing global data, while the latter can be especially useful for implementing multiplayer systems like minigames and factions.
7+
This module allows mods to attach components to `Scoreboard` and `Team` objects.
8+
The former can be used for storing global data, while the latter can be especially useful for implementing multiplayer systems like minigames and factions.
9+
10+
By default, the scoreboard itself is not affected in any way by the data that is attached to it through Cardinal Components API.
11+
It is only used as a convenient provider that can easily be accessed by mods.
12+
{:.admonition.admonition-important}
813

914
## Usage
1015
### Registration
1116

12-
Scoreboard components are registered by a [`ScoreboardComponentInitializer`](https://github.com/Ladysnake/Cardinal-Components-API/blob/master/cardinal-components-scoreboard/src/main/java/org/ladysnake/cca/api/v3/scoreboard/ScoreboardComponentInitializer.java), exposed as `cardinal-components-scoreboard` in the mod json (more information on the [component registration page](../registration#2-attaching-your-component)).
17+
Scoreboard components are registered by a [`ScoreboardComponentInitializer`](https://github.com/Ladysnake/Cardinal-Components-API/blob/master/cardinal-components-scoreboard/src/main/java/org/ladysnake/cca/api/v3/scoreboard/ScoreboardComponentInitializer.java), exposed as either `cardinal-components-scoreboard`
18+
or simply `cardinal-components` in the mod json (more information on the [component registration page](../registration#2-attaching-your-component)).
1319
Once a component factory is registered for either scoreboards or teams, its associated component will be available on every relevant instance, on both clients and servers.
1420

21+
Scoreboard and team component factories are passed a `MinecraftServer` instance, which allows for advanced behaviour during *e.g.* component ticking.
22+
This server instance will be `null` on the logical client.
23+
{:.admonition.admonition-note.admonition-icon}
24+
25+
#### Example
26+
27+
```java
28+
public final class MyComponents implements ScoreboardComponentInitializer {
29+
@Override
30+
public void registerScoreboardComponentFactories(ScoreboardComponentFactoryRegistry registry) {
31+
// Global data component
32+
registry.registerScoreboardComponent(TrophyComponent.KEY, TrophyComponent::new);
33+
// Team-specific component, useful for minigames
34+
registry.registerTeamComponent(TrophyComponent.KEY, (scoreboard, team, server) -> new TeamTrophyComponent(team));
35+
}
36+
}
37+
```
38+
1539
### Synchronization
1640

17-
Scoreboard components can be automatically synchronized from the server to the client by implementing [`AutoSyncedComponent`](https://github.com/Ladysnake/Cardinal-Components-API/blob/master/cardinal-components-base/src/main/java/org/ladysnake/cca/api/v3/component/sync/AutoSyncedComponent.java) - more information is available on [the component synchronization page](../synchronization.md).
41+
Both Scoreboard and Team components can be automatically synchronized from the server to the client by implementing
42+
[`AutoSyncedComponent`](https://github.com/Ladysnake/Cardinal-Components-API/blob/master/cardinal-components-base/src/main/java/org/ladysnake/cca/api/v3/component/sync/AutoSyncedComponent.java) - more information is available on [the component synchronization page](../synchronization.md).
43+
A scoreboard component should call `KEY.sync(scoreboard)` to trigger server-to-client synchronization, while a team
44+
component should call `KEY.sync(team)`.
1845

1946
### Ticking
2047

2148
Scoreboard components support both [server](https://github.com/Ladysnake/Cardinal-Components-API/blob/main/cardinal-components-base/src/main/java/org/ladysnake/cca/api/v3/component/tick/ServerTickingComponent.java) and [client](https://github.com/Ladysnake/Cardinal-Components-API/blob/main/cardinal-components-base/src/main/java/org/ladysnake/cca/api/v3/component/tick/ClientTickingComponent.java) ticking.
2249
They get ticked at the end of the server/client tick.
50+
51+
## Global Component Example
52+
53+
Here is an example of a global component that can be used to track modded player data even when the players are offline:
54+
55+
```java
56+
public class TrophyComponent implements AutoSyncedComponent {
57+
private final Map<UUID, TrophyCollection> data = new HashMap<>();
58+
private final Scoreboard provider;
59+
60+
public TrophyComponent(Scoreboard provider, @Nullable MinecraftServer server) {
61+
this.provider = provider;
62+
}
63+
64+
public void addTrophy(PlayerEntity player, Trophy trophy) {
65+
this.data.computeIfAbsent(playerId, i -> new TrophyCollection()).grant(trophy);
66+
KEY.sync(this.provider);
67+
}
68+
69+
public List<Trophy> listTrophies(PlayerEntity player) {
70+
return this.listTrophies(player.getUuid());
71+
}
72+
73+
public List<Trophy> listTrophies(UUID playerId) {
74+
TrophyCollection trophies = this.data.get(playerId);
75+
return trophies == null ? List.of() : trophies.toList();
76+
}
77+
78+
// Sync implementation: only sync the players' own data
79+
// (in most cases that's what you want, but you could also sync the entirety of the map)
80+
81+
@Override
82+
public boolean shouldSyncWith(ServerPlayerEntity player) {
83+
return data.containsKey(player.getUuid());
84+
}
85+
86+
@Override
87+
public void writeSyncPacket(RegistryByteBuf buf, ServerPlayerEntity recipient) {
88+
buf.writeMap(
89+
Map.of(recipient.getUuid(), data.get(recipient.getUuid())),
90+
PacketByteBuf::writeUuid,
91+
TrophyCollection::writeToPacket
92+
);
93+
}
94+
95+
@Override public void applySyncPacket(RegistryByteBuf buf) { /* ... */ }
96+
}
97+
```
98+
99+
In a similar way, you could use a `Map<RegistryKey<World>, Data>` to store globally available data about dimensions.
100+
101+
## Vanilla Alternatives
102+
Here are some alternatives to store global data if you don't feel like adding a dependency to your project.
103+
_Opinion:_ the only one we would recommend, if there is no need for synchronization, is the Overworld `PersistentState`.
104+
105+
### Overworld `PersistentState`
106+
Instead of components attached to `Scoreboard`, one can use a `PersistentState` specifically attached to the Overworld.
107+
108+
```diff
109+
+ No dependency required
110+
= Comparable amount of setup
111+
- Requires access to a MinecraftServer instance - cannot be synchronized, requires casting to use
112+
- Depends on the assumption that the Overworld is always accessible and never reset
113+
```
114+
115+
### Actual scoreboard storage
116+
Instead of storing global data in components attached to the scoreboard, one could directly store said data in the scoreboard itself.
117+
118+
```diff
119+
+ No dependency required
120+
= Is automatically synchronized
121+
- Requires more setup
122+
- Only stores numbers
123+
- Can interfere with commands
124+
```
125+
126+
### Entirely custom file
127+
It is possible for a mod to manage a dedicated file storing the global data in a world's save directory.
128+
129+
```diff
130+
+ No dependency required
131+
+ Can also be saved clientside for offline access
132+
- requires custom implementation for saving, syncing, ticking, etc.
133+
- is susceptible to file corruption and other things that Minecraft deals with
134+
```

0 commit comments

Comments
 (0)