Coder Social home page Coder Social logo

code-disaster / steamworks4j Goto Github PK

View Code? Open in Web Editor NEW
461.0 34.0 64.0 18.16 MB

A thin Java wrapper to access the Steamworks API

Home Page: https://code-disaster.github.io/steamworks4j/

License: MIT License

Lua 1.16% Shell 0.44% Java 64.97% C++ 25.92% C 7.31% Batchfile 0.20%
java bindings steamworks

steamworks4j's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

steamworks4j's Issues

SteamUGCCallback onRequestUGCDetails() not being called

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.

Steam isDlcInstalled not in the latest release

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

Windows Library could not be loaded

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)

SteamUGCCallback onSubscribeItem() and onUnsubscribeItem() not called

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.

Authentication problem

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

SteamController interface can't find controllers

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?

add new functionalities / future plans

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 !

SteamAPI.restartAppIfNecessary(APPID) not working

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.

iSteamUtils.getServerRealTime

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

Crash when using bundled 64-bit bundled JRE on Windows

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!

steam workshop process

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...

Can no longer call SteamAPI.getSteamUserPointer()

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);

Crashes while attempting to write to remote storage.

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).

SteamFriendsCallback doesn't exist in 1.0.1

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.

Global stats are not implemented

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 BIsDlcInstalled

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

SteamUGC deleteItem() not implemented

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

How do I get the ticket token.

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!

64Bit Linux loads wrong lib file

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)

Request: Friend Invites & Rich Presence

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 :)

Exit Code -1: The SteamAPI Doesn't Initialize

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
When I tried debuging it however, it only said this:
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


I don't know what's going on. Here is my code:

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?

Cannot get any stats / achievements.

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:

  • I set all my callbacks for the user, user stats, remote storage, etc.
  • Then I call requestCurrentStats (which returns true).
  • But the retrieval callback says that it failed: result=Fail.
  • If I try to use the data, it gives me no achievements, even though I set up 7 of them.

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

Windows Defender detects a trojan in steamworks4j.dll

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...

SteamUtils.getImageRGBA leaves buffer empty

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?

getAuthSessionTicket not filling buffer

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.

Steam Matchmaking UnsatisfiedLink on startup

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?

Support for Steam Shutdown Callback

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

Bug: Running 2+ Steam Apps /w Steamworks4J (steam_api.dll cannot be accessed)

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 username/user details from steamID ?

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 ?

MicroTxnAuthorizationResponse_t callback

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?

SteamMatching getLobbyMemberByIndex returns bad SteamID

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?

Beta tag of next release?

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.

Crashes while loading native libs

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.

SteamID(long id) should be public (or expose an equivilent API)

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.

Details Support for Leaderboards

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:

  • In SteamUserStats.uploadLeaderboardScore: Accept an int[] argument containing the details into be uploaded
  • In SteamUserStats.getDownloadedLeaderboardEntry, accept an int[] arguments into which the received details can be passed back. (Or, put an int[] field into the SteamLeaderboardEntry class?).

I would appreciate this very much if possible.

Thank you so much!
Danny

Exit from Steam produce terminating of JavaFX thread

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.

Version 1.2.4 is not available in Maven repository

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.

Downloading a published file via fileRead has stopped working

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.

Steam Inventory?

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.