feat(Steamworks): add auto-configuration for Steamworks integration and update README
This commit is contained in:
18
README.md
18
README.md
@@ -1107,13 +1107,25 @@ No additional configuration required.
|
||||
#### Purpose and Overview
|
||||
Provides integration with the Steam platform API through a connector abstraction. Supports Steam features including user identity, Steam overlay, lobbies, achievements, and rich presence. The connector is designed as a singleton and can be optionally initialized when running on Steam.
|
||||
|
||||
**Note**: This is an optional component that requires the Steamworks4J library and proper Steam initialization.
|
||||
**Note**: This is an optional component that requires the Steamworks4J library and proper Steam initialization. It is **disabled by default** and must be explicitly enabled via configuration property.
|
||||
|
||||
#### Setup / Autoconfiguration
|
||||
No auto-configuration provided. Must be manually initialized by setting `SteamworksConnector.setInstance()` with a concrete implementation (e.g., `SteamworksConnectorImpl`).
|
||||
**Configuration Class**: `SteamworksAutoConfiguration`
|
||||
|
||||
**Property**: `game-engine.steamworks.enabled` (default: `false`)
|
||||
|
||||
The auto-configuration is guarded by two conditions:
|
||||
- `game-engine.steamworks.enabled=true` must be set
|
||||
- The `com.codedisaster.steamworks.SteamAPI` class must be present on the classpath (`@ConditionalOnClass`)
|
||||
|
||||
When enabled, `SteamworksConnectorImpl` is instantiated, registered as the singleton via `SteamworksConnector.setInstance()`, and a `SteamworksRunner` thread (implementing `SmartLifecycle`) is started to drive the Steam callback loop. The runner has a phase of `Integer.MAX_VALUE` (starts last, stops first) and will gracefully shut down the Steam API on context close.
|
||||
|
||||
#### Exposed Spring Beans
|
||||
None (managed as a singleton via static accessor)
|
||||
- **`SteamworksConnector`** (via `SteamworksConnectorImpl`): The Steam API connector singleton
|
||||
- **`SteamworksRunner`**: Lifecycle-managed callback runner thread
|
||||
|
||||
#### Integration Notes
|
||||
If a custom `SteamworksConnector` bean is provided, the auto-configuration will not create `SteamworksConnectorImpl` but will still create the `SteamworksRunner` to drive callbacks. Both beans use `@ConditionalOnMissingBean`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>de.extio</groupId>
|
||||
<artifactId>game-engine</artifactId>
|
||||
<version>1.0.24</version>
|
||||
<version>1.0.25</version>
|
||||
|
||||
<properties>
|
||||
<java.version>25</java.version>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package de.extio.game_engine.steamworks;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@AutoConfiguration
|
||||
@ConditionalOnProperty(name = "game-engine.steamworks.enabled", havingValue = "true")
|
||||
@ConditionalOnClass(name = "com.codedisaster.steamworks.SteamAPI")
|
||||
public class SteamworksAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(SteamworksConnector.class)
|
||||
SteamworksConnectorImpl steamworksConnector() {
|
||||
final var connector = new SteamworksConnectorImpl();
|
||||
SteamworksConnector.setInstance(connector);
|
||||
return connector;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
SteamworksRunner steamworksRunner(final SteamworksConnector connector) {
|
||||
return new SteamworksRunner(connector);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,8 @@
|
||||
package de.extio.game_engine.steamworks;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -17,7 +13,6 @@ import com.codedisaster.steamworks.SteamAuth.AuthSessionResponse;
|
||||
import com.codedisaster.steamworks.SteamAuthTicket;
|
||||
import com.codedisaster.steamworks.SteamFriends;
|
||||
import com.codedisaster.steamworks.SteamFriends.OverlayDialog;
|
||||
import com.codedisaster.steamworks.SteamFriends.OverlayToWebPageMode;
|
||||
import com.codedisaster.steamworks.SteamFriends.PersonaChange;
|
||||
import com.codedisaster.steamworks.SteamFriendsCallback;
|
||||
import com.codedisaster.steamworks.SteamID;
|
||||
@@ -29,18 +24,9 @@ import com.codedisaster.steamworks.SteamMatchmaking.ChatMemberStateChange;
|
||||
import com.codedisaster.steamworks.SteamMatchmaking.ChatRoomEnterResponse;
|
||||
import com.codedisaster.steamworks.SteamMatchmaking.LobbyType;
|
||||
import com.codedisaster.steamworks.SteamMatchmakingCallback;
|
||||
import com.codedisaster.steamworks.SteamNativeHandle;
|
||||
import com.codedisaster.steamworks.SteamPublishedFileID;
|
||||
import com.codedisaster.steamworks.SteamRemoteStorage;
|
||||
import com.codedisaster.steamworks.SteamRemoteStorage.PublishedFileVisibility;
|
||||
import com.codedisaster.steamworks.SteamResult;
|
||||
import com.codedisaster.steamworks.SteamUGC;
|
||||
import com.codedisaster.steamworks.SteamUGC.ItemInstallInfo;
|
||||
import com.codedisaster.steamworks.SteamUGC.ItemUpdateInfo;
|
||||
import com.codedisaster.steamworks.SteamUGC.ItemUpdateStatus;
|
||||
import com.codedisaster.steamworks.SteamUGCCallback;
|
||||
import com.codedisaster.steamworks.SteamUGCDetails;
|
||||
import com.codedisaster.steamworks.SteamUGCQuery;
|
||||
import com.codedisaster.steamworks.SteamUGCUpdateHandle;
|
||||
import com.codedisaster.steamworks.SteamUser;
|
||||
import com.codedisaster.steamworks.SteamUserCallback;
|
||||
@@ -115,11 +101,6 @@ public final class SteamworksConnectorImpl extends SteamworksConnector {
|
||||
|
||||
@Override
|
||||
public void runCallbacks() {
|
||||
|
||||
|
||||
// TODO: Executor thread
|
||||
|
||||
|
||||
if (!this.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package de.extio.game_engine.steamworks;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
|
||||
public final class SteamworksRunner implements SmartLifecycle {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
private static final int SLEEP_MS = 33;
|
||||
|
||||
private final SteamworksConnector connector;
|
||||
|
||||
private final AtomicBoolean running = new AtomicBoolean();
|
||||
|
||||
private Thread thread;
|
||||
|
||||
public SteamworksRunner(final SteamworksConnector connector) {
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (this.running.compareAndSet(false, true)) {
|
||||
LOGGER.debug(() -> "SteamworksRunner starting");
|
||||
|
||||
this.thread = new Thread(this::run, "SteamworksRunner");
|
||||
this.thread.setDaemon(true);
|
||||
this.thread.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (this.running.compareAndSet(true, false)) {
|
||||
LOGGER.debug(() -> "SteamworksRunner stopping");
|
||||
final Thread t = this.thread;
|
||||
if (t != null) {
|
||||
t.interrupt();
|
||||
try {
|
||||
t.join(3000);
|
||||
}
|
||||
catch (final InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return this.running.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoStartup() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(final Runnable callback) {
|
||||
this.stop();
|
||||
callback.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPhase() {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
private void run() {
|
||||
try {
|
||||
while (this.running.get() && this.connector.isActive()) {
|
||||
this.connector.runCallbacks();
|
||||
Thread.sleep(SLEEP_MS);
|
||||
}
|
||||
}
|
||||
catch (final InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
catch (final Throwable t) {
|
||||
LOGGER.warn("Error in SteamworksRunner", t);
|
||||
}
|
||||
finally {
|
||||
this.connector.shutdown();
|
||||
LOGGER.debug(() -> "SteamworksRunner stopped");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,3 +8,4 @@ de.extio.game_engine.i18n.LocalizationAutoConfiguration
|
||||
de.extio.game_engine.resource.StaticResourceAutoConfiguration
|
||||
de.extio.game_engine.audio.AudioAutoConfiguration
|
||||
de.extio.game_engine.menu.MenuAutoConfiguration
|
||||
de.extio.game_engine.steamworks.SteamworksAutoConfiguration
|
||||
|
||||
Reference in New Issue
Block a user