Merge remote-tracking branch 'upstream/master' into fix/protocol

This commit is contained in:
Joshua Castle 2024-04-19 19:25:58 -07:00
commit 5636c7e00a
No known key found for this signature in database
GPG key ID: 7ECA1A2FC38ABA9F
15 changed files with 169 additions and 89 deletions

View file

@ -1,13 +1,27 @@
name: Build Pull Request
name: Build Remote
on:
pull_request:
merge_group:
on:
workflow_call:
inputs:
repository:
required: true
description: 'The repo of the remote'
type: string
ref:
required: true
description: 'The ref of the remote'
type: string
permissions: {}
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Set Build Number
run: |
echo "BUILD_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
- name: Set up JDK 17
# See https://github.com/actions/setup-java/commits
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
@ -15,29 +29,12 @@ jobs:
java-version: 17
distribution: temurin
- name: Check if the author has forked the API repo
# See https://github.com/Kas-tle/find-forks-action/commits
uses: Kas-tle/find-forks-action@1b5447d1e3c7a8ed79583dd817cc5399686eed3a
id: find_forks
with:
owner: GeyserMC
repo: api
token: ${{ secrets.GITHUB_TOKEN }}
- name: Use author's API repo if it exists
if: ${{ steps.find_forks.outputs.target_branch_found == 'true' }}
env:
API_FORK_URL: ${{ steps.find_forks.outputs.user_fork_url }}
API_FORK_BRANCH: ${{ github.event.pull_request.head.ref }}
run: |
git clone "${API_FORK_URL}" --single-branch --branch "${API_FORK_BRANCH}" api
cd api
./gradlew publishToMavenLocal
- name: Checkout repository and submodules
# See https://github.com/actions/checkout/commits
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
repository: ${{ inputs.repository }}
ref: ${{ inputs.ref }}
submodules: recursive
path: geyser
@ -46,11 +43,12 @@ jobs:
uses: gradle/wrapper-validation-action@699bb18358f12c5b78b37bb0111d3a0e2276e0e2 # v2.1.1
- name: Build Geyser
# See https://github.com/gradle/gradle-build-action/commits
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 from https://github.com/gradle/actions/commits
# See https://github.com/gradle/actions/commits
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
with:
arguments: build
build-root-directory: geyser
cache-read-only: true
- name: Archive artifacts (Geyser Fabric)
# See https://github.com/actions/upload-artifact/commits
@ -101,22 +99,4 @@ jobs:
with:
name: Geyser ViaProxy
path: geyser/bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
if-no-files-found: error
- name: Trigger Preview Deployment
if: >-
contains(github.event.pull_request.labels.*.name, 'PR: Needs Testing')
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
with:
script: |
github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'preview.yml',
ref: 'master',
inputs: {
runId: '${{ github.run_id }}',
build: '${{ github.run_number }}',
version: 'pr.${{ github.event.pull_request.number }}'
}
});
if-no-files-found: error

View file

@ -7,8 +7,9 @@ on:
- 'gh-readonly-queue/**'
paths-ignore:
- '.github/ISSUE_TEMPLATE/*.yml'
- '.github/actions/pullrequest.yml'
- '.github/actions/preview.yml'
- '.github/actions/workflows/build-remote.yml'
- '.github/actions/workflows/preview.yml'
- '.github/actions/workflows/pull-request.yml'
- '.idea/copyright/*.xml'
- '.gitignore'
- 'CONTRIBUTING.md'
@ -23,6 +24,13 @@ jobs:
env:
PROJECT: 'geyser'
steps:
- name: Set Build Number
env:
BUILD_JSON: ${{ vars.RELEASEACTION_PREVRELEASE }}
run: |
BUILD_NUMBER=$(echo $BUILD_JSON | jq --arg branch "${GITHUB_REF_NAME}" 'if .[$branch] == null then 1 else .[$branch] | .t | tonumber + 1 end // 1')
echo "BUILD_NUMBER=${BUILD_NUMBER}" >> $GITHUB_ENV
- name: Checkout repository and submodules
# See https://github.com/actions/checkout/commits
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
@ -40,8 +48,8 @@ jobs:
distribution: temurin
- name: Build
# See https://github.com/gradle/gradle-build-action/commits
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 from https://github.com/gradle/actions/commits
# See https://github.com/gradle/actions/commits
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
with:
arguments: build
gradle-home-cache-cleanup: true
@ -108,7 +116,8 @@ jobs:
- name: Get Release Metadata
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
uses: Kas-tle/base-release-action@b863fa0f89bd15267a96a72efb84aec25f168d4c # https://github.com/Kas-tle/base-release-action/releases/tag/main-11
# See https://github.com/Kas-tle/base-release-action/releases/tag/main-11
uses: Kas-tle/base-release-action@b863fa0f89bd15267a96a72efb84aec25f168d4c # main-11
with:
appID: ${{ secrets.RELEASE_APP_ID }}
appPrivateKey: ${{ secrets.RELEASE_APP_PK }}
@ -134,6 +143,7 @@ jobs:
| .downloads |= map_values({"name", "sha256"})
| {$project, "repo", $version, "number": .build, "changes", "downloads"}
' | tee metadata.json
echo
- name: Publish to Downloads API
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
shell: bash
@ -177,4 +187,4 @@ jobs:
uses: Tim203/actions-git-discord-webhook@70f38ded3aca51635ec978ab4e1a58cd4cd0c2ff
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ job.status }}
status: ${{ job.status }}

