code-disaster / steamworks4j Goto Github PK
View Code? Open in Web Editor NEWA thin Java wrapper to access the Steamworks API
Home Page: https://code-disaster.github.io/steamworks4j/
License: MIT License
A thin Java wrapper to access the Steamworks API
Home Page: https://code-disaster.github.io/steamworks4j/
License: MIT License
When I request UGC details as followed
SteamPublishedFileID [] ids = new SteamPublishedFileID[steamUGC.getNumSubscribedItems()];
steamUGC.getSubscribedItems(ids);
steamUGC.sendQueryUGCRequest(steamUGC.createQueryUGCDetailsRequest(Arrays.asList(ids)));
In my callback method onUGCQueryCompleted() gets called instead of onRequestUGCDetails(). I currently manually call onRequestUGCDetails() from onUGCQueryCompleted(), but I think this is not the intended behavior.
Hello,
I have seen you added a method isDlcInstalled in SteamApps object, but current release (v1.6.2) doesn't have this method yet.
Would you mind releasing current build so we can use this function?
Also, will it be possible to add function to retrieve steamworks4j library version?
We can use that for debugging purposes.
Thank you very much!
Les
Hi,
since the last few changes, the server could not be loaded anymore. I get the following error in my client/server test case (the missing DLL exists in steamworks4j-server-1.7.0-SNAPSHOT.jar):
Steam API initialized: true
Steam client active: true
Steam API initialized: true
Steam client active: true
java.lang.UnsatisfiedLinkError: C:\Users\Alrik\AppData\Local\Temp\steamworks4j\1.7.0-SNAPSHOT\steamworks4j-server64.dll: Can't find dependent libraries
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1824)
at java.lang.Runtime.load0(Runtime.java:809)
at java.lang.System.load(System.java:1086)
at com.codedisaster.steamworks.SteamSharedLibraryLoader.loadLibrary(SteamSharedLibraryLoader.java:122)
at com.codedisaster.steamworks.SteamGameServerAPI.init(SteamGameServerAPI.java:32)
at com.codedisaster.steamworks.SteamGameServerAPI.init(SteamGameServerAPI.java:17)
at net.qb.steamworks.SteamworksStateServer.<init>(SteamworksStateServer.java:54)
at net.qb.steamworks.SteamworkTest.main(SteamworkTest.java:53)
java.lang.UnsatisfiedLinkError: com.codedisaster.steamworks.SteamGameServerAPINative.getSteamGameServerPointer()J
at com.codedisaster.steamworks.SteamGameServerAPINative.getSteamGameServerPointer(Native Method)
at com.codedisaster.steamworks.SteamGameServer.<init>(SteamGameServer.java:33)
at net.qb.steamworks.SteamworksStateServer.initialize(SteamworksStateServer.java:97)
at com.jme3.app.state.AppStateManager.initializePending(AppStateManager.java:251)
at com.jme3.app.state.AppStateManager.update(AppStateManager.java:281)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:236)
at net.qb.steamworks.SteamworkTest.initSteamworks(SteamworkTest.java:70)
at net.qb.steamworks.SteamworkTest.simpleInitApp(SteamworkTest.java:268)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:220)
at com.jme3.system.lwjgl.LwjglWindow.initInThread(LwjglWindow.java:500)
at com.jme3.system.lwjgl.LwjglWindow.run(LwjglWindow.java:600)
at com.jme3.system.lwjgl.LwjglWindow.create(LwjglWindow.java:445)
at com.jme3.app.LegacyApplication.start(LegacyApplication.java:463)
at com.jme3.app.LegacyApplication.start(LegacyApplication.java:424)
at com.jme3.app.SimpleApplication.start(SimpleApplication.java:125)
at net.qb.steamworks.SteamworkTest.main(SteamworkTest.java:65)
Would it be possible to add in GetImageSize from ISteamUtils because without it its not possible to generate an avatar. Thanks in advance.
Khm. Unless I again understand steamworks' docs wrong, those methods are supposed to be called when the user subscribes to an item externally while the game is running (via steam client, steam overlay web browser, etc.). Or are these methods only supposed to be called when I subscribe with my code? According to the steamworks' docs, those methods are actually supposed to be in SteamRemoteStorageCallback, but I agree that they make more sense where they are.
I put some printlns in there and nothing gets called.
Hi,
I'm testing the latest snapshot and I can't get the authentication system to work anymore.
More specifically, everything is fine client-side, the ticket is generated.
Then I transmit it to the server, and the server calls beginAuthSession with the ticket.
I receive a BeginAuthSessionResult.OK, just like in previous version.
The problem is: at this point, onValidateAuthTicketResponse of the server callback should be called, and it seems that it's never called anymore.
Please note that the ticket is fine because the snapshot client works well with older-version servers.
Edit: It might be a config problem with my steam game, I'm not sure why but actually I don't receive this callback anymore even in the previous versions, with the current steam client. Strangely enough it still works on a linux server. Well, please disregard this issue for now
Regards,
Marc Fortin
getLobbyMemberLimit() returns an int value, not a boolean.
You can zap the signatures in SteamMatchmaking.java and it all works even without any changes in the underlying native lib (at least on Windows)
As a follow-up to the ability to set tags, it would also be very useful to be able to get them, by adding the tags field to SteamUGCDetails.
In my particular case, I'm uploading ship designs that really need both an exterior and an interior view for people to see. Being able to specify multiple preview images would be very useful for this.
The following code (which seems to be correct, based on Valve's sparse documentation and having looked at SpaceWar) returns an array of null values
try {
SteamAPI.init();
} catch (SteamException e) {
e.printStackTrace();
}
SteamController controller = new SteamController();
controller.init();
SteamControllerHandle[] handles = new SteamControllerHandle[STEAM_CONTROLLER_MAX_COUNT];
controller.getConnectedControllers(handles);
My controller is definitely connected, as I can use it in SpaceWar, 3rd party games, and Windows itself
Both of the init methods return true
EDIT: The SteamControllerTestApp that you provide also doesn't detect any controllers, so I'm assuming it's a problem on my end?
Hi,
I was wondering what are your plans about adding new functions ?
I know that you only wrote what you needed, but I think it would be very useful to integrate more api stuffs.
I saw that franzbischoff forked the project and added game server functions, don't know what are his plans about pulling its fork to this one.
Also, I could help to add new functionalites, no problem, the only problem is that I'm under linux and so I can't compile the library for macos and windows.
But anyway, tell me your plans (franzbischoff if you read this, you are welcome :)) and if I can help, I'm ready !
Hi,
I've got this error message after calling SteamAPI.restartAppIfNecessary(APPID) as the very first command:
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.codedisaster.steamworks.SteamAPI.restartAppIfNecessary(I)Z
at com.codedisaster.steamworks.SteamAPI.restartAppIfNecessary(Native Method)
...
I tried to fix the problem but I have no idea whats wrong with it.
Hi again!
Would it be possible to ask for the addition of getServerRealTime to the framework?
This should, as documented, return a long with the current Unix time stamp.
I believe that this should be a simple wrapper/getter method on the existing underlying method.
Thank you so much!
Danny
Hi,
First I'd like to thank you very much for the awesome work.
Here is the issue I'm facing: everything works well when I launch from Eclipse, with a 64-bit JVM.
Everything works well when I launch from a 32-bit packr exe, with a 32-bit JVM.
But it crash when I launch from a 64-bit packr exe, with a 64-bit JVM.
I tried several JVM (OpenJDK 7, Java SE 8) and it crashed exactly the same:
A fatal error has been detected by the Java Runtime Environment:
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ff98f3b6996, pid=8980, tid=12792
JRE version: OpenJDK Runtime Environment (7.0-b31) (build 1.7.0-u45-unofficial-b31)
Java VM: OpenJDK 64-Bit Server VM (24.45-b08 mixed mode windows-amd64 compressed oops)
Problematic frame:
C [steamworks4j64.dll+0x6996]A fatal error has been detected by the Java Runtime Environment:
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ff9930e6996, pid=704, tid=5368
JRE version: Java(TM) SE Runtime Environment (8.0_71-b15) (build 1.8.0_71-b15)
Java VM: Java HotSpot(TM) 64-Bit Server VM (25.71-b15 mixed mode windows-amd64 compressed ops)
Problematic frame:
C [steamworks4j64.dll+0x6996]
The game start well, init() is done without problem, but it crash when I use getPersonaName to retrieve the full username of the player (which works well in 32-bit).
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j com.codedisaster.steamworks.SteamFriends.getPersonaName(J)Ljava/lang/String;+0
j com.codedisaster.steamworks.SteamFriends.getPersonaName()Ljava/lang/String;+4
j net.osaris.alchemist.multiplayer.User.checkAuth()Z+34
j net.osaris.alchemist.j.i.()V+63
j net.osaris.alchemist.j.i.a()V+4
j net.osaris.alchemist.j.()V+140
j net.osaris.alchemist.a.g()V+117
j net.osaris.alchemist.a.render()V+636
j com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop()V+684
j com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run()V+27
v ~StubRoutines::call_stub
Here is the full crash file: http://pastebin.com/tLmcqKNu
Let me know if you need more info.
Thanks!
Hi,
I'm trying to use steam workshop and I'm facing some issues.
As function names are different, I can't figure how to simply publish a file on workshop.
I tried publishWorkshopFile but I always have "fileNotFound". Same for fileWrite or fileShare...
Has this been updated?
What is the best way to initialize a new "user"?
SteamAPI.init();
user = new SteamUser(SteamAPI.getSteamUserPointer());
userStats = new SteamUserStats(SteamAPI.getSteamUserStatsPointer(), userStatsCallback);
Hey there, I am attempting to utilize steam cloud by writing a chunk to an open stream. After appearing to open a file stream successfully my application crashes when I run:
ByteBuffer writeBuffer = ByteBuffer.allocate(100);
String mockFileContents = "This is a test of remote file writes.";
writeBuffer.put(mockFileContents.getBytes());
SteamUGCFileWriteStreamHandle filestream = steamCloud.fileWriteStreamOpen(remoteFilename);
steamCloud.fileWriteStreamWriteChunk(filestream, writeBuffer, 100); //FAILS HERE
steamCloud.fileWriteStreamClose(filestream);
When looking at the exception when the JVM crashes I see:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000005080863b, pid=3756, tid=0x0000000000000f78
#
# JRE version: Java(TM) SE Runtime Environment (8.0_131-b11) (build 1.8.0_131-b11)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C [steamclient64.dll+0x7b863b]
Also here are the stack frames:
Stack: [0x0000000020aa0000,0x0000000020f70000], sp=0x0000000020f6ef48, free space=4923k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [steamclient64.dll+0x7b863b]
C [steamclient64.dll+0x636003]
C [steamclient64.dll+0x374049]
C [steamclient64.dll+0x34cb21]
C 0x0000000003be5c74
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j com.codedisaster.steamworks.SteamRemoteStorage.fileWriteStreamWriteChunk(JJLjava/nio/ByteBuffer;I)Z+0
j com.codedisaster.steamworks.SteamRemoteStorage.fileWriteStreamWriteChunk(Lcom/codedisaster/steamworks/SteamUGCFileWriteStreamHandle;Ljava/nio/ByteBuffer;I)Z+10
j com.megacrit.cardcrawl.steam.SteamSaveSync.syncFileToCloud(Ljava/lang/String;Ljava/lang/String;)V+230
j com.megacrit.cardcrawl.core.CardCrawlGame.create()V+344
j com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop()V+29
j com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run()V+27
v ~StubRoutines::call_stub
We are using the latest version of steamworks4j (1.6.2).
I installed steamworks4j 1.0.1 using gradle and my IDE (IntelliJ IDEA) says that SteamFriendsCallback doesn't exist. Your example code contains reference to this class and I searched in your repository and it's there. I don't know what going on. I will try refreshing gradle, but if this doesn't succeed it is probably something wrong in your code.
Hello,
How to open a web page INSIDE Steam Client?
Is that possible?
Les
I already told code-disaster about this one, but I figured for sake of completion I should make a github issue.
Essentially aggregated stats don't have the proper functions implemented in order to properly use them. All this really requires is adding the equivalent global stat functions parallel with the local/player stat function
SteamApps is currently missing some functions relating to checking if DLC is installed. I need access to
virtual bool BIsDlcInstalled( AppId_t appID ) = 0;
It would be helpful if this was added. Thanks
Greetings,
I am currently developing Steam Workshop support for an application and during item creation and submission, the process can fail due several reasons. As stated on the Steamworks SDK, there is no way of canceling the process once it's done. As such, temporary junk file appear on the user's workshop due to the error caused.
One solution I found to fix this is to call DeleteItem after an unsuccessful submission. However, the SteamUGC does not seem to implement this method call. Is this intended?
Best Regards,
Diogo Braga
Hi Guys,
I couldn't find how to get the ticket token using steamworks4j. Here is my snippet.
`try {
SteamUser steamUser = new SteamUser(userCallback);
System.out.println(steamUser.getSteamID());
ByteBuffer userAuthTicketData = ByteBuffer.allocateDirect(256);
int[] sizeRequired = new int[1];
SteamAuthTicket userAuthTicket = steamUser.getAuthSessionTicket(userAuthTicketData, sizeRequired);
System.out.println(userAuthTicket.isValid()); //true
} catch (SteamException e) {
}`
Could anyone give some tips? Thanks in advanced!
I've received an error report from one of my testers. He uses Linux mint 64bit but libsteam_api.so was loaded instead of libsteam_api64.so.
This is the error report:
********** qb-CrashReport (7/1/17 12:56 AM) **********
java.lang.UnsatisfiedLinkError: /tmp/steamworks4j/1.7.0-SNAPSHOT/libsteam_api.so: /tmp/steamworks4j/1.7.0-SNAPSHOT/libsteam_api.so: wrong ELF class: ELFCLASS32 (Possible cause: architecture word width mismatch)
**** Details ****
**** Environment ****
Java: 1.8.0_121 64 Bit Oracle Corporation
JVM Args: -Xmx2G
Memory (DIRECT): 1 MB (used) / 89 Buffers
Memory (HEAP): 45 MB (used) / 195 MB (free) / 240 MB (total) / 1820 MB (max)
OpenGL Renderer Information:
* Vendor: NVIDIA Corporation
* Renderer: GeForce GTX 1050 Ti/PCIe/SSE2
* OpenGL Version: 3.2.0 NVIDIA 375.39
* GLSL Version: 1.50 NVIDIA via Cg compiler
OS: Linux 4.4.0-77-generic amd64
Processors: 4
qb-Version: 0.3.0.2
**** StackTrace ****
java.lang.UnsatisfiedLinkError: /tmp/steamworks4j/1.7.0-SNAPSHOT/libsteam_api.so: /tmp/steamworks4j/1.7.0-SNAPSHOT/libsteam_api.so: wrong ELF class: ELFCLASS32 (Possible cause: architecture word width mismatch)
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1824)
at java.lang.Runtime.load0(Runtime.java:809)
at java.lang.System.load(System.java:1086)
at com.codedisaster.steamworks.SteamSharedLibraryLoader.loadLibrary(SteamSharedLibraryLoader.java:122)
at com.codedisaster.steamworks.SteamAPI.init(SteamAPI.java:19)
at com.codedisaster.steamworks.SteamAPI.init(SteamAPI.java:10)
at Bw.<init>(Unknown Source)
at net.qb.QbClient.simpleInitApp(Unknown Source)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:220)
at com.jme3.system.lwjgl.QbWindow.initInThread(Unknown Source)
at com.jme3.system.lwjgl.QbWindow.run(Unknown Source)
at com.jme3.system.lwjgl.QbWindow.create(Unknown Source)
at com.jme3.app.LegacyApplication.start(LegacyApplication.java:463)
at com.jme3.app.LegacyApplication.start(LegacyApplication.java:424)
at com.jme3.app.SimpleApplication.start(SimpleApplication.java:125)
at net.qb.QbClient.<init>(Unknown Source)
at net.qb.QbClient.main(Unknown Source)
Hi,
is it possible to implement the encrypted app ticket functionality? It does not require any connection to a running steam client and basically works "offline".
This is a great library! Thanks :-D
Anyhow, I got a request. In order to invite friends to games, the following methods would really come in handy. With rich presence (2) you can inform others about a game you are playing & people can connect to it. The invite functionality (1) allows to directly invite players to a game! This obviously only makes sense for multiplayer games.
Implementation Required:
(1) SteamFriends.inviteUserToGame
(2) SteamFriends.setRichPresence
(2) SteamFriendsCallback.onGameRichPresenceJoinRequested
Thanks for the consideration :)
I used your test application code with minor changes (to see if it works on my system before adding more code) and I ran it, my IDE (again, IntelliJ IDEA) says in it's log:
Initialise Steam API ...
Process Finished with Exit Code -1
Connected to the target VM, address: '127.0.0.1:51430', transport: 'socket'
Initialise Steam API ...
Disconnected from the target VM, address: '127.0.0.1:51430', transport: 'socket'
Process finished with exit code -1
package awesomespider.labyrinth;
import com.codedisaster.steamworks.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Scanner;
/**
* Created by Wyatt on 4/6/2015.
*/
public class Labyrinth {
private SteamUser user;
private SteamUserStats userStats;
private SteamRemoteStorage remoteStorage;
private SteamUGC ugc;
private SteamUtils utils;
private SteamApps apps;
private SteamFriends friends;
private SteamLeaderboardHandle currentLeaderboard = null;
private SteamUserStatsCallback userStatsCallback = new SteamUserStatsCallback() {
@Override
public void onUserStatsReceived(long gameId, long userId, SteamResult result) {
System.out.println("User stats received: gameId=" + gameId + ", userId=" + userId +
", result=" + result.toString());
int numAchievements = userStats.getNumAchievements();
System.out.println("Num of achievements: " + numAchievements);
for (int i = 0; i < numAchievements; i++) {
String name = userStats.getAchievementName(i);
boolean achieved = userStats.isAchieved(name, false);
System.out.println("# " + i + " : name=" + name + ", achieved=" + (achieved ? "yes" : "no"));
}
}
@Override
public void onUserStatsStored(long gameId, SteamResult result) {
System.out.println("User stats stored: gameId=" + gameId +
", result=" + result.toString());
}
@Override
public void onLeaderboardFindResult(SteamLeaderboardHandle leaderboard, boolean found) {
System.out.println("Leaderboard find result: handle=" + leaderboard.toString() +
", found=" + (found ? "yes" : "no"));
if (found) {
System.out.println("Leaderboard: name=" + userStats.getLeaderboardName(leaderboard) +
", entries=" + userStats.getLeaderboardEntryCount(leaderboard));
currentLeaderboard = leaderboard;
}
}
@Override
public void onLeaderboardScoresDownloaded(SteamLeaderboardHandle leaderboard,
SteamLeaderboardEntriesHandle entries,
int numEntries) {
System.out.println("Leaderboard scores downloaded: handle=" + leaderboard.toString() +
", entries=" + entries.toString() + ", count=" + numEntries);
for (int i = 0; i < numEntries; i++) {
SteamLeaderboardEntry entry = new SteamLeaderboardEntry();
if (userStats.getDownloadedLeaderboardEntry(entries, i, entry)) {
System.out.println("Leaderboard entry #" + i +
": steamIDUser=" + entry.getSteamIDUser().getAccountID() +
", globalRank=" + entry.getGlobalRank() +
", score=" + entry.getScore());
if (friends.requestUserInformation(entry.getSteamIDUser(), true)) {
System.out.println(" ... requested user information for entry");
} else {
System.out.println(" ... user name is '" +
friends.getFriendPersonaName(entry.getSteamIDUser()) + "'");
}
}
}
}
@Override
public void onLeaderboardScoreUploaded(boolean success,
SteamLeaderboardHandle leaderboard,
int score,
boolean scoreChanged,
int globalRankNew,
int globalRankPrevious) {
System.out.println("Leaderboard score uploaded: " + (success ? "yes" : "no") +
", handle=" + leaderboard.toString() +
", score=" + score +
", changed=" + (scoreChanged ? "yes" : "no") +
", globalRankNew=" + globalRankNew +
", globalRankPrevious=" + globalRankPrevious);
}
};
private SteamRemoteStorageCallback remoteStorageCallback = new SteamRemoteStorageCallback() {
@Override
public void onFileShareResult(SteamUGCHandle fileHandle, String fileName, SteamResult result) {
System.out.println("Remote storage file share result: handle='" + fileHandle.toString() +
", name=" + fileName + "', result=" + result.toString());
}
@Override
public void onDownloadUGCResult(SteamUGCHandle fileHandle, SteamResult result) {
System.out.println("Remote storage download UGC result: handle='" + fileHandle.toString() +
"', result=" + result.toString());
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
int offset = 0, bytesRead;
do {
bytesRead = remoteStorage.ugcRead(fileHandle, buffer, buffer.limit(), offset,
SteamRemoteStorage.UGCReadAction.ContinueReadingUntilFinished);
offset += bytesRead;
} while (bytesRead > 0);
System.out.println("Read " + offset + " bytes from handle=" + fileHandle.toString());
}
@Override
public void onPublishFileResult(SteamPublishedFileID publishedFileID, boolean needsToAcceptWLA, SteamResult result) {
System.out.println("Remote storage publish file result: publishedFileID=" + publishedFileID.toString() +
", needsToAcceptWLA=" + needsToAcceptWLA + ", result=" + result.toString());
}
@Override
public void onUpdatePublishedFileResult(SteamPublishedFileID publishedFileID, boolean needsToAcceptWLA, SteamResult result) {
System.out.println("Remote storage update published file result: publishedFileID=" + publishedFileID.toString() +
", needsToAcceptWLA=" + needsToAcceptWLA + ", result=" + result.toString());
}
};
private SteamUGCCallback ugcCallback = new SteamUGCCallback() {
@Override
public void onUGCQueryCompleted(SteamUGCQuery query, int numResultsReturned, int totalMatchingResults,
boolean isCachedData, SteamResult result) {
System.out.println("UGC query completed: handle=" + query.toString() + ", " + numResultsReturned + " of " +
totalMatchingResults + " results returned, result=" + result.toString());
for (int i = 0; i < numResultsReturned; i++) {
SteamUGCDetails details = new SteamUGCDetails();
ugc.getQueryUGCResult(query, i, details);
System.out.println("UGC details #" + i +
": publishedFileID=" + details.getPublishedFileID().toString() +
", result=" + details.getResult().toString() +
", title='" + details.getTitle() + "'" +
", description='" + details.getDescription() + "'" +
", fileName=" + details.getFileName() +
", fileHandle=" + details.getFileHandle().toString() +
", previewFileHandle=" + details.getPreviewFileHandle().toString());
}
ugc.releaseQueryUserUGCRequest(query);
}
};
private SteamFriendsCallback friendsCallback = new SteamFriendsCallback() {
@Override
public void onPersonaStateChange(SteamID steamID, SteamFriends.PersonaChange change) {
switch (change) {
case Name:
System.out.println("Persona name received: " +
"accountID=" + steamID.getAccountID() +
", name='" + friends.getFriendPersonaName(steamID) + "'");
break;
default:
System.out.println("Persona state changed (unhandled: " +
"accountID=" + steamID.getAccountID() +
", change=" + change.name());
break;
}
}
};
class InputHandler implements Runnable {
private volatile boolean alive;
private Thread mainThread;
private Scanner scanner;
public InputHandler(Thread mainThread) {
this.alive = true;
this.mainThread = mainThread;
this.scanner = new Scanner(System.in);
scanner.useDelimiter("[\r\n\t]");
}
@Override
public void run() {
while (alive && mainThread.isAlive()) {
if (scanner.hasNext()) {
String input = scanner.next();
if (input.equals("q")) {
alive = false;
} else if (input.equals("stats request")) {
userStats.requestCurrentStats();
} else if (input.equals("stats store")) {
userStats.storeStats();
} else if (input.equals("file list")) {
int numFiles = remoteStorage.getFileCount();
System.out.println("Num of files: " + numFiles);
for (int i = 0; i < numFiles; i++) {
int[] sizes = new int[1];
String name = remoteStorage.getFileNameAndSize(i, sizes);
boolean exists = remoteStorage.fileExists(name);
System.out.println("# " + i + " : name=" + name + ", size=" + sizes[0] + ", exists=" + (exists ? "yes" : "no"));
}
} else if (input.startsWith("file write ")) {
String path = input.substring("file write ".length());
File file = new File(path);
try {
FileInputStream in = new FileInputStream(file);
SteamUGCFileWriteStreamHandle remoteFile = remoteStorage.fileWriteStreamOpen(path);
if (remoteFile != null) {
byte[] bytes = new byte[1024];
int bytesRead;
while((bytesRead = in.read(bytes, 0, bytes.length)) > 0) {
ByteBuffer buffer = ByteBuffer.allocateDirect(bytesRead);
buffer.put(bytes, 0, bytesRead);
remoteStorage.fileWriteStreamWriteChunk(remoteFile, buffer, buffer.limit());
}
remoteStorage.fileWriteStreamClose(remoteFile);
}
} catch (IOException e) {
e.printStackTrace();
}
} else if (input.startsWith("file delete ")) {
String path = input.substring("file delete ".length());
if (remoteStorage.fileDelete(path)) {
System.out.println("deleted file '" + path + "'");
}
} else if (input.startsWith("file share ")) {
remoteStorage.fileShare(input.substring("file share ".length()));
} else if (input.startsWith("file publish ")) {
String[] paths = input.substring("file publish ".length()).split(" ");
if (paths.length >= 2) {
System.out.println("publishing file: " + paths[0] + ", preview file: " + paths[1]);
remoteStorage.publishWorkshopFile(paths[0], paths[1], utils.getAppID(),
"Test UGC!", "Dummy UGC file published by SteamAPITestApplication.",
SteamRemoteStorage.PublishedFileVisibility.Private, null,
SteamRemoteStorage.WorkshopFileType.Community);
}
} else if (input.startsWith("file republish ")) {
String[] paths = input.substring("file republish ".length()).split(" ");
if (paths.length >= 3) {
System.out.println("republishing id: " + paths[0] + ", file: " + paths[1] + ", preview file: " + paths[2]);
SteamPublishedFileID fileID = new SteamPublishedFileID(Long.parseLong(paths[0]));
SteamPublishedFileUpdateHandle updateHandle = remoteStorage.createPublishedFileUpdateRequest(fileID);
if (updateHandle != null) {
remoteStorage.updatePublishedFileFile(updateHandle, paths[1]);
remoteStorage.updatePublishedFilePreviewFile(updateHandle, paths[2]);
remoteStorage.updatePublishedFileTitle(updateHandle, "Updated Test UGC!");
remoteStorage.updatePublishedFileDescription(updateHandle, "Dummy UGC file *updated* by SteamAPITestApplication.");
remoteStorage.commitPublishedFileUpdate(updateHandle);
}
}
} else if (input.equals("ugc query")) {
SteamUGCQuery query = ugc.createQueryUserUGCRequest(user.getSteamID().getAccountID(), SteamUGC.UserUGCList.Subscribed,
SteamUGC.MatchingUGCType.UsableInGame, SteamUGC.UserUGCListSortOrder.TitleAsc,
utils.getAppID(), utils.getAppID(), 1);
if (query.isValid()) {
System.out.println("sending UGC query: " + query.toString());
//ugc.setReturnTotalOnly(query, true);
ugc.sendQueryUGCRequest(query);
}
} else if (input.startsWith("ugc download ")) {
String name = input.substring("ugc download ".length());
SteamUGCHandle handle = new SteamUGCHandle(Long.parseLong(name, 16));
remoteStorage.ugcDownload(handle, 0);
} else if (input.startsWith("leaderboard find ")) {
String name = input.substring("leaderboard find ".length());
userStats.findLeaderboard(name);
} else if (input.startsWith("leaderboard list ")) {
String[] params = input.substring("leaderboard list ".length()).split(" ");
if (currentLeaderboard != null && params.length >= 2) {
userStats.downloadLeaderboardEntries(currentLeaderboard,
SteamUserStats.LeaderboardDataRequest.Global,
Integer.valueOf(params[0]), Integer.valueOf(params[1]));
}
} else if (input.startsWith("leaderboard score ")) {
String score = input.substring("leaderboard score ".length());
if (currentLeaderboard != null) {
System.out.println("uploading score " + score + " to leaderboard " + currentLeaderboard.toString());
userStats.uploadLeaderboardScore(currentLeaderboard,
SteamUserStats.LeaderboardUploadScoreMethod.KeepBest, Integer.valueOf(score));
}
} else if (input.startsWith("apps subscribed ")) {
String appId = input.substring("apps subscribed ".length());
boolean subscribed = apps.isSubscribedApp(Long.parseLong(appId));
System.out.println("user described to app #" + appId + ": " + (subscribed ? "yes" : "no"));
}
}
}
}
public boolean alive() {
return alive;
}
}
private boolean run(@SuppressWarnings("unused") String[] arguments) throws SteamException {
System.out.println("Initialise Steam API ...");
if (!SteamAPI.init()) {
return false;
}
System.out.println("Register user ...");
user = new SteamUser(SteamAPI.getSteamUserPointer());
System.out.println("Register user stats callback ...");
userStats = new SteamUserStats(SteamAPI.getSteamUserStatsPointer(), userStatsCallback);
System.out.println("Register remote storage ...");
remoteStorage = new SteamRemoteStorage(SteamAPI.getSteamRemoteStoragePointer(), remoteStorageCallback);
System.out.println("Register UGC ...");
ugc = new SteamUGC(SteamAPI.getSteamUGCPointer(), ugcCallback);
System.out.println("Register Utils ...");
utils = new SteamUtils(SteamAPI.getSteamUtilsPointer());
System.out.println("Register Apps ...");
apps = new SteamApps(SteamAPI.getSteamAppsPointer());
System.out.println("Register Friends ...");
friends = new SteamFriends(SteamAPI.getSteamFriendsPointer(), friendsCallback);
System.out.println("Local user account ID: " + user.getSteamID().getAccountID());
System.out.println("App ID: " + utils.getAppID());
InputHandler inputHandler = new InputHandler(Thread.currentThread());
new Thread(inputHandler).start();
while (inputHandler.alive() && SteamAPI.isSteamRunning()) {
// process callbacks
SteamAPI.runCallbacks();
try {
// sleep a little (Steam says it should poll at least 15 times/second)
Thread.sleep(1000 / 15);
} catch (InterruptedException e) {
// ignore
}
}
System.out.println("Shutting down Steam API ...");
SteamAPI.shutdown();
System.out.println("Bye!");
return true;
}
public static void main(String[] arguments) {
try {
if (!new Labyrinth().run(arguments)) {
System.exit(-1);
}
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
}
It seems as though Steam isn't initializing properly. The method run(String[] arguments
is returning false (from what I gather from this code) which is making the exit code be -1. What should I do?
First off, thanks for making this wrapper, it's awesome. I am having an issue with connecting to steam's servers. I am using some code from your example programs.
Log (ignore X's):
Register user ...
Setting breakpad minidump AppID = 392020
Steam_SetMinidumpSteamID: Caching Steam ID: XXXXXXXXXXXXXXXXX [API loaded no]
Register user stats callback ...
Register remote storage ...
Register UGC ...
Register Utils ...
Local user account ID: XXXXXXXXX
App ID: 392020
requestCurrentStats: true
User stats received: gameId=392020, userId=XXXXXXXXX, result=Fail
Num of achievements: 0
Process finished with exit code 255
The program goes like this:
result=Fail
.I cannot access any stats or achievements, which are vital to me releasing my game on schedule. What is going on here? Could it have something to do with Steamworks4j being out of date with Steam's API (1.33 vs. 1.34)?
I'm on Ubuntu 14.04 x86_64 with OpenJDK 7, running Intellij IDEA with libGDX, if it matters.
Thanks,
-wes
There is currently no way to update the tags of a published file. Would it be possible to add that functionality?
(Really great library BTW.)
I was using steamworks4j 1.2.2 and after last Windows Defenders virus signature update my game is now detected with Trojan WIN32/Varpes.L!cl
The trojan is detected inside steamworks4j.dll
I tried updating to 1.2.3 but same problem, and indeed if I download the file from github ( https://github.com/code-disaster/steamworks4j/raw/f42a033279de75c85c1e59cfb8e8ea4e9f2e8044/natives/libs/steamworks4j.dll ) Windows Defender immediately detects it as a trojan
Online anti virus don't seem to find anything suspicious on this file, but my game is basically unplayable on default Windows installation...
I have been using your library for some time and it works great, thanks!
I am trying to integrate with Steam leaderboards and everything works smoothly except getting user avatars. Here is the code I use:
int imageId = Steam.friends.getSmallFriendAvatar(steamID);
int imageWidth = Steam.utils.getImageWidth(imageId);
int imageHeight = Steam.utils.getImageHeight(imageId);
int sizeInBytes = imageWidth * imageHeight * 4;
byte[] content = new byte[sizeInBytes];
ByteBuffer buffer = ByteBuffer.wrap(content);
boolean ok = Steam.utils.getImageRGBA(imageId, buffer, sizeInBytes);
steamID is my Steam ID or that of a Steam friend so I know there is something associated with it and I can access it.
getSmallFriendAvatar()
returns an int > 0
getImageWidth()
=> 32
getImageHeight()
=> 32
But buffer
remains full of 0s...
Am I missing something?
ByteBuffer authTicket = ByteBuffer.allocate(2048);
int authSessionTicket = steamUser.getAuthSessionTicket(authTicket);
byte[] array = authTicket.array();
I'm getting back a zero array. I don't see how to register ValidateAuthTicketResponse_t. I've tried waiting for 10s of second before checking the buffer but even then it's not filled.
I tried the SteamMatchmakingTestApp from the matchmaking branch. After staring it gave me:
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.codedisaster.steamworks.SteamAPI.getSteamMatchmakingPointer()J
at com.codedisaster.steamworks.SteamAPI.getSteamMatchmakingPointer(Native Method)
at com.codedisaster.steamworks.SteamMatchmaking.<init>(SteamMatchmaking.java:136)
at com.codedisaster.steamworks.test.SteamMatchmakingTestApp.registerInterfaces(SteamMatchmakingTestApp.java:153)
at com.codedisaster.steamworks.test.SteamTestApp.runAsClient(SteamTestApp.java:75)
at com.codedisaster.steamworks.test.SteamTestApp.clientMain(SteamTestApp.java:111)
at com.codedisaster.steamworks.test.SteamMatchmakingTestApp.main(SteamMatchmakingTestApp.java:255)
Any suggestions on how to get it to work?
Hi again!
Would it be possible to request support for an onSteamShutdown() sort of callback to be added?
It seems as if the SDK supports a callback listener attached to ISteamUtils for the reporting of Steam being closed.
This allows for notification of the Steam app being closed out from behind of the currently running game.
In my experience (and, this may just be my games?), upon Steam being requested to close, it will first fire an onSteamShutdown callback toward the running game, and then wait for the running game to close first. In my experience, without this callback, this can sometimes lead to a very long timeout, if this callback is not utilized.
Thank you again!
Danny
Without this method it is impossible to tell if you are connected to the remote end or not, so it's kinda very required to do any actual work.
Running more than one app using Steamworks4J will result in an error accessing the steam_api.dll for the second app. Please note those apps run independently on different JVMs. This is the error that the 2nd app will receive:
steam_api.dll (The process cannot access the file because it is being used by another process)
It appears the first app locks access to the steam_api.dll preventing the 2nd app from using it/initializing Steam! Could that DLL be simply placed in a separate temp directory to make it all work again?
Stacktrace:
com.codedisaster.steamworks.SteamException: java.io.FileNotFoundException: C:\Users\CHRIST~1\AppData\Local\Temp\steamworks4j\ec05efa3\steam_api.dll (The process cannot access the file because it is being used by another process)
at SteamSharedLibraryLoader.loadLibraries(SteamSharedLibraryLoader.java:163)
at com.codedisaster.steamworks.SteamAPI.init(SteamAPI.java:15)
at com.codedisaster.steamworks.SteamAPI.init(SteamAPI.java:10)
at com.noblemaster.lib.boot.plaf.impl.commondesk.arch.t.a(SourceFile:91)
at com.noblemaster.lib.boot.plaf.impl.commondesk.arch.p.a(SourceFile:199)
at com.noblemaster.lib.gear.b.b.b.i.c(SourceFile:140)
at com.noblemaster.lib.boot.a.m.n(SourceFile:145)
at com.noblemaster.lib.boot.a.l.i(SourceFile:37)
at com.noblemaster.lib.boot.a.m.i(SourceFile:177)
at com.noblemaster.lib.boot.plaf.impl.b.g.create(SourceFile:623)
at com.noblemaster.lib.boot.plaf.impl.b.ae.create(SourceFile:400)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:147)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:124)
Caused by: java.io.FileNotFoundException: C:\Users\CHRIST~1\AppData\Local\Temp\steamworks4j\ec05efa3\steam_api.dll (The process cannot access the file because it is being used by another process)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(Unknown Source)
at java.io.FileOutputStream.<init>(Unknown Source)
at SteamSharedLibraryLoader.extractLibrary(SteamSharedLibraryLoader.java:115)
at SteamSharedLibraryLoader.loadLibraries(SteamSharedLibraryLoader.java:83)
at SteamSharedLibraryLoader.loadLibraries(SteamSharedLibraryLoader.java:161)
... 12 more
How to get friends list in steamworks4j?
I followed the instructions on how to compile the code (http://code-disaster.github.io/steamworks4j/build-instructions.html). But it did not work. The instructions are not very easy to follow. Please could you simplify the steps or just add a .jar file to the github repo. Thanks.
How to get a username / user details from a SteamID ?
There is "requestUserInformation" in SteamFriends, but for what I understand, the callback may be "onPersonaStateChange", but it only returns persona state and steam ID.
Is it incomplete or is there another way ?
Is this implemented yet? I'd like to create lobbies and be able to use matchmaking features in my game at some point. The features are here: https://partner.steamgames.com/documentation/matchmaking
How hard would it be to add in these to the wrapper?
Does this lib support the use of the MicroTxnAuthorizationResponse_t used for in-game shops? I could not find it when I looked through the JNI natives folder but I was hoping I might have missed it. If it is not supported do you have any plans to add it?
Calling getAccountID
returns zero from getLobbyMemberByIndex
for all calls and similar error for getLobbyOwner
.
Tested with dozens of different lobbies and application runs. Added the following snippet to the SteamMatchmakingTestApp with same results.
@Override
public void onLobbyMatchList(int lobbiesMatching) {
System.out.println("Found " + lobbiesMatching + " matching lobbies.");
lobbies.clear();
for (int i = 0; i < lobbiesMatching; i++) {
SteamID lobby = matchmaking.getLobbyByIndex(i);
lobbies.put(lobby.getNativeHandle(), lobby);
int memberCount = matchmaking.getNumLobbyMembers(lobby);
for(int m = 0; m < memberCount; m++) {
SteamID member = matchmaking.getLobbyMemberByIndex(lobby, m);
System.out.println("ACCOUNT ID: " + member.getAccountID()); // ACCOUNT ID: 0
}
}
}
Any ideas?
I was wondering if you could release a beta tag (or final if you think it's stable) for the current snapshot? Was hoping to use the new simpler API in my game.
Btw, love the library, you should try get it stickied on the Steam Developer Group as I had started coding my own JNI wrapper before I discovered this.
Hi,
In the latest snapshot, there seems to be a problem in the way libs are loaded on linux.
The function "isSdkLibName" is used even when the sdk path is not used, and this leads to never have 64 in the getPlatformLibName on linux.
So when not using the sdk, the 32 bit version is used instead of 64 bit and the game crash:
java.lang.UnsatisfiedLinkError: /tmp/steamworks4j/1.7.0-SNAPSHOT/libsteam_api.so: /tmp/steamworks4j/1.7.0-SNAPSHOT/libsteam_api.so: неправильный класс ELF: ELFCLASS32 (Possible cause: architecture word width mismatch)
Another problem, in windows, some antivirus block the use of extracted libs:
Exception in thread "LWJGL Application" com.badlogic.gdx.utils.GdxRuntimeException: java.lang.UnsatisfiedLinkError: C:\Users\antho\AppData\Local\Temp\steamworks4j\1.7.0-SNAPSHOT\steam_api64.dll: Access is denied
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(Unknown Source)
Caused by: java.lang.UnsatisfiedLinkError: C:\Users\antho\AppData\Local\Temp\steamworks4j\1.7.0-SNAPSHOT\steam_api64.dll: Access is denied
So, it would be great to have a option to not extract the lib and simply read it from a folder where it is put on game install.
The current API doesn't work well across the network. SteamID is not serializable, nor would I really want to be forced to send SteamID structure across the network and persist then with the account save files and require steamworks4j deserilization to open my save files. Luckily getNativeHandle() is exposed although deprecrated. Using the steamid handle is better since steam can't easily change it so it's not an implementation detail that's likely to break.
On the server side receiving/storing a raw steamid handle is ideal. However I can't create a SteamID to call 'steamGameServerStats.setUserAchievement(steamIDHandle, key);' because SteamID(long) is private.
I understand that hiding the steamid handle is better for single player game but I think there needs to be a solution for multi player games. Either SteamID(long) could be made public or perhaps some more explicit SteamID.createFromRemoteHandle(long) function to stear single player games to avoid this.
Hi there!
Thank you so much for this awesome code base! I would love to use it in our upcoming game.
Would it be possible to add support for details to the leaderboard methods?
To do so, it seems like the following would be needed:
I would appreciate this very much if possible.
Thank you so much!
Danny
Hello.
Exit from the Steam application brings in end of a thread of JavaFX. At first I thought that steamworks finishes a thread in which the initialization was made. However it not, because if I make initialization in other thread and exit from Steam, then JavaFX thread terminated. I'm sorry, my English is bad.
Change log describes a version 1.2.4 that I am unable to download from Maven.
<dependency> <groupId>com.code-disaster.steamworks4j</groupId> <artifactId>steamworks4j</artifactId> <version>1.2.4</version> </dependency>
Could not find artifact com.code-disaster.steamworks4j:steamworks4j:jar:1.2.4 in central (http://repo.maven.apache.org/maven2)
Version 1.2.3 does work however.
Previously, I was able to download a published file by name using the following code:
public static byte[] readFile(String name) throws SteamException {
int sz = storage.getFileSize(name);
ByteBuffer bb = ByteBuffer.allocateDirect(sz);
storage.fileRead(name, bb, sz);
byte[] a = new byte[sz];
bb.get(a);
return a;
}
Now, storage.getFileSize returns 0.
Does the wrapper have any access to steam inventory yet? I was thinking of using it but I haven't read anything about it or know how it works. How would you go about securing items in a game and tying them to steam accounts inventory? If you have any idea please let me know.
What would stop a player from just adding the items themselves if they have access the client jar.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.