Compare commits
67 Commits
Author | SHA1 | Date | |
---|---|---|---|
19abe80449 | |||
fa39179be7 | |||
3566190a01 | |||
592f134d80 | |||
794bbccd51 | |||
8bceae0a3a | |||
4cf8ca5670 | |||
e07806424b | |||
5882823830 | |||
4dcb4afd2e | |||
6dc12b82c6 | |||
432166ef1d | |||
bd995f047d | |||
63b467f81d | |||
9c6495ab3e | |||
21eb1e459b | |||
ff24776107 | |||
70cd486e13 | |||
7ca912a5ac | |||
10383339cc | |||
0144c8200c | |||
9b07431476 | |||
ad86b14b79 | |||
93510d492e | |||
8dab07035f | |||
b87c6c9b5b | |||
f45eb6c443 | |||
759af3a89e | |||
d102b33ed3 | |||
c0899fd512 | |||
dbb7b626b0 | |||
88f47486cb | |||
0271889b2e | |||
54bef63d67 | |||
c82cc94538 | |||
470259e8b0 | |||
f6853fac1b | |||
f06b187d2d | |||
ee11358d7f | |||
7324ae890c | |||
7fe7e2ab53 | |||
27e39a0ec5 | |||
60ad70adc2 | |||
a7eb65355e | |||
2311a26eb0 | |||
67a81b82cd | |||
1e971e1161 | |||
120fe1b069 | |||
d5e6c4c11a | |||
c3c27c730d | |||
1b7f782f57 | |||
059ab337c8 | |||
52bdc2714d | |||
98852fba82 | |||
e69f9fbf71 | |||
a6a9b6259f | |||
ef60ec40c3 | |||
6774b5d881 | |||
6b10bd6c51 | |||
93d9ba10c2 | |||
6338a572d3 | |||
9eb7e41c4b | |||
ffab428366 | |||
20ad7e4ced | |||
bfcfd10baa | |||
f617f3b78d | |||
1f6fd05884 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
/build*/
|
/build*/
|
||||||
/.vscode/
|
/.vscode/
|
||||||
/thirdparty/
|
/thirdparty/
|
||||||
|
.vs/
|
||||||
|
@ -52,8 +52,3 @@ add_library(rapidjson STATIC IMPORTED ${RAPIDJSON})
|
|||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
add_subdirectory(examples/send-presence)
|
add_subdirectory(examples/send-presence)
|
||||||
|
|
||||||
add_custom_target(bundle
|
|
||||||
WORKING_DIRECTORY "${CMAKE_INSTALL_PREFIX}"
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E tar cfvz "${CMAKE_BINARY_DIR}/discord-rpc.tar.gz" .
|
|
||||||
)
|
|
||||||
|
44
README.md
44
README.md
@ -1,16 +1,23 @@
|
|||||||
# Discord RPC
|
# Discord RPC
|
||||||
|
|
||||||
This is a lib and a couple of quick demos, one that implements the very minimal subset to show
|
This is a lib and quick demos that implement the very minimal subset to show current status, and
|
||||||
current status, and one that is more complete. The idea here is to give you an lib that implements
|
have callbacks for where a more complete game would do more things. You can use the lib directly
|
||||||
the rpc connection and wraps sending events, and a basic example that uses it; you can use the lib
|
if you like, or use it as a guide to writing your own if it doesn't suit your game as is.
|
||||||
directly if you like, or use it as a guide to writing your own if it doesn't suit your game as is.
|
|
||||||
|
|
||||||
PRs/feedback welcome if you have an improvement everyone might want.
|
PRs/feedback welcome if you have an improvement everyone might want, or can describe how this
|
||||||
|
doesn't meet your needs.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
The most up to date documentation for Rich Presence can always be found in our [developer site](https://discordapp.com/developers/docs/topics/rich-presence)!
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
Zeroith, you should be set up to build things because you are a game developer, right?
|
||||||
|
|
||||||
First, head on over to the [Discord developers site](https://discordapp.com/developers/applications/me)
|
First, head on over to the [Discord developers site](https://discordapp.com/developers/applications/me)
|
||||||
and make yourself an app. Keep track of `Client ID` -- you'll need it here.
|
and make yourself an app. Keep track of `Client ID` -- you'll need it here to pass to the init
|
||||||
|
function.
|
||||||
|
|
||||||
### From package
|
### From package
|
||||||
|
|
||||||
@ -19,17 +26,34 @@ linker paths, and link with `discord-rpc`.
|
|||||||
|
|
||||||
### From repo
|
### From repo
|
||||||
|
|
||||||
There's a CMake file that should be able to generate the lib for you; I use it like this:
|
There's a [CMake](https://cmake.org/download/) file that should be able to generate the lib for
|
||||||
|
you; I use it like this:
|
||||||
```sh
|
```sh
|
||||||
cd /path/to/discord-rpc
|
cd <path to discord-rpc>
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/that
|
cmake .. -DCMAKE_INSTALL_PREFIX=<path to install discord-rpc to>
|
||||||
cmake --build . --config Release --target install
|
cmake --build . --config Release --target install
|
||||||
```
|
```
|
||||||
Sometimes I use the generated project files.
|
Sometimes I use the generated project files. There are a couple of CMake options you might care about:
|
||||||
|
|
||||||
|
| flag | default | does |
|
||||||
|
|------|---------|------|
|
||||||
|
| `ENABLE_IO_THREAD` | `ON` | When enabled, we start up a thread to do io processing, if disabled you should call `Discord_UpdateConnection` yourself.
|
||||||
|
| `BUILD_DYNAMIC_LIB` | `OFF` | Build library as a DLL
|
||||||
|
|
||||||
## Sample: send-presence
|
## Sample: send-presence
|
||||||
|
|
||||||
This is a text adventure "game" that inits/deinits the connection to Discord, and sends a presence
|
This is a text adventure "game" that inits/deinits the connection to Discord, and sends a presence
|
||||||
update on each command.
|
update on each command.
|
||||||
|
|
||||||
|
## Sample: button-clicker
|
||||||
|
|
||||||
|
This is a sample [Unity](https://unity3d.com/) project that wraps a DLL version of the library, and
|
||||||
|
sends presence updates when you click on a button.
|
||||||
|
|
||||||
|
## Sample: unrealstatus
|
||||||
|
|
||||||
|
This is a sample [Unreal](https://www.unrealengine.com) project that wraps the DLL version of the
|
||||||
|
library with an Unreal plugin, exposes a blueprint class for interacting with it, and uses that to
|
||||||
|
make a very simple UI.
|
||||||
|
87
build.py
Normal file
87
build.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import click
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
import zipfile
|
||||||
|
from contextlib import contextmanager
|
||||||
|
|
||||||
|
|
||||||
|
SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def cd(new_dir):
|
||||||
|
""" Temporarily change current directory """
|
||||||
|
if new_dir:
|
||||||
|
old_dir = os.getcwd()
|
||||||
|
os.chdir(new_dir)
|
||||||
|
yield
|
||||||
|
if new_dir:
|
||||||
|
os.chdir(old_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def mkdir_p(path):
|
||||||
|
""" mkdir -p """
|
||||||
|
if not os.path.isdir(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
|
||||||
|
|
||||||
|
def build_lib(build_name, generator, options):
|
||||||
|
build_path = os.path.join(SCRIPT_PATH, 'builds', build_name)
|
||||||
|
install_path = os.path.join(SCRIPT_PATH, 'builds', 'install', build_name)
|
||||||
|
mkdir_p(build_path)
|
||||||
|
mkdir_p(install_path)
|
||||||
|
with cd(build_path):
|
||||||
|
initial_cmake = ['cmake', SCRIPT_PATH, '-DCMAKE_INSTALL_PREFIX=%s' % os.path.join('..', 'install', build_name)]
|
||||||
|
if generator:
|
||||||
|
initial_cmake.extend(['-G', generator])
|
||||||
|
for key in options:
|
||||||
|
val = 'ON' if options[key] else 'OFF'
|
||||||
|
initial_cmake.append('-D%s=%s' %(key, val))
|
||||||
|
subprocess.check_call(initial_cmake)
|
||||||
|
subprocess.check_call(['cmake', '--build', '.', '--config', 'Debug'])
|
||||||
|
subprocess.check_call(['cmake', '--build', '.', '--config', 'Release', '--target', 'install'])
|
||||||
|
|
||||||
|
|
||||||
|
def create_archive():
|
||||||
|
archive_file_path = os.path.join(SCRIPT_PATH, 'builds', 'discord-rpc.zip')
|
||||||
|
archive_file = zipfile.ZipFile(archive_file_path, 'w', zipfile.ZIP_DEFLATED)
|
||||||
|
archive_src_base_path = os.path.join(SCRIPT_PATH, 'builds', 'install')
|
||||||
|
archive_dst_base_path = 'discord-rpc'
|
||||||
|
with cd(archive_src_base_path):
|
||||||
|
for path, subdirs, filenames in os.walk('.'):
|
||||||
|
for fname in filenames:
|
||||||
|
fpath = os.path.join(path, fname)
|
||||||
|
archive_file.write(fpath, os.path.normpath(os.path.join(archive_dst_base_path, fpath)))
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
@click.option('--clean', is_flag=True)
|
||||||
|
def main(clean):
|
||||||
|
os.chdir(SCRIPT_PATH)
|
||||||
|
|
||||||
|
if clean:
|
||||||
|
shutil.rmtree('builds', ignore_errors=True)
|
||||||
|
|
||||||
|
if sys.platform.startswith('win'):
|
||||||
|
generator32 = 'Visual Studio 14 2015'
|
||||||
|
generator64 = 'Visual Studio 14 2015 Win64'
|
||||||
|
|
||||||
|
build_lib('win32-static', generator32, {})
|
||||||
|
build_lib('win32-dynamic', generator32, {'BUILD_DYNAMIC_LIB': True})
|
||||||
|
build_lib('win64-static', generator64, {})
|
||||||
|
build_lib('win64-dynamic', generator64, {'BUILD_DYNAMIC_LIB': True})
|
||||||
|
|
||||||
|
# todo: this in some better way
|
||||||
|
src_dll = os.path.join(SCRIPT_PATH, 'builds', 'win64-dynamic', 'src', 'Release', 'discord-rpc.dll')
|
||||||
|
dst_dll = os.path.join(SCRIPT_PATH, 'examples', 'button-clicker', 'Assets', 'Resources', 'discord-rpc.dll')
|
||||||
|
shutil.copy(src_dll, dst_dll)
|
||||||
|
dst_dll = os.path.join(SCRIPT_PATH, 'examples', 'unrealstatus', 'Plugins', 'discordrpc', 'Binaries', 'ThirdParty', 'discordrpcLibrary', 'Win64', 'discord-rpc.dll')
|
||||||
|
shutil.copy(src_dll, dst_dll)
|
||||||
|
|
||||||
|
create_archive()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
99
documentation/hard-mode.md
Normal file
99
documentation/hard-mode.md
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
# Hard Mode: Roll Your Own Client
|
||||||
|
|
||||||
|
Discord's Rich Presence feature is designed as an obfuscated addition to our existing [RPC infrastructure](https://discordapp.com/developers/docs/topics/rpc). The standalone library and header files make it easy for any dev to drop it into their game.
|
||||||
|
|
||||||
|
Our library communicates with Discord over the local Discord RPC socket. We've already done the work in connecting properly, handling disconnects and reconnects, and other RPC intracacies, but those who have done this implementation for our private alpha Voice and Chat SDK can simply make use of the new RPC commands and events to implement Rich Presence.
|
||||||
|
|
||||||
|
## Hark! A warning!
|
||||||
|
|
||||||
|
By committing to an RPC-only integration, you decide to forego the work our library and header file have done for you in the way of error handling, state storage, disconnecting and reconnecting, and other quality of life abstractions. While simply implementing the new RPC command and events will enable Rich Presence for your game, we highly suggest that you do your best to mimic the functionality of the SDK the most that you can. It ensure not only code quality on your part, but also an excellent experience on the part of your players.
|
||||||
|
|
||||||
|
## Application Protocol Registration
|
||||||
|
|
||||||
|
One thing that cannot be explicitly done over RPC is registering an application protocol for your game. If you choose to do an RPC-only implementation, you will have to register your application protocol yourself in the format of `discord-[your_app_id]://`. You can use `Discord_Register()` from `src/discord-register.cpp` as a good example of how to properly register an application protocol for use with Discord.
|
||||||
|
|
||||||
|
## New RPC Command
|
||||||
|
|
||||||
|
The new RPC command for Rich Presence is `SET_ACTIVITY`. The fields are similar to what is outlined in the SDK; we've combined similar fields into objects for the sake of less data on the wire.
|
||||||
|
|
||||||
|
The one major difference is the `party.size` field. It is an array with a size of two. The first element is the current party size, `partySize` from the main documentation. The second element is the maximum party size, `partyMax` from the main documentation.
|
||||||
|
|
||||||
|
Below is a full example of a `SET_ACTIVITY` command. Field restrictions like size are the same as outlined in the main documentation.
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"cmd": "SET_ACTIVITY",
|
||||||
|
"args": {
|
||||||
|
"pid": 9999, // Your application's process id - required field
|
||||||
|
"activity": {
|
||||||
|
"state": "In a Group",
|
||||||
|
"details": "Competitive | In a Match",
|
||||||
|
"timestamps": {
|
||||||
|
"start": time(nullptr),
|
||||||
|
"end": time(nullptr) + ((60 * 5) + 23)
|
||||||
|
},
|
||||||
|
"assets": {
|
||||||
|
"large_image": "numbani_map",
|
||||||
|
"large_text": "Numbani",
|
||||||
|
"small_image": "pharah_profile",
|
||||||
|
"small_text": "Pharah"
|
||||||
|
},
|
||||||
|
"party": {
|
||||||
|
"id": GameEngine.GetPartyId(),
|
||||||
|
"size": [3, 6]
|
||||||
|
},
|
||||||
|
"secrets": {
|
||||||
|
"join": "025ed05c71f639de8bfaa0d679d7c94b2fdce12f",
|
||||||
|
"spectate": "e7eb30d2ee025ed05c71ea495f770b76454ee4e0",
|
||||||
|
"match": "4b2fdce12f639de8bfa7e3591b71a0d679d7c93f"
|
||||||
|
},
|
||||||
|
"instance": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nonce": "647d814a-4cf8-4fbb-948f-898abd24f55b"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## New RPC Events
|
||||||
|
|
||||||
|
The two new RPC events for Rich Presence power the ability to join and spectate your friends' games. First is the `GAME_JOIN` event:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"cmd": "DISPATCH",
|
||||||
|
"data": {
|
||||||
|
"secret": "025ed05c71f639de8bfaa0d679d7c94b2fdce12f"
|
||||||
|
},
|
||||||
|
"evnt": "GAME_JOIN"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And second is the `GAME_SPECTATE` event:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"cmd": "DISPATCH",
|
||||||
|
"data": {
|
||||||
|
"secret": "e7eb30d2ee025ed05c71ea495f770b76454ee4e0"
|
||||||
|
},
|
||||||
|
"evnt": "GAME_SPECTATE"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In order to receive these events, you need to [subscribe](https://discordapp.com/developers/docs/topics/rpc#subscribe) to them like so:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"nonce": "be9a6de3-31d0-4767-a8e9-4818c5690015",
|
||||||
|
"evt": "GAME_JOIN",
|
||||||
|
"cmd": "SUBSCRIBE"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"nonce": "ae9qdde3-31d0-8989-a8e9-dnakwy174he",
|
||||||
|
"evt": "GAME_SPECTATE",
|
||||||
|
"cmd": "SUBSCRIBE"
|
||||||
|
}
|
||||||
|
```
|
BIN
documentation/images/rp-dev-dashboard.png
Normal file
BIN
documentation/images/rp-dev-dashboard.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 318 KiB |
BIN
documentation/images/rp-profile-view.png
Normal file
BIN
documentation/images/rp-profile-view.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
BIN
documentation/images/rp-secret-example.png
Normal file
BIN
documentation/images/rp-secret-example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
6
examples/button-clicker/.gitignore
vendored
Normal file
6
examples/button-clicker/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/Library/
|
||||||
|
/Temp/
|
||||||
|
/obj/
|
||||||
|
*.sln
|
||||||
|
*.csproj
|
||||||
|
*.userprefs
|
89
examples/button-clicker/Assets/DiscordController.cs
Normal file
89
examples/button-clicker/Assets/DiscordController.cs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class DiscordController : MonoBehaviour {
|
||||||
|
public DiscordRpc.RichPresence presence;
|
||||||
|
public string applicationId;
|
||||||
|
public string optionalSteamId;
|
||||||
|
public int callbackCalls;
|
||||||
|
public int clickCounter;
|
||||||
|
public UnityEngine.Events.UnityEvent onConnect;
|
||||||
|
public UnityEngine.Events.UnityEvent onDisconnect;
|
||||||
|
|
||||||
|
DiscordRpc.EventHandlers handlers;
|
||||||
|
|
||||||
|
public void OnClick()
|
||||||
|
{
|
||||||
|
Debug.Log("Discord: on click!");
|
||||||
|
clickCounter++;
|
||||||
|
|
||||||
|
presence.details = string.Format("Button clicked {0} times", clickCounter);
|
||||||
|
|
||||||
|
DiscordRpc.UpdatePresence(ref presence);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReadyCallback()
|
||||||
|
{
|
||||||
|
++callbackCalls;
|
||||||
|
Debug.Log("Discord: ready");
|
||||||
|
onConnect.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisconnectedCallback(int errorCode, string message)
|
||||||
|
{
|
||||||
|
++callbackCalls;
|
||||||
|
Debug.Log(string.Format("Discord: disconnect {0}: {1}", errorCode, message));
|
||||||
|
onDisconnect.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ErrorCallback(int errorCode, string message)
|
||||||
|
{
|
||||||
|
++callbackCalls;
|
||||||
|
Debug.Log(string.Format("Discord: error {0}: {1}", errorCode, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void JoinCallback(string secret)
|
||||||
|
{
|
||||||
|
++callbackCalls;
|
||||||
|
Debug.Log(string.Format("Discord: join ({0})", secret));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SpectateCallback(string secret)
|
||||||
|
{
|
||||||
|
++callbackCalls;
|
||||||
|
Debug.Log(string.Format("Discord: spectate ({0})", secret));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start () {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update () {
|
||||||
|
DiscordRpc.RunCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEnable()
|
||||||
|
{
|
||||||
|
Debug.Log("Discord: init");
|
||||||
|
callbackCalls = 0;
|
||||||
|
|
||||||
|
handlers = new DiscordRpc.EventHandlers();
|
||||||
|
handlers.readyCallback = ReadyCallback;
|
||||||
|
handlers.disconnectedCallback += DisconnectedCallback;
|
||||||
|
handlers.errorCallback += ErrorCallback;
|
||||||
|
handlers.joinCallback += JoinCallback;
|
||||||
|
handlers.spectateCallback += SpectateCallback;
|
||||||
|
DiscordRpc.Initialize(applicationId, ref handlers, true, optionalSteamId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDisable()
|
||||||
|
{
|
||||||
|
Debug.Log("Discord: shutdown");
|
||||||
|
DiscordRpc.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDestroy()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
12
examples/button-clicker/Assets/DiscordController.cs.meta
Normal file
12
examples/button-clicker/Assets/DiscordController.cs.meta
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 27f0a5f59ffffa84c86547736e2e730a
|
||||||
|
timeCreated: 1501697692
|
||||||
|
licenseType: Free
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
61
examples/button-clicker/Assets/DiscordRpc.cs
Normal file
61
examples/button-clicker/Assets/DiscordRpc.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
public class DiscordRpc
|
||||||
|
{
|
||||||
|
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
|
||||||
|
public delegate void ReadyCallback();
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
|
||||||
|
public delegate void DisconnectedCallback(int errorCode, string message);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
|
||||||
|
public delegate void ErrorCallback(int errorCode, string message);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
|
||||||
|
public delegate void JoinCallback(string secret);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
|
||||||
|
public delegate void SpectateCallback(string secret);
|
||||||
|
|
||||||
|
public struct EventHandlers
|
||||||
|
{
|
||||||
|
public ReadyCallback readyCallback;
|
||||||
|
public DisconnectedCallback disconnectedCallback;
|
||||||
|
public ErrorCallback errorCallback;
|
||||||
|
public JoinCallback joinCallback;
|
||||||
|
public SpectateCallback spectateCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Serializable]
|
||||||
|
public struct RichPresence
|
||||||
|
{
|
||||||
|
public string state; /* max 128 bytes */
|
||||||
|
public string details; /* max 128 bytes */
|
||||||
|
public long startTimestamp;
|
||||||
|
public long endTimestamp;
|
||||||
|
public string largeImageKey; /* max 32 bytes */
|
||||||
|
public string largeImageText; /* max 128 bytes */
|
||||||
|
public string smallImageKey; /* max 32 bytes */
|
||||||
|
public string smallImageText; /* max 128 bytes */
|
||||||
|
public string partyId; /* max 128 bytes */
|
||||||
|
public int partySize;
|
||||||
|
public int partyMax;
|
||||||
|
public string matchSecret; /* max 128 bytes */
|
||||||
|
public string joinSecret; /* max 128 bytes */
|
||||||
|
public string spectateSecret; /* max 128 bytes */
|
||||||
|
public bool instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("discord-rpc", EntryPoint = "Discord_Initialize")]
|
||||||
|
public static extern void Initialize(string applicationId, ref EventHandlers handlers, bool autoRegister, string optionalSteamId);
|
||||||
|
|
||||||
|
[DllImport("discord-rpc", EntryPoint = "Discord_Shutdown")]
|
||||||
|
public static extern void Shutdown();
|
||||||
|
|
||||||
|
[DllImport("discord-rpc", EntryPoint = "Discord_RunCallbacks")]
|
||||||
|
public static extern void RunCallbacks();
|
||||||
|
|
||||||
|
[DllImport("discord-rpc", EntryPoint = "Discord_UpdatePresence")]
|
||||||
|
public static extern void UpdatePresence(ref RichPresence presence);
|
||||||
|
}
|
||||||
|
|
12
examples/button-clicker/Assets/DiscordRpc.cs.meta
Normal file
12
examples/button-clicker/Assets/DiscordRpc.cs.meta
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b4474a677de9d80409e98c5393ec5b1e
|
||||||
|
timeCreated: 1501697692
|
||||||
|
licenseType: Free
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
9
examples/button-clicker/Assets/Resources.meta
Normal file
9
examples/button-clicker/Assets/Resources.meta
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4ddcc1759a3a2394fa1fa376963639e0
|
||||||
|
folderAsset: yes
|
||||||
|
timeCreated: 1501697278
|
||||||
|
licenseType: Free
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
examples/button-clicker/Assets/Resources/discord-rpc.dll
Normal file
BIN
examples/button-clicker/Assets/Resources/discord-rpc.dll
Normal file
Binary file not shown.
@ -0,0 +1,27 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2aadd6305b09fa94dab94261a8bb8caf
|
||||||
|
timeCreated: 1501697340
|
||||||
|
licenseType: Free
|
||||||
|
PluginImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
platformData:
|
||||||
|
data:
|
||||||
|
first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings: {}
|
||||||
|
data:
|
||||||
|
first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
718
examples/button-clicker/Assets/main.unity
Normal file
718
examples/button-clicker/Assets/main.unity
Normal file
@ -0,0 +1,718 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!29 &1
|
||||||
|
OcclusionCullingSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 2
|
||||||
|
m_OcclusionBakeSettings:
|
||||||
|
smallestOccluder: 5
|
||||||
|
smallestHole: 0.25
|
||||||
|
backfaceThreshold: 100
|
||||||
|
m_SceneGUID: 00000000000000000000000000000000
|
||||||
|
m_OcclusionCullingData: {fileID: 0}
|
||||||
|
--- !u!104 &2
|
||||||
|
RenderSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 8
|
||||||
|
m_Fog: 0
|
||||||
|
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||||
|
m_FogMode: 3
|
||||||
|
m_FogDensity: 0.01
|
||||||
|
m_LinearFogStart: 0
|
||||||
|
m_LinearFogEnd: 300
|
||||||
|
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||||
|
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||||
|
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||||
|
m_AmbientIntensity: 1
|
||||||
|
m_AmbientMode: 3
|
||||||
|
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||||
|
m_SkyboxMaterial: {fileID: 0}
|
||||||
|
m_HaloStrength: 0.5
|
||||||
|
m_FlareStrength: 1
|
||||||
|
m_FlareFadeSpeed: 3
|
||||||
|
m_HaloTexture: {fileID: 0}
|
||||||
|
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
m_DefaultReflectionMode: 0
|
||||||
|
m_DefaultReflectionResolution: 128
|
||||||
|
m_ReflectionBounces: 1
|
||||||
|
m_ReflectionIntensity: 1
|
||||||
|
m_CustomReflection: {fileID: 0}
|
||||||
|
m_Sun: {fileID: 0}
|
||||||
|
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
|
||||||
|
--- !u!157 &3
|
||||||
|
LightmapSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 11
|
||||||
|
m_GIWorkflowMode: 1
|
||||||
|
m_GISettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_BounceScale: 1
|
||||||
|
m_IndirectOutputScale: 1
|
||||||
|
m_AlbedoBoost: 1
|
||||||
|
m_TemporalCoherenceThreshold: 1
|
||||||
|
m_EnvironmentLightingMode: 0
|
||||||
|
m_EnableBakedLightmaps: 0
|
||||||
|
m_EnableRealtimeLightmaps: 0
|
||||||
|
m_LightmapEditorSettings:
|
||||||
|
serializedVersion: 9
|
||||||
|
m_Resolution: 2
|
||||||
|
m_BakeResolution: 40
|
||||||
|
m_TextureWidth: 1024
|
||||||
|
m_TextureHeight: 1024
|
||||||
|
m_AO: 0
|
||||||
|
m_AOMaxDistance: 1
|
||||||
|
m_CompAOExponent: 1
|
||||||
|
m_CompAOExponentDirect: 0
|
||||||
|
m_Padding: 2
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_LightmapsBakeMode: 1
|
||||||
|
m_TextureCompression: 1
|
||||||
|
m_FinalGather: 0
|
||||||
|
m_FinalGatherFiltering: 1
|
||||||
|
m_FinalGatherRayCount: 256
|
||||||
|
m_ReflectionCompression: 2
|
||||||
|
m_MixedBakeMode: 2
|
||||||
|
m_BakeBackend: 0
|
||||||
|
m_PVRSampling: 1
|
||||||
|
m_PVRDirectSampleCount: 32
|
||||||
|
m_PVRSampleCount: 500
|
||||||
|
m_PVRBounces: 2
|
||||||
|
m_PVRFiltering: 0
|
||||||
|
m_PVRFilteringMode: 1
|
||||||
|
m_PVRCulling: 1
|
||||||
|
m_PVRFilteringGaussRadiusDirect: 1
|
||||||
|
m_PVRFilteringGaussRadiusIndirect: 5
|
||||||
|
m_PVRFilteringGaussRadiusAO: 2
|
||||||
|
m_PVRFilteringAtrousColorSigma: 1
|
||||||
|
m_PVRFilteringAtrousNormalSigma: 1
|
||||||
|
m_PVRFilteringAtrousPositionSigma: 1
|
||||||
|
m_LightingDataAsset: {fileID: 0}
|
||||||
|
m_UseShadowmask: 1
|
||||||
|
--- !u!196 &4
|
||||||
|
NavMeshSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_BuildSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
agentTypeID: 0
|
||||||
|
agentRadius: 0.5
|
||||||
|
agentHeight: 2
|
||||||
|
agentSlope: 45
|
||||||
|
agentClimb: 0.4
|
||||||
|
ledgeDropHeight: 0
|
||||||
|
maxJumpAcrossDistance: 0
|
||||||
|
minRegionArea: 2
|
||||||
|
manualCellSize: 0
|
||||||
|
cellSize: 0.16666667
|
||||||
|
manualTileSize: 0
|
||||||
|
tileSize: 256
|
||||||
|
accuratePlacement: 0
|
||||||
|
m_NavMeshData: {fileID: 0}
|
||||||
|
--- !u!1 &134146651
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
serializedVersion: 5
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 134146656}
|
||||||
|
- component: {fileID: 134146655}
|
||||||
|
- component: {fileID: 134146654}
|
||||||
|
- component: {fileID: 134146653}
|
||||||
|
- component: {fileID: 134146652}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Main Camera
|
||||||
|
m_TagString: MainCamera
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!81 &134146652
|
||||||
|
AudioListener:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 134146651}
|
||||||
|
m_Enabled: 1
|
||||||
|
--- !u!124 &134146653
|
||||||
|
Behaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 134146651}
|
||||||
|
m_Enabled: 1
|
||||||
|
--- !u!92 &134146654
|
||||||
|
Behaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 134146651}
|
||||||
|
m_Enabled: 1
|
||||||
|
--- !u!20 &134146655
|
||||||
|
Camera:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 134146651}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 2
|
||||||
|
m_ClearFlags: 1
|
||||||
|
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||||
|
m_NormalizedViewPortRect:
|
||||||
|
serializedVersion: 2
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 1
|
||||||
|
height: 1
|
||||||
|
near clip plane: 0.3
|
||||||
|
far clip plane: 1000
|
||||||
|
field of view: 60
|
||||||
|
orthographic: 1
|
||||||
|
orthographic size: 5
|
||||||
|
m_Depth: -1
|
||||||
|
m_CullingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_RenderingPath: -1
|
||||||
|
m_TargetTexture: {fileID: 0}
|
||||||
|
m_TargetDisplay: 0
|
||||||
|
m_TargetEye: 3
|
||||||
|
m_HDR: 1
|
||||||
|
m_AllowMSAA: 1
|
||||||
|
m_ForceIntoRT: 0
|
||||||
|
m_OcclusionCulling: 1
|
||||||
|
m_StereoConvergence: 10
|
||||||
|
m_StereoSeparation: 0.022
|
||||||
|
m_StereoMirrorMode: 0
|
||||||
|
--- !u!4 &134146656
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 134146651}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: -10}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &359174702
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
serializedVersion: 5
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 359174703}
|
||||||
|
- component: {fileID: 359174705}
|
||||||
|
- component: {fileID: 359174704}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: Text
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &359174703
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 359174702}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 1032248339}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 0, y: 0}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!114 &359174704
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 359174702}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||||
|
m_RaycastTarget: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
|
||||||
|
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||||
|
m_FontData:
|
||||||
|
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
m_FontSize: 14
|
||||||
|
m_FontStyle: 0
|
||||||
|
m_BestFit: 0
|
||||||
|
m_MinSize: 10
|
||||||
|
m_MaxSize: 40
|
||||||
|
m_Alignment: 4
|
||||||
|
m_AlignByGeometry: 0
|
||||||
|
m_RichText: 1
|
||||||
|
m_HorizontalOverflow: 0
|
||||||
|
m_VerticalOverflow: 0
|
||||||
|
m_LineSpacing: 1
|
||||||
|
m_Text: Button
|
||||||
|
--- !u!222 &359174705
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 359174702}
|
||||||
|
--- !u!1 &657463235
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
serializedVersion: 5
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 657463238}
|
||||||
|
- component: {fileID: 657463237}
|
||||||
|
- component: {fileID: 657463236}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: IsConnectedLabel
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &657463236
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 657463235}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 0.89518255, g: 0.9338235, b: 0.23345588, a: 1}
|
||||||
|
m_RaycastTarget: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
|
||||||
|
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||||
|
m_FontData:
|
||||||
|
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
m_FontSize: 24
|
||||||
|
m_FontStyle: 0
|
||||||
|
m_BestFit: 0
|
||||||
|
m_MinSize: 2
|
||||||
|
m_MaxSize: 40
|
||||||
|
m_Alignment: 0
|
||||||
|
m_AlignByGeometry: 0
|
||||||
|
m_RichText: 1
|
||||||
|
m_HorizontalOverflow: 0
|
||||||
|
m_VerticalOverflow: 0
|
||||||
|
m_LineSpacing: 1
|
||||||
|
m_Text: Discord Disconnected
|
||||||
|
--- !u!222 &657463237
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 657463235}
|
||||||
|
--- !u!224 &657463238
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 657463235}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 1766020814}
|
||||||
|
m_RootOrder: 1
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 1}
|
||||||
|
m_AnchorMax: {x: 0, y: 1}
|
||||||
|
m_AnchoredPosition: {x: 16, y: -19.00003}
|
||||||
|
m_SizeDelta: {x: 239.20001, y: 37.799988}
|
||||||
|
m_Pivot: {x: 0, y: 1}
|
||||||
|
--- !u!1 &1032248338
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
serializedVersion: 5
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1032248339}
|
||||||
|
- component: {fileID: 1032248342}
|
||||||
|
- component: {fileID: 1032248341}
|
||||||
|
- component: {fileID: 1032248340}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: Button
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &1032248339
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1032248338}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 359174703}
|
||||||
|
m_Father: {fileID: 1766020814}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 160, y: 30}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!114 &1032248340
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1032248338}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 1392445389, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_Navigation:
|
||||||
|
m_Mode: 3
|
||||||
|
m_SelectOnUp: {fileID: 0}
|
||||||
|
m_SelectOnDown: {fileID: 0}
|
||||||
|
m_SelectOnLeft: {fileID: 0}
|
||||||
|
m_SelectOnRight: {fileID: 0}
|
||||||
|
m_Transition: 1
|
||||||
|
m_Colors:
|
||||||
|
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||||
|
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||||
|
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||||
|
m_ColorMultiplier: 1
|
||||||
|
m_FadeDuration: 0.1
|
||||||
|
m_SpriteState:
|
||||||
|
m_HighlightedSprite: {fileID: 0}
|
||||||
|
m_PressedSprite: {fileID: 0}
|
||||||
|
m_DisabledSprite: {fileID: 0}
|
||||||
|
m_AnimationTriggers:
|
||||||
|
m_NormalTrigger: Normal
|
||||||
|
m_HighlightedTrigger: Highlighted
|
||||||
|
m_PressedTrigger: Pressed
|
||||||
|
m_DisabledTrigger: Disabled
|
||||||
|
m_Interactable: 1
|
||||||
|
m_TargetGraphic: {fileID: 1032248341}
|
||||||
|
m_OnClick:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls:
|
||||||
|
- m_Target: {fileID: 1929635629}
|
||||||
|
m_MethodName: OnClick
|
||||||
|
m_Mode: 1
|
||||||
|
m_Arguments:
|
||||||
|
m_ObjectArgument: {fileID: 0}
|
||||||
|
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
|
||||||
|
m_IntArgument: 0
|
||||||
|
m_FloatArgument: 0
|
||||||
|
m_StringArgument:
|
||||||
|
m_BoolArgument: 0
|
||||||
|
m_CallState: 2
|
||||||
|
m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0,
|
||||||
|
Culture=neutral, PublicKeyToken=null
|
||||||
|
--- !u!114 &1032248341
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1032248338}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_RaycastTarget: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
|
||||||
|
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||||
|
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_Type: 1
|
||||||
|
m_PreserveAspect: 0
|
||||||
|
m_FillCenter: 1
|
||||||
|
m_FillMethod: 4
|
||||||
|
m_FillAmount: 1
|
||||||
|
m_FillClockwise: 1
|
||||||
|
m_FillOrigin: 0
|
||||||
|
--- !u!222 &1032248342
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1032248338}
|
||||||
|
--- !u!1 &1470895131
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
serializedVersion: 5
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1470895134}
|
||||||
|
- component: {fileID: 1470895133}
|
||||||
|
- component: {fileID: 1470895132}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: EventSystem
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &1470895132
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1470895131}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 1077351063, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_HorizontalAxis: Horizontal
|
||||||
|
m_VerticalAxis: Vertical
|
||||||
|
m_SubmitButton: Submit
|
||||||
|
m_CancelButton: Cancel
|
||||||
|
m_InputActionsPerSecond: 10
|
||||||
|
m_RepeatDelay: 0.5
|
||||||
|
m_ForceModuleActive: 0
|
||||||
|
--- !u!114 &1470895133
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1470895131}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: -619905303, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_FirstSelected: {fileID: 0}
|
||||||
|
m_sendNavigationEvents: 1
|
||||||
|
m_DragThreshold: 5
|
||||||
|
--- !u!4 &1470895134
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1470895131}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 2
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &1766020810
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
serializedVersion: 5
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1766020814}
|
||||||
|
- component: {fileID: 1766020813}
|
||||||
|
- component: {fileID: 1766020812}
|
||||||
|
- component: {fileID: 1766020811}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: Canvas
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &1766020811
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1766020810}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 1301386320, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_IgnoreReversedGraphics: 1
|
||||||
|
m_BlockingObjects: 0
|
||||||
|
m_BlockingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
--- !u!114 &1766020812
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1766020810}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 1980459831, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_UiScaleMode: 0
|
||||||
|
m_ReferencePixelsPerUnit: 100
|
||||||
|
m_ScaleFactor: 1
|
||||||
|
m_ReferenceResolution: {x: 800, y: 600}
|
||||||
|
m_ScreenMatchMode: 0
|
||||||
|
m_MatchWidthOrHeight: 0
|
||||||
|
m_PhysicalUnit: 3
|
||||||
|
m_FallbackScreenDPI: 96
|
||||||
|
m_DefaultSpriteDPI: 96
|
||||||
|
m_DynamicPixelsPerUnit: 1
|
||||||
|
--- !u!223 &1766020813
|
||||||
|
Canvas:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1766020810}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_RenderMode: 0
|
||||||
|
m_Camera: {fileID: 0}
|
||||||
|
m_PlaneDistance: 100
|
||||||
|
m_PixelPerfect: 0
|
||||||
|
m_ReceivesEvents: 1
|
||||||
|
m_OverrideSorting: 0
|
||||||
|
m_OverridePixelPerfect: 0
|
||||||
|
m_SortingBucketNormalizedSize: 0
|
||||||
|
m_AdditionalShaderChannelsFlag: 0
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_TargetDisplay: 0
|
||||||
|
--- !u!224 &1766020814
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1766020810}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 1032248339}
|
||||||
|
- {fileID: 657463238}
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 1
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
m_AnchorMax: {x: 0, y: 0}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 0, y: 0}
|
||||||
|
m_Pivot: {x: 0, y: 0}
|
||||||
|
--- !u!1 &1929635628
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
serializedVersion: 5
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1929635630}
|
||||||
|
- component: {fileID: 1929635629}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Discord
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &1929635629
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1929635628}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 27f0a5f59ffffa84c86547736e2e730a, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
presence:
|
||||||
|
state: Button clicking
|
||||||
|
details:
|
||||||
|
startTimestamp: 0
|
||||||
|
endTimestamp: 0
|
||||||
|
largeImageKey: stable-large
|
||||||
|
largeImageText:
|
||||||
|
smallImageKey: canary-small
|
||||||
|
smallImageText:
|
||||||
|
partyId: abcdefg
|
||||||
|
partySize: 1
|
||||||
|
partyMax: 10
|
||||||
|
matchSecret:
|
||||||
|
joinSecret:
|
||||||
|
spectateSecret:
|
||||||
|
instance: 0
|
||||||
|
applicationId: 345229890980937739
|
||||||
|
optionalSteamId:
|
||||||
|
callbackCalls: 0
|
||||||
|
clickCounter: 0
|
||||||
|
onConnect:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls:
|
||||||
|
- m_Target: {fileID: 657463236}
|
||||||
|
m_MethodName: set_text
|
||||||
|
m_Mode: 5
|
||||||
|
m_Arguments:
|
||||||
|
m_ObjectArgument: {fileID: 0}
|
||||||
|
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
|
||||||
|
m_IntArgument: 0
|
||||||
|
m_FloatArgument: 0
|
||||||
|
m_StringArgument: Discord Connected
|
||||||
|
m_BoolArgument: 1
|
||||||
|
m_CallState: 2
|
||||||
|
m_TypeName: UnityEngine.Events.UnityEvent, UnityEngine, Version=0.0.0.0, Culture=neutral,
|
||||||
|
PublicKeyToken=null
|
||||||
|
onDisconnect:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls:
|
||||||
|
- m_Target: {fileID: 657463236}
|
||||||
|
m_MethodName: set_text
|
||||||
|
m_Mode: 5
|
||||||
|
m_Arguments:
|
||||||
|
m_ObjectArgument: {fileID: 0}
|
||||||
|
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
|
||||||
|
m_IntArgument: 0
|
||||||
|
m_FloatArgument: 0
|
||||||
|
m_StringArgument: Discord Disconnected
|
||||||
|
m_BoolArgument: 0
|
||||||
|
m_CallState: 2
|
||||||
|
m_TypeName: UnityEngine.Events.UnityEvent, UnityEngine, Version=0.0.0.0, Culture=neutral,
|
||||||
|
PublicKeyToken=null
|
||||||
|
--- !u!4 &1929635630
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_PrefabParentObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1929635628}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 3
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
8
examples/button-clicker/Assets/main.unity.meta
Normal file
8
examples/button-clicker/Assets/main.unity.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3b03d21bb25fa494e8694cd6e4b6d769
|
||||||
|
timeCreated: 1501696924
|
||||||
|
licenseType: Free
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
17
examples/button-clicker/ProjectSettings/AudioManager.asset
Normal file
17
examples/button-clicker/ProjectSettings/AudioManager.asset
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!11 &1
|
||||||
|
AudioManager:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_Volume: 1
|
||||||
|
Rolloff Scale: 1
|
||||||
|
Doppler Factor: 1
|
||||||
|
Default Speaker Mode: 2
|
||||||
|
m_SampleRate: 0
|
||||||
|
m_DSPBufferSize: 0
|
||||||
|
m_VirtualVoiceCount: 512
|
||||||
|
m_RealVoiceCount: 32
|
||||||
|
m_SpatializerPlugin:
|
||||||
|
m_AmbisonicDecoderPlugin:
|
||||||
|
m_DisableAudio: 0
|
||||||
|
m_VirtualizeEffects: 1
|
@ -0,0 +1,6 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!236 &1
|
||||||
|
ClusterInputManager:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_Inputs: []
|
@ -0,0 +1,19 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!55 &1
|
||||||
|
PhysicsManager:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Gravity: {x: 0, y: -9.81, z: 0}
|
||||||
|
m_DefaultMaterial: {fileID: 0}
|
||||||
|
m_BounceThreshold: 2
|
||||||
|
m_SleepThreshold: 0.005
|
||||||
|
m_DefaultContactOffset: 0.01
|
||||||
|
m_DefaultSolverIterations: 6
|
||||||
|
m_DefaultSolverVelocityIterations: 1
|
||||||
|
m_QueriesHitBackfaces: 0
|
||||||
|
m_QueriesHitTriggers: 1
|
||||||
|
m_EnableAdaptiveForce: 0
|
||||||
|
m_EnablePCM: 1
|
||||||
|
m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||||
|
m_AutoSimulation: 1
|
@ -0,0 +1,7 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1045 &1
|
||||||
|
EditorBuildSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Scenes: []
|
16
examples/button-clicker/ProjectSettings/EditorSettings.asset
Normal file
16
examples/button-clicker/ProjectSettings/EditorSettings.asset
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!159 &1
|
||||||
|
EditorSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 4
|
||||||
|
m_ExternalVersionControlSupport: Visible Meta Files
|
||||||
|
m_SerializationMode: 2
|
||||||
|
m_DefaultBehaviorMode: 1
|
||||||
|
m_SpritePackerMode: 4
|
||||||
|
m_SpritePackerPaddingPower: 1
|
||||||
|
m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd
|
||||||
|
m_ProjectGenerationRootNamespace:
|
||||||
|
m_UserGeneratedProjectSuffix:
|
||||||
|
m_CollabEditorSettings:
|
||||||
|
inProgressEnabled: 1
|
@ -0,0 +1,61 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!30 &1
|
||||||
|
GraphicsSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 12
|
||||||
|
m_Deferred:
|
||||||
|
m_Mode: 1
|
||||||
|
m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_DeferredReflections:
|
||||||
|
m_Mode: 1
|
||||||
|
m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_ScreenSpaceShadows:
|
||||||
|
m_Mode: 1
|
||||||
|
m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_LegacyDeferred:
|
||||||
|
m_Mode: 1
|
||||||
|
m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_DepthNormals:
|
||||||
|
m_Mode: 1
|
||||||
|
m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_MotionVectors:
|
||||||
|
m_Mode: 1
|
||||||
|
m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_LightHalo:
|
||||||
|
m_Mode: 1
|
||||||
|
m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_LensFlare:
|
||||||
|
m_Mode: 1
|
||||||
|
m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_AlwaysIncludedShaders:
|
||||||
|
- {fileID: 7, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
- {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
- {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
- {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
- {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
- {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_PreloadedShaders: []
|
||||||
|
m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000,
|
||||||
|
type: 0}
|
||||||
|
m_CustomRenderPipeline: {fileID: 0}
|
||||||
|
m_TransparencySortMode: 0
|
||||||
|
m_TransparencySortAxis: {x: 0, y: 0, z: 1}
|
||||||
|
m_DefaultRenderingPath: 1
|
||||||
|
m_DefaultMobileRenderingPath: 1
|
||||||
|
m_TierSettings: []
|
||||||
|
m_LightmapStripping: 0
|
||||||
|
m_FogStripping: 0
|
||||||
|
m_InstancingStripping: 0
|
||||||
|
m_LightmapKeepPlain: 1
|
||||||
|
m_LightmapKeepDirCombined: 1
|
||||||
|
m_LightmapKeepDynamicPlain: 1
|
||||||
|
m_LightmapKeepDynamicDirCombined: 1
|
||||||
|
m_LightmapKeepShadowMask: 1
|
||||||
|
m_LightmapKeepSubtractive: 1
|
||||||
|
m_FogKeepLinear: 1
|
||||||
|
m_FogKeepExp: 1
|
||||||
|
m_FogKeepExp2: 1
|
||||||
|
m_AlbedoSwatchInfos: []
|
||||||
|
m_LightsUseLinearIntensity: 0
|
||||||
|
m_LightsUseColorTemperature: 0
|
295
examples/button-clicker/ProjectSettings/InputManager.asset
Normal file
295
examples/button-clicker/ProjectSettings/InputManager.asset
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!13 &1
|
||||||
|
InputManager:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Axes:
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Horizontal
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton: left
|
||||||
|
positiveButton: right
|
||||||
|
altNegativeButton: a
|
||||||
|
altPositiveButton: d
|
||||||
|
gravity: 3
|
||||||
|
dead: 0.001
|
||||||
|
sensitivity: 3
|
||||||
|
snap: 1
|
||||||
|
invert: 0
|
||||||
|
type: 0
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Vertical
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton: down
|
||||||
|
positiveButton: up
|
||||||
|
altNegativeButton: s
|
||||||
|
altPositiveButton: w
|
||||||
|
gravity: 3
|
||||||
|
dead: 0.001
|
||||||
|
sensitivity: 3
|
||||||
|
snap: 1
|
||||||
|
invert: 0
|
||||||
|
type: 0
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Fire1
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton: left ctrl
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton: mouse 0
|
||||||
|
gravity: 1000
|
||||||
|
dead: 0.001
|
||||||
|
sensitivity: 1000
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 0
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Fire2
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton: left alt
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton: mouse 1
|
||||||
|
gravity: 1000
|
||||||
|
dead: 0.001
|
||||||
|
sensitivity: 1000
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 0
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Fire3
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton: left shift
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton: mouse 2
|
||||||
|
gravity: 1000
|
||||||
|
dead: 0.001
|
||||||
|
sensitivity: 1000
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 0
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Jump
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton: space
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton:
|
||||||
|
gravity: 1000
|
||||||
|
dead: 0.001
|
||||||
|
sensitivity: 1000
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 0
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Mouse X
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton:
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton:
|
||||||
|
gravity: 0
|
||||||
|
dead: 0
|
||||||
|
sensitivity: 0.1
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 1
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Mouse Y
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton:
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton:
|
||||||
|
gravity: 0
|
||||||
|
dead: 0
|
||||||
|
sensitivity: 0.1
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 1
|
||||||
|
axis: 1
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Mouse ScrollWheel
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton:
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton:
|
||||||
|
gravity: 0
|
||||||
|
dead: 0
|
||||||
|
sensitivity: 0.1
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 1
|
||||||
|
axis: 2
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Horizontal
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton:
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton:
|
||||||
|
gravity: 0
|
||||||
|
dead: 0.19
|
||||||
|
sensitivity: 1
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 2
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Vertical
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton:
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton:
|
||||||
|
gravity: 0
|
||||||
|
dead: 0.19
|
||||||
|
sensitivity: 1
|
||||||
|
snap: 0
|
||||||
|
invert: 1
|
||||||
|
type: 2
|
||||||
|
axis: 1
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Fire1
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton: joystick button 0
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton:
|
||||||
|
gravity: 1000
|
||||||
|
dead: 0.001
|
||||||
|
sensitivity: 1000
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 0
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Fire2
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton: joystick button 1
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton:
|
||||||
|
gravity: 1000
|
||||||
|
dead: 0.001
|
||||||
|
sensitivity: 1000
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 0
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Fire3
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton: joystick button 2
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton:
|
||||||
|
gravity: 1000
|
||||||
|
dead: 0.001
|
||||||
|
sensitivity: 1000
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 0
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Jump
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton: joystick button 3
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton:
|
||||||
|
gravity: 1000
|
||||||
|
dead: 0.001
|
||||||
|
sensitivity: 1000
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 0
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Submit
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton: return
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton: joystick button 0
|
||||||
|
gravity: 1000
|
||||||
|
dead: 0.001
|
||||||
|
sensitivity: 1000
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 0
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Submit
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton: enter
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton: space
|
||||||
|
gravity: 1000
|
||||||
|
dead: 0.001
|
||||||
|
sensitivity: 1000
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 0
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
m_Name: Cancel
|
||||||
|
descriptiveName:
|
||||||
|
descriptiveNegativeName:
|
||||||
|
negativeButton:
|
||||||
|
positiveButton: escape
|
||||||
|
altNegativeButton:
|
||||||
|
altPositiveButton: joystick button 1
|
||||||
|
gravity: 1000
|
||||||
|
dead: 0.001
|
||||||
|
sensitivity: 1000
|
||||||
|
snap: 0
|
||||||
|
invert: 0
|
||||||
|
type: 0
|
||||||
|
axis: 0
|
||||||
|
joyNum: 0
|
89
examples/button-clicker/ProjectSettings/NavMeshAreas.asset
Normal file
89
examples/button-clicker/ProjectSettings/NavMeshAreas.asset
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!126 &1
|
||||||
|
NavMeshProjectSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 2
|
||||||
|
areas:
|
||||||
|
- name: Walkable
|
||||||
|
cost: 1
|
||||||
|
- name: Not Walkable
|
||||||
|
cost: 1
|
||||||
|
- name: Jump
|
||||||
|
cost: 2
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
- name:
|
||||||
|
cost: 1
|
||||||
|
m_LastAgentTypeID: -887442657
|
||||||
|
m_Settings:
|
||||||
|
- serializedVersion: 2
|
||||||
|
agentTypeID: 0
|
||||||
|
agentRadius: 0.5
|
||||||
|
agentHeight: 2
|
||||||
|
agentSlope: 45
|
||||||
|
agentClimb: 0.75
|
||||||
|
ledgeDropHeight: 0
|
||||||
|
maxJumpAcrossDistance: 0
|
||||||
|
minRegionArea: 2
|
||||||
|
manualCellSize: 0
|
||||||
|
cellSize: 0.16666667
|
||||||
|
manualTileSize: 0
|
||||||
|
tileSize: 256
|
||||||
|
accuratePlacement: 0
|
||||||
|
m_SettingNames:
|
||||||
|
- Humanoid
|
@ -0,0 +1,8 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!149 &1
|
||||||
|
NetworkManager:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_DebugLevel: 0
|
||||||
|
m_Sendrate: 15
|
||||||
|
m_AssetToPrefab: {}
|
@ -0,0 +1,36 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!19 &1
|
||||||
|
Physics2DSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Gravity: {x: 0, y: -9.81}
|
||||||
|
m_DefaultMaterial: {fileID: 0}
|
||||||
|
m_VelocityIterations: 8
|
||||||
|
m_PositionIterations: 3
|
||||||
|
m_VelocityThreshold: 1
|
||||||
|
m_MaxLinearCorrection: 0.2
|
||||||
|
m_MaxAngularCorrection: 8
|
||||||
|
m_MaxTranslationSpeed: 100
|
||||||
|
m_MaxRotationSpeed: 360
|
||||||
|
m_BaumgarteScale: 0.2
|
||||||
|
m_BaumgarteTimeOfImpactScale: 0.75
|
||||||
|
m_TimeToSleep: 0.5
|
||||||
|
m_LinearSleepTolerance: 0.01
|
||||||
|
m_AngularSleepTolerance: 2
|
||||||
|
m_DefaultContactOffset: 0.01
|
||||||
|
m_AutoSimulation: 1
|
||||||
|
m_QueriesHitTriggers: 1
|
||||||
|
m_QueriesStartInColliders: 1
|
||||||
|
m_ChangeStopsCallbacks: 0
|
||||||
|
m_CallbacksOnDisable: 1
|
||||||
|
m_AlwaysShowColliders: 0
|
||||||
|
m_ShowColliderSleep: 1
|
||||||
|
m_ShowColliderContacts: 0
|
||||||
|
m_ShowColliderAABB: 0
|
||||||
|
m_ContactArrowScale: 0.2
|
||||||
|
m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412}
|
||||||
|
m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432}
|
||||||
|
m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745}
|
||||||
|
m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804}
|
||||||
|
m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
594
examples/button-clicker/ProjectSettings/ProjectSettings.asset
Normal file
594
examples/button-clicker/ProjectSettings/ProjectSettings.asset
Normal file
@ -0,0 +1,594 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!129 &1
|
||||||
|
PlayerSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 12
|
||||||
|
productGUID: 5eccc60d3e382a346a65f512d6b81b84
|
||||||
|
AndroidProfiler: 0
|
||||||
|
defaultScreenOrientation: 4
|
||||||
|
targetDevice: 2
|
||||||
|
useOnDemandResources: 0
|
||||||
|
accelerometerFrequency: 60
|
||||||
|
companyName: DefaultCompany
|
||||||
|
productName: button-clicker
|
||||||
|
defaultCursor: {fileID: 0}
|
||||||
|
cursorHotspot: {x: 0, y: 0}
|
||||||
|
m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1}
|
||||||
|
m_ShowUnitySplashScreen: 1
|
||||||
|
m_ShowUnitySplashLogo: 1
|
||||||
|
m_SplashScreenOverlayOpacity: 1
|
||||||
|
m_SplashScreenAnimation: 1
|
||||||
|
m_SplashScreenLogoStyle: 1
|
||||||
|
m_SplashScreenDrawMode: 0
|
||||||
|
m_SplashScreenBackgroundAnimationZoom: 1
|
||||||
|
m_SplashScreenLogoAnimationZoom: 1
|
||||||
|
m_SplashScreenBackgroundLandscapeAspect: 1
|
||||||
|
m_SplashScreenBackgroundPortraitAspect: 1
|
||||||
|
m_SplashScreenBackgroundLandscapeUvs:
|
||||||
|
serializedVersion: 2
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 1
|
||||||
|
height: 1
|
||||||
|
m_SplashScreenBackgroundPortraitUvs:
|
||||||
|
serializedVersion: 2
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 1
|
||||||
|
height: 1
|
||||||
|
m_SplashScreenLogos: []
|
||||||
|
m_SplashScreenBackgroundLandscape: {fileID: 0}
|
||||||
|
m_SplashScreenBackgroundPortrait: {fileID: 0}
|
||||||
|
m_VirtualRealitySplashScreen: {fileID: 0}
|
||||||
|
m_HolographicTrackingLossScreen: {fileID: 0}
|
||||||
|
defaultScreenWidth: 1024
|
||||||
|
defaultScreenHeight: 768
|
||||||
|
defaultScreenWidthWeb: 960
|
||||||
|
defaultScreenHeightWeb: 600
|
||||||
|
m_StereoRenderingPath: 0
|
||||||
|
m_ActiveColorSpace: 0
|
||||||
|
m_MTRendering: 1
|
||||||
|
m_MobileMTRendering: 0
|
||||||
|
m_StackTraceTypes: 010000000100000001000000010000000100000001000000
|
||||||
|
iosShowActivityIndicatorOnLoading: -1
|
||||||
|
androidShowActivityIndicatorOnLoading: -1
|
||||||
|
tizenShowActivityIndicatorOnLoading: -1
|
||||||
|
iosAppInBackgroundBehavior: 0
|
||||||
|
displayResolutionDialog: 1
|
||||||
|
iosAllowHTTPDownload: 1
|
||||||
|
allowedAutorotateToPortrait: 1
|
||||||
|
allowedAutorotateToPortraitUpsideDown: 1
|
||||||
|
allowedAutorotateToLandscapeRight: 1
|
||||||
|
allowedAutorotateToLandscapeLeft: 1
|
||||||
|
useOSAutorotation: 1
|
||||||
|
use32BitDisplayBuffer: 1
|
||||||
|
disableDepthAndStencilBuffers: 0
|
||||||
|
defaultIsFullScreen: 1
|
||||||
|
defaultIsNativeResolution: 1
|
||||||
|
runInBackground: 0
|
||||||
|
captureSingleScreen: 0
|
||||||
|
muteOtherAudioSources: 0
|
||||||
|
Prepare IOS For Recording: 0
|
||||||
|
Force IOS Speakers When Recording: 0
|
||||||
|
submitAnalytics: 1
|
||||||
|
usePlayerLog: 1
|
||||||
|
bakeCollisionMeshes: 0
|
||||||
|
forceSingleInstance: 0
|
||||||
|
resizableWindow: 0
|
||||||
|
useMacAppStoreValidation: 0
|
||||||
|
macAppStoreCategory: public.app-category.games
|
||||||
|
gpuSkinning: 0
|
||||||
|
graphicsJobs: 0
|
||||||
|
xboxPIXTextureCapture: 0
|
||||||
|
xboxEnableAvatar: 0
|
||||||
|
xboxEnableKinect: 0
|
||||||
|
xboxEnableKinectAutoTracking: 0
|
||||||
|
xboxEnableFitness: 0
|
||||||
|
visibleInBackground: 1
|
||||||
|
allowFullscreenSwitch: 1
|
||||||
|
graphicsJobMode: 0
|
||||||
|
macFullscreenMode: 2
|
||||||
|
d3d9FullscreenMode: 1
|
||||||
|
d3d11FullscreenMode: 1
|
||||||
|
xboxSpeechDB: 0
|
||||||
|
xboxEnableHeadOrientation: 0
|
||||||
|
xboxEnableGuest: 0
|
||||||
|
xboxEnablePIXSampling: 0
|
||||||
|
n3dsDisableStereoscopicView: 0
|
||||||
|
n3dsEnableSharedListOpt: 1
|
||||||
|
n3dsEnableVSync: 0
|
||||||
|
ignoreAlphaClear: 0
|
||||||
|
xboxOneResolution: 0
|
||||||
|
xboxOneMonoLoggingLevel: 0
|
||||||
|
xboxOneLoggingLevel: 1
|
||||||
|
xboxOneDisableEsram: 0
|
||||||
|
videoMemoryForVertexBuffers: 0
|
||||||
|
psp2PowerMode: 0
|
||||||
|
psp2AcquireBGM: 1
|
||||||
|
wiiUTVResolution: 0
|
||||||
|
wiiUGamePadMSAA: 1
|
||||||
|
wiiUSupportsNunchuk: 0
|
||||||
|
wiiUSupportsClassicController: 0
|
||||||
|
wiiUSupportsBalanceBoard: 0
|
||||||
|
wiiUSupportsMotionPlus: 0
|
||||||
|
wiiUSupportsProController: 0
|
||||||
|
wiiUAllowScreenCapture: 1
|
||||||
|
wiiUControllerCount: 0
|
||||||
|
m_SupportedAspectRatios:
|
||||||
|
4:3: 1
|
||||||
|
5:4: 1
|
||||||
|
16:10: 1
|
||||||
|
16:9: 1
|
||||||
|
Others: 1
|
||||||
|
bundleVersion: 1.0
|
||||||
|
preloadedAssets: []
|
||||||
|
metroInputSource: 0
|
||||||
|
m_HolographicPauseOnTrackingLoss: 1
|
||||||
|
xboxOneDisableKinectGpuReservation: 0
|
||||||
|
xboxOneEnable7thCore: 0
|
||||||
|
vrSettings:
|
||||||
|
cardboard:
|
||||||
|
depthFormat: 0
|
||||||
|
enableTransitionView: 0
|
||||||
|
daydream:
|
||||||
|
depthFormat: 0
|
||||||
|
useSustainedPerformanceMode: 0
|
||||||
|
hololens:
|
||||||
|
depthFormat: 1
|
||||||
|
protectGraphicsMemory: 0
|
||||||
|
useHDRDisplay: 0
|
||||||
|
targetPixelDensity: 0
|
||||||
|
resolutionScalingMode: 0
|
||||||
|
applicationIdentifier: {}
|
||||||
|
buildNumber: {}
|
||||||
|
AndroidBundleVersionCode: 1
|
||||||
|
AndroidMinSdkVersion: 16
|
||||||
|
AndroidTargetSdkVersion: 0
|
||||||
|
AndroidPreferredInstallLocation: 1
|
||||||
|
aotOptions:
|
||||||
|
stripEngineCode: 1
|
||||||
|
iPhoneStrippingLevel: 0
|
||||||
|
iPhoneScriptCallOptimization: 0
|
||||||
|
ForceInternetPermission: 0
|
||||||
|
ForceSDCardPermission: 0
|
||||||
|
CreateWallpaper: 0
|
||||||
|
APKExpansionFiles: 0
|
||||||
|
keepLoadedShadersAlive: 0
|
||||||
|
StripUnusedMeshComponents: 0
|
||||||
|
VertexChannelCompressionMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 238
|
||||||
|
iPhoneSdkVersion: 988
|
||||||
|
iOSTargetOSVersionString:
|
||||||
|
tvOSSdkVersion: 0
|
||||||
|
tvOSRequireExtendedGameController: 0
|
||||||
|
tvOSTargetOSVersionString:
|
||||||
|
uIPrerenderedIcon: 0
|
||||||
|
uIRequiresPersistentWiFi: 0
|
||||||
|
uIRequiresFullScreen: 1
|
||||||
|
uIStatusBarHidden: 1
|
||||||
|
uIExitOnSuspend: 0
|
||||||
|
uIStatusBarStyle: 0
|
||||||
|
iPhoneSplashScreen: {fileID: 0}
|
||||||
|
iPhoneHighResSplashScreen: {fileID: 0}
|
||||||
|
iPhoneTallHighResSplashScreen: {fileID: 0}
|
||||||
|
iPhone47inSplashScreen: {fileID: 0}
|
||||||
|
iPhone55inPortraitSplashScreen: {fileID: 0}
|
||||||
|
iPhone55inLandscapeSplashScreen: {fileID: 0}
|
||||||
|
iPadPortraitSplashScreen: {fileID: 0}
|
||||||
|
iPadHighResPortraitSplashScreen: {fileID: 0}
|
||||||
|
iPadLandscapeSplashScreen: {fileID: 0}
|
||||||
|
iPadHighResLandscapeSplashScreen: {fileID: 0}
|
||||||
|
appleTVSplashScreen: {fileID: 0}
|
||||||
|
tvOSSmallIconLayers: []
|
||||||
|
tvOSLargeIconLayers: []
|
||||||
|
tvOSTopShelfImageLayers: []
|
||||||
|
tvOSTopShelfImageWideLayers: []
|
||||||
|
iOSLaunchScreenType: 0
|
||||||
|
iOSLaunchScreenPortrait: {fileID: 0}
|
||||||
|
iOSLaunchScreenLandscape: {fileID: 0}
|
||||||
|
iOSLaunchScreenBackgroundColor:
|
||||||
|
serializedVersion: 2
|
||||||
|
rgba: 0
|
||||||
|
iOSLaunchScreenFillPct: 100
|
||||||
|
iOSLaunchScreenSize: 100
|
||||||
|
iOSLaunchScreenCustomXibPath:
|
||||||
|
iOSLaunchScreeniPadType: 0
|
||||||
|
iOSLaunchScreeniPadImage: {fileID: 0}
|
||||||
|
iOSLaunchScreeniPadBackgroundColor:
|
||||||
|
serializedVersion: 2
|
||||||
|
rgba: 0
|
||||||
|
iOSLaunchScreeniPadFillPct: 100
|
||||||
|
iOSLaunchScreeniPadSize: 100
|
||||||
|
iOSLaunchScreeniPadCustomXibPath:
|
||||||
|
iOSDeviceRequirements: []
|
||||||
|
iOSURLSchemes: []
|
||||||
|
iOSBackgroundModes: 0
|
||||||
|
iOSMetalForceHardShadows: 0
|
||||||
|
metalEditorSupport: 1
|
||||||
|
metalAPIValidation: 1
|
||||||
|
iOSRenderExtraFrameOnPause: 0
|
||||||
|
appleDeveloperTeamID:
|
||||||
|
iOSManualSigningProvisioningProfileID:
|
||||||
|
tvOSManualSigningProvisioningProfileID:
|
||||||
|
appleEnableAutomaticSigning: 0
|
||||||
|
AndroidTargetDevice: 0
|
||||||
|
AndroidSplashScreenScale: 0
|
||||||
|
androidSplashScreen: {fileID: 0}
|
||||||
|
AndroidKeystoreName:
|
||||||
|
AndroidKeyaliasName:
|
||||||
|
AndroidTVCompatibility: 1
|
||||||
|
AndroidIsGame: 1
|
||||||
|
androidEnableBanner: 1
|
||||||
|
m_AndroidBanners:
|
||||||
|
- width: 320
|
||||||
|
height: 180
|
||||||
|
banner: {fileID: 0}
|
||||||
|
androidGamepadSupportLevel: 0
|
||||||
|
resolutionDialogBanner: {fileID: 0}
|
||||||
|
m_BuildTargetIcons: []
|
||||||
|
m_BuildTargetBatching: []
|
||||||
|
m_BuildTargetGraphicsAPIs: []
|
||||||
|
m_BuildTargetVRSettings: []
|
||||||
|
openGLRequireES31: 0
|
||||||
|
openGLRequireES31AEP: 0
|
||||||
|
webPlayerTemplate: APPLICATION:Default
|
||||||
|
m_TemplateCustomTags: {}
|
||||||
|
wiiUTitleID: 0005000011000000
|
||||||
|
wiiUGroupID: 00010000
|
||||||
|
wiiUCommonSaveSize: 4096
|
||||||
|
wiiUAccountSaveSize: 2048
|
||||||
|
wiiUOlvAccessKey: 0
|
||||||
|
wiiUTinCode: 0
|
||||||
|
wiiUJoinGameId: 0
|
||||||
|
wiiUJoinGameModeMask: 0000000000000000
|
||||||
|
wiiUCommonBossSize: 0
|
||||||
|
wiiUAccountBossSize: 0
|
||||||
|
wiiUAddOnUniqueIDs: []
|
||||||
|
wiiUMainThreadStackSize: 3072
|
||||||
|
wiiULoaderThreadStackSize: 1024
|
||||||
|
wiiUSystemHeapSize: 128
|
||||||
|
wiiUTVStartupScreen: {fileID: 0}
|
||||||
|
wiiUGamePadStartupScreen: {fileID: 0}
|
||||||
|
wiiUDrcBufferDisabled: 0
|
||||||
|
wiiUProfilerLibPath:
|
||||||
|
playModeTestRunnerEnabled: 0
|
||||||
|
actionOnDotNetUnhandledException: 1
|
||||||
|
enableInternalProfiler: 0
|
||||||
|
logObjCUncaughtExceptions: 1
|
||||||
|
enableCrashReportAPI: 0
|
||||||
|
cameraUsageDescription:
|
||||||
|
locationUsageDescription:
|
||||||
|
microphoneUsageDescription:
|
||||||
|
switchNetLibKey:
|
||||||
|
switchSocketMemoryPoolSize: 6144
|
||||||
|
switchSocketAllocatorPoolSize: 128
|
||||||
|
switchSocketConcurrencyLimit: 14
|
||||||
|
switchScreenResolutionBehavior: 2
|
||||||
|
switchUseCPUProfiler: 0
|
||||||
|
switchApplicationID: 0x01004b9000490000
|
||||||
|
switchNSODependencies:
|
||||||
|
switchTitleNames_0:
|
||||||
|
switchTitleNames_1:
|
||||||
|
switchTitleNames_2:
|
||||||
|
switchTitleNames_3:
|
||||||
|
switchTitleNames_4:
|
||||||
|
switchTitleNames_5:
|
||||||
|
switchTitleNames_6:
|
||||||
|
switchTitleNames_7:
|
||||||
|
switchTitleNames_8:
|
||||||
|
switchTitleNames_9:
|
||||||
|
switchTitleNames_10:
|
||||||
|
switchTitleNames_11:
|
||||||
|
switchPublisherNames_0:
|
||||||
|
switchPublisherNames_1:
|
||||||
|
switchPublisherNames_2:
|
||||||
|
switchPublisherNames_3:
|
||||||
|
switchPublisherNames_4:
|
||||||
|
switchPublisherNames_5:
|
||||||
|
switchPublisherNames_6:
|
||||||
|
switchPublisherNames_7:
|
||||||
|
switchPublisherNames_8:
|
||||||
|
switchPublisherNames_9:
|
||||||
|
switchPublisherNames_10:
|
||||||
|
switchPublisherNames_11:
|
||||||
|
switchIcons_0: {fileID: 0}
|
||||||
|
switchIcons_1: {fileID: 0}
|
||||||
|
switchIcons_2: {fileID: 0}
|
||||||
|
switchIcons_3: {fileID: 0}
|
||||||
|
switchIcons_4: {fileID: 0}
|
||||||
|
switchIcons_5: {fileID: 0}
|
||||||
|
switchIcons_6: {fileID: 0}
|
||||||
|
switchIcons_7: {fileID: 0}
|
||||||
|
switchIcons_8: {fileID: 0}
|
||||||
|
switchIcons_9: {fileID: 0}
|
||||||
|
switchIcons_10: {fileID: 0}
|
||||||
|
switchIcons_11: {fileID: 0}
|
||||||
|
switchSmallIcons_0: {fileID: 0}
|
||||||
|
switchSmallIcons_1: {fileID: 0}
|
||||||
|
switchSmallIcons_2: {fileID: 0}
|
||||||
|
switchSmallIcons_3: {fileID: 0}
|
||||||
|
switchSmallIcons_4: {fileID: 0}
|
||||||
|
switchSmallIcons_5: {fileID: 0}
|
||||||
|
switchSmallIcons_6: {fileID: 0}
|
||||||
|
switchSmallIcons_7: {fileID: 0}
|
||||||
|
switchSmallIcons_8: {fileID: 0}
|
||||||
|
switchSmallIcons_9: {fileID: 0}
|
||||||
|
switchSmallIcons_10: {fileID: 0}
|
||||||
|
switchSmallIcons_11: {fileID: 0}
|
||||||
|
switchManualHTML:
|
||||||
|
switchAccessibleURLs:
|
||||||
|
switchLegalInformation:
|
||||||
|
switchMainThreadStackSize: 1048576
|
||||||
|
switchPresenceGroupId: 0x01004b9000490000
|
||||||
|
switchLogoHandling: 0
|
||||||
|
switchReleaseVersion: 0
|
||||||
|
switchDisplayVersion: 1.0.0
|
||||||
|
switchStartupUserAccount: 0
|
||||||
|
switchTouchScreenUsage: 0
|
||||||
|
switchSupportedLanguagesMask: 0
|
||||||
|
switchLogoType: 0
|
||||||
|
switchApplicationErrorCodeCategory:
|
||||||
|
switchUserAccountSaveDataSize: 0
|
||||||
|
switchUserAccountSaveDataJournalSize: 0
|
||||||
|
switchApplicationAttribute: 0
|
||||||
|
switchCardSpecSize: 4
|
||||||
|
switchCardSpecClock: 25
|
||||||
|
switchRatingsMask: 0
|
||||||
|
switchRatingsInt_0: 0
|
||||||
|
switchRatingsInt_1: 0
|
||||||
|
switchRatingsInt_2: 0
|
||||||
|
switchRatingsInt_3: 0
|
||||||
|
switchRatingsInt_4: 0
|
||||||
|
switchRatingsInt_5: 0
|
||||||
|
switchRatingsInt_6: 0
|
||||||
|
switchRatingsInt_7: 0
|
||||||
|
switchRatingsInt_8: 0
|
||||||
|
switchRatingsInt_9: 0
|
||||||
|
switchRatingsInt_10: 0
|
||||||
|
switchRatingsInt_11: 0
|
||||||
|
switchLocalCommunicationIds_0: 0x01004b9000490000
|
||||||
|
switchLocalCommunicationIds_1:
|
||||||
|
switchLocalCommunicationIds_2:
|
||||||
|
switchLocalCommunicationIds_3:
|
||||||
|
switchLocalCommunicationIds_4:
|
||||||
|
switchLocalCommunicationIds_5:
|
||||||
|
switchLocalCommunicationIds_6:
|
||||||
|
switchLocalCommunicationIds_7:
|
||||||
|
switchParentalControl: 0
|
||||||
|
switchAllowsScreenshot: 1
|
||||||
|
switchDataLossConfirmation: 0
|
||||||
|
switchSupportedNpadStyles: 3
|
||||||
|
switchSocketConfigEnabled: 0
|
||||||
|
switchTcpInitialSendBufferSize: 32
|
||||||
|
switchTcpInitialReceiveBufferSize: 64
|
||||||
|
switchTcpAutoSendBufferSizeMax: 256
|
||||||
|
switchTcpAutoReceiveBufferSizeMax: 256
|
||||||
|
switchUdpSendBufferSize: 9
|
||||||
|
switchUdpReceiveBufferSize: 42
|
||||||
|
switchSocketBufferEfficiency: 4
|
||||||
|
ps4NPAgeRating: 12
|
||||||
|
ps4NPTitleSecret:
|
||||||
|
ps4NPTrophyPackPath:
|
||||||
|
ps4ParentalLevel: 11
|
||||||
|
ps4ContentID: ED1633-NPXX51362_00-0000000000000000
|
||||||
|
ps4Category: 0
|
||||||
|
ps4MasterVersion: 01.00
|
||||||
|
ps4AppVersion: 01.00
|
||||||
|
ps4AppType: 0
|
||||||
|
ps4ParamSfxPath:
|
||||||
|
ps4VideoOutPixelFormat: 0
|
||||||
|
ps4VideoOutInitialWidth: 1920
|
||||||
|
ps4VideoOutBaseModeInitialWidth: 1920
|
||||||
|
ps4VideoOutReprojectionRate: 120
|
||||||
|
ps4PronunciationXMLPath:
|
||||||
|
ps4PronunciationSIGPath:
|
||||||
|
ps4BackgroundImagePath:
|
||||||
|
ps4StartupImagePath:
|
||||||
|
ps4SaveDataImagePath:
|
||||||
|
ps4SdkOverride:
|
||||||
|
ps4BGMPath:
|
||||||
|
ps4ShareFilePath:
|
||||||
|
ps4ShareOverlayImagePath:
|
||||||
|
ps4PrivacyGuardImagePath:
|
||||||
|
ps4NPtitleDatPath:
|
||||||
|
ps4RemotePlayKeyAssignment: -1
|
||||||
|
ps4RemotePlayKeyMappingDir:
|
||||||
|
ps4PlayTogetherPlayerCount: 0
|
||||||
|
ps4EnterButtonAssignment: 1
|
||||||
|
ps4ApplicationParam1: 0
|
||||||
|
ps4ApplicationParam2: 0
|
||||||
|
ps4ApplicationParam3: 0
|
||||||
|
ps4ApplicationParam4: 0
|
||||||
|
ps4DownloadDataSize: 0
|
||||||
|
ps4GarlicHeapSize: 2048
|
||||||
|
ps4ProGarlicHeapSize: 2560
|
||||||
|
ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ
|
||||||
|
ps4pnSessions: 1
|
||||||
|
ps4pnPresence: 1
|
||||||
|
ps4pnFriends: 1
|
||||||
|
ps4pnGameCustomData: 1
|
||||||
|
playerPrefsSupport: 0
|
||||||
|
restrictedAudioUsageRights: 0
|
||||||
|
ps4UseResolutionFallback: 0
|
||||||
|
ps4ReprojectionSupport: 0
|
||||||
|
ps4UseAudio3dBackend: 0
|
||||||
|
ps4SocialScreenEnabled: 0
|
||||||
|
ps4ScriptOptimizationLevel: 0
|
||||||
|
ps4Audio3dVirtualSpeakerCount: 14
|
||||||
|
ps4attribCpuUsage: 0
|
||||||
|
ps4PatchPkgPath:
|
||||||
|
ps4PatchLatestPkgPath:
|
||||||
|
ps4PatchChangeinfoPath:
|
||||||
|
ps4PatchDayOne: 0
|
||||||
|
ps4attribUserManagement: 0
|
||||||
|
ps4attribMoveSupport: 0
|
||||||
|
ps4attrib3DSupport: 0
|
||||||
|
ps4attribShareSupport: 0
|
||||||
|
ps4attribExclusiveVR: 0
|
||||||
|
ps4disableAutoHideSplash: 0
|
||||||
|
ps4videoRecordingFeaturesUsed: 0
|
||||||
|
ps4contentSearchFeaturesUsed: 0
|
||||||
|
ps4attribEyeToEyeDistanceSettingVR: 0
|
||||||
|
ps4IncludedModules: []
|
||||||
|
monoEnv:
|
||||||
|
psp2Splashimage: {fileID: 0}
|
||||||
|
psp2NPTrophyPackPath:
|
||||||
|
psp2NPSupportGBMorGJP: 0
|
||||||
|
psp2NPAgeRating: 12
|
||||||
|
psp2NPTitleDatPath:
|
||||||
|
psp2NPCommsID:
|
||||||
|
psp2NPCommunicationsID:
|
||||||
|
psp2NPCommsPassphrase:
|
||||||
|
psp2NPCommsSig:
|
||||||
|
psp2ParamSfxPath:
|
||||||
|
psp2ManualPath:
|
||||||
|
psp2LiveAreaGatePath:
|
||||||
|
psp2LiveAreaBackroundPath:
|
||||||
|
psp2LiveAreaPath:
|
||||||
|
psp2LiveAreaTrialPath:
|
||||||
|
psp2PatchChangeInfoPath:
|
||||||
|
psp2PatchOriginalPackage:
|
||||||
|
psp2PackagePassword: F69AzBlax3CF3EDNhm3soLBPh71Yexui
|
||||||
|
psp2KeystoneFile:
|
||||||
|
psp2MemoryExpansionMode: 0
|
||||||
|
psp2DRMType: 0
|
||||||
|
psp2StorageType: 0
|
||||||
|
psp2MediaCapacity: 0
|
||||||
|
psp2DLCConfigPath:
|
||||||
|
psp2ThumbnailPath:
|
||||||
|
psp2BackgroundPath:
|
||||||
|
psp2SoundPath:
|
||||||
|
psp2TrophyCommId:
|
||||||
|
psp2TrophyPackagePath:
|
||||||
|
psp2PackagedResourcesPath:
|
||||||
|
psp2SaveDataQuota: 10240
|
||||||
|
psp2ParentalLevel: 1
|
||||||
|
psp2ShortTitle: Not Set
|
||||||
|
psp2ContentID: IV0000-ABCD12345_00-0123456789ABCDEF
|
||||||
|
psp2Category: 0
|
||||||
|
psp2MasterVersion: 01.00
|
||||||
|
psp2AppVersion: 01.00
|
||||||
|
psp2TVBootMode: 0
|
||||||
|
psp2EnterButtonAssignment: 2
|
||||||
|
psp2TVDisableEmu: 0
|
||||||
|
psp2AllowTwitterDialog: 1
|
||||||
|
psp2Upgradable: 0
|
||||||
|
psp2HealthWarning: 0
|
||||||
|
psp2UseLibLocation: 0
|
||||||
|
psp2InfoBarOnStartup: 0
|
||||||
|
psp2InfoBarColor: 0
|
||||||
|
psp2ScriptOptimizationLevel: 0
|
||||||
|
psmSplashimage: {fileID: 0}
|
||||||
|
splashScreenBackgroundSourceLandscape: {fileID: 0}
|
||||||
|
splashScreenBackgroundSourcePortrait: {fileID: 0}
|
||||||
|
spritePackerPolicy:
|
||||||
|
webGLMemorySize: 256
|
||||||
|
webGLExceptionSupport: 1
|
||||||
|
webGLNameFilesAsHashes: 0
|
||||||
|
webGLDataCaching: 0
|
||||||
|
webGLDebugSymbols: 0
|
||||||
|
webGLEmscriptenArgs:
|
||||||
|
webGLModulesDirectory:
|
||||||
|
webGLTemplate: APPLICATION:Default
|
||||||
|
webGLAnalyzeBuildSize: 0
|
||||||
|
webGLUseEmbeddedResources: 0
|
||||||
|
webGLUseWasm: 0
|
||||||
|
webGLCompressionFormat: 1
|
||||||
|
scriptingDefineSymbols: {}
|
||||||
|
platformArchitecture: {}
|
||||||
|
scriptingBackend: {}
|
||||||
|
incrementalIl2cppBuild: {}
|
||||||
|
additionalIl2CppArgs:
|
||||||
|
scriptingRuntimeVersion: 0
|
||||||
|
apiCompatibilityLevelPerPlatform: {}
|
||||||
|
m_RenderingPath: 1
|
||||||
|
m_MobileRenderingPath: 1
|
||||||
|
metroPackageName: button-clicker
|
||||||
|
metroPackageVersion:
|
||||||
|
metroCertificatePath:
|
||||||
|
metroCertificatePassword:
|
||||||
|
metroCertificateSubject:
|
||||||
|
metroCertificateIssuer:
|
||||||
|
metroCertificateNotAfter: 0000000000000000
|
||||||
|
metroApplicationDescription: button-clicker
|
||||||
|
wsaImages: {}
|
||||||
|
metroTileShortName:
|
||||||
|
metroCommandLineArgsFile:
|
||||||
|
metroTileShowName: 0
|
||||||
|
metroMediumTileShowName: 0
|
||||||
|
metroLargeTileShowName: 0
|
||||||
|
metroWideTileShowName: 0
|
||||||
|
metroDefaultTileSize: 1
|
||||||
|
metroTileForegroundText: 2
|
||||||
|
metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0}
|
||||||
|
metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628,
|
||||||
|
a: 1}
|
||||||
|
metroSplashScreenUseBackgroundColor: 0
|
||||||
|
platformCapabilities: {}
|
||||||
|
metroFTAName:
|
||||||
|
metroFTAFileTypes: []
|
||||||
|
metroProtocolName:
|
||||||
|
metroCompilationOverrides: 1
|
||||||
|
tizenProductDescription:
|
||||||
|
tizenProductURL:
|
||||||
|
tizenSigningProfileName:
|
||||||
|
tizenGPSPermissions: 0
|
||||||
|
tizenMicrophonePermissions: 0
|
||||||
|
tizenDeploymentTarget:
|
||||||
|
tizenDeploymentTargetType: -1
|
||||||
|
tizenMinOSVersion: 1
|
||||||
|
n3dsUseExtSaveData: 0
|
||||||
|
n3dsCompressStaticMem: 1
|
||||||
|
n3dsExtSaveDataNumber: 0x12345
|
||||||
|
n3dsStackSize: 131072
|
||||||
|
n3dsTargetPlatform: 2
|
||||||
|
n3dsRegion: 7
|
||||||
|
n3dsMediaSize: 0
|
||||||
|
n3dsLogoStyle: 3
|
||||||
|
n3dsTitle: GameName
|
||||||
|
n3dsProductCode:
|
||||||
|
n3dsApplicationId: 0xFF3FF
|
||||||
|
stvDeviceAddress:
|
||||||
|
stvProductDescription:
|
||||||
|
stvProductAuthor:
|
||||||
|
stvProductAuthorEmail:
|
||||||
|
stvProductLink:
|
||||||
|
stvProductCategory: 0
|
||||||
|
XboxOneProductId:
|
||||||
|
XboxOneUpdateKey:
|
||||||
|
XboxOneSandboxId:
|
||||||
|
XboxOneContentId:
|
||||||
|
XboxOneTitleId:
|
||||||
|
XboxOneSCId:
|
||||||
|
XboxOneGameOsOverridePath:
|
||||||
|
XboxOnePackagingOverridePath:
|
||||||
|
XboxOneAppManifestOverridePath:
|
||||||
|
XboxOnePackageEncryption: 0
|
||||||
|
XboxOnePackageUpdateGranularity: 2
|
||||||
|
XboxOneDescription:
|
||||||
|
XboxOneLanguage:
|
||||||
|
- enus
|
||||||
|
XboxOneCapability: []
|
||||||
|
XboxOneGameRating: {}
|
||||||
|
XboxOneIsContentPackage: 0
|
||||||
|
XboxOneEnableGPUVariability: 0
|
||||||
|
XboxOneSockets: {}
|
||||||
|
XboxOneSplashScreen: {fileID: 0}
|
||||||
|
XboxOneAllowedProductIds: []
|
||||||
|
XboxOnePersistentLocalStorageSize: 0
|
||||||
|
xboxOneScriptCompiler: 0
|
||||||
|
vrEditorSettings:
|
||||||
|
daydream:
|
||||||
|
daydreamIconForeground: {fileID: 0}
|
||||||
|
daydreamIconBackground: {fileID: 0}
|
||||||
|
cloudServicesEnabled: {}
|
||||||
|
facebookSdkVersion: 7.9.4
|
||||||
|
apiCompatibilityLevel: 2
|
||||||
|
cloudProjectId:
|
||||||
|
projectName:
|
||||||
|
organizationId:
|
||||||
|
cloudEnabled: 0
|
||||||
|
enableNativePlatformBackendsForNewInputSystem: 0
|
||||||
|
disableOldInputManagerSupport: 0
|
@ -0,0 +1 @@
|
|||||||
|
m_EditorVersion: 2017.1.0f3
|
193
examples/button-clicker/ProjectSettings/QualitySettings.asset
Normal file
193
examples/button-clicker/ProjectSettings/QualitySettings.asset
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!47 &1
|
||||||
|
QualitySettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 5
|
||||||
|
m_CurrentQuality: 5
|
||||||
|
m_QualitySettings:
|
||||||
|
- serializedVersion: 2
|
||||||
|
name: Very Low
|
||||||
|
pixelLightCount: 0
|
||||||
|
shadows: 0
|
||||||
|
shadowResolution: 0
|
||||||
|
shadowProjection: 1
|
||||||
|
shadowCascades: 1
|
||||||
|
shadowDistance: 15
|
||||||
|
shadowNearPlaneOffset: 3
|
||||||
|
shadowCascade2Split: 0.33333334
|
||||||
|
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
||||||
|
shadowmaskMode: 0
|
||||||
|
blendWeights: 1
|
||||||
|
textureQuality: 1
|
||||||
|
anisotropicTextures: 0
|
||||||
|
antiAliasing: 0
|
||||||
|
softParticles: 0
|
||||||
|
softVegetation: 0
|
||||||
|
realtimeReflectionProbes: 0
|
||||||
|
billboardsFaceCameraPosition: 0
|
||||||
|
vSyncCount: 0
|
||||||
|
lodBias: 0.3
|
||||||
|
maximumLODLevel: 0
|
||||||
|
particleRaycastBudget: 4
|
||||||
|
asyncUploadTimeSlice: 2
|
||||||
|
asyncUploadBufferSize: 4
|
||||||
|
resolutionScalingFixedDPIFactor: 1
|
||||||
|
excludedTargetPlatforms: []
|
||||||
|
- serializedVersion: 2
|
||||||
|
name: Low
|
||||||
|
pixelLightCount: 0
|
||||||
|
shadows: 0
|
||||||
|
shadowResolution: 0
|
||||||
|
shadowProjection: 1
|
||||||
|
shadowCascades: 1
|
||||||
|
shadowDistance: 20
|
||||||
|
shadowNearPlaneOffset: 3
|
||||||
|
shadowCascade2Split: 0.33333334
|
||||||
|
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
||||||
|
shadowmaskMode: 0
|
||||||
|
blendWeights: 2
|
||||||
|
textureQuality: 0
|
||||||
|
anisotropicTextures: 0
|
||||||
|
antiAliasing: 0
|
||||||
|
softParticles: 0
|
||||||
|
softVegetation: 0
|
||||||
|
realtimeReflectionProbes: 0
|
||||||
|
billboardsFaceCameraPosition: 0
|
||||||
|
vSyncCount: 0
|
||||||
|
lodBias: 0.4
|
||||||
|
maximumLODLevel: 0
|
||||||
|
particleRaycastBudget: 16
|
||||||
|
asyncUploadTimeSlice: 2
|
||||||
|
asyncUploadBufferSize: 4
|
||||||
|
resolutionScalingFixedDPIFactor: 1
|
||||||
|
excludedTargetPlatforms: []
|
||||||
|
- serializedVersion: 2
|
||||||
|
name: Medium
|
||||||
|
pixelLightCount: 1
|
||||||
|
shadows: 1
|
||||||
|
shadowResolution: 0
|
||||||
|
shadowProjection: 1
|
||||||
|
shadowCascades: 1
|
||||||
|
shadowDistance: 20
|
||||||
|
shadowNearPlaneOffset: 3
|
||||||
|
shadowCascade2Split: 0.33333334
|
||||||
|
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
||||||
|
shadowmaskMode: 0
|
||||||
|
blendWeights: 2
|
||||||
|
textureQuality: 0
|
||||||
|
anisotropicTextures: 1
|
||||||
|
antiAliasing: 0
|
||||||
|
softParticles: 0
|
||||||
|
softVegetation: 0
|
||||||
|
realtimeReflectionProbes: 0
|
||||||
|
billboardsFaceCameraPosition: 0
|
||||||
|
vSyncCount: 1
|
||||||
|
lodBias: 0.7
|
||||||
|
maximumLODLevel: 0
|
||||||
|
particleRaycastBudget: 64
|
||||||
|
asyncUploadTimeSlice: 2
|
||||||
|
asyncUploadBufferSize: 4
|
||||||
|
resolutionScalingFixedDPIFactor: 1
|
||||||
|
excludedTargetPlatforms: []
|
||||||
|
- serializedVersion: 2
|
||||||
|
name: High
|
||||||
|
pixelLightCount: 2
|
||||||
|
shadows: 2
|
||||||
|
shadowResolution: 1
|
||||||
|
shadowProjection: 1
|
||||||
|
shadowCascades: 2
|
||||||
|
shadowDistance: 40
|
||||||
|
shadowNearPlaneOffset: 3
|
||||||
|
shadowCascade2Split: 0.33333334
|
||||||
|
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
||||||
|
shadowmaskMode: 1
|
||||||
|
blendWeights: 2
|
||||||
|
textureQuality: 0
|
||||||
|
anisotropicTextures: 1
|
||||||
|
antiAliasing: 0
|
||||||
|
softParticles: 0
|
||||||
|
softVegetation: 1
|
||||||
|
realtimeReflectionProbes: 1
|
||||||
|
billboardsFaceCameraPosition: 1
|
||||||
|
vSyncCount: 1
|
||||||
|
lodBias: 1
|
||||||
|
maximumLODLevel: 0
|
||||||
|
particleRaycastBudget: 256
|
||||||
|
asyncUploadTimeSlice: 2
|
||||||
|
asyncUploadBufferSize: 4
|
||||||
|
resolutionScalingFixedDPIFactor: 1
|
||||||
|
excludedTargetPlatforms: []
|
||||||
|
- serializedVersion: 2
|
||||||
|
name: Very High
|
||||||
|
pixelLightCount: 3
|
||||||
|
shadows: 2
|
||||||
|
shadowResolution: 2
|
||||||
|
shadowProjection: 1
|
||||||
|
shadowCascades: 2
|
||||||
|
shadowDistance: 70
|
||||||
|
shadowNearPlaneOffset: 3
|
||||||
|
shadowCascade2Split: 0.33333334
|
||||||
|
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
||||||
|
shadowmaskMode: 1
|
||||||
|
blendWeights: 4
|
||||||
|
textureQuality: 0
|
||||||
|
anisotropicTextures: 2
|
||||||
|
antiAliasing: 2
|
||||||
|
softParticles: 1
|
||||||
|
softVegetation: 1
|
||||||
|
realtimeReflectionProbes: 1
|
||||||
|
billboardsFaceCameraPosition: 1
|
||||||
|
vSyncCount: 1
|
||||||
|
lodBias: 1.5
|
||||||
|
maximumLODLevel: 0
|
||||||
|
particleRaycastBudget: 1024
|
||||||
|
asyncUploadTimeSlice: 2
|
||||||
|
asyncUploadBufferSize: 4
|
||||||
|
resolutionScalingFixedDPIFactor: 1
|
||||||
|
excludedTargetPlatforms: []
|
||||||
|
- serializedVersion: 2
|
||||||
|
name: Ultra
|
||||||
|
pixelLightCount: 4
|
||||||
|
shadows: 2
|
||||||
|
shadowResolution: 2
|
||||||
|
shadowProjection: 1
|
||||||
|
shadowCascades: 4
|
||||||
|
shadowDistance: 150
|
||||||
|
shadowNearPlaneOffset: 3
|
||||||
|
shadowCascade2Split: 0.33333334
|
||||||
|
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
||||||
|
shadowmaskMode: 1
|
||||||
|
blendWeights: 4
|
||||||
|
textureQuality: 0
|
||||||
|
anisotropicTextures: 2
|
||||||
|
antiAliasing: 2
|
||||||
|
softParticles: 1
|
||||||
|
softVegetation: 1
|
||||||
|
realtimeReflectionProbes: 1
|
||||||
|
billboardsFaceCameraPosition: 1
|
||||||
|
vSyncCount: 1
|
||||||
|
lodBias: 2
|
||||||
|
maximumLODLevel: 0
|
||||||
|
particleRaycastBudget: 4096
|
||||||
|
asyncUploadTimeSlice: 2
|
||||||
|
asyncUploadBufferSize: 4
|
||||||
|
resolutionScalingFixedDPIFactor: 1
|
||||||
|
excludedTargetPlatforms: []
|
||||||
|
m_PerPlatformDefaultQuality:
|
||||||
|
Android: 2
|
||||||
|
Nintendo 3DS: 5
|
||||||
|
Nintendo Switch: 5
|
||||||
|
PS4: 5
|
||||||
|
PSM: 5
|
||||||
|
PSP2: 2
|
||||||
|
Samsung TV: 2
|
||||||
|
Standalone: 5
|
||||||
|
Tizen: 2
|
||||||
|
Web: 5
|
||||||
|
WebGL: 3
|
||||||
|
WiiU: 5
|
||||||
|
Windows Store Apps: 5
|
||||||
|
XboxOne: 5
|
||||||
|
iPhone: 2
|
||||||
|
tvOS: 2
|
43
examples/button-clicker/ProjectSettings/TagManager.asset
Normal file
43
examples/button-clicker/ProjectSettings/TagManager.asset
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!78 &1
|
||||||
|
TagManager:
|
||||||
|
serializedVersion: 2
|
||||||
|
tags: []
|
||||||
|
layers:
|
||||||
|
- Default
|
||||||
|
- TransparentFX
|
||||||
|
- Ignore Raycast
|
||||||
|
-
|
||||||
|
- Water
|
||||||
|
- UI
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
m_SortingLayers:
|
||||||
|
- name: Default
|
||||||
|
uniqueID: 0
|
||||||
|
locked: 0
|
@ -0,0 +1,9 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!5 &1
|
||||||
|
TimeManager:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
Fixed Timestep: 0.02
|
||||||
|
Maximum Allowed Timestep: 0.33333334
|
||||||
|
m_TimeScale: 1
|
||||||
|
Maximum Particle Timestep: 0.03
|
@ -0,0 +1,34 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!310 &1
|
||||||
|
UnityConnectSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_Enabled: 0
|
||||||
|
m_TestMode: 0
|
||||||
|
m_TestEventUrl:
|
||||||
|
m_TestConfigUrl:
|
||||||
|
m_TestInitMode: 0
|
||||||
|
CrashReportingSettings:
|
||||||
|
m_EventUrl: https://perf-events.cloud.unity3d.com/api/events/crashes
|
||||||
|
m_Enabled: 0
|
||||||
|
m_CaptureEditorExceptions: 1
|
||||||
|
UnityPurchasingSettings:
|
||||||
|
m_Enabled: 0
|
||||||
|
m_TestMode: 0
|
||||||
|
UnityAnalyticsSettings:
|
||||||
|
m_Enabled: 0
|
||||||
|
m_InitializeOnStartup: 1
|
||||||
|
m_TestMode: 0
|
||||||
|
m_TestEventUrl:
|
||||||
|
m_TestConfigUrl:
|
||||||
|
UnityAdsSettings:
|
||||||
|
m_Enabled: 0
|
||||||
|
m_InitializeOnStartup: 1
|
||||||
|
m_TestMode: 0
|
||||||
|
m_EnabledPlatforms: 4294967295
|
||||||
|
m_IosGameId:
|
||||||
|
m_AndroidGameId:
|
||||||
|
m_GameIds: {}
|
||||||
|
m_GameId:
|
||||||
|
PerformanceReportingSettings:
|
||||||
|
m_Enabled: 0
|
@ -1,3 +1,10 @@
|
|||||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||||
add_executable(send-presence send-presence.c)
|
add_executable(send-presence send-presence.c)
|
||||||
target_link_libraries(send-presence discord-rpc)
|
target_link_libraries(send-presence discord-rpc)
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS send-presence
|
||||||
|
RUNTIME
|
||||||
|
DESTINATION "bin"
|
||||||
|
CONFIGURATIONS Release
|
||||||
|
)
|
@ -11,8 +11,9 @@
|
|||||||
|
|
||||||
#include "discord-rpc.h"
|
#include "discord-rpc.h"
|
||||||
|
|
||||||
static const char* APPLICATION_ID = "338030514596216832";
|
static const char* APPLICATION_ID = "345229890980937739";
|
||||||
static int FrustrationLevel = 0;
|
static int FrustrationLevel = 0;
|
||||||
|
static int64_t StartTime;
|
||||||
|
|
||||||
static void updateDiscordPresence()
|
static void updateDiscordPresence()
|
||||||
{
|
{
|
||||||
@ -22,6 +23,17 @@ static void updateDiscordPresence()
|
|||||||
discordPresence.state = "West of House";
|
discordPresence.state = "West of House";
|
||||||
sprintf(buffer, "Frustration level: %d", FrustrationLevel);
|
sprintf(buffer, "Frustration level: %d", FrustrationLevel);
|
||||||
discordPresence.details = buffer;
|
discordPresence.details = buffer;
|
||||||
|
discordPresence.startTimestamp = StartTime;
|
||||||
|
discordPresence.endTimestamp = time(0) + 5 * 60;
|
||||||
|
discordPresence.largeImageKey = "canary-large";
|
||||||
|
discordPresence.smallImageKey = "ptb-small";
|
||||||
|
discordPresence.partyId = "party1234";
|
||||||
|
discordPresence.partySize = 1;
|
||||||
|
discordPresence.partyMax = 6;
|
||||||
|
discordPresence.matchSecret = "xyzzy";
|
||||||
|
discordPresence.joinSecret = "join";
|
||||||
|
discordPresence.spectateSecret = "look";
|
||||||
|
discordPresence.instance = 0;
|
||||||
Discord_UpdatePresence(&discordPresence);
|
Discord_UpdatePresence(&discordPresence);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,10 +52,14 @@ static void handleDiscordError(int errcode, const char* message)
|
|||||||
printf("\nDiscord: error (%d: %s)\n", errcode, message);
|
printf("\nDiscord: error (%d: %s)\n", errcode, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleDiscordPresenceRequested()
|
static void handleDiscordJoin(const char* secret)
|
||||||
{
|
{
|
||||||
printf("\nDiscord: requests presence\n");
|
printf("\nDiscord: join (%s)\n", secret);
|
||||||
updateDiscordPresence();
|
}
|
||||||
|
|
||||||
|
static void handleDiscordSpectate(const char* secret)
|
||||||
|
{
|
||||||
|
printf("\nDiscord: spectate (%s)\n", secret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int prompt(char* line, size_t size)
|
static int prompt(char* line, size_t size)
|
||||||
@ -52,7 +68,7 @@ static int prompt(char* line, size_t size)
|
|||||||
char* nl;
|
char* nl;
|
||||||
printf("\n> ");
|
printf("\n> ");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
res = fgets(line, size, stdin) ? 1 : 0;
|
res = fgets(line, (int)size, stdin) ? 1 : 0;
|
||||||
line[size - 1] = 0;
|
line[size - 1] = 0;
|
||||||
nl = strchr(line, '\n');
|
nl = strchr(line, '\n');
|
||||||
if (nl) {
|
if (nl) {
|
||||||
@ -61,17 +77,44 @@ static int prompt(char* line, size_t size)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void discordInit()
|
||||||
|
{
|
||||||
|
DiscordEventHandlers handlers;
|
||||||
|
memset(&handlers, 0, sizeof(handlers));
|
||||||
|
handlers.ready = handleDiscordReady;
|
||||||
|
handlers.disconnected = handleDiscordDisconnected;
|
||||||
|
handlers.errored = handleDiscordError;
|
||||||
|
handlers.joinGame = handleDiscordJoin;
|
||||||
|
handlers.spectateGame = handleDiscordSpectate;
|
||||||
|
Discord_Initialize(APPLICATION_ID, &handlers, 1, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void gameLoop()
|
static void gameLoop()
|
||||||
{
|
{
|
||||||
char line[512];
|
char line[512];
|
||||||
char* space;
|
char* space;
|
||||||
|
|
||||||
|
StartTime = time(0);
|
||||||
|
|
||||||
printf("You are standing in an open field west of a white house.\n");
|
printf("You are standing in an open field west of a white house.\n");
|
||||||
while (prompt(line, sizeof(line))) {
|
while (prompt(line, sizeof(line))) {
|
||||||
if (line[0]) {
|
if (line[0]) {
|
||||||
if (line[0] == 'q') {
|
if (line[0] == 'q') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line[0] == 't') {
|
||||||
|
printf("Shutting off Discord.\n");
|
||||||
|
Discord_Shutdown();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line[0] == 'y') {
|
||||||
|
printf("Reinit Discord.\n");
|
||||||
|
discordInit();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (time(NULL) & 1) {
|
if (time(NULL) & 1) {
|
||||||
printf("I don't understand that.\n");
|
printf("I don't understand that.\n");
|
||||||
}
|
}
|
||||||
@ -95,15 +138,9 @@ static void gameLoop()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
DiscordEventHandlers handlers;
|
discordInit();
|
||||||
memset(&handlers, 0, sizeof(handlers));
|
|
||||||
handlers.ready = handleDiscordReady;
|
|
||||||
handlers.disconnected = handleDiscordDisconnected;
|
|
||||||
handlers.errored = handleDiscordError;
|
|
||||||
handlers.presenceRequested = handleDiscordPresenceRequested;
|
|
||||||
Discord_Initialize(APPLICATION_ID, &handlers);
|
|
||||||
|
|
||||||
gameLoop();
|
gameLoop();
|
||||||
|
|
||||||
|
75
examples/unrealstatus/.gitignore
vendored
Normal file
75
examples/unrealstatus/.gitignore
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# Visual Studio 2015 user specific files
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# Visual Studio 2015 database file
|
||||||
|
*.VC.db
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
*.ipa
|
||||||
|
|
||||||
|
# These project files can be generated by the engine
|
||||||
|
*.xcodeproj
|
||||||
|
*.xcworkspace
|
||||||
|
*.sln
|
||||||
|
*.suo
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.VC.db
|
||||||
|
*.VC.opendb
|
||||||
|
|
||||||
|
# Precompiled Assets
|
||||||
|
SourceArt/**/*.png
|
||||||
|
SourceArt/**/*.tga
|
||||||
|
|
||||||
|
# Binary Files
|
||||||
|
Binaries/
|
||||||
|
|
||||||
|
# Builds
|
||||||
|
Build/*
|
||||||
|
|
||||||
|
# Whitelist PakBlacklist-<BuildConfiguration>.txt files
|
||||||
|
!Build/*/
|
||||||
|
Build/*/**
|
||||||
|
!Build/*/PakBlacklist*.txt
|
||||||
|
|
||||||
|
# Don't ignore icon files in Build
|
||||||
|
!Build/**/*.ico
|
||||||
|
|
||||||
|
# Built data for maps
|
||||||
|
*_BuiltData.uasset
|
||||||
|
|
||||||
|
# Configuration files generated by the Editor
|
||||||
|
Saved/*
|
||||||
|
|
||||||
|
# Compiled source files for the engine to use
|
||||||
|
Intermediate/
|
||||||
|
|
||||||
|
# Cache files for the editor to use
|
||||||
|
DerivedDataCache/
|
0
examples/unrealstatus/Config/DefaultEditor.ini
Normal file
0
examples/unrealstatus/Config/DefaultEditor.ini
Normal file
54
examples/unrealstatus/Config/DefaultEngine.ini
Normal file
54
examples/unrealstatus/Config/DefaultEngine.ini
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
[URL]
|
||||||
|
|
||||||
|
[/Script/HardwareTargeting.HardwareTargetingSettings]
|
||||||
|
TargetedHardwareClass=Desktop
|
||||||
|
AppliedTargetedHardwareClass=Desktop
|
||||||
|
DefaultGraphicsPerformance=Maximum
|
||||||
|
AppliedDefaultGraphicsPerformance=Maximum
|
||||||
|
|
||||||
|
[/Script/Engine.EndUserSettings]
|
||||||
|
bSendAnonymousUsageDataToEpic=False
|
||||||
|
|
||||||
|
[/Script/Engine.PhysicsSettings]
|
||||||
|
DefaultGravityZ=-980.000000
|
||||||
|
DefaultTerminalVelocity=4000.000000
|
||||||
|
DefaultFluidFriction=0.300000
|
||||||
|
SimulateScratchMemorySize=262144
|
||||||
|
RagdollAggregateThreshold=4
|
||||||
|
TriangleMeshTriangleMinAreaThreshold=5.000000
|
||||||
|
bEnableAsyncScene=False
|
||||||
|
bEnableShapeSharing=False
|
||||||
|
bEnablePCM=False
|
||||||
|
bEnableStabilization=False
|
||||||
|
bWarnMissingLocks=True
|
||||||
|
bEnable2DPhysics=False
|
||||||
|
LockedAxis=Invalid
|
||||||
|
DefaultDegreesOfFreedom=Full3D
|
||||||
|
BounceThresholdVelocity=200.000000
|
||||||
|
FrictionCombineMode=Average
|
||||||
|
RestitutionCombineMode=Average
|
||||||
|
MaxAngularVelocity=3600.000000
|
||||||
|
MaxDepenetrationVelocity=0.000000
|
||||||
|
ContactOffsetMultiplier=0.010000
|
||||||
|
MinContactOffset=0.000100
|
||||||
|
MaxContactOffset=1.000000
|
||||||
|
bSimulateSkeletalMeshOnDedicatedServer=True
|
||||||
|
DefaultShapeComplexity=CTF_UseSimpleAndComplex
|
||||||
|
bDefaultHasComplexCollision=True
|
||||||
|
bSuppressFaceRemapTable=False
|
||||||
|
bSupportUVFromHitResults=False
|
||||||
|
bDisableActiveActors=False
|
||||||
|
bDisableCCD=False
|
||||||
|
MaxPhysicsDeltaTime=0.033333
|
||||||
|
bSubstepping=False
|
||||||
|
bSubsteppingAsync=False
|
||||||
|
MaxSubstepDeltaTime=0.016667
|
||||||
|
MaxSubsteps=6
|
||||||
|
SyncSceneSmoothingFactor=0.000000
|
||||||
|
AsyncSceneSmoothingFactor=0.990000
|
||||||
|
InitialAverageFrameRate=0.016667
|
||||||
|
|
||||||
|
[/Script/EngineSettings.GameMapsSettings]
|
||||||
|
EditorStartupMap=/Game/ShowTheUILevel.ShowTheUILevel
|
||||||
|
GameDefaultMap=/Game/ShowTheUILevel.ShowTheUILevel
|
||||||
|
|
7
examples/unrealstatus/Config/DefaultGame.ini
Normal file
7
examples/unrealstatus/Config/DefaultGame.ini
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[/Script/EngineSettings.GeneralProjectSettings]
|
||||||
|
ProjectID=E5977A24492699DF20B8ADBF736AF6C6
|
||||||
|
ProjectName=Discord RPC Example
|
||||||
|
CompanyName=Discord Inc.
|
||||||
|
Homepage="https://discordapp.com/"
|
||||||
|
CopyrightNotice=
|
||||||
|
|
BIN
examples/unrealstatus/Content/MainScreenBP.uasset
Normal file
BIN
examples/unrealstatus/Content/MainScreenBP.uasset
Normal file
Binary file not shown.
BIN
examples/unrealstatus/Content/MouseGameModeBP.uasset
Normal file
BIN
examples/unrealstatus/Content/MouseGameModeBP.uasset
Normal file
Binary file not shown.
BIN
examples/unrealstatus/Content/MousePlayerControllerBP.uasset
Normal file
BIN
examples/unrealstatus/Content/MousePlayerControllerBP.uasset
Normal file
Binary file not shown.
BIN
examples/unrealstatus/Content/ShowTheUILevel.umap
Normal file
BIN
examples/unrealstatus/Content/ShowTheUILevel.umap
Normal file
Binary file not shown.
BIN
examples/unrealstatus/Plugins/discordrpc/Resources/Icon128.png
Normal file
BIN
examples/unrealstatus/Plugins/discordrpc/Resources/Icon128.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.6 KiB |
BIN
examples/unrealstatus/Plugins/discordrpc/Resources/discord.png
Normal file
BIN
examples/unrealstatus/Plugins/discordrpc/Resources/discord.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.6 KiB |
@ -0,0 +1,26 @@
|
|||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using UnrealBuildTool;
|
||||||
|
|
||||||
|
public class discordrpcLibrary : ModuleRules
|
||||||
|
{
|
||||||
|
public discordrpcLibrary(ReadOnlyTargetRules Target) : base(Target)
|
||||||
|
{
|
||||||
|
Type = ModuleType.External;
|
||||||
|
|
||||||
|
if (Target.Platform == UnrealTargetPlatform.Win64)
|
||||||
|
{
|
||||||
|
// Add the import library
|
||||||
|
PublicLibraryPaths.Add(Path.Combine(ModuleDirectory, "x64", "Release"));
|
||||||
|
PublicAdditionalLibraries.Add("discord-rpc.lib");
|
||||||
|
|
||||||
|
// Delay-load the DLL, so we can load it from the right place first
|
||||||
|
PublicDelayLoadDLLs.Add("discord-rpc.dll");
|
||||||
|
}
|
||||||
|
else if (Target.Platform == UnrealTargetPlatform.Mac)
|
||||||
|
{
|
||||||
|
PublicDelayLoadDLLs.Add(Path.Combine(ModuleDirectory, "Mac", "Release", "libdiscord-rpc.dylib"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include "DiscordRpcBlueprint.h"
|
||||||
|
|
||||||
|
#include "discord-rpc.h"
|
||||||
|
|
||||||
|
DEFINE_LOG_CATEGORY(Discord)
|
||||||
|
|
||||||
|
static UDiscordRpc* self = nullptr;
|
||||||
|
static void ReadyHandler()
|
||||||
|
{
|
||||||
|
UE_LOG(Discord, Log, TEXT("Discord connected"));
|
||||||
|
if (self) {
|
||||||
|
self->IsConnected = true;
|
||||||
|
self->OnConnected.Broadcast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DisconnectHandler(int errorCode, const char* message)
|
||||||
|
{
|
||||||
|
auto msg = FString(message);
|
||||||
|
UE_LOG(Discord, Log, TEXT("Discord disconnected (%d): %s"), errorCode, *msg);
|
||||||
|
if (self) {
|
||||||
|
self->IsConnected = false;
|
||||||
|
self->OnDisconnected.Broadcast(errorCode, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ErroredHandler(int errorCode, const char* message)
|
||||||
|
{
|
||||||
|
auto msg = FString(message);
|
||||||
|
UE_LOG(Discord, Log, TEXT("Discord error (%d): %s"), errorCode, *msg);
|
||||||
|
if (self) {
|
||||||
|
self->OnErrored.Broadcast(errorCode, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void JoinGameHandler(const char* joinSecret)
|
||||||
|
{
|
||||||
|
auto secret = FString(joinSecret);
|
||||||
|
UE_LOG(Discord, Log, TEXT("Discord join %s"), *secret);
|
||||||
|
if (self) {
|
||||||
|
self->OnJoin.Broadcast(secret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SpectateGameHandler(const char* spectateSecret)
|
||||||
|
{
|
||||||
|
auto secret = FString(spectateSecret);
|
||||||
|
UE_LOG(Discord, Log, TEXT("Discord spectate %s"), *secret);
|
||||||
|
if (self) {
|
||||||
|
self->OnSpectate.Broadcast(secret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UDiscordRpc::Initialize(const FString& applicationId,
|
||||||
|
bool autoRegister,
|
||||||
|
const FString& optionalSteamId)
|
||||||
|
{
|
||||||
|
self = this;
|
||||||
|
IsConnected = false;
|
||||||
|
DiscordEventHandlers handlers{};
|
||||||
|
handlers.ready = ReadyHandler;
|
||||||
|
handlers.disconnected = DisconnectHandler;
|
||||||
|
handlers.errored = ErroredHandler;
|
||||||
|
if (OnJoin.IsBound()) {
|
||||||
|
handlers.joinGame = JoinGameHandler;
|
||||||
|
}
|
||||||
|
if (OnSpectate.IsBound()) {
|
||||||
|
handlers.spectateGame = SpectateGameHandler;
|
||||||
|
}
|
||||||
|
auto appId = StringCast<ANSICHAR>(*applicationId);
|
||||||
|
auto steamId = StringCast<ANSICHAR>(*optionalSteamId);
|
||||||
|
Discord_Initialize(
|
||||||
|
(const char*)appId.Get(), &handlers, autoRegister, (const char*)steamId.Get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void UDiscordRpc::Shutdown()
|
||||||
|
{
|
||||||
|
Discord_Shutdown();
|
||||||
|
self = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UDiscordRpc::RunCallbacks()
|
||||||
|
{
|
||||||
|
Discord_RunCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UDiscordRpc::UpdatePresence()
|
||||||
|
{
|
||||||
|
DiscordRichPresence rp{};
|
||||||
|
|
||||||
|
auto state = StringCast<ANSICHAR>(*RichPresence.state);
|
||||||
|
rp.state = state.Get();
|
||||||
|
|
||||||
|
auto details = StringCast<ANSICHAR>(*RichPresence.details);
|
||||||
|
rp.details = details.Get();
|
||||||
|
|
||||||
|
auto largeImageKey = StringCast<ANSICHAR>(*RichPresence.largeImageKey);
|
||||||
|
rp.largeImageKey = largeImageKey.Get();
|
||||||
|
|
||||||
|
auto largeImageText = StringCast<ANSICHAR>(*RichPresence.largeImageText);
|
||||||
|
rp.largeImageText = largeImageText.Get();
|
||||||
|
|
||||||
|
auto smallImageKey = StringCast<ANSICHAR>(*RichPresence.smallImageKey);
|
||||||
|
rp.smallImageKey = smallImageKey.Get();
|
||||||
|
|
||||||
|
auto smallImageText = StringCast<ANSICHAR>(*RichPresence.smallImageText);
|
||||||
|
rp.smallImageText = smallImageText.Get();
|
||||||
|
|
||||||
|
auto partyId = StringCast<ANSICHAR>(*RichPresence.partyId);
|
||||||
|
rp.partyId = partyId.Get();
|
||||||
|
|
||||||
|
auto matchSecret = StringCast<ANSICHAR>(*RichPresence.matchSecret);
|
||||||
|
rp.matchSecret = matchSecret.Get();
|
||||||
|
|
||||||
|
auto joinSecret = StringCast<ANSICHAR>(*RichPresence.joinSecret);
|
||||||
|
rp.joinSecret = joinSecret.Get();
|
||||||
|
|
||||||
|
auto spectateSecret = StringCast<ANSICHAR>(*RichPresence.spectateSecret);
|
||||||
|
rp.spectateSecret = spectateSecret.Get();
|
||||||
|
|
||||||
|
rp.startTimestamp = RichPresence.startTimestamp;
|
||||||
|
rp.endTimestamp = RichPresence.endTimestamp;
|
||||||
|
rp.partySize = RichPresence.partySize;
|
||||||
|
rp.partyMax = RichPresence.partyMax;
|
||||||
|
rp.instance = RichPresence.instance;
|
||||||
|
|
||||||
|
Discord_UpdatePresence(&rp);
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "discordrpc.h"
|
||||||
|
#include "Core.h"
|
||||||
|
#include "ModuleManager.h"
|
||||||
|
#include "IPluginManager.h"
|
||||||
|
|
||||||
|
#define LOCTEXT_NAMESPACE "FdiscordrpcModule"
|
||||||
|
|
||||||
|
void FdiscordrpcModule::StartupModule()
|
||||||
|
{
|
||||||
|
// This code will execute after your module is loaded into memory; the exact timing is specified
|
||||||
|
// in the .uplugin file per-module
|
||||||
|
|
||||||
|
// Get the base directory of this plugin
|
||||||
|
FString BaseDir = IPluginManager::Get().FindPlugin("discordrpc")->GetBaseDir();
|
||||||
|
|
||||||
|
// Add on the relative location of the third party dll and load it
|
||||||
|
FString LibraryPath;
|
||||||
|
#if PLATFORM_WINDOWS
|
||||||
|
LibraryPath = FPaths::Combine(
|
||||||
|
*BaseDir, TEXT("Binaries/ThirdParty/discordrpcLibrary/Win64/discord-rpc.dll"));
|
||||||
|
#elif PLATFORM_MAC
|
||||||
|
LibraryPath = FPaths::Combine(
|
||||||
|
*BaseDir, TEXT("Source/ThirdParty/discordrpcLibrary/Mac/Release/libdiscord-rpc.dylib"));
|
||||||
|
#endif // PLATFORM_WINDOWS
|
||||||
|
|
||||||
|
DiscordLibraryHandle =
|
||||||
|
!LibraryPath.IsEmpty() ? FPlatformProcess::GetDllHandle(*LibraryPath) : nullptr;
|
||||||
|
|
||||||
|
if (!DiscordLibraryHandle) {
|
||||||
|
FMessageDialog::Open(
|
||||||
|
EAppMsgType::Ok, LOCTEXT("ThirdPartyLibraryError", "Failed to load discord-rpc library"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FdiscordrpcModule::ShutdownModule()
|
||||||
|
{
|
||||||
|
// This function may be called during shutdown to clean up your module. For modules that
|
||||||
|
// support dynamic reloading,
|
||||||
|
// we call this function before unloading the module.
|
||||||
|
|
||||||
|
// Free the dll handle
|
||||||
|
FPlatformProcess::FreeDllHandle(DiscordLibraryHandle);
|
||||||
|
DiscordLibraryHandle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef LOCTEXT_NAMESPACE
|
||||||
|
|
||||||
|
IMPLEMENT_MODULE(FdiscordrpcModule, discordrpc)
|
@ -0,0 +1,126 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Engine.h"
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "DiscordRpcBlueprint.generated.h"
|
||||||
|
|
||||||
|
// unreal's header tool hates clang-format
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
DECLARE_LOG_CATEGORY_EXTERN(Discord, Log, All);
|
||||||
|
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDiscordConnected);
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDiscordDisconnected, int, errorCode, const FString&, errorMessage);
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDiscordErrored, int, errorCode, const FString&, errorMessage);
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDiscordJoin, const FString&, joinSecret);
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDiscordSpectate, const FString&, spectateSecret);
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rich presence data
|
||||||
|
*/
|
||||||
|
USTRUCT(BlueprintType)
|
||||||
|
struct FDiscordRichPresence {
|
||||||
|
GENERATED_USTRUCT_BODY()
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
FString state;
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
FString details;
|
||||||
|
// todo, timestamps are 64bit, does that even matter?
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
int startTimestamp;
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
int endTimestamp;
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
FString largeImageKey;
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
FString largeImageText;
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
FString smallImageKey;
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
FString smallImageText;
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
FString partyId;
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
int partySize;
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
int partyMax;
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
FString matchSecret;
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
FString joinSecret;
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
FString spectateSecret;
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
bool instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
UCLASS(BlueprintType, meta = (DisplayName = "Discord RPC"), Category = "Discord")
|
||||||
|
class DISCORDRPC_API UDiscordRpc : public UObject {
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UFUNCTION(BlueprintCallable,
|
||||||
|
meta = (DisplayName = "Initialize connection", Keywords = "Discord rpc"),
|
||||||
|
Category = "Discord")
|
||||||
|
void Initialize(const FString& applicationId,
|
||||||
|
bool autoRegister,
|
||||||
|
const FString& optionalSteamId);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable,
|
||||||
|
meta = (DisplayName = "Shut down connection", Keywords = "Discord rpc"),
|
||||||
|
Category = "Discord")
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable,
|
||||||
|
meta = (DisplayName = "Check for callbacks", Keywords = "Discord rpc"),
|
||||||
|
Category = "Discord")
|
||||||
|
void RunCallbacks();
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable,
|
||||||
|
meta = (DisplayName = "Send presence", Keywords = "Discord rpc"),
|
||||||
|
Category = "Discord")
|
||||||
|
void UpdatePresence();
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadOnly,
|
||||||
|
meta = (DisplayName = "Is Discord connected", Keywords = "Discord rpc"),
|
||||||
|
Category = "Discord")
|
||||||
|
bool IsConnected;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintAssignable,
|
||||||
|
meta = (DisplayName = "On connection", Keywords = "Discord rpc"),
|
||||||
|
Category = "Discord")
|
||||||
|
FDiscordConnected OnConnected;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintAssignable,
|
||||||
|
meta = (DisplayName = "On disconnection", Keywords = "Discord rpc"),
|
||||||
|
Category = "Discord")
|
||||||
|
FDiscordDisconnected OnDisconnected;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintAssignable,
|
||||||
|
meta = (DisplayName = "On error message", Keywords = "Discord rpc"),
|
||||||
|
Category = "Discord")
|
||||||
|
FDiscordErrored OnErrored;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintAssignable,
|
||||||
|
meta = (DisplayName = "When Discord user presses join", Keywords = "Discord rpc"),
|
||||||
|
Category = "Discord")
|
||||||
|
FDiscordJoin OnJoin;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintAssignable,
|
||||||
|
meta = (DisplayName = "When Discord user presses spectate", Keywords = "Discord rpc"),
|
||||||
|
Category = "Discord")
|
||||||
|
FDiscordSpectate OnSpectate;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite,
|
||||||
|
meta = (DisplayName = "Rich presence info", Keywords = "Discord rpc"),
|
||||||
|
Category = "Discord")
|
||||||
|
FDiscordRichPresence RichPresence;
|
||||||
|
};
|
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ModuleManager.h"
|
||||||
|
|
||||||
|
class FdiscordrpcModule : public IModuleInterface {
|
||||||
|
public:
|
||||||
|
/** IModuleInterface implementation */
|
||||||
|
virtual void StartupModule() override;
|
||||||
|
virtual void ShutdownModule() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** Handle to the test dll we will load */
|
||||||
|
void* DiscordLibraryHandle;
|
||||||
|
};
|
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
using UnrealBuildTool;
|
||||||
|
|
||||||
|
public class discordrpc : ModuleRules
|
||||||
|
{
|
||||||
|
public discordrpc(ReadOnlyTargetRules Target) : base(Target)
|
||||||
|
{
|
||||||
|
Definitions.Add("DISCORD_DYNAMIC_LIB=1");
|
||||||
|
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||||
|
|
||||||
|
PublicIncludePaths.AddRange(
|
||||||
|
new string[] {
|
||||||
|
"discordrpc/Public"
|
||||||
|
// ... add public include paths required here ...
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
PrivateIncludePaths.AddRange(
|
||||||
|
new string[] {
|
||||||
|
"discordrpc/Private",
|
||||||
|
"../../../../../include"
|
||||||
|
// ... add other private include paths required here ...
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
PublicLibraryPaths.AddRange(
|
||||||
|
new string[] {
|
||||||
|
System.IO.Path.Combine(ModuleDirectory, "../../Binaries/ThirdParty/discordrpcLibrary/", Target.Platform.ToString()),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
PublicDependencyModuleNames.AddRange(
|
||||||
|
new string[]
|
||||||
|
{
|
||||||
|
"CoreUObject",
|
||||||
|
"Engine",
|
||||||
|
"Slate",
|
||||||
|
"SlateCore",
|
||||||
|
"Core",
|
||||||
|
"discordrpcLibrary",
|
||||||
|
"Projects"
|
||||||
|
// ... add other public dependencies that you statically link with here ...
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
PrivateDependencyModuleNames.AddRange(
|
||||||
|
new string[]
|
||||||
|
{
|
||||||
|
// ... add private dependencies that you statically link with here ...
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
DynamicallyLoadedModuleNames.AddRange(
|
||||||
|
new string[]
|
||||||
|
{
|
||||||
|
// ... add any modules that your module loads dynamically here ...
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
23
examples/unrealstatus/Plugins/discordrpc/discordrpc.uplugin
Normal file
23
examples/unrealstatus/Plugins/discordrpc/discordrpc.uplugin
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"FileVersion": 3,
|
||||||
|
"Version": 1,
|
||||||
|
"VersionName": "1.0",
|
||||||
|
"FriendlyName": "Discord RPC",
|
||||||
|
"Description": "Wrap the Discord RPC library.",
|
||||||
|
"Category": "Messaging",
|
||||||
|
"CreatedBy": "Chris Marsh <chris@discordapp.com>",
|
||||||
|
"CreatedByURL": "https://discordapp.com/",
|
||||||
|
"DocsURL": "",
|
||||||
|
"MarketplaceURL": "",
|
||||||
|
"SupportURL": "",
|
||||||
|
"CanContainContent": true,
|
||||||
|
"IsBetaVersion": true,
|
||||||
|
"Installed": false,
|
||||||
|
"Modules": [
|
||||||
|
{
|
||||||
|
"Name": "discordrpc",
|
||||||
|
"Type": "Developer",
|
||||||
|
"LoadingPhase": "Default"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
14
examples/unrealstatus/Source/unrealstatus.Target.cs
Normal file
14
examples/unrealstatus/Source/unrealstatus.Target.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
using UnrealBuildTool;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
public class unrealstatusTarget : TargetRules
|
||||||
|
{
|
||||||
|
public unrealstatusTarget(TargetInfo Target) : base(Target)
|
||||||
|
{
|
||||||
|
Type = TargetType.Game;
|
||||||
|
|
||||||
|
ExtraModuleNames.AddRange( new string[] { "unrealstatus" } );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
using UnrealBuildTool;
|
||||||
|
|
||||||
|
public class unrealstatus : ModuleRules
|
||||||
|
{
|
||||||
|
public unrealstatus(ReadOnlyTargetRules Target) : base(Target)
|
||||||
|
{
|
||||||
|
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||||
|
|
||||||
|
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
|
||||||
|
|
||||||
|
PrivateDependencyModuleNames.AddRange(new string[] { });
|
||||||
|
|
||||||
|
// Uncomment if you are using Slate UI
|
||||||
|
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
|
||||||
|
|
||||||
|
// Uncomment if you are using online features
|
||||||
|
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
|
||||||
|
|
||||||
|
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
#include "unrealstatus.h"
|
||||||
|
#include "Modules/ModuleManager.h"
|
||||||
|
|
||||||
|
IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, unrealstatus, "unrealstatus");
|
5
examples/unrealstatus/Source/unrealstatus/unrealstatus.h
Normal file
5
examples/unrealstatus/Source/unrealstatus/unrealstatus.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
@ -0,0 +1,3 @@
|
|||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
#include "unrealstatusGameModeBase.h"
|
@ -0,0 +1,15 @@
|
|||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "GameFramework/GameModeBase.h"
|
||||||
|
#include "unrealstatusGameModeBase.generated.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
UCLASS()
|
||||||
|
class UNREALSTATUS_API AunrealstatusGameModeBase : public AGameModeBase {
|
||||||
|
GENERATED_BODY()
|
||||||
|
};
|
14
examples/unrealstatus/Source/unrealstatusEditor.Target.cs
Normal file
14
examples/unrealstatus/Source/unrealstatusEditor.Target.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
using UnrealBuildTool;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
public class unrealstatusEditorTarget : TargetRules
|
||||||
|
{
|
||||||
|
public unrealstatusEditorTarget(TargetInfo Target) : base(Target)
|
||||||
|
{
|
||||||
|
Type = TargetType.Editor;
|
||||||
|
|
||||||
|
ExtraModuleNames.AddRange( new string[] { "unrealstatus" } );
|
||||||
|
}
|
||||||
|
}
|
19
examples/unrealstatus/unrealstatus.uproject
Normal file
19
examples/unrealstatus/unrealstatus.uproject
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"FileVersion": 3,
|
||||||
|
"EngineAssociation": "4.16",
|
||||||
|
"Category": "",
|
||||||
|
"Description": "",
|
||||||
|
"Modules": [
|
||||||
|
{
|
||||||
|
"Name": "unrealstatus",
|
||||||
|
"Type": "Runtime",
|
||||||
|
"LoadingPhase": "Default"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TargetPlatforms": [
|
||||||
|
"LinuxNoEditor",
|
||||||
|
"MacNoEditor",
|
||||||
|
"WindowsNoEditor",
|
||||||
|
"AllDesktop"
|
||||||
|
]
|
||||||
|
}
|
@ -1,25 +1,43 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#if defined(DISCORD_DYNAMIC_LIB)
|
||||||
|
# if defined(_WIN32)
|
||||||
|
# if defined(DISCORD_BUILDING_SDK)
|
||||||
|
# define DISCORD_EXPORT __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define DISCORD_EXPORT __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define DISCORD_EXPORT __attribute__((visibility("default")))
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define DISCORD_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct DiscordRichPresence {
|
typedef struct DiscordRichPresence {
|
||||||
const char* state;
|
const char* state; /* max 128 bytes */
|
||||||
const char* details;
|
const char* details; /* max 128 bytes */
|
||||||
int64_t startTimestamp;
|
int64_t startTimestamp;
|
||||||
int64_t endTimestamp;
|
int64_t endTimestamp;
|
||||||
const char* largeImageKey;
|
const char* largeImageKey; /* max 32 bytes */
|
||||||
const char* largeImageText;
|
const char* largeImageText; /* max 128 bytes */
|
||||||
const char* smallImageKey;
|
const char* smallImageKey; /* max 32 bytes */
|
||||||
const char* smallImageText;
|
const char* smallImageText; /* max 128 bytes */
|
||||||
const char* partyId;
|
const char* partyId; /* max 128 bytes */
|
||||||
int partySize;
|
int partySize;
|
||||||
int partyMax;
|
int partyMax;
|
||||||
const char* matchSecret;
|
const char* matchSecret; /* max 128 bytes */
|
||||||
const char* joinSecret;
|
const char* joinSecret; /* max 128 bytes */
|
||||||
const char* spectateSecret;
|
const char* spectateSecret; /* max 128 bytes */
|
||||||
int8_t instance;
|
int8_t instance;
|
||||||
} DiscordRichPresence;
|
} DiscordRichPresence;
|
||||||
|
|
||||||
@ -27,23 +45,25 @@ typedef struct DiscordEventHandlers {
|
|||||||
void (*ready)();
|
void (*ready)();
|
||||||
void (*disconnected)(int errorCode, const char* message);
|
void (*disconnected)(int errorCode, const char* message);
|
||||||
void (*errored)(int errorCode, const char* message);
|
void (*errored)(int errorCode, const char* message);
|
||||||
void (*presenceRequested)();
|
|
||||||
void (*joinGame)(const char* joinSecret);
|
void (*joinGame)(const char* joinSecret);
|
||||||
void (*spectateGame)(const char* spectateSecret);
|
void (*spectateGame)(const char* spectateSecret);
|
||||||
} DiscordEventHandlers;
|
} DiscordEventHandlers;
|
||||||
|
|
||||||
void Discord_Initialize(const char* applicationId, DiscordEventHandlers* handlers);
|
DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
|
||||||
void Discord_Shutdown();
|
DiscordEventHandlers* handlers,
|
||||||
|
int autoRegister,
|
||||||
|
const char* optionalSteamId);
|
||||||
|
DISCORD_EXPORT void Discord_Shutdown();
|
||||||
|
|
||||||
/* checks for incoming messages, dispatches callbacks */
|
/* checks for incoming messages, dispatches callbacks */
|
||||||
void Discord_RunCallbacks();
|
DISCORD_EXPORT void Discord_RunCallbacks();
|
||||||
|
|
||||||
/* If you disable the lib starting its own io thread, you'll need to call this from your own */
|
/* If you disable the lib starting its own io thread, you'll need to call this from your own */
|
||||||
#ifdef DISCORD_DISABLE_IO_THREAD
|
#ifdef DISCORD_DISABLE_IO_THREAD
|
||||||
void Discord_UpdateConnection();
|
DISCORD_EXPORT void Discord_UpdateConnection();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Discord_UpdatePresence(const DiscordRichPresence* presence);
|
DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
@ -1,23 +1,50 @@
|
|||||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
option(ENABLE_IO_THREAD "Start up a separate I/O thread, otherwise I'd need to call an update function" ON)
|
option(ENABLE_IO_THREAD "Start up a separate I/O thread, otherwise I'd need to call an update function" ON)
|
||||||
|
option(BUILD_DYNAMIC_LIB "Build library as a DLL" OFF)
|
||||||
|
|
||||||
if (${ENABLE_IO_THREAD} EQUAL OFF)
|
set(BASE_RPC_SRC
|
||||||
add_definitions(-DDISCORD_DISABLE_IO_THREAD)
|
${PROJECT_SOURCE_DIR}/include/discord-rpc.h
|
||||||
endif (${ENABLE_IO_THREAD} EQUAL OFF)
|
discord-rpc.cpp
|
||||||
|
discord-register.h
|
||||||
|
discord-register.cpp
|
||||||
|
rpc_connection.h
|
||||||
|
rpc_connection.cpp
|
||||||
|
serialization.h
|
||||||
|
serialization.cpp
|
||||||
|
connection.h
|
||||||
|
backoff.h
|
||||||
|
)
|
||||||
|
|
||||||
set(BASE_RPC_SRC ${PROJECT_SOURCE_DIR}/include/discord-rpc.h discord-rpc.cpp rpc_connection.h rpc_connection.cpp serialization.h serialization.cpp connection.h backoff.h)
|
if (${BUILD_DYNAMIC_LIB})
|
||||||
|
set(RPC_LIBRARY_TYPE SHARED)
|
||||||
|
set(BASE_RPC_SRC ${BASE_RPC_SRC} dllmain.cpp)
|
||||||
|
else(${BUILD_DYNAMIC_LIB})
|
||||||
|
set(RPC_LIBRARY_TYPE STATIC)
|
||||||
|
endif(${BUILD_DYNAMIC_LIB})
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
add_library(discord-rpc STATIC ${BASE_RPC_SRC} connection_win.cpp)
|
add_library(discord-rpc ${RPC_LIBRARY_TYPE} ${BASE_RPC_SRC} connection_win.cpp)
|
||||||
|
target_compile_options(discord-rpc PRIVATE /W4)
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
add_library(discord-rpc STATIC ${BASE_RPC_SRC} connection_unix.cpp)
|
add_library(discord-rpc ${RPC_LIBRARY_TYPE} ${BASE_RPC_SRC} connection_unix.cpp)
|
||||||
|
target_link_libraries(discord-rpc PUBLIC pthread)
|
||||||
|
target_compile_options(discord-rpc PRIVATE -g -Wall -std=c++14)
|
||||||
endif(UNIX)
|
endif(UNIX)
|
||||||
|
|
||||||
target_include_directories(discord-rpc PRIVATE ${RAPIDJSON}/include)
|
target_include_directories(discord-rpc PRIVATE ${RAPIDJSON}/include)
|
||||||
|
|
||||||
|
if (NOT ${ENABLE_IO_THREAD})
|
||||||
|
add_definitions(discord-rpc PUBLIC -DDISCORD_DISABLE_IO_THREAD)
|
||||||
|
endif (NOT ${ENABLE_IO_THREAD})
|
||||||
|
|
||||||
|
if (${BUILD_DYNAMIC_LIB})
|
||||||
|
target_compile_definitions(discord-rpc PUBLIC -DDISCORD_DYNAMIC_LIB)
|
||||||
|
target_compile_definitions(discord-rpc PRIVATE -DDISCORD_BUILDING_SDK)
|
||||||
|
endif(${BUILD_DYNAMIC_LIB})
|
||||||
|
|
||||||
add_dependencies(discord-rpc clangformat)
|
add_dependencies(discord-rpc clangformat)
|
||||||
|
|
||||||
# install
|
# install
|
||||||
@ -25,9 +52,17 @@ add_dependencies(discord-rpc clangformat)
|
|||||||
install(
|
install(
|
||||||
TARGETS discord-rpc
|
TARGETS discord-rpc
|
||||||
EXPORT "discord-rpc"
|
EXPORT "discord-rpc"
|
||||||
LIBRARY DESTINATION "lib"
|
RUNTIME
|
||||||
ARCHIVE DESTINATION "lib"
|
DESTINATION "bin"
|
||||||
INCLUDES DESTINATION "include"
|
CONFIGURATIONS Release
|
||||||
|
LIBRARY
|
||||||
|
DESTINATION "lib"
|
||||||
|
CONFIGURATIONS Release
|
||||||
|
ARCHIVE
|
||||||
|
DESTINATION "lib"
|
||||||
|
CONFIGURATIONS Release
|
||||||
|
INCLUDES
|
||||||
|
DESTINATION "include"
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
struct Backoff {
|
struct Backoff {
|
||||||
int64_t minAmount;
|
int64_t minAmount;
|
||||||
@ -19,6 +20,7 @@ struct Backoff {
|
|||||||
, maxAmount(max)
|
, maxAmount(max)
|
||||||
, current(min)
|
, current(min)
|
||||||
, fails(0)
|
, fails(0)
|
||||||
|
, randGenerator(time(0))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ int GetProcessId();
|
|||||||
struct BaseConnection {
|
struct BaseConnection {
|
||||||
static BaseConnection* Create();
|
static BaseConnection* Create();
|
||||||
static void Destroy(BaseConnection*&);
|
static void Destroy(BaseConnection*&);
|
||||||
|
bool isOpen{false};
|
||||||
bool Open();
|
bool Open();
|
||||||
bool Close();
|
bool Close();
|
||||||
bool Write(const void* data, size_t length);
|
bool Write(const void* data, size_t length);
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/un.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
int GetProcessId()
|
int GetProcessId()
|
||||||
@ -8,52 +14,109 @@ int GetProcessId()
|
|||||||
return ::getpid();
|
return ::getpid();
|
||||||
}
|
}
|
||||||
|
|
||||||
const int RpcVersion = 1;
|
struct BaseConnectionUnix : public BaseConnection {
|
||||||
const int NumFrames = 4;
|
int sock{-1};
|
||||||
|
|
||||||
struct RpcConnectionUnix : public RpcConnection {
|
|
||||||
int pipe{-1};
|
|
||||||
RpcMessageFrame frames[NumFrames];
|
|
||||||
int nextFrame{0};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*static*/ RpcConnection* RpcConnection::Create(const char* applicationId)
|
static BaseConnectionUnix Connection;
|
||||||
|
static sockaddr_un PipeAddr{};
|
||||||
|
#ifdef MSG_NOSIGNAL
|
||||||
|
static int MsgFlags = MSG_NOSIGNAL;
|
||||||
|
#else
|
||||||
|
static int MsgFlags = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const char* GetTempPath()
|
||||||
{
|
{
|
||||||
return new RpcConnectionUnix;
|
const char* temp = getenv("XDG_RUNTIME_DIR");
|
||||||
|
temp = temp ? temp : getenv("TMPDIR");
|
||||||
|
temp = temp ? temp : getenv("TMP");
|
||||||
|
temp = temp ? temp : getenv("TEMP");
|
||||||
|
temp = temp ? temp : "/tmp";
|
||||||
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ void RpcConnection::Destroy(RpcConnection*& c)
|
/*static*/ BaseConnection* BaseConnection::Create()
|
||||||
{
|
{
|
||||||
auto self = reinterpret_cast<RpcConnectionUnix*&>(c);
|
PipeAddr.sun_family = AF_UNIX;
|
||||||
delete self;
|
return &Connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static*/ void BaseConnection::Destroy(BaseConnection*& c)
|
||||||
|
{
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(c);
|
||||||
|
self->Close();
|
||||||
c = nullptr;
|
c = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RpcConnection::Open()
|
bool BaseConnection::Open()
|
||||||
{
|
{
|
||||||
|
const char* tempPath = GetTempPath();
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
|
self->sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (self->sock == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fcntl(self->sock, F_SETFL, O_NONBLOCK);
|
||||||
|
#ifdef SO_NOSIGPIPE
|
||||||
|
int optval = 1;
|
||||||
|
setsockopt(self->sock, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (int pipeNum = 0; pipeNum < 10; ++pipeNum) {
|
||||||
|
snprintf(
|
||||||
|
PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum);
|
||||||
|
int err = connect(self->sock, (const sockaddr*)&PipeAddr, sizeof(PipeAddr));
|
||||||
|
if (err == 0) {
|
||||||
|
self->isOpen = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self->Close();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RpcConnection::Close()
|
bool BaseConnection::Close()
|
||||||
{
|
{
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
|
if (self->sock == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
close(self->sock);
|
||||||
|
self->sock = -1;
|
||||||
|
self->isOpen = false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RpcConnection::Write(const void* data, size_t length)
|
bool BaseConnection::Write(const void* data, size_t length)
|
||||||
{
|
{
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
|
|
||||||
|
if (self->sock == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t sentBytes = send(self->sock, data, length, MsgFlags);
|
||||||
|
if (sentBytes < 0) {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
return sentBytes == (ssize_t)length;
|
||||||
}
|
}
|
||||||
|
|
||||||
RpcMessageFrame* RpcConnection::Read()
|
bool BaseConnection::Read(void* data, size_t length)
|
||||||
{
|
{
|
||||||
return nullptr;
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
}
|
|
||||||
|
|
||||||
RpcMessageFrame* RpcConnection::GetNextFrame()
|
if (self->sock == -1) {
|
||||||
{
|
return false;
|
||||||
auto self = reinterpret_cast<RpcConnectionUnix*>(this);
|
}
|
||||||
auto result = &(self->frames[self->nextFrame]);
|
|
||||||
self->nextFrame = (self->nextFrame + 1) % NumFrames;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RpcConnection::WriteFrame(RpcMessageFrame* frame)
|
int res = recv(self->sock, data, length, MsgFlags);
|
||||||
{
|
if (res < 0) {
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
return res == (int)length;
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,6 @@ struct BaseConnectionWin : public BaseConnection {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static BaseConnectionWin Connection;
|
static BaseConnectionWin Connection;
|
||||||
// static const wchar_t* PipeName = L"\\\\?\\pipe\\discord-ipc";
|
|
||||||
static const wchar_t* PipeName = L"\\\\?\\pipe\\discord-ipc-0";
|
|
||||||
|
|
||||||
/*static*/ BaseConnection* BaseConnection::Create()
|
/*static*/ BaseConnection* BaseConnection::Create()
|
||||||
{
|
{
|
||||||
@ -33,21 +31,32 @@ static const wchar_t* PipeName = L"\\\\?\\pipe\\discord-ipc-0";
|
|||||||
|
|
||||||
bool BaseConnection::Open()
|
bool BaseConnection::Open()
|
||||||
{
|
{
|
||||||
|
wchar_t pipeName[]{L"\\\\?\\pipe\\discord-ipc-0"};
|
||||||
|
const size_t pipeDigit = sizeof(pipeName) / sizeof(wchar_t) - 2;
|
||||||
|
pipeName[pipeDigit] = L'0';
|
||||||
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
self->pipe = ::CreateFileW(
|
self->pipe = ::CreateFileW(
|
||||||
PipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
pipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||||
if (self->pipe != INVALID_HANDLE_VALUE) {
|
if (self->pipe != INVALID_HANDLE_VALUE) {
|
||||||
|
self->isOpen = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetLastError() != ERROR_PIPE_BUSY) {
|
auto lastError = GetLastError();
|
||||||
return false;
|
if (lastError == ERROR_FILE_NOT_FOUND) {
|
||||||
|
if (pipeName[pipeDigit] < L'9') {
|
||||||
|
pipeName[pipeDigit]++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else if (lastError == ERROR_PIPE_BUSY) {
|
||||||
if (!WaitNamedPipeW(PipeName, 10000)) {
|
if (!WaitNamedPipeW(pipeName, 10000)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,25 +65,41 @@ bool BaseConnection::Close()
|
|||||||
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
||||||
::CloseHandle(self->pipe);
|
::CloseHandle(self->pipe);
|
||||||
self->pipe = INVALID_HANDLE_VALUE;
|
self->pipe = INVALID_HANDLE_VALUE;
|
||||||
|
self->isOpen = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Write(const void* data, size_t length)
|
bool BaseConnection::Write(const void* data, size_t length)
|
||||||
{
|
{
|
||||||
|
if (length == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
||||||
return ::WriteFile(self->pipe, data, length, nullptr, nullptr) == TRUE;
|
if (self->pipe == INVALID_HANDLE_VALUE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ::WriteFile(self->pipe, data, (DWORD)length, nullptr, nullptr) == TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Read(void* data, size_t length)
|
bool BaseConnection::Read(void* data, size_t length)
|
||||||
{
|
{
|
||||||
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
||||||
|
if (self->pipe == INVALID_HANDLE_VALUE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
DWORD bytesAvailable = 0;
|
DWORD bytesAvailable = 0;
|
||||||
if (::PeekNamedPipe(self->pipe, nullptr, 0, nullptr, &bytesAvailable, nullptr)) {
|
if (::PeekNamedPipe(self->pipe, nullptr, 0, nullptr, &bytesAvailable, nullptr)) {
|
||||||
if (bytesAvailable >= length) {
|
if (bytesAvailable >= length) {
|
||||||
if (::ReadFile(self->pipe, data, length, nullptr, nullptr) == TRUE) {
|
if (::ReadFile(self->pipe, data, (DWORD)length, nullptr, nullptr) == TRUE) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
137
src/discord-register.cpp
Normal file
137
src/discord-register.cpp
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#include "discord-rpc.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define NOMCX
|
||||||
|
#define NOSERVICE
|
||||||
|
#define NOIME
|
||||||
|
#include <windows.h>
|
||||||
|
#include <Psapi.h>
|
||||||
|
#include <Strsafe.h>
|
||||||
|
#pragma comment(lib, "Psapi.lib")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* command)
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx
|
||||||
|
// we want to register games so we can run them as discord-<appid>://
|
||||||
|
// Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions.
|
||||||
|
|
||||||
|
wchar_t exeFilePath[MAX_PATH];
|
||||||
|
int exeLen = GetModuleFileNameExW(GetCurrentProcess(), nullptr, exeFilePath, MAX_PATH);
|
||||||
|
wchar_t openCommand[1024];
|
||||||
|
const auto commandBufferLen = sizeof(openCommand) / sizeof(*openCommand);
|
||||||
|
|
||||||
|
if (command && command[0]) {
|
||||||
|
StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", command);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lstrcpyW(openCommand, exeFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t protocolName[64];
|
||||||
|
StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%s", applicationId);
|
||||||
|
wchar_t protocolDescription[128];
|
||||||
|
StringCbPrintfW(
|
||||||
|
protocolDescription, sizeof(protocolDescription), L"URL:Run game %s protocol", applicationId);
|
||||||
|
wchar_t urlProtocol = 0;
|
||||||
|
|
||||||
|
wchar_t keyName[256];
|
||||||
|
StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%s", protocolName);
|
||||||
|
HKEY key;
|
||||||
|
auto status =
|
||||||
|
RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, nullptr, 0, KEY_WRITE, nullptr, &key, nullptr);
|
||||||
|
if (status != ERROR_SUCCESS) {
|
||||||
|
fprintf(stderr, "Error creating key\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DWORD len;
|
||||||
|
LSTATUS result;
|
||||||
|
len = lstrlenW(protocolDescription) + 1;
|
||||||
|
result =
|
||||||
|
RegSetKeyValueW(key, nullptr, nullptr, REG_SZ, protocolDescription, len * sizeof(wchar_t));
|
||||||
|
if (FAILED(result)) {
|
||||||
|
fprintf(stderr, "Error writing description\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
len = lstrlenW(protocolDescription) + 1;
|
||||||
|
result = RegSetKeyValueW(key, nullptr, L"URL Protocol", REG_SZ, &urlProtocol, sizeof(wchar_t));
|
||||||
|
if (FAILED(result)) {
|
||||||
|
fprintf(stderr, "Error writing description\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
result = RegSetKeyValueW(
|
||||||
|
key, L"DefaultIcon", nullptr, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t));
|
||||||
|
if (FAILED(result)) {
|
||||||
|
fprintf(stderr, "Error writing icon\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
len = lstrlenW(openCommand) + 1;
|
||||||
|
result = RegSetKeyValueW(
|
||||||
|
key, L"shell\\open\\command", nullptr, REG_SZ, openCommand, len * sizeof(wchar_t));
|
||||||
|
if (FAILED(result)) {
|
||||||
|
fprintf(stderr, "Error writing command\n");
|
||||||
|
}
|
||||||
|
RegCloseKey(key);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Discord_Register(const char* applicationId, const char* command)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
wchar_t appId[32];
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
|
||||||
|
|
||||||
|
wchar_t openCommand[1024];
|
||||||
|
const wchar_t* wcommand = nullptr;
|
||||||
|
if (command && command[0]) {
|
||||||
|
const auto commandBufferLen = sizeof(openCommand) / sizeof(*openCommand);
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, command, -1, openCommand, commandBufferLen);
|
||||||
|
wcommand = openCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
Discord_RegisterW(appId, wcommand);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Discord_RegisterSteamGame(const char* applicationId, const char* steamId)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
wchar_t appId[32];
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
|
||||||
|
|
||||||
|
wchar_t wSteamId[32];
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, steamId, -1, wSteamId, 32);
|
||||||
|
|
||||||
|
HKEY key;
|
||||||
|
auto status = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", 0, KEY_READ, &key);
|
||||||
|
if (status != ERROR_SUCCESS) {
|
||||||
|
fprintf(stderr, "Error opening Steam key\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t steamPath[MAX_PATH];
|
||||||
|
DWORD pathBytes = sizeof(steamPath);
|
||||||
|
status = RegQueryValueExW(key, L"SteamExe", nullptr, nullptr, (BYTE*)steamPath, &pathBytes);
|
||||||
|
RegCloseKey(key);
|
||||||
|
if (status != ERROR_SUCCESS || pathBytes < 1) {
|
||||||
|
fprintf(stderr, "Error reading SteamExe key\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD pathChars = pathBytes / sizeof(wchar_t);
|
||||||
|
for (DWORD i = 0; i < pathChars; ++i) {
|
||||||
|
if (steamPath[i] == L'/') {
|
||||||
|
steamPath[i] = L'\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t command[1024];
|
||||||
|
StringCbPrintfW(command, sizeof(command), L"\"%s\" steam://run/%s", steamPath, wSteamId);
|
||||||
|
|
||||||
|
Discord_RegisterW(appId, command);
|
||||||
|
#endif
|
||||||
|
}
|
4
src/discord-register.h
Normal file
4
src/discord-register.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void Discord_Register(const char* applicationId, const char* command);
|
||||||
|
void Discord_RegisterSteamGame(const char* applicationId, const char* steamId);
|
@ -1,11 +1,13 @@
|
|||||||
#include "discord-rpc.h"
|
#include "discord-rpc.h"
|
||||||
|
|
||||||
#include "backoff.h"
|
#include "backoff.h"
|
||||||
|
#include "discord-register.h"
|
||||||
#include "rpc_connection.h"
|
#include "rpc_connection.h"
|
||||||
#include "serialization.h"
|
#include "serialization.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#ifndef DISCORD_DISABLE_IO_THREAD
|
#ifndef DISCORD_DISABLE_IO_THREAD
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
@ -18,15 +20,21 @@ constexpr size_t MessageQueueSize{8};
|
|||||||
struct QueuedMessage {
|
struct QueuedMessage {
|
||||||
size_t length;
|
size_t length;
|
||||||
char buffer[MaxMessageSize];
|
char buffer[MaxMessageSize];
|
||||||
|
|
||||||
|
void Copy(const QueuedMessage& other)
|
||||||
|
{
|
||||||
|
length = other.length;
|
||||||
|
if (length) {
|
||||||
|
memcpy(buffer, other.buffer, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static RpcConnection* Connection{nullptr};
|
static RpcConnection* Connection{nullptr};
|
||||||
static char ApplicationId[64]{};
|
|
||||||
static DiscordEventHandlers Handlers{};
|
static DiscordEventHandlers Handlers{};
|
||||||
static std::atomic_bool WasJustConnected{false};
|
static std::atomic_bool WasJustConnected{false};
|
||||||
static std::atomic_bool WasJustDisconnected{false};
|
static std::atomic_bool WasJustDisconnected{false};
|
||||||
static std::atomic_bool GotErrorMessage{false};
|
static std::atomic_bool GotErrorMessage{false};
|
||||||
static std::atomic_bool WasPresenceRequested{false};
|
|
||||||
static std::atomic_bool WasJoinGame{false};
|
static std::atomic_bool WasJoinGame{false};
|
||||||
static std::atomic_bool WasSpectateGame{false};
|
static std::atomic_bool WasSpectateGame{false};
|
||||||
static char JoinGameSecret[256];
|
static char JoinGameSecret[256];
|
||||||
@ -35,10 +43,14 @@ static int LastErrorCode{0};
|
|||||||
static char LastErrorMessage[256];
|
static char LastErrorMessage[256];
|
||||||
static int LastDisconnectErrorCode{0};
|
static int LastDisconnectErrorCode{0};
|
||||||
static char LastDisconnectErrorMessage[256];
|
static char LastDisconnectErrorMessage[256];
|
||||||
|
static std::mutex PresenceMutex;
|
||||||
|
static QueuedMessage QueuedPresence{};
|
||||||
static QueuedMessage SendQueue[MessageQueueSize]{};
|
static QueuedMessage SendQueue[MessageQueueSize]{};
|
||||||
static std::atomic_uint SendQueueNextAdd{0};
|
static std::atomic_uint SendQueueNextAdd{0};
|
||||||
static std::atomic_uint SendQueueNextSend{0};
|
static std::atomic_uint SendQueueNextSend{0};
|
||||||
static std::atomic_uint SendQueuePendingSends{0};
|
static std::atomic_uint SendQueuePendingSends{0};
|
||||||
|
// We want to auto connect, and retry on failure, but not as fast as possible. This does expoential
|
||||||
|
// backoff from 0.5 seconds to 1 minute
|
||||||
static Backoff ReconnectTimeMs(500, 60 * 1000);
|
static Backoff ReconnectTimeMs(500, 60 * 1000);
|
||||||
static auto NextConnect{std::chrono::system_clock::now()};
|
static auto NextConnect{std::chrono::system_clock::now()};
|
||||||
static int Pid{0};
|
static int Pid{0};
|
||||||
@ -59,6 +71,11 @@ static void UpdateReconnectTime()
|
|||||||
|
|
||||||
static QueuedMessage* SendQueueGetNextAddMessage()
|
static QueuedMessage* SendQueueGetNextAddMessage()
|
||||||
{
|
{
|
||||||
|
// if we are not connected, let's not batch up stale messages for later
|
||||||
|
if (!Connection || !Connection->IsOpen()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// if we are falling behind, bail
|
// if we are falling behind, bail
|
||||||
if (SendQueuePendingSends.load() >= MessageQueueSize) {
|
if (SendQueuePendingSends.load() >= MessageQueueSize) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -78,6 +95,10 @@ static void SendQueueCommitMessage()
|
|||||||
|
|
||||||
extern "C" void Discord_UpdateConnection()
|
extern "C" void Discord_UpdateConnection()
|
||||||
{
|
{
|
||||||
|
if (!Connection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Connection->IsOpen()) {
|
if (!Connection->IsOpen()) {
|
||||||
if (std::chrono::system_clock::now() >= NextConnect) {
|
if (std::chrono::system_clock::now() >= NextConnect) {
|
||||||
UpdateReconnectTime();
|
UpdateReconnectTime();
|
||||||
@ -94,20 +115,16 @@ extern "C" void Discord_UpdateConnection()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* evtName = nullptr;
|
const char* evtName = GetStrMember(&message, "evt");
|
||||||
auto evt = message.FindMember("evt");
|
const char* nonce = GetStrMember(&message, "nonce");
|
||||||
if (evt != message.MemberEnd() && evt->value.IsString()) {
|
|
||||||
evtName = evt->value.GetString();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto nonce = message.FindMember("nonce");
|
if (nonce) {
|
||||||
if (nonce != message.MemberEnd() && nonce->value.IsString()) {
|
|
||||||
// in responses only -- should use to match up response when needed.
|
// in responses only -- should use to match up response when needed.
|
||||||
|
|
||||||
if (evtName && strcmp(evtName, "ERROR") == 0) {
|
if (evtName && strcmp(evtName, "ERROR") == 0) {
|
||||||
auto data = message.FindMember("data");
|
auto data = GetObjMember(&message, "data");
|
||||||
LastErrorCode = data->value["code"].GetInt();
|
LastErrorCode = GetIntMember(data, "code");
|
||||||
StringCopy(LastErrorMessage, data->value["message"].GetString());
|
StringCopy(LastErrorMessage, GetStrMember(data, "message", ""));
|
||||||
GotErrorMessage.store(true);
|
GotErrorMessage.store(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,26 +134,40 @@ extern "C" void Discord_UpdateConnection()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo ug
|
if (strcmp(evtName, "GAME_JOIN") == 0) {
|
||||||
if (strcmp(evtName, "PRESENCE_REQUESTED") == 0) {
|
auto data = GetObjMember(&message, "data");
|
||||||
WasPresenceRequested.store(true);
|
auto secret = GetStrMember(data, "secret");
|
||||||
|
if (secret) {
|
||||||
|
StringCopy(JoinGameSecret, secret);
|
||||||
|
WasJoinGame.store(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (strcmp(evtName, "JOIN_GAME") == 0) {
|
else if (strcmp(evtName, "GAME_SPECTATE") == 0) {
|
||||||
auto data = message.FindMember("data");
|
auto data = GetObjMember(&message, "data");
|
||||||
auto secret = data->value["secret"].GetString();
|
auto secret = GetStrMember(data, "secret");
|
||||||
StringCopy(JoinGameSecret, secret);
|
if (secret) {
|
||||||
WasJoinGame.store(true);
|
StringCopy(SpectateGameSecret, secret);
|
||||||
}
|
WasSpectateGame.store(true);
|
||||||
else if (strcmp(evtName, "SPECTATE_GAME") == 0) {
|
}
|
||||||
auto data = message.FindMember("data");
|
|
||||||
auto secret = data->value["secret"].GetString();
|
|
||||||
StringCopy(SpectateGameSecret, secret);
|
|
||||||
WasSpectateGame.store(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// writes
|
// writes
|
||||||
|
if (QueuedPresence.length) {
|
||||||
|
QueuedMessage local;
|
||||||
|
PresenceMutex.lock();
|
||||||
|
local.Copy(QueuedPresence);
|
||||||
|
QueuedPresence.length = 0;
|
||||||
|
PresenceMutex.unlock();
|
||||||
|
if (!Connection->Write(local.buffer, local.length)) {
|
||||||
|
// if we fail to send, requeue
|
||||||
|
PresenceMutex.lock();
|
||||||
|
QueuedPresence.Copy(local);
|
||||||
|
PresenceMutex.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (SendQueuePendingSends.load()) {
|
while (SendQueuePendingSends.load()) {
|
||||||
auto qmessage = SendQueueGetNextSendMessage();
|
auto qmessage = SendQueueGetNextSendMessage();
|
||||||
Connection->Write(qmessage->buffer, qmessage->length);
|
Connection->Write(qmessage->buffer, qmessage->length);
|
||||||
@ -179,8 +210,20 @@ bool RegisterForEvent(const char* evtName)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_Initialize(const char* applicationId, DiscordEventHandlers* handlers)
|
extern "C" void Discord_Initialize(const char* applicationId,
|
||||||
|
DiscordEventHandlers* handlers,
|
||||||
|
int autoRegister,
|
||||||
|
const char* optionalSteamId)
|
||||||
{
|
{
|
||||||
|
if (autoRegister) {
|
||||||
|
if (optionalSteamId && optionalSteamId[0]) {
|
||||||
|
Discord_RegisterSteamGame(applicationId, optionalSteamId);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Discord_Register(applicationId, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Pid = GetProcessId();
|
Pid = GetProcessId();
|
||||||
|
|
||||||
if (handlers) {
|
if (handlers) {
|
||||||
@ -190,21 +233,21 @@ extern "C" void Discord_Initialize(const char* applicationId, DiscordEventHandle
|
|||||||
Handlers = {};
|
Handlers = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Connection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Connection = RpcConnection::Create(applicationId);
|
Connection = RpcConnection::Create(applicationId);
|
||||||
Connection->onConnect = []() {
|
Connection->onConnect = []() {
|
||||||
WasJustConnected.exchange(true);
|
WasJustConnected.exchange(true);
|
||||||
ReconnectTimeMs.reset();
|
ReconnectTimeMs.reset();
|
||||||
|
|
||||||
if (Handlers.presenceRequested) {
|
|
||||||
RegisterForEvent("PRESENCE_REQUESTED");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Handlers.joinGame) {
|
if (Handlers.joinGame) {
|
||||||
RegisterForEvent("JOIN_GAME");
|
RegisterForEvent("GAME_JOIN");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Handlers.spectateGame) {
|
if (Handlers.spectateGame) {
|
||||||
RegisterForEvent("SPECTATE_GAME");
|
RegisterForEvent("GAME_SPECTATE");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Connection->onDisconnect = [](int err, const char* message) {
|
Connection->onDisconnect = [](int err, const char* message) {
|
||||||
@ -215,12 +258,16 @@ extern "C" void Discord_Initialize(const char* applicationId, DiscordEventHandle
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifndef DISCORD_DISABLE_IO_THREAD
|
#ifndef DISCORD_DISABLE_IO_THREAD
|
||||||
|
KeepRunning.store(true);
|
||||||
IoThread = std::thread(DiscordRpcIo);
|
IoThread = std::thread(DiscordRpcIo);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_Shutdown()
|
extern "C" void Discord_Shutdown()
|
||||||
{
|
{
|
||||||
|
if (!Connection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Connection->onConnect = nullptr;
|
Connection->onConnect = nullptr;
|
||||||
Connection->onDisconnect = nullptr;
|
Connection->onDisconnect = nullptr;
|
||||||
Handlers = {};
|
Handlers = {};
|
||||||
@ -236,31 +283,39 @@ extern "C" void Discord_Shutdown()
|
|||||||
|
|
||||||
extern "C" void Discord_UpdatePresence(const DiscordRichPresence* presence)
|
extern "C" void Discord_UpdatePresence(const DiscordRichPresence* presence)
|
||||||
{
|
{
|
||||||
auto qmessage = SendQueueGetNextAddMessage();
|
PresenceMutex.lock();
|
||||||
if (qmessage) {
|
QueuedPresence.length = JsonWriteRichPresenceObj(
|
||||||
qmessage->length = JsonWriteRichPresenceObj(
|
QueuedPresence.buffer, sizeof(QueuedPresence.buffer), Nonce++, Pid, presence);
|
||||||
qmessage->buffer, sizeof(qmessage->buffer), Nonce++, Pid, presence);
|
PresenceMutex.unlock();
|
||||||
SendQueueCommitMessage();
|
SignalIOActivity();
|
||||||
SignalIOActivity();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_RunCallbacks()
|
extern "C" void Discord_RunCallbacks()
|
||||||
{
|
{
|
||||||
if (GotErrorMessage.exchange(false) && Handlers.errored) {
|
// Note on some weirdness: internally we might connect, get other signals, disconnect any number
|
||||||
Handlers.errored(LastErrorCode, LastErrorMessage);
|
// of times inbetween calls here. Externally, we want the sequence to seem sane, so any other
|
||||||
|
// signals are book-ended by calls to ready and disconnect.
|
||||||
|
|
||||||
|
if (!Connection) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WasJustDisconnected.exchange(false) && Handlers.disconnected) {
|
bool wasDisconnected = WasJustDisconnected.exchange(false);
|
||||||
Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage);
|
bool isConnected = Connection->IsOpen();
|
||||||
|
|
||||||
|
if (isConnected) {
|
||||||
|
// if we are connected, disconnect cb first
|
||||||
|
if (wasDisconnected && Handlers.disconnected) {
|
||||||
|
Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WasJustConnected.exchange(false) && Handlers.ready) {
|
if (WasJustConnected.exchange(false) && Handlers.ready) {
|
||||||
Handlers.ready();
|
Handlers.ready();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WasPresenceRequested.exchange(false) && Handlers.presenceRequested) {
|
if (GotErrorMessage.exchange(false) && Handlers.errored) {
|
||||||
Handlers.presenceRequested();
|
Handlers.errored(LastErrorCode, LastErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WasJoinGame.exchange(false) && Handlers.joinGame) {
|
if (WasJoinGame.exchange(false) && Handlers.joinGame) {
|
||||||
@ -270,4 +325,11 @@ extern "C" void Discord_RunCallbacks()
|
|||||||
if (WasSpectateGame.exchange(false) && Handlers.spectateGame) {
|
if (WasSpectateGame.exchange(false) && Handlers.spectateGame) {
|
||||||
Handlers.spectateGame(SpectateGameSecret);
|
Handlers.spectateGame(SpectateGameSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isConnected) {
|
||||||
|
// if we are not connected, disconnect message last
|
||||||
|
if (wasDisconnected && Handlers.disconnected) {
|
||||||
|
Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
6
src/dllmain.cpp
Normal file
6
src/dllmain.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HMODULE, DWORD, LPVOID)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
@ -17,6 +17,7 @@ static RpcConnection Instance;
|
|||||||
{
|
{
|
||||||
c->Close();
|
c->Close();
|
||||||
BaseConnection::Destroy(c->connection);
|
BaseConnection::Destroy(c->connection);
|
||||||
|
c = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RpcConnection::Open()
|
void RpcConnection::Open()
|
||||||
@ -36,16 +37,9 @@ void RpcConnection::Open()
|
|||||||
if (state == State::SentHandshake) {
|
if (state == State::SentHandshake) {
|
||||||
JsonDocument message;
|
JsonDocument message;
|
||||||
if (Read(message)) {
|
if (Read(message)) {
|
||||||
auto cmd = message.FindMember("cmd");
|
auto cmd = GetStrMember(&message, "cmd");
|
||||||
if (cmd == message.MemberEnd() || !cmd->value.IsString()) {
|
auto evt = GetStrMember(&message, "evt");
|
||||||
return;
|
if (cmd && evt && !strcmp(cmd, "DISPATCH") && !strcmp(evt, "READY")) {
|
||||||
}
|
|
||||||
auto evt = message.FindMember("evt");
|
|
||||||
if (evt == message.MemberEnd() || !evt->value.IsString()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!strcmp(cmd->value.GetString(), "DISPATCH") &&
|
|
||||||
!strcmp(evt->value.GetString(), "READY")) {
|
|
||||||
state = State::Connected;
|
state = State::Connected;
|
||||||
if (onConnect) {
|
if (onConnect) {
|
||||||
onConnect();
|
onConnect();
|
||||||
@ -55,8 +49,8 @@ void RpcConnection::Open()
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sendFrame.opcode = Opcode::Handshake;
|
sendFrame.opcode = Opcode::Handshake;
|
||||||
sendFrame.length =
|
sendFrame.length = (uint32_t)JsonWriteHandshakeObj(
|
||||||
JsonWriteHandshakeObj(sendFrame.message, sizeof(sendFrame.message), RpcVersion, appId);
|
sendFrame.message, sizeof(sendFrame.message), RpcVersion, appId);
|
||||||
|
|
||||||
if (connection->Write(&sendFrame, sizeof(MessageFrameHeader) + sendFrame.length)) {
|
if (connection->Write(&sendFrame, sizeof(MessageFrameHeader) + sendFrame.length)) {
|
||||||
state = State::SentHandshake;
|
state = State::SentHandshake;
|
||||||
@ -80,7 +74,7 @@ bool RpcConnection::Write(const void* data, size_t length)
|
|||||||
{
|
{
|
||||||
sendFrame.opcode = Opcode::Frame;
|
sendFrame.opcode = Opcode::Frame;
|
||||||
memcpy(sendFrame.message, data, length);
|
memcpy(sendFrame.message, data, length);
|
||||||
sendFrame.length = length;
|
sendFrame.length = (uint32_t)length;
|
||||||
if (!connection->Write(&sendFrame, sizeof(MessageFrameHeader) + length)) {
|
if (!connection->Write(&sendFrame, sizeof(MessageFrameHeader) + length)) {
|
||||||
Close();
|
Close();
|
||||||
return false;
|
return false;
|
||||||
@ -97,13 +91,18 @@ bool RpcConnection::Read(JsonDocument& message)
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
bool didRead = connection->Read(&readFrame, sizeof(MessageFrameHeader));
|
bool didRead = connection->Read(&readFrame, sizeof(MessageFrameHeader));
|
||||||
if (!didRead) {
|
if (!didRead) {
|
||||||
|
if (!connection->isOpen) {
|
||||||
|
lastErrorCode = (int)ErrorCode::PipeClosed;
|
||||||
|
StringCopy(lastErrorMessage, "Pipe closed");
|
||||||
|
Close();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readFrame.length > 0) {
|
if (readFrame.length > 0) {
|
||||||
didRead = connection->Read(readFrame.message, readFrame.length);
|
didRead = connection->Read(readFrame.message, readFrame.length);
|
||||||
if (!didRead) {
|
if (!didRead) {
|
||||||
lastErrorCode = -2;
|
lastErrorCode = (int)ErrorCode::ReadCorrupt;
|
||||||
StringCopy(lastErrorMessage, "Partial data in frame");
|
StringCopy(lastErrorMessage, "Partial data in frame");
|
||||||
Close();
|
Close();
|
||||||
return false;
|
return false;
|
||||||
@ -114,9 +113,8 @@ bool RpcConnection::Read(JsonDocument& message)
|
|||||||
switch (readFrame.opcode) {
|
switch (readFrame.opcode) {
|
||||||
case Opcode::Close: {
|
case Opcode::Close: {
|
||||||
message.ParseInsitu(readFrame.message);
|
message.ParseInsitu(readFrame.message);
|
||||||
lastErrorCode = message["code"].GetInt();
|
lastErrorCode = GetIntMember(&message, "code");
|
||||||
const auto& m = message["message"];
|
StringCopy(lastErrorMessage, GetStrMember(&message, "message", ""));
|
||||||
StringCopy(lastErrorMessage, m.GetString());
|
|
||||||
Close();
|
Close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -133,7 +131,7 @@ bool RpcConnection::Read(JsonDocument& message)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// something bad happened
|
// something bad happened
|
||||||
lastErrorCode = -1;
|
lastErrorCode = (int)ErrorCode::ReadCorrupt;
|
||||||
StringCopy(lastErrorMessage, "Bad ipc frame");
|
StringCopy(lastErrorMessage, "Bad ipc frame");
|
||||||
Close();
|
Close();
|
||||||
return false;
|
return false;
|
||||||
|
@ -8,6 +8,12 @@
|
|||||||
constexpr size_t MaxRpcFrameSize = 64 * 1024;
|
constexpr size_t MaxRpcFrameSize = 64 * 1024;
|
||||||
|
|
||||||
struct RpcConnection {
|
struct RpcConnection {
|
||||||
|
enum class ErrorCode : int {
|
||||||
|
Success = 0,
|
||||||
|
PipeClosed = 1,
|
||||||
|
ReadCorrupt = 2,
|
||||||
|
};
|
||||||
|
|
||||||
enum class Opcode : uint32_t {
|
enum class Opcode : uint32_t {
|
||||||
Handshake = 0,
|
Handshake = 0,
|
||||||
Frame = 1,
|
Frame = 1,
|
||||||
|
@ -2,7 +2,30 @@
|
|||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "discord-rpc.h"
|
#include "discord-rpc.h"
|
||||||
|
|
||||||
MallocAllocator MallocAllocatorInst;
|
template <typename T>
|
||||||
|
void NumberToString(char* dest, T number)
|
||||||
|
{
|
||||||
|
if (!number) {
|
||||||
|
*dest++ = '0';
|
||||||
|
*dest++ = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (number < 0) {
|
||||||
|
*dest++ = '-';
|
||||||
|
number = -number;
|
||||||
|
}
|
||||||
|
char temp[32];
|
||||||
|
int place = 0;
|
||||||
|
while (number) {
|
||||||
|
auto digit = number % 10;
|
||||||
|
number = number / 10;
|
||||||
|
temp[place++] = '0' + (char)digit;
|
||||||
|
}
|
||||||
|
for (--place; place >= 0; --place) {
|
||||||
|
*dest++ = temp[place];
|
||||||
|
}
|
||||||
|
*dest = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// it's ever so slightly faster to not have to strlen the key
|
// it's ever so slightly faster to not have to strlen the key
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -11,10 +34,39 @@ void WriteKey(JsonWriter& w, T& k)
|
|||||||
w.Key(k, sizeof(T) - 1);
|
w.Key(k, sizeof(T) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct WriteObject {
|
||||||
|
JsonWriter& writer;
|
||||||
|
WriteObject(JsonWriter& w)
|
||||||
|
: writer(w)
|
||||||
|
{
|
||||||
|
writer.StartObject();
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
WriteObject(JsonWriter& w, T& name)
|
||||||
|
: writer(w)
|
||||||
|
{
|
||||||
|
WriteKey(writer, name);
|
||||||
|
writer.StartObject();
|
||||||
|
}
|
||||||
|
~WriteObject() { writer.EndObject(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WriteArray {
|
||||||
|
JsonWriter& writer;
|
||||||
|
template <typename T>
|
||||||
|
WriteArray(JsonWriter& w, T& name)
|
||||||
|
: writer(w)
|
||||||
|
{
|
||||||
|
WriteKey(writer, name);
|
||||||
|
writer.StartArray();
|
||||||
|
}
|
||||||
|
~WriteArray() { writer.EndArray(); }
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void WriteOptionalString(JsonWriter& w, T& k, const char* value)
|
void WriteOptionalString(JsonWriter& w, T& k, const char* value)
|
||||||
{
|
{
|
||||||
if (value) {
|
if (value && value[0]) {
|
||||||
w.Key(k, sizeof(T) - 1);
|
w.Key(k, sizeof(T) - 1);
|
||||||
w.String(value);
|
w.String(value);
|
||||||
}
|
}
|
||||||
@ -23,154 +75,125 @@ void WriteOptionalString(JsonWriter& w, T& k, const char* value)
|
|||||||
void JsonWriteNonce(JsonWriter& writer, int nonce)
|
void JsonWriteNonce(JsonWriter& writer, int nonce)
|
||||||
{
|
{
|
||||||
WriteKey(writer, "nonce");
|
WriteKey(writer, "nonce");
|
||||||
char nonceBuffer[32]{};
|
char nonceBuffer[32];
|
||||||
rapidjson::internal::i32toa(nonce, nonceBuffer);
|
NumberToString(nonceBuffer, nonce);
|
||||||
writer.String(nonceBuffer);
|
writer.String(nonceBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonWriteCommandStart(JsonWriter& writer, int nonce, const char* cmd)
|
|
||||||
{
|
|
||||||
writer.StartObject();
|
|
||||||
|
|
||||||
JsonWriteNonce(writer, nonce);
|
|
||||||
|
|
||||||
WriteKey(writer, "cmd");
|
|
||||||
writer.String(cmd);
|
|
||||||
|
|
||||||
WriteKey(writer, "args");
|
|
||||||
writer.StartObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
void JsonWriteCommandEnd(JsonWriter& writer)
|
|
||||||
{
|
|
||||||
writer.EndObject(); // args
|
|
||||||
writer.EndObject(); // top level
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t JsonWriteRichPresenceObj(char* dest,
|
size_t JsonWriteRichPresenceObj(char* dest,
|
||||||
size_t maxLen,
|
size_t maxLen,
|
||||||
int nonce,
|
int nonce,
|
||||||
int pid,
|
int pid,
|
||||||
const DiscordRichPresence* presence)
|
const DiscordRichPresence* presence)
|
||||||
{
|
{
|
||||||
DirectStringBuffer sb(dest, maxLen);
|
JsonWriter writer(dest, maxLen);
|
||||||
StackAllocator wa;
|
|
||||||
JsonWriter writer(sb, &wa, WriterNestingLevels);
|
|
||||||
|
|
||||||
JsonWriteCommandStart(writer, nonce, "SET_ACTIVITY");
|
{
|
||||||
|
WriteObject top(writer);
|
||||||
|
|
||||||
WriteKey(writer, "pid");
|
JsonWriteNonce(writer, nonce);
|
||||||
writer.Int(pid);
|
|
||||||
|
|
||||||
WriteKey(writer, "activity");
|
WriteKey(writer, "cmd");
|
||||||
writer.StartObject();
|
writer.String("SET_ACTIVITY");
|
||||||
|
|
||||||
WriteOptionalString(writer, "state", presence->state);
|
{
|
||||||
WriteOptionalString(writer, "details", presence->details);
|
WriteObject args(writer, "args");
|
||||||
|
|
||||||
if (presence->startTimestamp || presence->endTimestamp) {
|
WriteKey(writer, "pid");
|
||||||
WriteKey(writer, "timestamps");
|
writer.Int(pid);
|
||||||
writer.StartObject();
|
|
||||||
|
|
||||||
if (presence->startTimestamp) {
|
{
|
||||||
WriteKey(writer, "start");
|
WriteObject activity(writer, "activity");
|
||||||
writer.Int64(presence->startTimestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presence->endTimestamp) {
|
WriteOptionalString(writer, "state", presence->state);
|
||||||
WriteKey(writer, "end");
|
WriteOptionalString(writer, "details", presence->details);
|
||||||
writer.Int64(presence->endTimestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.EndObject();
|
if (presence->startTimestamp || presence->endTimestamp) {
|
||||||
}
|
WriteObject timestamps(writer, "timestamps");
|
||||||
|
|
||||||
if (presence->largeImageKey || presence->largeImageText || presence->smallImageKey ||
|
if (presence->startTimestamp) {
|
||||||
presence->smallImageText) {
|
WriteKey(writer, "start");
|
||||||
WriteKey(writer, "assets");
|
writer.Int64(presence->startTimestamp);
|
||||||
writer.StartObject();
|
}
|
||||||
|
|
||||||
WriteOptionalString(writer, "large_image", presence->largeImageKey);
|
if (presence->endTimestamp) {
|
||||||
WriteOptionalString(writer, "large_text", presence->largeImageText);
|
WriteKey(writer, "end");
|
||||||
WriteOptionalString(writer, "small_image", presence->smallImageKey);
|
writer.Int64(presence->endTimestamp);
|
||||||
WriteOptionalString(writer, "small_text", presence->smallImageText);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
writer.EndObject();
|
if ((presence->largeImageKey && presence->largeImageKey[0]) ||
|
||||||
}
|
(presence->largeImageText && presence->largeImageText[0]) ||
|
||||||
|
(presence->smallImageKey && presence->smallImageKey[0]) ||
|
||||||
|
(presence->smallImageText && presence->smallImageText[0])) {
|
||||||
|
WriteObject assets(writer, "assets");
|
||||||
|
WriteOptionalString(writer, "large_image", presence->largeImageKey);
|
||||||
|
WriteOptionalString(writer, "large_text", presence->largeImageText);
|
||||||
|
WriteOptionalString(writer, "small_image", presence->smallImageKey);
|
||||||
|
WriteOptionalString(writer, "small_text", presence->smallImageText);
|
||||||
|
}
|
||||||
|
|
||||||
if (presence->partyId || presence->partySize || presence->partyMax) {
|
if ((presence->partyId && presence->partyId[0]) || presence->partySize ||
|
||||||
WriteKey(writer, "party");
|
presence->partyMax) {
|
||||||
writer.StartObject();
|
WriteObject party(writer, "party");
|
||||||
|
WriteOptionalString(writer, "id", presence->partyId);
|
||||||
|
if (presence->partySize) {
|
||||||
|
WriteArray size(writer, "size");
|
||||||
|
writer.Int(presence->partySize);
|
||||||
|
if (0 < presence->partyMax) {
|
||||||
|
writer.Int(presence->partyMax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WriteOptionalString(writer, "id", presence->partyId);
|
if ((presence->matchSecret && presence->matchSecret[0]) ||
|
||||||
if (presence->partySize) {
|
(presence->joinSecret && presence->joinSecret[0]) ||
|
||||||
writer.StartArray();
|
(presence->spectateSecret && presence->spectateSecret[0])) {
|
||||||
|
WriteObject secrets(writer, "secrets");
|
||||||
|
WriteOptionalString(writer, "match", presence->matchSecret);
|
||||||
|
WriteOptionalString(writer, "join", presence->joinSecret);
|
||||||
|
WriteOptionalString(writer, "spectate", presence->spectateSecret);
|
||||||
|
}
|
||||||
|
|
||||||
writer.Int(presence->partySize);
|
writer.Key("instance");
|
||||||
if (0 < presence->partyMax) {
|
writer.Bool(presence->instance != 0);
|
||||||
writer.Int(presence->partyMax);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.EndArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.EndObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (presence->matchSecret || presence->joinSecret || presence->spectateSecret) {
|
return writer.Size();
|
||||||
WriteKey(writer, "secrets");
|
|
||||||
writer.StartObject();
|
|
||||||
|
|
||||||
WriteOptionalString(writer, "match", presence->matchSecret);
|
|
||||||
WriteOptionalString(writer, "join", presence->joinSecret);
|
|
||||||
WriteOptionalString(writer, "spectate", presence->spectateSecret);
|
|
||||||
|
|
||||||
writer.EndObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.Key("instance");
|
|
||||||
writer.Bool(presence->instance != 0);
|
|
||||||
|
|
||||||
writer.EndObject(); // activity
|
|
||||||
|
|
||||||
JsonWriteCommandEnd(writer);
|
|
||||||
|
|
||||||
return sb.GetSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId)
|
size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId)
|
||||||
{
|
{
|
||||||
DirectStringBuffer sb(dest, maxLen);
|
JsonWriter writer(dest, maxLen);
|
||||||
StackAllocator wa;
|
|
||||||
JsonWriter writer(sb, &wa, WriterNestingLevels);
|
|
||||||
|
|
||||||
writer.StartObject();
|
{
|
||||||
WriteKey(writer, "v");
|
WriteObject obj(writer);
|
||||||
writer.Int(version);
|
WriteKey(writer, "v");
|
||||||
WriteKey(writer, "client_id");
|
writer.Int(version);
|
||||||
writer.String(applicationId);
|
WriteKey(writer, "client_id");
|
||||||
writer.EndObject();
|
writer.String(applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
return sb.GetSize();
|
return writer.Size();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName)
|
size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName)
|
||||||
{
|
{
|
||||||
DirectStringBuffer sb(dest, maxLen);
|
JsonWriter writer(dest, maxLen);
|
||||||
StackAllocator wa;
|
|
||||||
JsonWriter writer(sb, &wa, WriterNestingLevels);
|
|
||||||
|
|
||||||
writer.StartObject();
|
{
|
||||||
|
WriteObject obj(writer);
|
||||||
|
|
||||||
JsonWriteNonce(writer, nonce);
|
JsonWriteNonce(writer, nonce);
|
||||||
|
|
||||||
WriteKey(writer, "cmd");
|
WriteKey(writer, "cmd");
|
||||||
writer.String("SUBSCRIBE");
|
writer.String("SUBSCRIBE");
|
||||||
|
|
||||||
WriteKey(writer, "evt");
|
WriteKey(writer, "evt");
|
||||||
writer.String(evtName);
|
writer.String(evtName);
|
||||||
|
}
|
||||||
|
|
||||||
writer.EndObject();
|
return writer.Size();
|
||||||
|
|
||||||
return sb.GetSize();
|
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,12 @@
|
|||||||
#include "rapidjson/document.h"
|
#include "rapidjson/document.h"
|
||||||
#include "rapidjson/writer.h"
|
#include "rapidjson/writer.h"
|
||||||
#include "rapidjson/stringbuffer.h"
|
#include "rapidjson/stringbuffer.h"
|
||||||
#include "rapidjson/internal/itoa.h"
|
|
||||||
|
|
||||||
// if only there was a standard library function for this
|
// if only there was a standard library function for this
|
||||||
template <size_t Len>
|
template <size_t Len>
|
||||||
inline size_t StringCopy(char (&dest)[Len], const char* src)
|
inline size_t StringCopy(char (&dest)[Len], const char* src)
|
||||||
{
|
{
|
||||||
if (!dest || !src || !Len) {
|
if (!src || !Len) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
size_t copied;
|
size_t copied;
|
||||||
@ -35,8 +34,7 @@ size_t JsonWriteRichPresenceObj(char* dest,
|
|||||||
size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName);
|
size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName);
|
||||||
|
|
||||||
// I want to use as few allocations as I can get away with, and to do that with RapidJson, you need
|
// I want to use as few allocations as I can get away with, and to do that with RapidJson, you need
|
||||||
// to supply some of
|
// to supply some of your own allocators for stuff rather than use the defaults
|
||||||
// your own allocators for stuff rather than use the defaults
|
|
||||||
|
|
||||||
class LinearAllocator {
|
class LinearAllocator {
|
||||||
public:
|
public:
|
||||||
@ -71,7 +69,11 @@ public:
|
|||||||
assert(!originalPtr && !originalSize);
|
assert(!originalPtr && !originalSize);
|
||||||
return Malloc(newSize);
|
return Malloc(newSize);
|
||||||
}
|
}
|
||||||
static void Free(void* ptr) { /* shrug */}
|
static void Free(void* ptr)
|
||||||
|
{
|
||||||
|
/* shrug */
|
||||||
|
(void)ptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <size_t Size>
|
template <size_t Size>
|
||||||
@ -116,8 +118,23 @@ using UTF8 = rapidjson::UTF8<char>;
|
|||||||
// Writer appears to need about 16 bytes per nested object level (with 64bit size_t)
|
// Writer appears to need about 16 bytes per nested object level (with 64bit size_t)
|
||||||
using StackAllocator = FixedLinearAllocator<2048>;
|
using StackAllocator = FixedLinearAllocator<2048>;
|
||||||
constexpr size_t WriterNestingLevels = 2048 / (2 * sizeof(size_t));
|
constexpr size_t WriterNestingLevels = 2048 / (2 * sizeof(size_t));
|
||||||
using JsonWriter =
|
using JsonWriterBase =
|
||||||
rapidjson::Writer<DirectStringBuffer, UTF8, UTF8, StackAllocator, rapidjson::kWriteNoFlags>;
|
rapidjson::Writer<DirectStringBuffer, UTF8, UTF8, StackAllocator, rapidjson::kWriteNoFlags>;
|
||||||
|
class JsonWriter : public JsonWriterBase {
|
||||||
|
public:
|
||||||
|
DirectStringBuffer stringBuffer_;
|
||||||
|
StackAllocator stackAlloc_;
|
||||||
|
|
||||||
|
JsonWriter(char* dest, size_t maxLen)
|
||||||
|
: JsonWriterBase(stringBuffer_, &stackAlloc_, WriterNestingLevels)
|
||||||
|
, stringBuffer_(dest, maxLen)
|
||||||
|
, stackAlloc_()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Size() const { return stringBuffer_.GetSize(); }
|
||||||
|
};
|
||||||
|
|
||||||
using JsonDocumentBase = rapidjson::GenericDocument<UTF8, PoolAllocator, StackAllocator>;
|
using JsonDocumentBase = rapidjson::GenericDocument<UTF8, PoolAllocator, StackAllocator>;
|
||||||
class JsonDocument : public JsonDocumentBase {
|
class JsonDocument : public JsonDocumentBase {
|
||||||
public:
|
public:
|
||||||
@ -138,3 +155,40 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using JsonValue = rapidjson::GenericValue<UTF8, PoolAllocator>;
|
||||||
|
|
||||||
|
inline JsonValue* GetObjMember(JsonValue* obj, const char* name)
|
||||||
|
{
|
||||||
|
if (obj) {
|
||||||
|
auto member = obj->FindMember(name);
|
||||||
|
if (member != obj->MemberEnd() && member->value.IsObject()) {
|
||||||
|
return &member->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int GetIntMember(JsonValue* obj, const char* name, int notFoundDefault = 0)
|
||||||
|
{
|
||||||
|
if (obj) {
|
||||||
|
auto member = obj->FindMember(name);
|
||||||
|
if (member != obj->MemberEnd() && member->value.IsInt()) {
|
||||||
|
return member->value.GetInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return notFoundDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* GetStrMember(JsonValue* obj,
|
||||||
|
const char* name,
|
||||||
|
const char* notFoundDefault = nullptr)
|
||||||
|
{
|
||||||
|
if (obj) {
|
||||||
|
auto member = obj->FindMember(name);
|
||||||
|
if (member != obj->MemberEnd() && member->value.IsString()) {
|
||||||
|
return member->value.GetString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return notFoundDefault;
|
||||||
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "test-rpc-server",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"server": "node rpc-server.js",
|
|
||||||
"client": "node test-client.js"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
const path = require('path');
|
|
||||||
|
|
||||||
const VERSION = 1;
|
|
||||||
|
|
||||||
const OPCODES = {
|
|
||||||
HANDSHAKE: 0,
|
|
||||||
FRAME: 1,
|
|
||||||
CLOSE: 2,
|
|
||||||
PING: 3,
|
|
||||||
PONG: 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
let PipePath;
|
|
||||||
if (process.platform == 'win32') {
|
|
||||||
PipePath = '\\\\?\\pipe\\discord-ipc';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const temp = process.env.XDG_RUNTIME_DIR || process.env.TMPDIR || process.env.TMP || process.env.TEMP || '/tmp';
|
|
||||||
PipePath = path.join(temp, 'discord-ipc');
|
|
||||||
}
|
|
||||||
|
|
||||||
class RpcMessage {
|
|
||||||
|
|
||||||
static serialize(opcode, obj) {
|
|
||||||
const serializedJson = JSON.stringify(obj);
|
|
||||||
const msgLen = serializedJson.length;
|
|
||||||
let buff = Buffer.alloc(8 + msgLen);
|
|
||||||
buff.writeInt32LE(opcode, 0);
|
|
||||||
buff.writeInt32LE(msgLen, 4);
|
|
||||||
buff.write(serializedJson, 8, serializedJson.length, 'utf-8');
|
|
||||||
return buff;
|
|
||||||
}
|
|
||||||
|
|
||||||
static handshake(id) {
|
|
||||||
const opcode = OPCODES.HANDSHAKE;
|
|
||||||
return RpcMessage.serialize(opcode, {
|
|
||||||
client_id: id,
|
|
||||||
v: VERSION
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static send(obj) {
|
|
||||||
const opcode = OPCODES.FRAME;
|
|
||||||
return RpcMessage.serialize(opcode, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
static sendClose(code, message) {
|
|
||||||
const opcode = OPCODES.CLOSE;
|
|
||||||
return RpcMessage.serialize(opcode, {code, message});
|
|
||||||
}
|
|
||||||
|
|
||||||
static sendPing(message) {
|
|
||||||
const opcode = OPCODES.PING;
|
|
||||||
return RpcMessage.serialize(opcode, {message});
|
|
||||||
}
|
|
||||||
|
|
||||||
static deserialize(buff) {
|
|
||||||
const opcode = buff.readInt32LE(0);
|
|
||||||
const msgLen = buff.readInt32LE(4);
|
|
||||||
if (msgLen == 0) {
|
|
||||||
return {opcode, data: ''};
|
|
||||||
}
|
|
||||||
if (buff.length < (msgLen + 8)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const msg = buff.toString('utf-8', 8, msgLen + 8);
|
|
||||||
try {
|
|
||||||
return {opcode, data: JSON.parse(msg)};
|
|
||||||
} catch(e) {
|
|
||||||
console.log(`failed to parse "${msg}"`);
|
|
||||||
console.error(e);
|
|
||||||
return {opcode: OPCODES.CLOSE, message: e.message};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {OPCODES, PipePath, RpcMessage};
|
|
@ -1,75 +0,0 @@
|
|||||||
const net = require('net');
|
|
||||||
const repl = require('repl');
|
|
||||||
const {PipePath, RpcMessage} = require('./rpc-message');
|
|
||||||
|
|
||||||
let connectionNonce = 0;
|
|
||||||
global.connections = {};
|
|
||||||
|
|
||||||
const server = net.createServer(function(sock) {
|
|
||||||
connectionNonce += 1;
|
|
||||||
console.log('Server: on connection', connectionNonce);
|
|
||||||
let myConnection = connectionNonce;
|
|
||||||
let messages = 0;
|
|
||||||
|
|
||||||
global.connections[myConnection] = sock;
|
|
||||||
|
|
||||||
sock.on('data', function(data) {
|
|
||||||
messages++;
|
|
||||||
const msgObj = RpcMessage.deserialize(data);
|
|
||||||
if (msgObj != null) {
|
|
||||||
const {opcode, data} = msgObj;
|
|
||||||
console.log(`\nServer (${myConnection}): got opcode: ${opcode}, data: ${JSON.stringify(data)}`);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.log('\nServer: got some data', data.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
sock.on('end', function() {
|
|
||||||
delete global.connections[myConnection];
|
|
||||||
console.log('\nServer: on end', myConnection);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
server.on('close', function(){
|
|
||||||
console.log('\nServer: on close');
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
server.listen(PipePath, function(){
|
|
||||||
console.log('\nServer: on listening');
|
|
||||||
});
|
|
||||||
} catch(e) {
|
|
||||||
console.error('\nServer: could not start:', e);
|
|
||||||
}
|
|
||||||
|
|
||||||
const replServer = repl.start({prompt: '> ', useGlobal: true, breakEvalOnSigint: true});
|
|
||||||
replServer.defineCommand('kill', {
|
|
||||||
help: 'Kill a client',
|
|
||||||
action(who) {
|
|
||||||
this.bufferedCommand = '';
|
|
||||||
who = parseInt(who, 10);
|
|
||||||
const sock = global.connections[who];
|
|
||||||
if (sock) {
|
|
||||||
console.log('killing', who);
|
|
||||||
sock.end(RpcMessage.sendClose(123, 'killed'));
|
|
||||||
}
|
|
||||||
this.displayPrompt();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
replServer.defineCommand('ping', {
|
|
||||||
help: 'Ping all clients',
|
|
||||||
action() {
|
|
||||||
this.bufferedCommand = '';
|
|
||||||
Object.keys(global.connections).forEach((who) => {
|
|
||||||
const sock = global.connections[who];
|
|
||||||
if (sock) {
|
|
||||||
console.log('pinging', who);
|
|
||||||
sock.write(RpcMessage.sendPing('hello'));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.displayPrompt();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
|||||||
const net = require('net');
|
|
||||||
const {OPCODES, PipePath, RpcMessage} = require('./rpc-message');
|
|
||||||
|
|
||||||
const APP_ID = '12345678910';
|
|
||||||
global.isConnected = false;
|
|
||||||
global.timeoutId = null;
|
|
||||||
|
|
||||||
function sendMesg(testUpdatesToSend, stream) {
|
|
||||||
const msgObj = {
|
|
||||||
state: (testUpdatesToSend % 2 == 0) ? 'In a match' : 'In Lobby',
|
|
||||||
details: 'Excited'
|
|
||||||
};
|
|
||||||
console.log('Client: send update:', msgObj);
|
|
||||||
stream.write(RpcMessage.send(msgObj));
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendMessageLoop(testUpdatesToSend, interval, stream) {
|
|
||||||
global.timeoutId = null;
|
|
||||||
if (!global.isConnected) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sendMesg(testUpdatesToSend, stream);
|
|
||||||
if (testUpdatesToSend > 1) {
|
|
||||||
global.timeoutId = setTimeout(() => {sendMessageLoop(testUpdatesToSend - 1, interval, stream)}, interval);
|
|
||||||
} else {
|
|
||||||
shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const client = net.connect(PipePath, function(stream) {
|
|
||||||
console.log('Client: on connection');
|
|
||||||
global.isConnected = true;
|
|
||||||
client.write(RpcMessage.handshake(APP_ID));
|
|
||||||
sendMessageLoop(10, 3000, client);
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('data', function(data) {
|
|
||||||
const msgObj = RpcMessage.deserialize(data);
|
|
||||||
if (msgObj != null) {
|
|
||||||
const {opcode, data} = msgObj;
|
|
||||||
console.log(`Client: got opcode: ${opcode}, data: ${JSON.stringify(data)}`);
|
|
||||||
|
|
||||||
if (opcode == OPCODES.CLOSE) {
|
|
||||||
shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log('Client: got some data', data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('end', function() {
|
|
||||||
global.isConnected = false;
|
|
||||||
console.log('Client: on end');
|
|
||||||
});
|
|
||||||
|
|
||||||
function shutdown() {
|
|
||||||
if (global.timeoutId !== null) {
|
|
||||||
clearTimeout(global.timeoutId);
|
|
||||||
global.timeoutId = null;
|
|
||||||
}
|
|
||||||
client.end();
|
|
||||||
}
|
|
Reference in New Issue
Block a user