View file

@ -12,23 +12,44 @@ on:
version:
required: true
description: 'Version under which to upload to the Downloads API'
workflow_call:
inputs:
build:
required: true
description: 'Build number for the release'
type: string
version:
required: true
description: 'Version under which to upload to the Downloads API'
type: string
jobs:
upload:
runs-on: ubuntu-latest
env:
PROJECT: 'geyserpreview'
BUILD: ${{ github.event.inputs.build }}
VERSION: ${{ github.event.inputs.version }}
steps:
- uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # https://github.com/actions/download-artifact/releases/tag/v4.1.4
- name: Set Variables
id: setvars
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
echo "BUILD=${{ github.event.inputs.build }}" >> $GITHUB_ENV
echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
echo "RUN=${{ github.event.inputs.runId }}" >> $GITHUB_OUTPUT
else
echo "BUILD=${{ inputs.build }}" >> $GITHUB_ENV
echo "VERSION=${{ inputs.version }}" >> $GITHUB_ENV
echo "RUN=${{ github.run_id }}" >> $GITHUB_OUTPUT
fi
- uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427
with:
run-id: ${{ github.event.inputs.runId }}
run-id: ${{ steps.setvars.outputs.RUN }}
github-token: ${{ secrets.GITHUB_TOKEN }}
merge-multiple: true
- name: Get Preview Metadata
if: success()
uses: Kas-tle/base-release-action@b863fa0f89bd15267a96a72efb84aec25f168d4c # https://github.com/Kas-tle/base-release-action/releases/tag/main-11
# See https://github.com/Kas-tle/base-release-action/releases/tag/main-11
uses: Kas-tle/base-release-action@664c39985eb9d0d393ce98e7eb8414d3d98e762a # main-11
with:
appID: ${{ secrets.RELEASE_APP_ID }}
appPrivateKey: ${{ secrets.RELEASE_APP_PK }}

24
.github/workflows/pull-request.yml vendored Normal file
View file

@ -0,0 +1,24 @@
name: Process Pull Request
on:
pull_request_target:
jobs:
build:
# Forbid access to secrets nor GH Token perms while building the PR
permissions: {}
secrets: {}
uses: ./.github/workflows/build-remote.yml
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.sha }}
preview:
needs: [build]
if: >-
contains(github.event.pull_request.labels.*.name, 'PR: Needs Testing')
# Allow access to secrets if we are uploading a preview
secrets: inherit
uses: ./.github/workflows/preview.yml
with:
build: ${{ github.run_number }}
version: pr.${{ github.event.pull_request.number }}

View file

