diff --git a/.examples/extend/simple-proxy/go.mod b/.examples/extend/simple-proxy/go.mod
index 446adeb25..aeafbc34f 100644
--- a/.examples/extend/simple-proxy/go.mod
+++ b/.examples/extend/simple-proxy/go.mod
@@ -7,8 +7,8 @@ replace go.minekube.com/gate => ../../../
require (
github.com/robinbraemer/event v0.1.1
go.minekube.com/brigodier v0.0.2
- go.minekube.com/common v0.3.0
- go.minekube.com/gate v0.66.39
+ go.minekube.com/common v0.4.0
+ go.minekube.com/gate v0.68.20
)
require (
@@ -42,13 +42,13 @@ require (
github.com/honeycombio/otel-config-go v1.17.0 // indirect
github.com/jellydator/ttlcache/v3 v3.4.1 // indirect
github.com/knadh/koanf/providers/file v1.2.1 // indirect
- github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
+ github.com/lucasb-eyer/go-colorful v1.4.0 // indirect
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
- github.com/pires/go-proxyproto v0.12.0 // indirect
+ github.com/pires/go-proxyproto v0.13.0 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
@@ -70,24 +70,24 @@ require (
github.com/yusufpapurcu/wmi v1.2.4 // indirect
github.com/zyedidia/generic v1.2.1 // indirect
go.minekube.com/connect v0.6.2 // indirect
- go.minekube.com/geyserlite v0.3.14 // indirect
- go.minekube.com/vialite v0.1.0 // indirect
+ go.minekube.com/geyserlite v0.3.17 // indirect
+ go.minekube.com/vialite v0.3.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/host v0.63.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect
go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 // indirect
go.opentelemetry.io/contrib/propagators/b3 v1.38.0 // indirect
go.opentelemetry.io/contrib/propagators/ot v1.38.0 // indirect
- go.opentelemetry.io/otel v1.41.0 // indirect
+ go.opentelemetry.io/otel v1.44.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect
- go.opentelemetry.io/otel/metric v1.41.0 // indirect
- go.opentelemetry.io/otel/sdk v1.39.0 // indirect
- go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect
- go.opentelemetry.io/otel/trace v1.41.0 // indirect
+ go.opentelemetry.io/otel/metric v1.44.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.44.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect
+ go.opentelemetry.io/otel/trace v1.44.0 // indirect
go.opentelemetry.io/proto/otlp v1.8.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
@@ -95,9 +95,9 @@ require (
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect
golang.org/x/net v0.49.0 // indirect
- golang.org/x/sync v0.19.0 // indirect
- golang.org/x/sys v0.40.0 // indirect
- golang.org/x/text v0.33.0 // indirect
+ golang.org/x/sync v0.21.0 // indirect
+ golang.org/x/sys v0.45.0 // indirect
+ golang.org/x/text v0.38.0 // indirect
golang.org/x/time v0.14.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260114163908-3f89685c29c3 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect
diff --git a/.examples/extend/simple-proxy/go.sum b/.examples/extend/simple-proxy/go.sum
index 2a0b213cc..7bce84ce5 100644
--- a/.examples/extend/simple-proxy/go.sum
+++ b/.examples/extend/simple-proxy/go.sum
@@ -174,6 +174,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4=
+github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg=
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
@@ -203,6 +205,8 @@ github.com/pires/go-proxyproto v0.9.1 h1:wTPjpyk41pJm1Im9BqHtPLuhxfjxL+qNfSikx9u
github.com/pires/go-proxyproto v0.9.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
github.com/pires/go-proxyproto v0.12.0 h1:TTCxD66dU898tahivkqc3hoceZp7P44FnorWyo9d5vM=
github.com/pires/go-proxyproto v0.12.0/go.mod h1:qUvfqUMEoX7T8g0q7TQLDnhMjdTrxnG0hvpMn+7ePNI=
+github.com/pires/go-proxyproto v0.13.0 h1:kMrnyu6w92odDfOVzjYV6s5GqYGnIEKoxxsP38VrPSs=
+github.com/pires/go-proxyproto v0.13.0/go.mod h1:qUvfqUMEoX7T8g0q7TQLDnhMjdTrxnG0hvpMn+7ePNI=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
@@ -301,6 +305,7 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
@@ -332,6 +337,8 @@ go.minekube.com/common v0.0.6 h1:XA4mcgDG13hQEBcY2JdmK0Ca2mx2jOZ9M8pflZ85dkE=
go.minekube.com/common v0.0.6/go.mod h1:RTT2cwrMS+hwGAjJOt06bWtbKx04MuiF0tScyvGeAZo=
go.minekube.com/common v0.3.0 h1:eKqNHFDR3eIclCqViHKP/gzWCYgfRdFpZ8+vnKPrnv8=
go.minekube.com/common v0.3.0/go.mod h1:CKCUOhcDjVWRfn77u3Tp/ECV6l1OQ5WUW5M159pu38M=
+go.minekube.com/common v0.4.0 h1:gIeGWtXYh7cIaCOSEBk1myzN211MCRXAuSZZ2TqStMY=
+go.minekube.com/common v0.4.0/go.mod h1:Nr3bszhOFSBFlglXyqtUmoiLawg+PfzeNEgN00PkK9c=
go.minekube.com/connect v0.6.2 h1:RajPc7YgqygcOviV2g4xetL3J0Wzi8b/lsYXUzIltxE=
go.minekube.com/connect v0.6.2/go.mod h1:28k11I4RyzUfAL3AkOXt3atzjeOFAC8eqbCMwsYKAb0=
go.minekube.com/geyserlite v0.3.5 h1:H/7ctRDCQo09is1eu1MEXtvU78jN3dn2+6M3hW7vJDs=
@@ -344,8 +351,16 @@ go.minekube.com/geyserlite v0.3.13 h1:Pe6I20z1EvXgWHJ/OUrXag+vQ2m0GcnUFhY140E4Ub
go.minekube.com/geyserlite v0.3.13/go.mod h1:yy0/M0zSD6X3FoQMwtmf5Jn+7YFM7AZWamKw0E8fnOE=
go.minekube.com/geyserlite v0.3.14 h1:+cSN9o/b5jEOHeym/uXvt5MEoGnrYloJidrVe9K9pWo=
go.minekube.com/geyserlite v0.3.14/go.mod h1:yy0/M0zSD6X3FoQMwtmf5Jn+7YFM7AZWamKw0E8fnOE=
+go.minekube.com/geyserlite v0.3.15 h1:1HOPV7RJSmiqJJO4/1hD39x739S0CRMc0iC1/L7NXm0=
+go.minekube.com/geyserlite v0.3.15/go.mod h1:yy0/M0zSD6X3FoQMwtmf5Jn+7YFM7AZWamKw0E8fnOE=
+go.minekube.com/geyserlite v0.3.16 h1:g2iB/V4NtQ8C8GluhocCzaeOLfgjEVWrMGUU3re4OYA=
+go.minekube.com/geyserlite v0.3.16/go.mod h1:yy0/M0zSD6X3FoQMwtmf5Jn+7YFM7AZWamKw0E8fnOE=
+go.minekube.com/geyserlite v0.3.17 h1:vYkZCCOb43/yWSbsGRyUAmpl+NARNq4V0sejg4yFr30=
+go.minekube.com/geyserlite v0.3.17/go.mod h1:yy0/M0zSD6X3FoQMwtmf5Jn+7YFM7AZWamKw0E8fnOE=
go.minekube.com/vialite v0.1.0 h1:RMnNeDcDKchIs+N5KqxOzCK9tgkrVPjgUgjU5ARdn5o=
go.minekube.com/vialite v0.1.0/go.mod h1:W9L1l8/b/GsLmkw1BW4wijaaPj/zV3OdrtYJgWdkhxE=
+go.minekube.com/vialite v0.3.0 h1:IeJLHnaw8tBa0ZQVW4SYwzR0eXxG+j3u2KI805J8F4w=
+go.minekube.com/vialite v0.3.0/go.mod h1:W9L1l8/b/GsLmkw1BW4wijaaPj/zV3OdrtYJgWdkhxE=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
@@ -355,6 +370,8 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 h1:PeBoRj6af6xMI7qCupwFvTbbnd49V7n5YpG6pg8iDYQ=
go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0/go.mod h1:ingqBCtMCe8I4vpz/UVzCW6sxoqgZB37nao91mLQ3Bw=
go.opentelemetry.io/contrib/propagators/b3 v1.38.0 h1:uHsCCOSKl0kLrV2dLkFK+8Ywk9iKa/fptkytc6aFFEo=
@@ -365,6 +382,8 @@ go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
+go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
+go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk=
@@ -379,18 +398,26 @@ go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgf
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
+go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
+go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
+go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
+go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
+go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
+go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
+go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
+go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
go.opentelemetry.io/proto/otlp v1.8.0 h1:fRAZQDcAFHySxpJ1TwlA1cJ4tvcrw7nXl9xWWC8N5CE=
go.opentelemetry.io/proto/otlp v1.8.0/go.mod h1:tIeYOeNBU4cvmPqpaji1P+KbB4Oloai8wN4rWzRrFF0=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
@@ -451,6 +478,8 @@ golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
+golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -467,6 +496,8 @@ golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
+golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
@@ -477,6 +508,8 @@ golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
+golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
+golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
diff --git a/.github/workflows/bump-managed-dependency.yml b/.github/workflows/bump-managed-dependency.yml
new file mode 100644
index 000000000..2bdb3631c
--- /dev/null
+++ b/.github/workflows/bump-managed-dependency.yml
@@ -0,0 +1,47 @@
+name: Bump managed dependency
+
+on:
+ workflow_dispatch:
+ inputs:
+ dependency:
+ description: Managed dependency to update.
+ required: true
+ type: choice
+ options:
+ - geyserlite
+ - vialite
+ version:
+ description: Released version tag, for example v0.3.15.
+ required: true
+ type: string
+ source_repository:
+ description: Repository that published the release.
+ required: false
+ type: string
+ source_release_url:
+ description: Release URL that triggered the update.
+ required: false
+ type: string
+
+permissions:
+ contents: read
+ id-token: write
+
+concurrency:
+ group: bump-managed-dependency-${{ inputs.dependency }}
+ cancel-in-progress: true
+
+jobs:
+ bump:
+ uses: minekube/actions/.github/workflows/bump-go-module.yml@v1
+ with:
+ module: ${{ inputs.dependency == 'geyserlite' && 'go.minekube.com/geyserlite' || inputs.dependency == 'vialite' && 'go.minekube.com/vialite' || '' }}
+ version: ${{ inputs.version }}
+ base-ref: master
+ branch: automation/update-${{ inputs.dependency }}
+ pr-title: "fix(deps): update ${{ inputs.dependency }} to ${{ inputs.version }}"
+ commit-message: "fix(deps): update ${{ inputs.dependency }} to ${{ inputs.version }}"
+ ci-workflow: ci.yml
+ source-repository: ${{ inputs.source_repository }}
+ source-release-url: ${{ inputs.source_release_url }}
+ secrets: inherit
diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml
index 888036f11..601954122 100644
--- a/.github/workflows/release-please.yml
+++ b/.github/workflows/release-please.yml
@@ -59,3 +59,22 @@ jobs:
gh workflow run ci.yml \
--repo "${{ github.repository }}" \
--ref "${{ needs.release-please.outputs.tag_name }}"
+
+ dispatch-moxy-bump:
+ needs: release-please
+ if: needs.release-please.outputs.release_created == 'true'
+ uses: minekube/actions/.github/workflows/dispatch-workflow.yml@v1
+ permissions:
+ contents: read
+ id-token: write
+ with:
+ target-repository: moxy
+ target-workflow: bump-gate.yml
+ target-ref: main
+ inputs-json: |
+ {
+ "version": "${{ needs.release-please.outputs.tag_name }}",
+ "source_repository": "${{ github.repository }}",
+ "source_release_url": "${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ needs.release-please.outputs.tag_name }}"
+ }
+ secrets: inherit
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 93e2be7fb..a9d0cc147 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
".": "0.69.0"
-}
+}
\ No newline at end of file
diff --git a/.web/AGENTS.md b/.web/AGENTS.md
new file mode 100644
index 000000000..badd915d5
--- /dev/null
+++ b/.web/AGENTS.md
@@ -0,0 +1,29 @@
+# Gate Web Docs Agent Notes
+
+These instructions apply to the VitePress documentation under `.web/docs`.
+
+## Navigation
+
+- Keep the top navigation limited to broad entry points. `Bedrock` and `Lite Mode` are acceptable header entries because they are primary user-facing Gate modes.
+- Do not add lower-level runtime pages such as `GeyserLite` and `ViaLite` to the header. Put them in the Guide sidebar near the related user-facing feature.
+- Do not use emoji in sidebar labels, top navigation labels, headings, or other structural navigation text. The docs should read like professional technical documentation.
+- Keep sidebar labels short and scannable. Prefer direct nouns such as `Bedrock Support`, `ViaLite`, and `Configuration`.
+
+## Content Shape
+
+- Avoid duplicating setup guidance across Bedrock, GeyserLite, ViaLite, compatibility, and multi-version pages.
+- Use `guide/bedrock.md` for operator-facing Bedrock setup.
+- Use `/geyserlite/` to explain the managed Bedrock runtime, release policy, and relation to GeyserMC.
+- Use `guide/compatibility.md` for server implementation compatibility. Its path and title should stay aligned around compatibility.
+- Use `guide/multi-version.md` for user-facing Via-powered multi-version setup.
+- Use `/vialite/` for the lower-level ViaLite runtime, topology, and release policy.
+
+## Verification
+
+- Run the VitePress build from `.web` before opening a docs PR:
+
+ ```sh
+ pnpm build
+ ```
+
+- When changing navigation, check the rendered desktop and mobile docs navigation before merging.
diff --git a/.web/docs/.vitepress/config.ts b/.web/docs/.vitepress/config.ts
index 22ac72d73..e408aaccb 100644
--- a/.web/docs/.vitepress/config.ts
+++ b/.web/docs/.vitepress/config.ts
@@ -21,6 +21,177 @@ const communityStats = {
githubStars: numberFromEnv(process.env.GATE_DOCS_GITHUB_STARS, 1050),
};
+const guideSidebar = [
+ {
+ text: 'Getting Started',
+ items: [
+ { text: 'Introduction', link: '/guide/' },
+ { text: 'Quick Start', link: '/guide/quick-start' },
+ { text: 'Why', link: '/guide/why' },
+ { text: 'Feedback', link: '/guide/feedback' },
+ ],
+ },
+ {
+ text: 'Installation',
+ items: [
+ {
+ text: 'Prebuilt Binaries',
+ link: '/guide/install/binaries',
+ },
+ {
+ text: 'Go Install',
+ link: '/guide/install/go',
+ },
+ {
+ text: 'Docker',
+ link: '/guide/install/docker',
+ },
+ {
+ text: 'Kubernetes',
+ link: '/guide/install/kubernetes',
+ },
+ ],
+ },
+ {
+ text: 'Core Features',
+ items: [
+ {
+ text: 'Bedrock Support',
+ link: '/guide/bedrock',
+ },
+ {
+ text: 'GeyserLite',
+ link: '/geyserlite/',
+ },
+ {
+ text: 'Compatibility',
+ link: '/guide/compatibility',
+ },
+ {
+ text: 'Multi-Version Support',
+ link: '/guide/multi-version',
+ },
+ {
+ text: 'ViaLite',
+ link: '/vialite/',
+ },
+ {
+ text: 'Lite Mode',
+ link: '/guide/lite',
+ },
+ {
+ text: 'Modded Servers',
+ link: '/guide/modded-servers',
+ },
+ ],
+ },
+ {
+ text: 'Developers & API',
+ items: [
+ {
+ text: 'Developers Guide',
+ link: '/developers/',
+ },
+ {
+ text: 'API & SDKs',
+ link: '/developers/api/',
+ },
+ {
+ text: 'Events',
+ link: '/developers/events',
+ },
+ {
+ text: 'Commands',
+ link: '/developers/commands',
+ },
+ {
+ text: 'Examples',
+ link: '/developers/examples/simple-proxy',
+ },
+ ],
+ },
+ {
+ text: 'Configuration',
+ items: [
+ {
+ text: 'Configuration & Templates',
+ link: '/guide/config/',
+ },
+ {
+ text: 'Auto Reload',
+ link: '/guide/config/reload',
+ },
+ {
+ text: 'Builtin Commands',
+ link: '/guide/builtin-commands',
+ },
+ {
+ text: 'Rate Limiting',
+ link: '/guide/rate-limiting',
+ },
+ {
+ text: 'Enabling Connect',
+ link: '/guide/connect',
+ },
+ {
+ text: 'ForcedHosts Routing',
+ link: '/guide/forced-hosts',
+ },
+ ],
+ },
+ {
+ text: 'OpenTelemetry',
+ items: [
+ {
+ text: 'Overview',
+ link: '/guide/otel/',
+ },
+ {
+ text: 'Grafana',
+ items: [
+ {
+ text: 'Grafana Cloud',
+ link: '/guide/otel/grafana-cloud/',
+ },
+ {
+ text: 'Self-hosted Grafana Stack',
+ link: '/guide/otel/self-hosted/grafana-stack.md',
+ },
+ {
+ text: 'Grafana Dashboards',
+ link: '/guide/otel/self-hosted/dashboard',
+ },
+ ],
+ },
+ {
+ text: 'Honeycomb',
+ link: '/guide/otel/honeycomb/',
+ },
+ {
+ text: 'Self-hosted Jaeger',
+ link: '/guide/otel/self-hosted/jaeger',
+ },
+ {
+ text: 'FAQ',
+ link: '/guide/otel/faq/',
+ },
+ ],
+ },
+ {
+ text: 'Security',
+ items: [
+ {
+ text: 'Cybersecurity',
+ link: '/guide/security/',
+ },
+ {
+ text: 'DDoS Protection',
+ link: '/guide/security/ddos',
+ },
+ ],
+ },
+];
+
export default defineConfig({
title: `Gate Proxy${additionalTitle}`,
description: ogDescription,
@@ -132,164 +303,7 @@ export default defineConfig({
],
sidebar: {
- '/guide/': [
- {
- text: 'Getting Started',
- items: [
- { text: 'Introduction', link: '/guide/' },
- { text: 'Quick Start', link: '/guide/quick-start' },
- { text: 'Why', link: '/guide/why' },
- { text: 'Feedback', link: '/guide/feedback' },
- ],
- },
- {
- text: '📦 Installation',
- items: [
- {
- text: 'Prebuilt Binaries',
- link: '/guide/install/binaries',
- },
- {
- text: 'Go Install',
- link: '/guide/install/go',
- },
- {
- text: 'Docker',
- link: '/guide/install/docker',
- },
- {
- text: 'Kubernetes',
- link: '/guide/install/kubernetes',
- },
- ],
- },
- {
- text: 'Core Features',
- items: [
- {
- text: '🎮 Bedrock Support',
- link: '/guide/bedrock',
- },
- {
- text: '⚡ Lite Mode',
- link: '/guide/lite',
- },
- {
- text: '🔧 Modded Servers',
- link: '/guide/modded-servers',
- },
- {
- text: '🔗 Compatibility',
- link: '/guide/compatibility',
- },
- ],
- },
- {
- text: 'Developers & API',
- items: [
- {
- text: '👨💻 Developers Guide',
- link: '/developers/',
- },
- {
- text: '🚀 API & SDKs',
- link: '/developers/api/',
- },
- {
- text: '📚 Events',
- link: '/developers/events',
- },
- {
- text: '⚡ Commands',
- link: '/developers/commands',
- },
- {
- text: '💡 Examples',
- link: '/developers/examples/simple-proxy',
- },
- ],
- },
- {
- text: 'Configuration',
- items: [
- {
- text: '📋 Configuration & Templates',
- link: '/guide/config/',
- },
- {
- text: '🔄 Auto Reload',
- link: '/guide/config/reload',
- },
- {
- text: '⚙️ Builtin Commands',
- link: '/guide/builtin-commands',
- },
- {
- text: '🛡️ Rate Limiting',
- link: '/guide/rate-limiting',
- },
- {
- text: '🌐 Enabling Connect',
- link: '/guide/connect',
- },
- {
- text: '🌐 ForcedHosts Routing',
- link: '/guide/forced-hosts',
- },
- ],
- },
- {
- text: 'OpenTelemetry',
- items: [
- {
- text: 'Overview',
- link: '/guide/otel/',
- },
- {
- text: 'Grafana',
- items: [
- {
- text: 'Grafana Cloud',
- link: '/guide/otel/grafana-cloud/',
- },
- {
- text: 'Self-hosted Grafana Stack',
- link: '/guide/otel/self-hosted/grafana-stack.md',
- },
- {
- text: 'Grafana Dashboards',
- link: '/guide/otel/self-hosted/dashboard',
- },
- ],
- },
- {
- text: 'Honeycomb',
- link: '/guide/otel/honeycomb/',
- },
- {
- text: 'Self-hosted Jaeger',
- link: '/guide/otel/self-hosted/jaeger',
- },
- {
- text: 'FAQ',
- link: '/guide/otel/faq/',
- },
- ],
- },
- {
- text: 'Security',
- items: [
- {
- text: 'Cybersecurity',
- link: '/guide/security/',
- },
- {
- text: 'DDoS Protection',
- link: '/guide/security/ddos',
- },
- ],
- },
- ],
+ '/guide/': guideSidebar,
'/developers/': [
{
text: 'Developers Guide',
@@ -382,10 +396,12 @@ export default defineConfig({
],
},
{
- text: '← Back to Guides',
+ text: 'Back to Guides',
link: '/guide/',
},
],
+ '/geyserlite/': guideSidebar,
+ '/vialite/': guideSidebar,
// '/config/': [
// {
// text: 'Configuration',
diff --git a/.web/docs/developers/api/java/pom.xml b/.web/docs/developers/api/java/pom.xml
index 140fbe631..3797491e6 100644
--- a/.web/docs/developers/api/java/pom.xml
+++ b/.web/docs/developers/api/java/pom.xml
@@ -44,23 +44,23 @@
io.grpc
grpc-netty-shaded
- 1.82.0
+ 1.82.1
io.grpc
grpc-protobuf
- 1.82.0
+ 1.82.1
io.grpc
grpc-stub
- 1.82.0
+ 1.82.1
com.google.protobuf
protobuf-java
- 4.33.4
+ 4.35.1
\ No newline at end of file
diff --git a/.web/docs/developers/api/kotlin/build.gradle.kts b/.web/docs/developers/api/kotlin/build.gradle.kts
index 6b830cd14..6cb9e3be1 100644
--- a/.web/docs/developers/api/kotlin/build.gradle.kts
+++ b/.web/docs/developers/api/kotlin/build.gradle.kts
@@ -11,10 +11,10 @@ repositories {
}
}
-val grpcVersion = "1.82.0"
+val grpcVersion = "1.82.1"
val grpcKotlinVersion = "1.5.0"
val connectVersion = "0.7.1"
-val protobufVersion = "4.33.4"
+val protobufVersion = "4.35.1"
dependencies {
// Kotlin
diff --git a/.web/docs/geyserlite/index.md b/.web/docs/geyserlite/index.md
new file mode 100644
index 000000000..cb2a9ff95
--- /dev/null
+++ b/.web/docs/geyserlite/index.md
@@ -0,0 +1,69 @@
+---
+title: "GeyserLite - Managed Bedrock Runtime for Gate"
+description: "GeyserLite is the managed runtime Gate uses to provide Bedrock cross-play through GeyserMC."
+---
+
+# GeyserLite
+
+GeyserLite is Minekube's managed runtime packaging for
+[GeyserMC](https://geysermc.org/). Gate uses it for Bedrock cross-play without
+requiring operators to run and wire a separate Geyser process for the common
+case.
+
+For operator setup and configuration examples, use the
+[Bedrock support guide](/guide/bedrock).
+
+## Topology
+
+```text
+Bedrock player
+ -> GeyserLite
+ -> Gate classic
+ -> optional ViaLite
+ -> backend server
+```
+
+GeyserLite is the Bedrock ingress layer. It translates Bedrock protocol into
+Java protocol before the connection reaches Gate. Gate then owns routing,
+events, forwarding, Connect integration, and backend login.
+
+If [ViaLite](/vialite/) is enabled, it sits behind Gate. Bedrock traffic is
+already translated to Java before ViaLite handles backend version translation.
+
+## Runtime Scope
+
+GeyserLite is responsible for the managed Geyser runtime shape:
+
+- Native executable for managed subprocess mode.
+- Shared library for embedded integrations where supported.
+- Container image for standalone deployments.
+- Release artifacts and checksums that Gate can consume as a managed
+ dependency.
+
+Gate decides which runtime mode to use for the current platform and
+configuration. The Bedrock guide covers the Gate config surface.
+
+## Version Policy
+
+GeyserLite tracks upstream Geyser through a pinned source ref and a managed
+release chain. Production guidance follows upstream Geyser support:
+
+- If Geyser officially supports the relevant Java and Bedrock versions, Gate's
+ managed Bedrock mode is the stable path.
+- If a backend updates to a brand-new Java version before Geyser supports it,
+ production networks should usually wait before upgrading Bedrock-critical
+ servers.
+- Preview pins are exceptional. They should require a concrete upstream Geyser
+ preview build or PR and a clear user-impact reason.
+
+ViaLite may help when only the Java backend protocol is newer, but it cannot
+fix unsupported Bedrock client protocols or missing Geyser Bedrock-to-Java
+translation.
+
+## Links
+
+- [Bedrock support guide](/guide/bedrock)
+- [ViaLite](/vialite/)
+- [GeyserLite repository](https://github.com/minekube/geyserlite)
+- [GeyserLite releases](https://github.com/minekube/geyserlite/releases)
+- [GeyserMC supported versions](https://geysermc.org/wiki/geyser/supported-versions/)
diff --git a/.web/docs/guide/bedrock.md b/.web/docs/guide/bedrock.md
index 749f3b60f..ad6fca593 100644
--- a/.web/docs/guide/bedrock.md
+++ b/.web/docs/guide/bedrock.md
@@ -42,7 +42,8 @@ gate --config config.yml
Gate automatically generates encryption keys, downloads Geyser, creates optimized configs, and manages everything for you. The `bedrock: true` shorthand enables both Bedrock support and managed mode in one line.
:::
-
+Managed Bedrock support is powered by [GeyserLite](/geyserlite/), Minekube's
+native runtime packaging of GeyserMC for Gate.
## How It Works
@@ -54,8 +55,13 @@ Gate's Bedrock support uses a **proxy-in-front-of-proxy** architecture with buil
1. **Bedrock Players** connect to Geyser on UDP port 19132 (default, customizable)
2. **Geyser** translates Bedrock protocol to Java Edition and forwards to Gate
-3. **Gate** receives translated connections, handles Floodgate authentication internally, and presents them as regular Java players to backend servers
-4. **Backend servers** see all players as normal Java Edition connections - no plugins required!
+3. **Gate** receives translated connections, handles Floodgate authentication internally, and presents them as regular Java players to backend servers by default
+4. **Backend servers** see normal Java Edition connections - no plugins required unless you explicitly enable backend Floodgate compatibility for specific servers
+
+If [ViaLite](/vialite/) is enabled, it runs behind Gate after GeyserLite has
+already translated Bedrock traffic to Java protocol. That can help with Java
+backend version differences, but it does not replace Geyser's Bedrock protocol
+support.
### Key Benefits
@@ -110,6 +116,7 @@ bedrock:
| `usernameFormat` | Format string for Bedrock usernames (use `%s` for username) | `".%s"` |
| `geyserListenAddr` | Address where Gate listens for Geyser connections | `localhost:25567` |
| `floodgateKeyPath` | Path to Floodgate encryption key | `floodgate.pem` |
+| `backendFloodgate` | Optional allowlist for backend Floodgate plugin compatibility | disabled |
::: tip geyserListenAddr Network Configuration
@@ -135,6 +142,54 @@ Note: All connections are authenticated via Floodgate keys regardless of the bin
| `dataDir` | Directory for Geyser files | `.geyser` |
| `extraArgs` | Additional JVM arguments | `[]` |
+### Backend Floodgate Compatibility
+
+Gate handles Floodgate authentication itself, so most servers do not need a backend Floodgate plugin. Some backend plugins still call the Floodgate API directly to check whether a player is from Bedrock Edition, read linked-account data, or apply platform-specific behavior. For those servers, enable backend Floodgate compatibility explicitly per backend.
+
+:::: code-group
+
+```yaml [config.yml]
+config:
+ forwarding:
+ # backendFloodgate supports none and velocity.
+ # legacy and bungeeguard are not compatible because they also use
+ # hostname-based forwarding.
+ mode: velocity
+
+ servers:
+ lobby: localhost:25566
+ survival: localhost:25567
+ auth: localhost:25568
+ try:
+ - lobby
+
+ bedrock:
+ enabled: true
+ managed: true
+ floodgateKeyPath: floodgate.pem
+
+ backendFloodgate:
+ enabled: true
+ allowedServers:
+ - lobby
+ - survival
+```
+
+::::
+
+When enabled, Gate re-attaches freshly encrypted Floodgate player data only for verified Bedrock players and only when they connect to a listed backend. Java clients cannot spoof this data through the hostname, and unlisted backends continue to receive the normal clean Java hostname.
+
+::: warning Trust boundary
+Only allow backends that you operate and trust with the same Floodgate key. Do not enable this for third-party, shared, or untrusted backend servers.
+:::
+
+Requirements:
+
+- `bedrock.enabled` must be `true`.
+- `backendFloodgate.allowedServers` must list existing `config.servers` names.
+- `floodgateKeyPath` must point to the key shared with the backend Floodgate plugin, unless managed mode will generate it.
+- `forwarding.mode` must be `none` or `velocity`.
+
### Configuration Modes
Gate supports two approaches for Bedrock integration:
diff --git a/.web/docs/guide/compatibility.md b/.web/docs/guide/compatibility.md
index 6d95e7acf..93349cd6f 100644
--- a/.web/docs/guide/compatibility.md
+++ b/.web/docs/guide/compatibility.md
@@ -1,40 +1,21 @@
---
-title: "Gate Compatibility - Supported Minecraft Versions"
-description: "Gate supports Minecraft versions 1.8 to latest, including modded servers, plugins, and cross-platform compatibility."
+title: "Gate Compatibility"
+description: "Gate compatibility notes for Minecraft server implementations, modded servers, proxy setups, Bedrock players, and multi-version networks."
---
-# Server Compatibility
+# Compatibility
-Gate is compatible with many Minecraft server implementations.
-The expectation is that if the server acts like vanilla, Gate will work,
-and we make special provisions for modded setups where we can.
+Gate is compatible with many Minecraft server implementations. If the server
+acts like vanilla, Gate should work, and Gate includes specific support for
+common modded setups.
-Gate provides excellent support for **modded servers** including Fabric and NeoForge. See our [Modded Servers Guide](modded-servers) for detailed setup instructions.
+Gate itself supports Minecraft 1.8 through the latest version supported by the
+current Gate release. For client/backend protocol translation between different
+Java Minecraft versions, see [Multi-Version Support](multi-version).
-Gate is compatible with Minecraft 1.8 through the latest version
-and we maintainers update Gate as soon as a new Minecraft version is released.
+## Server Implementations
-## Java Version Translation
-
-Gate can run managed Via translation in classic proxy mode. When `config.via.enabled`
-is true, Gate starts vialite, keeps it on the latest stable release by default,
-and routes backend connections through Via-compatible protocol translation.
-This applies to both configured servers and API-registered servers, so dynamic
-Connect/session backends can be joined by Java clients even when the backend
-Minecraft version differs from the client version.
-
-```yaml
-config:
- via:
- enabled: true
-```
-
-Lite mode does not run managed Via translation. Dynamic API-registered backend
-translation uses the default subprocess mode; embedded mode is limited to
-configured servers. For controlled deployments, Gate still supports exact
-vialite version pins, offline mode, and local artifact paths.
-
-## Paper Recommended
+### Paper Recommended
We highly recommend using [Paper](https://papermc.io/) for running a server in most cases.
Gate is tested with older and most recent versions of it.
@@ -42,14 +23,14 @@ Gate is tested with older and most recent versions of it.
You can use `modern` forwarding (like Velocity does) if you run Paper
1.13.2 or higher. If you use Paper 1.12.2 or lower, you can use `legacy` BungeeCord-style forwarding or the more secure `bungeeguard` [Bungeeguard](https://www.spigotmc.org/resources/bungeeguard.79601/) forwarding.
-## Spigot
+### Spigot
Spigot is not well-tested with Gate.
However, it is based on vanilla and as it is the base for Paper, it is relatively well-supported.
Spigot does not support Gate/Velocity modern forwarding, but does support legacy BungeeCord forwarding and the more secure Bungeeguard forwarding when using the [Bungeeguard](https://www.spigotmc.org/resources/bungeeguard.79601/) plugin.
-## Forks of Spigot/Paper
+### Forks of Spigot/Paper
Forks of Spigot are not well-tested with Gate, though they may work perfectly fine.
@@ -84,12 +65,24 @@ Gate has excellent compatibility with modded Minecraft servers:
- **Legacy forwarding only** - Use BungeeCord forwarding
- **Older versions** - May have compatibility issues
-For detailed setup instructions, configuration examples, and troubleshooting, see our comprehensive [Modded Servers Guide](modded-servers).
+For setup instructions, configuration examples, and troubleshooting, see the
+[Modded Servers Guide](modded-servers).
+
+## Bedrock Players
+
+Bedrock support is handled by [GeyserLite](/geyserlite/) before the player
+reaches Gate. Start with the [Bedrock support guide](bedrock) for setup.
+
+If Bedrock players need to join Java backend servers on a different Minecraft
+version, Gate may also use [Multi-Version Support](multi-version) behind Gate,
+after GeyserLite has translated the Bedrock session into Java protocol.
-## Proxy-behind-proxy setups
+## Proxy-Behind-Proxy Setups
-These setups are only supported with [Lite mode](lite#proxy-behind-proxy) or [Connect enabled](connect)!
+These setups are only supported with [Lite mode](lite#proxy-behind-proxy) or
+[Connect enabled](connect).
-You are best advised to avoid other kinds of setups, as they can cause lots of issues.
-Most proxy-behind-proxy setups are either illogical in the first place or can be handled more
-gracefully by purpose-built solutions like [Connect](https://connect.minekube.com/) or [Lite mode](lite).
+Avoid other proxy-behind-proxy setups where possible. They often introduce
+ambiguous authentication and forwarding behavior that is better handled by
+purpose-built solutions like [Connect](https://connect.minekube.com/) or
+[Lite mode](lite).
diff --git a/.web/docs/guide/index.md b/.web/docs/guide/index.md
index b2f8aa66c..cfc498963 100644
--- a/.web/docs/guide/index.md
+++ b/.web/docs/guide/index.md
@@ -37,8 +37,27 @@ Google, Microsoft, Meta, Amazon, Twitter, PayPal, Twitch, Netflix, Dropbox, Uber
Ready to jump in? Choose your path:
-- **Server Owners**: Head to the [Quick Start](quick-start) guide
-- **Developers**: Check out the [Developer Guide](/developers/)
+
## Why Use a Minecraft Proxy?
@@ -162,6 +181,83 @@ This architecture enables powerful features like load balancing, server maintena
color: var(--vp-c-text-2);
}
+.path-cards {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 20px;
+ margin: 24px 0 32px;
+}
+
+.path-card {
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ color: inherit;
+ text-decoration: none;
+ background-color: var(--vp-c-bg-soft);
+ border: 1px solid var(--vp-c-divider);
+ border-radius: 8px;
+ transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
+}
+
+.vp-doc .path-card {
+ color: inherit;
+ text-decoration: none;
+}
+
+.path-card:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 2px 12px 0 var(--vp-c-divider);
+ border-color: var(--vp-c-brand-1);
+ text-decoration: none;
+}
+
+.path-card:focus-visible {
+ outline: 2px solid var(--vp-c-brand-1);
+ outline-offset: 3px;
+}
+
+.path-card-media {
+ display: block;
+ width: 100%;
+ aspect-ratio: 16 / 9;
+ overflow: hidden;
+ background-color: var(--vp-c-bg-alt);
+}
+
+.path-card-media img {
+ display: block;
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
+.path-card-content {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ gap: 6px;
+ padding: 18px 20px 20px;
+}
+
+.path-card-title {
+ color: var(--vp-c-brand-1);
+ font-size: 18px;
+ font-weight: 700;
+ line-height: 1.35;
+}
+
+.path-card-text {
+ color: var(--vp-c-text-2);
+ line-height: 1.55;
+}
+
+@media (max-width: 640px) {
+ .path-cards {
+ grid-template-columns: 1fr;
+ }
+}
+
.feature-image {
margin: 2rem 0;
border-radius: 8px;
diff --git a/.web/docs/guide/multi-version.md b/.web/docs/guide/multi-version.md
new file mode 100644
index 000000000..8ac5c6a4d
--- /dev/null
+++ b/.web/docs/guide/multi-version.md
@@ -0,0 +1,62 @@
+---
+title: "Gate Multi-Version Support"
+description: "Use Gate's managed Via support to let Java clients join backend servers across different Minecraft protocol versions."
+---
+
+# Multi-Version Support
+
+Gate classic can route backend connections through managed Via-powered Java
+protocol translation. This lets clients join backend servers even when the
+client and backend Minecraft versions differ.
+
+Enable it with:
+
+```yaml
+config:
+ via:
+ enabled: true
+```
+
+Gate starts [ViaLite](/vialite/) and routes backend connections through it.
+This applies to configured servers and API-registered servers, so dynamic
+Connect/session backends can use the same version translation path.
+
+## Topology
+
+```text
+Java player
+ -> Gate classic
+ -> ViaLite
+ -> backend server
+
+Bedrock player
+ -> GeyserLite
+ -> Gate classic
+ -> ViaLite
+ -> backend server
+```
+
+ViaLite sits behind Gate. Gate accepts the player, handles routing and events,
+and then ViaLite translates the backend-facing Java protocol where needed.
+
+## Bedrock Players
+
+[GeyserLite](/geyserlite/) translates Bedrock sessions into Java protocol
+before the player reaches Gate. ViaLite can then help with Java backend version
+differences behind Gate.
+
+ViaLite does not replace Geyser protocol support. If Geyser does not support a
+new Bedrock or Java version yet, production networks should usually wait for
+official upstream Geyser support before upgrading Bedrock-critical backends.
+
+## Gate Lite
+
+Gate Lite raw-pipes backend traffic after the initial handshake so backend
+servers keep authentication ownership. Managed Via translation needs to decode
+and rewrite packets after login, so it belongs to Gate classic backend
+connections, not Gate Lite.
+
+## Runtime Details
+
+For runtime modes, platform support, pins, offline deployment, and release
+policy, see [ViaLite](/vialite/).
diff --git a/.web/docs/images/choose-path-developer.webp b/.web/docs/images/choose-path-developer.webp
new file mode 100644
index 000000000..8bc1d1820
Binary files /dev/null and b/.web/docs/images/choose-path-developer.webp differ
diff --git a/.web/docs/images/choose-path-server-owner.webp b/.web/docs/images/choose-path-server-owner.webp
new file mode 100644
index 000000000..bdd903696
Binary files /dev/null and b/.web/docs/images/choose-path-server-owner.webp differ
diff --git a/.web/docs/index.md b/.web/docs/index.md
index 6e15de97e..e881018f7 100644
--- a/.web/docs/index.md
+++ b/.web/docs/index.md
@@ -56,6 +56,6 @@ features:
details:
Gate supports Minecraft server versions 1.8 to latest and is constantly updated to support
new versions.
- link: /guide/compatibility
- linkText: Compatibility
+ link: /guide/multi-version
+ linkText: Multi-Version Support
---
diff --git a/.web/docs/vialite/index.md b/.web/docs/vialite/index.md
new file mode 100644
index 000000000..278f75d9f
--- /dev/null
+++ b/.web/docs/vialite/index.md
@@ -0,0 +1,86 @@
+---
+title: "ViaLite - Managed Java Version Compatibility for Gate"
+description: "ViaLite gives Gate managed Via-powered backend protocol translation for Java clients and Bedrock players already translated through GeyserLite."
+---
+
+# ViaLite
+
+ViaLite is Minekube's managed Via runtime for Gate classic. It lets Gate route
+backend connections through Via-powered Java protocol translation while Gate
+keeps ownership of authentication, events, routing, Connect, and backend login.
+
+For user-facing setup, start with [Multi-Version Support](/guide/multi-version).
+This page covers the runtime shape behind that feature.
+
+## Topology
+
+```text
+Java player
+ -> Gate classic
+ -> ViaLite
+ -> backend server
+
+Bedrock player
+ -> GeyserLite
+ -> Gate classic
+ -> ViaLite
+ -> backend server
+```
+
+ViaLite sits behind Gate, not in front of it. Gate has already accepted the
+player and selected a backend before ViaLite translates backend packets.
+
+## Not Lite Mode
+
+Gate Lite intentionally reads the initial handshake, chooses a backend, and
+then raw-pipes bytes so backend servers keep authentication ownership. ViaLite
+must decode and rewrite packets after login, so it belongs to Gate classic
+backend connections instead.
+
+## Runtime Configuration
+
+By default, Gate uses the latest stable ViaLite release for managed
+multi-version support. Operators can still pin or override the runtime when
+they need controlled rollout or offline deployment.
+
+Subprocess mode is the portable default. Embedded mode is available where the
+native shared library is supported. See
+[Multi-Version Support](/guide/multi-version) for the basic enablement config.
+
+## Early Backend Upgrades
+
+ViaLite can bridge some early-upgrade scenarios:
+
+- A Java backend moves to a newer Minecraft server version.
+- Gate can still accept the client session.
+- Via supports translation between Gate's backend-facing protocol and that
+ backend version.
+
+For Bedrock players, GeyserLite must still be able to translate the Bedrock
+session into Java and connect to Gate. ViaLite can help with the Java backend
+side after that point, but it cannot add missing Geyser Bedrock protocol
+support.
+
+## Update Chain
+
+ViaLite releases publish checksummed native artifacts. Gate consumes those
+releases as a managed dependency, so the normal chain is:
+
+```text
+ViaLite release
+ -> Gate managed dependency bump
+ -> Gate release
+ -> downstream deployments
+```
+
+Use pins only for controlled rollouts. Otherwise let Gate's managed runtime use
+the stable ViaLite release channel.
+
+## Links
+
+- [Multi-Version Support](/guide/multi-version)
+- [Gate compatibility guide](/guide/compatibility)
+- [GeyserLite docs](/geyserlite/)
+- [ViaLite repository](https://github.com/minekube/vialite)
+- [ViaLite releases](https://github.com/minekube/vialite/releases)
+- [ViaVersion](https://viaversion.com/)
diff --git a/.web/pnpm-lock.yaml b/.web/pnpm-lock.yaml
index 9d5aa3fd5..1d1fd032b 100644
--- a/.web/pnpm-lock.yaml
+++ b/.web/pnpm-lock.yaml
@@ -20,16 +20,16 @@ importers:
devDependencies:
'@cloudflare/workers-types':
specifier: ^4.20251117.0
- version: 4.20260623.1
+ version: 4.20260702.1
'@types/node':
specifier: ^20.14.0
version: 20.19.43
autoprefixer:
specifier: ^10.4.13
- version: 10.5.2(postcss@8.5.15)
+ version: 10.5.2(postcss@8.5.16)
postcss:
specifier: ^8.4.20
- version: 8.5.15
+ version: 8.5.16
tailwindcss:
specifier: ^3.2.4
version: 3.4.19(yaml@2.8.1)
@@ -38,7 +38,7 @@ importers:
version: 5.9.3
vitepress:
specifier: ^1.6.4
- version: 1.6.4(@algolia/client-search@5.37.0)(@types/node@20.19.43)(postcss@8.5.15)(search-insights@2.17.3)(typescript@5.9.3)
+ version: 1.6.4(@algolia/client-search@5.37.0)(@types/node@20.19.43)(postcss@8.5.16)(search-insights@2.17.3)(typescript@5.9.3)
vue:
specifier: ^3.2.45
version: 3.5.39(typescript@5.9.3)
@@ -142,8 +142,8 @@ packages:
resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==}
engines: {node: '>=6.9.0'}
- '@cloudflare/workers-types@4.20260623.1':
- resolution: {integrity: sha512-J/0POl0HeLepbwDE5Yx5c7jQrHFkvCEFu3TS+TQsDDlg/vTs5og7wdGP6eNGXOAntgWUrjcvvKTmVLTP7OrnAg==}
+ '@cloudflare/workers-types@4.20260702.1':
+ resolution: {integrity: sha512-mOhf5TUEB1m2vPrxtqoIGfz0fUC9xyxRDx5gWHy5s+OCo6dcV+g7wI1R7gYCMFohhqF/2y2xeKVwMwCJjfn/WA==}
'@docsearch/css@3.8.2':
resolution: {integrity: sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==}
@@ -586,27 +586,15 @@ packages:
vite: ^5.0.0 || ^6.0.0
vue: ^3.2.25
- '@vue/compiler-core@3.5.38':
- resolution: {integrity: sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==}
-
'@vue/compiler-core@3.5.39':
resolution: {integrity: sha512-16KBTEXAJCpDr0mwlw+AZyhu8iyC7R3S2vBwsI7QnWJU6X3WKc9VKeNEZpiMdZ569qWhz9574L3vV55qRL0Vtw==}
- '@vue/compiler-dom@3.5.38':
- resolution: {integrity: sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==}
-
'@vue/compiler-dom@3.5.39':
resolution: {integrity: sha512-oQPigALqYbNxTNPvNgSOe+czwVExfbVF02lz8jP0S3AXJiu3jxYDygNUiqSep4ezzW8XgnubqH63My2A7JR/vg==}
- '@vue/compiler-sfc@3.5.38':
- resolution: {integrity: sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==}
-
'@vue/compiler-sfc@3.5.39':
resolution: {integrity: sha512-d0ki86iOyN8LoZPBmk5SJWNwHP19CnDDCfuo//+2WJa2g5Ke0Jay983PIBIcSSzldC68I8DrD5GrHV3OSDfodg==}
- '@vue/compiler-ssr@3.5.38':
- resolution: {integrity: sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==}
-
'@vue/compiler-ssr@3.5.39':
resolution: {integrity: sha512-Ce7/wvwMHai74bdszfXExdazFigYnlF9zgCmEQUcM1j0fOymlouZ7XilTYNo8oUjhlnjYOZbGrcYKuqjz89Ucw==}
@@ -619,29 +607,15 @@ packages:
'@vue/devtools-shared@7.7.7':
resolution: {integrity: sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw==}
- '@vue/reactivity@3.5.38':
- resolution: {integrity: sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==}
-
'@vue/reactivity@3.5.39':
resolution: {integrity: sha512-TpsuBJ9gGlZa5d23XcM2y8EXanz9dZeVDQBXRwzy46ItgvM+rWpzs+UVM0wcRLxGvcav0HE5jz2gNL53xlRAog==}
- '@vue/runtime-core@3.5.38':
- resolution: {integrity: sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==}
-
'@vue/runtime-core@3.5.39':
resolution: {integrity: sha512-9GLtNyRvPAUMbX+7ono0RC2j0guo2LXVi8LvcmAooImACUKm0oFf0jjwbX8/H0AE/t1nxhAkn8RSl9PMCzzxZw==}
- '@vue/runtime-dom@3.5.38':
- resolution: {integrity: sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==}
-
'@vue/runtime-dom@3.5.39':
resolution: {integrity: sha512-7Y6aAGboKcXAZ3ECuUy7RrS5yy2r47dhTp2SKaJmYxjopImaVFaNa5Ne66NwGovsrxVAl5S5rwc7m22UG7Lmww==}
- '@vue/server-renderer@3.5.38':
- resolution: {integrity: sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==}
- peerDependencies:
- vue: 3.5.38
-
'@vue/server-renderer@3.5.39':
resolution: {integrity: sha512-yZSakiAGw85rZfG7UM8akMnIF+FmeiNk47uvHf2nVBBSe+dIKUhZuZq9+XgJhbV3nS5Z4ALH23/MpXofW+mbcw==}
peerDependencies:
@@ -650,9 +624,6 @@ packages:
'@vue/shared@3.5.21':
resolution: {integrity: sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==}
- '@vue/shared@3.5.38':
- resolution: {integrity: sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==}
-
'@vue/shared@3.5.39':
resolution: {integrity: sha512-l1rrBtBfTnmxvtsvdQDXltUUy8S1Y+ZaqdfUzmAnJkTd8Z8rv5v/ytW+TKiqEOWyHPoqtPlNFSs0lhRmYVSHVA==}
@@ -978,8 +949,8 @@ packages:
mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
- nanoid@3.3.12:
- resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
+ nanoid@3.3.15:
+ resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
@@ -1070,8 +1041,8 @@ packages:
postcss-value-parser@4.2.0:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
- postcss@8.5.15:
- resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
+ postcss@8.5.16:
+ resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==}
engines: {node: ^10 || ^12 || >=14}
posthog-js@1.390.2:
@@ -1278,14 +1249,6 @@ packages:
postcss:
optional: true
- vue@3.5.38:
- resolution: {integrity: sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==}
- peerDependencies:
- typescript: '*'
- peerDependenciesMeta:
- typescript:
- optional: true
-
vue@3.5.39:
resolution: {integrity: sha512-xmZCYabFGcirU8r0fTuvl/LICc1OU620rnqepaJDL/a141ZigkG7AyaxQLdqJ02ZRYzWe6YPaDHeQx7MfknQfA==}
peerDependencies:
@@ -1434,7 +1397,7 @@ snapshots:
'@babel/helper-string-parser': 7.29.7
'@babel/helper-validator-identifier': 7.29.7
- '@cloudflare/workers-types@4.20260623.1': {}
+ '@cloudflare/workers-types@4.20260702.1': {}
'@docsearch/css@3.8.2': {}
@@ -1800,18 +1763,10 @@ snapshots:
'@ungap/structured-clone@1.3.0': {}
- '@vitejs/plugin-vue@5.2.4(vite@5.4.19(@types/node@20.19.43))(vue@3.5.38(typescript@5.9.3))':
+ '@vitejs/plugin-vue@5.2.4(vite@5.4.19(@types/node@20.19.43))(vue@3.5.39(typescript@5.9.3))':
dependencies:
vite: 5.4.19(@types/node@20.19.43)
- vue: 3.5.38(typescript@5.9.3)
-
- '@vue/compiler-core@3.5.38':
- dependencies:
- '@babel/parser': 7.29.7
- '@vue/shared': 3.5.38
- entities: 7.0.1
- estree-walker: 2.0.2
- source-map-js: 1.2.1
+ vue: 3.5.39(typescript@5.9.3)
'@vue/compiler-core@3.5.39':
dependencies:
@@ -1821,28 +1776,11 @@ snapshots:
estree-walker: 2.0.2
source-map-js: 1.2.1
- '@vue/compiler-dom@3.5.38':
- dependencies:
- '@vue/compiler-core': 3.5.38
- '@vue/shared': 3.5.38
-
'@vue/compiler-dom@3.5.39':
dependencies:
'@vue/compiler-core': 3.5.39
'@vue/shared': 3.5.39
- '@vue/compiler-sfc@3.5.38':
- dependencies:
- '@babel/parser': 7.29.7
- '@vue/compiler-core': 3.5.38
- '@vue/compiler-dom': 3.5.38
- '@vue/compiler-ssr': 3.5.38
- '@vue/shared': 3.5.38
- estree-walker: 2.0.2
- magic-string: 0.30.21
- postcss: 8.5.15
- source-map-js: 1.2.1
-
'@vue/compiler-sfc@3.5.39':
dependencies:
'@babel/parser': 7.29.7
@@ -1852,14 +1790,9 @@ snapshots:
'@vue/shared': 3.5.39
estree-walker: 2.0.2
magic-string: 0.30.21
- postcss: 8.5.15
+ postcss: 8.5.16
source-map-js: 1.2.1
- '@vue/compiler-ssr@3.5.38':
- dependencies:
- '@vue/compiler-dom': 3.5.38
- '@vue/shared': 3.5.38
-
'@vue/compiler-ssr@3.5.39':
dependencies:
'@vue/compiler-dom': 3.5.39
@@ -1883,31 +1816,15 @@ snapshots:
dependencies:
rfdc: 1.4.1
- '@vue/reactivity@3.5.38':
- dependencies:
- '@vue/shared': 3.5.38
-
'@vue/reactivity@3.5.39':
dependencies:
'@vue/shared': 3.5.39
- '@vue/runtime-core@3.5.38':
- dependencies:
- '@vue/reactivity': 3.5.38
- '@vue/shared': 3.5.38
-
'@vue/runtime-core@3.5.39':
dependencies:
'@vue/reactivity': 3.5.39
'@vue/shared': 3.5.39
- '@vue/runtime-dom@3.5.38':
- dependencies:
- '@vue/reactivity': 3.5.38
- '@vue/runtime-core': 3.5.38
- '@vue/shared': 3.5.38
- csstype: 3.2.3
-
'@vue/runtime-dom@3.5.39':
dependencies:
'@vue/reactivity': 3.5.39
@@ -1915,12 +1832,6 @@ snapshots:
'@vue/shared': 3.5.39
csstype: 3.2.3
- '@vue/server-renderer@3.5.38(vue@3.5.38(typescript@5.9.3))':
- dependencies:
- '@vue/compiler-ssr': 3.5.38
- '@vue/shared': 3.5.38
- vue: 3.5.38(typescript@5.9.3)
-
'@vue/server-renderer@3.5.39(vue@3.5.39(typescript@5.9.3))':
dependencies:
'@vue/compiler-ssr': 3.5.39
@@ -1929,8 +1840,6 @@ snapshots:
'@vue/shared@3.5.21': {}
- '@vue/shared@3.5.38': {}
-
'@vue/shared@3.5.39': {}
'@vueuse/core@12.8.2(typescript@5.9.3)':
@@ -1938,7 +1847,7 @@ snapshots:
'@types/web-bluetooth': 0.0.21
'@vueuse/metadata': 12.8.2
'@vueuse/shared': 12.8.2(typescript@5.9.3)
- vue: 3.5.38(typescript@5.9.3)
+ vue: 3.5.39(typescript@5.9.3)
transitivePeerDependencies:
- typescript
@@ -1946,7 +1855,7 @@ snapshots:
dependencies:
'@vueuse/core': 12.8.2(typescript@5.9.3)
'@vueuse/shared': 12.8.2(typescript@5.9.3)
- vue: 3.5.38(typescript@5.9.3)
+ vue: 3.5.39(typescript@5.9.3)
optionalDependencies:
focus-trap: 7.6.5
transitivePeerDependencies:
@@ -1956,7 +1865,7 @@ snapshots:
'@vueuse/shared@12.8.2(typescript@5.9.3)':
dependencies:
- vue: 3.5.38(typescript@5.9.3)
+ vue: 3.5.39(typescript@5.9.3)
transitivePeerDependencies:
- typescript
@@ -1986,13 +1895,13 @@ snapshots:
arg@5.0.2: {}
- autoprefixer@10.5.2(postcss@8.5.15):
+ autoprefixer@10.5.2(postcss@8.5.16):
dependencies:
browserslist: 4.28.4
caniuse-lite: 1.0.30001799
fraction.js: 5.3.4
picocolors: 1.1.1
- postcss: 8.5.15
+ postcss: 8.5.16
postcss-value-parser: 4.2.0
baseline-browser-mapping@2.10.38: {}
@@ -2250,7 +2159,7 @@ snapshots:
object-assign: 4.1.1
thenify-all: 1.6.0
- nanoid@3.3.12: {}
+ nanoid@3.3.15: {}
node-releases@2.0.49: {}
@@ -2280,29 +2189,29 @@ snapshots:
pirates@4.0.7: {}
- postcss-import@15.1.0(postcss@8.5.15):
+ postcss-import@15.1.0(postcss@8.5.16):
dependencies:
- postcss: 8.5.15
+ postcss: 8.5.16
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.11
- postcss-js@4.1.0(postcss@8.5.15):
+ postcss-js@4.1.0(postcss@8.5.16):
dependencies:
camelcase-css: 2.0.1
- postcss: 8.5.15
+ postcss: 8.5.16
- postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.15)(yaml@2.8.1):
+ postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.16)(yaml@2.8.1):
dependencies:
lilconfig: 3.1.3
optionalDependencies:
jiti: 1.21.7
- postcss: 8.5.15
+ postcss: 8.5.16
yaml: 2.8.1
- postcss-nested@6.2.0(postcss@8.5.15):
+ postcss-nested@6.2.0(postcss@8.5.16):
dependencies:
- postcss: 8.5.15
+ postcss: 8.5.16
postcss-selector-parser: 6.1.2
postcss-selector-parser@6.1.2:
@@ -2312,9 +2221,9 @@ snapshots:
postcss-value-parser@4.2.0: {}
- postcss@8.5.15:
+ postcss@8.5.16:
dependencies:
- nanoid: 3.3.12
+ nanoid: 3.3.15
picocolors: 1.1.1
source-map-js: 1.2.1
@@ -2454,11 +2363,11 @@ snapshots:
normalize-path: 3.0.0
object-hash: 3.0.0
picocolors: 1.1.1
- postcss: 8.5.15
- postcss-import: 15.1.0(postcss@8.5.15)
- postcss-js: 4.1.0(postcss@8.5.15)
- postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.15)(yaml@2.8.1)
- postcss-nested: 6.2.0(postcss@8.5.15)
+ postcss: 8.5.16
+ postcss-import: 15.1.0(postcss@8.5.16)
+ postcss-js: 4.1.0(postcss@8.5.16)
+ postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.16)(yaml@2.8.1)
+ postcss-nested: 6.2.0(postcss@8.5.16)
postcss-selector-parser: 6.1.2
resolve: 1.22.11
sucrase: 3.35.1
@@ -2541,13 +2450,13 @@ snapshots:
vite@5.4.19(@types/node@20.19.43):
dependencies:
esbuild: 0.21.5
- postcss: 8.5.15
+ postcss: 8.5.16
rollup: 4.50.0
optionalDependencies:
'@types/node': 20.19.43
fsevents: 2.3.3
- vitepress@1.6.4(@algolia/client-search@5.37.0)(@types/node@20.19.43)(postcss@8.5.15)(search-insights@2.17.3)(typescript@5.9.3):
+ vitepress@1.6.4(@algolia/client-search@5.37.0)(@types/node@20.19.43)(postcss@8.5.16)(search-insights@2.17.3)(typescript@5.9.3):
dependencies:
'@docsearch/css': 3.8.2
'@docsearch/js': 3.8.2(@algolia/client-search@5.37.0)(search-insights@2.17.3)
@@ -2556,7 +2465,7 @@ snapshots:
'@shikijs/transformers': 2.5.0
'@shikijs/types': 2.5.0
'@types/markdown-it': 14.1.2
- '@vitejs/plugin-vue': 5.2.4(vite@5.4.19(@types/node@20.19.43))(vue@3.5.38(typescript@5.9.3))
+ '@vitejs/plugin-vue': 5.2.4(vite@5.4.19(@types/node@20.19.43))(vue@3.5.39(typescript@5.9.3))
'@vue/devtools-api': 7.7.7
'@vue/shared': 3.5.21
'@vueuse/core': 12.8.2(typescript@5.9.3)
@@ -2566,9 +2475,9 @@ snapshots:
minisearch: 7.1.2
shiki: 2.5.0
vite: 5.4.19(@types/node@20.19.43)
- vue: 3.5.38(typescript@5.9.3)
+ vue: 3.5.39(typescript@5.9.3)
optionalDependencies:
- postcss: 8.5.15
+ postcss: 8.5.16
transitivePeerDependencies:
- '@algolia/client-search'
- '@types/node'
@@ -2596,16 +2505,6 @@ snapshots:
- typescript
- universal-cookie
- vue@3.5.38(typescript@5.9.3):
- dependencies:
- '@vue/compiler-dom': 3.5.38
- '@vue/compiler-sfc': 3.5.38
- '@vue/runtime-dom': 3.5.38
- '@vue/server-renderer': 3.5.38(vue@3.5.38(typescript@5.9.3))
- '@vue/shared': 3.5.38
- optionalDependencies:
- typescript: 5.9.3
-
vue@3.5.39(typescript@5.9.3):
dependencies:
'@vue/compiler-dom': 3.5.39
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b32acf4be..40395b23d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,275 +1,146 @@
# Changelog
-## [0.69.0](https://github.com/o7studios/gate/compare/v0.68.2...v0.69.0) (2026-06-26)
+## [0.68.22](https://github.com/minekube/gate/compare/v0.68.21...v0.68.22) (2026-07-02)
-### Features
+### Bug Fixes
+
+* queue config plugin messages during backend login ([ccc6212](https://github.com/minekube/gate/commit/ccc62121c3bb1b084148e65341d8d69a3a34320c))
+
+## [0.68.21](https://github.com/minekube/gate/compare/v0.68.20...v0.68.21) (2026-07-02)
+
+
+### Bug Fixes
+
+* **deps:** update module go.minekube.com/gate to v0.68.20 ([#888](https://github.com/minekube/gate/issues/888)) ([e9a0ac5](https://github.com/minekube/gate/commit/e9a0ac50f36e85604432a81140f5c27ec5047f1d))
+
+## [0.68.20](https://github.com/minekube/gate/compare/v0.68.19...v0.68.20) (2026-07-01)
+
+
+### Bug Fixes
+
+* **deps:** update module github.com/pires/go-proxyproto to v0.13.0 ([#883](https://github.com/minekube/gate/issues/883)) ([bc88136](https://github.com/minekube/gate/commit/bc88136f27018b7d162cc9b869dd2d8a31235498))
+
+## [0.68.19](https://github.com/minekube/gate/compare/v0.68.18...v0.68.19) (2026-07-01)
+
+
+### Bug Fixes
+
+* **java:** ignore untracked modern resource pack responses ([a653b71](https://github.com/minekube/gate/commit/a653b7124298b0b7c36f06efd5c3e1d7224938b0))
+* **java:** ignore untracked modern resource pack responses ([95cb756](https://github.com/minekube/gate/commit/95cb75688e051be9b090c354c64c2a094bd08d5a))
+
+## [0.68.18](https://github.com/minekube/gate/compare/v0.68.17...v0.68.18) (2026-07-01)
+
+
+### Bug Fixes
+
+* **deps:** update module go.minekube.com/gate to v0.68.17 ([#881](https://github.com/minekube/gate/issues/881)) ([47b4ec8](https://github.com/minekube/gate/commit/47b4ec823ab6cbbc16ed94cb718d647d537942dc))
+
+## [0.68.17](https://github.com/minekube/gate/compare/v0.68.16...v0.68.17) (2026-06-30)
+
+
+### Bug Fixes
+
+* **deps:** update module golang.org/x/text to v0.38.0 ([#879](https://github.com/minekube/gate/issues/879)) ([089e4be](https://github.com/minekube/gate/commit/089e4be75e9dd2d7c36281c29a73a222e2ca2e0f))
+
+## [0.68.16](https://github.com/minekube/gate/compare/v0.68.15...v0.68.16) (2026-06-30)
+
+
+### Bug Fixes
+
+* **deps:** update module go.minekube.com/gate to v0.68.15 ([#877](https://github.com/minekube/gate/issues/877)) ([12d85a4](https://github.com/minekube/gate/commit/12d85a41837076cc5353e77353a128be9fd23370))
+
+## [0.68.15](https://github.com/minekube/gate/compare/v0.68.14...v0.68.15) (2026-06-30)
+
+
+### Bug Fixes
+
+* **deps:** Update geyserlite to v0.3.17 ([#874](https://github.com/minekube/gate/issues/874)) ([1494394](https://github.com/minekube/gate/commit/14943941a7c4f26d823f41fb23e62877ce6b88f9))
+* **deps:** update module go.minekube.com/gate to v0.68.14 ([#871](https://github.com/minekube/gate/issues/871)) ([b2f3158](https://github.com/minekube/gate/commit/b2f31583c9c8fed5f9eb8cdd97767001f71de397))
+
+## [0.68.14](https://github.com/minekube/gate/compare/v0.68.13...v0.68.14) (2026-06-29)
+
+
+### Bug Fixes
+
+* skip ViaLite for matching dynamic backend protocol ([27db687](https://github.com/minekube/gate/commit/27db687c010383013ea106111a32340ae7a5e4ad))
+
+## [0.68.13](https://github.com/minekube/gate/compare/v0.68.12...v0.68.13) (2026-06-29)
+
+
+### Bug Fixes
+
+* **deps:** update module golang.org/x/sync to v0.21.0 ([#865](https://github.com/minekube/gate/issues/865)) ([273b542](https://github.com/minekube/gate/commit/273b542897d3a6c2d051dc60ce47479436739581))
+
+## [0.68.12](https://github.com/minekube/gate/compare/v0.68.11...v0.68.12) (2026-06-28)
+
+
+### Bug Fixes
+
+* **deps:** update module go.minekube.com/gate to v0.68.11 ([#863](https://github.com/minekube/gate/issues/863)) ([3d80eb0](https://github.com/minekube/gate/commit/3d80eb041626b15798412862e4636d9a2c6dfb2d))
+
+## [0.68.11](https://github.com/minekube/gate/compare/v0.68.10...v0.68.11) (2026-06-28)
-* Add BungeeGuard Compatible mode ([#390](https://github.com/o7studios/gate/issues/390)) ([f62d8c4](https://github.com/o7studios/gate/commit/f62d8c40918d9fb2e55637910df02b7f6b2e63dc))
-* add comprehensive CLI version support (fixes [#282](https://github.com/o7studios/gate/issues/282)) ([#561](https://github.com/o7studios/gate/issues/561)) ([34f103c](https://github.com/o7studios/gate/commit/34f103c45e2e1666d0745b421f5eecfef04aacda))
-* add config subcommand to generate default config files ([#608](https://github.com/o7studios/gate/issues/608)) ([4ace975](https://github.com/o7studios/gate/commit/4ace975ae30bbbedaa88c79bea7fd29556ead5c5))
-* Add DialogClear and DialogShow packets to packet tests ([2c7e2af](https://github.com/o7studios/gate/commit/2c7e2af97a442e4bb8482af88e724cc8445066bd))
-* Add EntityArgumentType for minecraft:entity commands (PR [#78](https://github.com/o7studios/gate/issues/78)) ([d7779f6](https://github.com/o7studios/gate/commit/d7779f6c02b00f68aa90c6075c76a1ee0cdf4950))
-* Add ForcedHosts configuration to config.yml and update documentation ([d98e8b3](https://github.com/o7studios/gate/commit/d98e8b3a7789218e143a6ffdce8d4d1ab86a13dd))
-* add Minecraft 26.1 (protocol 775) support ([#679](https://github.com/o7studios/gate/issues/679)) ([d12d659](https://github.com/o7studios/gate/commit/d12d659b43fca433adc02b96399024b7dfc89ad2))
-* add note about cached results ([5d26598](https://github.com/o7studios/gate/commit/5d26598073a3b9527a140a93cc4f18430954fb3b))
-* add option to disable auto config reload ([#607](https://github.com/o7studios/gate/issues/607)) ([fb7d2a8](https://github.com/o7studios/gate/commit/fb7d2a848e294cb0504dddf8ea1723b5072f9002)), closes [#602](https://github.com/o7studios/gate/issues/602)
-* add semantic version tags to Docker images ([#617](https://github.com/o7studios/gate/issues/617)) ([31c79d8](https://github.com/o7studios/gate/commit/31c79d80839d77a23709af90e1e134b54853349a)), closes [#616](https://github.com/o7studios/gate/issues/616)
-* Add server registration and unregistration events ([#593](https://github.com/o7studios/gate/issues/593)) ([0ec2ed1](https://github.com/o7studios/gate/commit/0ec2ed1fd60e297fb686efd5436e15f6e733fc4b))
-* add strategy support to lite mode ([#538](https://github.com/o7studios/gate/issues/538)) ([c312dd0](https://github.com/o7studios/gate/commit/c312dd00acb0e49884439c195dbde3eb08a83a1e))
-* Add support for changing the default logger ([#536](https://github.com/o7studios/gate/issues/536)) ([24014d8](https://github.com/o7studios/gate/commit/24014d8022d8362c577fb4dbc2ee0c6c8abe359b))
-* Add support for Minecraft 1.21.7 (Protocol 772) ([#546](https://github.com/o7studios/gate/issues/546)) ([074d3e9](https://github.com/o7studios/gate/commit/074d3e966d4b4b08fadfbbfe4095630f717396a9))
-* Add support for offline mode players in Connect configuration ([de6f865](https://github.com/o7studios/gate/commit/de6f865ffbfb6a1dc4960d08bfeb4c2417801a35))
-* **bedrock:** default managed mode to geyserlite ([c82a7de](https://github.com/o7studios/gate/commit/c82a7de629ecbe94e349e2a41c07921045f5968e))
-* **bedrock:** default managed mode to geyserlite ([205bb49](https://github.com/o7studios/gate/commit/205bb494b4bb6df7b4b05c520b2f34e7075ab6dd))
-* **connect:** add CONNECT_TOKEN env var ([72f0e70](https://github.com/o7studios/gate/commit/72f0e701d187b65d76d3afaf54125a86b30af59a))
-* Cookies API ([#535](https://github.com/o7studios/gate/issues/535)) ([2a8e179](https://github.com/o7studios/gate/commit/2a8e1796b5e62b2e1dacf5f09d1bb76a59c6a06f))
-* **docker:** add multi-target images and bump distroless base to Debian 12 ([#568](https://github.com/o7studios/gate/issues/568)) ([8d91027](https://github.com/o7studios/gate/commit/8d910278bcebcbf8a9b568e5d1cdf1f6f75b9162))
-* **docs:** add OpenAPI documentation link and update API definition formatting ([d3c6a57](https://github.com/o7studios/gate/commit/d3c6a57d9998b0dc73fc3251ec5f1f5ad4b14530))
-* **docs:** clarify Bedrock Edition support ([#588](https://github.com/o7studios/gate/issues/588)) ([7cd126b](https://github.com/o7studios/gate/commit/7cd126b5f28721a7b18f14fc04fb2228f25f371d))
-* **docs:** Use GitHub App over PAT and use octokit ([#599](https://github.com/o7studios/gate/issues/599)) ([959dc1b](https://github.com/o7studios/gate/commit/959dc1b3708bdca2e31bbdfd01c3c04df5d2e55f))
-* Enhance installation script for cross-platform support ([b91fdfd](https://github.com/o7studios/gate/commit/b91fdfd86732999c9c95ec98c084b03bbb0ca061))
-* Enhance LandingAfter component with tabbed configuration and Git clone examples ([e43bae3](https://github.com/o7studios/gate/commit/e43bae34dd8a1eea658ab967509b552f727f5e5b))
-* Extensions/Projects page on the Gate Website ([#424](https://github.com/o7studios/gate/issues/424)) ([81a1528](https://github.com/o7studios/gate/commit/81a1528d1823f4f21682ff6d5100713d338619b2))
-* Gate HTTP API ([#423](https://github.com/o7studios/gate/issues/423)) ([e960e6b](https://github.com/o7studios/gate/commit/e960e6b45bd6c6cee5e65351d88a99d7d47e9393))
-* harden login plugin-message and keep-alive handling ([#689](https://github.com/o7studios/gate/issues/689)) ([f818164](https://github.com/o7studios/gate/commit/f818164793cbc85c715f8f04718f10223d556db5))
-* implement proper ForcedHosts functionality (fixes [#226](https://github.com/o7studios/gate/issues/226)) ([#560](https://github.com/o7studios/gate/issues/560)) ([a07c4c4](https://github.com/o7studios/gate/commit/a07c4c4d0f2f9ff8fc71bba92b890bfee49dee7a))
-* Initial Bedrock Geyser Support ([#552](https://github.com/o7studios/gate/issues/552)) ([75ec7d3](https://github.com/o7studios/gate/commit/75ec7d3603671f53ca17c1ae2eba31fa770ad197))
-* **lite:** Add support for hostname parameter routing in backend addresses ([#603](https://github.com/o7studios/gate/issues/603)) ([11882b0](https://github.com/o7studios/gate/commit/11882b0b429fab24c5ac360db0df136ed612594f))
-* **Lite:** Allow configuring players in fallback status response [#281](https://github.com/o7studios/gate/issues/281) ([#477](https://github.com/o7studios/gate/issues/477)) ([2ae1f11](https://github.com/o7studios/gate/commit/2ae1f11e727047fcf31d45d33047352ff1bed55a))
-* make ServerConnection accessible in ServerLoginPluginMessageEvent ([#664](https://github.com/o7studios/gate/issues/664)) ([64bd57e](https://github.com/o7studios/gate/commit/64bd57e25b7fcbf6959504ffcc313e047aeaf843)), closes [#663](https://github.com/o7studios/gate/issues/663)
-* Minecraft 1.21.8 ([6faa101](https://github.com/o7studios/gate/commit/6faa101a11b6519f270c8bdecea9aecb822ecb5f))
-* Minecraft version 1.21.6 ([#543](https://github.com/o7studios/gate/issues/543)) ([4cfc98e](https://github.com/o7studios/gate/commit/4cfc98ebd11e8347c878eab43dfe938f619d8356))
-* Modern Forge (FML2/FML3) login relay for 1.13-1.20.1 ([#680](https://github.com/o7studios/gate/issues/680)) ([df65927](https://github.com/o7studios/gate/commit/df65927aa87ace5e0334130197a4dc75cfd0a09c))
-* per-connection serverbound packet rate limiter ([#691](https://github.com/o7studios/gate/issues/691)) ([c8ed9bb](https://github.com/o7studios/gate/commit/c8ed9bba63b9e89091e1d5b599e3544a59dc3218))
-* route dynamic servers through managed Via ([d22711d](https://github.com/o7studios/gate/commit/d22711dc53bb024bafa08b741f29454d332581c2))
-* Support Minecraft 1.21.5 ([7eee5e6](https://github.com/o7studios/gate/commit/7eee5e61bfc6b4c8aaadec28981274a6ce977ceb))
-* Support Minecraft Java 1.21.11 ([b3119ff](https://github.com/o7studios/gate/commit/b3119ffe31a5542dc351ba8de0a7f4c97dd04a3a))
-* Support Minecraft_1_21_4 ([0fa5ca2](https://github.com/o7studios/gate/commit/0fa5ca2a1c034da3231f489b237a5e82f78bfb47))
-* Support overriding forwarding secrets with environment variables ([#575](https://github.com/o7studios/gate/issues/575)) ([080575f](https://github.com/o7studios/gate/commit/080575f361a1c7a90f64f556e0c64df057b75077))
-* **ui:** improve search mode toggle visibility and naming ([6aea92c](https://github.com/o7studios/gate/commit/6aea92c36b363ae42827ad706eda117e77adfe31))
-* Update for Minecraft 1.21.9 and 1.21.10 ([#580](https://github.com/o7studios/gate/issues/580)) ([40a741e](https://github.com/o7studios/gate/commit/40a741e6b076b6fb4c64c87c8a9357541a439677))
-* use vialite auto latest subprocess runtime ([c174b31](https://github.com/o7studios/gate/commit/c174b3153769c33873b25a27f2e8695b977f3cb6))
-* **WIP:** add opentelemetry ([#439](https://github.com/o7studios/gate/issues/439)) ([18eda21](https://github.com/o7studios/gate/commit/18eda21c439aa0d96ae3dc115a229690070999fc))
-
-
-### Bug Fixes
-
-* add musl linux installer assets ([e22541c](https://github.com/o7studios/gate/commit/e22541cbf57fa9841eb5ddaf19a913abe6e92c26))
-* adopt modern Common text components ([4f2debc](https://github.com/o7studios/gate/commit/4f2debcde3c083df814c078b97a590e22edcd287))
-* **bedrock:** avoid forwarding mobile ping to backend keepalive ([#771](https://github.com/o7studios/gate/issues/771)) ([0b6c3ba](https://github.com/o7studios/gate/commit/0b6c3ba369db8b01adf1a092848972122c73713f))
-* **bedrock:** document engine-specific managed config ([7c21844](https://github.com/o7studios/gate/commit/7c218447a96dfb4f5104b382227a01293093b1d2))
-* **bedrock:** document engine-specific managed config ([4d6038d](https://github.com/o7studios/gate/commit/4d6038d3a3590b651e8f9f662de756edb770f0af))
-* **bedrock:** forward hostnames in managed java geyser ([a71a7d2](https://github.com/o7studios/gate/commit/a71a7d26c00cd86199ad11a89f634f9202149e5c))
-* **bedrock:** forward hostnames in managed Java Geyser ([392ce14](https://github.com/o7studios/gate/commit/392ce14d8c3b1582b0b7226544276c47a148c252))
-* **bedrock:** handle geyserlite ci platform gaps ([48c4857](https://github.com/o7studios/gate/commit/48c48570adf3a54fe36cce1689b362d99a936d19))
-* **bedrock:** trust linked Geyser accounts safely ([c307797](https://github.com/o7studios/gate/commit/c307797319aa578a78efaa12ff79aa0cc6d39919))
-* **bedrock:** use geyserlite windows build fix ([f266386](https://github.com/o7studios/gate/commit/f266386837184b433bf3ba9922bbd85f0ff0ac74))
-* **bedrock:** wait for managed geyserlite readiness ([cf0a4ef](https://github.com/o7studios/gate/commit/cf0a4efaaee747c45381748f3160fb31a875d785))
-* **bedrock:** wait for managed geyserlite readiness ([5dcbdf3](https://github.com/o7studios/gate/commit/5dcbdf388f73264f271f2d5f7a07b058d175bf11))
-* broken .gitignore ([#596](https://github.com/o7studios/gate/issues/596)) ([606126c](https://github.com/o7studios/gate/commit/606126cedc72eac84dd6cf34fd295dcf350baaa8))
-* cleanups and extra tests for SNBT/CESU-8 ([#665](https://github.com/o7studios/gate/issues/665)) ([#666](https://github.com/o7studios/gate/issues/666)) ([ca468b1](https://github.com/o7studios/gate/commit/ca468b1de2d62929cf6e7e185fdd274dfd6d81ec))
-* config path in k8s examples ([#511](https://github.com/o7studios/gate/issues/511)) ([2fe7c17](https://github.com/o7studios/gate/commit/2fe7c17fde81f1e19e0c216435e54bf97fc78fcd))
-* correct Play ClientBound plugin.Message packet ID for 1.21.9+ (fixes [#612](https://github.com/o7studios/gate/issues/612)) ([#674](https://github.com/o7studios/gate/issues/674)) ([f3e7f43](https://github.com/o7studios/gate/commit/f3e7f434818ab8f25ad5d05ab4b809fda7b37cbb))
-* correct PluginMessageEvent source/target in initial connect handler ([#693](https://github.com/o7studios/gate/issues/693)) ([a634425](https://github.com/o7studios/gate/commit/a6344253ce4c86d8cb5cd77c8689058c3517b4b4))
-* Correct ServerLinks packet decoding for 1.21.2+ ([074d3e9](https://github.com/o7studios/gate/commit/074d3e966d4b4b08fadfbbfe4095630f717396a9))
-* data race in loginInboundConn during Forge login relay ([#690](https://github.com/o7studios/gate/issues/690)) ([1b03ac8](https://github.com/o7studios/gate/commit/1b03ac8226529fb201eb942bfe3bacb22978058e))
-* **deps:** automate geyserlite updates ([e934efd](https://github.com/o7studios/gate/commit/e934efd644bca4ede35ab849f019f3e4b4f12e96))
-* **deps:** automate geyserlite updates ([6b2820b](https://github.com/o7studios/gate/commit/6b2820ba99c8b2ece26e9d65c8fbde5931ea376e))
-* **deps:** bump geyserlite to v0.3.4 ([b574809](https://github.com/o7studios/gate/commit/b574809008c25776703fe63327259a625ec198ed))
-* **deps:** resolve merge conflicts and update dependencies in go.mod and go.sum ([ac075d2](https://github.com/o7studios/gate/commit/ac075d2d3f0a8bbdfd017dd3efa11487ead647b8))
-* **deps:** update dependency @bufbuild/buf to v1.48.0 ([#470](https://github.com/o7studios/gate/issues/470)) ([86819cd](https://github.com/o7studios/gate/commit/86819cd4d114105d5888a97620dd617d1bea98e7))
-* **deps:** update dependency @bufbuild/buf to v1.49.0 ([#481](https://github.com/o7studios/gate/issues/481)) ([b18c29d](https://github.com/o7studios/gate/commit/b18c29d7bd060c353c1f1e1f1f6bce9105717038))
-* **deps:** update dependency @bufbuild/buf to v1.50.0 ([#496](https://github.com/o7studios/gate/issues/496)) ([915a94d](https://github.com/o7studios/gate/commit/915a94d0c545fd4ae19c12042134cc696136e880))
-* **deps:** update dependency @bufbuild/protobuf to v1.10.1 ([#516](https://github.com/o7studios/gate/issues/516)) ([1f1058c](https://github.com/o7studios/gate/commit/1f1058c4ac72d39354c38cec24823faa5e224769))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.68.2.1.20241118150055.50fffb007499 ([#446](https://github.com/o7studios/gate/issues/446)) ([037ca6c](https://github.com/o7studios/gate/commit/037ca6cf64d3d8f33a2c1a6b1d813732b77b7125))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.69.0.1.20241118150055.50fffb007499 ([#463](https://github.com/o7studios/gate/issues/463)) ([c66ed21](https://github.com/o7studios/gate/commit/c66ed215ea85c43be26853e853981e72bb25ad03))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.69.1.1.20241118150055.50fffb007499 ([#495](https://github.com/o7studios/gate/issues/495)) ([1e48064](https://github.com/o7studios/gate/commit/1e48064526155c0676d29b974a64389434791a53))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.70.0.1.20241118150055.50fffb007499 ([#501](https://github.com/o7studios/gate/issues/501)) ([c5f087e](https://github.com/o7studios/gate/commit/c5f087ec690e035c1bab74514aa1f6583f52d7c4))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.72.0.1.20241118150055.50fffb007499 ([#520](https://github.com/o7studios/gate/issues/520)) ([99e53a4](https://github.com/o7studios/gate/commit/99e53a45d1057d2bcc0e9d027279ab42c48f52f5))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.78.0.1.20241118150055.50fffb007499 ([#641](https://github.com/o7studios/gate/issues/641)) ([c4b3250](https://github.com/o7studios/gate/commit/c4b3250f9da279a984285cef73bde85da46af60b))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.81.0.1.20241118150055.50fffb007499 ([#736](https://github.com/o7studios/gate/issues/736)) ([3f260e5](https://github.com/o7studios/gate/commit/3f260e51a557b1e4fdb5369cdf163ca5c46db592))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.82.0.1.20241118150055.50fffb007499 ([#752](https://github.com/o7studios/gate/issues/752)) ([f79e95b](https://github.com/o7studios/gate/commit/f79e95b8d6aa5c871f1950e37eabd93d3af99404))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.82.1.1.20241118150055.50fffb007499 ([#832](https://github.com/o7studios/gate/issues/832)) ([48a2c54](https://github.com/o7studios/gate/commit/48a2c5434adee9c8bfef94d12eaf992d57827e62))
-* **deps:** update dependency build.buf.gen:minekube_gate_protocolbuffers_java to v29 ([#447](https://github.com/o7studios/gate/issues/447)) ([2b5a7aa](https://github.com/o7studios/gate/commit/2b5a7aa1d007b3a719f808d58ca368b481fb904a))
-* **deps:** update dependency build.buf.gen:minekube_gate_protocolbuffers_java to v29.1.0.1.20241118150055.50fffb007499 ([#458](https://github.com/o7studios/gate/issues/458)) ([2f553e8](https://github.com/o7studios/gate/commit/2f553e82c650998c68dd64678d6caa89ef7d1449))
-* **deps:** update dependency build.buf.gen:minekube_gate_protocolbuffers_java to v29.2.0.1.20241118150055.50fffb007499 ([#471](https://github.com/o7studios/gate/issues/471)) ([448931a](https://github.com/o7studios/gate/commit/448931a8c3544b8ea09d916c591826f7ae90c122))
-* **deps:** update dependency build.buf.gen:minekube_gate_protocolbuffers_java to v29.3.0.1.20241118150055.50fffb007499 ([#486](https://github.com/o7studios/gate/issues/486)) ([e0624bc](https://github.com/o7studios/gate/commit/e0624bc03a9254a9a79d6c33c605abfd757307aa))
-* **deps:** update dependency build.buf.gen:minekube_gate_protocolbuffers_java to v29.5.0.1.20241118150055.50fffb007499 ([#643](https://github.com/o7studios/gate/issues/643)) ([cf779b3](https://github.com/o7studios/gate/commit/cf779b3be9676b461d8525551cf5c6682dbb44eb))
-* **deps:** update dependency build.buf.gen:minekube_gate_protocolbuffers_java to v29.5.0.2.20241118150055.50fffb007499 ([#727](https://github.com/o7studios/gate/issues/727)) ([e85b87c](https://github.com/o7studios/gate/commit/e85b87c244b12a48550f06db43b813c56fa2d4fb))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.0 ([#442](https://github.com/o7studios/gate/issues/442)) ([4ad1615](https://github.com/o7studios/gate/commit/4ad161573261d8e7b015aa761f5307a94c4fbf4b))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.0 ([#443](https://github.com/o7studios/gate/issues/443)) ([b792f23](https://github.com/o7studios/gate/commit/b792f2309fb0b8470c1ad559275d502bd640426c))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.1 ([#454](https://github.com/o7studios/gate/issues/454)) ([0d2d930](https://github.com/o7studios/gate/commit/0d2d9309a69b0874747d3bbf39eb229c31c42a3f))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.1 ([#455](https://github.com/o7studios/gate/issues/455)) ([c984582](https://github.com/o7studios/gate/commit/c984582c2291642da7547b9c2241d0ebcc882188))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.2 ([#467](https://github.com/o7studios/gate/issues/467)) ([684aec7](https://github.com/o7studios/gate/commit/684aec7e78e9ef2f5de2b3e47e9ab8608f6ed7ce))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.2 ([#468](https://github.com/o7studios/gate/issues/468)) ([9d5d26c](https://github.com/o7studios/gate/commit/9d5d26c49f1fd15229d9fabc448437f72e96a2a4))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.3 ([#483](https://github.com/o7studios/gate/issues/483)) ([68ec072](https://github.com/o7studios/gate/commit/68ec072a8c32b866d436a886a298a06309a47934))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.3 ([#484](https://github.com/o7studios/gate/issues/484)) ([88e7616](https://github.com/o7studios/gate/commit/88e7616943f44f3778a04e5210d17a8e64cd6da6))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.30.2 ([#521](https://github.com/o7studios/gate/issues/521)) ([202a586](https://github.com/o7studios/gate/commit/202a58680e9352f7f571700903e0ee6a0768a390))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.33.4 ([#645](https://github.com/o7studios/gate/issues/645)) ([0fe4786](https://github.com/o7studios/gate/commit/0fe47867ac87758c51e066dd059b212a31d7eeec))
-* **deps:** update dependency io.grpc:grpc-kotlin-stub to v1.4.3 ([#518](https://github.com/o7studios/gate/issues/518)) ([de2b8b3](https://github.com/o7studios/gate/commit/de2b8b34caecc0df7d306330eb32af3a549a4ef8))
-* **deps:** update dependency io.grpc:grpc-kotlin-stub to v1.5.0 ([#646](https://github.com/o7studios/gate/issues/646)) ([64e974b](https://github.com/o7studios/gate/commit/64e974b3fc28d241f392dcc6b0603b45a1ddb95a))
-* **deps:** update dependency io.grpc:grpc-netty-shaded to v1.68.2 ([#444](https://github.com/o7studios/gate/issues/444)) ([3231462](https://github.com/o7studios/gate/commit/323146210735e686f28b7ef1c8f9150088a1f589))
-* **deps:** update dependency io.grpc:grpc-netty-shaded to v1.75.0 [security] ([#576](https://github.com/o7studios/gate/issues/576)) ([79f6984](https://github.com/o7studios/gate/commit/79f6984a910bce38a05329711fb496a0427efe06))
-* **deps:** update dependency org.jetbrains.kotlinx:kotlinx-coroutines-core to v1.10.1 ([#472](https://github.com/o7studios/gate/issues/472)) ([d4fc427](https://github.com/o7studios/gate/commit/d4fc4278c111c5c8f80e785f6adc4949a9e3722e))
-* **deps:** update dependency org.jetbrains.kotlinx:kotlinx-coroutines-core to v1.10.2 ([#512](https://github.com/o7studios/gate/issues/512)) ([24b5fcf](https://github.com/o7studios/gate/commit/24b5fcfe8f57ae162f006963d529e05f1ec58302))
-* **deps:** update dependency org.jetbrains.kotlinx:kotlinx-coroutines-core to v1.9.0 ([#431](https://github.com/o7studios/gate/issues/431)) ([62a9454](https://github.com/o7studios/gate/commit/62a94541a12efa4dbd4b5a9f9de6bef072e7ef0e))
-* **deps:** Update geyserlite ([#802](https://github.com/o7studios/gate/issues/802)) ([eebb580](https://github.com/o7studios/gate/commit/eebb580bf88c79a3fe65fe6551e9c00a879b8871))
-* **deps:** update geyserlite to v0.3.0 ([#722](https://github.com/o7studios/gate/issues/722)) ([69bfeb7](https://github.com/o7studios/gate/commit/69bfeb7bd3504231a547df13aebbd2f86ad040fe))
-* **deps:** Update geyserlite to v0.3.10 ([#791](https://github.com/o7studios/gate/issues/791)) ([53bbf8f](https://github.com/o7studios/gate/commit/53bbf8fb37d6a5b841cbbe0d8a7acc4303369dc4))
-* **deps:** Update geyserlite to v0.3.12 ([#798](https://github.com/o7studios/gate/issues/798)) ([f87a81e](https://github.com/o7studios/gate/commit/f87a81e9972862a09f3d700f9a60f96b7bc74c06))
-* **deps:** update geyserlite to v0.3.14 ([a3e7ed7](https://github.com/o7studios/gate/commit/a3e7ed723db9b0037690d33854aa602a21255f97))
-* **deps:** update geyserlite to v0.3.14 ([d854e39](https://github.com/o7studios/gate/commit/d854e39f4200a1d07c0b79da238c61daa1a512e8))
-* **deps:** Update geyserlite to v0.3.5 ([#749](https://github.com/o7studios/gate/issues/749)) ([e620e0b](https://github.com/o7studios/gate/commit/e620e0b8af0a58f788ef41c2016e3792d2fd2608))
-* **deps:** update github.com/pires/go-proxyproto digest to b718e7c ([#323](https://github.com/o7studios/gate/issues/323)) ([9992ad4](https://github.com/o7studios/gate/commit/9992ad4fc6bcd899ca27a8ee17376af80476cb04))
-* **deps:** update golang.org/x/exp digest to 701f63a ([#375](https://github.com/o7studios/gate/issues/375)) ([f73fd4b](https://github.com/o7studios/gate/commit/f73fd4beb155442a6691d3bb711671896ef1e5dc))
-* **deps:** update golang.org/x/exp digest to 716be56 ([#590](https://github.com/o7studios/gate/issues/590)) ([fbc4ad8](https://github.com/o7studios/gate/commit/fbc4ad89f777ede8f236901713ce33887f0225ba))
-* **deps:** update grpc-java monorepo to v1.68.2 ([#441](https://github.com/o7studios/gate/issues/441)) ([4d70d86](https://github.com/o7studios/gate/commit/4d70d862bdf756dce455f5593aa1f44bed97ead1))
-* **deps:** update grpc-java monorepo to v1.69.0 ([#461](https://github.com/o7studios/gate/issues/461)) ([527cf77](https://github.com/o7studios/gate/commit/527cf7766687525d1dc35acca8595b4c6745fb8d))
-* **deps:** update grpc-java monorepo to v1.69.1 ([#494](https://github.com/o7studios/gate/issues/494)) ([705ca60](https://github.com/o7studios/gate/commit/705ca6052f24380cb3eb900bcaf8a06156e6da88))
-* **deps:** update grpc-java monorepo to v1.70.0 ([#497](https://github.com/o7studios/gate/issues/497)) ([0ded7a5](https://github.com/o7studios/gate/commit/0ded7a532974a66f42f9e4d9bbd14dbd9a926596))
-* **deps:** update grpc-java monorepo to v1.72.0 ([#523](https://github.com/o7studios/gate/issues/523)) ([b900085](https://github.com/o7studios/gate/commit/b900085f0397839840873c5b05423f546e03399e))
-* **deps:** update grpc-java monorepo to v1.78.0 ([#649](https://github.com/o7studios/gate/issues/649)) ([1f05e43](https://github.com/o7studios/gate/commit/1f05e4315617f6fec4f08ab54acaa8db8e627eaf))
-* **deps:** update grpc-java monorepo to v1.81.0 ([#738](https://github.com/o7studios/gate/issues/738)) ([f122ad7](https://github.com/o7studios/gate/commit/f122ad75a93f01783e99395005ba48ad658cb4ed))
-* **deps:** update grpc-java monorepo to v1.82.0 ([#755](https://github.com/o7studios/gate/issues/755)) ([2feb606](https://github.com/o7studios/gate/commit/2feb60623c16ac7fc71046c7255544c66e83815e))
-* **deps:** update kotlinx-coroutines monorepo to v1.11.0 ([#759](https://github.com/o7studios/gate/issues/759)) ([6690cf1](https://github.com/o7studios/gate/commit/6690cf1ba8f6c0654c57ff5afced151c8b8e19c8))
-* **deps:** update module buf.build/gen/go/minekube/gate/connectrpc/go to v1.17.0-20241120101512-f1a10b5029ce.1 ([#429](https://github.com/o7studios/gate/issues/429)) ([6f458b3](https://github.com/o7studios/gate/commit/6f458b38e1a78cc9aa077304ea7a77c13f7bd89f))
-* **deps:** update module buf.build/gen/go/minekube/gate/connectrpc/go to v1.18.1-20241120101512-f1a10b5029ce.1 ([#482](https://github.com/o7studios/gate/issues/482)) ([4ef9df0](https://github.com/o7studios/gate/commit/4ef9df00e463bfc234e7a19d339c068c4ea72a0c))
-* **deps:** update module buf.build/gen/go/minekube/gate/connectrpc/go to v1.19.1-20250516132630-2a0c7768e191.2 ([#652](https://github.com/o7studios/gate/issues/652)) ([b48faa3](https://github.com/o7studios/gate/commit/b48faa36d41b5304bf8a4a020811d9938073cb40))
-* **deps:** update module buf.build/gen/go/minekube/gate/connectrpc/go to v1.20.0-20250516132630-2a0c7768e191.1 ([#761](https://github.com/o7studios/gate/issues/761)) ([0c6591e](https://github.com/o7studios/gate/commit/0c6591eae358c647fc0671c8cfd8e043a87d5087))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.35.2-20241120101512-f1a10b5029ce.1 ([#430](https://github.com/o7studios/gate/issues/430)) ([3bd983e](https://github.com/o7studios/gate/commit/3bd983e4a6dbd20ee501ddaa14102f4e62395e0c))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.36.0-20241120101512-f1a10b5029ce.1 ([#473](https://github.com/o7studios/gate/issues/473)) ([15555a5](https://github.com/o7studios/gate/commit/15555a5ff0e57a21f9bb7802aa7cc5e50314c97f))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.36.1-20241120101512-f1a10b5029ce.1 ([#476](https://github.com/o7studios/gate/issues/476)) ([87980af](https://github.com/o7studios/gate/commit/87980afcf7b9fe7a54b697a8d91dd0dc9856ceb7))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.36.11-20250516132630-2a0c7768e191.1 ([#623](https://github.com/o7studios/gate/issues/623)) ([7571bb4](https://github.com/o7studios/gate/commit/7571bb4401e157ead7a410b99bd568b30e35a403))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.36.2-20241120101512-f1a10b5029ce.1 ([#479](https://github.com/o7studios/gate/issues/479)) ([0e8f74d](https://github.com/o7studios/gate/commit/0e8f74da68c10bd021a2ac527cf6874d818eaff1))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.36.3-20241120101512-f1a10b5029ce.1 ([#490](https://github.com/o7studios/gate/issues/490)) ([cb7b7dc](https://github.com/o7studios/gate/commit/cb7b7dc284171293e37054df8dc4b473c052fa3f))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.36.4-20241120101512-f1a10b5029ce.1 ([#500](https://github.com/o7studios/gate/issues/500)) ([35970b4](https://github.com/o7studios/gate/commit/35970b4b6c479e10f404f4cfd4f1d4e12179d82c))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.36.6-20241120101512-f1a10b5029ce.1 ([#519](https://github.com/o7studios/gate/issues/519)) ([9c31fbf](https://github.com/o7studios/gate/commit/9c31fbf0bd96d72f727220178d763cf6cc13046e))
-* **deps:** update module connectrpc.com/connect to v1.18.1 ([#487](https://github.com/o7studios/gate/issues/487)) ([06e2274](https://github.com/o7studios/gate/commit/06e2274a3b51c7c86fd917ec491191d411d9dadf))
-* **deps:** update module connectrpc.com/connect to v1.20.0 ([#763](https://github.com/o7studios/gate/issues/763)) ([c6741c7](https://github.com/o7studios/gate/commit/c6741c74fb3a2b9dfe749812cf9fbc0c4a4187f3))
-* **deps:** update module connectrpc.com/otelconnect to v0.9.0 ([#653](https://github.com/o7studios/gate/issues/653)) ([fb8d252](https://github.com/o7studios/gate/commit/fb8d252a2b8133d4bfec6772a3634600fbb59866))
-* **deps:** update module github.com/coder/websocket to v1.8.15 ([#766](https://github.com/o7studios/gate/issues/766)) ([f321f8c](https://github.com/o7studios/gate/commit/f321f8ca7b7ce7d60f1be40476babf3bdf756c8a))
-* **deps:** update module github.com/gammazero/deque to v1.2.0 ([#654](https://github.com/o7studios/gate/issues/654)) ([5af988d](https://github.com/o7studios/gate/commit/5af988db88b574fc868a510a108767c251b84755))
-* **deps:** update module github.com/gammazero/deque to v1.2.1 ([#729](https://github.com/o7studios/gate/issues/729)) ([1520d56](https://github.com/o7studios/gate/commit/1520d5612ac390191e91eaa522b02e9b5ab9467b))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.5.0 ([5fdd7c1](https://github.com/o7studios/gate/commit/5fdd7c190e05cb1935c159b81e1638c50210b53e))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.6.0 ([#524](https://github.com/o7studios/gate/issues/524)) ([9de9723](https://github.com/o7studios/gate/commit/9de97233a8d821a8aa8928e85c36cdbb55b2030c))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.6.1 ([#528](https://github.com/o7studios/gate/issues/528)) ([c31c248](https://github.com/o7studios/gate/commit/c31c248f390a19cc24b02e530604eb300b9246bf))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.7.0 ([#655](https://github.com/o7studios/gate/issues/655)) ([5ebed38](https://github.com/o7studios/gate/commit/5ebed38aff8050d5be7643bd40755e02246b0e12))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.8.0 ([#768](https://github.com/o7studios/gate/issues/768)) ([694b83f](https://github.com/o7studios/gate/commit/694b83f8c2af0d14e0ac7b3f1b15e00c4e9faddf))
-* **deps:** update module github.com/gookit/color to v1.6.0 ([#656](https://github.com/o7studios/gate/issues/656)) ([94cf91d](https://github.com/o7studios/gate/commit/94cf91ddfe7c894bbadfa98496b715dfeeda9b4e))
-* **deps:** update module github.com/gookit/color to v1.6.1 ([#731](https://github.com/o7studios/gate/issues/731)) ([da4e57d](https://github.com/o7studios/gate/commit/da4e57d343c19cd804ff567214a5072b8d33006b))
-* **deps:** update module github.com/jellydator/ttlcache/v3 to v3.2.1 ([5cf2af8](https://github.com/o7studios/gate/commit/5cf2af817ac910bbce22ce139a61ac2b843b2eec))
-* **deps:** update module github.com/jellydator/ttlcache/v3 to v3.3.0 ([b38fb74](https://github.com/o7studios/gate/commit/b38fb741c8045dac1a1a5b79add4a95753918c7a))
-* **deps:** update module github.com/jellydator/ttlcache/v3 to v3.4.1 ([#804](https://github.com/o7studios/gate/issues/804)) ([3e3500e](https://github.com/o7studios/gate/commit/3e3500e9a46c113756d0d36881b193530c5c43a7))
-* **deps:** update module github.com/knadh/koanf/providers/file to v1.1.1 ([1689d66](https://github.com/o7studios/gate/commit/1689d661f23cfb046232fcaa105c9b35a901846f))
-* **deps:** update module github.com/knadh/koanf/providers/file to v1.1.2 ([8476477](https://github.com/o7studios/gate/commit/84764772827729d1459dcf9e3005fdb5c82317a8))
-* **deps:** update module github.com/knadh/koanf/providers/file to v1.2.1 ([#624](https://github.com/o7studios/gate/issues/624)) ([16eabe4](https://github.com/o7studios/gate/commit/16eabe44a7996d4d5b521f878524e96bb7c850f6))
-* **deps:** update module github.com/pires/go-proxyproto to v0.12.0 ([#770](https://github.com/o7studios/gate/issues/770)) ([695f1e2](https://github.com/o7studios/gate/commit/695f1e2ce45e51a6b6ac0c721bd17c9da1d7429a))
-* **deps:** update module github.com/pires/go-proxyproto to v0.8.0 ([3114d14](https://github.com/o7studios/gate/commit/3114d1484aea67b91da6fafce60f7db75177413b))
-* **deps:** update module github.com/pires/go-proxyproto to v0.9.1 ([#657](https://github.com/o7studios/gate/issues/657)) ([fad1080](https://github.com/o7studios/gate/commit/fad10801c6a45e87c30301822165bbb469eab370))
-* **deps:** update module github.com/robinbraemer/event to v0.1.1 ([#440](https://github.com/o7studios/gate/issues/440)) ([ad9659f](https://github.com/o7studios/gate/commit/ad9659fd892fa8d1e229297ff21ec0a1b21bae45))
-* **deps:** update module github.com/rs/xid to v1.6.0 ([ecbef7f](https://github.com/o7studios/gate/commit/ecbef7f8a0a259433fc7a152c1c94a228308c515))
-* **deps:** update module github.com/stretchr/testify to v1.10.0 ([#438](https://github.com/o7studios/gate/issues/438)) ([7811568](https://github.com/o7studios/gate/commit/7811568b75818ca4a10e81dd3cc4467564bafa05))
-* **deps:** update module github.com/urfave/cli/v2 to v2.27.5 ([fc11e84](https://github.com/o7studios/gate/commit/fc11e84fdf2ba6560813244daee32fb118439fb8))
-* **deps:** update module go.minekube.com/brigodier to v0.0.2 ([#625](https://github.com/o7studios/gate/issues/625)) ([3ff1b4b](https://github.com/o7studios/gate/commit/3ff1b4bfba156c90ca54467d0dcc4472a01add0f))
-* **deps:** update module go.minekube.com/common to v0.0.6 ([#460](https://github.com/o7studios/gate/issues/460)) ([bd7808e](https://github.com/o7studios/gate/commit/bd7808ef68afd192fb2bccb525a5f926e8714099))
-* **deps:** update module go.minekube.com/gate to v0.40.0 ([cfd00e8](https://github.com/o7studios/gate/commit/cfd00e892295994f28709f07b63380c705adea66))
-* **deps:** update module go.minekube.com/gate to v0.41.0 ([9e0c531](https://github.com/o7studios/gate/commit/9e0c53126dd89b911e00318d230f3f9466a05373))
-* **deps:** update module go.minekube.com/gate to v0.41.2 ([947e48b](https://github.com/o7studios/gate/commit/947e48b505a4f249c3cb024e7aaba231f4debac4))
-* **deps:** update module go.minekube.com/gate to v0.42.0 ([9a51e72](https://github.com/o7studios/gate/commit/9a51e7231917a3b4e4c47b95fdb44b683a0ee37d))
-* **deps:** update module go.minekube.com/gate to v0.42.1 ([82be2c2](https://github.com/o7studios/gate/commit/82be2c22b212e042e5068f8324927e3050263765))
-* **deps:** update module go.minekube.com/gate to v0.42.2 ([#426](https://github.com/o7studios/gate/issues/426)) ([ef6d83f](https://github.com/o7studios/gate/commit/ef6d83f4369e75e1ad39e0ad0fd86c59b7ea03e2))
-* **deps:** update module go.minekube.com/gate to v0.43.0 ([#432](https://github.com/o7studios/gate/issues/432)) ([ffedb83](https://github.com/o7studios/gate/commit/ffedb83025800079fd677586d0be2d60603b3458))
-* **deps:** update module go.minekube.com/gate to v0.46.0 ([#462](https://github.com/o7studios/gate/issues/462)) ([a5aa21c](https://github.com/o7studios/gate/commit/a5aa21c372d859eed65a06b0d2028255d0de779c))
-* **deps:** update module go.minekube.com/gate to v0.47.0 ([#488](https://github.com/o7studios/gate/issues/488)) ([d4ca812](https://github.com/o7studios/gate/commit/d4ca8128f2651519e9d0379f94ba9fdd4f9bd089))
-* **deps:** update module go.minekube.com/gate to v0.48.1 ([#525](https://github.com/o7studios/gate/issues/525)) ([35e4a38](https://github.com/o7studios/gate/commit/35e4a38f02d4e1d8bdce20b91952dc37c970a506))
-* **deps:** update module go.minekube.com/gate to v0.62.3 ([#658](https://github.com/o7studios/gate/issues/658)) ([657a719](https://github.com/o7studios/gate/commit/657a719274b8dbf00b81ae70f23729717f602f12))
-* **deps:** update module go.minekube.com/gate to v0.66.24 ([#776](https://github.com/o7studios/gate/issues/776)) ([d428e12](https://github.com/o7studios/gate/commit/d428e120235b3342e8c41a090a28ad5e5e0f892b))
-* **deps:** update module go.minekube.com/gate to v0.66.26 ([#782](https://github.com/o7studios/gate/issues/782)) ([c7745a3](https://github.com/o7studios/gate/commit/c7745a3630026fd87773ab281797dc7eb994cfb3))
-* **deps:** update module go.minekube.com/gate to v0.66.28 ([#788](https://github.com/o7studios/gate/issues/788)) ([fec6844](https://github.com/o7studios/gate/commit/fec6844e34b50e1e82df9e0d59554d2fe14fc9ac))
-* **deps:** update module go.minekube.com/gate to v0.66.30 ([#796](https://github.com/o7studios/gate/issues/796)) ([88f1673](https://github.com/o7studios/gate/commit/88f1673086827d37f3d84417aafff5a0aabae71d))
-* **deps:** update module go.minekube.com/gate to v0.66.32 ([#800](https://github.com/o7studios/gate/issues/800)) ([84d56d5](https://github.com/o7studios/gate/commit/84d56d52086ad48746988d0bc8bbb868811d301a))
-* **deps:** update module go.minekube.com/gate to v0.66.36 ([#806](https://github.com/o7studios/gate/issues/806)) ([6549dfe](https://github.com/o7studios/gate/commit/6549dfe607102a8906663ae1aab46b220a0e0c2e))
-* **deps:** update module go.minekube.com/gate to v0.66.38 ([#816](https://github.com/o7studios/gate/issues/816)) ([318d0ba](https://github.com/o7studios/gate/commit/318d0ba66dd7551c29d8a4f295748f74d7aa5830))
-* **deps:** update module go.minekube.com/gate to v0.66.39 ([#824](https://github.com/o7studios/gate/issues/824)) ([a842a3b](https://github.com/o7studios/gate/commit/a842a3b22566e331ff113dc279cd34ca1fc456b1))
-* **deps:** update module go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp to v0.64.0 ([#659](https://github.com/o7studios/gate/issues/659)) ([b005987](https://github.com/o7studios/gate/commit/b005987e75ef8da33c5b9f2ca7567a5c008339ea))
-* **deps:** update module go.opentelemetry.io/otel to v1.41.0 [security] ([#685](https://github.com/o7studios/gate/issues/685)) ([e5b12e6](https://github.com/o7studios/gate/commit/e5b12e689e7a025f660ec6059ce47bbc59d0bd95))
-* **deps:** update module go.uber.org/zap to v1.27.1 ([#626](https://github.com/o7studios/gate/issues/626)) ([9727a30](https://github.com/o7studios/gate/commit/9727a30ee717a145f82c8c3938081d9c5a7cb482))
-* **deps:** update module go.uber.org/zap to v1.28.0 ([#778](https://github.com/o7studios/gate/issues/778)) ([a85fe51](https://github.com/o7studios/gate/commit/a85fe518c77da8a4f3677c6e6f895e76bd61458c))
-* **deps:** update module golang.org/x/net to v0.32.0 ([#457](https://github.com/o7studios/gate/issues/457)) ([4485562](https://github.com/o7studios/gate/commit/4485562445c3525fe1dfd6168bc561831c6328df))
-* **deps:** update module golang.org/x/net to v0.33.0 [security] ([#466](https://github.com/o7studios/gate/issues/466)) ([0143cbb](https://github.com/o7studios/gate/commit/0143cbb76f2a1d7345949f41ae3c8fadc9d41bb6))
-* **deps:** update module golang.org/x/net to v0.34.0 ([#480](https://github.com/o7studios/gate/issues/480)) ([1f944bd](https://github.com/o7studios/gate/commit/1f944bd79ecd13a436fe1a3756c924b7a90cef6f))
-* **deps:** update module golang.org/x/net to v0.36.0 [security] ([#508](https://github.com/o7studios/gate/issues/508)) ([5fc43ae](https://github.com/o7studios/gate/commit/5fc43ae2be5dc29b63ce9ed8fb27b403f93bcc49))
-* **deps:** update module golang.org/x/net to v0.38.0 [security] ([#513](https://github.com/o7studios/gate/issues/513)) ([cf50511](https://github.com/o7studios/gate/commit/cf505118ba70cc423e004b13c91bb25e00d6fde7))
-* **deps:** update module golang.org/x/net to v0.39.0 ([#526](https://github.com/o7studios/gate/issues/526)) ([6c5b676](https://github.com/o7studios/gate/commit/6c5b6766bb5255ff325de8676fbfbc3faf25ac3a))
-* **deps:** update module golang.org/x/net to v0.49.0 ([#660](https://github.com/o7studios/gate/issues/660)) ([5a3e0f6](https://github.com/o7studios/gate/commit/5a3e0f6a7a34b8d4701c4070a7021e27b88facb8))
-* **deps:** update module golang.org/x/sync to v0.10.0 ([#451](https://github.com/o7studios/gate/issues/451)) ([862a977](https://github.com/o7studios/gate/commit/862a977a55dcef660c78fbb772efb89578aafe52))
-* **deps:** update module golang.org/x/sync to v0.9.0 ([#418](https://github.com/o7studios/gate/issues/418)) ([c94333d](https://github.com/o7studios/gate/commit/c94333dafeda3e18127d6b0d18fbaadff0d215c5))
-* **deps:** update module golang.org/x/text to v0.18.0 ([89bd837](https://github.com/o7studios/gate/commit/89bd837eb8abc0642aa36b22325a2aa1bcdcf0eb))
-* **deps:** update module golang.org/x/text to v0.19.0 ([011939f](https://github.com/o7studios/gate/commit/011939f8e994fc20ca212afb37e51bb643d2d055))
-* **deps:** update module golang.org/x/text to v0.20.0 ([#419](https://github.com/o7studios/gate/issues/419)) ([220582c](https://github.com/o7studios/gate/commit/220582c36bb7e660166ee497c7a9b2d734b561c7))
-* **deps:** update module golang.org/x/text to v0.21.0 ([#452](https://github.com/o7studios/gate/issues/452)) ([02e0acb](https://github.com/o7studios/gate/commit/02e0acba319d089ad6635a3d866e4dc4571947cf))
-* **deps:** update module golang.org/x/time to v0.11.0 ([#529](https://github.com/o7studios/gate/issues/529)) ([4fb1cee](https://github.com/o7studios/gate/commit/4fb1ceedf4f775966f4a79fb60c09b7ba377410f))
-* **deps:** update module golang.org/x/time to v0.7.0 ([2457473](https://github.com/o7studios/gate/commit/2457473590b885844989f8e1b9e60a37f17da304))
-* **deps:** update module golang.org/x/time to v0.8.0 ([#420](https://github.com/o7studios/gate/issues/420)) ([7b46c4c](https://github.com/o7studios/gate/commit/7b46c4c4dbdb7abfc3c478e65ccf00ecb153a4c3))
-* **deps:** update module golang.org/x/time to v0.9.0 ([#489](https://github.com/o7studios/gate/issues/489)) ([14f3f2a](https://github.com/o7studios/gate/commit/14f3f2a737e2dfe8258bf30a9c1cb6526142e040))
-* **deps:** update module google.golang.org/grpc to v1.66.0 ([bf9aa22](https://github.com/o7studios/gate/commit/bf9aa22f123b16deec0e28cc8b78b9e48c676221))
-* **deps:** update module google.golang.org/grpc to v1.66.2 ([9ecb33c](https://github.com/o7studios/gate/commit/9ecb33cf867678b6f80ff44db425bb766231aa5e))
-* **deps:** update module google.golang.org/grpc to v1.67.0 ([#389](https://github.com/o7studios/gate/issues/389)) ([7cc97ab](https://github.com/o7studios/gate/commit/7cc97ab2083d54e008ba0fbff71039e9bc96c0d1))
-* **deps:** update module google.golang.org/grpc to v1.67.1 ([ee304c9](https://github.com/o7studios/gate/commit/ee304c928a4dd776e0dbd389f54d7079f8e71499))
-* **deps:** update module google.golang.org/grpc to v1.68.0 ([#421](https://github.com/o7studios/gate/issues/421)) ([4916245](https://github.com/o7studios/gate/commit/491624518aa52800530210af01211f67acd84dc0))
-* **deps:** update module google.golang.org/grpc to v1.68.1 ([#453](https://github.com/o7studios/gate/issues/453)) ([062c5fe](https://github.com/o7studios/gate/commit/062c5fed8a56e7e7ffd92c18b75494e8aa89abf8))
-* **deps:** update module google.golang.org/grpc to v1.69.0 ([#464](https://github.com/o7studios/gate/issues/464)) ([be6795d](https://github.com/o7studios/gate/commit/be6795d8efa14d33021aa325e26e38fce802e82a))
-* **deps:** update module google.golang.org/grpc to v1.69.2 ([#469](https://github.com/o7studios/gate/issues/469)) ([6bec70d](https://github.com/o7studios/gate/commit/6bec70d476d2d8de4a39bc70c815491734515afb))
-* **deps:** update module google.golang.org/grpc to v1.69.4 ([#485](https://github.com/o7studios/gate/issues/485)) ([731be02](https://github.com/o7studios/gate/commit/731be020c46b51ff1fab681c7e2c51c89d8cb5dc))
-* **deps:** update module google.golang.org/grpc to v1.70.0 ([#498](https://github.com/o7studios/gate/issues/498)) ([ee995c8](https://github.com/o7studios/gate/commit/ee995c8f7c431c073b3bd5c171c3805cb4e0ad07))
-* **deps:** update module google.golang.org/grpc to v1.72.0 ([#530](https://github.com/o7studios/gate/issues/530)) ([cc649ab](https://github.com/o7studios/gate/commit/cc649abb4082a3cf12bd5f7d69b611f6ea867e26))
-* **deps:** update module google.golang.org/grpc to v1.78.0 ([#661](https://github.com/o7studios/gate/issues/661)) ([398f57e](https://github.com/o7studios/gate/commit/398f57e2e2fc9ee9b517c644b9cae9080a337450))
-* **deps:** update module google.golang.org/grpc to v1.79.3 [security] ([#678](https://github.com/o7studios/gate/issues/678)) ([2217f5f](https://github.com/o7studios/gate/commit/2217f5f357edba3b8901d100c704dc46e4bcc14b))
-* **deps:** update module google.golang.org/protobuf to v1.36.0 ([#474](https://github.com/o7studios/gate/issues/474)) ([a3e2d72](https://github.com/o7studios/gate/commit/a3e2d723e8dbbdd2b1b9ff4c4db7189f53024111))
-* **deps:** update module google.golang.org/protobuf to v1.36.1 ([#475](https://github.com/o7studios/gate/issues/475)) ([014683e](https://github.com/o7studios/gate/commit/014683e819e9d1ff0f76560643a9256eab68d71e))
-* **deps:** update module google.golang.org/protobuf to v1.36.11 ([#627](https://github.com/o7studios/gate/issues/627)) ([7bf90b4](https://github.com/o7studios/gate/commit/7bf90b4fcfd874b5f1627f3c41d6d15211b20a50))
-* **deps:** update module google.golang.org/protobuf to v1.36.2 ([#478](https://github.com/o7studios/gate/issues/478)) ([b607131](https://github.com/o7studios/gate/commit/b6071319aa53a1417c0570154ba83040332dd940))
-* **deps:** update module google.golang.org/protobuf to v1.36.3 ([#491](https://github.com/o7studios/gate/issues/491)) ([27bdf09](https://github.com/o7studios/gate/commit/27bdf096532bafc4450c4df07fe2af73490e8553))
-* **deps:** update module google.golang.org/protobuf to v1.36.4 ([#499](https://github.com/o7studios/gate/issues/499)) ([83369c6](https://github.com/o7studios/gate/commit/83369c6a6fcbe13def581a100ad91f52befeeb7d))
-* **docker:** support managed geyserlite on arm64 ([#717](https://github.com/o7studios/gate/issues/717)) ([beda893](https://github.com/o7studios/gate/commit/beda893a11a3d158939201746c5686de13100138))
-* **docker:** use glibc base images so dynamically linked gate binary execs ([#712](https://github.com/o7studios/gate/issues/712)) ([9d503c3](https://github.com/o7studios/gate/commit/9d503c348a724711835a1fcd78e8434b77024d23))
-* **docs:** include ([03ecca5](https://github.com/o7studios/gate/commit/03ecca5eb78d361503fed26e26eb48b9ccc8e793))
-* **docs:** links ([10fc08e](https://github.com/o7studios/gate/commit/10fc08e044010defd8da378f752d4cb7dd85fd95))
-* **docs:** use correct comment syntax for VitePress colored diffs in YAML blocks ([#572](https://github.com/o7studios/gate/issues/572)) ([23bdc97](https://github.com/o7studios/gate/commit/23bdc97304a3628bc68758be1e9c7ce22bbe963a))
-* Double slash commands (closes [#414](https://github.com/o7studios/gate/issues/414)) ([a6ae8b3](https://github.com/o7studios/gate/commit/a6ae8b34605e79e8be8d8c2d1020bbdbc19732ae))
-* handle bare IPv6 addresses in proxy protocol header (fixes [#670](https://github.com/o7studios/gate/issues/670)) ([#673](https://github.com/o7studios/gate/issues/673)) ([3db7f7b](https://github.com/o7studios/gate/commit/3db7f7ba5433b18006cb6c0fed38445d1f369fa8))
-* ignore ErrDecoderLeftBytes in status response decoding ([#559](https://github.com/o7studios/gate/issues/559)) ([8ee714f](https://github.com/o7studios/gate/commit/8ee714f12eff1e3d400c99ac2c93b47e20023289))
-* increase byte array length limit for 1.7.x clients in WriteBytes17 ([#558](https://github.com/o7studios/gate/issues/558)) ([0dc2f12](https://github.com/o7studios/gate/commit/0dc2f12d0b40c113091f43f87136ebf765ee2517)), closes [#533](https://github.com/o7studios/gate/issues/533)
-* **java/config:** validate forcedHosts against servers ([#569](https://github.com/o7studios/gate/issues/569)) ([98cfd60](https://github.com/o7studios/gate/commit/98cfd6040ce587fc77b603c53c10280e3ea0343e))
-* **java:** allow nil tab list header footer ([#710](https://github.com/o7studios/gate/issues/710)) ([10c0f64](https://github.com/o7studios/gate/commit/10c0f64af2efbb56298009db868ab6573eb17d48))
-* **java:** normalize NBT component style booleans ([486e4a8](https://github.com/o7studios/gate/commit/486e4a802e26168d832e0c27e1bbd48070eb54e1))
-* **java:** set packet state for registry-created packets ([6cd71ba](https://github.com/o7studios/gate/commit/6cd71baa76eb21a9dddc93a64dd06e37760d4939))
-* **java:** set packet state for registry-created packets ([0a9433b](https://github.com/o7studios/gate/commit/0a9433b0b12c08a0bb7e526b15c0bca7aa73ad75))
-* light mode text hover ([84544ea](https://github.com/o7studios/gate/commit/84544ea7be54cc1995bf628c05a5bea2798b1804))
-* limit docker platforms to supported linux arches ([1400ee3](https://github.com/o7studios/gate/commit/1400ee355eb485ae2dec699997f56418d7dafa48))
-* **lite:** fix glob cache key mutation, use QuoteMeta, and share single regex cache ([#675](https://github.com/o7studios/gate/issues/675)) ([c6c670b](https://github.com/o7studios/gate/commit/c6c670b89d6f9febe19b897e8a8c20c8be6fc7c2))
-* **network:** fix AvailableCommands packet for mods ([#534](https://github.com/o7studios/gate/issues/534)) ([7f683a6](https://github.com/o7studios/gate/commit/7f683a6a2292363a0db7a16969eb789be72ea0b3))
-* nil pointer dereference in session chat LastSeenMessages handling ([1f78da9](https://github.com/o7studios/gate/commit/1f78da990abd94a14d83c866b1e9ab46d8dd7485))
-* player gets kicked when using suggestions in commands ([#584](https://github.com/o7studios/gate/issues/584)) ([884161a](https://github.com/o7studios/gate/commit/884161a8cb68c6102b30b62575396c0dfd68c5ef))
-* prevent map sharing between config reloads causing server persistence ([#557](https://github.com/o7studios/gate/issues/557)) ([ad12bd9](https://github.com/o7studios/gate/commit/ad12bd9f6e6efa9db41409b049cbcb4ef35ca1e5))
-* PreviousServer is always nil ([#541](https://github.com/o7studios/gate/issues/541)) ([322916a](https://github.com/o7studios/gate/commit/322916ac75568ef020048dfc085a12aa6214dd42))
-* **proxy:** forward backend register/unregister packets to client ([#672](https://github.com/o7studios/gate/issues/672)) ([1c5d6c8](https://github.com/o7studios/gate/commit/1c5d6c8ddc61235f70244de84be9cb4cbaf4eae6))
-* register 0x4C ID for Respawn packet in 1.21.2+ ([#416](https://github.com/o7studios/gate/issues/416)) ([f07cdc8](https://github.com/o7studios/gate/commit/f07cdc8714754e92a747ac61990299b436627779))
-* Removed `Modded Servers Config` from sidebar in favor of `Modded Servers` ([#573](https://github.com/o7studios/gate/issues/573)) ([6b84a42](https://github.com/o7studios/gate/commit/6b84a428cbf2284106cdc1bc089359d376959b37))
-* resolve architecture mismatch for multi-arch docker builds ([fd083f6](https://github.com/o7studios/gate/commit/fd083f6f3f5ed4af63db7246cfaa5acaf337119a))
-* resolve architecture mismatch for multi-arch docker builds ([a0f7da7](https://github.com/o7studios/gate/commit/a0f7da718477b71efe29ba1bfa062bb6d5986c75))
-* resolve lite mode backend issues and add sequential strategy default ([#565](https://github.com/o7studios/gate/issues/565)) ([798cb65](https://github.com/o7studios/gate/commit/798cb659677769b698b76be738cad1db74eeae35))
-* resolve nil pointer dereference warnings in forward_test.go ([#606](https://github.com/o7studios/gate/issues/606)) ([d1f198b](https://github.com/o7studios/gate/commit/d1f198b25625f15d63e6c1c0e5e3ef562730cc11))
-* retain queued backend keepalive replies ([#807](https://github.com/o7studios/gate/issues/807)) ([03af8de](https://github.com/o7studios/gate/commit/03af8dea7ef15c10baeec465354af0162f95b4ab))
-* Return context on ErrDecoderLeftBytes ([#579](https://github.com/o7studios/gate/issues/579)) ([01d87bd](https://github.com/o7studios/gate/commit/01d87bdfc9953cb6d8b88bc3c7cafa37de89c436))
-* SoundEntityPacket panic and protocol desync ([#605](https://github.com/o7studios/gate/issues/605)) ([4592ec4](https://github.com/o7studios/gate/commit/4592ec40184679df0e25bf69db5b41803a3aaa15))
-* strip leading slash from legacy commands to prevent double slash forwarding ([#556](https://github.com/o7studios/gate/issues/556)) ([5d55592](https://github.com/o7studios/gate/commit/5d55592a3d148f42e3f1c7d941d978c1c67be937))
-* **ui:** improve search mode toggle visibility ([6fc2b28](https://github.com/o7studios/gate/commit/6fc2b28e44697bc804b0edc4099aea81616c7318))
-* update community stats in documentation ([6eb3e56](https://github.com/o7studios/gate/commit/6eb3e5633dd4bbd49366a375f710018d2a8822f8))
-* Update member counts in LandingAfter component ([f158f91](https://github.com/o7studios/gate/commit/f158f91ce11a663d430cc32da933bc5e9b9df390))
-* **web:** fix bedrock quick link ([#571](https://github.com/o7studios/gate/issues/571)) ([6b2129e](https://github.com/o7studios/gate/commit/6b2129e672a85698a16e312587ab1c1a47c9af1f))
-* wrap SetReader with fullReader to fix large packet read issues ([#615](https://github.com/o7studios/gate/issues/615)) ([4b5d548](https://github.com/o7studios/gate/commit/4b5d54834f5ae19cae8068186694b0bc322fcbcf))
+
+### Bug Fixes
+
+* **deps:** update module go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp to v0.69.0 ([#861](https://github.com/minekube/gate/issues/861)) ([8033c48](https://github.com/minekube/gate/commit/8033c4898a2150dc03f1a02035f6dda9e0e7118b))
+
+## [0.68.10](https://github.com/minekube/gate/compare/v0.68.9...v0.68.10) (2026-06-28)
+
+
+### Bug Fixes
+
+* **deps:** update module go.minekube.com/gate to v0.68.9 ([#856](https://github.com/minekube/gate/issues/856)) ([dc6f1aa](https://github.com/minekube/gate/commit/dc6f1aa473fbde53fed562e6bdbfcbac4493b5f6))
+
+## [0.68.9](https://github.com/minekube/gate/compare/v0.68.8...v0.68.9) (2026-06-28)
+
+
+### Bug Fixes
+
+* **deps:** update module github.com/go-faker/faker/v4 to v4.9.0 ([#853](https://github.com/minekube/gate/issues/853)) ([9859b14](https://github.com/minekube/gate/commit/9859b140eb9f0aca6ac28813cedfb14039ceac48))
+
+## [0.68.8](https://github.com/minekube/gate/compare/v0.68.7...v0.68.8) (2026-06-28)
+
+
+### Bug Fixes
+
+* **deps:** update geyserlite to v0.3.16 ([#850](https://github.com/minekube/gate/issues/850)) ([5803dcf](https://github.com/minekube/gate/commit/5803dcfa2c433f7bec1d8c8e167783f313ce5050))
+
+## [0.68.7](https://github.com/minekube/gate/compare/v0.68.6...v0.68.7) (2026-06-28)
+
+
+### Bug Fixes
+
+* **deps:** update module go.minekube.com/common to v0.4.0 ([#848](https://github.com/minekube/gate/issues/848)) ([87d0c2b](https://github.com/minekube/gate/commit/87d0c2b5a2335709c868dff8f95b8df67aa9f576))
+
+## [0.68.6](https://github.com/minekube/gate/compare/v0.68.5...v0.68.6) (2026-06-27)
+
+
+### Bug Fixes
+
+* **deps:** Update geyserlite to v0.3.15 ([#813](https://github.com/minekube/gate/issues/813)) ([36fc507](https://github.com/minekube/gate/commit/36fc507c40aad62ae921c85e9ebbff32f5669a0c))
+
+## [0.68.5](https://github.com/minekube/gate/compare/v0.68.4...v0.68.5) (2026-06-26)
+
+
+### Bug Fixes
+
+* **deps:** update dependency com.google.protobuf:protobuf-java to v4.35.1 ([#842](https://github.com/minekube/gate/issues/842)) ([a236e18](https://github.com/minekube/gate/commit/a236e18e69e6144717c93b9bf1eca82a10c62ec0))
+
+## [0.68.4](https://github.com/minekube/gate/compare/v0.68.3...v0.68.4) (2026-06-26)
+
+
+### Bug Fixes
+
+* **deps:** update vialite to v0.3.0 ([#843](https://github.com/minekube/gate/issues/843)) ([40e7e00](https://github.com/minekube/gate/commit/40e7e0044fca39a6b66a4aca791846d2bcb94efc))
+
+## [0.68.3](https://github.com/minekube/gate/compare/v0.68.2...v0.68.3) (2026-06-26)
+
+
+### Bug Fixes
+
+* **deps:** update grpc-java monorepo to v1.82.1 ([#836](https://github.com/minekube/gate/issues/836)) ([f987505](https://github.com/minekube/gate/commit/f987505c4e0bb77e72ca349f38c71631cc9fdecb))
## [0.68.2](https://github.com/minekube/gate/compare/v0.68.1...v0.68.2) (2026-06-26)
@@ -490,75 +361,6 @@
## [0.66.13](https://github.com/minekube/gate/compare/v0.66.12...v0.66.13) (2026-06-10)
-### Bug Fixes
-
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.81.0.1.20241118150055.50fffb007499 ([#736](https://github.com/o7studios/gate/issues/736)) ([3f260e5](https://github.com/o7studios/gate/commit/3f260e51a557b1e4fdb5369cdf163ca5c46db592))
-* **deps:** update dependency build.buf.gen:minekube_gate_protocolbuffers_java to v29.5.0.2.20241118150055.50fffb007499 ([#727](https://github.com/o7studios/gate/issues/727)) ([e85b87c](https://github.com/o7studios/gate/commit/e85b87c244b12a48550f06db43b813c56fa2d4fb))
-* **deps:** update geyserlite to v0.3.0 ([#722](https://github.com/o7studios/gate/issues/722)) ([69bfeb7](https://github.com/o7studios/gate/commit/69bfeb7bd3504231a547df13aebbd2f86ad040fe))
-* **deps:** update grpc-java monorepo to v1.81.0 ([#738](https://github.com/o7studios/gate/issues/738)) ([f122ad7](https://github.com/o7studios/gate/commit/f122ad75a93f01783e99395005ba48ad658cb4ed))
-* **deps:** update module github.com/gammazero/deque to v1.2.1 ([#729](https://github.com/o7studios/gate/issues/729)) ([1520d56](https://github.com/o7studios/gate/commit/1520d5612ac390191e91eaa522b02e9b5ab9467b))
-* **deps:** update module github.com/gookit/color to v1.6.1 ([#731](https://github.com/o7studios/gate/issues/731)) ([da4e57d](https://github.com/o7studios/gate/commit/da4e57d343c19cd804ff567214a5072b8d33006b))
-* **docker:** support managed geyserlite on arm64 ([#717](https://github.com/o7studios/gate/issues/717)) ([beda893](https://github.com/o7studios/gate/commit/beda893a11a3d158939201746c5686de13100138))
-
-## [0.67.0](https://github.com/o7studios/gate/compare/v0.66.6...v0.67.0) (2026-06-06)
-
-
-### Features
-
-* Add BungeeGuard Compatible mode ([#390](https://github.com/o7studios/gate/issues/390)) ([f62d8c4](https://github.com/o7studios/gate/commit/f62d8c40918d9fb2e55637910df02b7f6b2e63dc))
-* add comprehensive CLI version support (fixes [#282](https://github.com/o7studios/gate/issues/282)) ([#561](https://github.com/o7studios/gate/issues/561)) ([34f103c](https://github.com/o7studios/gate/commit/34f103c45e2e1666d0745b421f5eecfef04aacda))
-* add config subcommand to generate default config files ([#608](https://github.com/o7studios/gate/issues/608)) ([4ace975](https://github.com/o7studios/gate/commit/4ace975ae30bbbedaa88c79bea7fd29556ead5c5))
-* Add DialogClear and DialogShow packets to packet tests ([2c7e2af](https://github.com/o7studios/gate/commit/2c7e2af97a442e4bb8482af88e724cc8445066bd))
-* Add EntityArgumentType for minecraft:entity commands (PR [#78](https://github.com/o7studios/gate/issues/78)) ([d7779f6](https://github.com/o7studios/gate/commit/d7779f6c02b00f68aa90c6075c76a1ee0cdf4950))
-* Add ForcedHosts configuration to config.yml and update documentation ([d98e8b3](https://github.com/o7studios/gate/commit/d98e8b3a7789218e143a6ffdce8d4d1ab86a13dd))
-* add KickPlayerRaw handler for bungeecord plugin channel ([1d21188](https://github.com/o7studios/gate/commit/1d21188d85ee523c0d73216f19bac35ff990b789))
-* add Minecraft 26.1 (protocol 775) support ([#679](https://github.com/o7studios/gate/issues/679)) ([d12d659](https://github.com/o7studios/gate/commit/d12d659b43fca433adc02b96399024b7dfc89ad2))
-* add note about cached results ([5d26598](https://github.com/o7studios/gate/commit/5d26598073a3b9527a140a93cc4f18430954fb3b))
-* add option to disable auto config reload ([#607](https://github.com/o7studios/gate/issues/607)) ([fb7d2a8](https://github.com/o7studios/gate/commit/fb7d2a848e294cb0504dddf8ea1723b5072f9002)), closes [#602](https://github.com/o7studios/gate/issues/602)
-* add semantic version tags to Docker images ([#617](https://github.com/o7studios/gate/issues/617)) ([31c79d8](https://github.com/o7studios/gate/commit/31c79d80839d77a23709af90e1e134b54853349a)), closes [#616](https://github.com/o7studios/gate/issues/616)
-* Add server registration and unregistration events ([#593](https://github.com/o7studios/gate/issues/593)) ([0ec2ed1](https://github.com/o7studios/gate/commit/0ec2ed1fd60e297fb686efd5436e15f6e733fc4b))
-* add strategy support to lite mode ([#538](https://github.com/o7studios/gate/issues/538)) ([c312dd0](https://github.com/o7studios/gate/commit/c312dd00acb0e49884439c195dbde3eb08a83a1e))
-* Add support for changing the default logger ([#536](https://github.com/o7studios/gate/issues/536)) ([24014d8](https://github.com/o7studios/gate/commit/24014d8022d8362c577fb4dbc2ee0c6c8abe359b))
-* Add support for Minecraft 1.21.7 (Protocol 772) ([#546](https://github.com/o7studios/gate/issues/546)) ([074d3e9](https://github.com/o7studios/gate/commit/074d3e966d4b4b08fadfbbfe4095630f717396a9))
-* Add support for offline mode players in Connect configuration ([de6f865](https://github.com/o7studios/gate/commit/de6f865ffbfb6a1dc4960d08bfeb4c2417801a35))
-* Allow setting custom mojang authentication server ([#264](https://github.com/o7studios/gate/issues/264)) ([91e3d7e](https://github.com/o7studios/gate/commit/91e3d7e6d42e8900044b4ca7857edbdc7625c3ba))
-* Auto config reload on file update ([#235](https://github.com/o7studios/gate/issues/235)) ([5af2c7d](https://github.com/o7studios/gate/commit/5af2c7de109d69cb18ca27e3e64da69de79bc27b))
-* **bedrock:** default managed mode to geyserlite ([c82a7de](https://github.com/o7studios/gate/commit/c82a7de629ecbe94e349e2a41c07921045f5968e))
-* **bedrock:** default managed mode to geyserlite ([205bb49](https://github.com/o7studios/gate/commit/205bb494b4bb6df7b4b05c520b2f34e7075ab6dd))
-* **connect:** add CONNECT_TOKEN env var ([72f0e70](https://github.com/o7studios/gate/commit/72f0e701d187b65d76d3afaf54125a86b30af59a))
-* Cookies API ([#535](https://github.com/o7studios/gate/issues/535)) ([2a8e179](https://github.com/o7studios/gate/commit/2a8e1796b5e62b2e1dacf5f09d1bb76a59c6a06f))
-* disconnect on too many empty packets ([dd0f15d](https://github.com/o7studios/gate/commit/dd0f15d3be3c438e3ff4167014b05776cc02ee3f))
-* **docker:** add multi-target images and bump distroless base to Debian 12 ([#568](https://github.com/o7studios/gate/issues/568)) ([8d91027](https://github.com/o7studios/gate/commit/8d910278bcebcbf8a9b568e5d1cdf1f6f75b9162))
-* **docs:** add OpenAPI documentation link and update API definition formatting ([d3c6a57](https://github.com/o7studios/gate/commit/d3c6a57d9998b0dc73fc3251ec5f1f5ad4b14530))
-* **docs:** clarify Bedrock Edition support ([#588](https://github.com/o7studios/gate/issues/588)) ([7cd126b](https://github.com/o7studios/gate/commit/7cd126b5f28721a7b18f14fc04fb2228f25f371d))
-* **docs:** Use GitHub App over PAT and use octokit ([#599](https://github.com/o7studios/gate/issues/599)) ([959dc1b](https://github.com/o7studios/gate/commit/959dc1b3708bdca2e31bbdfd01c3c04df5d2e55f))
-* Enhance installation script for cross-platform support ([b91fdfd](https://github.com/o7studios/gate/commit/b91fdfd86732999c9c95ec98c084b03bbb0ca061))
-* Enhance LandingAfter component with tabbed configuration and Git clone examples ([e43bae3](https://github.com/o7studios/gate/commit/e43bae34dd8a1eea658ab967509b552f727f5e5b))
-* Extensions/Projects page on the Gate Website ([#424](https://github.com/o7studios/gate/issues/424)) ([81a1528](https://github.com/o7studios/gate/commit/81a1528d1823f4f21682ff6d5100713d338619b2))
-* Gate HTTP API ([#423](https://github.com/o7studios/gate/issues/423)) ([e960e6b](https://github.com/o7studios/gate/commit/e960e6b45bd6c6cee5e65351d88a99d7d47e9393))
-* Gate Lite: Add fallback status for offline route ([#217](https://github.com/o7studios/gate/issues/217)) ([2632061](https://github.com/o7studios/gate/commit/2632061335d8f51cea120eedcb0dce31c61d63de))
-* harden login plugin-message and keep-alive handling ([#689](https://github.com/o7studios/gate/issues/689)) ([f818164](https://github.com/o7studios/gate/commit/f818164793cbc85c715f8f04718f10223d556db5))
-* implement proper ForcedHosts functionality (fixes [#226](https://github.com/o7studios/gate/issues/226)) ([#560](https://github.com/o7studios/gate/issues/560)) ([a07c4c4](https://github.com/o7studios/gate/commit/a07c4c4d0f2f9ff8fc71bba92b890bfee49dee7a))
-* Initial Bedrock Geyser Support ([#552](https://github.com/o7studios/gate/issues/552)) ([75ec7d3](https://github.com/o7studios/gate/commit/75ec7d3603671f53ca17c1ae2eba31fa770ad197))
-* **Lite:** Add modifyVirtualHost route option (closes [#180](https://github.com/o7studios/gate/issues/180)) ([429c59a](https://github.com/o7studios/gate/commit/429c59a81ad9c755aa1afb2ba392c12782907536))
-* **lite:** Add support for hostname parameter routing in backend addresses ([#603](https://github.com/o7studios/gate/issues/603)) ([11882b0](https://github.com/o7studios/gate/commit/11882b0b429fab24c5ac360db0df136ed612594f))
-* **Lite:** Allow configuring players in fallback status response [#281](https://github.com/o7studios/gate/issues/281) ([#477](https://github.com/o7studios/gate/issues/477)) ([2ae1f11](https://github.com/o7studios/gate/commit/2ae1f11e727047fcf31d45d33047352ff1bed55a))
-* make ServerConnection accessible in ServerLoginPluginMessageEvent ([#664](https://github.com/o7studios/gate/issues/664)) ([64bd57e](https://github.com/o7studios/gate/commit/64bd57e25b7fcbf6959504ffcc313e047aeaf843)), closes [#663](https://github.com/o7studios/gate/issues/663)
-* Minecraft 1.20.2-4 support ([#258](https://github.com/o7studios/gate/issues/258)) ([d6f4446](https://github.com/o7studios/gate/commit/d6f444697638796cf0c5c986974f9396d4dfc876))
-* Minecraft 1.21.8 ([6faa101](https://github.com/o7studios/gate/commit/6faa101a11b6519f270c8bdecea9aecb822ecb5f))
-* Minecraft version 1.21.6 ([#543](https://github.com/o7studios/gate/issues/543)) ([4cfc98e](https://github.com/o7studios/gate/commit/4cfc98ebd11e8347c878eab43dfe938f619d8356))
-* Modern Forge (FML2/FML3) login relay for 1.13-1.20.1 ([#680](https://github.com/o7studios/gate/issues/680)) ([df65927](https://github.com/o7studios/gate/commit/df65927aa87ace5e0334130197a4dc75cfd0a09c))
-* per-connection serverbound packet rate limiter ([#691](https://github.com/o7studios/gate/issues/691)) ([c8ed9bb](https://github.com/o7studios/gate/commit/c8ed9bba63b9e89091e1d5b599e3544a59dc3218))
-* Support Minecraft 1.21.5 ([7eee5e6](https://github.com/o7studios/gate/commit/7eee5e61bfc6b4c8aaadec28981274a6ce977ceb))
-* Support Minecraft Java 1.21.11 ([b3119ff](https://github.com/o7studios/gate/commit/b3119ffe31a5542dc351ba8de0a7f4c97dd04a3a))
-* Support Minecraft_1_21_4 ([0fa5ca2](https://github.com/o7studios/gate/commit/0fa5ca2a1c034da3231f489b237a5e82f78bfb47))
-* Support overriding forwarding secrets with environment variables ([#575](https://github.com/o7studios/gate/issues/575)) ([080575f](https://github.com/o7studios/gate/commit/080575f361a1c7a90f64f556e0c64df057b75077))
-* **ui:** improve search mode toggle visibility and naming ([6aea92c](https://github.com/o7studios/gate/commit/6aea92c36b363ae42827ad706eda117e77adfe31))
-* Update 1.21 protocol to include 1.21.1 ([c98a677](https://github.com/o7studios/gate/commit/c98a677436671e949bfdc082e81631dd6568e37d))
-* Update for Minecraft 1.21.9 and 1.21.10 ([#580](https://github.com/o7studios/gate/issues/580)) ([40a741e](https://github.com/o7studios/gate/commit/40a741e6b076b6fb4c64c87c8a9357541a439677))
-* **WIP:** add opentelemetry ([#439](https://github.com/o7studios/gate/issues/439)) ([18eda21](https://github.com/o7studios/gate/commit/18eda21c439aa0d96ae3dc115a229690070999fc))
-
-## [0.66.13](https://github.com/minekube/gate/compare/v0.66.12...v0.66.13) (2026-06-10)
### Bug Fixes
@@ -601,263 +403,9 @@
## [0.66.7](https://github.com/minekube/gate/compare/v0.66.6...v0.66.7) (2026-06-08)
+
### Bug Fixes
-* Add missing duration unit ([b8a2e67](https://github.com/o7studios/gate/commit/b8a2e67b901bd1e58c2026d90748107e01253796))
-* **bedrock:** document engine-specific managed config ([7c21844](https://github.com/o7studios/gate/commit/7c218447a96dfb4f5104b382227a01293093b1d2))
-* **bedrock:** document engine-specific managed config ([4d6038d](https://github.com/o7studios/gate/commit/4d6038d3a3590b651e8f9f662de756edb770f0af))
-* **bedrock:** forward hostnames in managed java geyser ([a71a7d2](https://github.com/o7studios/gate/commit/a71a7d26c00cd86199ad11a89f634f9202149e5c))
-* **bedrock:** forward hostnames in managed Java Geyser ([392ce14](https://github.com/o7studios/gate/commit/392ce14d8c3b1582b0b7226544276c47a148c252))
-* **bedrock:** handle geyserlite ci platform gaps ([48c4857](https://github.com/o7studios/gate/commit/48c48570adf3a54fe36cce1689b362d99a936d19))
-* **bedrock:** trust linked Geyser accounts safely ([c307797](https://github.com/o7studios/gate/commit/c307797319aa578a78efaa12ff79aa0cc6d39919))
-* **bedrock:** use geyserlite windows build fix ([f266386](https://github.com/o7studios/gate/commit/f266386837184b433bf3ba9922bbd85f0ff0ac74))
-* **bedrock:** wait for managed geyserlite readiness ([cf0a4ef](https://github.com/o7studios/gate/commit/cf0a4efaaee747c45381748f3160fb31a875d785))
-* **bedrock:** wait for managed geyserlite readiness ([5dcbdf3](https://github.com/o7studios/gate/commit/5dcbdf388f73264f271f2d5f7a07b058d175bf11))
-* broken .gitignore ([#596](https://github.com/o7studios/gate/issues/596)) ([606126c](https://github.com/o7studios/gate/commit/606126cedc72eac84dd6cf34fd295dcf350baaa8))
-* cleanups and extra tests for SNBT/CESU-8 ([#665](https://github.com/o7studios/gate/issues/665)) ([#666](https://github.com/o7studios/gate/issues/666)) ([ca468b1](https://github.com/o7studios/gate/commit/ca468b1de2d62929cf6e7e185fdd274dfd6d81ec))
-* config path in k8s examples ([#511](https://github.com/o7studios/gate/issues/511)) ([2fe7c17](https://github.com/o7studios/gate/commit/2fe7c17fde81f1e19e0c216435e54bf97fc78fcd))
-* **config:** Fix YAML config unmarshalling (fix [#232](https://github.com/o7studios/gate/issues/232)) ([add9dec](https://github.com/o7studios/gate/commit/add9dec514a800dd5ebdc41cd4db94f563946c31))
-* **connect:** Ensure Connect instance runs only once ([73d0ab8](https://github.com/o7studios/gate/commit/73d0ab8b70f22cab78e92b2712cb8fd4da944848))
-* connection timeout duration ([f2a0488](https://github.com/o7studios/gate/commit/f2a0488f170208251d9fc50bfa85c8879d139a32))
-* correct Play ClientBound plugin.Message packet ID for 1.21.9+ (fixes [#612](https://github.com/o7studios/gate/issues/612)) ([#674](https://github.com/o7studios/gate/issues/674)) ([f3e7f43](https://github.com/o7studios/gate/commit/f3e7f434818ab8f25ad5d05ab4b809fda7b37cbb))
-* correct PluginMessageEvent source/target in initial connect handler ([#693](https://github.com/o7studios/gate/issues/693)) ([a634425](https://github.com/o7studios/gate/commit/a6344253ce4c86d8cb5cd77c8689058c3517b4b4))
-* Correct ServerLinks packet decoding for 1.21.2+ ([074d3e9](https://github.com/o7studios/gate/commit/074d3e966d4b4b08fadfbbfe4095630f717396a9))
-* data race in loginInboundConn during Forge login relay ([#690](https://github.com/o7studios/gate/issues/690)) ([1b03ac8](https://github.com/o7studios/gate/commit/1b03ac8226529fb201eb942bfe3bacb22978058e))
-* **deps:** automate geyserlite updates ([e934efd](https://github.com/o7studios/gate/commit/e934efd644bca4ede35ab849f019f3e4b4f12e96))
-* **deps:** automate geyserlite updates ([6b2820b](https://github.com/o7studios/gate/commit/6b2820ba99c8b2ece26e9d65c8fbde5931ea376e))
-* **deps:** resolve merge conflicts and update dependencies in go.mod and go.sum ([ac075d2](https://github.com/o7studios/gate/commit/ac075d2d3f0a8bbdfd017dd3efa11487ead647b8))
-* **deps:** update dependency @bufbuild/buf to v1.48.0 ([#470](https://github.com/o7studios/gate/issues/470)) ([86819cd](https://github.com/o7studios/gate/commit/86819cd4d114105d5888a97620dd617d1bea98e7))
-* **deps:** update dependency @bufbuild/buf to v1.49.0 ([#481](https://github.com/o7studios/gate/issues/481)) ([b18c29d](https://github.com/o7studios/gate/commit/b18c29d7bd060c353c1f1e1f1f6bce9105717038))
-* **deps:** update dependency @bufbuild/buf to v1.50.0 ([#496](https://github.com/o7studios/gate/issues/496)) ([915a94d](https://github.com/o7studios/gate/commit/915a94d0c545fd4ae19c12042134cc696136e880))
-* **deps:** update dependency @bufbuild/protobuf to v1.10.1 ([#516](https://github.com/o7studios/gate/issues/516)) ([1f1058c](https://github.com/o7studios/gate/commit/1f1058c4ac72d39354c38cec24823faa5e224769))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.68.2.1.20241118150055.50fffb007499 ([#446](https://github.com/o7studios/gate/issues/446)) ([037ca6c](https://github.com/o7studios/gate/commit/037ca6cf64d3d8f33a2c1a6b1d813732b77b7125))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.69.0.1.20241118150055.50fffb007499 ([#463](https://github.com/o7studios/gate/issues/463)) ([c66ed21](https://github.com/o7studios/gate/commit/c66ed215ea85c43be26853e853981e72bb25ad03))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.69.1.1.20241118150055.50fffb007499 ([#495](https://github.com/o7studios/gate/issues/495)) ([1e48064](https://github.com/o7studios/gate/commit/1e48064526155c0676d29b974a64389434791a53))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.70.0.1.20241118150055.50fffb007499 ([#501](https://github.com/o7studios/gate/issues/501)) ([c5f087e](https://github.com/o7studios/gate/commit/c5f087ec690e035c1bab74514aa1f6583f52d7c4))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.72.0.1.20241118150055.50fffb007499 ([#520](https://github.com/o7studios/gate/issues/520)) ([99e53a4](https://github.com/o7studios/gate/commit/99e53a45d1057d2bcc0e9d027279ab42c48f52f5))
-* **deps:** update dependency build.buf.gen:minekube_gate_grpc_java to v1.78.0.1.20241118150055.50fffb007499 ([#641](https://github.com/o7studios/gate/issues/641)) ([c4b3250](https://github.com/o7studios/gate/commit/c4b3250f9da279a984285cef73bde85da46af60b))
-* **deps:** update dependency build.buf.gen:minekube_gate_protocolbuffers_java to v29 ([#447](https://github.com/o7studios/gate/issues/447)) ([2b5a7aa](https://github.com/o7studios/gate/commit/2b5a7aa1d007b3a719f808d58ca368b481fb904a))
-* **deps:** update dependency build.buf.gen:minekube_gate_protocolbuffers_java to v29.1.0.1.20241118150055.50fffb007499 ([#458](https://github.com/o7studios/gate/issues/458)) ([2f553e8](https://github.com/o7studios/gate/commit/2f553e82c650998c68dd64678d6caa89ef7d1449))
-* **deps:** update dependency build.buf.gen:minekube_gate_protocolbuffers_java to v29.2.0.1.20241118150055.50fffb007499 ([#471](https://github.com/o7studios/gate/issues/471)) ([448931a](https://github.com/o7studios/gate/commit/448931a8c3544b8ea09d916c591826f7ae90c122))
-* **deps:** update dependency build.buf.gen:minekube_gate_protocolbuffers_java to v29.3.0.1.20241118150055.50fffb007499 ([#486](https://github.com/o7studios/gate/issues/486)) ([e0624bc](https://github.com/o7studios/gate/commit/e0624bc03a9254a9a79d6c33c605abfd757307aa))
-* **deps:** update dependency build.buf.gen:minekube_gate_protocolbuffers_java to v29.5.0.1.20241118150055.50fffb007499 ([#643](https://github.com/o7studios/gate/issues/643)) ([cf779b3](https://github.com/o7studios/gate/commit/cf779b3be9676b461d8525551cf5c6682dbb44eb))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.0 ([#442](https://github.com/o7studios/gate/issues/442)) ([4ad1615](https://github.com/o7studios/gate/commit/4ad161573261d8e7b015aa761f5307a94c4fbf4b))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.0 ([#443](https://github.com/o7studios/gate/issues/443)) ([b792f23](https://github.com/o7studios/gate/commit/b792f2309fb0b8470c1ad559275d502bd640426c))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.1 ([#454](https://github.com/o7studios/gate/issues/454)) ([0d2d930](https://github.com/o7studios/gate/commit/0d2d9309a69b0874747d3bbf39eb229c31c42a3f))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.1 ([#455](https://github.com/o7studios/gate/issues/455)) ([c984582](https://github.com/o7studios/gate/commit/c984582c2291642da7547b9c2241d0ebcc882188))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.2 ([#467](https://github.com/o7studios/gate/issues/467)) ([684aec7](https://github.com/o7studios/gate/commit/684aec7e78e9ef2f5de2b3e47e9ab8608f6ed7ce))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.2 ([#468](https://github.com/o7studios/gate/issues/468)) ([9d5d26c](https://github.com/o7studios/gate/commit/9d5d26c49f1fd15229d9fabc448437f72e96a2a4))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.3 ([#483](https://github.com/o7studios/gate/issues/483)) ([68ec072](https://github.com/o7studios/gate/commit/68ec072a8c32b866d436a886a298a06309a47934))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.29.3 ([#484](https://github.com/o7studios/gate/issues/484)) ([88e7616](https://github.com/o7studios/gate/commit/88e7616943f44f3778a04e5210d17a8e64cd6da6))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.30.2 ([#521](https://github.com/o7studios/gate/issues/521)) ([202a586](https://github.com/o7studios/gate/commit/202a58680e9352f7f571700903e0ee6a0768a390))
-* **deps:** update dependency com.google.protobuf:protobuf-java to v4.33.4 ([#645](https://github.com/o7studios/gate/issues/645)) ([0fe4786](https://github.com/o7studios/gate/commit/0fe47867ac87758c51e066dd059b212a31d7eeec))
-* **deps:** update dependency io.grpc:grpc-kotlin-stub to v1.4.3 ([#518](https://github.com/o7studios/gate/issues/518)) ([de2b8b3](https://github.com/o7studios/gate/commit/de2b8b34caecc0df7d306330eb32af3a549a4ef8))
-* **deps:** update dependency io.grpc:grpc-kotlin-stub to v1.5.0 ([#646](https://github.com/o7studios/gate/issues/646)) ([64e974b](https://github.com/o7studios/gate/commit/64e974b3fc28d241f392dcc6b0603b45a1ddb95a))
-* **deps:** update dependency io.grpc:grpc-netty-shaded to v1.68.2 ([#444](https://github.com/o7studios/gate/issues/444)) ([3231462](https://github.com/o7studios/gate/commit/323146210735e686f28b7ef1c8f9150088a1f589))
-* **deps:** update dependency io.grpc:grpc-netty-shaded to v1.75.0 [security] ([#576](https://github.com/o7studios/gate/issues/576)) ([79f6984](https://github.com/o7studios/gate/commit/79f6984a910bce38a05329711fb496a0427efe06))
-* **deps:** update dependency org.jetbrains.kotlinx:kotlinx-coroutines-core to v1.10.1 ([#472](https://github.com/o7studios/gate/issues/472)) ([d4fc427](https://github.com/o7studios/gate/commit/d4fc4278c111c5c8f80e785f6adc4949a9e3722e))
-* **deps:** update dependency org.jetbrains.kotlinx:kotlinx-coroutines-core to v1.10.2 ([#512](https://github.com/o7studios/gate/issues/512)) ([24b5fcf](https://github.com/o7studios/gate/commit/24b5fcfe8f57ae162f006963d529e05f1ec58302))
-* **deps:** update dependency org.jetbrains.kotlinx:kotlinx-coroutines-core to v1.9.0 ([#431](https://github.com/o7studios/gate/issues/431)) ([62a9454](https://github.com/o7studios/gate/commit/62a94541a12efa4dbd4b5a9f9de6bef072e7ef0e))
-* **deps:** update github.com/pires/go-proxyproto digest to b718e7c ([#323](https://github.com/o7studios/gate/issues/323)) ([9992ad4](https://github.com/o7studios/gate/commit/9992ad4fc6bcd899ca27a8ee17376af80476cb04))
-* **deps:** update golang.org/x/exp digest to 701f63a ([#375](https://github.com/o7studios/gate/issues/375)) ([f73fd4b](https://github.com/o7studios/gate/commit/f73fd4beb155442a6691d3bb711671896ef1e5dc))
-* **deps:** update golang.org/x/exp digest to 716be56 ([#590](https://github.com/o7studios/gate/issues/590)) ([fbc4ad8](https://github.com/o7studios/gate/commit/fbc4ad89f777ede8f236901713ce33887f0225ba))
-* **deps:** update grpc-java monorepo to v1.68.2 ([#441](https://github.com/o7studios/gate/issues/441)) ([4d70d86](https://github.com/o7studios/gate/commit/4d70d862bdf756dce455f5593aa1f44bed97ead1))
-* **deps:** update grpc-java monorepo to v1.69.0 ([#461](https://github.com/o7studios/gate/issues/461)) ([527cf77](https://github.com/o7studios/gate/commit/527cf7766687525d1dc35acca8595b4c6745fb8d))
-* **deps:** update grpc-java monorepo to v1.69.1 ([#494](https://github.com/o7studios/gate/issues/494)) ([705ca60](https://github.com/o7studios/gate/commit/705ca6052f24380cb3eb900bcaf8a06156e6da88))
-* **deps:** update grpc-java monorepo to v1.70.0 ([#497](https://github.com/o7studios/gate/issues/497)) ([0ded7a5](https://github.com/o7studios/gate/commit/0ded7a532974a66f42f9e4d9bbd14dbd9a926596))
-* **deps:** update grpc-java monorepo to v1.72.0 ([#523](https://github.com/o7studios/gate/issues/523)) ([b900085](https://github.com/o7studios/gate/commit/b900085f0397839840873c5b05423f546e03399e))
-* **deps:** update grpc-java monorepo to v1.78.0 ([#649](https://github.com/o7studios/gate/issues/649)) ([1f05e43](https://github.com/o7studios/gate/commit/1f05e4315617f6fec4f08ab54acaa8db8e627eaf))
-* **deps:** update module buf.build/gen/go/minekube/gate/connectrpc/go to v1.17.0-20241120101512-f1a10b5029ce.1 ([#429](https://github.com/o7studios/gate/issues/429)) ([6f458b3](https://github.com/o7studios/gate/commit/6f458b38e1a78cc9aa077304ea7a77c13f7bd89f))
-* **deps:** update module buf.build/gen/go/minekube/gate/connectrpc/go to v1.18.1-20241120101512-f1a10b5029ce.1 ([#482](https://github.com/o7studios/gate/issues/482)) ([4ef9df0](https://github.com/o7studios/gate/commit/4ef9df00e463bfc234e7a19d339c068c4ea72a0c))
-* **deps:** update module buf.build/gen/go/minekube/gate/connectrpc/go to v1.19.1-20250516132630-2a0c7768e191.2 ([#652](https://github.com/o7studios/gate/issues/652)) ([b48faa3](https://github.com/o7studios/gate/commit/b48faa36d41b5304bf8a4a020811d9938073cb40))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.35.2-20241120101512-f1a10b5029ce.1 ([#430](https://github.com/o7studios/gate/issues/430)) ([3bd983e](https://github.com/o7studios/gate/commit/3bd983e4a6dbd20ee501ddaa14102f4e62395e0c))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.36.0-20241120101512-f1a10b5029ce.1 ([#473](https://github.com/o7studios/gate/issues/473)) ([15555a5](https://github.com/o7studios/gate/commit/15555a5ff0e57a21f9bb7802aa7cc5e50314c97f))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.36.1-20241120101512-f1a10b5029ce.1 ([#476](https://github.com/o7studios/gate/issues/476)) ([87980af](https://github.com/o7studios/gate/commit/87980afcf7b9fe7a54b697a8d91dd0dc9856ceb7))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.36.11-20250516132630-2a0c7768e191.1 ([#623](https://github.com/o7studios/gate/issues/623)) ([7571bb4](https://github.com/o7studios/gate/commit/7571bb4401e157ead7a410b99bd568b30e35a403))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.36.2-20241120101512-f1a10b5029ce.1 ([#479](https://github.com/o7studios/gate/issues/479)) ([0e8f74d](https://github.com/o7studios/gate/commit/0e8f74da68c10bd021a2ac527cf6874d818eaff1))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.36.3-20241120101512-f1a10b5029ce.1 ([#490](https://github.com/o7studios/gate/issues/490)) ([cb7b7dc](https://github.com/o7studios/gate/commit/cb7b7dc284171293e37054df8dc4b473c052fa3f))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.36.4-20241120101512-f1a10b5029ce.1 ([#500](https://github.com/o7studios/gate/issues/500)) ([35970b4](https://github.com/o7studios/gate/commit/35970b4b6c479e10f404f4cfd4f1d4e12179d82c))
-* **deps:** update module buf.build/gen/go/minekube/gate/protocolbuffers/go to v1.36.6-20241120101512-f1a10b5029ce.1 ([#519](https://github.com/o7studios/gate/issues/519)) ([9c31fbf](https://github.com/o7studios/gate/commit/9c31fbf0bd96d72f727220178d763cf6cc13046e))
-* **deps:** update module connectrpc.com/connect to v1.18.1 ([#487](https://github.com/o7studios/gate/issues/487)) ([06e2274](https://github.com/o7studios/gate/commit/06e2274a3b51c7c86fd917ec491191d411d9dadf))
-* **deps:** update module connectrpc.com/otelconnect to v0.9.0 ([#653](https://github.com/o7studios/gate/issues/653)) ([fb8d252](https://github.com/o7studios/gate/commit/fb8d252a2b8133d4bfec6772a3634600fbb59866))
-* **deps:** update module github.com/gammazero/deque to v1.2.0 ([#654](https://github.com/o7studios/gate/issues/654)) ([5af988d](https://github.com/o7studios/gate/commit/5af988db88b574fc868a510a108767c251b84755))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.1.1 ([#215](https://github.com/o7studios/gate/issues/215)) ([e887e09](https://github.com/o7studios/gate/commit/e887e097cf7dddbf140eca1b0166ca2676ac4bb7))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.2.1 ([0f049b3](https://github.com/o7studios/gate/commit/0f049b363ea3238543cd2226df133d3ba72b63c4))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.3.0 ([eff7c06](https://github.com/o7studios/gate/commit/eff7c06a017da70216faa2da5c5805232acf7f58))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.4.0 ([f945ce3](https://github.com/o7studios/gate/commit/f945ce3cdeab5ccc83ad8140fe7b62a5f9f6a8e5))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.4.1 ([3383a57](https://github.com/o7studios/gate/commit/3383a57c3f73b682218b244a4d25ca34a344e2f4))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.4.2 ([2c297e3](https://github.com/o7studios/gate/commit/2c297e3507d45cf30ca1c6a8dfc8339cf1914c2f))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.5.0 ([5fdd7c1](https://github.com/o7studios/gate/commit/5fdd7c190e05cb1935c159b81e1638c50210b53e))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.6.0 ([#524](https://github.com/o7studios/gate/issues/524)) ([9de9723](https://github.com/o7studios/gate/commit/9de97233a8d821a8aa8928e85c36cdbb55b2030c))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.6.1 ([#528](https://github.com/o7studios/gate/issues/528)) ([c31c248](https://github.com/o7studios/gate/commit/c31c248f390a19cc24b02e530604eb300b9246bf))
-* **deps:** update module github.com/go-faker/faker/v4 to v4.7.0 ([#655](https://github.com/o7studios/gate/issues/655)) ([5ebed38](https://github.com/o7studios/gate/commit/5ebed38aff8050d5be7643bd40755e02246b0e12))
-* **deps:** update module github.com/go-logr/logr to v1.4.2 ([63f9b66](https://github.com/o7studios/gate/commit/63f9b66ad951263d9395f1db14b7e1a63a91ca80))
-* **deps:** update module github.com/google/uuid to v1.6.0 ([3350975](https://github.com/o7studios/gate/commit/3350975ea6639c38cdf69705a5870e825047694f))
-* **deps:** update module github.com/gookit/color to v1.5.4 ([#184](https://github.com/o7studios/gate/issues/184)) ([b8a43d1](https://github.com/o7studios/gate/commit/b8a43d1282e47ad735cec10447e8ec1c2a33bedc))
-* **deps:** update module github.com/gookit/color to v1.6.0 ([#656](https://github.com/o7studios/gate/issues/656)) ([94cf91d](https://github.com/o7studios/gate/commit/94cf91ddfe7c894bbadfa98496b715dfeeda9b4e))
-* **deps:** update module github.com/jellydator/ttlcache/v3 to v3.2.0 ([73c9303](https://github.com/o7studios/gate/commit/73c93033f9fac6b1de4fb18aab0a9641bc416476))
-* **deps:** update module github.com/jellydator/ttlcache/v3 to v3.2.1 ([5cf2af8](https://github.com/o7studios/gate/commit/5cf2af817ac910bbce22ce139a61ac2b843b2eec))
-* **deps:** update module github.com/jellydator/ttlcache/v3 to v3.3.0 ([b38fb74](https://github.com/o7studios/gate/commit/b38fb741c8045dac1a1a5b79add4a95753918c7a))
-* **deps:** update module github.com/knadh/koanf/providers/file to v1.1.1 ([1689d66](https://github.com/o7studios/gate/commit/1689d661f23cfb046232fcaa105c9b35a901846f))
-* **deps:** update module github.com/knadh/koanf/providers/file to v1.1.2 ([8476477](https://github.com/o7studios/gate/commit/84764772827729d1459dcf9e3005fdb5c82317a8))
-* **deps:** update module github.com/knadh/koanf/providers/file to v1.2.1 ([#624](https://github.com/o7studios/gate/issues/624)) ([16eabe4](https://github.com/o7studios/gate/commit/16eabe44a7996d4d5b521f878524e96bb7c850f6))
-* **deps:** update module github.com/pires/go-proxyproto to v0.8.0 ([3114d14](https://github.com/o7studios/gate/commit/3114d1484aea67b91da6fafce60f7db75177413b))
-* **deps:** update module github.com/pires/go-proxyproto to v0.9.1 ([#657](https://github.com/o7studios/gate/issues/657)) ([fad1080](https://github.com/o7studios/gate/commit/fad10801c6a45e87c30301822165bbb469eab370))
-* **deps:** update module github.com/robinbraemer/event to v0.1.1 ([#440](https://github.com/o7studios/gate/issues/440)) ([ad9659f](https://github.com/o7studios/gate/commit/ad9659fd892fa8d1e229297ff21ec0a1b21bae45))
-* **deps:** update module github.com/rs/xid to v1.5.0 ([#201](https://github.com/o7studios/gate/issues/201)) ([6679247](https://github.com/o7studios/gate/commit/66792471c44a7a2c6bdfb35478ffc8c8447cf89f))
-* **deps:** update module github.com/rs/xid to v1.6.0 ([ecbef7f](https://github.com/o7studios/gate/commit/ecbef7f8a0a259433fc7a152c1c94a228308c515))
-* **deps:** update module github.com/sandertv/go-raknet to v1.13.0 ([23d050a](https://github.com/o7studios/gate/commit/23d050a5f2a3ec2ebafd458b86f0520d1a5fd6c7))
-* **deps:** update module github.com/sandertv/gophertunnel to v1.35.0 ([d49211d](https://github.com/o7studios/gate/commit/d49211d4e2de6f1e0f410a23cdc8d37f415532f5))
-* **deps:** update module github.com/sandertv/gophertunnel to v1.36.0 ([c09a5ef](https://github.com/o7studios/gate/commit/c09a5ef268ce7c151b75198c5c54c22c999da1a2))
-* **deps:** update module github.com/sandertv/gophertunnel to v1.36.1 ([8d9a362](https://github.com/o7studios/gate/commit/8d9a362d19a3f5acb98bbad88c67d1e531d8cb76))
-* **deps:** update module github.com/sandertv/gophertunnel to v1.37.0 ([b818384](https://github.com/o7studios/gate/commit/b8183844ad1891b7ae49b4cc199e76a3d59eacb9))
-* **deps:** update module github.com/spf13/viper to v1.19.0 ([69bdd16](https://github.com/o7studios/gate/commit/69bdd16042971b858489908cf61d6be67eaa6c60))
-* **deps:** update module github.com/stretchr/testify to v1.10.0 ([#438](https://github.com/o7studios/gate/issues/438)) ([7811568](https://github.com/o7studios/gate/commit/7811568b75818ca4a10e81dd3cc4467564bafa05))
-* **deps:** update module github.com/stretchr/testify to v1.9.0 ([f7c6a6b](https://github.com/o7studios/gate/commit/f7c6a6b4ae25d491b59367211d011fbe377f1d4e))
-* **deps:** update module github.com/tnze/go-mc to v1.20.2 ([0a6de01](https://github.com/o7studios/gate/commit/0a6de01b6dc036d258a5d30ce2a64745c3dfa16d))
-* **deps:** update module github.com/urfave/cli/v2 to v2.27.2 ([962df75](https://github.com/o7studios/gate/commit/962df75e974a49903e0bb5cd8364aef08b3e6d6e))
-* **deps:** update module github.com/urfave/cli/v2 to v2.27.3 ([6c7235e](https://github.com/o7studios/gate/commit/6c7235e8f49b62cbdaf82eeb76a7af37ce05abb1))
-* **deps:** update module github.com/urfave/cli/v2 to v2.27.4 ([a1aa419](https://github.com/o7studios/gate/commit/a1aa419f3ad29b86db7edd8970c714e1f3bc1fac))
-* **deps:** update module github.com/urfave/cli/v2 to v2.27.5 ([fc11e84](https://github.com/o7studios/gate/commit/fc11e84fdf2ba6560813244daee32fb118439fb8))
-* **deps:** update module go.minekube.com/brigodier to v0.0.2 ([#625](https://github.com/o7studios/gate/issues/625)) ([3ff1b4b](https://github.com/o7studios/gate/commit/3ff1b4bfba156c90ca54467d0dcc4472a01add0f))
-* **deps:** update module go.minekube.com/common to v0.0.6 ([#460](https://github.com/o7studios/gate/issues/460)) ([bd7808e](https://github.com/o7studios/gate/commit/bd7808ef68afd192fb2bccb525a5f926e8714099))
-* **deps:** update module go.minekube.com/gate to v0.29.0 ([#185](https://github.com/o7studios/gate/issues/185)) ([4de4f7b](https://github.com/o7studios/gate/commit/4de4f7b18af0671b28a3032ef04f79e1f175ab68))
-* **deps:** update module go.minekube.com/gate to v0.32.0 ([#214](https://github.com/o7studios/gate/issues/214)) ([04ba50b](https://github.com/o7studios/gate/commit/04ba50b4d791cf9739a185a72724de4c75b8451a))
-* **deps:** update module go.minekube.com/gate to v0.36.4 ([e897760](https://github.com/o7studios/gate/commit/e897760ff8bb30e46e387229e0b03fb62d1bea92))
-* **deps:** update module go.minekube.com/gate to v0.36.5 ([dee5106](https://github.com/o7studios/gate/commit/dee51064e1b7f76cdceb96a6462a79f9707a5a4e))
-* **deps:** update module go.minekube.com/gate to v0.36.7 ([7f9d349](https://github.com/o7studios/gate/commit/7f9d349bfc53ae1cbb1e39a34d0f236b45ce7a82))
-* **deps:** update module go.minekube.com/gate to v0.37.0 ([#343](https://github.com/o7studios/gate/issues/343)) ([014b18f](https://github.com/o7studios/gate/commit/014b18f18ec6bc7d67a21e4b6fd57684beb0c373))
-* **deps:** update module go.minekube.com/gate to v0.37.1 ([e97381a](https://github.com/o7studios/gate/commit/e97381a307313da2731abdce7cddfb6ac23a3302))
-* **deps:** update module go.minekube.com/gate to v0.38.0 ([da9f947](https://github.com/o7studios/gate/commit/da9f947d0a619c83b89c06a6fd7ed810d55d28d3))
-* **deps:** update module go.minekube.com/gate to v0.38.1 ([3ebcb74](https://github.com/o7studios/gate/commit/3ebcb744e540dba019e90c91c4e6961523d5027c))
-* **deps:** update module go.minekube.com/gate to v0.38.2 ([fc6f8c4](https://github.com/o7studios/gate/commit/fc6f8c4b43f1ab38797e2bfbd191b55cf97e4957))
-* **deps:** update module go.minekube.com/gate to v0.39.2 ([c101a4f](https://github.com/o7studios/gate/commit/c101a4f211b3b47c4e7afdfa379d97069bacec7e))
-* **deps:** update module go.minekube.com/gate to v0.39.3 ([e05d2ac](https://github.com/o7studios/gate/commit/e05d2ac489d10f6aa0341489ecf9441e2331b2bd))
-* **deps:** update module go.minekube.com/gate to v0.40.0 ([cfd00e8](https://github.com/o7studios/gate/commit/cfd00e892295994f28709f07b63380c705adea66))
-* **deps:** update module go.minekube.com/gate to v0.41.0 ([9e0c531](https://github.com/o7studios/gate/commit/9e0c53126dd89b911e00318d230f3f9466a05373))
-* **deps:** update module go.minekube.com/gate to v0.41.2 ([947e48b](https://github.com/o7studios/gate/commit/947e48b505a4f249c3cb024e7aaba231f4debac4))
-* **deps:** update module go.minekube.com/gate to v0.42.0 ([9a51e72](https://github.com/o7studios/gate/commit/9a51e7231917a3b4e4c47b95fdb44b683a0ee37d))
-* **deps:** update module go.minekube.com/gate to v0.42.1 ([82be2c2](https://github.com/o7studios/gate/commit/82be2c22b212e042e5068f8324927e3050263765))
-* **deps:** update module go.minekube.com/gate to v0.42.2 ([#426](https://github.com/o7studios/gate/issues/426)) ([ef6d83f](https://github.com/o7studios/gate/commit/ef6d83f4369e75e1ad39e0ad0fd86c59b7ea03e2))
-* **deps:** update module go.minekube.com/gate to v0.43.0 ([#432](https://github.com/o7studios/gate/issues/432)) ([ffedb83](https://github.com/o7studios/gate/commit/ffedb83025800079fd677586d0be2d60603b3458))
-* **deps:** update module go.minekube.com/gate to v0.46.0 ([#462](https://github.com/o7studios/gate/issues/462)) ([a5aa21c](https://github.com/o7studios/gate/commit/a5aa21c372d859eed65a06b0d2028255d0de779c))
-* **deps:** update module go.minekube.com/gate to v0.47.0 ([#488](https://github.com/o7studios/gate/issues/488)) ([d4ca812](https://github.com/o7studios/gate/commit/d4ca8128f2651519e9d0379f94ba9fdd4f9bd089))
-* **deps:** update module go.minekube.com/gate to v0.48.1 ([#525](https://github.com/o7studios/gate/issues/525)) ([35e4a38](https://github.com/o7studios/gate/commit/35e4a38f02d4e1d8bdce20b91952dc37c970a506))
-* **deps:** update module go.minekube.com/gate to v0.62.3 ([#658](https://github.com/o7studios/gate/issues/658)) ([657a719](https://github.com/o7studios/gate/commit/657a719274b8dbf00b81ae70f23729717f602f12))
-* **deps:** update module go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp to v0.64.0 ([#659](https://github.com/o7studios/gate/issues/659)) ([b005987](https://github.com/o7studios/gate/commit/b005987e75ef8da33c5b9f2ca7567a5c008339ea))
-* **deps:** update module go.opentelemetry.io/otel to v1.41.0 [security] ([#685](https://github.com/o7studios/gate/issues/685)) ([e5b12e6](https://github.com/o7studios/gate/commit/e5b12e689e7a025f660ec6059ce47bbc59d0bd95))
-* **deps:** update module go.uber.org/zap to v1.25.0 ([#227](https://github.com/o7studios/gate/issues/227)) ([2996af7](https://github.com/o7studios/gate/commit/2996af7a3d1cd7d37f621efcd4d81222aac55f35))
-* **deps:** update module go.uber.org/zap to v1.27.0 ([ee89f5b](https://github.com/o7studios/gate/commit/ee89f5ba4ab538743132ffdbe0443bce922e54c1))
-* **deps:** update module go.uber.org/zap to v1.27.1 ([#626](https://github.com/o7studios/gate/issues/626)) ([9727a30](https://github.com/o7studios/gate/commit/9727a30ee717a145f82c8c3938081d9c5a7cb482))
-* **deps:** update module golang.org/x/net to v0.32.0 ([#457](https://github.com/o7studios/gate/issues/457)) ([4485562](https://github.com/o7studios/gate/commit/4485562445c3525fe1dfd6168bc561831c6328df))
-* **deps:** update module golang.org/x/net to v0.33.0 [security] ([#466](https://github.com/o7studios/gate/issues/466)) ([0143cbb](https://github.com/o7studios/gate/commit/0143cbb76f2a1d7345949f41ae3c8fadc9d41bb6))
-* **deps:** update module golang.org/x/net to v0.34.0 ([#480](https://github.com/o7studios/gate/issues/480)) ([1f944bd](https://github.com/o7studios/gate/commit/1f944bd79ecd13a436fe1a3756c924b7a90cef6f))
-* **deps:** update module golang.org/x/net to v0.36.0 [security] ([#508](https://github.com/o7studios/gate/issues/508)) ([5fc43ae](https://github.com/o7studios/gate/commit/5fc43ae2be5dc29b63ce9ed8fb27b403f93bcc49))
-* **deps:** update module golang.org/x/net to v0.38.0 [security] ([#513](https://github.com/o7studios/gate/issues/513)) ([cf50511](https://github.com/o7studios/gate/commit/cf505118ba70cc423e004b13c91bb25e00d6fde7))
-* **deps:** update module golang.org/x/net to v0.39.0 ([#526](https://github.com/o7studios/gate/issues/526)) ([6c5b676](https://github.com/o7studios/gate/commit/6c5b6766bb5255ff325de8676fbfbc3faf25ac3a))
-* **deps:** update module golang.org/x/net to v0.49.0 ([#660](https://github.com/o7studios/gate/issues/660)) ([5a3e0f6](https://github.com/o7studios/gate/commit/5a3e0f6a7a34b8d4701c4070a7021e27b88facb8))
-* **deps:** update module golang.org/x/sync to v0.10.0 ([#451](https://github.com/o7studios/gate/issues/451)) ([862a977](https://github.com/o7studios/gate/commit/862a977a55dcef660c78fbb772efb89578aafe52))
-* **deps:** update module golang.org/x/sync to v0.7.0 ([a213cbd](https://github.com/o7studios/gate/commit/a213cbd32d2b49358c23f4e13df6d97b1dc058d3))
-* **deps:** update module golang.org/x/sync to v0.8.0 ([0e83a98](https://github.com/o7studios/gate/commit/0e83a98767f9e502ab7bc3011f4a123cda84e500))
-* **deps:** update module golang.org/x/sync to v0.9.0 ([#418](https://github.com/o7studios/gate/issues/418)) ([c94333d](https://github.com/o7studios/gate/commit/c94333dafeda3e18127d6b0d18fbaadff0d215c5))
-* **deps:** update module golang.org/x/text to v0.12.0 ([#228](https://github.com/o7studios/gate/issues/228)) ([c96c325](https://github.com/o7studios/gate/commit/c96c3252dfbfb7873152591e37f57ca015ddf727))
-* **deps:** update module golang.org/x/text to v0.15.0 ([59a0491](https://github.com/o7studios/gate/commit/59a049183bb4649bd4889724c5a70a3778445d06))
-* **deps:** update module golang.org/x/text to v0.16.0 ([d1a521a](https://github.com/o7studios/gate/commit/d1a521a4f1cef854ff48e2511cc5e822a2853cc4))
-* **deps:** update module golang.org/x/text to v0.18.0 ([89bd837](https://github.com/o7studios/gate/commit/89bd837eb8abc0642aa36b22325a2aa1bcdcf0eb))
-* **deps:** update module golang.org/x/text to v0.19.0 ([011939f](https://github.com/o7studios/gate/commit/011939f8e994fc20ca212afb37e51bb643d2d055))
-* **deps:** update module golang.org/x/text to v0.20.0 ([#419](https://github.com/o7studios/gate/issues/419)) ([220582c](https://github.com/o7studios/gate/commit/220582c36bb7e660166ee497c7a9b2d734b561c7))
-* **deps:** update module golang.org/x/text to v0.21.0 ([#452](https://github.com/o7studios/gate/issues/452)) ([02e0acb](https://github.com/o7studios/gate/commit/02e0acba319d089ad6635a3d866e4dc4571947cf))
-* **deps:** update module golang.org/x/time to v0.11.0 ([#529](https://github.com/o7studios/gate/issues/529)) ([4fb1cee](https://github.com/o7studios/gate/commit/4fb1ceedf4f775966f4a79fb60c09b7ba377410f))
-* **deps:** update module golang.org/x/time to v0.6.0 ([468513d](https://github.com/o7studios/gate/commit/468513d0bb8cb10bb61bf1417d532019b86b78a8))
-* **deps:** update module golang.org/x/time to v0.7.0 ([2457473](https://github.com/o7studios/gate/commit/2457473590b885844989f8e1b9e60a37f17da304))
-* **deps:** update module golang.org/x/time to v0.8.0 ([#420](https://github.com/o7studios/gate/issues/420)) ([7b46c4c](https://github.com/o7studios/gate/commit/7b46c4c4dbdb7abfc3c478e65ccf00ecb153a4c3))
-* **deps:** update module golang.org/x/time to v0.9.0 ([#489](https://github.com/o7studios/gate/issues/489)) ([14f3f2a](https://github.com/o7studios/gate/commit/14f3f2a737e2dfe8258bf30a9c1cb6526142e040))
-* **deps:** update module google.golang.org/grpc to v1.61.0 ([b201e6b](https://github.com/o7studios/gate/commit/b201e6bbd3cd69bf2913c08c1bf4d6a32a187799))
-* **deps:** update module google.golang.org/grpc to v1.61.1 ([34e370b](https://github.com/o7studios/gate/commit/34e370b4dfad167bd0db4718c4d761b155724a54))
-* **deps:** update module google.golang.org/grpc to v1.62.0 ([d36cc68](https://github.com/o7studios/gate/commit/d36cc68c83d1a2f96ebc6e11bcef1612f94515cc))
-* **deps:** update module google.golang.org/grpc to v1.62.1 ([ddd43cb](https://github.com/o7studios/gate/commit/ddd43cb43c49d5f3db204a40dce8a82cb2aaa08a))
-* **deps:** update module google.golang.org/grpc to v1.63.0 ([11e81c5](https://github.com/o7studios/gate/commit/11e81c5492ead7592d21d601a5b37a3c97e0635f))
-* **deps:** update module google.golang.org/grpc to v1.63.2 ([ea86cca](https://github.com/o7studios/gate/commit/ea86cca74e6f157702ab15b588ea9e83fa008bd5))
-* **deps:** update module google.golang.org/grpc to v1.64.0 ([a01e8b0](https://github.com/o7studios/gate/commit/a01e8b052289588b7b8851decc3e284990f3dfb2))
-* **deps:** update module google.golang.org/grpc to v1.65.0 ([cfe9ed0](https://github.com/o7studios/gate/commit/cfe9ed020e18d794322cb99547f2e655962be87d))
-* **deps:** update module google.golang.org/grpc to v1.66.0 ([bf9aa22](https://github.com/o7studios/gate/commit/bf9aa22f123b16deec0e28cc8b78b9e48c676221))
-* **deps:** update module google.golang.org/grpc to v1.66.2 ([9ecb33c](https://github.com/o7studios/gate/commit/9ecb33cf867678b6f80ff44db425bb766231aa5e))
-* **deps:** update module google.golang.org/grpc to v1.67.0 ([#389](https://github.com/o7studios/gate/issues/389)) ([7cc97ab](https://github.com/o7studios/gate/commit/7cc97ab2083d54e008ba0fbff71039e9bc96c0d1))
-* **deps:** update module google.golang.org/grpc to v1.67.1 ([ee304c9](https://github.com/o7studios/gate/commit/ee304c928a4dd776e0dbd389f54d7079f8e71499))
-* **deps:** update module google.golang.org/grpc to v1.68.0 ([#421](https://github.com/o7studios/gate/issues/421)) ([4916245](https://github.com/o7studios/gate/commit/491624518aa52800530210af01211f67acd84dc0))
-* **deps:** update module google.golang.org/grpc to v1.68.1 ([#453](https://github.com/o7studios/gate/issues/453)) ([062c5fe](https://github.com/o7studios/gate/commit/062c5fed8a56e7e7ffd92c18b75494e8aa89abf8))
-* **deps:** update module google.golang.org/grpc to v1.69.0 ([#464](https://github.com/o7studios/gate/issues/464)) ([be6795d](https://github.com/o7studios/gate/commit/be6795d8efa14d33021aa325e26e38fce802e82a))
-* **deps:** update module google.golang.org/grpc to v1.69.2 ([#469](https://github.com/o7studios/gate/issues/469)) ([6bec70d](https://github.com/o7studios/gate/commit/6bec70d476d2d8de4a39bc70c815491734515afb))
-* **deps:** update module google.golang.org/grpc to v1.69.4 ([#485](https://github.com/o7studios/gate/issues/485)) ([731be02](https://github.com/o7studios/gate/commit/731be020c46b51ff1fab681c7e2c51c89d8cb5dc))
-* **deps:** update module google.golang.org/grpc to v1.70.0 ([#498](https://github.com/o7studios/gate/issues/498)) ([ee995c8](https://github.com/o7studios/gate/commit/ee995c8f7c431c073b3bd5c171c3805cb4e0ad07))
-* **deps:** update module google.golang.org/grpc to v1.72.0 ([#530](https://github.com/o7studios/gate/issues/530)) ([cc649ab](https://github.com/o7studios/gate/commit/cc649abb4082a3cf12bd5f7d69b611f6ea867e26))
-* **deps:** update module google.golang.org/grpc to v1.78.0 ([#661](https://github.com/o7studios/gate/issues/661)) ([398f57e](https://github.com/o7studios/gate/commit/398f57e2e2fc9ee9b517c644b9cae9080a337450))
-* **deps:** update module google.golang.org/grpc to v1.79.3 [security] ([#678](https://github.com/o7studios/gate/issues/678)) ([2217f5f](https://github.com/o7studios/gate/commit/2217f5f357edba3b8901d100c704dc46e4bcc14b))
-* **deps:** update module google.golang.org/protobuf to v1.36.0 ([#474](https://github.com/o7studios/gate/issues/474)) ([a3e2d72](https://github.com/o7studios/gate/commit/a3e2d723e8dbbdd2b1b9ff4c4db7189f53024111))
-* **deps:** update module google.golang.org/protobuf to v1.36.1 ([#475](https://github.com/o7studios/gate/issues/475)) ([014683e](https://github.com/o7studios/gate/commit/014683e819e9d1ff0f76560643a9256eab68d71e))
-* **deps:** update module google.golang.org/protobuf to v1.36.11 ([#627](https://github.com/o7studios/gate/issues/627)) ([7bf90b4](https://github.com/o7studios/gate/commit/7bf90b4fcfd874b5f1627f3c41d6d15211b20a50))
-* **deps:** update module google.golang.org/protobuf to v1.36.2 ([#478](https://github.com/o7studios/gate/issues/478)) ([b607131](https://github.com/o7studios/gate/commit/b6071319aa53a1417c0570154ba83040332dd940))
-* **deps:** update module google.golang.org/protobuf to v1.36.3 ([#491](https://github.com/o7studios/gate/issues/491)) ([27bdf09](https://github.com/o7studios/gate/commit/27bdf096532bafc4450c4df07fe2af73490e8553))
-* **deps:** update module google.golang.org/protobuf to v1.36.4 ([#499](https://github.com/o7studios/gate/issues/499)) ([83369c6](https://github.com/o7studios/gate/commit/83369c6a6fcbe13def581a100ad91f52befeeb7d))
-* **deps:** update module nhooyr.io/websocket to v1.8.11 ([7953aef](https://github.com/o7studios/gate/commit/7953aefae5f52b165ec4dce3e6aae74cde05cb62))
-* Do not track plugin channels registered per-player on the proxy; Plugin Messages sent from the backend server do work ([29c482e](https://github.com/o7studios/gate/commit/29c482e4cb17e511f10161b2f26022f2fb45fefa))
-* **docker:** use glibc base images so dynamically linked gate binary execs ([#712](https://github.com/o7studios/gate/issues/712)) ([9d503c3](https://github.com/o7studios/gate/commit/9d503c348a724711835a1fcd78e8434b77024d23))
-* **docs:** Disabling response cache ([0b3b733](https://github.com/o7studios/gate/commit/0b3b733dc3bdede11873fce5f52704ef2ec519cf))
-* **docs:** include ([03ecca5](https://github.com/o7studios/gate/commit/03ecca5eb78d361503fed26e26eb48b9ccc8e793))
-* **docs:** links ([10fc08e](https://github.com/o7studios/gate/commit/10fc08e044010defd8da378f752d4cb7dd85fd95))
-* **docs:** Pageview ([c9b4822](https://github.com/o7studios/gate/commit/c9b48220be7b8395e2b58b521a2e0b9ea2313b78))
-* **docs:** use correct comment syntax for VitePress colored diffs in YAML blocks ([#572](https://github.com/o7studios/gate/issues/572)) ([23bdc97](https://github.com/o7studios/gate/commit/23bdc97304a3628bc68758be1e9c7ce22bbe963a))
-* Double slash commands (closes [#414](https://github.com/o7studios/gate/issues/414)) ([a6ae8b3](https://github.com/o7studios/gate/commit/a6ae8b34605e79e8be8d8c2d1020bbdbc19732ae))
-* Entity/player suggestions in commands ([c443620](https://github.com/o7studios/gate/commit/c443620bb84f66f3d334ec6e86fb66d9069cff6d))
-* handle bare IPv6 addresses in proxy protocol header (fixes [#670](https://github.com/o7studios/gate/issues/670)) ([#673](https://github.com/o7studios/gate/issues/673)) ([3db7f7b](https://github.com/o7studios/gate/commit/3db7f7ba5433b18006cb6c0fed38445d1f369fa8))
-* ignore ErrDecoderLeftBytes in status response decoding ([#559](https://github.com/o7studios/gate/issues/559)) ([8ee714f](https://github.com/o7studios/gate/commit/8ee714f12eff1e3d400c99ac2c93b47e20023289))
-* Implement YAML en-/decoder (fixes [#223](https://github.com/o7studios/gate/issues/223)) ([b034584](https://github.com/o7studios/gate/commit/b034584eeac22a2c5296f17f88681f0d2d99fbbe))
-* increase byte array length limit for 1.7.x clients in WriteBytes17 ([#558](https://github.com/o7studios/gate/issues/558)) ([0dc2f12](https://github.com/o7studios/gate/commit/0dc2f12d0b40c113091f43f87136ebf765ee2517)), closes [#533](https://github.com/o7studios/gate/issues/533)
-* **java/config:** validate forcedHosts against servers ([#569](https://github.com/o7studios/gate/issues/569)) ([98cfd60](https://github.com/o7studios/gate/commit/98cfd6040ce587fc77b603c53c10280e3ea0343e))
-* **java:** allow nil tab list header footer ([#710](https://github.com/o7studios/gate/issues/710)) ([10c0f64](https://github.com/o7studios/gate/commit/10c0f64af2efbb56298009db868ab6573eb17d48))
-* **java:** normalize NBT component style booleans ([486e4a8](https://github.com/o7studios/gate/commit/486e4a802e26168d832e0c27e1bbd48070eb54e1))
-* **java:** set packet state for registry-created packets ([6cd71ba](https://github.com/o7studios/gate/commit/6cd71baa76eb21a9dddc93a64dd06e37760d4939))
-* **java:** set packet state for registry-created packets ([0a9433b](https://github.com/o7studios/gate/commit/0a9433b0b12c08a0bb7e526b15c0bca7aa73ad75))
-* Join/switch server pre-1.20.2 ([083226c](https://github.com/o7studios/gate/commit/083226c6009005a7a2fa5c9fc569e7d3d49361b6))
-* JSON Decode ServerPing with string as description ([141278e](https://github.com/o7studios/gate/commit/141278e72921867adb1a5e8df54d50d303927e86))
-* Json to Snbt string escaping ([25208f9](https://github.com/o7studios/gate/commit/25208f9cdfd092756bd405dad65114fa7a6be84b))
-* **JsonToSNBT:** Always quote string values ([9584d7e](https://github.com/o7studios/gate/commit/9584d7e31023948d270b4de01c5fecec7af70ec4))
-* light mode text hover ([84544ea](https://github.com/o7studios/gate/commit/84544ea7be54cc1995bf628c05a5bea2798b1804))
-* limit docker platforms to supported linux arches ([1400ee3](https://github.com/o7studios/gate/commit/1400ee355eb485ae2dec699997f56418d7dafa48))
-* **lite:** fix glob cache key mutation, use QuoteMeta, and share single regex cache ([#675](https://github.com/o7studios/gate/issues/675)) ([c6c670b](https://github.com/o7studios/gate/commit/c6c670b89d6f9febe19b897e8a8c20c8be6fc7c2))
-* **Lite:** nil pointer dereference caused by defer and return nil when could not write handshake packet ([6e35d73](https://github.com/o7studios/gate/commit/6e35d7304b5c64b92b3e036d56e38170f238f628))
-* **Lite:** Ping cache key is backend + protocol (fix [#255](https://github.com/o7studios/gate/issues/255)) ([09b27eb](https://github.com/o7studios/gate/commit/09b27eb91be40ac4fb645e68cdc926c8080014f1))
-* **network:** fix AvailableCommands packet for mods ([#534](https://github.com/o7studios/gate/issues/534)) ([7f683a6](https://github.com/o7studios/gate/commit/7f683a6a2292363a0db7a16969eb789be72ea0b3))
-* nil pointer dereference in session chat LastSeenMessages handling ([1f78da9](https://github.com/o7studios/gate/commit/1f78da990abd94a14d83c866b1e9ab46d8dd7485))
-* No lint errors ([b4972ad](https://github.com/o7studios/gate/commit/b4972ad67cc749f5127b8852a54b049530836af5))
-* out-of-order disconnects by using chat queue ([231cd43](https://github.com/o7studios/gate/commit/231cd4374f4bd210f4b2e9cba58bb922907e0d9d))
-* out-of-order disconnects by using chat queue ([996f54b](https://github.com/o7studios/gate/commit/996f54b89809152f322d6950b5034f7dbf4ce862))
-* Parse number Durations in config correctly (fix [#221](https://github.com/o7studios/gate/issues/221)) ([59afe39](https://github.com/o7studios/gate/commit/59afe398a3125b1b5fa07b8347afa5000bf6b558))
-* player gets kicked when using suggestions in commands ([#584](https://github.com/o7studios/gate/issues/584)) ([884161a](https://github.com/o7studios/gate/commit/884161a8cb68c6102b30b62575396c0dfd68c5ef))
-* prevent map sharing between config reloads causing server persistence ([#557](https://github.com/o7studios/gate/issues/557)) ([ad12bd9](https://github.com/o7studios/gate/commit/ad12bd9f6e6efa9db41409b049cbcb4ef35ca1e5))
-* PreviousServer is always nil ([#541](https://github.com/o7studios/gate/issues/541)) ([322916a](https://github.com/o7studios/gate/commit/322916ac75568ef020048dfc085a12aa6214dd42))
-* **proxy:** forward backend register/unregister packets to client ([#672](https://github.com/o7studios/gate/issues/672)) ([1c5d6c8](https://github.com/o7studios/gate/commit/1c5d6c8ddc61235f70244de84be9cb4cbaf4eae6))
-* proxyproto: invalid address ([4030e57](https://github.com/o7studios/gate/commit/4030e5772a4c9f15cf96c8e8008853b11def752b))
-* register 0x4C ID for Respawn packet in 1.21.2+ ([#416](https://github.com/o7studios/gate/issues/416)) ([f07cdc8](https://github.com/o7studios/gate/commit/f07cdc8714754e92a747ac61990299b436627779))
-* remove debug printf ([96c0a2e](https://github.com/o7studios/gate/commit/96c0a2e9f8bd4d91849bba08fbcd8d1d6dc04a79))
-* Removed `Modded Servers Config` from sidebar in favor of `Modded Servers` ([#573](https://github.com/o7studios/gate/issues/573)) ([6b84a42](https://github.com/o7studios/gate/commit/6b84a428cbf2284106cdc1bc089359d376959b37))
-* resolve architecture mismatch for multi-arch docker builds ([fd083f6](https://github.com/o7studios/gate/commit/fd083f6f3f5ed4af63db7246cfaa5acaf337119a))
-* resolve architecture mismatch for multi-arch docker builds ([a0f7da7](https://github.com/o7studios/gate/commit/a0f7da718477b71efe29ba1bfa062bb6d5986c75))
-* resolve lite mode backend issues and add sequential strategy default ([#565](https://github.com/o7studios/gate/issues/565)) ([798cb65](https://github.com/o7studios/gate/commit/798cb659677769b698b76be738cad1db74eeae35))
-* resolve nil pointer dereference warnings in forward_test.go ([#606](https://github.com/o7studios/gate/issues/606)) ([d1f198b](https://github.com/o7studios/gate/commit/d1f198b25625f15d63e6c1c0e5e3ef562730cc11))
-* Return context on ErrDecoderLeftBytes ([#579](https://github.com/o7studios/gate/issues/579)) ([01d87bd](https://github.com/o7studios/gate/commit/01d87bdfc9953cb6d8b88bc3c7cafa37de89c436))
-* Send resource pack twice ([#197](https://github.com/o7studios/gate/issues/197)); feat: Add PendingResourcePack & AppliedResourcePack getters ([937d3f3](https://github.com/o7studios/gate/commit/937d3f3f07dec95ac8bc4bfcbb2cd02db015dfe1))
-* SoundEntityPacket panic and protocol desync ([#605](https://github.com/o7studios/gate/issues/605)) ([4592ec4](https://github.com/o7studios/gate/commit/4592ec40184679df0e25bf69db5b41803a3aaa15))
-* strip leading slash from legacy commands to prevent double slash forwarding ([#556](https://github.com/o7studios/gate/issues/556)) ([5d55592](https://github.com/o7studios/gate/commit/5d55592a3d148f42e3f1c7d941d978c1c67be937))
-* Support Gate Lite + Connect enabled ([42d854f](https://github.com/o7studios/gate/commit/42d854f246e6de9afb8519f41eee463e01ed9b25))
-* Switch server and some data races ([896441b](https://github.com/o7studios/gate/commit/896441b1f6063b3c9307339f256721544bf0164d))
-* **ui:** improve search mode toggle visibility ([6fc2b28](https://github.com/o7studios/gate/commit/6fc2b28e44697bc804b0edc4099aea81616c7318))
-* update community stats in documentation ([6eb3e56](https://github.com/o7studios/gate/commit/6eb3e5633dd4bbd49366a375f710018d2a8822f8))
-* Update member counts in LandingAfter component ([f158f91](https://github.com/o7studios/gate/commit/f158f91ce11a663d430cc32da933bc5e9b9df390))
-* Use Vipers config finder ([1c75a1b](https://github.com/o7studios/gate/commit/1c75a1b3270a16941d735258e71c96905bcd3ed5))
-* **web:** fix bedrock quick link ([#571](https://github.com/o7studios/gate/issues/571)) ([6b2129e](https://github.com/o7studios/gate/commit/6b2129e672a85698a16e312587ab1c1a47c9af1f))
-* Workaround until fix of https://github.com/spf13/viper/issues/338 (fixes [#218](https://github.com/o7studios/gate/issues/218)) ([ef86ad3](https://github.com/o7studios/gate/commit/ef86ad39777acc7f2710a188d87b81410d785fbe))
-* wrap SetReader with fullReader to fix large packet read issues ([#615](https://github.com/o7studios/gate/issues/615)) ([4b5d548](https://github.com/o7studios/gate/commit/4b5d54834f5ae19cae8068186694b0bc322fcbcf))
* **docker:** support managed geyserlite on arm64 ([#717](https://github.com/minekube/gate/issues/717)) ([beda893](https://github.com/minekube/gate/commit/beda893a11a3d158939201746c5686de13100138))
## [0.66.6](https://github.com/minekube/gate/compare/v0.66.5...v0.66.6) (2026-06-06)
diff --git a/config.yml b/config.yml
index d005d2ad0..f2a03c402 100644
--- a/config.yml
+++ b/config.yml
@@ -282,6 +282,17 @@ config:
# Default: "floodgate.pem"
#floodgateKeyPath: "floodgate.pem"
+ # Backend Floodgate compatibility.
+ # Re-emits verified Bedrock identity data only to the listed Java backends.
+ # Enable this only for backend servers you operate and trust with the same Floodgate key.
+ # Incompatible with forwarding.mode: legacy and bungeeguard.
+ # Default: disabled
+ #backendFloodgate:
+ # enabled: false
+ # allowedServers:
+ # - lobby
+ # - survival
+
# Managed Geyser mode: Gate automatically handles the Geyser process.
# This is the recommended setup for most users.
managed:
diff --git a/go.mod b/go.mod
index 8be4d64d4..affe13c92 100644
--- a/go.mod
+++ b/go.mod
@@ -12,7 +12,7 @@ require (
github.com/dboslee/lru v0.0.1
github.com/edwingeng/deque/v2 v2.1.1
github.com/gammazero/deque v1.2.1
- github.com/go-faker/faker/v4 v4.8.0
+ github.com/go-faker/faker/v4 v4.9.0
github.com/go-logr/logr v1.4.3
github.com/go-logr/zapr v1.3.0
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8
@@ -22,7 +22,7 @@ require (
github.com/jellydator/ttlcache/v3 v3.4.1
github.com/knadh/koanf/providers/file v1.2.1
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
- github.com/pires/go-proxyproto v0.12.0
+ github.com/pires/go-proxyproto v0.13.0
github.com/robinbraemer/event v0.1.1
github.com/rs/xid v1.6.0
github.com/sandertv/go-raknet v1.13.0
@@ -34,18 +34,18 @@ require (
go.minekube.com/brigodier v0.0.2
go.minekube.com/common v0.4.0
go.minekube.com/connect v0.6.2
- go.minekube.com/geyserlite v0.3.14
- go.minekube.com/vialite v0.2.8
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0
- go.opentelemetry.io/otel v1.41.0
- go.opentelemetry.io/otel/metric v1.41.0
- go.opentelemetry.io/otel/trace v1.41.0
+ go.minekube.com/geyserlite v0.3.17
+ go.minekube.com/vialite v0.3.0
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0
+ go.opentelemetry.io/otel v1.44.0
+ go.opentelemetry.io/otel/metric v1.44.0
+ go.opentelemetry.io/otel/trace v1.44.0
go.uber.org/atomic v1.11.0
go.uber.org/zap v1.28.0
golang.org/x/exp v0.0.0-20260112195511-716be5621a96
golang.org/x/net v0.49.0
- golang.org/x/sync v0.19.0
- golang.org/x/text v0.33.0
+ golang.org/x/sync v0.21.0
+ golang.org/x/text v0.38.0
golang.org/x/time v0.14.0
google.golang.org/grpc v1.79.3
google.golang.org/protobuf v1.36.11
@@ -98,13 +98,13 @@ require (
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect
- go.opentelemetry.io/otel/sdk v1.39.0 // indirect
- go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.44.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect
go.opentelemetry.io/proto/otlp v1.8.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/image v0.18.0 // indirect
- golang.org/x/sys v0.40.0 // indirect
+ golang.org/x/sys v0.45.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
)
diff --git a/go.sum b/go.sum
index 2a1d8a5ee..bc5fec969 100644
--- a/go.sum
+++ b/go.sum
@@ -63,6 +63,8 @@ github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aev
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-faker/faker/v4 v4.8.0 h1:QAKmb4TyAMxIgf3a8fXubQXwFFJviBGL2/IDa34N6JQ=
github.com/go-faker/faker/v4 v4.8.0/go.mod h1:u1dIRP5neLB6kTzgyVjdBOV5R1uP7BdxkcWk7tiKQXk=
+github.com/go-faker/faker/v4 v4.9.0 h1:a4HXLwueuTCtgF93VpUsl8Zd2nG1VH2SgNWDPVEBg5U=
+github.com/go-faker/faker/v4 v4.9.0/go.mod h1:u1dIRP5neLB6kTzgyVjdBOV5R1uP7BdxkcWk7tiKQXk=
github.com/go-gl/mathgl v1.1.0 h1:0lzZ+rntPX3/oGrDzYGdowSLC2ky8Osirvf5uAwfIEA=
github.com/go-gl/mathgl v1.1.0/go.mod h1:yhpkQzEiH9yPyxDUGzkmgScbaBVlhC06qodikEM0ZwQ=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -131,9 +133,6 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
-github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
-github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4=
github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg=
@@ -153,6 +152,8 @@ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pires/go-proxyproto v0.12.0 h1:TTCxD66dU898tahivkqc3hoceZp7P44FnorWyo9d5vM=
github.com/pires/go-proxyproto v0.12.0/go.mod h1:qUvfqUMEoX7T8g0q7TQLDnhMjdTrxnG0hvpMn+7ePNI=
+github.com/pires/go-proxyproto v0.13.0 h1:kMrnyu6w92odDfOVzjYV6s5GqYGnIEKoxxsP38VrPSs=
+github.com/pires/go-proxyproto v0.13.0/go.mod h1:qUvfqUMEoX7T8g0q7TQLDnhMjdTrxnG0hvpMn+7ePNI=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
@@ -226,7 +227,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
@@ -250,16 +250,16 @@ github.com/zyedidia/generic v1.2.1 h1:Zv5KS/N2m0XZZiuLS82qheRG4X1o5gsWreGb0hR7XD
github.com/zyedidia/generic v1.2.1/go.mod h1:ly2RBz4mnz1yeuVbQA/VFwGjK3mnHGRj1JuoG336Bis=
go.minekube.com/brigodier v0.0.2 h1:g6VJtyeQr7Y+lAP1EfpM7Cdv5STiJaE2eXv8LRuGDG8=
go.minekube.com/brigodier v0.0.2/go.mod h1:WJf/lyJVTId/phiY6phPW6++qkTjCQ72rbOWqo4XIqc=
-go.minekube.com/common v0.3.0 h1:eKqNHFDR3eIclCqViHKP/gzWCYgfRdFpZ8+vnKPrnv8=
-go.minekube.com/common v0.3.0/go.mod h1:CKCUOhcDjVWRfn77u3Tp/ECV6l1OQ5WUW5M159pu38M=
go.minekube.com/common v0.4.0 h1:gIeGWtXYh7cIaCOSEBk1myzN211MCRXAuSZZ2TqStMY=
go.minekube.com/common v0.4.0/go.mod h1:Nr3bszhOFSBFlglXyqtUmoiLawg+PfzeNEgN00PkK9c=
go.minekube.com/connect v0.6.2 h1:RajPc7YgqygcOviV2g4xetL3J0Wzi8b/lsYXUzIltxE=
go.minekube.com/connect v0.6.2/go.mod h1:28k11I4RyzUfAL3AkOXt3atzjeOFAC8eqbCMwsYKAb0=
-go.minekube.com/geyserlite v0.3.14 h1:+cSN9o/b5jEOHeym/uXvt5MEoGnrYloJidrVe9K9pWo=
-go.minekube.com/geyserlite v0.3.14/go.mod h1:yy0/M0zSD6X3FoQMwtmf5Jn+7YFM7AZWamKw0E8fnOE=
-go.minekube.com/vialite v0.2.8 h1:3xEuciKORVeuDdCOY6w2BSnenVYti0ZS8xlqCUX42nk=
-go.minekube.com/vialite v0.2.8/go.mod h1:W9L1l8/b/GsLmkw1BW4wijaaPj/zV3OdrtYJgWdkhxE=
+go.minekube.com/geyserlite v0.3.16 h1:g2iB/V4NtQ8C8GluhocCzaeOLfgjEVWrMGUU3re4OYA=
+go.minekube.com/geyserlite v0.3.16/go.mod h1:yy0/M0zSD6X3FoQMwtmf5Jn+7YFM7AZWamKw0E8fnOE=
+go.minekube.com/geyserlite v0.3.17 h1:vYkZCCOb43/yWSbsGRyUAmpl+NARNq4V0sejg4yFr30=
+go.minekube.com/geyserlite v0.3.17/go.mod h1:yy0/M0zSD6X3FoQMwtmf5Jn+7YFM7AZWamKw0E8fnOE=
+go.minekube.com/vialite v0.3.0 h1:IeJLHnaw8tBa0ZQVW4SYwzR0eXxG+j3u2KI805J8F4w=
+go.minekube.com/vialite v0.3.0/go.mod h1:W9L1l8/b/GsLmkw1BW4wijaaPj/zV3OdrtYJgWdkhxE=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
@@ -269,6 +269,8 @@ go.opentelemetry.io/contrib/instrumentation/host v0.63.0 h1:zsaUrWypCf0NtYSUby+/
go.opentelemetry.io/contrib/instrumentation/host v0.63.0/go.mod h1:Ru+kuFO+ToZqBKwI59rCStOhW6LWrbGisYrFaX61bJk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 h1:PeBoRj6af6xMI7qCupwFvTbbnd49V7n5YpG6pg8iDYQ=
go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0/go.mod h1:ingqBCtMCe8I4vpz/UVzCW6sxoqgZB37nao91mLQ3Bw=
go.opentelemetry.io/contrib/propagators/b3 v1.38.0 h1:uHsCCOSKl0kLrV2dLkFK+8Ywk9iKa/fptkytc6aFFEo=
@@ -277,6 +279,8 @@ go.opentelemetry.io/contrib/propagators/ot v1.38.0 h1:k4gSyyohaDXI8F9BDXYC3uO2vr
go.opentelemetry.io/contrib/propagators/ot v1.38.0/go.mod h1:2hDsuiHRO39SRUMhYGqmj64z/IuMRoxE4bBSFR82Lo8=
go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
+go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
+go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk=
@@ -289,12 +293,20 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
+go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
+go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
+go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
+go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
+go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
+go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
+go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
+go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
go.opentelemetry.io/proto/otlp v1.8.0 h1:fRAZQDcAFHySxpJ1TwlA1cJ4tvcrw7nXl9xWWC8N5CE=
go.opentelemetry.io/proto/otlp v1.8.0/go.mod h1:tIeYOeNBU4cvmPqpaji1P+KbB4Oloai8wN4rWzRrFF0=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
@@ -342,6 +354,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
+golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -352,10 +366,14 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
+golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
+golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
+golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
diff --git a/pkg/configs/config.yml b/pkg/configs/config.yml
index d005d2ad0..f2a03c402 100644
--- a/pkg/configs/config.yml
+++ b/pkg/configs/config.yml
@@ -282,6 +282,17 @@ config:
# Default: "floodgate.pem"
#floodgateKeyPath: "floodgate.pem"
+ # Backend Floodgate compatibility.
+ # Re-emits verified Bedrock identity data only to the listed Java backends.
+ # Enable this only for backend servers you operate and trust with the same Floodgate key.
+ # Incompatible with forwarding.mode: legacy and bungeeguard.
+ # Default: disabled
+ #backendFloodgate:
+ # enabled: false
+ # allowedServers:
+ # - lobby
+ # - survival
+
# Managed Geyser mode: Gate automatically handles the Geyser process.
# This is the recommended setup for most users.
managed:
diff --git a/pkg/edition/bedrock/config/config.go b/pkg/edition/bedrock/config/config.go
index f81b45e7b..37dbfd05a 100644
--- a/pkg/edition/bedrock/config/config.go
+++ b/pkg/edition/bedrock/config/config.go
@@ -66,6 +66,16 @@ type Config struct {
// Managed Geyser (recommended): Gate automatically handles Geyser process
Managed *ManagedGeyser `yaml:"managed,omitempty" json:"managed,omitempty"` // Automatic Geyser management and process control
+
+ // Backend Floodgate compatibility re-emits verified Bedrock identity data to explicitly allowed Java backends.
+ BackendFloodgate BackendFloodgate `yaml:"backendFloodgate,omitempty" json:"backendFloodgate,omitempty"`
+}
+
+// BackendFloodgate controls whether verified Bedrock identity data is forwarded
+// to backend servers that run Floodgate-aware plugins.
+type BackendFloodgate struct {
+ Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
+ AllowedServers []string `yaml:"allowedServers,omitempty" json:"allowedServers,omitempty"`
}
// ManagedGeyser configures automatic Geyser management.
@@ -151,6 +161,9 @@ type BedrockConfig struct {
// Managed Geyser (recommended): Gate automatically handles Geyser process
// Can be either bool (true) or ManagedGeyser struct for advanced config
Managed BoolOrManagedGeyser `yaml:"managed,omitempty" json:"managed,omitempty"`
+
+ // Backend Floodgate compatibility re-emits verified Bedrock identity data to explicitly allowed Java backends.
+ BackendFloodgate BackendFloodgate `yaml:"backendFloodgate,omitempty" json:"backendFloodgate,omitempty"`
}
// BoolOrManagedGeyser represents a field that can be either:
@@ -169,6 +182,7 @@ func (bc *BedrockConfig) ToConfig() Config {
GeyserListenAddr: bc.GeyserListenAddr,
UsernameFormat: bc.UsernameFormat,
FloodgateKeyPath: bc.FloodgateKeyPath,
+ BackendFloodgate: bc.BackendFloodgate,
}
// Apply defaults if empty
diff --git a/pkg/edition/bedrock/config/config_test.go b/pkg/edition/bedrock/config/config_test.go
index afac6f4b2..7b1ce936c 100644
--- a/pkg/edition/bedrock/config/config_test.go
+++ b/pkg/edition/bedrock/config/config_test.go
@@ -291,6 +291,38 @@ managed:
}
}
+func TestBedrockConfig_BackendFloodgate(t *testing.T) {
+ yamlConfig := `
+enabled: true
+floodgateKeyPath: floodgate.pem
+backendFloodgate:
+ enabled: true
+ allowedServers:
+ - lobby
+ - survival
+`
+
+ var cfg BedrockConfig
+ if err := yaml.Unmarshal([]byte(yamlConfig), &cfg); err != nil {
+ t.Fatalf("yaml.Unmarshal() error = %v", err)
+ }
+
+ if !cfg.BackendFloodgate.Enabled {
+ t.Fatal("BackendFloodgate.Enabled = false, want true")
+ }
+ if got := strings.Join(cfg.BackendFloodgate.AllowedServers, ","); got != "lobby,survival" {
+ t.Fatalf("BackendFloodgate.AllowedServers = %q, want lobby,survival", got)
+ }
+
+ resolved := cfg.ToConfig()
+ if !resolved.BackendFloodgate.Enabled {
+ t.Fatal("resolved BackendFloodgate.Enabled = false, want true")
+ }
+ if got := strings.Join(resolved.BackendFloodgate.AllowedServers, ","); got != "lobby,survival" {
+ t.Fatalf("resolved BackendFloodgate.AllowedServers = %q, want lobby,survival", got)
+ }
+}
+
func TestManagedNestedJavaConfig(t *testing.T) {
yamlConfig := `
managed:
diff --git a/pkg/edition/bedrock/config/validate.go b/pkg/edition/bedrock/config/validate.go
index f6c8a8912..f08e8ee93 100644
--- a/pkg/edition/bedrock/config/validate.go
+++ b/pkg/edition/bedrock/config/validate.go
@@ -4,6 +4,8 @@ import (
"fmt"
"os"
"strings"
+
+ "go.minekube.com/gate/pkg/util/validation"
)
// Validate validates the Bedrock edition configuration.
@@ -36,6 +38,26 @@ func (c *Config) Validate() (warns []error, errs []error) {
e("Username format must contain %%s placeholder")
}
+ if c.BackendFloodgate.Enabled {
+ if len(c.BackendFloodgate.AllowedServers) == 0 {
+ e("backendFloodgate.allowedServers must not be empty when backendFloodgate is enabled")
+ }
+ seen := make(map[string]struct{}, len(c.BackendFloodgate.AllowedServers))
+ for _, name := range c.BackendFloodgate.AllowedServers {
+ if !validation.ValidServerName(name) {
+ e("Invalid backendFloodgate allowed server name %q: %s and length be 1-%d", name,
+ validation.QualifiedNameErrMsg, validation.QualifiedNameMaxLength)
+ continue
+ }
+ normalized := strings.ToLower(name)
+ if _, ok := seen[normalized]; ok {
+ e("Duplicate backendFloodgate allowed server %q", name)
+ continue
+ }
+ seen[normalized] = struct{}{}
+ }
+ }
+
// Validate managed mode options
if managed.Enabled {
switch managed.Engine {
diff --git a/pkg/edition/bedrock/geyser/backend_handshake_test.go b/pkg/edition/bedrock/geyser/backend_handshake_test.go
new file mode 100644
index 000000000..7b5a60c38
--- /dev/null
+++ b/pkg/edition/bedrock/geyser/backend_handshake_test.go
@@ -0,0 +1,213 @@
+package geyser
+
+import (
+ "bytes"
+ "context"
+ "os"
+ "path/filepath"
+ "reflect"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ bedrockconfig "go.minekube.com/gate/pkg/edition/bedrock/config"
+ "go.minekube.com/gate/pkg/edition/bedrock/geyser/floodgate"
+ "go.minekube.com/gate/pkg/edition/java/proxy"
+ "go.minekube.com/gate/pkg/util/netutil"
+)
+
+var _ proxy.BackendHandshakeAddresser = (*Integration)(nil)
+
+type contextOnlyPlayer struct {
+ proxy.Player
+ ctx context.Context
+}
+
+func (p contextOnlyPlayer) Context() context.Context {
+ return p.ctx
+}
+
+type backendHandshakeTarget struct {
+ info proxy.ServerInfo
+}
+
+func (t backendHandshakeTarget) ServerInfo() proxy.ServerInfo {
+ return t.info
+}
+
+func (t backendHandshakeTarget) Players() proxy.Players {
+ return nil
+}
+
+func TestBackendHandshakeAddrEmitsFloodgateDataForAllowedBedrockTarget(t *testing.T) {
+ fg := newTestFloodgate(t)
+ bedrockData := testBedrockData()
+ ctx := withBedrockContext(context.Background(), &GeyserConnection{
+ BedrockData: bedrockData,
+ OriginalHost: "original.example.org:19132",
+ })
+ integration := &Integration{
+ config: &bedrockconfig.Config{
+ BackendFloodgate: bedrockconfig.BackendFloodgate{
+ Enabled: true,
+ AllowedServers: []string{"lobby"},
+ },
+ },
+ floodgate: fg,
+ }
+
+ got, err := integration.BackendHandshakeAddr("clean.example.org", contextOnlyPlayer{ctx: ctx}, testBackendTarget("Lobby"))
+
+ require.NoError(t, err)
+ original, decoded, err := fg.ReadHostname(got)
+ require.NoError(t, err)
+ require.Equal(t, "clean.example.org", original)
+ require.Equal(t, *bedrockData, *decoded)
+}
+
+func TestBackendHandshakeAddrLeavesNonAllowedTargetClean(t *testing.T) {
+ fg := newTestFloodgate(t)
+ ctx := withBedrockContext(context.Background(), &GeyserConnection{
+ BedrockData: testBedrockData(),
+ OriginalHost: "original.example.org:19132",
+ })
+ integration := &Integration{
+ config: &bedrockconfig.Config{
+ BackendFloodgate: bedrockconfig.BackendFloodgate{
+ Enabled: true,
+ AllowedServers: []string{"lobby"},
+ },
+ },
+ floodgate: fg,
+ }
+
+ got, err := integration.BackendHandshakeAddr("clean.example.org", contextOnlyPlayer{ctx: ctx}, testBackendTarget("survival"))
+
+ require.NoError(t, err)
+ require.Equal(t, "clean.example.org", got)
+}
+
+func TestBackendHandshakeAddrRejectsSpoofedJavaFloodgateHostnameForNonAllowedTarget(t *testing.T) {
+ integration := &Integration{
+ config: &bedrockconfig.Config{
+ BackendFloodgate: bedrockconfig.BackendFloodgate{
+ Enabled: true,
+ AllowedServers: []string{"lobby"},
+ },
+ },
+ floodgate: newTestFloodgate(t),
+ }
+
+ _, err := integration.BackendHandshakeAddr("clean.example.org\x00spoofed", contextOnlyPlayer{ctx: context.Background()}, testBackendTarget("survival"))
+
+ require.Error(t, err)
+}
+
+func TestBackendHandshakeAddrRejectsSpoofedJavaFloodgateHostnameForAllowedTarget(t *testing.T) {
+ integration := &Integration{
+ config: &bedrockconfig.Config{
+ BackendFloodgate: bedrockconfig.BackendFloodgate{
+ Enabled: true,
+ AllowedServers: []string{"lobby"},
+ },
+ },
+ floodgate: newTestFloodgate(t),
+ }
+
+ _, err := integration.BackendHandshakeAddr("clean.example.org\x00spoofed", contextOnlyPlayer{ctx: context.Background()}, testBackendTarget("lobby"))
+
+ require.Error(t, err)
+}
+
+func TestBackendHandshakeAddrFailsClosedForAllowedBedrockTarget(t *testing.T) {
+ fg := newTestFloodgate(t)
+ bedrockData := testBedrockData()
+ bedrockData.Username = "Bedrock\x00Admin"
+ ctx := withBedrockContext(context.Background(), &GeyserConnection{
+ BedrockData: bedrockData,
+ })
+ integration := &Integration{
+ config: &bedrockconfig.Config{
+ BackendFloodgate: bedrockconfig.BackendFloodgate{
+ Enabled: true,
+ AllowedServers: []string{"lobby"},
+ },
+ },
+ floodgate: fg,
+ }
+
+ _, err := integration.BackendHandshakeAddr("clean.example.org", contextOnlyPlayer{ctx: ctx}, testBackendTarget("lobby"))
+
+ require.Error(t, err)
+}
+
+func TestNewIntegrationRegistersAndStopsBackendHandshakeAddresserWhenEnabled(t *testing.T) {
+ keyPath := writeTestFloodgateKey(t)
+ p := new(proxy.Proxy)
+ integration, err := NewIntegration(context.Background(), p, &bedrockconfig.Config{
+ FloodgateKeyPath: keyPath,
+ GeyserListenAddr: "127.0.0.1:0",
+ BackendFloodgate: bedrockconfig.BackendFloodgate{
+ Enabled: true,
+ AllowedServers: []string{"lobby"},
+ },
+ })
+ require.NoError(t, err)
+ require.True(t, backendHandshakeAddresserRegistered(p))
+
+ integration.Stop()
+
+ require.False(t, backendHandshakeAddresserRegistered(p))
+}
+
+func TestNewIntegrationDoesNotRegisterBackendHandshakeAddresserWhenDisabled(t *testing.T) {
+ keyPath := writeTestFloodgateKey(t)
+ p := new(proxy.Proxy)
+ _, err := NewIntegration(context.Background(), p, &bedrockconfig.Config{
+ FloodgateKeyPath: keyPath,
+ GeyserListenAddr: "127.0.0.1:0",
+ })
+ require.NoError(t, err)
+
+ require.False(t, backendHandshakeAddresserRegistered(p))
+}
+
+func newTestFloodgate(t *testing.T) *floodgate.Floodgate {
+ t.Helper()
+ fg, err := floodgate.NewFloodgate(bytes.Repeat([]byte{0x24}, 16))
+ require.NoError(t, err)
+ return fg
+}
+
+func testBedrockData() *floodgate.BedrockData {
+ return &floodgate.BedrockData{
+ Version: "1",
+ Username: "BedrockPlayer",
+ Xuid: 987654321,
+ DeviceOS: floodgate.DeviceOSAndroid,
+ Language: "en_US",
+ UIProfile: 1,
+ InputMode: 1,
+ IP: "198.51.100.8",
+ LinkedPlayer: "",
+ Proxy: false,
+ SubscribeID: "sub",
+ VerifyCode: "code",
+ }
+}
+
+func testBackendTarget(name string) proxy.RegisteredServer {
+ return backendHandshakeTarget{info: proxy.NewServerInfo(name, netutil.NewAddr("127.0.0.1:25566", "tcp"))}
+}
+
+func writeTestFloodgateKey(t *testing.T) string {
+ t.Helper()
+ keyPath := filepath.Join(t.TempDir(), "floodgate.key")
+ require.NoError(t, os.WriteFile(keyPath, bytes.Repeat([]byte{0x24}, 16), 0o600))
+ return keyPath
+}
+
+func backendHandshakeAddresserRegistered(p *proxy.Proxy) bool {
+ field := reflect.ValueOf(p).Elem().FieldByName("backendHandshakeAddresser")
+ return !field.IsNil()
+}
diff --git a/pkg/edition/bedrock/geyser/floodgate/floodgate.go b/pkg/edition/bedrock/geyser/floodgate/floodgate.go
index 4e90393f0..fdadd9c20 100644
--- a/pkg/edition/bedrock/geyser/floodgate/floodgate.go
+++ b/pkg/edition/bedrock/geyser/floodgate/floodgate.go
@@ -85,6 +85,49 @@ func (f *Floodgate) ReadHostname(hostname string) (string, *BedrockData, error)
return originalHostname, bedrockData, nil
}
+// WriteHostname encodes Bedrock player data into a Floodgate hostname payload.
+func (f *Floodgate) WriteHostname(originalHostname string, d *BedrockData) (string, error) {
+ if d == nil {
+ return "", fmt.Errorf("bedrock data must not be nil")
+ }
+ if strings.ContainsRune(originalHostname, '\x00') {
+ return "", fmt.Errorf("original hostname must not contain NUL")
+ }
+ fields := []string{
+ d.Version,
+ d.Username,
+ strconv.FormatInt(d.Xuid, 10),
+ strconv.Itoa(d.DeviceOS.ID),
+ d.Language,
+ strconv.Itoa(d.UIProfile),
+ strconv.Itoa(d.InputMode),
+ d.IP,
+ d.LinkedPlayer,
+ boolString(d.Proxy),
+ d.SubscribeID,
+ d.VerifyCode,
+ }
+ for _, field := range fields {
+ if strings.ContainsRune(field, '\x00') {
+ return "", fmt.Errorf("bedrock data fields must not contain NUL")
+ }
+ }
+ data := strings.Join(fields, "\x00")
+
+ encrypted, err := f.Encrypt([]byte(data))
+ if err != nil {
+ return "", err
+ }
+ return fmt.Sprintf("%s\x00%s", originalHostname, encrypted), nil
+}
+
+func boolString(v bool) string {
+ if v {
+ return "1"
+ }
+ return "0"
+}
+
// ReadBedrockData parses the decrypted Bedrock data string.
// The format follows Floodgate's protocol: 12 null-separated fields.
func ReadBedrockData(data string) (*BedrockData, error) {
diff --git a/pkg/edition/bedrock/geyser/floodgate/floodgate_test.go b/pkg/edition/bedrock/geyser/floodgate/floodgate_test.go
index 661f4df35..1e1450531 100644
--- a/pkg/edition/bedrock/geyser/floodgate/floodgate_test.go
+++ b/pkg/edition/bedrock/geyser/floodgate/floodgate_test.go
@@ -52,6 +52,79 @@ func TestReadHostnameAndData(t *testing.T) {
}
}
+func TestWriteHostnameRoundTripsBedrockData(t *testing.T) {
+ key := bytes.Repeat([]byte{0x42}, 16)
+ fg, err := NewFloodgate(key)
+ if err != nil {
+ t.Fatalf("NewFloodgate: %v", err)
+ }
+
+ want := &BedrockData{
+ Version: "1",
+ Username: "Fox",
+ Xuid: 123456789,
+ DeviceOS: DeviceOSWindowsUWP,
+ Language: "en_US",
+ UIProfile: 1,
+ InputMode: 2,
+ IP: "203.0.113.10",
+ LinkedPlayer: "LinkedJava",
+ Proxy: true,
+ SubscribeID: "sub-id",
+ VerifyCode: "verify-code",
+ }
+
+ host, err := fg.WriteHostname("play.example.org:19132", want)
+ if err != nil {
+ t.Fatalf("WriteHostname: %v", err)
+ }
+
+ original, got, err := fg.ReadHostname(host)
+ if err != nil {
+ t.Fatalf("ReadHostname: %v", err)
+ }
+
+ if original != "play.example.org:19132" {
+ t.Fatalf("original host = %q, want %q", original, "play.example.org:19132")
+ }
+ if *got != *want {
+ t.Fatalf("bedrock data = %#v, want %#v", got, want)
+ }
+}
+
+func TestWriteHostnameRejectsAmbiguousData(t *testing.T) {
+ key := bytes.Repeat([]byte{0x42}, 16)
+ fg, err := NewFloodgate(key)
+ if err != nil {
+ t.Fatalf("NewFloodgate: %v", err)
+ }
+
+ valid := &BedrockData{
+ Version: "1",
+ Username: "Fox",
+ Xuid: 123456789,
+ DeviceOS: DeviceOSWindowsUWP,
+ Language: "en_US",
+ UIProfile: 1,
+ InputMode: 2,
+ IP: "203.0.113.10",
+ }
+
+ if _, err := fg.WriteHostname("play.example.org\x00spoof", valid); err == nil {
+ t.Fatal("WriteHostname accepted original hostname containing NUL")
+ }
+
+ withNUL := *valid
+ withNUL.Username = "Fox\x00Admin"
+ if _, err := fg.WriteHostname("play.example.org", &withNUL); err == nil {
+ t.Fatal("WriteHostname accepted Bedrock data containing NUL")
+ }
+
+ if _, err := fg.WriteHostname("play.example.org", nil); err == nil {
+ t.Fatal("WriteHostname accepted nil Bedrock data")
+ }
+}
+
func TestGenerateKey(t *testing.T) {
key, err := GenerateKey()
if err != nil {
diff --git a/pkg/edition/bedrock/geyser/geyser.go b/pkg/edition/bedrock/geyser/geyser.go
index 5108dafb9..9ff195bc9 100644
--- a/pkg/edition/bedrock/geyser/geyser.go
+++ b/pkg/edition/bedrock/geyser/geyser.go
@@ -83,6 +83,7 @@ type Integration struct {
connections map[net.Addr]*GeyserConnection
mu sync.RWMutex
unsubs []func()
+ unregisterHook func()
manager managedRunner
}
@@ -151,6 +152,9 @@ func NewIntegration(ctx context.Context, p *proxy.Proxy, cfg *config.Config) (*I
return nil, fmt.Errorf("failed to initialize floodgate: %w", err)
}
integration.floodgate = fg
+ if cfg.BackendFloodgate.Enabled {
+ integration.unregisterHook = p.SetBackendHandshakeAddresser(integration)
+ }
return integration, nil
}
@@ -212,6 +216,10 @@ func (i *Integration) Stop() {
if i.manager != nil {
i.manager.Stop()
}
+ if i.unregisterHook != nil {
+ i.unregisterHook()
+ i.unregisterHook = nil
+ }
}
func (i *Integration) listen() (net.Listener, error) {
@@ -429,3 +437,44 @@ func splitOriginalHostPort(originalHost string) (string, uint16) {
}
return originalHost, 0
}
+
+// BackendHandshakeAddr re-attaches verified Floodgate hostname data for
+// allowlisted backend Floodgate plugins.
+func (i *Integration) BackendHandshakeAddr(defaultServerAddress string, player proxy.Player, target proxy.RegisteredServer) (string, error) {
+ if i == nil || i.config == nil || !i.config.BackendFloodgate.Enabled {
+ return defaultServerAddress, nil
+ }
+ if strings.ContainsRune(defaultServerAddress, '\x00') {
+ return "", fmt.Errorf("refusing backend Floodgate hostname prefix containing NUL")
+ }
+ if !i.backendFloodgateAllowed(target) {
+ return defaultServerAddress, nil
+ }
+
+ geyserConn, ok := FromContext(player.Context())
+ if !ok || geyserConn.BedrockData == nil {
+ return defaultServerAddress, nil
+ }
+ if i.floodgate == nil {
+ return "", fmt.Errorf("backend Floodgate is enabled but Floodgate is not initialized")
+ }
+
+ encoded, err := i.floodgate.WriteHostname(defaultServerAddress, geyserConn.BedrockData)
+ if err != nil {
+ return "", fmt.Errorf("failed to encode backend Floodgate hostname: %w", err)
+ }
+ return encoded, nil
+}
+
+func (i *Integration) backendFloodgateAllowed(target proxy.RegisteredServer) bool {
+ if target == nil || target.ServerInfo() == nil {
+ return false
+ }
+ targetName := strings.ToLower(target.ServerInfo().Name())
+ for _, name := range i.config.BackendFloodgate.AllowedServers {
+ if strings.ToLower(name) == targetName {
+ return true
+ }
+ }
+ return false
+}
diff --git a/pkg/edition/bedrock/proxy/proxy.go b/pkg/edition/bedrock/proxy/proxy.go
index e20dc29d2..f0726fd6d 100644
--- a/pkg/edition/bedrock/proxy/proxy.go
+++ b/pkg/edition/bedrock/proxy/proxy.go
@@ -78,34 +78,13 @@ func (p *Proxy) Start(ctx context.Context) error {
if err := integration.Start(); err != nil {
p.log.Error(err, "failed to start geyser integration")
+ integration.Stop()
return err
}
// Listen for config reloads and restart Geyser integration when relevant fields change
unsubReload := reload.Subscribe(p.event, func(e *bedrockConfigUpdateEvent) {
- prev := e.PrevConfig
- curr := e.Config
- // Replace config for future use
- *p.config = *curr
-
- // Check if restart is required
- if requiresRestart(prev, curr) {
- p.log.Info("restarting geyser integration due to bedrock config change")
- if p.geyserIntegration != nil {
- p.geyserIntegration.Stop()
- }
- integ, err := geyser.NewIntegration(ctx, p.javaProxy, p.config)
- if err != nil {
- p.log.Error(err, "failed to re-initialize geyser integration")
- return
- }
- p.geyserIntegration = integ
- if err := integ.Start(); err != nil {
- p.log.Error(err, "failed to restart geyser integration")
- return
- }
- p.log.Info("geyser integration reloaded")
- }
+ p.handleConfigUpdate(ctx, e)
})
p.log.Info("bedrock proxy started with geyser integration")
@@ -125,6 +104,46 @@ func (p *Proxy) Start(ctx context.Context) error {
return nil
}
+func (p *Proxy) handleConfigUpdate(ctx context.Context, e *bedrockConfigUpdateEvent) {
+ if e == nil {
+ return
+ }
+ prev := e.PrevConfig
+ curr := e.Config
+ if curr == nil {
+ if p.geyserIntegration != nil {
+ p.geyserIntegration.Stop()
+ p.geyserIntegration = nil
+ }
+ return
+ }
+
+ if prev == nil || requiresRestart(prev, curr) {
+ p.log.Info("restarting geyser integration due to bedrock config change")
+ if p.geyserIntegration != nil {
+ p.geyserIntegration.Stop()
+ p.geyserIntegration = nil
+ }
+ p.config = curr
+ integ, err := geyser.NewIntegration(ctx, p.javaProxy, p.config)
+ if err != nil {
+ p.log.Error(err, "failed to re-initialize geyser integration")
+ return
+ }
+ p.geyserIntegration = integ
+ if err := integ.Start(); err != nil {
+ p.log.Error(err, "failed to restart geyser integration")
+ integ.Stop()
+ p.geyserIntegration = nil
+ return
+ }
+ p.log.Info("geyser integration reloaded")
+ return
+ }
+
+ p.config = curr
+}
+
// requiresRestart determines if a Geyser integration restart is needed based on config changes.
// Returns true if any critical configuration has changed that requires restarting Geyser.
func requiresRestart(prev, curr *config.Config) bool {
@@ -134,6 +153,9 @@ func requiresRestart(prev, curr *config.Config) bool {
prev.FloodgateKeyPath != curr.FloodgateKeyPath {
return true
}
+ if !reflect.DeepEqual(prev.BackendFloodgate, curr.BackendFloodgate) {
+ return true
+ }
// Check managed Geyser settings
prevManaged := prev.GetManaged()
diff --git a/pkg/edition/bedrock/proxy/proxy_test.go b/pkg/edition/bedrock/proxy/proxy_test.go
index a1e621d18..24ab84089 100644
--- a/pkg/edition/bedrock/proxy/proxy_test.go
+++ b/pkg/edition/bedrock/proxy/proxy_test.go
@@ -1,9 +1,19 @@
package proxy
import (
+ "bytes"
+ "context"
+ "os"
+ "path/filepath"
+ "reflect"
"testing"
+ "github.com/robinbraemer/event"
+
"go.minekube.com/gate/pkg/edition/bedrock/config"
+ "go.minekube.com/gate/pkg/edition/bedrock/geyser"
+ jconfig "go.minekube.com/gate/pkg/edition/java/config"
+ jproxy "go.minekube.com/gate/pkg/edition/java/proxy"
)
func TestRequiresRestart(t *testing.T) {
@@ -93,6 +103,32 @@ func TestRequiresRestart(t *testing.T) {
shouldRestart: true,
description: "Floodgate key path change should trigger restart",
},
+ {
+ name: "backend floodgate enabled change",
+ modifyConfig: func(cfg *config.Config) *config.Config {
+ modified := *cfg
+ modified.BackendFloodgate = config.BackendFloodgate{
+ Enabled: true,
+ AllowedServers: []string{"lobby"},
+ }
+ return &modified
+ },
+ shouldRestart: true,
+ description: "Enabling backend Floodgate compatibility should trigger restart",
+ },
+ {
+ name: "backend floodgate allowed server change",
+ modifyConfig: func(cfg *config.Config) *config.Config {
+ modified := *cfg
+ modified.BackendFloodgate = config.BackendFloodgate{
+ Enabled: false,
+ AllowedServers: []string{"lobby"},
+ }
+ return &modified
+ },
+ shouldRestart: true,
+ description: "Changing backend Floodgate allowed servers should trigger restart",
+ },
{
name: "managed enabled toggle",
modifyConfig: func(cfg *config.Config) *config.Config {
@@ -269,6 +305,94 @@ func TestRequiresRestart(t *testing.T) {
}
}
+func TestStartClearsBackendHandshakeHookWhenIntegrationStartFails(t *testing.T) {
+ keyPath := filepath.Join(t.TempDir(), "floodgate.key")
+ if err := os.WriteFile(keyPath, bytes.Repeat([]byte{0x24}, 16), 0o600); err != nil {
+ t.Fatalf("WriteFile() error = %v", err)
+ }
+
+ javaProxy, err := jproxy.New(jproxy.Options{
+ Config: &jconfig.DefaultConfig,
+ EventMgr: event.Nop,
+ })
+ if err != nil {
+ t.Fatalf("jproxy.New() error = %v", err)
+ }
+ p, err := New(Options{
+ Config: &config.Config{
+ FloodgateKeyPath: keyPath,
+ GeyserListenAddr: "127.0.0.1",
+ BackendFloodgate: config.BackendFloodgate{
+ Enabled: true,
+ AllowedServers: []string{"lobby"},
+ },
+ },
+ JavaProxy: javaProxy,
+ })
+ if err != nil {
+ t.Fatalf("New() error = %v", err)
+ }
+
+ if err := p.Start(context.Background()); err == nil {
+ t.Fatal("Start() returned nil error for invalid listen address")
+ }
+ if backendHandshakeAddresserRegistered(javaProxy) {
+ t.Fatal("backend handshake addresser remains registered after failed start")
+ }
+}
+
+func TestConfigUpdateNilCurrentStopsIntegrationAndClearsHook(t *testing.T) {
+ keyPath := filepath.Join(t.TempDir(), "floodgate.key")
+ if err := os.WriteFile(keyPath, bytes.Repeat([]byte{0x24}, 16), 0o600); err != nil {
+ t.Fatalf("WriteFile() error = %v", err)
+ }
+
+ javaProxy, err := jproxy.New(jproxy.Options{
+ Config: &jconfig.DefaultConfig,
+ EventMgr: event.Nop,
+ })
+ if err != nil {
+ t.Fatalf("jproxy.New() error = %v", err)
+ }
+ cfg := &config.Config{
+ FloodgateKeyPath: keyPath,
+ GeyserListenAddr: "127.0.0.1:0",
+ BackendFloodgate: config.BackendFloodgate{
+ Enabled: true,
+ AllowedServers: []string{"lobby"},
+ },
+ }
+ integration, err := geyser.NewIntegration(context.Background(), javaProxy, cfg)
+ if err != nil {
+ t.Fatalf("geyser.NewIntegration() error = %v", err)
+ }
+ if !backendHandshakeAddresserRegistered(javaProxy) {
+ t.Fatal("backend handshake addresser was not registered")
+ }
+
+ p := &Proxy{
+ config: cfg,
+ javaProxy: javaProxy,
+ geyserIntegration: integration,
+ }
+ p.handleConfigUpdate(context.Background(), &bedrockConfigUpdateEvent{
+ PrevConfig: cfg,
+ Config: nil,
+ })
+
+ if p.geyserIntegration != nil {
+ t.Fatal("geyserIntegration remains set after disabled Bedrock config update")
+ }
+ if backendHandshakeAddresserRegistered(javaProxy) {
+ t.Fatal("backend handshake addresser remains registered after disabled Bedrock config update")
+ }
+}
+
+func backendHandshakeAddresserRegistered(p *jproxy.Proxy) bool {
+ field := reflect.ValueOf(p).Elem().FieldByName("backendHandshakeAddresser")
+ return !field.IsNil()
+}
+
// TestRequiresRestart_EdgeCases tests edge cases for the restart logic
func TestRequiresRestart_EdgeCases(t *testing.T) {
tests := []struct {
diff --git a/pkg/edition/java/config/config.go b/pkg/edition/java/config/config.go
index aea877072..93d8b49a6 100644
--- a/pkg/edition/java/config/config.go
+++ b/pkg/edition/java/config/config.go
@@ -2,6 +2,7 @@ package config
import (
"fmt"
+ "os"
"strings"
"time"
@@ -244,8 +245,12 @@ func (c *Config) Validate() (warns []error, errs []error) {
w("Packet limiter has a rate set but interval <= 0; the limiter is disabled. Set packetLimiter.interval > 0 to enable it.")
}
+ validateBackendFloodgate(c, e)
if c.Lite.Enabled {
- return c.Lite.Validate()
+ warns2, errs2 := c.Lite.Validate()
+ warns = append(warns, warns2...)
+ errs = append(errs, errs2...)
+ return
}
validateVia(c, e)
@@ -307,6 +312,61 @@ func (c *Config) Validate() (warns []error, errs []error) {
return
}
+func validateBackendFloodgate(c *Config, e func(string, ...any)) {
+ backendFloodgate := c.Bedrock.BackendFloodgate
+ if !backendFloodgate.Enabled {
+ return
+ }
+ if !c.Bedrock.Enabled {
+ e("bedrock.backendFloodgate requires bedrock.enabled")
+ }
+ if len(backendFloodgate.AllowedServers) == 0 {
+ e("bedrock.backendFloodgate.allowedServers must not be empty")
+ }
+
+ servers := make(map[string]struct{}, len(c.Servers))
+ for name := range c.Servers {
+ servers[strings.ToLower(name)] = struct{}{}
+ }
+ seen := make(map[string]struct{}, len(backendFloodgate.AllowedServers))
+ for _, name := range backendFloodgate.AllowedServers {
+ if !validation.ValidServerName(name) {
+ e("Invalid bedrock.backendFloodgate.allowedServers server name %q: %s and length be 1-%d", name,
+ validation.QualifiedNameErrMsg, validation.QualifiedNameMaxLength)
+ continue
+ }
+ normalized := strings.ToLower(name)
+ if _, ok := seen[normalized]; ok {
+ e("Duplicate bedrock.backendFloodgate.allowedServers server %q", name)
+ continue
+ }
+ seen[normalized] = struct{}{}
+ if _, ok := servers[normalized]; !ok {
+ e("bedrock.backendFloodgate.allowedServers server %q must be registered under servers", name)
+ }
+ }
+
+ switch c.Forwarding.Mode {
+ case NoneForwardingMode, VelocityForwardingMode:
+ case LegacyForwardingMode, BungeeGuardForwardingMode:
+ e("bedrock.backendFloodgate is incompatible with forwarding.mode %q", c.Forwarding.Mode)
+ default:
+ e("bedrock.backendFloodgate requires forwarding.mode none or velocity, got %q", c.Forwarding.Mode)
+ }
+
+ bedrockConfig := c.Bedrock.ToConfig()
+ if bedrockConfig.FloodgateKeyPath == "" {
+ e("bedrock.backendFloodgate requires readable floodgateKeyPath")
+ return
+ }
+ if _, err := os.ReadFile(bedrockConfig.FloodgateKeyPath); err != nil {
+ if os.IsNotExist(err) && bedrockConfig.GetManaged().Enabled {
+ return
+ }
+ e("bedrock.backendFloodgate requires readable floodgateKeyPath %q: %v", bedrockConfig.FloodgateKeyPath, err)
+ }
+}
+
func validateVia(c *Config, e func(string, ...any)) {
if !c.Via.Enabled {
return
diff --git a/pkg/edition/java/config/config_test.go b/pkg/edition/java/config/config_test.go
index cf68d5048..e2c1a00f0 100644
--- a/pkg/edition/java/config/config_test.go
+++ b/pkg/edition/java/config/config_test.go
@@ -1,6 +1,8 @@
package config
import (
+ "os"
+ "path/filepath"
"reflect"
"strings"
"testing"
@@ -11,6 +13,7 @@ import (
bconfig "go.minekube.com/gate/pkg/edition/bedrock/config"
liteconfig "go.minekube.com/gate/pkg/edition/java/lite/config"
+ "go.minekube.com/gate/pkg/util/configutil"
)
func Test_texts(t *testing.T) {
@@ -93,6 +96,141 @@ func TestViaConfigIgnoredInLiteMode(t *testing.T) {
require.Empty(t, errs)
}
+func TestBackendFloodgateValidation(t *testing.T) {
+ t.Run("disabled by default", func(t *testing.T) {
+ cfg := DefaultConfig
+ cfg.Forwarding.Mode = NoneForwardingMode
+ cfg.Servers = map[string]string{"lobby": "127.0.0.1:25566"}
+ cfg.Try = []string{"lobby"}
+
+ _, errs := cfg.Validate()
+ require.Empty(t, errs)
+ })
+
+ t.Run("enabled requires bedrock", func(t *testing.T) {
+ cfg := validBackendFloodgateConfig(t)
+ cfg.Bedrock.Enabled = false
+
+ _, errs := cfg.Validate()
+ requireErrorContains(t, errs, "bedrock.backendFloodgate requires bedrock.enabled")
+ })
+
+ t.Run("enabled requires bedrock in lite mode", func(t *testing.T) {
+ cfg := validBackendFloodgateConfig(t)
+ cfg.Lite = liteconfig.Config{
+ Enabled: true,
+ Routes: []liteconfig.Route{{
+ Host: []string{"example.com"},
+ Backend: []string{"127.0.0.1:25566"},
+ }},
+ }
+ cfg.Bedrock.Enabled = false
+
+ _, errs := cfg.Validate()
+ requireErrorContains(t, errs, "bedrock.backendFloodgate requires bedrock.enabled")
+ })
+
+ t.Run("enabled requires allowed servers", func(t *testing.T) {
+ cfg := validBackendFloodgateConfig(t)
+ cfg.Bedrock.BackendFloodgate.AllowedServers = nil
+
+ _, errs := cfg.Validate()
+ requireErrorContains(t, errs, "bedrock.backendFloodgate.allowedServers must not be empty")
+ })
+
+ t.Run("allowed servers must exist", func(t *testing.T) {
+ cfg := validBackendFloodgateConfig(t)
+ cfg.Bedrock.BackendFloodgate.AllowedServers = []string{"missing"}
+
+ _, errs := cfg.Validate()
+ requireErrorContains(t, errs, `bedrock.backendFloodgate.allowedServers server "missing" must be registered under servers`)
+ })
+
+ t.Run("allowed servers are case-normalized", func(t *testing.T) {
+ cfg := validBackendFloodgateConfig(t)
+ cfg.Bedrock.BackendFloodgate.AllowedServers = []string{"Lobby"}
+
+ _, errs := cfg.Validate()
+ require.Empty(t, errs)
+ })
+
+ t.Run("enabled requires floodgate key unless managed can generate it", func(t *testing.T) {
+ cfg := validBackendFloodgateConfig(t)
+ cfg.Bedrock.FloodgateKeyPath = filepath.Join(t.TempDir(), "missing.key")
+
+ _, errs := cfg.Validate()
+ requireErrorContains(t, errs, "bedrock.backendFloodgate requires readable floodgateKeyPath")
+
+ cfg.Bedrock.Managed = bconfig.BoolOrManagedGeyser{}
+ cfg.Bedrock.Managed = configutil.NewBoolOrStructBool[bconfig.ManagedGeyser](true)
+ _, errs = cfg.Validate()
+ require.Empty(t, errs)
+ })
+
+ t.Run("forwarding mode compatibility", func(t *testing.T) {
+ for _, mode := range []ForwardingMode{NoneForwardingMode, VelocityForwardingMode} {
+ cfg := validBackendFloodgateConfig(t)
+ cfg.Forwarding.Mode = mode
+ _, errs := cfg.Validate()
+ require.Empty(t, errs, "mode %q should be allowed", mode)
+ }
+
+ for _, mode := range []ForwardingMode{LegacyForwardingMode, BungeeGuardForwardingMode} {
+ cfg := validBackendFloodgateConfig(t)
+ cfg.Forwarding.Mode = mode
+ _, errs := cfg.Validate()
+ requireErrorContains(t, errs, "bedrock.backendFloodgate is incompatible with forwarding.mode")
+ }
+ })
+
+ t.Run("unknown forwarding mode is rejected in lite mode", func(t *testing.T) {
+ cfg := validBackendFloodgateConfig(t)
+ cfg.Lite = liteconfig.Config{
+ Enabled: true,
+ Routes: []liteconfig.Route{{
+ Host: []string{"example.com"},
+ Backend: []string{"127.0.0.1:25566"},
+ }},
+ }
+ cfg.Forwarding.Mode = "typo"
+
+ _, errs := cfg.Validate()
+ requireErrorContains(t, errs, "bedrock.backendFloodgate requires forwarding.mode none or velocity")
+ })
+}
+
+func validBackendFloodgateConfig(t *testing.T) Config {
+ t.Helper()
+
+ keyPath := filepath.Join(t.TempDir(), "floodgate.key")
+ require.NoError(t, os.WriteFile(keyPath, []byte("0123456789abcdef"), 0o600))
+
+ cfg := DefaultConfig
+ cfg.Forwarding.Mode = NoneForwardingMode
+ cfg.Servers = map[string]string{
+ "lobby": "127.0.0.1:25566",
+ "survival": "127.0.0.1:25567",
+ }
+ cfg.Try = []string{"lobby"}
+ cfg.Bedrock.Enabled = true
+ cfg.Bedrock.FloodgateKeyPath = keyPath
+ cfg.Bedrock.BackendFloodgate = bconfig.BackendFloodgate{
+ Enabled: true,
+ AllowedServers: []string{"lobby"},
+ }
+ return cfg
+}
+
+func requireErrorContains(t *testing.T, errs []error, want string) {
+ t.Helper()
+ for _, err := range errs {
+ if strings.Contains(err.Error(), want) {
+ return
+ }
+ }
+ t.Fatalf("expected error containing %q, got %v", want, errs)
+}
+
func TestBedrockConfig_ManagedShorthand(t *testing.T) {
yamlConfig := `
bedrock:
diff --git a/pkg/edition/java/cookie/internal.go b/pkg/edition/java/cookie/internal.go
index d5ad1fa4c..a409f25f5 100644
--- a/pkg/edition/java/cookie/internal.go
+++ b/pkg/edition/java/cookie/internal.go
@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
- "strings"
"sync"
"github.com/robinbraemer/event"
@@ -12,6 +11,7 @@ import (
"go.minekube.com/gate/pkg/edition/java/internal/methods"
pkt "go.minekube.com/gate/pkg/edition/java/proto/packet/cookie"
"go.minekube.com/gate/pkg/edition/java/proto/state/states"
+ protoutils "go.minekube.com/gate/pkg/edition/java/proto/util"
"go.minekube.com/gate/pkg/edition/java/proto/version"
"go.minekube.com/gate/pkg/edition/java/proxy"
@@ -25,13 +25,7 @@ func validate(c *Cookie, cli Client) error {
}
func validateKey(key key.Key) error {
- if key == nil {
- return errors.New("key is nil")
- }
- if strings.TrimSpace(key.String()) == "" {
- return errors.New("empty key")
- }
- return nil
+ return protoutils.ValidateKey(key)
}
func validateCookie(c *Cookie) error {
diff --git a/pkg/edition/java/cookie/internal_test.go b/pkg/edition/java/cookie/internal_test.go
new file mode 100644
index 000000000..9ffe34c2f
--- /dev/null
+++ b/pkg/edition/java/cookie/internal_test.go
@@ -0,0 +1,22 @@
+package cookie
+
+import (
+ "testing"
+
+ "go.minekube.com/common/minecraft/key"
+)
+
+func TestValidateKeyRejectsInvalidResourceLocations(t *testing.T) {
+ for _, invalid := range []key.Key{
+ key.New("MineKube", "cookie"),
+ key.New("minecraft", "BadCookie"),
+ key.New("mine kube", "cookie"),
+ key.New("..", "cookie"),
+ } {
+ t.Run(invalid.String(), func(t *testing.T) {
+ if err := validateKey(invalid); err == nil {
+ t.Fatalf("validateKey(%q) succeeded, want error", invalid)
+ }
+ })
+ }
+}
diff --git a/pkg/edition/java/netmc/connection.go b/pkg/edition/java/netmc/connection.go
index 55e9647d4..4e0d07fb9 100644
--- a/pkg/edition/java/netmc/connection.go
+++ b/pkg/edition/java/netmc/connection.go
@@ -76,6 +76,11 @@ type MinecraftConn interface { // TODO convert to exported struct as this interf
// Default is true.
SetAutoReading(bool)
+ // SetOutboundState switches only the connection's outbound writer state.
+ // Use this for protocol phases where the local reader must remain in its
+ // current state until the peer confirms its transition.
+ SetOutboundState(state *state.Registry)
+
StateChanger
PacketWriter
@@ -529,6 +534,15 @@ func (c *minecraftConn) SetState(s *state.Registry) {
}
}
+func (c *minecraftConn) SetOutboundState(s *state.Registry) {
+ c.mu.Lock()
+ c.wr.SetState(s)
+ c.ensurePlayPacketQueue(s.State)
+ c.mu.Unlock()
+
+ c.log.V(1).Info("update outbound state", "new", s)
+}
+
func (c *minecraftConn) EnablePlayPacketQueue() {
if c.mu.TryLock() {
defer c.mu.Unlock()
diff --git a/pkg/edition/java/netmc/connection_state_test.go b/pkg/edition/java/netmc/connection_state_test.go
new file mode 100644
index 000000000..ceecc132f
--- /dev/null
+++ b/pkg/edition/java/netmc/connection_state_test.go
@@ -0,0 +1,63 @@
+package netmc
+
+import (
+ "bytes"
+ "context"
+ "net"
+ "testing"
+ "time"
+
+ "go.minekube.com/common/minecraft/component"
+ "go.minekube.com/gate/pkg/edition/java/proto/packet"
+ "go.minekube.com/gate/pkg/edition/java/proto/packet/chat"
+ "go.minekube.com/gate/pkg/edition/java/proto/state"
+ "go.minekube.com/gate/pkg/edition/java/proto/version"
+ "go.minekube.com/gate/pkg/gate/proto"
+)
+
+func TestSetOutboundStateReleasesPlayPacketQueue(t *testing.T) {
+ base := &recordingConn{}
+ conn, _ := NewMinecraftConn(
+ context.Background(),
+ base,
+ proto.ServerBound,
+ time.Second,
+ time.Second,
+ -1,
+ nil,
+ )
+ conn.SetProtocol(version.Minecraft_1_21_6.Protocol)
+ conn.SetState(state.Config)
+
+ err := conn.BufferPacket(&packet.HeaderAndFooter{
+ Header: *chat.FromComponent(new(component.Text)),
+ Footer: *chat.FromComponent(new(component.Text)),
+ })
+ if err != nil {
+ t.Fatalf("buffer play packet in config state: %v", err)
+ }
+ if base.Len() != 0 {
+ t.Fatalf("play packet was written before outbound play state, wrote %d bytes", base.Len())
+ }
+
+ conn.SetOutboundState(state.Play)
+
+ if base.Len() == 0 {
+ t.Fatal("queued play packet was not released when outbound state switched to play")
+ }
+ if conn.State() != state.Config {
+ t.Fatalf("SetOutboundState changed inbound state: got %v, want %v", conn.State(), state.Config)
+ }
+}
+
+type recordingConn struct {
+ bytes.Buffer
+}
+
+func (c *recordingConn) Read([]byte) (int, error) { select {} }
+func (c *recordingConn) Close() error { return nil }
+func (c *recordingConn) LocalAddr() net.Addr { return &net.TCPAddr{} }
+func (c *recordingConn) RemoteAddr() net.Addr { return &net.TCPAddr{} }
+func (c *recordingConn) SetDeadline(time.Time) error { return nil }
+func (c *recordingConn) SetReadDeadline(time.Time) error { return nil }
+func (c *recordingConn) SetWriteDeadline(time.Time) error { return nil }
diff --git a/pkg/edition/java/proto/packet/chat/component_holder.go b/pkg/edition/java/proto/packet/chat/component_holder.go
index 3e1006e7d..21e24d39b 100644
--- a/pkg/edition/java/proto/packet/chat/component_holder.go
+++ b/pkg/edition/java/proto/packet/chat/component_holder.go
@@ -1,6 +1,7 @@
package chat
import (
+ "bytes"
"encoding/json"
"fmt"
"io"
@@ -140,16 +141,48 @@ func (c *ComponentHolder) AsJson() (json.RawMessage, error) {
}
func componentObjectJSON(j json.RawMessage) (json.RawMessage, error) {
- if len(j) == 0 || j[0] != '"' {
+ if len(j) == 0 {
return j, nil
}
- var text string
- if err := json.Unmarshal(j, &text); err != nil {
+ dec := json.NewDecoder(bytes.NewReader(j))
+ dec.UseNumber()
+ var value any
+ if err := dec.Decode(&value); err != nil {
return nil, err
}
- return json.Marshal(struct {
- Text string `json:"text"`
- }{Text: text})
+ if err := dec.Decode(new(any)); err != io.EOF {
+ if err == nil {
+ return nil, fmt.Errorf("invalid component JSON: trailing value")
+ }
+ return nil, err
+ }
+ return json.Marshal(componentObjectValue(value))
+}
+
+func componentObjectValue(value any) any {
+ switch v := value.(type) {
+ case string:
+ return map[string]any{"text": v}
+ case []any:
+ for i, item := range v {
+ v[i] = componentObjectValue(item)
+ }
+ return v
+ case map[string]any:
+ for _, key := range []string{"extra", "with"} {
+ if item, ok := v[key]; ok {
+ v[key] = componentObjectValue(item)
+ }
+ }
+ for _, key := range []string{"separator"} {
+ if item, ok := v[key]; ok && item != nil {
+ v[key] = componentObjectValue(item)
+ }
+ }
+ return v
+ default:
+ return value
+ }
}
func (c *ComponentHolder) AsJsonOrNil() json.RawMessage {
diff --git a/pkg/edition/java/proto/packet/chat/component_holder_test.go b/pkg/edition/java/proto/packet/chat/component_holder_test.go
index 2427789e1..4ffee6728 100644
--- a/pkg/edition/java/proto/packet/chat/component_holder_test.go
+++ b/pkg/edition/java/proto/packet/chat/component_holder_test.go
@@ -4,6 +4,7 @@ import (
"testing"
"github.com/stretchr/testify/require"
+ "go.minekube.com/common/minecraft/color"
"go.minekube.com/common/minecraft/component"
"go.minekube.com/gate/pkg/edition/java/proto/nbtconv"
@@ -49,3 +50,68 @@ func TestComponentHolderAsJsonExpandsCachedCompactTextComponent(t *testing.T) {
require.NoError(t, err)
require.JSONEq(t, `{"text":"hi"}`, string(got))
}
+
+func TestComponentHolderAsJsonRejectsTrailingJSONValue(t *testing.T) {
+ holder := &ComponentHolder{
+ Protocol: version.Minecraft_1_21_11.Protocol,
+ JSON: []byte(`{"text":"hi"} {"text":"bye"}`),
+ }
+
+ _, err := holder.AsJson()
+ require.Error(t, err)
+}
+
+func TestComponentHolderAsBinaryTagHandlesEmptyModernTextComponent(t *testing.T) {
+ holder := &ComponentHolder{
+ Protocol: version.Minecraft_1_21_6.Protocol,
+ Component: &component.Text{},
+ }
+
+ j, err := holder.AsJson()
+ require.NoError(t, err)
+ require.JSONEq(t, `{"text":""}`, string(j))
+
+ _, err = holder.AsBinaryTag()
+ require.NoError(t, err)
+}
+
+func TestComponentHolderAsBinaryTagHandlesEmptyModernTranslationComponent(t *testing.T) {
+ holder := &ComponentHolder{
+ Protocol: version.Minecraft_1_21_6.Protocol,
+ Component: &component.Translation{},
+ }
+
+ j, err := holder.AsJson()
+ require.NoError(t, err)
+ require.JSONEq(t, `{"translate":""}`, string(j))
+
+ _, err = holder.AsBinaryTag()
+ require.NoError(t, err)
+}
+
+func TestComponentHolderAsBinaryTagHandlesModernStyledTextWithChildren(t *testing.T) {
+ holder := &ComponentHolder{
+ Protocol: version.Minecraft_1_21_6.Protocol,
+ Component: &component.Text{
+ S: component.Style{Color: color.Gray},
+ Extra: []component.Component{
+ &component.Text{Content: " \nConnect Network\n\n", S: component.Style{Color: color.Gold, Bold: component.True}},
+ &component.Text{Content: "Browse localhost & public servers!\n"},
+ },
+ },
+ }
+
+ j, err := holder.AsJson()
+ require.NoError(t, err)
+ require.JSONEq(t, `{
+ "color":"#aaaaaa",
+ "extra":[
+ {"bold":true,"color":"#ffaa00","text":" \nConnect Network\n\n"},
+ {"text":"Browse localhost & public servers!\n"}
+ ],
+ "text":""
+ }`, string(j))
+
+ _, err = holder.AsBinaryTag()
+ require.NoError(t, err)
+}
diff --git a/pkg/edition/java/proto/util/reader.go b/pkg/edition/java/proto/util/reader.go
index 0c6fe24f3..4a4416b02 100644
--- a/pkg/edition/java/proto/util/reader.go
+++ b/pkg/edition/java/proto/util/reader.go
@@ -437,7 +437,19 @@ func ReadUnixMilli(rd io.Reader) (time.Time, error) {
//
//
-const defaultKeySeparator = ":"
+// ValidateKey verifies that a key is a valid Minecraft resource location.
+func ValidateKey(k key.Key) error {
+ if k == nil {
+ return errors.New("key is nil")
+ }
+ if k.Namespace() == ".." {
+ return fmt.Errorf("invalid key %q: namespace must not be ..", k.String())
+ }
+ if !key.NamespaceValid(k.Namespace()) || !key.ValueValid(k.Value()) {
+ return fmt.Errorf("invalid key %q", k.String())
+ }
+ return nil
+}
// ReadKey reads a standard Mojang Text namespaced:key from the reader.
func ReadKey(rd io.Reader) (key.Key, error) {
@@ -445,15 +457,30 @@ func ReadKey(rd io.Reader) (key.Key, error) {
if err != nil {
return nil, err
}
- parts := strings.SplitN(str, defaultKeySeparator, 2)
- if len(parts) != 2 {
- return nil, errors.New("invalid key format")
+ k := parseIdentifierKey(str)
+ if err := ValidateKey(k); err != nil {
+ return nil, err
+ }
+ return k, nil
+}
+
+func parseIdentifierKey(str string) key.Key {
+ namespace := key.MinecraftNamespace
+ value := str
+ if separatorIndex := strings.IndexByte(str, ':'); separatorIndex >= 0 {
+ value = str[separatorIndex+1:]
+ if separatorIndex != 0 {
+ namespace = str[:separatorIndex]
+ }
}
- return key.New(parts[0], parts[1]), nil
+ return key.New(namespace, value)
}
// WriteKey writes a standard Mojang Text namespaced:key to the writer.
func WriteKey(wr io.Writer, k key.Key) error {
+ if err := ValidateKey(k); err != nil {
+ return err
+ }
return WriteString(wr, k.String())
}
diff --git a/pkg/edition/java/proto/util/writer_test.go b/pkg/edition/java/proto/util/writer_test.go
index 9d91abea2..120912853 100644
--- a/pkg/edition/java/proto/util/writer_test.go
+++ b/pkg/edition/java/proto/util/writer_test.go
@@ -4,8 +4,68 @@ import (
"bytes"
"math"
"testing"
+
+ "go.minekube.com/common/minecraft/key"
)
+func TestReadKeyRejectsInvalidResourceLocations(t *testing.T) {
+ for _, raw := range []string{
+ "MineKube:cookie",
+ "minecraft:BadCookie",
+ "mine kube:cookie",
+ "..:cookie",
+ } {
+ t.Run(raw, func(t *testing.T) {
+ var buf bytes.Buffer
+ if err := WriteString(&buf, raw); err != nil {
+ t.Fatalf("failed to write raw key string: %v", err)
+ }
+
+ if got, err := ReadKey(&buf); err == nil {
+ t.Fatalf("ReadKey(%q) = %q, want error", raw, got)
+ }
+ })
+ }
+}
+
+func TestReadKeyDefaultsMissingNamespaceToMinecraft(t *testing.T) {
+ for raw, want := range map[string]key.Key{
+ "cookie": key.New(key.MinecraftNamespace, "cookie"),
+ ":cookie": key.New(key.MinecraftNamespace, "cookie"),
+ } {
+ t.Run(raw, func(t *testing.T) {
+ var buf bytes.Buffer
+ if err := WriteString(&buf, raw); err != nil {
+ t.Fatalf("failed to write raw key string: %v", err)
+ }
+
+ got, err := ReadKey(&buf)
+ if err != nil {
+ t.Fatalf("ReadKey(%q) returned error: %v", raw, err)
+ }
+ if got.String() != want.String() {
+ t.Fatalf("ReadKey(%q) = %q, want %q", raw, got, want)
+ }
+ })
+ }
+}
+
+func TestWriteKeyRejectsInvalidResourceLocations(t *testing.T) {
+ for _, invalid := range []key.Key{
+ key.New("MineKube", "cookie"),
+ key.New("minecraft", "BadCookie"),
+ key.New("mine kube", "cookie"),
+ key.New("..", "cookie"),
+ } {
+ t.Run(invalid.String(), func(t *testing.T) {
+ var buf bytes.Buffer
+ if err := WriteKey(&buf, invalid); err == nil {
+ t.Fatalf("WriteKey(%q) succeeded, want error", invalid)
+ }
+ })
+ }
+}
+
// TestWriteBytes17_NonExtended tests WriteBytes17 with allowExtended=false
// This is the case that was failing for 1.7.x clients with encryption requests
func TestWriteBytes17_NonExtended(t *testing.T) {
diff --git a/pkg/edition/java/proxy/backend_handshake_addresser_test.go b/pkg/edition/java/proxy/backend_handshake_addresser_test.go
new file mode 100644
index 000000000..633d59f4f
--- /dev/null
+++ b/pkg/edition/java/proxy/backend_handshake_addresser_test.go
@@ -0,0 +1,143 @@
+package proxy
+
+import (
+ "errors"
+ "strings"
+ "testing"
+
+ "github.com/go-logr/logr"
+ "github.com/stretchr/testify/require"
+
+ "go.minekube.com/gate/pkg/edition/java/config"
+ "go.minekube.com/gate/pkg/edition/java/forge"
+ "go.minekube.com/gate/pkg/edition/java/profile"
+ "go.minekube.com/gate/pkg/edition/java/proto/packet"
+ "go.minekube.com/gate/pkg/edition/java/proxy/phase"
+ "go.minekube.com/gate/pkg/util/netutil"
+ "go.minekube.com/gate/pkg/util/uuid"
+)
+
+type staticBackendHandshakeAddresser struct {
+ gotDefaultHost string
+ gotPlayer Player
+ gotTarget RegisteredServer
+ nextHost string
+ err error
+}
+
+func (a *staticBackendHandshakeAddresser) BackendHandshakeAddr(defaultServerAddress string, player Player, target RegisteredServer) (string, error) {
+ a.gotDefaultHost = defaultServerAddress
+ a.gotPlayer = player
+ a.gotTarget = target
+ if a.err != nil {
+ return "", a.err
+ }
+ return a.nextHost, nil
+}
+
+func TestHandshakeAddrUsesBackendHandshakeAddresserWithTarget(t *testing.T) {
+ serverConn, player, target := newHandshakeAddrTestConnection(t, config.NoneForwardingMode, phase.Vanilla)
+ addresser := &staticBackendHandshakeAddresser{nextHost: "play.example.org\x00encrypted-floodgate-data"}
+ player.proxy.SetBackendHandshakeAddresser(addresser)
+
+ got, err := serverConn.handshakeAddr("play.example.org", player)
+
+ require.NoError(t, err)
+ require.Equal(t, "play.example.org", addresser.gotDefaultHost)
+ require.Same(t, player, addresser.gotPlayer)
+ require.Same(t, target, addresser.gotTarget)
+ require.Equal(t, "play.example.org\x00encrypted-floodgate-data", got)
+}
+
+func TestStartHandshakeReturnsBackendHandshakeAddresserErrorBeforeBufferingHandshake(t *testing.T) {
+ serverConn, player, _ := newHandshakeAddrTestConnection(t, config.NoneForwardingMode, phase.Vanilla)
+ wantErr := errors.New("backend floodgate encode failed")
+ player.proxy.SetBackendHandshakeAddresser(&staticBackendHandshakeAddresser{err: wantErr})
+ backendConn := &testMinecraftConn{}
+ serverConn.connection = backendConn
+
+ _, err := serverConn.startHandshake(func() {}, make(chan *connResponse, 1))
+
+ require.ErrorIs(t, err, wantErr)
+ require.Empty(t, backendConn.writtenPackets)
+}
+
+func TestHandshakeAddrPassesCleanHostToBackendAddresserForModernForge(t *testing.T) {
+ serverConn, player, _ := newHandshakeAddrTestConnection(t, config.NoneForwardingMode, phase.ModernForge)
+ player.virtualHost = netutil.NewAddr("play.example.org\x00FML3\x00:25565", "tcp")
+ addresser := &staticBackendHandshakeAddresser{nextHost: "play.example.org"}
+ player.proxy.SetBackendHandshakeAddresser(addresser)
+
+ got, err := serverConn.handshakeAddr("play.example.org\x00FML3\x00", player)
+
+ require.NoError(t, err)
+ require.Equal(t, "play.example.org", addresser.gotDefaultHost)
+ require.Equal(t, "\x00FML3\x00", got)
+}
+
+func TestHandshakeAddrPassesCleanHostToBackendAddresserForLegacyForge(t *testing.T) {
+ serverConn, player, _ := newHandshakeAddrTestConnection(t, config.NoneForwardingMode, phase.LegacyForge)
+ player.virtualHost = netutil.NewAddr("play.example.org\x00FML\x00:25565", "tcp")
+ addresser := &staticBackendHandshakeAddresser{nextHost: "play.example.org"}
+ player.proxy.SetBackendHandshakeAddresser(addresser)
+
+ got, err := serverConn.handshakeAddr("play.example.org\x00FML\x00", player)
+
+ require.NoError(t, err)
+ require.Equal(t, "play.example.org", addresser.gotDefaultHost)
+ require.Equal(t, "play.example.org"+forge.HandshakeHostnameToken, got)
+}
+
+func TestHandshakeAddrPreservesLegacyForwardingWhenBackendAddresserDisabled(t *testing.T) {
+ serverConn, player, _ := newHandshakeAddrTestConnection(t, config.LegacyForwardingMode, phase.ModernForge)
+ player.virtualHost = netutil.NewAddr("play.example.org\x00FML3\x00:25565", "tcp")
+
+ got, err := serverConn.handshakeAddr("play.example.org", serverConn.player)
+
+ require.NoError(t, err)
+ require.Equal(t, serverConn.createLegacyForwardingAddress(), got)
+ require.Contains(t, got, `"extraData"`)
+ require.False(t, strings.HasSuffix(got, "\x00FML3\x00"), "legacy forwarding already carries Forge metadata")
+}
+
+func TestStartHandshakeBuffersBackendHandshakeAddress(t *testing.T) {
+ serverConn, player, _ := newHandshakeAddrTestConnection(t, config.NoneForwardingMode, phase.Vanilla)
+ player.proxy.SetBackendHandshakeAddresser(&staticBackendHandshakeAddresser{nextHost: "play.example.org\x00encrypted-floodgate-data"})
+ backendConn := &testMinecraftConn{}
+ serverConn.connection = backendConn
+ resultChan := make(chan *connResponse, 1)
+ resultChan <- &connResponse{connectionResult: &connectionResult{}}
+
+ _, err := serverConn.startHandshake(func() {}, resultChan)
+
+ require.NoError(t, err)
+ require.Len(t, backendConn.writtenPackets, 2)
+ handshake, ok := backendConn.writtenPackets[0].(*packet.Handshake)
+ require.True(t, ok, "first packet = %T", backendConn.writtenPackets[0])
+ require.Equal(t, "play.example.org\x00encrypted-floodgate-data", handshake.ServerAddress)
+}
+
+func newHandshakeAddrTestConnection(t *testing.T, forwardingMode config.ForwardingMode, connType phase.ConnectionType) (*serverConnection, *connectedPlayer, RegisteredServer) {
+ t.Helper()
+
+ cfg := &config.Config{
+ Forwarding: config.Forwarding{Mode: forwardingMode},
+ }
+ p := &Proxy{cfg: cfg}
+ player := &connectedPlayer{
+ MinecraftConn: &testMinecraftConn{connType: connType},
+ sessionHandlerDeps: &sessionHandlerDeps{proxy: p, configProvider: p},
+ log: logr.Discard(),
+ profile: &profile.GameProfile{
+ ID: uuid.New(),
+ },
+ virtualHost: netutil.NewAddr("play.example.org:25565", "tcp"),
+ }
+ target := newRegisteredServer(NewServerInfo("backend", netutil.NewAddr("127.0.0.1:25566", "tcp")))
+ serverConn := &serverConnection{
+ server: target,
+ player: player,
+ log: logr.Discard(),
+ }
+ return serverConn, player, target
+}
diff --git a/pkg/edition/java/proxy/internal/resourcepack/handler_modern.go b/pkg/edition/java/proxy/internal/resourcepack/handler_modern.go
index 1cc6ee9f0..62b8d2f0a 100644
--- a/pkg/edition/java/proxy/internal/resourcepack/handler_modern.go
+++ b/pkg/edition/java/proxy/internal/resourcepack/handler_modern.go
@@ -149,16 +149,18 @@ func (m *modernHandler) OnResourcePackResponse(bundle *ResponseBundle) (bool, er
}
}
- e := newPlayerResourcePackStatusEvent(m.player, bundle.Status, queued.ID, *queued)
- event.FireParallel(m.eventMgr, e, func(e *PlayerResourcePackStatusEvent) {
- if e.Status() == packet.DeclinedResourcePackResponseStatus &&
- e.PackInfo().ShouldForce &&
- !e.OverwriteKick() {
- m.player.Disconnect(&component.Translation{
- Key: "multiplayer.requiredTexturePrompt.disconnect",
- })
- }
- })
+ if queued != nil {
+ e := newPlayerResourcePackStatusEvent(m.player, bundle.Status, id, *queued)
+ event.FireParallel(m.eventMgr, e, func(e *PlayerResourcePackStatusEvent) {
+ if e.Status() == packet.DeclinedResourcePackResponseStatus &&
+ e.PackInfo().ShouldForce &&
+ !e.OverwriteKick() {
+ m.player.Disconnect(&component.Translation{
+ Key: "multiplayer.requiredTexturePrompt.disconnect",
+ })
+ }
+ })
+ }
switch bundle.Status {
// The player has accepted the resource pack and will proceed to download it.
diff --git a/pkg/edition/java/proxy/internal/resourcepack/handler_modern_test.go b/pkg/edition/java/proxy/internal/resourcepack/handler_modern_test.go
new file mode 100644
index 000000000..ca2b54966
--- /dev/null
+++ b/pkg/edition/java/proxy/internal/resourcepack/handler_modern_test.go
@@ -0,0 +1,38 @@
+package resourcepack
+
+import (
+ "testing"
+
+ "github.com/robinbraemer/event"
+ "go.minekube.com/common/minecraft/component"
+ "go.minekube.com/gate/pkg/edition/java/proto/packet"
+ "go.minekube.com/gate/pkg/edition/java/proto/state"
+ "go.minekube.com/gate/pkg/edition/java/proto/version"
+ "go.minekube.com/gate/pkg/gate/proto"
+ "go.minekube.com/gate/pkg/util/uuid"
+)
+
+type testPlayer struct{}
+
+func (testPlayer) ID() uuid.UUID { return uuid.New() }
+func (testPlayer) WritePacket(proto.Packet) error { return nil }
+func (testPlayer) BundleHandler() *BundleDelimiterHandler { return nil }
+func (testPlayer) State() *state.Registry { return state.Play }
+func (testPlayer) Protocol() proto.Protocol { return version.Minecraft_1_20_3.Protocol }
+func (testPlayer) BackendInFlight() proto.PacketWriter { return nil }
+func (testPlayer) Disconnect(component.Component) {}
+
+func TestModernHandlerIgnoresUntrackedResourcePackResponse(t *testing.T) {
+ h := newModernHandler(testPlayer{}, event.Nop)
+
+ handled, err := h.OnResourcePackResponse(&ResponseBundle{
+ ID: uuid.New(),
+ Status: packet.SuccessfulResourcePackResponseStatus,
+ })
+ if err != nil {
+ t.Fatalf("OnResourcePackResponse returned error: %v", err)
+ }
+ if handled {
+ t.Fatal("OnResourcePackResponse handled untracked response")
+ }
+}
diff --git a/pkg/edition/java/proxy/proxy.go b/pkg/edition/java/proxy/proxy.go
index 63317cf3f..113743012 100644
--- a/pkg/edition/java/proxy/proxy.go
+++ b/pkg/edition/java/proxy/proxy.go
@@ -67,6 +67,10 @@ type Proxy struct {
sessionIDMu sync.Mutex
currentSessionID uuid.UUID
+ backendHandshakeAddresserMu sync.RWMutex
+ backendHandshakeAddresser BackendHandshakeAddresser
+ backendHandshakeAddresserID uint64
+
connectionsQuota *addrquota.Quota
loginsQuota *addrquota.Quota
@@ -429,6 +433,30 @@ func (p *Proxy) Lite() *lite.Lite {
return p.lite
}
+// SetBackendHandshakeAddresser sets a low-level hook applied to backend handshakes.
+// It returns an unregister function that only clears this registration.
+func (p *Proxy) SetBackendHandshakeAddresser(ha BackendHandshakeAddresser) func() {
+ p.backendHandshakeAddresserMu.Lock()
+ p.backendHandshakeAddresserID++
+ id := p.backendHandshakeAddresserID
+ p.backendHandshakeAddresser = ha
+ p.backendHandshakeAddresserMu.Unlock()
+
+ return func() {
+ p.backendHandshakeAddresserMu.Lock()
+ defer p.backendHandshakeAddresserMu.Unlock()
+ if p.backendHandshakeAddresserID == id {
+ p.backendHandshakeAddresser = nil
+ }
+ }
+}
+
+func (p *Proxy) backendHandshakeAddresserSnapshot() BackendHandshakeAddresser {
+ p.backendHandshakeAddresserMu.RLock()
+ defer p.backendHandshakeAddresserMu.RUnlock()
+ return p.backendHandshakeAddresser
+}
+
// Server gets a backend server registered with the proxy by name.
// Returns nil if not found.
func (p *Proxy) Server(name string) RegisteredServer {
diff --git a/pkg/edition/java/proxy/server.go b/pkg/edition/java/proxy/server.go
index 3f0ff7e98..0bf06e3e2 100644
--- a/pkg/edition/java/proxy/server.go
+++ b/pkg/edition/java/proxy/server.go
@@ -367,27 +367,74 @@ type HandshakeAddresser interface {
HandshakeAddr(defaultPlayerVirtualHost string, player Player) (newPlayerVirtualHost string)
}
-func (s *serverConnection) handshakeAddr(vHost string, player Player) string {
+// ForwardingModeProvider lets dynamic ServerInfo implementations select the
+// backend forwarding mode for this specific server registration.
+type ForwardingModeProvider interface {
+ ForwardingMode() config.ForwardingMode
+}
+
+// BackendVersionProvider lets dynamic ServerInfo implementations select the
+// backend Minecraft version used by protocol translation.
+type BackendVersionProvider interface {
+ BackendVersion() string
+}
+
+// ClientProtocolProvider lets dynamic ServerInfo implementations expose the
+// already-connected client protocol for per-player backend registration.
+type ClientProtocolProvider interface {
+ ClientProtocol() proto.Protocol
+}
+
+// BackendHandshakeAddresser provides the ServerAddress sent with the packet.Handshake
+// for integrations that need the target backend server context.
+type BackendHandshakeAddresser interface {
+ BackendHandshakeAddr(defaultServerAddress string, player Player, target RegisteredServer) (newServerAddress string, err error)
+}
+
+func (s *serverConnection) handshakeAddr(vHost string, player Player) (string, error) {
var ha HandshakeAddresser
var ok bool
+ usedForwarding := false
if ha, ok = s.Server().ServerInfo().(HandshakeAddresser); !ok {
if ha, ok = s.Server().(HandshakeAddresser); !ok {
switch s.config().Forwarding.Mode {
case config.LegacyForwardingMode:
- return s.createLegacyForwardingAddress()
+ vHost = s.createLegacyForwardingAddress()
+ usedForwarding = true
case config.BungeeGuardForwardingMode:
secret := s.config().Forwarding.BungeeGuardSecret
- return s.createBungeeGuardForwardingAddress(secret)
+ vHost = s.createBungeeGuardForwardingAddress(secret)
+ usedForwarding = true
}
}
}
if ha != nil {
vHost = ha.HandshakeAddr(vHost, player)
}
+ forgeTokenSource := vHost
+ if !usedForwarding {
+ if backendAddresser := s.player.proxy.backendHandshakeAddresserSnapshot(); backendAddresser != nil {
+ var err error
+ vHost, err = backendAddresser.BackendHandshakeAddr(backendHandshakeBaseHost(vHost, s.player.Type()), player, s.Server())
+ if err != nil {
+ return "", err
+ }
+ }
+ }
+ if usedForwarding {
+ return vHost, nil
+ }
if s.player.Type() == phase.LegacyForge {
vHost += forge.HandshakeHostnameToken
} else if s.player.Type() == phase.ModernForge {
- vHost = modernforge.ModernToken(vHost)
+ vHost = modernforge.ModernToken(forgeTokenSource)
+ }
+ return vHost, nil
+}
+
+func backendHandshakeBaseHost(vHost string, connType phase.ConnectionType) string {
+ if connType == phase.LegacyForge || connType == phase.ModernForge {
+ return strings.SplitN(vHost, "\x00", 2)[0]
}
return vHost
}
@@ -479,7 +526,11 @@ func (s *serverConnection) startHandshake(
if playerVHost == "" {
playerVHost = netutil.Host(s.server.ServerInfo().Addr())
}
- handshake.ServerAddress = s.handshakeAddr(playerVHost, s.player)
+ serverAddress, err := s.handshakeAddr(playerVHost, s.player)
+ if err != nil {
+ return nil, fmt.Errorf("error resolving backend handshake address: %w", err)
+ }
+ handshake.ServerAddress = serverAddress
}
if err := serverMc.BufferPacket(handshake); err != nil {
return nil, fmt.Errorf("error buffer handshake packet in server connection: %w", err)
diff --git a/pkg/edition/java/proxy/session_backend_login.go b/pkg/edition/java/proxy/session_backend_login.go
index 09bab1585..dc15b2f0e 100644
--- a/pkg/edition/java/proxy/session_backend_login.go
+++ b/pkg/edition/java/proxy/session_backend_login.go
@@ -309,6 +309,12 @@ func (b *backendLoginSessionHandler) handleServerLoginSuccess() {
}
ash := player.ActiveSessionHandler()
+ if csh, ok := ash.(*clientConfigSessionHandler); ok {
+ if err = csh.flushQueuedPluginMessagesTo(b.serverConn); err != nil {
+ fail(err)
+ return
+ }
+ }
csh, ok := ash.(*clientPlaySessionHandler)
if ok {
serverMc.SetAutoReading(false)
diff --git a/pkg/edition/java/proxy/session_backend_play_test.go b/pkg/edition/java/proxy/session_backend_play_test.go
index 8906da8df..850a7b5fa 100644
--- a/pkg/edition/java/proxy/session_backend_play_test.go
+++ b/pkg/edition/java/proxy/session_backend_play_test.go
@@ -55,6 +55,8 @@ func TestBackendPlayRegisterForwardsToPlayer(t *testing.T) {
type testMinecraftConn struct {
writtenPackets []proto.Packet
connType phase.ConnectionType
+ activeHandler netmc.SessionHandler
+ writer netmc.Writer
}
func (t *testMinecraftConn) Context() context.Context { return context.Background() }
@@ -70,15 +72,19 @@ func (t *testMinecraftConn) Type() phase.ConnectionType {
return phase.Vanilla
}
func (t *testMinecraftConn) SetType(ct phase.ConnectionType) { t.connType = ct }
-func (t *testMinecraftConn) ActiveSessionHandler() netmc.SessionHandler { return nil }
-func (t *testMinecraftConn) SetActiveSessionHandler(*state.Registry, netmc.SessionHandler) {
+func (t *testMinecraftConn) ActiveSessionHandler() netmc.SessionHandler { return t.activeHandler }
+func (t *testMinecraftConn) SetActiveSessionHandler(_ *state.Registry, handler netmc.SessionHandler) {
+ t.activeHandler = handler
}
func (t *testMinecraftConn) SwitchSessionHandler(*state.Registry) bool { return true }
func (t *testMinecraftConn) AddSessionHandler(*state.Registry, netmc.SessionHandler) {
}
-func (t *testMinecraftConn) SetAutoReading(bool) {}
-func (t *testMinecraftConn) SetProtocol(proto.Protocol) {}
-func (t *testMinecraftConn) SetState(*state.Registry) {}
+func (t *testMinecraftConn) SetAutoReading(bool) {}
+func (t *testMinecraftConn) SetProtocol(proto.Protocol) {}
+func (t *testMinecraftConn) SetState(*state.Registry) {}
+func (t *testMinecraftConn) SetOutboundState(s *state.Registry) {
+ t.Writer().SetState(s)
+}
func (t *testMinecraftConn) SetCompressionThreshold(int) error { return nil }
func (t *testMinecraftConn) EnableEncryption([]byte) error { return nil }
func (t *testMinecraftConn) WritePacket(packet proto.Packet) error {
@@ -93,7 +99,25 @@ func (t *testMinecraftConn) BufferPacket(packet proto.Packet) error {
func (t *testMinecraftConn) BufferPayload([]byte) error { return nil }
func (t *testMinecraftConn) Flush() error { return nil }
func (t *testMinecraftConn) Reader() netmc.Reader { return nil }
-func (t *testMinecraftConn) Writer() netmc.Writer { return nil }
-func (t *testMinecraftConn) EnablePlayPacketQueue() {}
+func (t *testMinecraftConn) Writer() netmc.Writer {
+ if t.writer == nil {
+ t.writer = &testWriter{}
+ }
+ return t.writer
+}
+func (t *testMinecraftConn) EnablePlayPacketQueue() {}
var _ netmc.MinecraftConn = (*testMinecraftConn)(nil)
+
+type testWriter struct {
+ state *state.Registry
+}
+
+func (t *testWriter) WritePacket(proto.Packet) (int, error) { return 0, nil }
+func (t *testWriter) Write([]byte) (int, error) { return 0, nil }
+func (t *testWriter) Flush() error { return nil }
+func (t *testWriter) SetProtocol(proto.Protocol) {}
+func (t *testWriter) SetState(s *state.Registry) { t.state = s }
+func (t *testWriter) SetCompressionThreshold(int) error { return nil }
+func (t *testWriter) EnableEncryption([]byte) error { return nil }
+func (t *testWriter) Direction() proto.Direction { return proto.ClientBound }
diff --git a/pkg/edition/java/proxy/session_client_config.go b/pkg/edition/java/proxy/session_client_config.go
index 23ce5a814..a8736a7e9 100644
--- a/pkg/edition/java/proxy/session_client_config.go
+++ b/pkg/edition/java/proxy/session_client_config.go
@@ -2,9 +2,13 @@ package proxy
import (
"bytes"
+ "fmt"
+ "sync"
+ "github.com/gammazero/deque"
"github.com/go-logr/logr"
"github.com/robinbraemer/event"
+ "go.minekube.com/common/minecraft/component"
"go.minekube.com/gate/pkg/edition/java/netmc"
"go.minekube.com/gate/pkg/edition/java/proto/packet"
"go.minekube.com/gate/pkg/edition/java/proto/packet/config"
@@ -22,10 +26,18 @@ type clientConfigSessionHandler struct {
player *connectedPlayer
log logr.Logger
- brandChannel string
-
configSwitchDone future.Future[any]
+ mu struct {
+ sync.Mutex
+ pluginMessages deque.Deque[*plugin.Message]
+ pluginMessagesBytes int
+ pluginMessagesOverflowed bool
+ brandChannel string
+ brandForwardedServer *serverConnection
+ readyServer *serverConnection
+ }
+
nopSessionHandler
}
@@ -80,26 +92,19 @@ func (h *clientConfigSessionHandler) HandlePacket(pc *proto.PacketContext) {
// handleBackendFinishUpdate handles the backend finishing the config stage.
func (h *clientConfigSessionHandler) handleBackendFinishUpdate(serverConn *serverConnection, p *config.FinishedUpdate) *future.Future[any] {
- smc, ok := serverConn.ensureConnected()
+ _, ok := serverConn.ensureConnected()
if !ok {
return nil
}
brand := serverConn.player.ClientBrand()
- if brand == "" && h.brandChannel != "" {
- buf := new(bytes.Buffer)
- _ = util.WriteString(buf, brand)
-
- brandPacket := &plugin.Message{
- Channel: h.brandChannel,
- Data: buf.Bytes(),
- }
- _ = smc.WritePacket(brandPacket)
+ if brand != "" {
+ h.writeBrandPacketTo(serverConn, brand)
}
if err := h.player.WritePacket(p); err != nil {
return nil
}
- h.player.Writer().SetState(state.Play)
+ h.player.SetOutboundState(state.Play)
return &h.configSwitchDone
}
@@ -115,23 +120,29 @@ func handleResourcePackResponse(p *packet.ResourcePackResponse, handler resource
}
func (h *clientConfigSessionHandler) handlePluginMessage(p *plugin.Message) {
- serverConn := h.player.connectionInFlight()
- if serverConn == nil {
- return
- }
-
if plugin.McBrand(p) {
brand := plugin.ReadBrandMessage(p.Data)
- h.brandChannel = p.Channel
+ h.player.setClientBrand(brand)
+ readyServer := h.setBrandChannel(p.Channel)
h.event().FireParallel(&PlayerClientBrandEvent{
player: h.player,
brand: brand,
})
// Client sends `minecraft:brand` packet immediately after Login,
// but at this time the backend server may not be ready
+ if readyServer != nil {
+ h.writeBrandPacketTo(readyServer, brand)
+ }
+ return
} else if bungeecord.IsBungeeCordMessage(p) {
return
+ } else if h.enqueuePluginMessage(h.player.connectionInFlightOrConnectedServer(), p) {
+ return
} else {
+ serverConn := h.player.connectionInFlightOrConnectedServer()
+ if serverConn == nil {
+ return
+ }
id, ok := h.player.proxy.ChannelRegistrar().FromID(p.Channel)
if !ok {
smc, ok := serverConn.ensureConnected()
@@ -164,8 +175,127 @@ func (h *clientConfigSessionHandler) handlePluginMessage(p *plugin.Message) {
}
}
+func (h *clientConfigSessionHandler) setBrandChannel(channel string) *serverConnection {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ h.mu.brandChannel = channel
+ return h.mu.readyServer
+}
+
+func (h *clientConfigSessionHandler) brandPacket(brand string) *plugin.Message {
+ h.mu.Lock()
+ channel := h.mu.brandChannel
+ h.mu.Unlock()
+ if channel == "" {
+ return nil
+ }
+ buf := new(bytes.Buffer)
+ _ = util.WriteString(buf, brand)
+ return &plugin.Message{
+ Channel: channel,
+ Data: buf.Bytes(),
+ }
+}
+
+func (h *clientConfigSessionHandler) writeBrandPacketTo(serverConn *serverConnection, brand string) {
+ h.mu.Lock()
+ if h.mu.brandForwardedServer == serverConn {
+ h.mu.Unlock()
+ return
+ }
+ h.mu.Unlock()
+
+ brandPacket := h.brandPacket(brand)
+ if brandPacket == nil {
+ return
+ }
+ smc, ok := serverConn.ensureConnected()
+ if !ok {
+ return
+ }
+ if err := smc.WritePacket(brandPacket); err != nil {
+ return
+ }
+
+ h.mu.Lock()
+ h.mu.brandForwardedServer = serverConn
+ h.mu.Unlock()
+}
+
+// enqueuePluginMessage returns true when the message was handled by the queue
+// path, including overflow rejection. It returns false only once the backend is
+// ready for direct config plugin messages.
+func (h *clientConfigSessionHandler) enqueuePluginMessage(target *serverConnection, msg *plugin.Message) bool {
+ h.mu.Lock()
+ if target != nil && h.mu.readyServer == target {
+ h.mu.Unlock()
+ return false
+ }
+ if h.mu.pluginMessagesOverflowed {
+ h.mu.Unlock()
+ return true
+ }
+ newBytes := h.mu.pluginMessagesBytes + len(msg.Data)
+ newCount := h.mu.pluginMessages.Len() + 1
+ if newBytes > maxQueuedLoginPluginMessageBytes || newCount > maxQueuedLoginPluginMessages {
+ h.mu.pluginMessagesOverflowed = true
+ h.mu.pluginMessages.Clear()
+ h.mu.pluginMessagesBytes = 0
+ h.mu.Unlock()
+ h.log.Info("disconnecting player: pre-backend config plugin message queue exceeded its limits",
+ "messages", newCount, "bytes", newBytes)
+ h.player.Disconnect(&component.Text{
+ Content: "Too many plugin messages were sent before joining a server",
+ })
+ return true
+ }
+ h.mu.pluginMessages.PushBack(&plugin.Message{
+ Channel: msg.Channel,
+ Data: append([]byte(nil), msg.Data...),
+ })
+ h.mu.pluginMessagesBytes = newBytes
+ h.mu.Unlock()
+ return true
+}
+
+func (h *clientConfigSessionHandler) flushQueuedPluginMessagesTo(serverConn *serverConnection) error {
+ smc, ok := serverConn.ensureConnected()
+ if !ok {
+ return netmc.ErrClosedConn
+ }
+
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ if h.mu.readyServer == serverConn {
+ return nil
+ }
+
+ h.mu.pluginMessagesBytes = 0
+ n := h.mu.pluginMessages.Len()
+ msgs := make([]*plugin.Message, 0, n)
+ for h.mu.pluginMessages.Len() != 0 {
+ msgs = append(msgs, h.mu.pluginMessages.PopFront())
+ }
+ for _, pm := range msgs {
+ if err := smc.BufferPacket(pm); err != nil {
+ return fmt.Errorf("error buffering queued config plugin message %q: %w", pm.Channel, err)
+ }
+ }
+ if n != 0 {
+ if err := smc.Flush(); err != nil {
+ return err
+ }
+ }
+ h.mu.readyServer = serverConn
+ return nil
+}
+
func (h *clientConfigSessionHandler) handleKnownPacks(p *config.KnownPacks, pc *proto.PacketContext) {
- smc, ok := h.player.connectionInFlightOrConnectedServer().ensureConnected()
+ serverConn := h.player.connectionInFlightOrConnectedServer()
+ if serverConn == nil {
+ return
+ }
+ smc, ok := serverConn.ensureConnected()
if ok {
_ = smc.WritePacket(p)
}
diff --git a/pkg/edition/java/proxy/session_client_config_test.go b/pkg/edition/java/proxy/session_client_config_test.go
new file mode 100644
index 000000000..944ed272f
--- /dev/null
+++ b/pkg/edition/java/proxy/session_client_config_test.go
@@ -0,0 +1,120 @@
+package proxy
+
+import (
+ "net"
+ "testing"
+
+ "github.com/go-logr/logr"
+ "github.com/robinbraemer/event"
+ "go.minekube.com/gate/pkg/edition/java/proto/packet/config"
+ "go.minekube.com/gate/pkg/edition/java/proto/packet/plugin"
+ "go.minekube.com/gate/pkg/edition/java/proto/state"
+ "go.minekube.com/gate/pkg/edition/java/proxy/message"
+)
+
+func newTestConfigHandler(t *testing.T) (*clientConfigSessionHandler, *connectedPlayer, *serverConnection, *testMinecraftConn) {
+ t.Helper()
+
+ clientConn := &testMinecraftConn{}
+ backendConn := &testMinecraftConn{}
+ player := &connectedPlayer{
+ MinecraftConn: clientConn,
+ log: logr.Discard(),
+ }
+ proxy := &Proxy{
+ event: event.Nop,
+ channelRegistrar: message.NewChannelRegistrar(),
+ }
+ server := newRegisteredServer(NewServerInfo("purpur", &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 25565}))
+ serverConn := newServerConnection(server, nil, player)
+ serverConn.connection = backendConn
+ player.sessionHandlerDeps = &sessionHandlerDeps{proxy: proxy}
+
+ return newClientConfigSessionHandler(player), player, serverConn, backendConn
+}
+
+func TestClientConfigQueuesPluginMessagesUntilBackendReady(t *testing.T) {
+ handler, player, serverConn, backendConn := newTestConfigHandler(t)
+
+ player.mu.Lock()
+ player.connInFlight = serverConn
+ player.mu.Unlock()
+
+ handler.handlePluginMessage(&plugin.Message{
+ Channel: "minecraft:register",
+ Data: []byte("purpur:config"),
+ })
+
+ if got := len(backendConn.writtenPackets); got != 0 {
+ t.Fatalf("plugin message was written before backend config was ready: got %d packets", got)
+ }
+
+ if err := handler.flushQueuedPluginMessagesTo(serverConn); err != nil {
+ t.Fatalf("flush queued config plugin messages: %v", err)
+ }
+
+ if got := len(backendConn.writtenPackets); got != 1 {
+ t.Fatalf("queued plugin messages written to backend = %d, want 1", got)
+ }
+ got, ok := backendConn.writtenPackets[0].(*plugin.Message)
+ if !ok {
+ t.Fatalf("queued packet type = %T, want *plugin.Message", backendConn.writtenPackets[0])
+ }
+ if got.Channel != "minecraft:register" || string(got.Data) != "purpur:config" {
+ t.Fatalf("queued packet = %q %q, want minecraft:register purpur:config", got.Channel, string(got.Data))
+ }
+}
+
+func TestClientConfigForwardsPluginMessagesAfterBackendReady(t *testing.T) {
+ handler, player, serverConn, backendConn := newTestConfigHandler(t)
+
+ player.mu.Lock()
+ player.connInFlight = serverConn
+ player.mu.Unlock()
+
+ if err := handler.flushQueuedPluginMessagesTo(serverConn); err != nil {
+ t.Fatalf("mark backend ready: %v", err)
+ }
+
+ handler.handlePluginMessage(&plugin.Message{
+ Channel: "minecraft:register",
+ Data: []byte("purpur:ready"),
+ })
+
+ if got := len(backendConn.writtenPackets); got != 1 {
+ t.Fatalf("direct plugin messages written to backend = %d, want 1", got)
+ }
+ got := backendConn.writtenPackets[0].(*plugin.Message)
+ if got.Channel != "minecraft:register" || string(got.Data) != "purpur:ready" {
+ t.Fatalf("direct packet = %q %q, want minecraft:register purpur:ready", got.Channel, string(got.Data))
+ }
+}
+
+func TestClientConfigBackendFinishReplaysClientBrandAndSwitchesOnlyOutboundState(t *testing.T) {
+ handler, player, serverConn, backendConn := newTestConfigHandler(t)
+ player.setClientBrand("vanilla")
+ handler.handlePluginMessage(&plugin.Message{
+ Channel: plugin.BrandChannel,
+ Data: []byte{0x07, 'v', 'a', 'n', 'i', 'l', 'l', 'a'},
+ })
+
+ done := handler.handleBackendFinishUpdate(serverConn, &config.FinishedUpdate{})
+ if done == nil {
+ t.Fatal("handleBackendFinishUpdate returned nil future")
+ }
+
+ if got := len(backendConn.writtenPackets); got != 1 {
+ t.Fatalf("backend packets = %d, want replayed brand only", got)
+ }
+ brand, ok := backendConn.writtenPackets[0].(*plugin.Message)
+ if !ok {
+ t.Fatalf("backend packet type = %T, want *plugin.Message", backendConn.writtenPackets[0])
+ }
+ if brand.Channel != plugin.BrandChannel || string(plugin.ReadBrandMessage(brand.Data)) != "vanilla" {
+ t.Fatalf("brand replay = %q %q, want minecraft:brand vanilla", brand.Channel, plugin.ReadBrandMessage(brand.Data))
+ }
+ writer := player.Writer().(*testWriter)
+ if writer.state != state.Play {
+ t.Fatalf("client outbound state = %v, want Play", writer.state)
+ }
+}
diff --git a/pkg/edition/java/proxy/vialite.go b/pkg/edition/java/proxy/vialite.go
index 636598272..c601801d4 100644
--- a/pkg/edition/java/proxy/vialite.go
+++ b/pkg/edition/java/proxy/vialite.go
@@ -14,6 +14,7 @@ import (
"time"
"go.minekube.com/gate/pkg/edition/java/config"
+ javaversion "go.minekube.com/gate/pkg/edition/java/proto/version"
vialite "go.minekube.com/vialite"
)
@@ -193,6 +194,9 @@ func (r *viaManagedRunner) AddBackend(ctx context.Context, info ServerInfo) (boo
return true, nil
}
r.mu.Unlock()
+ if r.shouldSkipDynamicBackend(info) {
+ return false, nil
+ }
backend, cleanup, err := r.dynamicBackend(info)
if err != nil {
@@ -234,8 +238,41 @@ func (r *viaManagedRunner) AddBackend(ctx context.Context, info ServerInfo) (boo
return true, nil
}
+func (r *viaManagedRunner) shouldSkipDynamicBackend(info ServerInfo) bool {
+ if info == nil {
+ return false
+ }
+ versionProvider, hasBackendVersion := info.(BackendVersionProvider)
+ clientProvider, hasClientProtocol := info.(ClientProtocolProvider)
+ if !hasBackendVersion || !hasClientProtocol {
+ return false
+ }
+ backendVersion := versionProvider.BackendVersion()
+ if backendVersion == "" {
+ return false
+ }
+ clientVersion := javaversion.Protocol(clientProvider.ClientProtocol()).Version()
+ if clientVersion == nil || clientVersion == javaversion.Unknown || clientVersion == javaversion.Legacy {
+ return false
+ }
+ for _, name := range clientVersion.Names {
+ if name == backendVersion {
+ return true
+ }
+ }
+ return false
+}
+
func (r *viaManagedRunner) dynamicBackend(info ServerInfo) (vialite.Backend, interface{ Close() error }, error) {
address := info.Addr().String()
+ version := ""
+ forwarding := viaForwarding(r.cfg.Forwarding.Mode)
+ if provider, ok := info.(BackendVersionProvider); ok {
+ version = provider.BackendVersion()
+ }
+ if provider, ok := info.(ForwardingModeProvider); ok {
+ forwarding = viaForwarding(provider.ForwardingMode())
+ }
var cleanup interface{ Close() error }
if dialer, ok := info.(ServerDialer); ok {
bridge, err := newViaBackendBridge(dialer)
@@ -248,7 +285,8 @@ func (r *viaManagedRunner) dynamicBackend(info ServerInfo) (vialite.Backend, int
return vialite.Backend{
Name: info.Name(),
Address: address,
- Forwarding: viaForwarding(r.cfg.Forwarding.Mode),
+ Version: version,
+ Forwarding: forwarding,
}, cleanup, nil
}
diff --git a/pkg/edition/java/proxy/vialite_test.go b/pkg/edition/java/proxy/vialite_test.go
index 89926d23a..a556cb4b7 100644
--- a/pkg/edition/java/proxy/vialite_test.go
+++ b/pkg/edition/java/proxy/vialite_test.go
@@ -16,6 +16,8 @@ import (
"go.minekube.com/gate/pkg/edition/java/auth"
"go.minekube.com/gate/pkg/edition/java/config"
liteconfig "go.minekube.com/gate/pkg/edition/java/lite/config"
+ javaversion "go.minekube.com/gate/pkg/edition/java/proto/version"
+ "go.minekube.com/gate/pkg/gate/proto"
vialite "go.minekube.com/vialite"
)
@@ -339,6 +341,120 @@ func TestProxyRegisterDynamicViaBackendPreservesServerDialer(t *testing.T) {
}
}
+func TestProxyRegisterSkipsDynamicViaBackendForMatchingClientProtocol(t *testing.T) {
+ cfg := &config.Config{
+ Via: config.Via{Enabled: true},
+ Lite: liteconfig.Config{Enabled: false},
+ }
+ fakeVia := &fakeVialiteServer{backends: map[string]string{}}
+ p := &Proxy{
+ log: logr.Discard(),
+ cfg: cfg,
+ event: event.Nop,
+ servers: make(map[string]*registeredServer),
+ configServers: make(map[string]bool),
+ via: &viaManagedRunner{
+ cfg: cfg,
+ server: fakeVia,
+ activeBackends: map[string]struct{}{},
+ dynamicBackends: map[string]*viaDynamicBackend{},
+ },
+ }
+ original := &fakeDynamicDialer{
+ name: "connect-session-1",
+ addr: mustParseAddr("127.0.0.1:25566"),
+ connections: make(chan net.Conn, 1),
+ dialed: make(chan Player, 1),
+ backendVersion: javaversion.Minecraft_1_21_6.FirstName(),
+ clientProtocol: javaversion.Minecraft_1_21_6.Protocol,
+ }
+
+ server, err := p.Register(original)
+ if err != nil {
+ t.Fatalf("Register: %v", err)
+ }
+ if _, ok := server.ServerInfo().(*viaServerInfo); ok {
+ t.Fatalf("ServerInfo = %T, did not want via wrapper for matching client/backend protocol", server.ServerInfo())
+ }
+ if _, ok := fakeVia.added["connect-session-1"]; ok {
+ t.Fatalf("matching client/backend protocol unexpectedly registered Via backend: %#v", fakeVia.added)
+ }
+}
+
+func TestProxyRegisterDoesNotSkipDynamicViaBackendForMismatchedClientProtocol(t *testing.T) {
+ cfg := &config.Config{
+ Via: config.Via{Enabled: true},
+ Lite: liteconfig.Config{Enabled: false},
+ }
+ fakeVia := &fakeVialiteServer{backends: map[string]string{}}
+ p := &Proxy{
+ log: logr.Discard(),
+ cfg: cfg,
+ event: event.Nop,
+ servers: make(map[string]*registeredServer),
+ configServers: make(map[string]bool),
+ via: &viaManagedRunner{
+ cfg: cfg,
+ server: fakeVia,
+ activeBackends: map[string]struct{}{},
+ dynamicBackends: map[string]*viaDynamicBackend{},
+ },
+ }
+ original := &fakeDynamicDialer{
+ name: "connect-session-1",
+ addr: mustParseAddr("127.0.0.1:25566"),
+ connections: make(chan net.Conn, 1),
+ dialed: make(chan Player, 1),
+ backendVersion: javaversion.Minecraft_1_21_5.FirstName(),
+ clientProtocol: javaversion.Minecraft_1_21_6.Protocol,
+ }
+
+ server, err := p.Register(original)
+ if err != nil {
+ t.Fatalf("Register: %v", err)
+ }
+ if _, ok := server.ServerInfo().(*viaServerInfo); !ok {
+ t.Fatalf("ServerInfo = %T, want via wrapper for mismatched client/backend protocol", server.ServerInfo())
+ }
+ if _, ok := fakeVia.added["connect-session-1"]; !ok {
+ t.Fatalf("mismatched client/backend protocol did not register Via backend: %#v", fakeVia.added)
+ }
+}
+
+func TestViaDynamicBackendUsesServerForwardingMode(t *testing.T) {
+ cfg := &config.Config{
+ Forwarding: config.Forwarding{Mode: config.NoneForwardingMode},
+ Via: config.Via{Enabled: true},
+ Lite: liteconfig.Config{Enabled: false},
+ }
+ runner := &viaManagedRunner{cfg: cfg}
+ info := &fakeDynamicDialer{
+ name: "connect-session-legacy",
+ addr: mustParseAddr("127.0.0.1:25566"),
+ connections: make(chan net.Conn, 1),
+ dialed: make(chan Player, 1),
+ forwardingMode: config.LegacyForwardingMode,
+ backendVersion: "1.21.6",
+ }
+
+ backend, cleanup, err := runner.dynamicBackend(info)
+ if err != nil {
+ t.Fatalf("dynamicBackend: %v", err)
+ }
+ if cleanup != nil {
+ defer cleanup.Close()
+ }
+ if backend.Forwarding != vialite.ForwardingLegacy {
+ t.Fatalf("backend Forwarding = %q, want %q", backend.Forwarding, vialite.ForwardingLegacy)
+ }
+ if backend.Version != "1.21.6" {
+ t.Fatalf("backend Version = %q, want 1.21.6", backend.Version)
+ }
+ if backend.Detect {
+ t.Fatal("backend Detect = true, want false for explicit dynamic backend version")
+ }
+}
+
func TestViaManagedRunnerStopClosesDynamicBridge(t *testing.T) {
cfg := &config.Config{
Via: config.Via{Enabled: true},
@@ -617,15 +733,30 @@ func (f *fakeVialiteServer) RemoveBackend(ctx context.Context, name string) erro
}
type fakeDynamicDialer struct {
- name string
- addr net.Addr
- connections chan net.Conn
- dialed chan Player
+ name string
+ addr net.Addr
+ connections chan net.Conn
+ dialed chan Player
+ forwardingMode config.ForwardingMode
+ backendVersion string
+ clientProtocol proto.Protocol
}
func (f *fakeDynamicDialer) Name() string { return f.name }
func (f *fakeDynamicDialer) Addr() net.Addr { return f.addr }
+func (f *fakeDynamicDialer) ForwardingMode() config.ForwardingMode {
+ return f.forwardingMode
+}
+
+func (f *fakeDynamicDialer) BackendVersion() string {
+ return f.backendVersion
+}
+
+func (f *fakeDynamicDialer) ClientProtocol() proto.Protocol {
+ return f.clientProtocol
+}
+
func (f *fakeDynamicDialer) Dial(ctx context.Context, player Player) (net.Conn, error) {
client, server := net.Pipe()
select {
diff --git a/sound.test b/sound.test
deleted file mode 100755
index e3eac084a..000000000
Binary files a/sound.test and /dev/null differ
diff --git a/test_sound_interface b/test_sound_interface
deleted file mode 100755
index f806dfea5..000000000
Binary files a/test_sound_interface and /dev/null differ