Skip to content

Commit 65e595f

Browse files
committed
PrioPacks is a thing
1 parent 6038232 commit 65e595f

File tree

10 files changed

+294
-101
lines changed

10 files changed

+294
-101
lines changed

.github/workflows/gradle.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Build and Release
2+
on:
3+
push:
4+
branches:
5+
- "main"
6+
7+
jobs:
8+
build:
9+
name: Build
10+
runs-on: ubuntu-latest
11+
container:
12+
image: gradle:8-jdk17
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v3
16+
17+
- name: Set up JDK
18+
uses: actions/setup-java@v3
19+
with:
20+
java-version: '17'
21+
distribution: 'adopt'
22+
cache: 'gradle'
23+
24+
- name: Gradle Build
25+
run: gradle build
26+
27+
- name: Release
28+
uses: GeyserMC/actions/release@master
29+
with:
30+
files: |
31+
build/libs/PrioPacks-*.jar
32+
appID: ${{ secrets.RELEASE_APP_ID }}
33+
appPrivateKey: ${{ secrets.RELEASE_APP_PK }}
34+
saveMetadata: true
35+
releaseEnabled: true
36+
discordWebhook: ${{ secrets.DISCORD_WEBHOOK }}
37+
ghReleaseNotes: true
38+
releaseName: Build ${tagBase}
39+
tagPrefix: release
40+
tagIncrement: true
41+
preRelease: false

README.md

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,35 @@
1-
# Geyser Extension Template
2-
A Geyser Extension template for creating Geyser Extensions.
1+
# PrioPacks
32

4-
## What are Geyser extensions?
5-
Geyser Extensions are the equivalent of “plugins”, but specifically for the Geyser platform. This brings the advantage of them being platform-agnostic, meaning that you won’t have to worry about supporting all platforms individually. Additionally, they will be, by design, only applied for Bedrock players joining via Geyser.
3+
A small Geyser extension that allows defining the order of resource pack registration. PrioPacks does not add any resource packs by itself,
4+
but it can set the pack stack order for any resource packs added by Geyser's pack folder, other extensions, and so forth.
65

