mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Extensions should specify geyser api version in the extension.yml (#3880)
* let extensions specify geyser api version instead of base api version * fix spacing, @link formatting, properly check for compat * Proper warning, update to API changes to also check patch version * Bump base-api version * adapt to new base api changes * Actually bump to 2.4.1 * Update api/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java * Address reviews * Address reviews * Update to latest base api changes; proper extension *human* version checking * no need to apply a plugin, that's the default --------- Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com>
This commit is contained in:
parent
03187b6139
commit
f3ba5848c2
8 changed files with 141 additions and 32 deletions
|
@ -1,8 +1,24 @@
|
||||||
plugins {
|
plugins {
|
||||||
|
// Allow blossom to mark sources root of templates
|
||||||
|
idea
|
||||||
id("geyser.publish-conventions")
|
id("geyser.publish-conventions")
|
||||||
|
alias(libs.plugins.blossom)
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(libs.base.api)
|
api(libs.base.api)
|
||||||
api(libs.math)
|
api(libs.math)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
version = property("version")!!
|
||||||
|
val apiVersion = (version as String).removeSuffix("-SNAPSHOT")
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
blossom {
|
||||||
|
javaSources {
|
||||||
|
property("version", apiVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.api;
|
||||||
|
|
||||||
|
import org.geysermc.api.util.ApiVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not a public API. For internal use only. May change without notice.
|
||||||
|
* This class is processed before compilation to insert build properties.
|
||||||
|
*/
|
||||||
|
class BuildData {
|
||||||
|
static final String VERSION = "{{ version }}";
|
||||||
|
static final ApiVersion API_VERSION;
|
||||||
|
|
||||||
|
static {
|
||||||
|
String[] parts = VERSION.split("\\.");
|
||||||
|
if (parts.length != 3) {
|
||||||
|
throw new RuntimeException("Invalid api version: " + VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int human = Integer.parseInt(parts[0]);
|
||||||
|
int major = Integer.parseInt(parts[1]);
|
||||||
|
int minor = Integer.parseInt(parts[2]);
|
||||||
|
API_VERSION = new ApiVersion(human, major, minor);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Invalid api version: " + VERSION, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.geysermc.api.Geyser;
|
import org.geysermc.api.Geyser;
|
||||||
import org.geysermc.api.GeyserApiBase;
|
import org.geysermc.api.GeyserApiBase;
|
||||||
|
import org.geysermc.api.util.ApiVersion;
|
||||||
import org.geysermc.geyser.api.command.CommandSource;
|
import org.geysermc.geyser.api.command.CommandSource;
|
||||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||||
import org.geysermc.geyser.api.event.EventBus;
|
import org.geysermc.geyser.api.event.EventBus;
|
||||||
|
@ -169,4 +170,14 @@ public interface GeyserApi extends GeyserApiBase {
|
||||||
static GeyserApi api() {
|
static GeyserApi api() {
|
||||||
return Geyser.api(GeyserApi.class);
|
return Geyser.api(GeyserApi.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link ApiVersion} representing the current Geyser api version.
|
||||||
|
* See the <a href="https://github.com/geysermc/api/blob/master/geyser-versioning.md">Geyser version outline</a>)
|
||||||
|
*
|
||||||
|
* @return the current geyser api version
|
||||||
|
*/
|
||||||
|
default ApiVersion geyserApiVersion() {
|
||||||
|
return BuildData.API_VERSION;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,33 +59,46 @@ public interface ExtensionDescription {
|
||||||
String main();
|
String main();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the extension's major api version
|
* Represents the human api version that the extension requires.
|
||||||
|
* See the <a href="https://github.com/geysermc/api/blob/master/geyser-versioning.md">Geyser version outline</a>)
|
||||||
|
* for more details on the Geyser API version.
|
||||||
*
|
*
|
||||||
* @return the extension's major api version
|
* @return the extension's requested human api version
|
||||||
|
*/
|
||||||
|
int humanApiVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the major api version that the extension requires.
|
||||||
|
* See the <a href="https://github.com/geysermc/api/blob/master/geyser-versioning.md">Geyser version outline</a>)
|
||||||
|
* for more details on the Geyser API version.
|
||||||
|
*
|
||||||
|
* @return the extension's requested major api version
|
||||||
*/
|
*/
|
||||||
int majorApiVersion();
|
int majorApiVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the extension's minor api version
|
* Represents the minor api version that the extension requires.
|
||||||
|
* See the <a href="https://github.com/geysermc/api/blob/master/geyser-versioning.md">Geyser version outline</a>)
|
||||||
|
* for more details on the Geyser API version.
|
||||||
*
|
*
|
||||||
* @return the extension's minor api version
|
* @return the extension's requested minor api version
|
||||||
*/
|
*/
|
||||||
int minorApiVersion();
|
int minorApiVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the extension's patch api version
|
* No longer in use. Geyser is now using an adaption of the romantic versioning scheme.
|
||||||
*
|
* See <a href="https://github.com/geysermc/api/blob/master/geyser-versioning.md">here</a> for details.
|
||||||
* @return the extension's patch api version
|
|
||||||
*/
|
*/
|
||||||
int patchApiVersion();
|
@Deprecated(forRemoval = true)
|
||||||
|
default int patchApiVersion() {
|
||||||
|
return minorApiVersion();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the extension's api version.
|
* Returns the extension's requested Geyser Api version.
|
||||||
*
|
|
||||||
* @return the extension's api version
|
|
||||||
*/
|
*/
|
||||||
default String apiVersion() {
|
default String apiVersion() {
|
||||||
return majorApiVersion() + "." + minorApiVersion() + "." + patchApiVersion();
|
return humanApiVersion() + "." + majorApiVersion() + "." + minorApiVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -43,9 +43,9 @@ import java.util.regex.Pattern;
|
||||||
public record GeyserExtensionDescription(@NonNull String id,
|
public record GeyserExtensionDescription(@NonNull String id,
|
||||||
@NonNull String name,
|
@NonNull String name,
|
||||||
@NonNull String main,
|
@NonNull String main,
|
||||||
|
int humanApiVersion,
|
||||||
int majorApiVersion,
|
int majorApiVersion,
|
||||||
int minorApiVersion,
|
int minorApiVersion,
|
||||||
int patchApiVersion,
|
|
||||||
@NonNull String version,
|
@NonNull String version,
|
||||||
@NonNull List<String> authors) implements ExtensionDescription {
|
@NonNull List<String> authors) implements ExtensionDescription {
|
||||||
|
|
||||||
|
@ -82,9 +82,9 @@ public record GeyserExtensionDescription(@NonNull String id,
|
||||||
throw new InvalidDescriptionException(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_format", name, apiVersion));
|
throw new InvalidDescriptionException(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_format", name, apiVersion));
|
||||||
}
|
}
|
||||||
String[] api = apiVersion.split("\\.");
|
String[] api = apiVersion.split("\\.");
|
||||||
int majorApi = Integer.parseUnsignedInt(api[0]);
|
int humanApi = Integer.parseUnsignedInt(api[0]);
|
||||||
int minorApi = Integer.parseUnsignedInt(api[1]);
|
int majorApi = Integer.parseUnsignedInt(api[1]);
|
||||||
int patchApi = Integer.parseUnsignedInt(api[2]);
|
int minorApi = Integer.parseUnsignedInt(api[2]);
|
||||||
|
|
||||||
List<String> authors = new ArrayList<>();
|
List<String> authors = new ArrayList<>();
|
||||||
if (source.author != null) {
|
if (source.author != null) {
|
||||||
|
@ -94,7 +94,7 @@ public record GeyserExtensionDescription(@NonNull String id,
|
||||||
authors.addAll(source.authors);
|
authors.addAll(source.authors);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GeyserExtensionDescription(id, name, main, majorApi, minorApi, patchApi, version, authors);
|
return new GeyserExtensionDescription(id, name, main, humanApi, majorApi, minorApi, version, authors);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
|
|
@ -29,10 +29,15 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.api.Geyser;
|
import org.geysermc.api.util.ApiVersion;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
import org.geysermc.geyser.api.GeyserApi;
|
||||||
import org.geysermc.geyser.api.event.ExtensionEventBus;
|
import org.geysermc.geyser.api.event.ExtensionEventBus;
|
||||||
import org.geysermc.geyser.api.extension.*;
|
import org.geysermc.geyser.api.extension.Extension;
|
||||||
|
import org.geysermc.geyser.api.extension.ExtensionDescription;
|
||||||
|
import org.geysermc.geyser.api.extension.ExtensionLoader;
|
||||||
|
import org.geysermc.geyser.api.extension.ExtensionLogger;
|
||||||
|
import org.geysermc.geyser.api.extension.ExtensionManager;
|
||||||
import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException;
|
import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException;
|
||||||
import org.geysermc.geyser.api.extension.exception.InvalidExtensionException;
|
import org.geysermc.geyser.api.extension.exception.InvalidExtensionException;
|
||||||
import org.geysermc.geyser.extension.event.GeyserExtensionEventBus;
|
import org.geysermc.geyser.extension.event.GeyserExtensionEventBus;
|
||||||
|
@ -40,7 +45,12 @@ import org.geysermc.geyser.text.GeyserLocale;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.nio.file.*;
|
import java.nio.file.FileSystem;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.NoSuchFileException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -176,16 +186,22 @@ public class GeyserExtensionLoader extends ExtensionLoader {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Completely different API version
|
// Check whether an extensions' requested api version is compatible
|
||||||
if (description.majorApiVersion() != Geyser.api().majorApiVersion()) {
|
ApiVersion.Compatibility compatibility = GeyserApi.api().geyserApiVersion().supportsRequestedVersion(
|
||||||
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion()));
|
description.humanApiVersion(),
|
||||||
return;
|
description.majorApiVersion(),
|
||||||
}
|
description.minorApiVersion()
|
||||||
|
);
|
||||||
|
|
||||||
// If the extension requires new API features, being backwards compatible
|
if (compatibility != ApiVersion.Compatibility.COMPATIBLE) {
|
||||||
if (description.minorApiVersion() > Geyser.api().minorApiVersion()) {
|
// Workaround for the switch to the Geyser API version instead of the Base API version in extensions
|
||||||
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion()));
|
if (compatibility == ApiVersion.Compatibility.HUMAN_DIFFER && description.humanApiVersion() == 1) {
|
||||||
return;
|
GeyserImpl.getInstance().getLogger().warning("The extension %s requested the Base API version %s, which is deprecated in favor of specifying the Geyser API version. Please update the extension, or contact its developer."
|
||||||
|
.formatted(name, description.apiVersion()));
|
||||||
|
} else {
|
||||||
|
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GeyserExtensionContainer container = this.loadExtension(path, description);
|
GeyserExtensionContainer container = this.loadExtension(path, description);
|
||||||
|
|
|
@ -7,5 +7,5 @@ org.gradle.vfs.watch=false
|
||||||
|
|
||||||
group=org.geysermc
|
group=org.geysermc
|
||||||
id=geyser
|
id=geyser
|
||||||
version=2.4.0-SNAPSHOT
|
version=2.4.1-SNAPSHOT
|
||||||
description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers.
|
description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[versions]
|
[versions]
|
||||||
base-api = "1.0.0-SNAPSHOT"
|
base-api = "1.0.1-SNAPSHOT"
|
||||||
cumulus = "1.1.2"
|
cumulus = "1.1.2"
|
||||||
erosion = "1.1-20240515.191456-1"
|
erosion = "1.1-20240515.191456-1"
|
||||||
events = "1.1-SNAPSHOT"
|
events = "1.1-SNAPSHOT"
|
||||||
|
|
Loading…
Reference in a new issue