diff --git a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamNetworkingMessage.java b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamNetworkingMessage.java new file mode 100644 index 00000000..2450de72 --- /dev/null +++ b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamNetworkingMessage.java @@ -0,0 +1,20 @@ +package com.codedisaster.steamworks; + +public class SteamNetworkingMessage { + + public byte[] payload; + + public int connectionHandle; + + public SteamNetworkingMessage() { + + } + + public byte[] getPayload() { + return payload; + } + + public long getConnectionHandle() { + return connectionHandle; + } +} diff --git a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamNetworkingSockets.java b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamNetworkingSockets.java new file mode 100644 index 00000000..9b4e88ee --- /dev/null +++ b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamNetworkingSockets.java @@ -0,0 +1,176 @@ +package com.codedisaster.steamworks; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; + +public class SteamNetworkingSockets extends SteamInterface { + + public static final int SEND_FLAG_UNRELIABLE = 0; + public static final int SEND_FLAG_NO_NAGLE = 1; + public static final int SEND_FLAG_NO_DELAY = 4; + public static final int SEND_FLAG_RELIABLE = 8; + public static final int SEND_FLAG_AUTO_RESTART = 32; + + public SteamNetworkingSockets(SteamNetworkingSocketsCallback callback) { + super(SteamNetworkingSocketsNative.createCallback(callback)); + } + + public int connectP2P(long steamID, int numVirtualPorts){ + return SteamNetworkingSocketsNative.connectP2P(steamID, numVirtualPorts); + } + + public int createListenSocketP2P(int numVirtualPorts){ + return SteamNetworkingSocketsNative.createListenSocketP2P(numVirtualPorts); + } + + /** + * Accepts an incoming connection request. + * + * @param connectionHandle The handle of the connection to be accepted. + * @return {@link SteamResult} indicating the result of the operation: + * + * This method communicates with the native SteamNetworkingSockets API to accept a connection. + */ + public SteamResult acceptConnection(int connectionHandle) { + int result = SteamNetworkingSocketsNative.acceptConnection(connectionHandle); + return SteamResult.byValue(result); + } + + + public boolean closeConnection(int connectionHandle, int reason, boolean linger){ + return SteamNetworkingSocketsNative.closeConnection(connectionHandle, reason, linger); + } + + public boolean closeListenSocket(int socketHandle){ + return SteamNetworkingSocketsNative.closeListenSocket(socketHandle); + } + + /** + * Sends a message to a specified connection. + * + * @param connectionHandle The handle of the connection to which the message is sent. + * @param data The byte array containing the message to be sent. + * @param sendFlags Flags controlling how the message is sent. + * @return {@link SteamResult} indicating the result of the operation. Possible values include: + * + * This method interfaces with the native SteamNetworkingSockets API for message transmission. + */ + public SteamResult sendMessageToConnection(int connectionHandle, byte[] data, int sendFlags) { + + ByteBuffer buffer = ByteBuffer.allocateDirect(data.length); + buffer.put(data); + + int result = SteamNetworkingSocketsNative.sendMessageToConnection(connectionHandle, buffer, data.length, sendFlags); + return SteamResult.byValue(result); + } + + + /** + * Flushes messages for a specified connection. + * + * @param connectionHandle The handle of the connection to flush messages for. + * @return {@link SteamResult} indicating the result of the operation. Possible values include: + * + * This method communicates with the native SteamNetworkingSockets API to perform the operation. + */ + public SteamResult flushMessages(int connectionHandle) { + int result = SteamNetworkingSocketsNative.flushMessages(connectionHandle); + return SteamResult.byValue(result); + } + + + public int receiveMessagesOnConnection(int connectionHandle, SteamNetworkingMessage[] messages){ + return SteamNetworkingSocketsNative.receiveMessagesOnConnection(connectionHandle, messages, messages.length); + } + + public int createPollGroup(){ + return SteamNetworkingSocketsNative.createPollGroup(); + } + + public boolean destroyPollGroup(int handle){ + return SteamNetworkingSocketsNative.destroyPollGroup(handle); + } + + public boolean setConnectionPollGroup(int connectionHandle, int pollGroupHandle){ + return SteamNetworkingSocketsNative.setConnectionPollGroup(connectionHandle, pollGroupHandle); + } + + public int receiveMessagesOnPollGroup(int pollGroupHandle, SteamNetworkingMessage[] messages){ + return SteamNetworkingSocketsNative.receiveMessagesOnPollGroup(pollGroupHandle, messages, messages.length); + } + + public SteamNetworkingAvailability initAuthentication(){ + int state = SteamNetworkingSocketsNative.initAuthentication(); + return SteamNetworkingAvailability.fromValue(state); + } + + public SteamNetworkingAvailability getAuthenticationStatus(){ + int state = SteamNetworkingSocketsNative.getAuthenticationStatus(); + return SteamNetworkingAvailability.fromValue(state); + } + + public void initRelayNetworkAccess(){ + SteamNetworkingSocketsNative.initRelayNetworkAccess(); + } + + public SteamNetworkingAvailability getRelayNetworkStatus(){ + int state = SteamNetworkingSocketsNative.getRelayNetworkStatus(); + return SteamNetworkingAvailability.fromValue(state); + } + + public enum SteamNetworkingAvailability { + // Enum values + CANNOT_TRY(-102), + FAILED(-101), + PREVIOUSLY(-100), + RETRYING(-10), + NEVER_TRIED(1), + WAITING(2), + ATTEMPTING(3), + CURRENT(100), + UNKNOWN(0); + + private final int value; + + // Static map to store the mapping from int values to enum constants + private static final Map valueToEnumMap = new HashMap<>(); + + // Static block to populate the map + static { + for (SteamNetworkingAvailability availability : values()) { + valueToEnumMap.put(availability.value, availability); + } + } + + SteamNetworkingAvailability(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + // Function to get enum by its value + public static SteamNetworkingAvailability fromValue(int value) { + return valueToEnumMap.getOrDefault(value, UNKNOWN); + } + } + + +} diff --git a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamNetworkingSocketsCallback.java b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamNetworkingSocketsCallback.java new file mode 100644 index 00000000..26dc12ad --- /dev/null +++ b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamNetworkingSocketsCallback.java @@ -0,0 +1,65 @@ +package com.codedisaster.steamworks; + +public interface SteamNetworkingSocketsCallback { + + void onConnectionStatusChanged(int connectionHandle, long steamID, int connectionState, int prevState); + + public static enum ConnectionState { + /** + * Indicates an error condition in the API. The specified connection doesn't exist or has already been closed. + */ + NONE(0), + + /** + * The process of establishing a connection is ongoing. This includes basic authentication, key exchange, etc. + * For client-side connections, this means the connection attempt is in progress. + * For server-side connections, it means the connection is ready to be accepted. + * Unreliable packets sent now are likely to be dropped. + */ + CONNECTING(1), + + /** + * The connection is in the process of finding a route (for certain connection types). + * Unreliable messages are likely to be discarded during this state. + */ + FINDING_ROUTE(2), + + /** + * A stable connection has been established. Reliable data sent before closing will be flushed and acknowledged. + */ + CONNECTED(3), + + /** + * The connection has been closed by the peer but not yet closed locally. The connection still exists, + * and any inbound messages can be retrieved before closing it. + */ + CLOSED_BY_PEER(4), + + /** + * A local disruption in the connection (e.g., timeout, local internet connection issue) has been detected. + * The connection still exists, but attempts to send messages will fail. + */ + PROBLEM_DETECTED_LOCALLY(5); + + private final int value; + + ConnectionState(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static ConnectionState fromValue(int value) { + for (ConnectionState state : values()) { + if (state.value == value) { + return state; + } + } + return null; // or throw an exception + } + } + + +} diff --git a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamNetworkingSocketsNative.java b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamNetworkingSocketsNative.java new file mode 100644 index 00000000..7a0f4dde --- /dev/null +++ b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamNetworkingSocketsNative.java @@ -0,0 +1,170 @@ +package com.codedisaster.steamworks; + +import java.nio.ByteBuffer; + +final class SteamNetworkingSocketsNative { + + // @off + + /*JNI + #include + #include "SteamNetworkingSocketsCallback.h" + #include + */ + + static native void initRelayNetworkAccess(); /* + SteamNetworkingUtils()->InitRelayNetworkAccess(); + */ + + static native int getRelayNetworkStatus();/* + return SteamNetworkingUtils()->GetRelayNetworkStatus(NULL); + */ + + static native long createCallback(SteamNetworkingSocketsCallback javaCallback); /* + return (intp) new SteamNetworkingSocketsCallback(env, javaCallback); + */ + + public static native int connectP2P(long steamID, int numVirtualPorts);/* + SteamNetworkingIdentity identity; + identity.m_eType = k_ESteamNetworkingIdentityType_SteamID; + identity.SetSteamID64(steamID); + + HSteamNetConnection connection = SteamNetworkingSockets()->ConnectP2P(identity, numVirtualPorts, 0, NULL); + + return connection; + */ + + public static native int createListenSocketP2P(int numVirtualPorts);/* + HSteamListenSocket socket = SteamNetworkingSockets()->CreateListenSocketP2P(numVirtualPorts, 0, NULL); + + return socket; + */ + + public static native int acceptConnection(int netConnectionHandle);/* + return SteamNetworkingSockets()->AcceptConnection(netConnectionHandle); + */ + + public static native boolean closeConnection(int netConnectionHandle, int reason, boolean linger);/* + return SteamNetworkingSockets()->CloseConnection(netConnectionHandle, reason, NULL, linger); + */ + + public static native boolean closeListenSocket(int socketHandle);/* + return SteamNetworkingSockets()->CloseListenSocket(socketHandle); + */ + + public static native int sendMessageToConnection(int netConnectionHandle, ByteBuffer data, int dataLength, int sendFlags);/* + return SteamNetworkingSockets()->SendMessageToConnection(netConnectionHandle, (const void*) data, dataLength, sendFlags, NULL); + */ + + public static native int receiveMessagesOnConnection(int netConnectionHandle, SteamNetworkingMessage[] messageBuffer, int maxMessages);/* + + if(maxMessages <= 0){ + return 0; + } + + jsize arrayLength = env->GetArrayLength(messageBuffer); + + if(arrayLength < maxMessages){ + return 0; + } + + SteamNetworkingMessage_t** ppOutMessages = new SteamNetworkingMessage_t*[maxMessages]; + + int num = SteamNetworkingSockets()->ReceiveMessagesOnConnection(netConnectionHandle, ppOutMessages, maxMessages); + + for(int i = 0; i < num;i++){ + SteamNetworkingMessage_t* netMessage = ppOutMessages[i]; + + jobject message = env->GetObjectArrayElement(messageBuffer, i); + jclass clazz = env->GetObjectClass(message); + + jfieldID payloadField = env->GetFieldID(clazz, "payload", "[B"); + jfieldID connectionField = env->GetFieldID(clazz, "connectionHandle", "I"); + + jbyteArray javaByteArray = env->NewByteArray(netMessage->m_cbSize); + + env->SetByteArrayRegion(javaByteArray, 0, netMessage->m_cbSize, (const jbyte*) netMessage->m_pData); + + env->SetIntField(message, connectionField, netMessage->m_conn); + env->SetObjectField(message, payloadField, javaByteArray); + + env->DeleteLocalRef(javaByteArray); + env->DeleteLocalRef(message); + + netMessage->Release(); + } + + delete[] ppOutMessages; + + return num; + */ + + public static native int flushMessages(int connectionHandle);/* + return SteamNetworkingSockets()->FlushMessagesOnConnection(connectionHandle); + */ + + public static native int createPollGroup(); /* + HSteamNetPollGroup pollGroup = SteamNetworkingSockets()->CreatePollGroup(); + + return pollGroup; + */ + + public static native boolean destroyPollGroup(int handle); /* + return SteamNetworkingSockets()->DestroyPollGroup(handle); + */ + + public static native boolean setConnectionPollGroup(int connectionHandle, int pollGroupHandle); /* + return SteamNetworkingSockets()->SetConnectionPollGroup(connectionHandle, pollGroupHandle); + */ + + public static native int receiveMessagesOnPollGroup(int pollGroupHandle, SteamNetworkingMessage[] messageBuffer, int maxMessages);/* + if(maxMessages <= 0){ + return 0; + } + + jsize arrayLength = env->GetArrayLength(messageBuffer); + + if(arrayLength < maxMessages){ + return 0; + } + + SteamNetworkingMessage_t** ppOutMessages = new SteamNetworkingMessage_t*[maxMessages]; + + int num = SteamNetworkingSockets()->ReceiveMessagesOnPollGroup(pollGroupHandle, ppOutMessages, maxMessages); + + for(int i = 0; i < num;i++){ + SteamNetworkingMessage_t* netMessage = ppOutMessages[i]; + + jobject message = env->GetObjectArrayElement(messageBuffer, i); + jclass clazz = env->GetObjectClass(message); + + jfieldID payloadField = env->GetFieldID(clazz, "payload", "[B"); + jfieldID connectionField = env->GetFieldID(clazz, "connectionHandle", "I"); + + jbyteArray javaByteArray = env->NewByteArray(netMessage->m_cbSize); + + env->SetByteArrayRegion(javaByteArray, 0, netMessage->m_cbSize, (const jbyte*) netMessage->m_pData); + + env->SetIntField(message, connectionField, netMessage->m_conn); + env->SetObjectField(message, payloadField, javaByteArray); + + env->DeleteLocalRef(javaByteArray); + env->DeleteLocalRef(message); + + netMessage->Release(); + } + + delete[] ppOutMessages; + + return num; + */ + + public static native int initAuthentication();/* + return SteamNetworkingSockets()->InitAuthentication(); + */ + + public static native int getAuthenticationStatus();/* + return SteamNetworkingSockets()->GetAuthenticationStatus(NULL); + */ + +} diff --git a/java-wrapper/src/main/native/SteamNetworkingSocketsCallback.cpp b/java-wrapper/src/main/native/SteamNetworkingSocketsCallback.cpp new file mode 100644 index 00000000..655c8c64 --- /dev/null +++ b/java-wrapper/src/main/native/SteamNetworkingSocketsCallback.cpp @@ -0,0 +1,18 @@ +#include "SteamNetworkingSocketsCallback.h" + +SteamNetworkingSocketsCallback::SteamNetworkingSocketsCallback(JNIEnv* env, jobject callback) : + SteamCallbackAdapter(env, callback) { +} + +SteamNetworkingSocketsCallback::~SteamNetworkingSocketsCallback() { +} + +void SteamNetworkingSocketsCallback::onConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t* callback) { + invokeCallback({ + callVoidMethod(env, "onConnectionStatusChanged", "(IJII)V", + callback->m_hConn, + callback->m_info.m_identityRemote.GetSteamID64(), + callback->m_info.m_eState, + callback->m_eOldState); + }); +} \ No newline at end of file diff --git a/java-wrapper/src/main/native/SteamNetworkingSocketsCallback.h b/java-wrapper/src/main/native/SteamNetworkingSocketsCallback.h new file mode 100644 index 00000000..a70c30d6 --- /dev/null +++ b/java-wrapper/src/main/native/SteamNetworkingSocketsCallback.h @@ -0,0 +1,14 @@ +#pragma once + +#include "SteamCallbackAdapter.h" +#include + +class SteamNetworkingSocketsCallback : public SteamCallbackAdapter { + +public: + SteamNetworkingSocketsCallback(JNIEnv* env, jobject callback); + ~SteamNetworkingSocketsCallback(); + + STEAM_CALLBACK(SteamNetworkingSocketsCallback, onConnectionStatusChanged, SteamNetConnectionStatusChangedCallback_t); + +}; \ No newline at end of file diff --git a/java-wrapper/src/main/resources/steamworks4j.dll b/java-wrapper/src/main/resources/steamworks4j.dll index 86dc3a55..608dd75d 100644 Binary files a/java-wrapper/src/main/resources/steamworks4j.dll and b/java-wrapper/src/main/resources/steamworks4j.dll differ diff --git a/java-wrapper/src/main/resources/steamworks4j64.dll b/java-wrapper/src/main/resources/steamworks4j64.dll index f1649909..4037cb26 100644 Binary files a/java-wrapper/src/main/resources/steamworks4j64.dll and b/java-wrapper/src/main/resources/steamworks4j64.dll differ diff --git a/server/src/main/resources/steamworks4j-encryptedappticket.dll b/server/src/main/resources/steamworks4j-encryptedappticket.dll index 53f560e7..d126e478 100644 Binary files a/server/src/main/resources/steamworks4j-encryptedappticket.dll and b/server/src/main/resources/steamworks4j-encryptedappticket.dll differ diff --git a/server/src/main/resources/steamworks4j-encryptedappticket64.dll b/server/src/main/resources/steamworks4j-encryptedappticket64.dll index 7752c99e..d88e17b5 100644 Binary files a/server/src/main/resources/steamworks4j-encryptedappticket64.dll and b/server/src/main/resources/steamworks4j-encryptedappticket64.dll differ diff --git a/server/src/main/resources/steamworks4j-server.dll b/server/src/main/resources/steamworks4j-server.dll index 7bfd18c1..b36271a6 100644 Binary files a/server/src/main/resources/steamworks4j-server.dll and b/server/src/main/resources/steamworks4j-server.dll differ diff --git a/server/src/main/resources/steamworks4j-server64.dll b/server/src/main/resources/steamworks4j-server64.dll index 8a85d72c..b25df386 100644 Binary files a/server/src/main/resources/steamworks4j-server64.dll and b/server/src/main/resources/steamworks4j-server64.dll differ