Release LexianDEV v1.0.0
Build and publish release / Build and publish LexianDEV (push) Successful in 1m0s

This commit is contained in:
root
2026-08-04 19:54:23 +02:00
parent 3dc2915604
commit 7f869855c9
14 changed files with 58 additions and 54 deletions
+2 -2
View File
@@ -10,7 +10,7 @@ permissions:
jobs: jobs:
release: release:
name: Build and publish RemotePackSync name: Build and publish LexianDEV
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -36,5 +36,5 @@ jobs:
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
with: with:
generate_release_notes: false generate_release_notes: false
files: target/RemotePackSync.jar files: target/LexianDEV.jar
fail_on_unmatched_files: true fail_on_unmatched_files: true
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2026 LF1 Copyright (c) 2026 LexianDEV
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+18 -16
View File
@@ -1,6 +1,8 @@
# RemotePackSync # LexianDEV
RemotePackSync is a lightweight **Spigot 26.2** plugin that keeps Java Edition resource packs synchronized with a remotely hosted SHA-1 checksum and optionally serves a local Bedrock Edition pack to players connecting through **GeyserMC**. It uses only public Bukkit/Spigot and Geyser APIs, so it runs on **Spigot, Paper, Purpur, Bukkit-compatible servers, and current GeyserMC**. Official website: <https://lexian.dev>
LexianDEV is a lightweight **Spigot 26.2** plugin that keeps Java Edition resource packs synchronized with a remotely hosted SHA-1 checksum and optionally serves a local Bedrock Edition pack to players connecting through **GeyserMC**. It uses only public Bukkit/Spigot and Geyser APIs, so it runs on **Spigot, Paper, Purpur, Bukkit-compatible servers, and current GeyserMC**.
No NMS, packet libraries, or server-fork-specific APIs are used. No NMS, packet libraries, or server-fork-specific APIs are used.
@@ -18,15 +20,15 @@ mvn clean package
The ready-to-install plugin is written to: The ready-to-install plugin is written to:
```text ```text
target/RemotePackSync.jar target/LexianDEV.jar
``` ```
## Installation ## Installation
1. Copy `RemotePackSync.jar` into the server's `plugins/` directory. 1. Copy `LexianDEV.jar` into the server's `plugins/` directory.
2. Start the server once. RemotePackSync writes `plugins/RemotePackSync/config.yml` automatically. 2. Start the server once. LexianDEV writes `plugins/LexianDEV/config.yml` automatically.
3. Configure the resource-pack and SHA-1 URLs. 3. Configure the resource-pack and SHA-1 URLs.
4. Restart the server, or run `/remotepacksync reload` as an operator. 4. Restart the server, or run `/lexiandev reload` as an operator.
## Configuration ## Configuration
@@ -46,7 +48,7 @@ refreshInterval: 300
bedrockResourcePackUrl: "https://example.com/packs/server-pack.mcpack" bedrockResourcePackUrl: "https://example.com/packs/server-pack.mcpack"
# Optional local alternative; use only when bedrockResourcePackUrl is blank. # Optional local alternative; use only when bedrockResourcePackUrl is blank.
# Relative paths are resolved from plugins/RemotePackSync/. # Relative paths are resolved from plugins/LexianDEV/.
bedrockResourcePack: "bedrock/server-pack.mcpack" bedrockResourcePack: "bedrock/server-pack.mcpack"
``` ```
@@ -64,7 +66,7 @@ The SHA-1 response must contain a 40-character hexadecimal SHA-1. Both of these
### Java Edition ### Java Edition
- On startup and at every refresh interval, RemotePackSync fetches only the SHA-1 file asynchronously. - On startup and at every refresh interval, LexianDEV fetches only the SHA-1 file asynchronously.
- When the SHA-1 changes, it sends the configured resource-pack URL and new hash to every online player. - When the SHA-1 changes, it sends the configured resource-pack URL and new hash to every online player.
- Players joining after a successful SHA-1 fetch receive the current resource pack. - Players joining after a successful SHA-1 fetch receive the current resource pack.
- A failed request leaves the last known-good SHA-1 active, so a brief CDN outage does not interrupt existing pack delivery. - A failed request leaves the last known-good SHA-1 active, so a brief CDN outage does not interrupt existing pack delivery.
@@ -72,24 +74,24 @@ The SHA-1 response must contain a 40-character hexadecimal SHA-1. Both of these
### Bedrock Edition through GeyserMC ### Bedrock Edition through GeyserMC
- Preferred remote mode: set `bedrockResourcePackUrl` to a direct `.mcpack` or `.zip` download URL. RemotePackSync creates a Geyser `UrlPackCodec` and registers it through the public `SessionLoadResourcePacksEvent` API, so Geyser supplies the URL to connecting Bedrock clients. - Preferred remote mode: set `bedrockResourcePackUrl` to a direct `.mcpack` or `.zip` download URL. LexianDEV creates a Geyser `UrlPackCodec` and registers it through the public `SessionLoadResourcePacksEvent` API, so Geyser supplies the URL to connecting Bedrock clients.
- The remote server must return `Content-Type: application/zip` and an exact `Content-Length`. RemotePackSync verifies those headers (following redirects) before registering the URL; a provider that returns `application/octet-stream` is not compatible with Bedrock URL packs. Redirects are allowed only when they ultimately resolve to a valid direct download. The URL should be stable and should expose a changed ETag or URL when the pack changes. - The remote server must return `Content-Type: application/zip` and an exact `Content-Length`. LexianDEV verifies those headers (following redirects) before registering the URL; a provider that returns `application/octet-stream` is not compatible with Bedrock URL packs. Redirects are allowed only when they ultimately resolve to a valid direct download. The URL should be stable and should expose a changed ETag or URL when the pack changes.
- Geyser validates/downloads remote URL packs during its lifecycle. Use `/remotepacksync reload` after changing the URL or after replacing a pack at the same URL; players already connected must reconnect. - Geyser validates/downloads remote URL packs during its lifecycle. Use `/lexiandev reload` after changing the URL or after replacing a pack at the same URL; players already connected must reconnect.
- Local alternative: set `bedrockResourcePack` to a `.mcpack` or `.zip` file. The source is checked asynchronously at `refreshInterval`; changes receive a deterministic manifest UUID and are managed under `plugins/RemotePackSync/bedrock-managed/`. - Local alternative: set `bedrockResourcePack` to a `.mcpack` or `.zip` file. The source is checked asynchronously at `refreshInterval`; changes receive a deterministic manifest UUID and are managed under `plugins/LexianDEV/bedrock-managed/`.
- The original configured local pack is never modified. - The original configured local pack is never modified.
- Every new Geyser Bedrock connection receives the latest successfully registered pack. - Every new Geyser Bedrock connection receives the latest successfully registered pack.
- The pack must be a valid Bedrock pack containing `manifest.json` at the archive root. Geyser does **not** convert Java packs into Bedrock packs. - The pack must be a valid Bedrock pack containing `manifest.json` at the archive root. Geyser does **not** convert Java packs into Bedrock packs.
- Bedrock's protocol only negotiates packs while a client connects. Players already connected when the file changes must reconnect to receive the new version; RemotePackSync cannot hot-push a replacement to an active Bedrock session. - Bedrock's protocol only negotiates packs while a client connects. Players already connected when the file changes must reconnect to receive the new version; LexianDEV cannot hot-push a replacement to an active Bedrock session.
- If Geyser is absent, Java Edition resource-pack operation continues normally and Bedrock delivery stays disabled. - If Geyser is absent, Java Edition resource-pack operation continues normally and Bedrock delivery stays disabled.
## Commands and permissions ## Commands and permissions
- `/remotepacksync reload` (alias: `/rps reload`) reloads `config.yml` and begins a fresh asynchronous SHA-1 refresh. - `/lexiandev reload` (alias: `/ldev reload`) reloads `config.yml` and begins a fresh asynchronous SHA-1 refresh.
- Permission: `remotepacksync.reload` (default: `op`). - Permission: `lexiandev.reload` (default: `op`).
## Compatibility ## Compatibility
RemotePackSync compiles against `org.spigotmc:spigot-api:26.2-R0.1-SNAPSHOT` and Geyser API `2.11.0-SNAPSHOT`, targeting Java 25 as required by Minecraft/Spigot 26.2. Java packs are sent through Bukkit's stable `Player#setResourcePack(String, byte[])` API; Bedrock packs use Geyser's public `UrlPackCodec`/pack-session API. Geyser is a soft dependency, so Java-only servers remain supported. LexianDEV compiles against `org.spigotmc:spigot-api:26.2-R0.1-SNAPSHOT` and Geyser API `2.11.0-SNAPSHOT`, targeting Java 25 as required by Minecraft/Spigot 26.2. Java packs are sent through Bukkit's stable `Player#setResourcePack(String, byte[])` API; Bedrock packs use Geyser's public `UrlPackCodec`/pack-session API. Geyser is a soft dependency, so Java-only servers remain supported.
## License ## License
+6 -5
View File
@@ -4,11 +4,12 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>io.github.lf1</groupId> <groupId>dev.lexian</groupId>
<artifactId>remotepacksync</artifactId> <artifactId>lexiandev</artifactId>
<version>1.0.0</version> <version>v1.0.0</version>
<name>RemotePackSync</name> <name>LexianDEV</name>
<description>Synchronizes a server resource-pack SHA-1 from a remote URL.</description> <description>Synchronizes a server resource-pack SHA-1 from a remote URL.</description>
<url>https://lexian.dev</url>
<properties> <properties>
<!-- Minecraft/Spigot 26.2 requires Java 25 at runtime. --> <!-- Minecraft/Spigot 26.2 requires Java 25 at runtime. -->
@@ -49,7 +50,7 @@
</dependencies> </dependencies>
<build> <build>
<finalName>RemotePackSync</finalName> <finalName>LexianDEV</finalName>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@@ -1,4 +1,4 @@
package io.github.lf1.remotepacksync; package dev.lexian.lexiandev;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
@@ -102,7 +102,7 @@ public final class BedrockPackManager {
} }
if (Bukkit.getPluginManager().getPlugin("Geyser-Spigot") == null) { if (Bukkit.getPluginManager().getPlugin("Geyser-Spigot") == null) {
plugin.getLogger().warning("bedrockResourcePack is configured, but Geyser-Spigot is not installed; " plugin.getLogger().warning("bedrockResourcePack is configured, but Geyser-Spigot is not installed; "
+ "the Bedrock pack will not be sent until Geyser is available and RemotePackSync is reloaded."); + "the Bedrock pack will not be sent until Geyser is available and LexianDEV is reloaded.");
return; return;
} }
@@ -215,8 +215,8 @@ public final class BedrockPackManager {
String extension = sourceName.endsWith(".mcpack") ? ".mcpack" : ".zip"; String extension = sourceName.endsWith(".mcpack") ? ".mcpack" : ".zip";
Path directory = plugin.getDataFolder().toPath().resolve("bedrock-managed"); Path directory = plugin.getDataFolder().toPath().resolve("bedrock-managed");
Files.createDirectories(directory); Files.createDirectories(directory);
Path target = directory.resolve("RemotePackSync-Bedrock" + extension); Path target = directory.resolve("LexianDEV-Bedrock" + extension);
Path temporary = Files.createTempFile(directory, "RemotePackSync-Bedrock-", extension); Path temporary = Files.createTempFile(directory, "LexianDEV-Bedrock-", extension);
UUID cacheBustingUuid = UUID.nameUUIDFromBytes(sourceSha256); UUID cacheBustingUuid = UUID.nameUUIDFromBytes(sourceSha256);
boolean foundManifest = false; boolean foundManifest = false;
@@ -1,4 +1,4 @@
package io.github.lf1.remotepacksync; package dev.lexian.lexiandev;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
@@ -1,4 +1,4 @@
package io.github.lf1.remotepacksync; package dev.lexian.lexiandev;
import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.event.EventRegistrar;
@@ -1,4 +1,4 @@
package io.github.lf1.remotepacksync; package dev.lexian.lexiandev;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
@@ -15,8 +15,8 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
/** Entry point for RemotePackSync. Uses only stable Bukkit/Spigot APIs. */ /** Entry point for LexianDEV. Uses only stable Bukkit/Spigot APIs. */
public final class RemotePackSyncPlugin extends JavaPlugin implements Listener, CommandExecutor, TabCompleter { public final class LexianDEVPlugin extends JavaPlugin implements Listener, CommandExecutor, TabCompleter {
private ResourcePackManager resourcePackManager; private ResourcePackManager resourcePackManager;
private BedrockPackManager bedrockPackManager; private BedrockPackManager bedrockPackManager;
@@ -30,7 +30,7 @@ public final class RemotePackSyncPlugin extends JavaPlugin implements Listener,
resourcePackManager = new ResourcePackManager(this); resourcePackManager = new ResourcePackManager(this);
getServer().getPluginManager().registerEvents(this, this); getServer().getPluginManager().registerEvents(this, this);
PluginCommand command = getCommand("remotepacksync"); PluginCommand command = getCommand("lexiandev");
if (command != null) { if (command != null) {
command.setExecutor(this); command.setExecutor(this);
command.setTabCompleter(this); command.setTabCompleter(this);
@@ -60,13 +60,13 @@ public final class RemotePackSyncPlugin extends JavaPlugin implements Listener,
sender.sendMessage("§eUsage: /" + label + " reload"); sender.sendMessage("§eUsage: /" + label + " reload");
return true; return true;
} }
if (!sender.hasPermission("remotepacksync.reload")) { if (!sender.hasPermission("lexiandev.reload")) {
sender.sendMessage("§cYou do not have permission to reload RemotePackSync."); sender.sendMessage("§cYou do not have permission to reload LexianDEV.");
return true; return true;
} }
reloadPackConfiguration(); reloadPackConfiguration();
sender.sendMessage("§aRemotePackSync configuration reloaded."); sender.sendMessage("§aLexianDEV configuration reloaded.");
return true; return true;
} }
@@ -1,4 +1,4 @@
package io.github.lf1.remotepacksync; package dev.lexian.lexiandev;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
@@ -1,4 +1,4 @@
package io.github.lf1.remotepacksync; package dev.lexian.lexiandev;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@@ -26,7 +26,7 @@ public final class RemoteSha1Fetcher {
.GET() .GET()
.timeout(REQUEST_TIMEOUT) .timeout(REQUEST_TIMEOUT)
.header("Accept", "text/plain, text/*;q=0.9, */*;q=0.1") .header("Accept", "text/plain, text/*;q=0.9, */*;q=0.1")
.header("User-Agent", "RemotePackSync/1.0") .header("User-Agent", "LexianDEV/v1.0.0")
.build(); .build();
HttpResponse<byte[]> response = client.send(request, HttpResponse.BodyHandlers.ofByteArray()); HttpResponse<byte[]> response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
@@ -1,4 +1,4 @@
package io.github.lf1.remotepacksync; package dev.lexian.lexiandev;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
+2 -2
View File
@@ -2,7 +2,7 @@
resourcePackUrl: "" resourcePackUrl: ""
# Direct URL to a text file containing the SHA-1 of the resource pack. # Direct URL to a text file containing the SHA-1 of the resource pack.
# RemotePackSync accepts a 40-character hexadecimal SHA-1 anywhere in the response, # LexianDEV accepts a 40-character hexadecimal SHA-1 anywhere in the response,
# so standard '<hash> filename.zip' checksum files are supported. # so standard '<hash> filename.zip' checksum files are supported.
sha1Url: "" sha1Url: ""
@@ -16,5 +16,5 @@ refreshInterval: 300
bedrockResourcePackUrl: "" bedrockResourcePackUrl: ""
# Optional local alternative. Configure this only when bedrockResourcePackUrl is blank. # Optional local alternative. Configure this only when bedrockResourcePackUrl is blank.
# Relative paths are resolved from plugins/RemotePackSync/. # Relative paths are resolved from plugins/LexianDEV/.
bedrockResourcePack: "" bedrockResourcePack: ""
+11 -10
View File
@@ -1,16 +1,17 @@
name: RemotePackSync name: LexianDEV
version: '1.0.0' version: 'v1.0.0'
main: io.github.lf1.remotepacksync.RemotePackSyncPlugin main: dev.lexian.lexiandev.LexianDEVPlugin
api-version: '26.2' api-version: '26.2'
description: Synchronizes a server resource-pack SHA-1 from a remote URL. description: Synchronizes a server resource-pack SHA-1 from a remote URL.
author: LF1 author: LexianDEV
website: https://lexian.dev
softdepend: [Geyser-Spigot] softdepend: [Geyser-Spigot]
commands: commands:
remotepacksync: lexiandev:
description: Reload RemotePackSync configuration and SHA-1 data. description: Reload LexianDEV configuration and SHA-1 data.
usage: /remotepacksync reload usage: /lexiandev reload
aliases: [rps] aliases: [ldev]
permissions: permissions:
remotepacksync.reload: lexiandev.reload:
description: Allows reloading RemotePackSync. description: Allows reloading LexianDEV.
default: op default: op
@@ -1,4 +1,4 @@
package io.github.lf1.remotepacksync; package dev.lexian.lexiandev;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;