diff --git a/.idea/detekt.xml b/.idea/detekt.xml
new file mode 100644
index 00000000..9f881422
--- /dev/null
+++ b/.idea/detekt.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/packages/google-agones-sdk/bindings/java/shulker.packages.google-agones-sdk.iml b/.idea/modules/packages/google-agones-sdk/bindings/java/shulker.packages.google-agones-sdk.iml
index 31a4a13c..25a80f82 100644
--- a/.idea/modules/packages/google-agones-sdk/bindings/java/shulker.packages.google-agones-sdk.iml
+++ b/.idea/modules/packages/google-agones-sdk/bindings/java/shulker.packages.google-agones-sdk.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/google-agones-sdk/bindings/java/shulker.packages.google-agones-sdk.main.iml b/.idea/modules/packages/google-agones-sdk/bindings/java/shulker.packages.google-agones-sdk.main.iml
index 84d2f144..d6721729 100644
--- a/.idea/modules/packages/google-agones-sdk/bindings/java/shulker.packages.google-agones-sdk.main.iml
+++ b/.idea/modules/packages/google-agones-sdk/bindings/java/shulker.packages.google-agones-sdk.main.iml
@@ -1,5 +1,5 @@
-
+
@@ -13,7 +13,7 @@
-
+
diff --git a/.idea/modules/packages/google-agones-sdk/bindings/java/shulker.packages.google-agones-sdk.test.iml b/.idea/modules/packages/google-agones-sdk/bindings/java/shulker.packages.google-agones-sdk.test.iml
index f4347692..55c95ae4 100644
--- a/.idea/modules/packages/google-agones-sdk/bindings/java/shulker.packages.google-agones-sdk.test.iml
+++ b/.idea/modules/packages/google-agones-sdk/bindings/java/shulker.packages.google-agones-sdk.test.iml
@@ -1,5 +1,5 @@
-
+
@@ -8,7 +8,7 @@
-
+
diff --git a/.idea/modules/packages/google-open-match-sdk/bindings/java/shulker.packages.google-open-match-sdk.iml b/.idea/modules/packages/google-open-match-sdk/bindings/java/shulker.packages.google-open-match-sdk.iml
index 531e9858..95782c19 100644
--- a/.idea/modules/packages/google-open-match-sdk/bindings/java/shulker.packages.google-open-match-sdk.iml
+++ b/.idea/modules/packages/google-open-match-sdk/bindings/java/shulker.packages.google-open-match-sdk.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/google-open-match-sdk/bindings/java/shulker.packages.google-open-match-sdk.main.iml b/.idea/modules/packages/google-open-match-sdk/bindings/java/shulker.packages.google-open-match-sdk.main.iml
index c4b33082..46e80816 100644
--- a/.idea/modules/packages/google-open-match-sdk/bindings/java/shulker.packages.google-open-match-sdk.main.iml
+++ b/.idea/modules/packages/google-open-match-sdk/bindings/java/shulker.packages.google-open-match-sdk.main.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/google-open-match-sdk/bindings/java/shulker.packages.google-open-match-sdk.test.iml b/.idea/modules/packages/google-open-match-sdk/bindings/java/shulker.packages.google-open-match-sdk.test.iml
index 8a874b99..23b596ae 100644
--- a/.idea/modules/packages/google-open-match-sdk/bindings/java/shulker.packages.google-open-match-sdk.test.iml
+++ b/.idea/modules/packages/google-open-match-sdk/bindings/java/shulker.packages.google-open-match-sdk.test.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.bungeecord.iml b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.bungeecord.iml
index e9318eb8..ca5ee5f5 100644
--- a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.bungeecord.iml
+++ b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.bungeecord.iml
@@ -1,5 +1,5 @@
-
+
@@ -42,7 +42,7 @@
-
+
@@ -165,7 +165,7 @@
-
+
diff --git a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.common.iml b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.common.iml
index c114c524..3d64ef56 100644
--- a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.common.iml
+++ b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.common.iml
@@ -1,5 +1,5 @@
-
+
@@ -42,7 +42,7 @@
-
+
@@ -136,7 +136,7 @@
-
+
diff --git a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.iml b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.iml
index 3020a7ac..ad0ffaa3 100644
--- a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.iml
+++ b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.main.iml b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.main.iml
index b90877ea..02f6b167 100644
--- a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.main.iml
+++ b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.main.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.test.iml b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.test.iml
index 2f44fe9d..fda204af 100644
--- a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.test.iml
+++ b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.test.iml
@@ -1,5 +1,5 @@
-
+
@@ -40,9 +40,11 @@
+
+
diff --git a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.velocity.iml b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.velocity.iml
index 33499c1a..bb8fd741 100644
--- a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.velocity.iml
+++ b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.velocity.iml
@@ -1,5 +1,5 @@
-
+
@@ -43,7 +43,7 @@
-
+
@@ -160,7 +160,7 @@
-
+
diff --git a/.idea/modules/packages/shulker-proxy-api/shulker.packages.shulker-proxy-api.iml b/.idea/modules/packages/shulker-proxy-api/shulker.packages.shulker-proxy-api.iml
index 43e7219f..579768bd 100644
--- a/.idea/modules/packages/shulker-proxy-api/shulker.packages.shulker-proxy-api.iml
+++ b/.idea/modules/packages/shulker-proxy-api/shulker.packages.shulker-proxy-api.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker-proxy-api/shulker.packages.shulker-proxy-api.main.iml b/.idea/modules/packages/shulker-proxy-api/shulker.packages.shulker-proxy-api.main.iml
index ef630304..7fccee43 100644
--- a/.idea/modules/packages/shulker-proxy-api/shulker.packages.shulker-proxy-api.main.iml
+++ b/.idea/modules/packages/shulker-proxy-api/shulker.packages.shulker-proxy-api.main.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker-proxy-api/shulker.packages.shulker-proxy-api.test.iml b/.idea/modules/packages/shulker-proxy-api/shulker.packages.shulker-proxy-api.test.iml
index 2e4ea85b..80430550 100644
--- a/.idea/modules/packages/shulker-proxy-api/shulker.packages.shulker-proxy-api.test.iml
+++ b/.idea/modules/packages/shulker-proxy-api/shulker.packages.shulker-proxy-api.test.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker-sdk/bindings/java/shulker.packages.shulker-sdk.iml b/.idea/modules/packages/shulker-sdk/bindings/java/shulker.packages.shulker-sdk.iml
index 4db87b06..7bb3c800 100644
--- a/.idea/modules/packages/shulker-sdk/bindings/java/shulker.packages.shulker-sdk.iml
+++ b/.idea/modules/packages/shulker-sdk/bindings/java/shulker.packages.shulker-sdk.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker-sdk/bindings/java/shulker.packages.shulker-sdk.main.iml b/.idea/modules/packages/shulker-sdk/bindings/java/shulker.packages.shulker-sdk.main.iml
index f86fd051..885f438c 100644
--- a/.idea/modules/packages/shulker-sdk/bindings/java/shulker.packages.shulker-sdk.main.iml
+++ b/.idea/modules/packages/shulker-sdk/bindings/java/shulker.packages.shulker-sdk.main.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker-sdk/bindings/java/shulker.packages.shulker-sdk.test.iml b/.idea/modules/packages/shulker-sdk/bindings/java/shulker.packages.shulker-sdk.test.iml
index 6e31e8d1..ce6aecab 100644
--- a/.idea/modules/packages/shulker-sdk/bindings/java/shulker.packages.shulker-sdk.test.iml
+++ b/.idea/modules/packages/shulker-sdk/bindings/java/shulker.packages.shulker-sdk.test.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.common.iml b/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.common.iml
index bc647473..1d05c50e 100644
--- a/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.common.iml
+++ b/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.common.iml
@@ -1,5 +1,5 @@
-
+
@@ -64,7 +64,7 @@
-
+
diff --git a/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.iml b/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.iml
index b08a78a7..2e88936e 100644
--- a/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.iml
+++ b/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.main.iml b/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.main.iml
index 2e14b8a7..14c02bd8 100644
--- a/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.main.iml
+++ b/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.main.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.paper.iml b/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.paper.iml
index 536ad3f1..37f4fa94 100644
--- a/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.paper.iml
+++ b/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.paper.iml
@@ -1,5 +1,5 @@
-
+
@@ -103,7 +103,7 @@
-
+
diff --git a/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.test.iml b/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.test.iml
index c168f15b..0657c66a 100644
--- a/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.test.iml
+++ b/.idea/modules/packages/shulker-server-agent/shulker.packages.shulker-server-agent.test.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker-server-api/shulker.packages.shulker-server-api.iml b/.idea/modules/packages/shulker-server-api/shulker.packages.shulker-server-api.iml
index 1d5a1ce4..5170ce49 100644
--- a/.idea/modules/packages/shulker-server-api/shulker.packages.shulker-server-api.iml
+++ b/.idea/modules/packages/shulker-server-api/shulker.packages.shulker-server-api.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker-server-api/shulker.packages.shulker-server-api.main.iml b/.idea/modules/packages/shulker-server-api/shulker.packages.shulker-server-api.main.iml
index 2f3884a1..05fe1795 100644
--- a/.idea/modules/packages/shulker-server-api/shulker.packages.shulker-server-api.main.iml
+++ b/.idea/modules/packages/shulker-server-api/shulker.packages.shulker-server-api.main.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker-server-api/shulker.packages.shulker-server-api.test.iml b/.idea/modules/packages/shulker-server-api/shulker.packages.shulker-server-api.test.iml
index 0a56b717..aa3b3abf 100644
--- a/.idea/modules/packages/shulker-server-api/shulker.packages.shulker-server-api.test.iml
+++ b/.idea/modules/packages/shulker-server-api/shulker.packages.shulker-server-api.test.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/packages/shulker.packages.iml b/.idea/modules/packages/shulker.packages.iml
index 51c3b371..6ce413c8 100644
--- a/.idea/modules/packages/shulker.packages.iml
+++ b/.idea/modules/packages/shulker.packages.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/shulker.iml b/.idea/modules/shulker.iml
index b450d7ea..2cf47fc4 100644
--- a/.idea/modules/shulker.iml
+++ b/.idea/modules/shulker.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/shulker.main.iml b/.idea/modules/shulker.main.iml
index 271efd57..601e085f 100644
--- a/.idea/modules/shulker.main.iml
+++ b/.idea/modules/shulker.main.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/modules/shulker.test.iml b/.idea/modules/shulker.test.iml
index 2f9b9f91..70c487a5 100644
--- a/.idea/modules/shulker.test.iml
+++ b/.idea/modules/shulker.test.iml
@@ -1,5 +1,5 @@
-
+
diff --git a/build.gradle.kts b/build.gradle.kts
index ca7e6a89..c9804a3b 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,8 +1,6 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import io.gitlab.arturbosch.detekt.Detekt
-import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask
import io.gitlab.arturbosch.detekt.report.ReportMergeTask
-import org.jetbrains.kotlin.utils.addToStdlib.safeAs
plugins {
id("idea")
@@ -96,13 +94,12 @@ subprojects {
detekt {
buildUponDefaultConfig = true
ignoreFailures = true
- baseline = file("$rootDir/gradle/detekt/baseline.xml")
+ config.setFrom("$rootDir/gradle/detekt-config.yml")
+ baseline = file("$rootDir/gradle/detekt-baseline.xml")
basePath = rootDir.absolutePath
}
tasks.withType().configureEach {
- jvmTarget = "1.8"
-
reports {
sarif.required = true
}
@@ -110,10 +107,6 @@ subprojects {
finalizedBy(detektReportMergeSarif)
}
- tasks.withType().configureEach {
- jvmTarget = "1.8"
- }
-
detektReportMergeSarif.configure {
input.from(tasks.withType().map { it.sarifReportFile })
}
@@ -189,7 +182,6 @@ subprojects {
uri("https://maven.jeremylvln.fr/artifactory/shulker-releases")
}
-
credentials {
username = findProperty("artifactory.username")?.toString() ?: System.getenv("ARTIFACTORY_USERNAME")
password = findProperty("artifactory.password")?.toString() ?: System.getenv("ARTIFACTORY_PASSWORD")
diff --git a/docs/src/next/guide/recipes/understanding-lifecycle-strategies.md b/docs/src/next/guide/recipes/understanding-lifecycle-strategies.md
new file mode 100644
index 00000000..fb5a9bd1
--- /dev/null
+++ b/docs/src/next/guide/recipes/understanding-lifecycle-strategies.md
@@ -0,0 +1,79 @@
+# Understanding Lifecycle Strategies
+
+Your proxies and servers lifecycles are _described_ by Shulker but
+are actually managed by **Agones**.
+
+You may want to customize the lifecycle of your servers so Agones
+does not disturb your players at innapropriate times.
+
+:::info EXAMPLE
+
+For instance, you may not want Agones to update your fleet of servers
+because you upgraded a plugin while some players are in a mini-game.
+
+:::
+
+While Shulker's server agent marks your server as `Ready` when the
+agent is fully loaded, you may want to also mark your server as
+`Allocated` when an interrupted game session is needed (a mini-game
+for instance).
+
+Shulker allows you to choose a **Lifecycle Strategy** that will
+change the automatic behaviors of Agones. It can be changed on
+the `MinecraftServer` and `MinecraftServerFleet`:
+
+```yaml
+apiVersion: shulkermc.io/v1alpha1
+kind: MinecraftServerFleet
+metadata:
+ name: dropper-game
+spec:
+ clusterRef:
+ name: getting-started
+ replicas: 1
+ template:
+ spec:
+ clusterRef:
+ name: getting-started
+ tags:
+ - lobby
+ version:
+ channel: Paper
+ name: '1.20.4'
+ config: // [!code focus]
+ lifecycleStrategy: AllocateWhenNotEmpty // [!code focus]
+```
+
+## `AllocateWhenNotEmpty` strategy
+
+With this strategy, Shulker's server agent will mark your server as
+`Allocated` when at lease one player is connected on the server.
+
+This will disable any automatic reschedule of Agones that may be
+due to a plugin upgrade. For your server to be updated, you'll have to
+either:
+
+1. Have all the players disconnected for the server is set back to
+ `Ready`
+2. Shutdown yourself the server (with the `/server` command for instance)
+
+:::info
+
+Shulker will still mark your server as `Ready` once the agent is
+fully loaded.
+
+:::
+
+## `Manual` strategy
+
+With this strategy, no extra work is done apart marking the server as
+`Ready` after loading. It is up to you and custom implementation to manage
+the lifecycle of your server.
+
+:::warning
+
+Using this strategy with no custom implementation will keep the `Ready`
+state forever. Thus, Agones will always think that the server is not used
+and it may be recreated at any time for any reason.
+
+:::
diff --git a/docs/src/next/sidebar.mts b/docs/src/next/sidebar.mts
index b74f2780..8f7d7d56 100644
--- a/docs/src/next/sidebar.mts
+++ b/docs/src/next/sidebar.mts
@@ -52,6 +52,10 @@ export default [
text: 'Using custom server JAR',
link: link('/guide/recipes/using-custom-server-jar'),
},
+ {
+ text: 'Understanding Lifecycle Strategy',
+ link: link('/guide/recipes/understanding-lifecycle-strategies'),
+ },
],
},
{
diff --git a/examples/getting-started/minecraftserver.yaml b/examples/getting-started/minecraftserver.yaml
index 21b106ef..765e5e46 100644
--- a/examples/getting-started/minecraftserver.yaml
+++ b/examples/getting-started/minecraftserver.yaml
@@ -14,5 +14,5 @@ spec:
- lobby
version:
channel: Paper
- name: "1.18.2"
+ name: "1.20.4"
config: {}
diff --git a/examples/getting-started/proxy.yaml b/examples/getting-started/proxy.yaml
index 5073e0a5..0977dc92 100644
--- a/examples/getting-started/proxy.yaml
+++ b/examples/getting-started/proxy.yaml
@@ -7,8 +7,8 @@ spec:
name: getting-started
replicas: 1
service:
- type: LoadBalancer
- externalTrafficPolicy: Local
+ type: ClusterIP
+ # externalTrafficPolicy: Local
template:
spec:
version:
diff --git a/gradle/detekt-config.yml b/gradle/detekt-config.yml
new file mode 100644
index 00000000..a702747d
--- /dev/null
+++ b/gradle/detekt-config.yml
@@ -0,0 +1,16 @@
+complexity:
+ TooManyFunctions:
+ active: false
+
+naming:
+ MemberNameEqualsClassName:
+ excludes:
+ - "**/kubernetes/models/**"
+
+style:
+ MaxLineLength:
+ active: false
+ ForbiddenVoid:
+ ignoreOverridden: true
+ ReturnCount:
+ active: false
diff --git a/packages/shulker-crds/src/v1alpha1/minecraft_server.rs b/packages/shulker-crds/src/v1alpha1/minecraft_server.rs
index 852ead22..5801b755 100644
--- a/packages/shulker-crds/src/v1alpha1/minecraft_server.rs
+++ b/packages/shulker-crds/src/v1alpha1/minecraft_server.rs
@@ -114,6 +114,10 @@ pub struct MinecraftServerConfigurationSpec {
/// this `MinecraftServer`
#[serde(default)]
pub proxy_forwarding_mode: MinecraftServerConfigurationProxyForwardingMode,
+
+ /// Strategy to apply concerning Agones `GameServer` lifecycle management
+ #[serde(default)]
+ pub lifecycle_strategy: MinecraftServerConfigurationLifecycleStrategy,
}
#[cfg(not(tarpaulin_include))]
@@ -140,6 +144,15 @@ pub enum MinecraftServerConfigurationProxyForwardingMode {
BungeeCord,
}
+#[derive(
+ PartialEq, Deserialize, Serialize, Clone, Debug, Default, JsonSchema, IntoStaticStr, Display,
+)]
+pub enum MinecraftServerConfigurationLifecycleStrategy {
+ #[default]
+ AllocateWhenNotEmpty,
+ Manual,
+}
+
#[derive(Deserialize, Serialize, Clone, Debug, Default, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct MinecraftServerPodOverridesSpec {
diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_role.rs b/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_role.rs
index c47b66e6..03480b21 100644
--- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_role.rs
+++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_role.rs
@@ -49,7 +49,10 @@ impl<'a> ResourceBuilder<'a> for MinecraftServerRoleBuilder {
PolicyRule {
api_groups: Some(vec!["".to_string()]),
resources: Some(vec!["events".to_string()]),
- verbs: vec!["create".to_string()],
+ verbs: vec![
+ "create".to_string(),
+ "patch".to_string()
+ ],
..PolicyRule::default()
},
PolicyRule {
diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_role__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_role__tests__build_snapshot.snap
index ea604425..03f1284d 100644
--- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_role__tests__build_snapshot.snap
+++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_role__tests__build_snapshot.snap
@@ -21,6 +21,7 @@ rules:
- events
verbs:
- create
+ - patch
- apiGroups:
- agones.dev
resources:
diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server/fixtures.rs b/packages/shulker-operator/src/reconcilers/minecraft_server/fixtures.rs
index 36dcf30a..7455cdc1 100644
--- a/packages/shulker-operator/src/reconcilers/minecraft_server/fixtures.rs
+++ b/packages/shulker-operator/src/reconcilers/minecraft_server/fixtures.rs
@@ -10,9 +10,10 @@ use shulker_crds::{
v1alpha1::{
minecraft_cluster::MinecraftClusterRef,
minecraft_server::{
- MinecraftServer, MinecraftServerConfigurationProxyForwardingMode,
- MinecraftServerConfigurationSpec, MinecraftServerPodOverridesSpec, MinecraftServerSpec,
- MinecraftServerVersion, MinecraftServerVersionSpec,
+ MinecraftServer, MinecraftServerConfigurationLifecycleStrategy,
+ MinecraftServerConfigurationProxyForwardingMode, MinecraftServerConfigurationSpec,
+ MinecraftServerPodOverridesSpec, MinecraftServerSpec, MinecraftServerVersion,
+ MinecraftServerVersionSpec,
},
},
};
@@ -50,7 +51,9 @@ lazy_static! {
disable_nether: false,
disable_end: true,
server_properties: None,
- proxy_forwarding_mode: MinecraftServerConfigurationProxyForwardingMode::Velocity
+ proxy_forwarding_mode: MinecraftServerConfigurationProxyForwardingMode::Velocity,
+ lifecycle_strategy:
+ MinecraftServerConfigurationLifecycleStrategy::AllocateWhenNotEmpty
},
pod_overrides: Some(MinecraftServerPodOverridesSpec {
image: None,
diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server/gameserver.rs b/packages/shulker-operator/src/reconcilers/minecraft_server/gameserver.rs
index 9b989096..eeebb288 100644
--- a/packages/shulker-operator/src/reconcilers/minecraft_server/gameserver.rs
+++ b/packages/shulker-operator/src/reconcilers/minecraft_server/gameserver.rs
@@ -430,6 +430,11 @@ impl<'a> GameServerBuilder {
),
..EnvVar::default()
},
+ EnvVar {
+ name: "SHULKER_SERVER_LIFECYCLE_STRATEGY".to_string(),
+ value: Some(minecraft_server.spec.config.lifecycle_strategy.to_string()),
+ ..EnvVar::default()
+ },
EnvVar {
name: "EULA".to_string(),
value: Some("TRUE".to_string()),
diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server/snapshots/shulker_operator__reconcilers__minecraft_server__gameserver__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_server/snapshots/shulker_operator__reconcilers__minecraft_server__gameserver__tests__build_snapshot.snap
index ada6f79e..507eccf8 100644
--- a/packages/shulker-operator/src/reconcilers/minecraft_server/snapshots/shulker_operator__reconcilers__minecraft_server__gameserver__tests__build_snapshot.snap
+++ b/packages/shulker-operator/src/reconcilers/minecraft_server/snapshots/shulker_operator__reconcilers__minecraft_server__gameserver__tests__build_snapshot.snap
@@ -50,6 +50,8 @@ spec:
fieldPath: metadata.namespace
- name: SHULKER_NETWORK_ADMINS
value: ""
+ - name: SHULKER_SERVER_LIFECYCLE_STRATEGY
+ value: AllocateWhenNotEmpty
- name: EULA
value: "TRUE"
- name: COPY_CONFIG_DEST
diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/fixtures.rs b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/fixtures.rs
index 552e7431..525d6122 100644
--- a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/fixtures.rs
+++ b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/fixtures.rs
@@ -14,6 +14,7 @@ use shulker_crds::{
v1alpha1::{
minecraft_cluster::MinecraftClusterRef,
minecraft_server::{
+ MinecraftServerConfigurationLifecycleStrategy,
MinecraftServerConfigurationProxyForwardingMode, MinecraftServerConfigurationSpec,
MinecraftServerPodOverridesSpec, MinecraftServerSpec, MinecraftServerVersion,
MinecraftServerVersionSpec,
@@ -71,7 +72,9 @@ lazy_static! {
disable_end: true,
server_properties: None,
proxy_forwarding_mode:
- MinecraftServerConfigurationProxyForwardingMode::Velocity
+ MinecraftServerConfigurationProxyForwardingMode::Velocity,
+ lifecycle_strategy:
+ MinecraftServerConfigurationLifecycleStrategy::AllocateWhenNotEmpty
},
pod_overrides: Some(MinecraftServerPodOverridesSpec {
image: None,
diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__fleet__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__fleet__tests__build_snapshot.snap
index ab5773b4..d7c5caba 100644
--- a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__fleet__tests__build_snapshot.snap
+++ b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__fleet__tests__build_snapshot.snap
@@ -72,6 +72,8 @@ spec:
fieldPath: metadata.namespace
- name: SHULKER_NETWORK_ADMINS
value: ""
+ - name: SHULKER_SERVER_LIFECYCLE_STRATEGY
+ value: AllocateWhenNotEmpty
- name: EULA
value: "TRUE"
- name: COPY_CONFIG_DEST
diff --git a/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/ProxyInterfaceBungeeCord.kt b/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/ProxyInterfaceBungeeCord.kt
index a368f9c9..b9b7403e 100644
--- a/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/ProxyInterfaceBungeeCord.kt
+++ b/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/ProxyInterfaceBungeeCord.kt
@@ -31,6 +31,7 @@ import java.net.InetSocketAddress
import java.util.UUID
import java.util.concurrent.TimeUnit
+@Suppress("TooManyFunctions")
class ProxyInterfaceBungeeCord(
private val plugin: Plugin,
private val proxy: ProxyServer
@@ -72,6 +73,7 @@ class ProxyInterfaceBungeeCord(
val result = hook()
if (!result.allowed) {
+ @Suppress("UnsafeCallOnNullableType")
event.setCancelReason(*BungeeComponentSerializer.get().serialize(result.rejectComponent!!))
}
}
@@ -116,6 +118,7 @@ class ProxyInterfaceBungeeCord(
val result = hook(wrapPlayer(event.player), event.target.name)
if (result.newServerName.isPresent) {
+ @Suppress("UnsafeCallOnNullableType")
event.target = proxy.servers[result.newServerName.get()]!!
}
}
diff --git a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/ProxyInterface.kt b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/ProxyInterface.kt
index b91c49ef..736c78ba 100644
--- a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/ProxyInterface.kt
+++ b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/ProxyInterface.kt
@@ -11,6 +11,7 @@ import java.net.InetSocketAddress
import java.util.UUID
import java.util.concurrent.TimeUnit
+@Suppress("TooManyFunctions")
interface ProxyInterface {
fun registerServer(name: String, address: InetSocketAddress)
fun unregisterServer(name: String): Boolean
diff --git a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/ShulkerProxyAgentCommon.kt b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/ShulkerProxyAgentCommon.kt
index ebcbbc5d..8794427d 100644
--- a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/ShulkerProxyAgentCommon.kt
+++ b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/ShulkerProxyAgentCommon.kt
@@ -21,6 +21,7 @@ import io.shulkermc.proxyagent.tasks.HealthcheckTask
import io.shulkermc.proxyagent.tasks.LostProxyPurgeTask
import redis.clients.jedis.JedisPool
import java.lang.Exception
+import java.util.logging.Level
import java.util.logging.Logger
import kotlin.system.exitProcess
@@ -40,6 +41,7 @@ class ShulkerProxyAgentCommon(val proxyInterface: ProxyInterface, val logger: Lo
lateinit var playerMovementService: PlayerMovementService
private lateinit var proxyLifecycleService: ProxyLifecycleService
+ // Tasks
private lateinit var healthcheckTask: ProxyInterface.ScheduledTask
private lateinit var lostProxyPurgeTask: ProxyInterface.ScheduledTask
@@ -86,9 +88,8 @@ class ShulkerProxyAgentCommon(val proxyInterface: ProxyInterface, val logger: Lo
this.cache.registerProxy(Configuration.PROXY_NAME)
this.agonesGateway.setAllocated()
- } catch (e: Exception) {
- this.logger.severe("Shulker Agent crashed, stopping proxy")
- e.printStackTrace()
+ } catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
+ this.logger.log(Level.SEVERE, "Shulker Agent crashed, stopping proxy", e)
this.shutdown()
}
}
@@ -109,8 +110,12 @@ class ShulkerProxyAgentCommon(val proxyInterface: ProxyInterface, val logger: Lo
this.cache.unregisterProxy(Configuration.PROXY_NAME)
this.pubSub.close()
this.agonesGateway.askShutdown()
- } catch (ex: Exception) {
- this.logger.severe("Failed to ask Agones sidecar to shutdown properly, stopping process manually")
+ } catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
+ this.logger.log(
+ Level.SEVERE,
+ "Failed to ask Agones sidecar to shutdown properly, stopping process manually",
+ e
+ )
exitProcess(0)
}
}
diff --git a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/adapters/mojang/HttpMojangGatewayAdapter.kt b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/adapters/mojang/HttpMojangGatewayAdapter.kt
index 480e233d..68c828ad 100644
--- a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/adapters/mojang/HttpMojangGatewayAdapter.kt
+++ b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/adapters/mojang/HttpMojangGatewayAdapter.kt
@@ -8,13 +8,17 @@ import java.util.Optional
import java.util.UUID
class HttpMojangGatewayAdapter : MojangGatewayAdapter {
+ companion object {
+ private const val HTTP_OK = 200
+ }
+
override fun getProfileFromName(playerName: String): Optional {
val url = URI("https://api.mojang.com/users/profiles/minecraft/$playerName").toURL()
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "GET"
val status = connection.responseCode
- if (status != 200) return Optional.empty()
+ if (status != HTTP_OK) return Optional.empty()
val response = connection.inputStream.bufferedReader().use { it.readText() }
val responseJson = JsonParser.parseString(response).asJsonObject
@@ -28,7 +32,7 @@ class HttpMojangGatewayAdapter : MojangGatewayAdapter {
connection.requestMethod = "GET"
val status = connection.responseCode
- if (status != 200) return Optional.empty()
+ if (status != HTTP_OK) return Optional.empty()
val response = connection.inputStream.bufferedReader().use { it.readText() }
val responseJson = JsonParser.parseString(response).asJsonObject
diff --git a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/platform/HookPostOrder.kt b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/platform/HookPostOrder.kt
index 89d617d3..a6ad5335 100644
--- a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/platform/HookPostOrder.kt
+++ b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/platform/HookPostOrder.kt
@@ -1,5 +1,5 @@
package io.shulkermc.proxyagent.platform
enum class HookPostOrder {
- FIRST, EARLY, NORMAL, LATE, LAST
+ FIRST, EARLY, NORMAL, LATE, LAST, MONITOR
}
diff --git a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/services/ProxyLifecycleService.kt b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/services/ProxyLifecycleService.kt
index 53ebff98..540d763d 100644
--- a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/services/ProxyLifecycleService.kt
+++ b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/services/ProxyLifecycleService.kt
@@ -57,7 +57,7 @@ class ProxyLifecycleService(private val agent: ShulkerProxyAgentCommon) {
this.agent.logger.info("Proxy is empty, stopping")
this.agent.shutdown()
} else {
- this.agent.logger.info(String.format("There are still %d players connected, waiting", playerCount))
+ this.agent.logger.info("There are still $playerCount players connected, waiting")
}
}
}
diff --git a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/tasks/LostProxyPurgeTask.kt b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/tasks/LostProxyPurgeTask.kt
index 886c7888..1ba72092 100644
--- a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/tasks/LostProxyPurgeTask.kt
+++ b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/tasks/LostProxyPurgeTask.kt
@@ -25,12 +25,12 @@ class LostProxyPurgeTask(private val agent: ShulkerProxyAgentCommon) : Runnable
val maybeLock = this.agent.cache.tryLockLostProxiesPurgeTask(Configuration.PROXY_NAME)
maybeLock.ifPresent { lock ->
- lock.use {
+ lock.use { _ ->
this.agent.cache.listRegisteredProxies()
.filter { System.currentTimeMillis() - it.lastSeenMillis > PROXY_LOST_MILLIS_THRESHOLD }
- .forEach {
- this.agent.cache.unregisterProxy(it.proxyName)
- this.agent.logger.info("Unregistered lost proxy ${it.proxyName}")
+ .forEach { proxy ->
+ this.agent.cache.unregisterProxy(proxy.proxyName)
+ this.agent.logger.info("Unregistered lost proxy ${proxy.proxyName}")
}
}
}
diff --git a/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/ProxyInterfaceVelocity.kt b/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/ProxyInterfaceVelocity.kt
index 2ef0011f..decda2dd 100644
--- a/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/ProxyInterfaceVelocity.kt
+++ b/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/ProxyInterfaceVelocity.kt
@@ -26,6 +26,7 @@ import java.util.UUID
import java.util.concurrent.TimeUnit
import kotlin.jvm.optionals.getOrElse
+@Suppress("TooManyFunctions")
class ProxyInterfaceVelocity(
private val plugin: ShulkerProxyAgentVelocity,
private val proxy: ProxyServer
@@ -185,6 +186,7 @@ class ProxyInterfaceVelocity(
HookPostOrder.NORMAL -> PostOrder.NORMAL
HookPostOrder.LATE -> PostOrder.LATE
HookPostOrder.LAST -> PostOrder.LAST
+ HookPostOrder.MONITOR -> PostOrder.LAST
}
}
diff --git a/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/Configuration.kt b/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/Configuration.kt
index 4c9cf3ef..1f9f8d04 100644
--- a/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/Configuration.kt
+++ b/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/Configuration.kt
@@ -12,5 +12,22 @@ object Configuration {
}
.orElse(emptyList())
+ val LIFECYCLE_STRATEGY: LifecycleStrategy = getOptionalStringEnv("SHULKER_SERVER_LIFECYCLE_STRATEGY")
+ .map { value -> LifecycleStrategy.byEnvValue(value) }
+ .orElse(LifecycleStrategy.ALLOCATE_WHEN_NOT_EMPTY)
+
private fun getOptionalStringEnv(name: String): Optional = Optional.ofNullable(System.getenv(name))
+
+ enum class LifecycleStrategy(private val strategy: String) {
+ ALLOCATE_WHEN_NOT_EMPTY("AllocateWhenNotEmpty"),
+ MANUAL("Manual");
+
+ companion object {
+ fun byEnvValue(value: String): LifecycleStrategy {
+ return requireNotNull(LifecycleStrategy.entries.find { it.strategy == value }) {
+ "Unknown lifecycle strategy: $value"
+ }
+ }
+ }
+ }
}
diff --git a/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/ServerInterface.kt b/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/ServerInterface.kt
index 418ffbbc..892f7be6 100644
--- a/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/ServerInterface.kt
+++ b/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/ServerInterface.kt
@@ -1,11 +1,19 @@
package io.shulkermc.serveragent
+import io.shulkermc.serveragent.platform.HookPostOrder
+import io.shulkermc.serveragent.platform.PlayerDisconnectHook
+import io.shulkermc.serveragent.platform.PlayerLoginHook
import java.util.UUID
import java.util.concurrent.TimeUnit
interface ServerInterface {
fun prepareNetworkAdminsPermissions(playerIds: List)
+ fun addPlayerJoinHook(hook: PlayerLoginHook, postOrder: HookPostOrder)
+ fun addPlayerQuitHook(hook: PlayerDisconnectHook, postOrder: HookPostOrder)
+
+ fun getPlayerCount(): Int
+
fun scheduleDelayedTask(delay: Long, timeUnit: TimeUnit, runnable: Runnable): ScheduledTask
fun scheduleRepeatingTask(delay: Long, interval: Long, timeUnit: TimeUnit, runnable: Runnable): ScheduledTask
diff --git a/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/ShulkerServerAgentCommon.kt b/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/ShulkerServerAgentCommon.kt
index 7396182f..d7e3e99a 100644
--- a/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/ShulkerServerAgentCommon.kt
+++ b/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/ShulkerServerAgentCommon.kt
@@ -4,19 +4,26 @@ import com.agones.dev.sdk.AgonesSDK
import com.agones.dev.sdk.AgonesSDKImpl
import io.shulkermc.serveragent.api.ShulkerServerAPI
import io.shulkermc.serveragent.api.ShulkerServerAPIImpl
+import io.shulkermc.serveragent.services.PlayerMovementService
import io.shulkermc.serveragent.tasks.HealthcheckTask
import java.lang.Exception
import java.util.concurrent.TimeUnit
+import java.util.logging.Level
import java.util.logging.Logger
import kotlin.system.exitProcess
-class ShulkerServerAgentCommon(val serverInterface: ServerInterface, private val logger: Logger) {
+class ShulkerServerAgentCommon(val serverInterface: ServerInterface, val logger: Logger) {
companion object {
private const val SUMMON_LABEL_NAME = "shulkermc.io/summoned"
private const val SUMMON_TIMEOUT_MINUTES = 5L
}
lateinit var agonesGateway: AgonesSDK
+
+ // Services
+ lateinit var playerMovementService: PlayerMovementService
+
+ // Tasks
private lateinit var healthcheckTask: ServerInterface.ScheduledTask
private var summonTimeoutTask: ServerInterface.ScheduledTask? = null
@@ -31,12 +38,7 @@ class ShulkerServerAgentCommon(val serverInterface: ServerInterface, private val
ShulkerServerAPI.INSTANCE = ShulkerServerAPIImpl(this)
- if (gameServer.objectMeta.containsLabels(SUMMON_LABEL_NAME)) {
- this.logger.info(
- "This server was summoned manually, it will be shutdown automatically in $SUMMON_TIMEOUT_MINUTES minutes" // ktlint-disable standard_max-line-length
- )
- this.summonTimeoutTask = this.createSummonTimeoutTask()
- }
+ this.playerMovementService = PlayerMovementService(this)
this.healthcheckTask = HealthcheckTask(this).schedule()
@@ -47,10 +49,16 @@ class ShulkerServerAgentCommon(val serverInterface: ServerInterface, private val
)
}
+ if (gameServer.objectMeta.containsLabels(SUMMON_LABEL_NAME)) {
+ this.logger.info(
+ "This server was summoned manually, it will be shutdown automatically in $SUMMON_TIMEOUT_MINUTES minutes" // ktlint-disable standard_max-line-length
+ )
+ this.summonTimeoutTask = this.createSummonTimeoutTask()
+ }
+
this.agonesGateway.setReady()
- } catch (e: Exception) {
- this.logger.severe("Shulker Agent crashed, stopping server")
- e.printStackTrace()
+ } catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
+ this.logger.log(Level.SEVERE, "Shulker Agent crashed, stopping server", e)
this.shutdown()
}
}
@@ -65,9 +73,12 @@ class ShulkerServerAgentCommon(val serverInterface: ServerInterface, private val
fun shutdown() {
try {
this.agonesGateway.askShutdown()
- } catch (ex: Exception) {
- this.logger.severe("Failed to ask Agones sidecar to shutdown properly, stopping process manually")
- ex.printStackTrace()
+ } catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
+ this.logger.log(
+ Level.SEVERE,
+ "Failed to ask Agones sidecar to shutdown properly, stopping process manually",
+ e
+ )
exitProcess(0)
}
}
diff --git a/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/platform/HookPostOrder.kt b/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/platform/HookPostOrder.kt
new file mode 100644
index 00000000..2bb29ad3
--- /dev/null
+++ b/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/platform/HookPostOrder.kt
@@ -0,0 +1,5 @@
+package io.shulkermc.serveragent.platform
+
+enum class HookPostOrder {
+ FIRST, EARLY, NORMAL, LATE, LAST, MONITOR
+}
diff --git a/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/platform/PlayerDisconnectHook.kt b/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/platform/PlayerDisconnectHook.kt
new file mode 100644
index 00000000..4771e758
--- /dev/null
+++ b/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/platform/PlayerDisconnectHook.kt
@@ -0,0 +1,3 @@
+package io.shulkermc.serveragent.platform
+
+typealias PlayerDisconnectHook = () -> Unit
diff --git a/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/platform/PlayerLoginHook.kt b/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/platform/PlayerLoginHook.kt
new file mode 100644
index 00000000..b216be20
--- /dev/null
+++ b/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/platform/PlayerLoginHook.kt
@@ -0,0 +1,3 @@
+package io.shulkermc.serveragent.platform
+
+typealias PlayerLoginHook = () -> Unit
diff --git a/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/services/PlayerMovementService.kt b/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/services/PlayerMovementService.kt
new file mode 100644
index 00000000..cea9e2d3
--- /dev/null
+++ b/packages/shulker-server-agent/src/common/kotlin/io/shulkermc/serveragent/services/PlayerMovementService.kt
@@ -0,0 +1,34 @@
+package io.shulkermc.serveragent.services
+
+import io.shulkermc.serveragent.Configuration
+import io.shulkermc.serveragent.ShulkerServerAgentCommon
+import io.shulkermc.serveragent.platform.HookPostOrder
+
+class PlayerMovementService(private val agent: ShulkerServerAgentCommon) {
+ init {
+ this.agent.serverInterface.addPlayerJoinHook(this::onPlayerJoin, HookPostOrder.MONITOR)
+ this.agent.serverInterface.addPlayerQuitHook(this::onPlayerQuit, HookPostOrder.MONITOR)
+ }
+
+ private fun onPlayerJoin() {
+ this.updateAllocationState(triggerFromJoin = true)
+ }
+
+ private fun onPlayerQuit() {
+ this.updateAllocationState(triggerFromJoin = false)
+ }
+
+ private fun updateAllocationState(triggerFromJoin: Boolean) {
+ if (Configuration.LIFECYCLE_STRATEGY !== Configuration.LifecycleStrategy.ALLOCATE_WHEN_NOT_EMPTY) {
+ return
+ }
+
+ val playerCount = this.agent.serverInterface.getPlayerCount()
+
+ if (triggerFromJoin && playerCount == 1) {
+ this.agent.agonesGateway.setAllocated()
+ } else if (!triggerFromJoin && playerCount == 1) {
+ this.agent.agonesGateway.setReady()
+ }
+ }
+}
diff --git a/packages/shulker-server-agent/src/paper/kotlin/io/shulkermc/serveragent/paper/ServerInterfacePaper.kt b/packages/shulker-server-agent/src/paper/kotlin/io/shulkermc/serveragent/paper/ServerInterfacePaper.kt
index 38fad97a..912c0f83 100644
--- a/packages/shulker-server-agent/src/paper/kotlin/io/shulkermc/serveragent/paper/ServerInterfacePaper.kt
+++ b/packages/shulker-server-agent/src/paper/kotlin/io/shulkermc/serveragent/paper/ServerInterfacePaper.kt
@@ -4,10 +4,16 @@ import io.shulkermc.serveragent.ServerInterface
import io.shulkermc.serveragent.paper.scheduler.ServerScheduler
import io.shulkermc.serveragent.paper.scheduler.ServerSchedulerFolia
import io.shulkermc.serveragent.paper.scheduler.ServerSchedulerPaper
-import org.bukkit.event.EventHandler
+import io.shulkermc.serveragent.platform.HookPostOrder
+import io.shulkermc.serveragent.platform.PlayerDisconnectHook
+import io.shulkermc.serveragent.platform.PlayerLoginHook
+import org.bukkit.event.Event
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
+import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.player.PlayerLoginEvent
+import org.bukkit.event.player.PlayerQuitEvent
+import org.bukkit.plugin.EventExecutor
import java.util.UUID
import java.util.concurrent.TimeUnit
@@ -23,6 +29,8 @@ class ServerInterfacePaper(private val plugin: ShulkerServerAgentPaper) : Server
}
}
+ private val eventListener = object : Listener {}
+
private val scheduler: ServerScheduler = if (isFoliaContext()) {
ServerSchedulerFolia(this.plugin)
} else {
@@ -30,19 +38,29 @@ class ServerInterfacePaper(private val plugin: ShulkerServerAgentPaper) : Server
}
override fun prepareNetworkAdminsPermissions(playerIds: List) {
- this.plugin.server.pluginManager.registerEvents(
- object : Listener {
- @EventHandler(priority = EventPriority.HIGHEST)
- fun onPlayerLogin(event: PlayerLoginEvent) {
- if (event.player.uniqueId in playerIds) {
- event.player.isOp = true
- // TODO: This may not be sufficient to give them all permissions
- // but there is solution to grant all of them without knowing them
- }
- }
- },
- this.plugin
- )
+ this.registerEventWithPriority(PlayerLoginEvent::class.java, HookPostOrder.FIRST) { event ->
+ if (event.player.uniqueId in playerIds) {
+ event.player.isOp = true
+ // TODO: This may not be sufficient to give them all permissions
+ // but there is solution to grant all of them without knowing them
+ }
+ }
+ }
+
+ override fun addPlayerJoinHook(hook: PlayerLoginHook, postOrder: HookPostOrder) {
+ this.registerEventWithPriority(PlayerJoinEvent::class.java, postOrder) {
+ hook()
+ }
+ }
+
+ override fun addPlayerQuitHook(hook: PlayerDisconnectHook, postOrder: HookPostOrder) {
+ this.registerEventWithPriority(PlayerQuitEvent::class.java, postOrder) {
+ hook()
+ }
+ }
+
+ override fun getPlayerCount(): Int {
+ return this.plugin.server.onlinePlayers.size
}
override fun scheduleDelayedTask(
@@ -57,4 +75,34 @@ class ServerInterfacePaper(private val plugin: ShulkerServerAgentPaper) : Server
timeUnit: TimeUnit,
runnable: Runnable
): ServerInterface.ScheduledTask = this.scheduler.scheduleRepeatingTask(delay, interval, timeUnit, runnable)
+
+ private fun registerEventWithPriority(
+ clazz: Class,
+ postOrder: HookPostOrder,
+ callback: (event: T) -> Unit
+ ) {
+ val executor = EventExecutor { _, event ->
+ @Suppress("UNCHECKED_CAST")
+ callback(event as T)
+ }
+
+ this.plugin.server.pluginManager.registerEvent(
+ clazz,
+ this.eventListener,
+ this.mapPostOrder(postOrder),
+ executor,
+ this.plugin
+ )
+ }
+
+ private fun mapPostOrder(postOrder: HookPostOrder): EventPriority {
+ return when (postOrder) {
+ HookPostOrder.FIRST -> EventPriority.LOWEST
+ HookPostOrder.EARLY -> EventPriority.LOW
+ HookPostOrder.NORMAL -> EventPriority.NORMAL
+ HookPostOrder.LATE -> EventPriority.HIGH
+ HookPostOrder.LAST -> EventPriority.HIGHEST
+ HookPostOrder.MONITOR -> EventPriority.MONITOR
+ }
+ }
}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 691672c5..0143b827 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -28,14 +28,14 @@ dependencyResolutionManagement {
plugin("buildconfig", "com.github.gmazzo.buildconfig").version("4.1.2")
plugin("shadow", "com.github.johnrengelman.shadow").version("8.1.0")
plugin("ktlint", "org.jlleitschuh.gradle.ktlint").version("11.6.1")
- plugin("detekt", "io.gitlab.arturbosch.detekt").version("1.23.1")
+ plugin("detekt", "io.gitlab.arturbosch.detekt").version("1.23.4")
}
}
}
fun includeBindingProject(name: String) {
- include(":packages:${name}")
- project(":packages:${name}").projectDir = file("packages/${name}/bindings/java")
+ include(":packages:$name")
+ project(":packages:$name").projectDir = file("packages/$name/bindings/java")
}
includeBindingProject("google-agones-sdk")