@ -22,6 +22,7 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
dependencies {
exclude(dependency("com.google.*:.*"))
exclude(dependency("io.netty.incubator:.*"))
exclude(dependency("io.netty:netty-transport-native-epoll:.*"))
exclude(dependency("io.netty:netty-transport-native-unix-common:.*"))
exclude(dependency("io.netty:netty-handler:.*"))

View file

@ -41,6 +41,7 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
// We cannot shade Netty, or else native libraries will not load
// Needed because older Spigot builds do not provide the haproxy module
exclude(dependency("io.netty.incubator:.*"))
exclude(dependency("io.netty:netty-transport-classes-epoll:.*"))
exclude(dependency("io.netty:netty-transport-native-epoll:.*"))
exclude(dependency("io.netty:netty-transport-native-unix-common:.*"))

View file

@ -12,7 +12,8 @@ platformRelocate("org.yaml")
exclude("com.google.*:*")
// Needed because Velocity provides every dependency except netty-resolver-dns
// Needed because Velocity provides every dependency except netty-resolver-dns
exclude("io.netty.incubator:.*")
exclude("io.netty:netty-transport-native-epoll:*")
exclude("io.netty:netty-transport-native-unix-common:*")
exclude("io.netty:netty-transport-native-kqueue:*")
@ -57,6 +58,7 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
exclude(dependency("io.netty:netty-transport:.*"))
exclude(dependency("io.netty:netty-codec:.*"))
exclude(dependency("io.netty:netty-codec-haproxy:.*"))
exclude(dependency("io.netty.incubator:.*"))
exclude(dependency("org.slf4j:.*"))
exclude(dependency("org.ow2.asm:.*"))
// Exclude all Kyori dependencies except the legacy NBT serializer

View file

@ -22,6 +22,7 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
dependencies {
exclude(dependency("com.google.*:.*"))
exclude(dependency("io.netty:.*"))
exclude(dependency("io.netty.incubator:.*"))
exclude(dependency("org.slf4j:.*"))
exclude(dependency("org.ow2.asm:.*"))
}

View file

@ -26,6 +26,8 @@ provided("io.netty", "netty-transport-native-epoll")
provided("io.netty", "netty-transport-native-unix-common")
provided("io.netty", "netty-transport-classes-kqueue")
provided("io.netty", "netty-transport-native-kqueue")
provided("io.netty.incubator", "netty-incubator-transport-native-io_uring")
provided("io.netty.incubator", "netty-incubator-transport-classes-io_uring")
provided("io.netty", "netty-handler")
provided("io.netty", "netty-common")
provided("io.netty", "netty-buffer")

View file

@ -47,6 +47,8 @@ dependencies {
implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-x86_64" } }
implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-aarch_64" } }
implementation(libs.netty.transport.native.kqueue) { artifact { classifier = "osx-x86_64" } }
implementation(libs.netty.transport.native.io.uring) { artifact { classifier = "linux-x86_64" } }
implementation(libs.netty.transport.native.io.uring) { artifact { classifier = "linux-aarch_64" } }
// Adventure text serialization
api(libs.bundles.adventure)
@ -66,11 +68,6 @@ dependencies {
api(libs.events)
}
configurations.api {
// This is still experimental - additionally, it could only really benefit standalone
exclude(group = "io.netty.incubator", module = "netty-incubator-transport-native-io_uring")
}
tasks.processResources {
// This is solely for backwards compatibility for other programs that used this file before the switch to gradle.
// It used to be generated by the maven Git-Commit-Id-Plugin
@ -101,7 +98,7 @@ configure<BlossomExtension> {
}
fun Project.buildNumber(): Int =
(System.getenv("GITHUB_RUN_NUMBER") ?: jenkinsBuildNumber())?.let { Integer.parseInt(it) } ?: -1
(System.getenv("BUILD_NUMBER"))?.let { Integer.parseInt(it) } ?: -1
inner class GitInfo {
val branch: String
@ -134,9 +131,6 @@ inner class GitInfo {
}
}
// todo remove this when we're not using Jenkins anymore
fun jenkinsBuildNumber(): String? = System.getenv("BUILD_NUMBER")
// Manual task to download the bedrock data files from the CloudburstMC/Data repository
// Invoke with ./gradlew :core:downloadBedrockData --suffix=1_20_70
// Set suffix to the current Bedrock version

View file

@ -45,7 +45,7 @@ import java.util.UUID;
public class CatEntity extends TameableEntity {
private byte collarColor;
private byte collarColor = 14; // Red - default
public CatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
@ -76,10 +76,7 @@ public class CatEntity extends TameableEntity {
@Override
public void setTameableFlags(ByteEntityMetadata entityMetadata) {
super.setTameableFlags(entityMetadata);
// Update collar color if tamed
if (getFlag(EntityFlag.TAMED)) {
dirtyMetadata.put(EntityDataTypes.COLOR, collarColor);
}
updateCollarColor();
}
public void setCatVariant(IntEntityMetadata entityMetadata) {
@ -101,6 +98,10 @@ public class CatEntity extends TameableEntity {
public void setCollarColor(IntEntityMetadata entityMetadata) {
collarColor = (byte) entityMetadata.getPrimitiveValue();
updateCollarColor();
}
private void updateCollarColor() {
// Needed or else wild cats are a red color
if (getFlag(EntityFlag.TAMED)) {
dirtyMetadata.put(EntityDataTypes.COLOR, collarColor);

View file

@ -32,6 +32,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
@ -41,6 +42,7 @@ import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import java.util.Collections;
import java.util.Set;
import java.util.UUID;
@ -54,7 +56,7 @@ public class WolfEntity extends TameableEntity {
Items.PORKCHOP, Items.BEEF, Items.RABBIT, Items.COOKED_PORKCHOP, Items.COOKED_BEEF, Items.ROTTEN_FLESH, Items.MUTTON, Items.COOKED_MUTTON,
Items.COOKED_RABBIT);
private byte collarColor;
private byte collarColor = 14; // Red - default
public WolfEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
@ -64,19 +66,27 @@ public class WolfEntity extends TameableEntity {
public void setTameableFlags(ByteEntityMetadata entityMetadata) {
super.setTameableFlags(entityMetadata);
// Reset wolf color
byte xd = entityMetadata.getPrimitiveValue();
boolean angry = (xd & 0x02) == 0x02;
if (angry) {
if (getFlag(EntityFlag.ANGRY)) {
dirtyMetadata.put(EntityDataTypes.COLOR, (byte) 0);
} else if (getFlag(EntityFlag.TAMED)) {
updateCollarColor();
// This fixes tail angle when taming
UpdateAttributesPacket packet = new UpdateAttributesPacket();
packet.setRuntimeEntityId(geyserId);
packet.setAttributes(Collections.singletonList(createHealthAttribute()));
session.sendUpstreamPacket(packet);
}
}
public void setCollarColor(IntEntityMetadata entityMetadata) {
collarColor = (byte) entityMetadata.getPrimitiveValue();
if (getFlag(EntityFlag.ANGRY)) {
return;
if (!getFlag(EntityFlag.ANGRY) && getFlag(EntityFlag.TAMED)) {
updateCollarColor();
}
}
private void updateCollarColor() {
dirtyMetadata.put(EntityDataTypes.COLOR, collarColor);
if (ownerBedrockId == 0) {
// If a color is set and there is no owner entity ID, set one.

View file

@ -49,6 +49,7 @@ public final class Bootstraps {
String kernelVersion;
try {
kernelVersion = Native.KERNEL_VERSION;
GeyserImpl.getInstance().getLogger().debug("Kernel version: " + kernelVersion);
} catch (Throwable e) {
GeyserImpl.getInstance().getLogger().debug("Could not determine kernel version! " + e.getMessage());
kernelVersion = null;
@ -67,10 +68,22 @@ public final class Bootstraps {
}
@SuppressWarnings({"rawtypes, unchecked"})
public static void setupBootstrap(AbstractBootstrap bootstrap) {
public static boolean setupBootstrap(AbstractBootstrap bootstrap) {
boolean success = true;
if (REUSEPORT_AVAILABLE) {
bootstrap.option(UnixChannelOption.SO_REUSEPORT, true);
// Guessing whether so_reuseport is available based on kernel version is cool, but unreliable.
Channel channel = bootstrap.register().channel();
if (channel.config().setOption(UnixChannelOption.SO_REUSEPORT, true)) {
bootstrap.option(UnixChannelOption.SO_REUSEPORT, true);
} else {
// If this occurs, we guessed wrong and reuseport is not available
GeyserImpl.getInstance().getLogger().debug("so_reuseport is not available despite version being " + Native.KERNEL_VERSION);
success = false;
}
// Now yeet that channel
channel.close();
}
return success;
}
private static int[] fromString(String input) {

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.network.netty;
import com.github.steveice10.packetlib.helper.TransportHelper;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
@ -39,6 +38,9 @@ import io.netty.channel.kqueue.KQueueEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.incubator.channel.uring.IOUring;
import io.netty.incubator.channel.uring.IOUringDatagramChannel;
import io.netty.incubator.channel.uring.IOUringEventLoopGroup;
import io.netty.util.concurrent.Future;
import lombok.Getter;
import net.jodah.expiringmap.ExpirationPolicy;
@ -106,7 +108,7 @@ public final class GeyserServer {
@Getter
private final ExpiringMap<InetSocketAddress, InetSocketAddress> proxiedAddresses;
private final int listenCount;
private int listenCount;
private ChannelFuture[] bootstrapFutures;
@ -127,8 +129,11 @@ public final class GeyserServer {
this.childGroup = TRANSPORT.eventLoopGroupFactory().apply(threadCount);
this.bootstrap = this.createBootstrap();
// setup SO_REUSEPORT if exists
Bootstraps.setupBootstrap(this.bootstrap);
// setup SO_REUSEPORT if exists - or, if the option does not actually exist, reset listen count
// otherwise, we try to bind multiple times which wont work if so_reuseport is not valid
if (!Bootstraps.setupBootstrap(this.bootstrap)) {
this.listenCount = 1;
}
if (this.geyser.getConfig().getBedrock().isEnableProxyProtocol()) {
this.proxiedAddresses = ExpiringMap.builder()
@ -415,22 +420,35 @@ public final class GeyserServer {
}
private static Transport compatibleTransport() {
TransportHelper.TransportMethod transportMethod = TransportHelper.determineTransportMethod();
if (transportMethod == TransportHelper.TransportMethod.EPOLL) {
if (isClassAvailable("io.netty.incubator.channel.uring.IOUring")
&& IOUring.isAvailable()
&& Boolean.parseBoolean(System.getProperty("Geyser.io_uring"))) {
return new Transport(IOUringDatagramChannel.class, IOUringEventLoopGroup::new);
}
if (isClassAvailable("io.netty.channel.epoll.Epoll") && Epoll.isAvailable()) {
return new Transport(EpollDatagramChannel.class, EpollEventLoopGroup::new);
}
if (transportMethod == TransportHelper.TransportMethod.KQUEUE) {
if (isClassAvailable("io.netty.channel.kqueue.KQueue") && KQueue.isAvailable()) {
return new Transport(KQueueDatagramChannel.class, KQueueEventLoopGroup::new);
}
// if (transportMethod == TransportHelper.TransportMethod.IO_URING) {
// return new Transport(IOUringDatagramChannel.class, IOUringEventLoopGroup::new);
// }
return new Transport(NioDatagramChannel.class, NioEventLoopGroup::new);
}
private record Transport(Class<? extends DatagramChannel> datagramChannel, IntFunction<EventLoopGroup> eventLoopGroupFactory) {
}
/**
* Used so implementations can opt to remove these dependencies if so desired
*/
private static boolean isClassAvailable(String className) {
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}

View file

@ -6,6 +6,7 @@ events = "1.1-SNAPSHOT"
jackson = "2.17.0"
fastutil = "8.5.2"
netty = "4.1.107.Final"
netty-io-uring = "0.0.25.Final-SNAPSHOT"
guava = "29.0-jre"
gson = "2.3.1" # Provided by Spigot 1.8.8
websocket = "1.5.1"
@ -75,6 +76,7 @@ netty-codec-haproxy = { group = "io.netty", name = "netty-codec-haproxy", versio
netty-handler = { group = "io.netty", name = "netty-handler", version.ref = "netty" }
netty-transport-native-epoll = { group = "io.netty", name = "netty-transport-native-epoll", version.ref = "netty" }
netty-transport-native-kqueue = { group = "io.netty", name = "netty-transport-native-kqueue", version.ref = "netty" }
netty-transport-native-io_uring = { group = "io.netty.incubator", name = "netty-incubator-transport-native-io_uring", version.ref = "netty-io-uring" }
log4j-api = { group = "org.apache.logging.log4j", name = "log4j-api", version.ref = "log4j" }
log4j-core = { group = "org.apache.logging.log4j", name = "log4j-core", version.ref = "log4j" }