7-
## What can extensions do?
8-
- Register [custom items](https://wiki.geysermc.org/geyser/custom-items/), [custom blocks](https://wiki.geysermc.org/geyser/custom-blocks/#geyser-extensions) and more in code!
9-
- Listen and toggle various Bedrock features (i.e. commands)
10-
- Send forms to Bedrock players using [Cumulus](https://github.com/GeyserMC/Cumulus)
11-
- Listen and interact with [Events](https://wiki.geysermc.org/geyser/events/)
6+
## Installing
7+
Download the PrioPacks.jar from the releases tab, and put it inside of Geyser's `extensions` folder. Then, restart Geyser, and you're done!
128

13-
## Using this Template
14-
Click "Use this template" on the top right, and create your own repo.
15-
Then, see the [usage guide](./USAGE.md) for instructions on how to use this template.
9+
## Configuration
1610

17-
## Documentation
18-
Our [wiki](https://geysermc.org/wiki/) has helpful articles. The following are recommended:
19-
- Geyser Event System documentation: https://geysermc.org/wiki/geyser/events
20-
- Geyser Forms / Cumulus documentation: https://geysermc.org/wiki/geyser/forms
21-
- Brief overview on the Geyser API: https://geysermc.org/wiki/geyser/api
22-
- Extension docs: https://geysermc.org/wiki/geyser/extensions
11+
```yml
12+
# PrioPacks Configuration
13+
#
14+
# Source: https://github.com/onebeastchris/PrioPacks/
2315

24-
## Existing Extensions
25-
See our list [here](https://github.com/GeyserMC/GeyserExtensionList).
16+
# The below list represents the resource pack stack. Each entry is a uuid of a loaded resource pack.
17+
# PrioPacks will then set priorities for each pack to ensure the order represented here!
18+
# Resource Packs higher in the stack will be applied first on the Bedrock client (e.g. overriding a texture change).
19+
# If this list contains uuids of resource packs that are not actually present, PrioPacks will gracefully skip over them.
20+
pack-stack:
21+
- e5f5c938-a701-11eb-b2a3-047d7bb283ba
22+
- d9ee1211-b03e-43ec-b7f6-b7bcc7cf3fa4
2623

27-
## Suggestions?
28-
Reach out on our [Discord](https://discord.gg/geysermc)!
24+
# The highest priority that PrioPacks will assign to the top resource pack in the stack above.
25+
highest-priority: 100
2926

30-
## Important Notes
31-
- `extension.yml` is required for Geyser to load the extension. It must be in the `resources` folder.
32-
- Geyser Extensions: https://github.com/GeyserMC/Geyser/blob/master/api/src/main/java/org/geysermc/geyser/api/extension/Extension.java
33-
- Geyser API javadocs: https://repo.opencollab.dev/javadoc/maven-snapshots/org/geysermc/geyser/api/latest
27+
# The lowest priority that PrioPacks will assign to the bottom resource pack in the stack.
28+
lowest-priority: -100
3429

30+
# The config version. DO NOT CHANGE!
31+
version: 1
32+
```
33+
34+
After making the changes, you can apply these using `/priopacks reload`. To see all Bedrock resource packs that a Bedrock client got when connecting,
35+
use `/priopacks debug` - this will print all resource packs of the first Bedrock client that joined after PrioPacks was started / reloaded.

USAGE.md

Lines changed: 0 additions & 23 deletions
This file was deleted.

build.gradle.kts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
plugins {
22
java
3+
id("io.freefair.lombok") version "8.14"
4+
id("com.gradleup.shadow") version "8.3.3"
35
}
46

57
val id = project.property("id") as String
68
val extensionName = project.property("name") as String
7-
val geyserApiVersion = "2.6.1"
9+
val geyserApiVersion = "2.6.2"
810

911
repositories {
1012
// Repo for the Geyser API artifact
@@ -19,6 +21,7 @@ dependencies {
1921
compileOnly("org.geysermc.geyser:api:$geyserApiVersion-SNAPSHOT")
2022

2123
// Include other dependencies here - e.g. configuration libraries.
24+
implementation("org.spongepowered:configurate-yaml:4.2.0-GeyserMC-SNAPSHOT")
2225
}
2326

2427
// Java currently requires Java 17 or higher, so extensions should also target it
@@ -53,4 +56,21 @@ tasks {
5356
)
5457
}
5558
}
59+
60+
build {
61+
dependsOn(shadowJar)
62+
}
63+
64+
jar {
65+
archiveBaseName.set("DEV-PrioPacks")
66+
archiveClassifier.set("unshaded")
67+
}
68+
69+
shadowJar {
70+
archiveClassifier.set("")
71+
archiveVersion.set(version.toString())
72+
relocate("org.spongepowered.configurate", "dev.onechris.extension.priopacks.relocate.configurate")
73+
relocate("io.leangen.geantyref", "dev.onechris.extension.priopacks.relocate.geantyref")
74+
relocate("com.typesafe.config", "dev.onechris.extension.priopacks.relocate.typesafe")
75+
}
5676
}

gradle.properties

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
version=1.0.0
2-
id=exampleid
3-
name=SomeExtension
4-
author=ExampleAuthor
2+
id=priopacks
3+
name=PrioPacks
4+
author=onechris
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package dev.onechris.extension.priopacks;
2+
3+
import lombok.Getter;
4+
import lombok.experimental.Accessors;
5+
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
6+
import org.spongepowered.configurate.objectmapping.meta.Comment;
7+
8+
import java.util.List;
9+
import java.util.UUID;
10+
11+
@Getter
12+
@Accessors(fluent = true)
13+
@ConfigSerializable
14+
public class Config {
15+
16+
@Comment("""
17+
The below list represents the resource pack stack. Each entry is a uuid of a loaded resource pack.
18+
PrioPacks will then set priorities for each pack to ensure the order represented here!
19+
Resource Packs higher in the stack will be applied first on the Bedrock client (e.g. overriding a texture change).
20+
If this list contains uuids of resource packs that are not actually present, PrioPacks will gracefully skip over them.
21+
""")
22+
private List<UUID> packStack = List.of(
23+
UUID.fromString("e5f5c938-a701-11eb-b2a3-047d7bb283ba"),
24+
UUID.fromString("d9ee1211-b03e-43ec-b7f6-b7bcc7cf3fa4")
25+
);
26+
27+
@Comment("""
28+
The highest priority that PrioPacks will assign to the top resource pack in the stack above.
29+
""")
30+
private int highestPriority = 100;
31+
32+
@Comment("""
33+
The lowest priority that PrioPacks will assign to the bottom resource pack in the stack.
34+
""")
35+
private int lowestPriority = -100;
36+
37+
@Comment("""
38+
The config version. DO NOT CHANGE!
39+
""")
40+
private int version = 1;
41+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package dev.onechris.extension.priopacks;
2+
3+
import org.geysermc.geyser.api.extension.Extension;
4+
import org.spongepowered.configurate.CommentedConfigurationNode;
5+
import org.spongepowered.configurate.yaml.NodeStyle;
6+
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
7+
8+
import java.io.IOException;
9+
import java.nio.file.Files;
10+
11+
public class ConfigLoader {
12+
13+
private static final String HEADER = """
14+
PrioPacks Configuration
15+
16+
Source: https://github.com/onebeastchris/PrioPacks/
17+
""";
18+
19+
public static Config loadConfig(Extension extension) throws IOException {
20+
Files.createDirectories(extension.dataFolder());
21+
22+
final YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
23+
.path(extension.dataFolder().resolve("config.yml"))
24+
.nodeStyle(NodeStyle.BLOCK)
25+
.defaultOptions(configurationOptions -> configurationOptions.header(HEADER))
26+
.build();
27+
28+
final CommentedConfigurationNode node = loader.load();
29+
30+
// Load the config with old values if available
31+
Config config = node.get(Config.class);
32+
if (config == null) {
33+
throw new IllegalStateException("config is null!");
34+
}
35+
36+
// Some validation
37+
if (config.highestPriority() > 100) {
38+
throw new IllegalStateException("Highest possible pack priority is 100!");
39+
}
40+
41+
if (config.lowestPriority() < -100) {
42+
throw new IllegalStateException("Lowest possible pack priority is 0!");
43+
}
44+
45+
if (config.highestPriority() <= config.lowestPriority()) {
46+
throw new IllegalStateException("Highest possible priority must be greater than lowest priority!");
47+
}
48+
49+
CommentedConfigurationNode newNode = CommentedConfigurationNode.root(loader.defaultOptions());
50+
newNode.set(Config.class, config);
51+
52+
loader.save(newNode);
53+
return config;
54+
}
55+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package dev.onechris.extension.priopacks;
2+
3+
import org.geysermc.event.PostOrder;
4+
import org.geysermc.event.subscribe.Subscribe;
5+
import org.geysermc.geyser.api.command.Command;
6+
import org.geysermc.geyser.api.command.CommandSource;
7+
import org.geysermc.geyser.api.event.bedrock.SessionLoadResourcePacksEvent;
8+
import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCommandsEvent;
9+
import org.geysermc.geyser.api.event.lifecycle.GeyserPreInitializeEvent;
10+
import org.geysermc.geyser.api.extension.Extension;
11+
import org.geysermc.geyser.api.pack.ResourcePack;
12+
import org.geysermc.geyser.api.pack.ResourcePackManifest;
13+
import org.geysermc.geyser.api.pack.exception.ResourcePackException;
14+
import org.geysermc.geyser.api.pack.option.PriorityOption;
15+
16+
import java.util.List;
17+
import java.util.UUID;
18+
19+
public class PrioPacks implements Extension {
20+
21+
private Config config;
22+
private int step;
23+
private List<ResourcePackManifest> manifests;
24+
25+
@Subscribe
26+
public void onGeyserInit(GeyserPreInitializeEvent event) {
27+
logger().info("Initializing PrioPacks...");
28+
loadPacks();
29+
}
30+
31+
@Subscribe
32+
public void onRegisterCommands(GeyserDefineCommandsEvent event) {
33+
event.register(Command.builder(this)
34+
.name("reload")
35+
.description("Reloads the PrioPacks config")
36+
.permission("priopacks.reload")
37+
.source(CommandSource.class)
38+
.executor((source, command, args) -> {
39+
loadPacks();
40+
source.sendMessage("Finished reloading PrioPacks!");
41+
})
42+
.build());
43+
44+
event.register(Command.builder(this)
45+
.name("debug")
46+
.description("Lists the last loaded packs; making it easier to obtain pack uuid's")
47+
.permission("priopacks.debug")
48+
.source(CommandSource.class)
49+
.executor((source, command, args) -> debug(source))
50+
.build());
51+
}
52+
53+
@Subscribe(postOrder = PostOrder.LATE)
54+
public void onSessionLoadPacks(SessionLoadResourcePacksEvent event) {
55+
List<UUID> order = config.packStack();
56+
57+
int currentPrio = config.highestPriority();
58+
for (UUID uuid : order) {
59+
try {
60+
event.registerOptions(uuid, PriorityOption.priority(ensureInBounds(currentPrio)));
61+
currentPrio = -step;
62+
} catch (ResourcePackException e) {
63+
logger().warning("Could not set priority for resource pack with uuid %s: Got error %s".formatted(uuid, e.getMessage()));
64+
}
65+
}
66+
67+
// For debug purposes
68+
if (manifests == null) {
69+
manifests = event.resourcePacks().stream().map(ResourcePack::manifest).toList();
70+
}
71+
}
72+
73+
private int ensureInBounds(int input) {
74+
return Math.min(Math.max(-100, input), 100);
75+
}
76+
77+
public void debug(CommandSource source) {
78+
if (manifests == null) {
79+
source.sendMessage("Cannot dump resource pack manifests as no Bedrock player joined yet!");
80+
return;
81+
}
82+
source.sendMessage("Here are all the resource packs sent to the last Bedrock connection:");
83+
for (ResourcePackManifest manifest : manifests) {
84+
source.sendMessage(manifest.toString());
85+
}
86+
}
87+
88+
private void loadPacks() {
89+
logger().info("Loading PrioPacks config!");
90+
try {
91+
config = ConfigLoader.loadConfig(this);
92+
} catch (Exception e) {
93+
logger().warning("Failed to load config! Error: " + e.getMessage());
94+
this.disable();
95+
}
96+
97+
manifests = null;
98+
if (config.packStack().isEmpty()) {
99+
step = 0;
100+
} else {
101+
step = (config.highestPriority() - config.lowestPriority()) / config.packStack().size();
102+
}
103+
logger().info("Enabled PrioPacks.");
104+
}
105+
}

0 commit comments

Comments
 (0)