Skip to content

Commit df699e1

Browse files
committed
Add more pages
1 parent f2149a6 commit df699e1

File tree

14 files changed

+763
-1
lines changed

14 files changed

+763
-1
lines changed

astro.config.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,9 +324,35 @@ export default defineConfig({
324324
"adventure/serializer/gson",
325325
"adventure/serializer/legacy",
326326
"adventure/serializer/plain",
327+
{
328+
label: "MiniMessage",
329+
items: [
330+
"adventure/minimessage/index",
331+
"adventure/minimessage/format",
332+
"adventure/minimessage/api",
333+
"adventure/minimessage/dynamic-replacements",
334+
"adventure/minimessage/translator",
335+
],
336+
},
327337
"adventure/serializer/ansi",
328338
],
329339
},
340+
"adventure/bossbar",
341+
"adventure/sound",
342+
"adventure/titles",
343+
"adventure/book",
344+
"adventure/tablist",
345+
"adventure/resource-pack",
346+
{
347+
label: "MiniMessage",
348+
items: [
349+
"adventure/minimessage/index",
350+
"adventure/minimessage/format",
351+
"adventure/minimessage/api",
352+
"adventure/minimessage/dynamic-replacements",
353+
"adventure/minimessage/translator",
354+
],
355+
},
330356
],
331357
},
332358
{
871 KB
Loading
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
title: Books
3+
---
4+
5+
## Constructing a Book
6+
7+
Books are composed of:
8+
* A component used for the title of the book
9+
* A component used for the author of the book
10+
* A collection of components used for the book pages
11+
12+
**Example:**
13+
14+
```java
15+
// Create and open a book about cats for the target audience
16+
public void openMyBook(final @NonNull Audience target) {
17+
Component bookTitle = Component.text("Encyclopedia of cats");
18+
Component bookAuthor = Component.text("kashike");
19+
Collection<Component> bookPages = Cats.getCatKnowledge();
20+
21+
Book myBook = Book.book(bookTitle, bookAuthor, bookPages);
22+
target.openBook(myBook);
23+
}
24+
```
25+
26+
## Extra info regarding Books
27+
28+
Books in adventure are not necessarily connected to an interactable book item in the client.
29+
As of the current release such a connection needs to be implemented outside of adventure.
30+
31+
Any component that surpasses the game limit for text per page will be truncated client side, the same applies
32+
to the amount of components (pages). Further reading about these limits can be done at the [Minecraft Wiki](https://minecraft.wiki/w/Book_and_Quill#Writing).
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
title: Boss Bars
3+
---
4+
5+
## Constructing a Boss Bar
6+
7+
Boss Bars are composed of:
8+
* A component used for the title of the boss bar
9+
* A number from 0 to 1 used to determine how full the boss bar should be
10+
* A color, will be downsampled for clients &lt;1.9
11+
* An overlay that determines the amount of visual segments on the boss bar
12+
13+
14+
**Examples:**
15+
16+
```java
17+
private @Nullable BossBar activeBar;
18+
19+
public void showMyBossBar(final @NonNull Audience target) {
20+
final Component name = Component.text("Awesome BossBar");
21+
// Creates a red boss bar which has no progress and no notches
22+
final BossBar emptyBar = BossBar.bossBar(name, 0, BossBar.Color.RED, BossBar.Overlay.PROGRESS);
23+
// Creates a green boss bar which has 50% progress and 10 notches
24+
final BossBar halfBar = BossBar.bossBar(name, 0.5f, BossBar.Color.GREEN, BossBar.Overlay.NOTCHED_10);
25+
// etc..
26+
final BossBar fullBar = BossBar.bossBar(name, 1, BossBar.Color.BLUE, BossBar.Overlay.NOTCHED_20);
27+
28+
// Send a bossbar to your audience
29+
target.showBossBar(fullBar);
30+
31+
// Store it locally to be able to hide it manually later
32+
this.activeBar = fullBar;
33+
}
34+
35+
public void hideActiveBossBar(final @NonNull Audience target) {
36+
target.hideBossBar(this.activeBar);
37+
this.activeBar = null;
38+
}
39+
```
40+
41+
## Changing an active Boss Bar
42+
43+
Boss bars are mutable and listen for changes on their object,
44+
the in-game view will change automatically without having to manually refresh it!
45+
46+
Therefore, if this boss bar is currently active
47+
48+
```java
49+
final BossBar bossBar = BossBar.bossBar(Component.text("Cat counter"), 0, BossBar.Color.RED, BossBar.Overlay.PROGRESS);
50+
```
51+
52+
and `BossBar.name()` with a component is called
53+
54+
```java
55+
final Component newText = Component.text("Duck counter");
56+
bossBar.name(newText);
57+
```
58+
59+
the boss bar will be updated automatically. The same thing goes for `progress`, `color` and `overlay`.
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
---
2+
title: API
3+
---
4+
5+
import AdventureDependency from "/src/components/adventure/AdventureDependency.astro";
6+
7+
## Dependency
8+
9+
<AdventureDependency artifact="adventure-text-minimessage" project="api" />
10+
11+
:::node
12+
13+
Some platforms already provide MiniMessage natively. In this case you will not need to add MiniMessage as a dependency.
14+
15+
:::
16+
17+
## Getting Started
18+
19+
MiniMessage exposes a simple API via the `MiniMessage` class.
20+
21+
A standard instance of the serializer is available through the `miniMessage()` method. This uses the default set of tags and is not in strict mode.
22+
23+
Additional customization of MiniMessage is possible via the [Builder](#builder).
24+
25+
MiniMessage allows you to both serialize components into MiniMessage strings and to parse/deserialize MiniMessage strings into components.
26+
27+
Here's a short example to try things out:
28+
29+
```java
30+
Audience player = ...;
31+
MiniMessage mm = MiniMessage.miniMessage();
32+
33+
Component parsed = mm.deserialize("Hello <rainbow>world</rainbow>, isn't <underlined>MiniMessage</underlined> fun?");
34+
35+
player.sendMessage(parsed);
36+
```
37+
38+
For more advanced uses, additional tag resolvers can be registered, which when given a tag name and arguments will produce a `Tag` instance. These are described in more detail below.
39+
40+
### Builder
41+
42+
To make customizing MiniMessage easier, we provide a Builder. The specific methods on the builder are explained in the javadoc.
43+
44+
```java
45+
MiniMessage minimessage = MiniMessage.builder()
46+
.tags(TagResolver.builder()
47+
.resolver(StandardTags.color())
48+
.resolver(StandardTags.decorations())
49+
.resolver(this.someResolvers)
50+
.build()
51+
)
52+
.build();
53+
```
54+
55+
:::tip
56+
57+
It's a good idea to initialize such a MiniMessage instance once, in a central location, and then use it for all your messages.
58+
Exception being if you want to customize MiniMessage based on permissions of a user (for example, admins should be allowed to use color and decoration in the message, normal users not)
59+
60+
:::
61+
62+
### Error handling
63+
64+
By default, MiniMessage will never throw an exception caused by user input. Instead, it will treat any invalid tags as normal text. `MiniMessage.Builder#strict(true)` mode will enable strict mode,
65+
which throws exceptions on unclosed tags, but still will allow any improperly specified tags through.
66+
67+
To capture information on why a parse may have failed, `MiniMessage.Builder#debug(Consumer<String>)` can be provided, which will accept debug logging for an input string.
68+
69+
70+
## Tag Resolvers
71+
72+
All tag resolution goes through tag resolvers. There is one global tag resolver, which describes the tags available through a `MiniMessage` instance, plus parse-specific resolvers which can provide additional input-specific tags.
73+
74+
Tag resolvers are the binding between a name and arguments, and the logic to produce a `Component` contained in a `Tag` instance. They are composable so a `TagResolver` can produce any number of actual `Tag` instances. The tag name passed to resolvers will always be lower-cased, to ensure case-insensitive searches.
75+
76+
Tag names are only allowed to contain the characters a-z, 0-9, `_`, and `-`. They can also optionally start with any of the following characters: `!?#`.
77+
78+
You can create your own `TagResolver` by using the static factory methods in `TagResolver`. To replace tags dynamically with text MiniMessage has built-in `Placeholder` and `Formatter`.
79+
Where possible, these built-in resolvers should be used, as MiniMessage can flatten combinations of these resolvers into a more efficient format.
80+
For built-in dynamic replacements take a look [here](adventure/minimessage/dynamic-replacements).
81+
82+
To combine multiple resolvers, take a look at the tag resolver builder, `TagResolver.builder()`.
83+
84+
The builder for `MiniMessage` allows providing a custom tag resolver rather than the default (`StandardTags.all()`), allowing
85+
86+
MiniMessage also provides convenience methods to do that:
87+
88+
```java
89+
MiniMessage serializer = MiniMessage.builder()
90+
.tags(TagResolver.builder()
91+
.resolver(StandardTags.color())
92+
.build()
93+
)
94+
.build();
95+
96+
Component parsed = serializer.deserialize("<green><bold>Hai");
97+
98+
// Assertion passes
99+
assertEquals(Component.text("<bold>Hai", NamedTextColor.GREEN), parsed);
100+
```
101+
102+
Because the `<bold>` tag is not enabled on this builder, the bold tag is interpreted as literal text.
103+
104+
### Handling Arguments
105+
106+
Tag resolvers have an `ArgumentQueue` parameter, which provides any tag arguments that are present in the input. Helper methods on `Tag.Argument` can assist with conversions of the tag.
107+
108+
Exceptions thrown by the `popOr()` methods will interrupt execution, but are not currently exposed to users outside of debug output. We plan to add an auto-completion function that can
109+
reveal some of this information to the user, so please do try to write useful error messages in custom tag resolvers.
110+
111+
## Tags
112+
113+
Once a tag resolver has handled arguments, it returns a `Tag` object. These objects implement the logic of producing or modifying a component tree. There are three main kinds of `Tag` -- all custom implementations must implement one of these interfaces.
114+
115+
### Pre-process
116+
117+
These tags implement the `PreProcess` interface, and have a value of a raw MiniMessage string that is replaced into the user input before parsing continues.
118+
119+
Due to limitations in the current parser implementation, note that pre-process tags will adjust offsets in error messages, and may inhibit tab completion. However, they are currently the only way to integrate markup fragments into a message.
120+
121+
### Inserting
122+
123+
These tags are fairly straightforward: they represent a literal `Component`. The vast majority of Tag implementations will want
124+
to be `Inserting` tags. `Inserting` tags may also optionally be self-closing -- by default, this is only true for tags created by `Placeholder.unparsed(String)` and `Placeholder.component(Component)`,
125+
so that placeholders are self-contained.
126+
127+
Most `standard tags <./format>` are `Inserting`. These tags will either directly insert a component, or use the helper `Tag.styling(StyleBuilderApplicable...)` to apply style to components.
128+
129+
This helper can be used to efficiently apply a collection of styles with one tag. For example, to create a `<a:[href]>Title</a>` tag, that makes the `Title` text into a link that opens a URL with traditional link styling, this could be used:
130+
131+
```java
132+
Component aTagExample() {
133+
final String input = "Hello, <a:https://docs.advntr.dev>click me!</a> but not me!";
134+
final MiniMessage extendedInstance = MiniMessage.builder()
135+
.editTags(b -> b.tag("a", MiniMessageTest::createA))
136+
.build();
137+
138+
return extendedInstance.deserialize(input);
139+
}
140+
141+
static Tag createA(final ArgumentQueue args, final Context ctx) {
142+
final String link = args.popOr("The <a> tag requires exactly one argument, the link to open").value();
143+
144+
return Tag.styling(
145+
NamedTextColor.BLUE,
146+
TextDecoration.UNDERLINED,
147+
ClickEvent.openUrl(link),
148+
HoverEvent.showText(Component.text("Open " + link))
149+
);
150+
}
151+
```
152+
153+
This allows producing rich styling relatively quickly.
154+
155+
156+
### Modifying
157+
158+
Modifying tags are the most complex, and most specialized of the tag types available. These tags receive the node tree and have an opportunity to analyze it before
159+
components are constructed, and then receive every produced child component and can modify those children. This is used for the built-in `<rainbow>` and `<gradient>` tags,
160+
but can be applied for similar complex transformations.
161+
162+
Modifying tags are first given an opportunity to visit every node of the tree in a depth-first traversal. If a `Modifying` instance stores any state during this traversal, its resolver should return a new instance every time to prevent state corruption.
163+
164+
:::note
165+
166+
The `Node` API in 4.10.0 is currently not very well developed -- most aspects are still internal. Additional information can be exposed as needed by tag developers.
167+
168+
:::
169+
170+
Once the whole parse tree has been visited, the `postVisit()` method is called. This method can optionally be overridden if any additional calculations must be performed.
171+
172+
Next, the `Modifying` instance enters the application phase, where the component tree is presented to the tag for transformation. This allows the tag to *modify* the contents of these components, giving it its name.
173+
174+
### Parser Directives
175+
176+
Parser directives are a special kind of tag, as they are instructions for the parser, and therefore cannot be implemented by end users.
177+
178+
There is currently only one, but more may be added at any time.
179+
180+
| RESET | This indicates to the parser that this tag should close all currently open tags. |
181+
182+
183+
This can be used to provide the functionality of a `<reset>` tag under a different name. For example:
184+
185+
```java
186+
final var clearTag = TagResolver.resolver("clear", ParserDirective.RESET);
187+
188+
final var parser = MiniMessage.builder()
189+
.editTags(t -> t.resolver(clearTag))
190+
.build();
191+
192+
final Component parsed = parser.deserialize("<red>hello <bold>world<clear>, how are you?");
193+
```
194+
195+
This code would add a `<clear>` tag, behaving identically to the `<reset>` tag available by default — ", how are you?" would not be bold or colored red.

0 commit comments

Comments
 (0)