Compare commits

...

167 Commits

Author SHA1 Message Date
Ishaan Bhardwaj d0fdaf30ab
Merge pull request #81 from Tetro48/std-rs-lockpatch
Patch standard.lua to prevent midair lock
2023-10-19 04:27:06 -04:00
Aymir Dmitrievich Danilov 8062f6e3fa
Patch standard.lua to prevent midair lock 2023-10-19 14:33:25 +07:00
Ishaan Bhardwaj 7c3cf0b1bd
Merge pull request #79 from aur9ra/feat-save-replay-once-per-game-only
Ensure replays are only saved once per game
2023-08-25 19:28:34 -04:00
aur9ra 52ddbbc174 Ensure replays are only saved once per game 2023-08-20 22:22:36 -07:00
Ishaan Bhardwaj 5f81c35677
Merge pull request #78 from Tetro48/replay-qol
Replay frame stepping
2023-08-14 11:26:56 -04:00
Tetro48 635ef6270f
Changed frame step input to `rotate_left` 2023-08-14 21:52:22 +07:00
Tetro48 649dd5f31d
Added frame stepping for replays
`menu_decide` for frame step action is temporary
2023-08-14 21:46:00 +07:00
Ishaan Bhardwaj 34fcc3f659
Merge pull request #77 from Kirby703/master-1
easter egg
2023-08-13 15:49:56 -04:00
Kirby703 4caa268adc
easter egg
scholars remain divided on whether 15640 frames should also be rounded up so as to never jump by .03, or whether it should remain rounded down so as to only have one exceptional timestamp rather than two
2023-08-13 13:51:36 -04:00
Ishaan Bhardwaj a79552a6f3 Pitching BGM added and implemented in replays 2023-07-30 04:53:23 -04:00
Ishaan Bhardwaj cd90405865 Simplified Big A2 code 2023-07-27 06:00:48 -04:00
Ishaan Bhardwaj e69659b2ad Changed the order of the image extensions list
To avoid Funny Stuff
2023-07-26 05:20:55 -04:00
Ishaan Bhardwaj d90e382037
Merge pull request #76 from infinifen/survival-2020-math-fix
Fix a typo causing crashes in Survival 2020 level 1500+
2023-07-22 11:29:39 -04:00
infinifen ba6f5bb837 Fix a typo causing crashes in Survival 2020 level 1500+ 2023-07-22 13:21:21 +02:00
Ishaan Bhardwaj 39e9dc3303 Fixed pressing F8 twice at the title screen 2023-07-21 22:55:00 -04:00
Ishaan Bhardwaj a1f0dfd9f2 Hotfix: Key config screen draws the correct background 2023-07-16 18:40:10 -04:00
Ishaan Bhardwaj 2a21484137 Bump version to v0.3.4 2023-07-16 02:02:55 -04:00
Ishaan Bhardwaj 50410958f0 Re-add clamp for backgrounds beyond the limit 2023-07-16 01:54:20 -04:00
Ishaan Bhardwaj 6fb583e463 Typo fix 2023-07-16 01:52:02 -04:00
Ishaan Bhardwaj 91c8dc3dcc Bump version to v0.3.3.3 2023-07-16 01:50:42 -04:00
Ishaan Bhardwaj 2166a3c6d8 Added support for backgrounds that are not 1280x960 2023-07-16 01:49:26 -04:00
Ishaan Bhardwaj 1556b247fe Style fixes for last pull request 2023-07-16 01:06:06 -04:00
Ishaan Bhardwaj 23d9feb357
Merge pull request #74 from aur9ra/add-video-background-support
Add video background support
2023-07-16 00:48:35 -04:00
Ishaan Bhardwaj c693871621 Added error handling in the case of a corrupt replay 2023-07-16 00:46:45 -04:00
aur9ra 2ba3611c56 Added support for video backgrounds 2023-07-15 21:28:03 -07:00
aur9ra 602e7105ab Merge branch 'master' into add-video-background-support 2023-07-14 23:23:49 -07:00
Ishaan Bhardwaj 7199aa7ef6 BGM playing changes and bugfixes 2023-07-15 02:18:43 -04:00
Ishaan Bhardwaj a972c31d9a
Merge pull request #73 from aur9ra/feat-show-invis-in-replay-option
show invis in replay
2023-07-15 01:59:07 -04:00
aur9ra 02f314997d Removed unnecessary change 2023-07-14 22:55:10 -07:00
aur9ra 4769daedf4 Added show invis support to replays. 2023-07-14 22:50:16 -07:00
aur9ra 4478c07acf First commit, WIP 2023-07-14 17:54:35 -07:00
Ishaan Bhardwaj 52d4aeb3d0 Merge branch 'Tetro48-replay-qol' 2023-07-10 20:51:02 -04:00
Ishaan Bhardwaj 91279c9f38 Merge branch 'replay-qol' of https://github.com/Tetro48/cambridge into Tetro48-replay-qol 2023-07-10 20:50:44 -04:00
Ishaan Bhardwaj 0572803627 Fixed a slight indentation error 2023-07-09 22:35:07 -04:00
Tetro48 1fef7b4880
Added replay fast-forwarding 2023-07-10 08:58:09 +07:00
Ishaan Bhardwaj e09b044de4
Merge pull request #71 from Kirby703/patch-13
fix lategame levelling bug
2023-07-09 20:45:35 -04:00
Kirby703 7d6f783c40
fix lategame levelling bug 2023-07-09 20:06:27 -04:00
Ishaan Bhardwaj 9d365f61a7
Merge pull request #70 from Kirby703/patch-12
fix duplicate cool at 2000
2023-07-09 15:44:04 -04:00
Kirby703 082697c3cd
fix duplicate cool at 2000
now you have to survive the roll for gm! terrifying
2023-07-09 15:41:19 -04:00
Ishaan Bhardwaj 788aa11470 Bump version to v0.3.3.2 2023-07-07 18:16:34 -04:00
Ishaan Bhardwaj a303e82b90 Merge branch 'master' of https://github.com/millabasset/cambridge 2023-07-07 18:14:20 -04:00
Ishaan Bhardwaj b06d03c4e6 Fix bravo detection 2023-07-07 18:14:17 -04:00
Ishaan Bhardwaj a6b8abff6d
Merge pull request #69 from Kirby703/patch-11
hotfix cool logic
2023-07-07 17:19:24 -04:00
Kirby703 bdc317c3c5
hotfix cool logic 2023-07-07 17:10:24 -04:00
Ishaan Bhardwaj 71c9147a2c
Merge pull request #68 from Kirby703/patch-10
re-add 180s and IRS wallkicks after inheritance change
2023-07-04 02:38:52 -04:00
Kirby703 79d706a415
re-add 180s and IRS wallkicks after inheritance change
fixes results of 323c457809
2023-07-04 02:27:04 -04:00
Ishaan Bhardwaj 5fa144f146 Fix Marathon 2020 section cool highlighting 2023-07-02 19:47:39 -04:00
Ishaan Bhardwaj 244e67074d Bump version to v0.3.3.1 2023-07-02 19:13:13 -04:00
Ishaan Bhardwaj 4b456cf49c Removed xcf fonts 2023-07-02 18:20:56 -04:00
Ishaan Bhardwaj 9a67a6ce03 8x11 font by MattMayuga with more characters 2023-07-02 18:07:40 -04:00
Ishaan Bhardwaj df19129228 Update main.lua 2023-07-01 23:30:36 -04:00
--global 80de771d2a Elaborate on TARGET_FPS 2023-07-01 23:27:10 -04:00
--global 7c32273971 Alias Lua random functions to Love2D's 2023-07-01 23:15:14 -04:00
--global 9d5dbb4674 Bump version to v0.3.3 2023-07-01 22:34:34 -04:00
Ishaan Bhardwaj 8d7ccae2bc
README: fix Cambridge logo link 2023-07-01 22:25:50 -04:00
Ishaan Bhardwaj 1e06a1ce8a
Merge pull request #67 from MillaBasset/features/backgrounds
Slight revamp on BG image handling
2023-07-01 22:22:50 -04:00
Ishaan Bhardwaj d24fff5bdc
Merge pull request #65 from nightmareci/master
Create unified batch file for running the game from the source directory on Windows and update README.md
2023-07-01 22:22:38 -04:00
Ishaan Bhardwaj e34005093c
Merge pull request #64 from hebo-MAI/master
fix the bug hanging up when starting M-roll
2023-07-01 22:22:04 -04:00
Ishaan Bhardwaj 3dc8b1214b
Merge pull request #63 from Kirby703/patch-9
fix line clear delay
2023-07-01 22:21:45 -04:00
Ishaan Bhardwaj 5d2da1b4fb
Merge pull request #62 from Tetro48/replay-qol
New replay file naming and fast replay saving.
2023-07-01 22:21:30 -04:00
Ishaan Bhardwaj f786bda9dd
Merge pull request #59 from Tetro48/fixes
Replay tunings fix
2023-07-01 22:21:10 -04:00
Ishaan Bhardwaj 3f789210a6
Merge pull request #56 from Kirby703/patch-8
added cool+regret colors to splits
2023-07-01 22:20:52 -04:00
Ishaan Bhardwaj a7e7ac43a6
Merge pull request #55 from Kirby703/patch-7
fixes a3 regret grading
2023-07-01 22:20:43 -04:00
Ishaan Bhardwaj 5dc72037ec
Merge pull request #54 from Kirby703/patch-6
fixed 2s rule for cools
2023-07-01 22:20:30 -04:00
Oshisaure e5cb69df43 Slight revamp on BG image handling
- The game can now load more than 20 backgrounds by putting them in /res/backgrounds in the save directory
- If a gamemode tries to set its background to an ID higher than the max it will be clamped down to the last background loaded
2023-07-01 01:56:51 +01:00
Oshisaure 3e68af6a5b
Merge pull request #66 from MillaBasset/features/pausing
Added counter for amount of pauses used
2023-06-24 20:35:17 +01:00
Oshisaure 8e6a760fe7 Added counter for amount of pauses used
* Pause count is saved in replays and shown when viewing replay
* Old replays display ?? pauses
* Removed suspend on lose focus
2023-06-24 15:46:38 +01:00
Joe Zeng a4b7a41a15 Changed the Phantom Mania non-N requirement back to automatic GM at 999.
(Only N should have the 31-tetris rule.)
2023-04-11 12:19:38 -04:00
nightmareci aa9e03506b Create unified batch file for running the game from the source directory on Windows and update README.md 2023-02-13 09:35:28 -08:00
hebo-MAI 40ac08c7e5
fix the bug hanging up when starting M-roll 2023-01-09 00:12:00 +09:00
Joe Zeng 323c457809 Reorganized the ruleset names and added ARS-X.
Also, the ruleset inheritance was a little wonky, so I changed that too.
In particular, I made SRS-X always spawn in-frame since that was always
supposed to be how it worked.
2022-10-24 20:09:08 -04:00
Joe Zeng decc1f563f
Changed cool/regret cutoffs.
They're all the same past 500 now - I've been meaning to tweak that for quite some time now.
2022-09-28 00:18:44 -04:00
Kirby703 63823ed4b1
fix line clear delay 2022-06-14 00:28:27 -04:00
Tetro48 d7c83b0bc7 New replay file naming and *fast replay saving.
*fast because lower CPU and IO use. No longer O(n²).
2022-05-16 19:53:31 +07:00
nightmareci e5892c0fae Rename shell scripts and implement better frame timing 2022-04-28 11:47:31 -07:00
--global 23a8c400ba Revert "made the experience feel closer to arcade stackers"
Happy April Fools!
This reverts commit bfbba75f17.
2022-04-01 18:43:35 -04:00
--global bfbba75f17 made the experience feel closer to arcade stackers 2022-03-31 23:27:22 -04:00
--global 27e699841e Fixed a graphical issue in Survival A2 when getting torikanned 2022-03-31 23:00:39 -04:00
--global fac8c6584e Added batch scripts to start the game on Windows 2022-03-10 22:36:21 -05:00
Tetro48 d868e8b803 Replay tunings fix 2022-03-09 10:05:06 +07:00
Oshisaure 9e447d51a7
Merge pull request #57 from jjdelvalle/master
Include complete path when printing screenshot info
2022-03-03 19:29:48 +00:00
JDV 4dfa234bc3 Include complete path when printing screenshot info 2022-03-03 20:27:41 +01:00
Kirby703 47863175a3
added cool+regret colors to splits 2022-02-10 01:09:21 -05:00
Kirby703 8730261a78
fixes a3 regret grading
getting a cool and a regret in the same split displays as yellow
2022-02-10 00:40:25 -05:00
Kirby703 703ce66c42
fix 2s rule for cools 2022-02-09 23:48:09 -05:00
Ishaan Bhardwaj 92d67968f5 Tiny UI feature added to the title screen.
If you load a custom block skin, the title screen will use your skin to draw the logo.
2022-02-07 20:39:26 -05:00
Ishaan Bhardwaj d68bd13d2a LOVE 11.3 notice
Reminder that Windows is unaffected by this, because Windows releases come bundled with the correct version, and the bleeding edge source includes the correct version of LOVE for Windows
2022-01-28 22:22:05 -05:00
Ishaan Bhardwaj a84335646d Fix two bugs with Marathon A3 grading
S4 now correctly has 3 internal grades instead of 4
You can get a green-line GM
2022-01-28 20:51:25 -05:00
Ishaan Bhardwaj d46973f12d Fixed color scheme setting not applying to active piece 2021-12-18 21:30:19 -05:00
Ishaan Bhardwaj d4360b3662 Fixed the replay system's interaction with secret inputs 2021-12-09 23:00:20 -05:00
Ishaan Bhardwaj 06225bd35a Fixed an issue where replays played in the menu could save a duplicate copy 2021-12-09 22:21:48 -05:00
Ishaan Bhardwaj e68238cbce Fixed disabling saving replays 2021-12-09 22:00:13 -05:00
Ishaan Bhardwaj 83e197b5d6 Slight RPC change to the selection menus 2021-12-09 21:51:41 -05:00
Ishaan Bhardwaj 1c0b73987d Rearrange sliders on the game settings menu 2021-12-09 21:48:39 -05:00
Ishaan Bhardwaj afe6a43dab Rearrange game settings, add toggle for replay saving 2021-12-09 21:44:18 -05:00
Ishaan Bhardwaj 47a5a53e23 Fixed sorting replays in the replay select
In addition, minor change to the default text that shows up when the game is paused
2021-12-09 18:18:23 -05:00
Ishaan Bhardwaj b9ae08051a Fixed BGM not resetting after a replay 2021-12-08 21:56:31 -05:00
Ishaan Bhardwaj d7f4aa2007 Reverted a mode select change 2021-12-08 21:56:17 -05:00
Ishaan Bhardwaj ca85107063 Replace replay select title graphic with text 2021-12-08 21:37:34 -05:00
Ishaan Bhardwaj fdcec19d56 Bump version to v0.3.1 + re-add snow easter egg 2021-12-08 21:30:09 -05:00
Ishaan Bhardwaj 89c7205347 Replay system v3 + `love.math.random` migration 2021-12-08 21:23:00 -05:00
Ishaan Bhardwaj 9b41e56135 Replay system v2 2021-12-08 20:19:46 -05:00
Ishaan Bhardwaj 710f658540
Merge pull request #48 from BoatsandJoes/replays
Added replays
2021-12-07 22:39:08 -05:00
BoatsandJoes 332e3869de Replay menu no longer crashes if level or timer is nil. 2021-12-06 22:38:07 -06:00
BoatsandJoes febd1de0ef Replays are now fully functional. 2021-12-05 22:17:44 -06:00
BoatsandJoes 81ab7cd4de Replays now replay inputs properly, and replay list has fast scroll. 2021-12-05 21:16:13 -06:00
BoatsandJoes a5750e4959 Replays list is now sorted, and replays are smaller. 2021-12-05 15:41:51 -06:00
BoatsandJoes 59c7834c9a Fixed replay deserialization. 2021-12-05 00:18:19 -06:00
BoatsandJoes 71ada76a00 Started work on replay select menu. 2021-12-04 23:37:51 -06:00
BoatsandJoes 6c4551ebef Added replay saving. 2021-12-04 20:35:15 -06:00
Ishaan Bhardwaj 9fc7e4b1eb
Merge pull request #47 from BoatsandJoes/game-over-animation
Game over fadeout easing function now accelerates
2021-12-02 19:27:32 -05:00
BoatsandJoes 9e59c158b2 Line clear easing is now quadratic for all line clear delays. 2021-12-02 16:22:29 -06:00
BoatsandJoes e464307625 Game over animation is longer, and reveals stack once it's over. 2021-12-02 15:49:27 -06:00
BoatsandJoes 888312c578 Game over fadeout easing function now accelerates. 2021-12-02 13:42:51 -06:00
Ishaan Bhardwaj a838294435
Merge pull request #46 from BoatsandJoes/line-clear-animation
Added new default line clear animations using easing functions.
2021-12-02 13:57:19 -05:00
BoatsandJoes 049806d9e2 Added a new default line clear animation using easing functions. 2021-12-02 10:59:45 -06:00
Ishaan Bhardwaj c1693524d7 Credits change 2021-11-30 20:08:52 -05:00
Ishaan Bhardwaj a063f10d33 Merge branch 'master' of https://github.com/MillaBasset/cambridge 2021-11-23 22:56:19 -05:00
Ishaan Bhardwaj 6e0b5e27c1 Rearranged the spawn SE actions 2021-11-23 22:56:11 -05:00
Joe Zeng 18e0e02c76
Removed a stupid exception to the mixing-tabs-and-spaces rule.
I apologize that it took me 2 years to think of this workaround.
2021-11-09 14:48:05 -05:00
Ishaan Bhardwaj 9381091110 Updated 3694 -> 3701 in other places 2021-11-03 17:34:34 -04:00
Ishaan Bhardwaj deb69fe28d
Merge pull request #43 from Kirby703/patch-5
tap roll 3694 -> 3701 frames
2021-11-03 17:32:43 -04:00
Kirby703 3085b765e5
fix roll 3694 -> 3701 frames 2021-11-03 17:31:04 -04:00
hailey 412405c1a1 celebrate!!! 2021-10-22 15:04:28 +10:00
Ishaan Bhardwaj 7495c4ad04 Revert "Separate in-game bindings from menu bindings"
This reverts commit 0fce4b632f.
This commit caused issue #41. Will resolve ASAP.
2021-10-21 20:52:42 -04:00
Ishaan Bhardwaj 0fce4b632f Separate in-game bindings from menu bindings
Also preemptive version bump
2021-10-19 18:35:32 -04:00
Ishaan Bhardwaj aa56248e34 Add an FPS counter 2021-10-18 23:27:54 -04:00
nightmareci 0a2e16ab2c Merge branch 'master' of https://github.com/SashLilac/cambridge 2021-10-17 08:52:15 -07:00
nightmareci 34d53c82cb Preliminary work to change from DiscordRPC to Discord GameSDK 2021-10-17 08:51:34 -07:00
Ishaan Bhardwaj 75ee07a04d
Merge pull request #35 from MarkGamed7794/origin/sound-effect-rework
Add some new behavior to sound effects
2021-10-17 11:42:45 -04:00
Ishaan Bhardwaj d2d710ead6 Bump version to v0.3 + title screen change!!! 2021-10-17 00:34:30 -04:00
Ishaan Bhardwaj 6f4adf5aad Refactored component API for rulesets with an arbitary...
...number of pieces (fixes #31)
2021-10-16 20:35:47 -04:00
Ishaan Bhardwaj 42f872a557 Oops, indenting fix in main.lua 2021-10-16 19:10:33 -04:00
Ishaan Bhardwaj a30791afc3 Fixed F2 shortcut not resetting changed settings 2021-10-16 19:08:01 -04:00
Ishaan Bhardwaj 8bd8c0eede Relocated call of `love.graphics.setDefaultFilter` to `love.load` 2021-10-16 15:15:44 -04:00
Ishaan Bhardwaj f52a5eaee5 Fixes an issue where IHS ignores buffer lock setting 2021-10-12 22:46:50 -04:00
Ishaan Bhardwaj e68a9b6f07
Merge pull request #38 from Kirby703/patch-4
removes green/orange line to match tap death
2021-10-09 21:27:07 -04:00
Kirby703 ff5b04bb97
removes green/orange line to match tap death 2021-10-09 16:52:26 -04:00
Ishaan Bhardwaj 8dbb75cbef Basic SOCD handling 2021-10-08 20:07:28 -04:00
Ishaan Bhardwaj bc54bc57b6 Changed Display Gamemode to Debug Info
Cambridge version will display at all times if on
2021-10-08 20:06:36 -04:00
Ishaan Bhardwaj 9611fc31bf update version to wip 2021-10-08 19:07:06 -04:00
Ishaan Bhardwaj a5fed31f4e Moved the LCA draw call to after the piece draw call 2021-10-02 20:14:03 -04:00
Ishaan Bhardwaj 625d4f80af Fixed an obscure bug with the menu DAS 2021-09-30 23:07:03 -04:00
Ishaan Bhardwaj 173b3ddbc9
Merge pull request #37 from terpyderp/master
fixed version color change bug
2021-09-29 19:43:49 -04:00
terpyderp 0f96bf7db0 fixed version color change bug
The version number will no longer change color on game over. ( Or whenever you use love.graphics.setColor(). )
2021-09-29 18:22:56 -05:00
Ishaan Bhardwaj 3770deca55 Fixed version number drawing in the wrong place 2021-09-29 18:12:02 -04:00
Ishaan Bhardwaj 4e297a8030 Version number now displays at bottom right always 2021-09-28 19:13:16 -04:00
Ishaan Bhardwaj 1336ea00e4 Snow RPC now used 2021-09-26 23:12:05 -04:00
hailey b8d43e38b7 2 cool rpc changes! 2021-09-27 12:26:52 +10:00
hailey 6b595d2146 Merge branch 'master' of https://github.com/MillaBasset/cambridge 2021-09-27 12:18:31 +10:00
hailey 1082a2903a small image text now shows version! 2021-09-27 12:09:03 +10:00
hailey 3480734a44 just a few more rpc strings 2021-09-27 11:55:42 +10:00
Ishaan Bhardwaj 82966e99c3 Added two more utility functions 2021-09-26 20:12:38 -04:00
Ishaan Bhardwaj d558faeef0 Fixed RPC details for some scenes 2021-09-26 15:30:37 -04:00
Ishaan Bhardwaj 8dc59a562e Revert "new easter egg, why not"
This easter egg doesn't really have a place within the game,
and is better left as a community goodie.
2021-09-26 10:38:48 -04:00
Ishaan Bhardwaj 2fa9ba40fa hey hailey don't do that please 2021-09-26 10:26:35 -04:00
hailey a7ee1d7861 new easter egg, why not 2021-09-26 14:30:12 +10:00
hailey bf6c61927e Removed print() that occured every game scene update 2021-09-26 14:09:43 +10:00
hailey 817ffd5c13 RPC image updates depending on ingame background now! 2021-09-26 14:02:35 +10:00
Ishaan Bhardwaj 50f6010ed1 Credits scene now has its own special RPC 2021-09-25 22:46:48 -04:00
Ishaan Bhardwaj ef966d8190 Merge branch 'master' of https://github.com/MillaBasset/cambridge 2021-09-25 22:40:18 -04:00
Ishaan Bhardwaj faef1ddc8f Added a long lost name to the credits scene 2021-09-25 22:38:00 -04:00
hailey ea38ebb89d more rpc stuff! 2021-09-26 09:51:43 +10:00
hailey b28759e0c8 hi again 2021-09-26 09:33:04 +10:00
Ishaan Bhardwaj 2fc763ae5d
Bump version to v0.3-beta7 2021-09-21 23:44:37 -04:00
MarkGamed7794 cf8ba16eb1 Remove the print statement
and also fix a logic issue
2021-09-16 21:56:35 -04:00
MarkGamed7794 71ecd51cde Catch up to main, and push changes to sfx 2021-09-12 02:59:05 -04:00
139 changed files with 13000 additions and 392 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

View File

@ -57,13 +57,13 @@ Coding conventions
Use tabs to indent, spaces to align.
* Specifically, spaces should not appear at the beginning of a line, and tabs should not appear _except_ at the beginning of a line.
* The sole exception is in a multiline `if` statement; the initial `if` should have four spaces before it to align it with an `elseif` on the next line. For example:
* If you're aligning multiline if-statements, the initial "if", "elseif" or "else" should be flush left with the indentation level, with spaces padding the gap to the next word as necessary. For example:
```lua
---- 4 spaces
if self.level < 900 then return 12
elseif self.level < 1200 then return 8
else return 6 end
if self.level < 900 then return 12
elseif self.level < 1200 then return 8
else return 6
end
```
Comments at the end of lines of code must be one line long. Multi-line comments must appear in their own block.

View File

@ -5,7 +5,7 @@ Cambridge
Welcome to Cambridge, the next open-source falling-block game engine!
The project is written and maintained exclusively by [Milla](https://github.com/MillaBasset), [joezeng](https://github.com/joezeng) and [Oshisaure](https://github.com/oshisaure)!
The project is written and maintained exclusively by [Milla](https://github.com/MillaBasset), [joezeng](https://github.com/joezeng) and [Oshisaure](https://github.com/oshisaure)!
The Discord server has been reopened! https://discord.gg/AADZUmgsph
@ -16,23 +16,23 @@ Playing the game
### Windows
You do not need LÖVE on Windows, as it comes bundled with the program.
You do not need LÖVE on Windows, as it comes bundled with the program.
#### Stable release
To get the stable release, simply download either `cambridge-win32.zip` (32-bit) or `cambridge-windows.zip` (64-bit) in the [latest release](https://github.com/MillaBasset/cambridge/releases/latest).
To get the stable release, simply download either `cambridge-win32.zip` (32-bit) or `cambridge-windows.zip` (64-bit) in the [latest release](https://github.com/MillaBasset/cambridge/releases/latest).
All assets needed are bundled with the executable.
#### Bleeding edge
If you want the bleeding edge version, download [this](https://github.com/MillaBasset/cambridge/archive/master.zip).
If you want the bleeding edge version, download [this](https://github.com/MillaBasset/cambridge/archive/master.zip). Extract the ZIP to a folder of your choosing.
Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command:
If you're on Windows, you can double-click `start.bat` to run the game. If that doesn't work, open a Command Prompt where you extracted Cambridge and run:
dist\windows\love.exe .
Alternatively, if you're on a 32-bit system, run this instead:
If that doesn't work, run this instead, still using Command Prompt where you extracted Cambridge:
dist\win32\love.exe .
@ -42,7 +42,7 @@ Then, check the mod pack section at the bottom of this page.
### macOS, Linux
If you haven't already, install `love` with your favourite package manager (Homebrew on macOS, your system's default on Linux). **Make sure you're using LÖVE 11, because it won't work with earlier versions!**
If you haven't already, install `love` with your favourite package manager (Homebrew on macOS, your system's default on Linux). **Make sure you're using LÖVE 11.3, because it won't work with earlier or later versions!**
#### Downloading a release
@ -102,10 +102,9 @@ Other Notable Games
- [Tetra Online](https://github.com/Juan-Cartes/Tetra-Offline) by Mine
- [Techmino](https://discord.gg/6Yuww44tq8) by MrZ
- [Example Block Game](https://github.com/oshisaure/example-block-game) by Oshisaure
- [TETR.IO](https://tetr.io) by osk
- [Master of Blocks](https://discord.gg/72FZ49mjWh) by Phoenix Flare
- [Spirit Drop](https://rayblastgames.com/spiritdrop.php) by RayRay26
- [Puzzle Trial](https://kagamine-rin.itch.io/puzzle-trial) by Rin
- [stackfuse](https://github.com/sinefuse/stackfuse) by sinefuse
![Cambridge Logo](https://cdn.discordapp.com/attachments/625496179433668635/763363717730664458/Icon_2.png)
![Cambridge Logo](https://cdn.discordapp.com/attachments/827186653772644452/1077674343544393820/Icon_2.png)

View File

@ -60,6 +60,9 @@ function formatTime(frames)
min = math.floor(frames/3600)
sec = math.floor(frames/60) % 60
hund = math.floor(frames/.6) % 100
if frames == 15641 then
hund = math.ceil(frames/.6) % 100
end
str = string.format("%02d:%02d.%02d", min, sec, hund)
return str
end
@ -97,6 +100,47 @@ function table.contains(table, element)
return false
end
function table.keys(table)
local target = {}
for key in pairs(table) do
target[#target+1] = key
end
return target
end
function table.numkeys(table)
local count = 0
for k in pairs(table) do
count = count + 1
end
return count
end
function equals(x, y)
if type(x) ~= "table" or type(y) ~= "table" then
return x == y
else
for k in pairs(x) do
if not equals(x[k], y[k]) then return false end
end
for k in pairs(y) do
if not equals(x[k], y[k]) then return false end
end
return true
end
end
function table.equalvalues(t1, t2)
if table.numkeys(t1) ~= table.numkeys(t2) then
return false
else
for _, v in pairs(t2) do
if not table.contains(t1, v) then return false end
end
return true
end
end
function clamp(x, min, max)
if max < min then
min, max = max, min

1048
libs/discordGameSDK.lua Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
## Discord Game SDK
> The SDK is currently under extensive development and is subject to change. Suggestions
> about the current API are welcome.
### Setup
- Create an application on the Discord [developer site](https://discordapp.com/developers/applications/me).
- Set a redirect URL. If you don't have one right now, just use <http://127.0.0.1>.
- Enable Rich Presence for the application. This enables whitelist access for the SDK.
- When you are ready to test with more people, add them to the whitelist.
- Copy the **Client ID**.
- Use this `CLIENT_ID` when initializing the SDK.

View File

@ -0,0 +1,646 @@
#ifndef _DISCORD_GAME_SDK_H_
#define _DISCORD_GAME_SDK_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <string.h>
#ifndef __cplusplus
#include <stdbool.h>
#endif
#define DISCORD_VERSION 2
#define DISCORD_APPLICATION_MANAGER_VERSION 1
#define DISCORD_USER_MANAGER_VERSION 1
#define DISCORD_IMAGE_MANAGER_VERSION 1
#define DISCORD_ACTIVITY_MANAGER_VERSION 1
#define DISCORD_RELATIONSHIP_MANAGER_VERSION 1
#define DISCORD_LOBBY_MANAGER_VERSION 1
#define DISCORD_NETWORK_MANAGER_VERSION 1
#define DISCORD_OVERLAY_MANAGER_VERSION 1
#define DISCORD_STORAGE_MANAGER_VERSION 1
#define DISCORD_STORE_MANAGER_VERSION 1
#define DISCORD_VOICE_MANAGER_VERSION 1
#define DISCORD_ACHIEVEMENT_MANAGER_VERSION 1
enum EDiscordResult {
DiscordResult_Ok = 0,
DiscordResult_ServiceUnavailable = 1,
DiscordResult_InvalidVersion = 2,
DiscordResult_LockFailed = 3,
DiscordResult_InternalError = 4,
DiscordResult_InvalidPayload = 5,
DiscordResult_InvalidCommand = 6,
DiscordResult_InvalidPermissions = 7,
DiscordResult_NotFetched = 8,
DiscordResult_NotFound = 9,
DiscordResult_Conflict = 10,
DiscordResult_InvalidSecret = 11,
DiscordResult_InvalidJoinSecret = 12,
DiscordResult_NoEligibleActivity = 13,
DiscordResult_InvalidInvite = 14,
DiscordResult_NotAuthenticated = 15,
DiscordResult_InvalidAccessToken = 16,
DiscordResult_ApplicationMismatch = 17,
DiscordResult_InvalidDataUrl = 18,
DiscordResult_InvalidBase64 = 19,
DiscordResult_NotFiltered = 20,
DiscordResult_LobbyFull = 21,
DiscordResult_InvalidLobbySecret = 22,
DiscordResult_InvalidFilename = 23,
DiscordResult_InvalidFileSize = 24,
DiscordResult_InvalidEntitlement = 25,
DiscordResult_NotInstalled = 26,
DiscordResult_NotRunning = 27,
DiscordResult_InsufficientBuffer = 28,
DiscordResult_PurchaseCanceled = 29,
DiscordResult_InvalidGuild = 30,
DiscordResult_InvalidEvent = 31,
DiscordResult_InvalidChannel = 32,
DiscordResult_InvalidOrigin = 33,
DiscordResult_RateLimited = 34,
DiscordResult_OAuth2Error = 35,
DiscordResult_SelectChannelTimeout = 36,
DiscordResult_GetGuildTimeout = 37,
DiscordResult_SelectVoiceForceRequired = 38,
DiscordResult_CaptureShortcutAlreadyListening = 39,
DiscordResult_UnauthorizedForAchievement = 40,
DiscordResult_InvalidGiftCode = 41,
DiscordResult_PurchaseError = 42,
DiscordResult_TransactionAborted = 43,
};
enum EDiscordCreateFlags {
DiscordCreateFlags_Default = 0,
DiscordCreateFlags_NoRequireDiscord = 1,
};
enum EDiscordLogLevel {
DiscordLogLevel_Error = 1,
DiscordLogLevel_Warn,
DiscordLogLevel_Info,
DiscordLogLevel_Debug,
};
enum EDiscordUserFlag {
DiscordUserFlag_Partner = 2,
DiscordUserFlag_HypeSquadEvents = 4,
DiscordUserFlag_HypeSquadHouse1 = 64,
DiscordUserFlag_HypeSquadHouse2 = 128,
DiscordUserFlag_HypeSquadHouse3 = 256,
};
enum EDiscordPremiumType {
DiscordPremiumType_None = 0,
DiscordPremiumType_Tier1 = 1,
DiscordPremiumType_Tier2 = 2,
};
enum EDiscordImageType {
DiscordImageType_User,
};
enum EDiscordActivityType {
DiscordActivityType_Playing,
DiscordActivityType_Streaming,
DiscordActivityType_Listening,
DiscordActivityType_Watching,
};
enum EDiscordActivityActionType {
DiscordActivityActionType_Join = 1,
DiscordActivityActionType_Spectate,
};
enum EDiscordActivityJoinRequestReply {
DiscordActivityJoinRequestReply_No,
DiscordActivityJoinRequestReply_Yes,
DiscordActivityJoinRequestReply_Ignore,
};
enum EDiscordStatus {
DiscordStatus_Offline = 0,
DiscordStatus_Online = 1,
DiscordStatus_Idle = 2,
DiscordStatus_DoNotDisturb = 3,
};
enum EDiscordRelationshipType {
DiscordRelationshipType_None,
DiscordRelationshipType_Friend,
DiscordRelationshipType_Blocked,
DiscordRelationshipType_PendingIncoming,
DiscordRelationshipType_PendingOutgoing,
DiscordRelationshipType_Implicit,
};
enum EDiscordLobbyType {
DiscordLobbyType_Private = 1,
DiscordLobbyType_Public,
};
enum EDiscordLobbySearchComparison {
DiscordLobbySearchComparison_LessThanOrEqual = -2,
DiscordLobbySearchComparison_LessThan,
DiscordLobbySearchComparison_Equal,
DiscordLobbySearchComparison_GreaterThan,
DiscordLobbySearchComparison_GreaterThanOrEqual,
DiscordLobbySearchComparison_NotEqual,
};
enum EDiscordLobbySearchCast {
DiscordLobbySearchCast_String = 1,
DiscordLobbySearchCast_Number,
};
enum EDiscordLobbySearchDistance {
DiscordLobbySearchDistance_Local,
DiscordLobbySearchDistance_Default,
DiscordLobbySearchDistance_Extended,
DiscordLobbySearchDistance_Global,
};
enum EDiscordEntitlementType {
DiscordEntitlementType_Purchase = 1,
DiscordEntitlementType_PremiumSubscription,
DiscordEntitlementType_DeveloperGift,
DiscordEntitlementType_TestModePurchase,
DiscordEntitlementType_FreePurchase,
DiscordEntitlementType_UserGift,
DiscordEntitlementType_PremiumPurchase,
};
enum EDiscordSkuType {
DiscordSkuType_Application = 1,
DiscordSkuType_DLC,
DiscordSkuType_Consumable,
DiscordSkuType_Bundle,
};
enum EDiscordInputModeType {
DiscordInputModeType_VoiceActivity = 0,
DiscordInputModeType_PushToTalk,
};
typedef int64_t DiscordClientId;
typedef int32_t DiscordVersion;
typedef int64_t DiscordSnowflake;
typedef int64_t DiscordTimestamp;
typedef DiscordSnowflake DiscordUserId;
typedef char DiscordLocale[128];
typedef char DiscordBranch[4096];
typedef DiscordSnowflake DiscordLobbyId;
typedef char DiscordLobbySecret[128];
typedef char DiscordMetadataKey[256];
typedef char DiscordMetadataValue[4096];
typedef uint64_t DiscordNetworkPeerId;
typedef uint8_t DiscordNetworkChannelId;
typedef char DiscordPath[4096];
typedef char DiscordDateTime[64];
struct DiscordUser {
DiscordUserId id;
char username[256];
char discriminator[8];
char avatar[128];
bool bot;
};
struct DiscordOAuth2Token {
char access_token[128];
char scopes[1024];
DiscordTimestamp expires;
};
struct DiscordImageHandle {
enum EDiscordImageType type;
int64_t id;
uint32_t size;
};
struct DiscordImageDimensions {
uint32_t width;
uint32_t height;
};
struct DiscordActivityTimestamps {
DiscordTimestamp start;
DiscordTimestamp end;
};
struct DiscordActivityAssets {
char large_image[128];
char large_text[128];
char small_image[128];
char small_text[128];
};
struct DiscordPartySize {
int32_t current_size;
int32_t max_size;
};
struct DiscordActivityParty {
char id[128];
struct DiscordPartySize size;
};
struct DiscordActivitySecrets {
char match[128];
char join[128];
char spectate[128];
};
struct DiscordActivity {
enum EDiscordActivityType type;
int64_t application_id;
char name[128];
char state[128];
char details[128];
struct DiscordActivityTimestamps timestamps;
struct DiscordActivityAssets assets;
struct DiscordActivityParty party;
struct DiscordActivitySecrets secrets;
bool instance;
};
struct DiscordPresence {
enum EDiscordStatus status;
struct DiscordActivity activity;
};
struct DiscordRelationship {
enum EDiscordRelationshipType type;
struct DiscordUser user;
struct DiscordPresence presence;
};
struct DiscordLobby {
DiscordLobbyId id;
enum EDiscordLobbyType type;
DiscordUserId owner_id;
DiscordLobbySecret secret;
uint32_t capacity;
bool locked;
};
struct DiscordFileStat {
char filename[260];
uint64_t size;
uint64_t last_modified;
};
struct DiscordEntitlement {
DiscordSnowflake id;
enum EDiscordEntitlementType type;
DiscordSnowflake sku_id;
};
struct DiscordSkuPrice {
uint32_t amount;
char currency[16];
};
struct DiscordSku {
DiscordSnowflake id;
enum EDiscordSkuType type;
char name[256];
struct DiscordSkuPrice price;
};
struct DiscordInputMode {
enum EDiscordInputModeType type;
char shortcut[256];
};
struct DiscordUserAchievement {
DiscordSnowflake user_id;
DiscordSnowflake achievement_id;
uint8_t percent_complete;
DiscordDateTime unlocked_at;
};
struct IDiscordLobbyTransaction {
enum EDiscordResult (*set_type)(struct IDiscordLobbyTransaction* lobby_transaction, enum EDiscordLobbyType type);
enum EDiscordResult (*set_owner)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordUserId owner_id);
enum EDiscordResult (*set_capacity)(struct IDiscordLobbyTransaction* lobby_transaction, uint32_t capacity);
enum EDiscordResult (*set_metadata)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordMetadataKey key, DiscordMetadataValue value);
enum EDiscordResult (*delete_metadata)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordMetadataKey key);
enum EDiscordResult (*set_locked)(struct IDiscordLobbyTransaction* lobby_transaction, bool locked);
};
struct IDiscordLobbyMemberTransaction {
enum EDiscordResult (*set_metadata)(struct IDiscordLobbyMemberTransaction* lobby_member_transaction, DiscordMetadataKey key, DiscordMetadataValue value);
enum EDiscordResult (*delete_metadata)(struct IDiscordLobbyMemberTransaction* lobby_member_transaction, DiscordMetadataKey key);
};
struct IDiscordLobbySearchQuery {
enum EDiscordResult (*filter)(struct IDiscordLobbySearchQuery* lobby_search_query, DiscordMetadataKey key, enum EDiscordLobbySearchComparison comparison, enum EDiscordLobbySearchCast cast, DiscordMetadataValue value);
enum EDiscordResult (*sort)(struct IDiscordLobbySearchQuery* lobby_search_query, DiscordMetadataKey key, enum EDiscordLobbySearchCast cast, DiscordMetadataValue value);
enum EDiscordResult (*limit)(struct IDiscordLobbySearchQuery* lobby_search_query, uint32_t limit);
enum EDiscordResult (*distance)(struct IDiscordLobbySearchQuery* lobby_search_query, enum EDiscordLobbySearchDistance distance);
};
typedef void* IDiscordApplicationEvents;
struct IDiscordApplicationManager {
void (*validate_or_exit)(struct IDiscordApplicationManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*get_current_locale)(struct IDiscordApplicationManager* manager, DiscordLocale* locale);
void (*get_current_branch)(struct IDiscordApplicationManager* manager, DiscordBranch* branch);
void (*get_oauth2_token)(struct IDiscordApplicationManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordOAuth2Token* oauth2_token));
void (*get_ticket)(struct IDiscordApplicationManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, const char* data));
};
struct IDiscordUserEvents {
void (*on_current_user_update)(void* event_data);
};
struct IDiscordUserManager {
enum EDiscordResult (*get_current_user)(struct IDiscordUserManager* manager, struct DiscordUser* current_user);
void (*get_user)(struct IDiscordUserManager* manager, DiscordUserId user_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordUser* user));
enum EDiscordResult (*get_current_user_premium_type)(struct IDiscordUserManager* manager, enum EDiscordPremiumType* premium_type);
enum EDiscordResult (*current_user_has_flag)(struct IDiscordUserManager* manager, enum EDiscordUserFlag flag, bool* has_flag);
};
typedef void* IDiscordImageEvents;
struct IDiscordImageManager {
void (*fetch)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, bool refresh, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordImageHandle handle_result));
enum EDiscordResult (*get_dimensions)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, struct DiscordImageDimensions* dimensions);
enum EDiscordResult (*get_data)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, uint8_t* data, uint32_t data_length);
};
struct IDiscordActivityEvents {
void (*on_activity_join)(void* event_data, const char* secret);
void (*on_activity_spectate)(void* event_data, const char* secret);
void (*on_activity_join_request)(void* event_data, struct DiscordUser* user);
void (*on_activity_invite)(void* event_data, enum EDiscordActivityActionType type, struct DiscordUser* user, struct DiscordActivity* activity);
};
struct IDiscordActivityManager {
enum EDiscordResult (*register_command)(struct IDiscordActivityManager* manager, const char* command);
enum EDiscordResult (*register_steam)(struct IDiscordActivityManager* manager, uint32_t steam_id);
void (*update_activity)(struct IDiscordActivityManager* manager, struct DiscordActivity* activity, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*clear_activity)(struct IDiscordActivityManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*send_request_reply)(struct IDiscordActivityManager* manager, DiscordUserId user_id, enum EDiscordActivityJoinRequestReply reply, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*send_invite)(struct IDiscordActivityManager* manager, DiscordUserId user_id, enum EDiscordActivityActionType type, const char* content, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*accept_invite)(struct IDiscordActivityManager* manager, DiscordUserId user_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
};
struct IDiscordRelationshipEvents {
void (*on_refresh)(void* event_data);
void (*on_relationship_update)(void* event_data, struct DiscordRelationship* relationship);
};
struct IDiscordRelationshipManager {
void (*filter)(struct IDiscordRelationshipManager* manager, void* filter_data, bool (*filter)(void* filter_data, struct DiscordRelationship* relationship));
enum EDiscordResult (*count)(struct IDiscordRelationshipManager* manager, int32_t* count);
enum EDiscordResult (*get)(struct IDiscordRelationshipManager* manager, DiscordUserId user_id, struct DiscordRelationship* relationship);
enum EDiscordResult (*get_at)(struct IDiscordRelationshipManager* manager, uint32_t index, struct DiscordRelationship* relationship);
};
struct IDiscordLobbyEvents {
void (*on_lobby_update)(void* event_data, int64_t lobby_id);
void (*on_lobby_delete)(void* event_data, int64_t lobby_id, uint32_t reason);
void (*on_member_connect)(void* event_data, int64_t lobby_id, int64_t user_id);
void (*on_member_update)(void* event_data, int64_t lobby_id, int64_t user_id);
void (*on_member_disconnect)(void* event_data, int64_t lobby_id, int64_t user_id);
void (*on_lobby_message)(void* event_data, int64_t lobby_id, int64_t user_id, uint8_t* data, uint32_t data_length);
void (*on_speaking)(void* event_data, int64_t lobby_id, int64_t user_id, bool speaking);
void (*on_network_message)(void* event_data, int64_t lobby_id, int64_t user_id, uint8_t channel_id, uint8_t* data, uint32_t data_length);
};
struct IDiscordLobbyManager {
enum EDiscordResult (*get_lobby_create_transaction)(struct IDiscordLobbyManager* manager, struct IDiscordLobbyTransaction** transaction);
enum EDiscordResult (*get_lobby_update_transaction)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct IDiscordLobbyTransaction** transaction);
enum EDiscordResult (*get_member_update_transaction)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct IDiscordLobbyMemberTransaction** transaction);
void (*create_lobby)(struct IDiscordLobbyManager* manager, struct IDiscordLobbyTransaction* transaction, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby));
void (*update_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct IDiscordLobbyTransaction* transaction, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*delete_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*connect_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordLobbySecret secret, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby));
void (*connect_lobby_with_activity_secret)(struct IDiscordLobbyManager* manager, DiscordLobbySecret activity_secret, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby));
void (*disconnect_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
enum EDiscordResult (*get_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct DiscordLobby* lobby);
enum EDiscordResult (*get_lobby_activity_secret)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordLobbySecret* secret);
enum EDiscordResult (*get_lobby_metadata_value)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordMetadataKey key, DiscordMetadataValue* value);
enum EDiscordResult (*get_lobby_metadata_key)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t index, DiscordMetadataKey* key);
enum EDiscordResult (*lobby_metadata_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t* count);
enum EDiscordResult (*member_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t* count);
enum EDiscordResult (*get_member_user_id)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t index, DiscordUserId* user_id);
enum EDiscordResult (*get_member_user)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct DiscordUser* user);
enum EDiscordResult (*get_member_metadata_value)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, DiscordMetadataKey key, DiscordMetadataValue* value);
enum EDiscordResult (*get_member_metadata_key)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, int32_t index, DiscordMetadataKey* key);
enum EDiscordResult (*member_metadata_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, int32_t* count);
void (*update_member)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct IDiscordLobbyMemberTransaction* transaction, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*send_lobby_message)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, uint8_t* data, uint32_t data_length, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
enum EDiscordResult (*get_search_query)(struct IDiscordLobbyManager* manager, struct IDiscordLobbySearchQuery** query);
void (*search)(struct IDiscordLobbyManager* manager, struct IDiscordLobbySearchQuery* query, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*lobby_count)(struct IDiscordLobbyManager* manager, int32_t* count);
enum EDiscordResult (*get_lobby_id)(struct IDiscordLobbyManager* manager, int32_t index, DiscordLobbyId* lobby_id);
void (*connect_voice)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*disconnect_voice)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
enum EDiscordResult (*connect_network)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id);
enum EDiscordResult (*disconnect_network)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id);
enum EDiscordResult (*flush_network)(struct IDiscordLobbyManager* manager);
enum EDiscordResult (*open_network_channel)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, uint8_t channel_id, bool reliable);
enum EDiscordResult (*send_network_message)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, uint8_t channel_id, uint8_t* data, uint32_t data_length);
};
struct IDiscordNetworkEvents {
void (*on_message)(void* event_data, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, uint8_t* data, uint32_t data_length);
void (*on_route_update)(void* event_data, const char* route_data);
};
struct IDiscordNetworkManager {
/**
* Get the local peer ID for this process.
*/
void (*get_peer_id)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId* peer_id);
/**
* Send pending network messages.
*/
enum EDiscordResult (*flush)(struct IDiscordNetworkManager* manager);
/**
* Open a connection to a remote peer.
*/
enum EDiscordResult (*open_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, const char* route_data);
/**
* Update the route data for a connected peer.
*/
enum EDiscordResult (*update_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, const char* route_data);
/**
* Close the connection to a remote peer.
*/
enum EDiscordResult (*close_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id);
/**
* Open a message channel to a connected peer.
*/
enum EDiscordResult (*open_channel)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, bool reliable);
/**
* Close a message channel to a connected peer.
*/
enum EDiscordResult (*close_channel)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id);
/**
* Send a message to a connected peer over an opened message channel.
*/
enum EDiscordResult (*send_message)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, uint8_t* data, uint32_t data_length);
};
struct IDiscordOverlayEvents {
void (*on_toggle)(void* event_data, bool locked);
};
struct IDiscordOverlayManager {
void (*is_enabled)(struct IDiscordOverlayManager* manager, bool* enabled);
void (*is_locked)(struct IDiscordOverlayManager* manager, bool* locked);
void (*set_locked)(struct IDiscordOverlayManager* manager, bool locked, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*open_activity_invite)(struct IDiscordOverlayManager* manager, enum EDiscordActivityActionType type, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*open_guild_invite)(struct IDiscordOverlayManager* manager, const char* code, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*open_voice_settings)(struct IDiscordOverlayManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
};
typedef void* IDiscordStorageEvents;
struct IDiscordStorageManager {
enum EDiscordResult (*read)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length, uint32_t* read);
void (*read_async)(struct IDiscordStorageManager* manager, const char* name, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, uint8_t* data, uint32_t data_length));
void (*read_async_partial)(struct IDiscordStorageManager* manager, const char* name, uint64_t offset, uint64_t length, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, uint8_t* data, uint32_t data_length));
enum EDiscordResult (*write)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length);
void (*write_async)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
enum EDiscordResult (*delete_)(struct IDiscordStorageManager* manager, const char* name);
enum EDiscordResult (*exists)(struct IDiscordStorageManager* manager, const char* name, bool* exists);
void (*count)(struct IDiscordStorageManager* manager, int32_t* count);
enum EDiscordResult (*stat)(struct IDiscordStorageManager* manager, const char* name, struct DiscordFileStat* stat);
enum EDiscordResult (*stat_at)(struct IDiscordStorageManager* manager, int32_t index, struct DiscordFileStat* stat);
enum EDiscordResult (*get_path)(struct IDiscordStorageManager* manager, DiscordPath* path);
};
struct IDiscordStoreEvents {
void (*on_entitlement_create)(void* event_data, struct DiscordEntitlement* entitlement);
void (*on_entitlement_delete)(void* event_data, struct DiscordEntitlement* entitlement);
};
struct IDiscordStoreManager {
void (*fetch_skus)(struct IDiscordStoreManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*count_skus)(struct IDiscordStoreManager* manager, int32_t* count);
enum EDiscordResult (*get_sku)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, struct DiscordSku* sku);
enum EDiscordResult (*get_sku_at)(struct IDiscordStoreManager* manager, int32_t index, struct DiscordSku* sku);
void (*fetch_entitlements)(struct IDiscordStoreManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*count_entitlements)(struct IDiscordStoreManager* manager, int32_t* count);
enum EDiscordResult (*get_entitlement)(struct IDiscordStoreManager* manager, DiscordSnowflake entitlement_id, struct DiscordEntitlement* entitlement);
enum EDiscordResult (*get_entitlement_at)(struct IDiscordStoreManager* manager, int32_t index, struct DiscordEntitlement* entitlement);
enum EDiscordResult (*has_sku_entitlement)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, bool* has_entitlement);
void (*start_purchase)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
};
struct IDiscordVoiceEvents {
void (*on_settings_update)(void* event_data);
};
struct IDiscordVoiceManager {
enum EDiscordResult (*get_input_mode)(struct IDiscordVoiceManager* manager, struct DiscordInputMode* input_mode);
void (*set_input_mode)(struct IDiscordVoiceManager* manager, struct DiscordInputMode input_mode, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
enum EDiscordResult (*is_self_mute)(struct IDiscordVoiceManager* manager, bool* mute);
enum EDiscordResult (*set_self_mute)(struct IDiscordVoiceManager* manager, bool mute);
enum EDiscordResult (*is_self_deaf)(struct IDiscordVoiceManager* manager, bool* deaf);
enum EDiscordResult (*set_self_deaf)(struct IDiscordVoiceManager* manager, bool deaf);
enum EDiscordResult (*is_local_mute)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, bool* mute);
enum EDiscordResult (*set_local_mute)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, bool mute);
enum EDiscordResult (*get_local_volume)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, uint8_t* volume);
enum EDiscordResult (*set_local_volume)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, uint8_t volume);
};
struct IDiscordAchievementEvents {
void (*on_user_achievement_update)(void* event_data, struct DiscordUserAchievement* user_achievement);
};
struct IDiscordAchievementManager {
void (*set_user_achievement)(struct IDiscordAchievementManager* manager, DiscordSnowflake achievement_id, uint8_t percent_complete, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*fetch_user_achievements)(struct IDiscordAchievementManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result));
void (*count_user_achievements)(struct IDiscordAchievementManager* manager, int32_t* count);
enum EDiscordResult (*get_user_achievement)(struct IDiscordAchievementManager* manager, DiscordSnowflake user_achievement_id, struct DiscordUserAchievement* user_achievement);
enum EDiscordResult (*get_user_achievement_at)(struct IDiscordAchievementManager* manager, int32_t index, struct DiscordUserAchievement* user_achievement);
};
typedef void* IDiscordCoreEvents;
struct IDiscordCore {
void (*destroy)(struct IDiscordCore* core);
enum EDiscordResult (*run_callbacks)(struct IDiscordCore* core);
void (*set_log_hook)(struct IDiscordCore* core, enum EDiscordLogLevel min_level, void* hook_data, void (*hook)(void* hook_data, enum EDiscordLogLevel level, const char* message));
struct IDiscordApplicationManager* (*get_application_manager)(struct IDiscordCore* core);
struct IDiscordUserManager* (*get_user_manager)(struct IDiscordCore* core);
struct IDiscordImageManager* (*get_image_manager)(struct IDiscordCore* core);
struct IDiscordActivityManager* (*get_activity_manager)(struct IDiscordCore* core);
struct IDiscordRelationshipManager* (*get_relationship_manager)(struct IDiscordCore* core);
struct IDiscordLobbyManager* (*get_lobby_manager)(struct IDiscordCore* core);
struct IDiscordNetworkManager* (*get_network_manager)(struct IDiscordCore* core);
struct IDiscordOverlayManager* (*get_overlay_manager)(struct IDiscordCore* core);
struct IDiscordStorageManager* (*get_storage_manager)(struct IDiscordCore* core);
struct IDiscordStoreManager* (*get_store_manager)(struct IDiscordCore* core);
struct IDiscordVoiceManager* (*get_voice_manager)(struct IDiscordCore* core);
struct IDiscordAchievementManager* (*get_achievement_manager)(struct IDiscordCore* core);
};
struct DiscordCreateParams {
DiscordClientId client_id;
uint64_t flags;
IDiscordCoreEvents* events;
void* event_data;
IDiscordApplicationEvents* application_events;
DiscordVersion application_version;
struct IDiscordUserEvents* user_events;
DiscordVersion user_version;
IDiscordImageEvents* image_events;
DiscordVersion image_version;
struct IDiscordActivityEvents* activity_events;
DiscordVersion activity_version;
struct IDiscordRelationshipEvents* relationship_events;
DiscordVersion relationship_version;
struct IDiscordLobbyEvents* lobby_events;
DiscordVersion lobby_version;
struct IDiscordNetworkEvents* network_events;
DiscordVersion network_version;
struct IDiscordOverlayEvents* overlay_events;
DiscordVersion overlay_version;
IDiscordStorageEvents* storage_events;
DiscordVersion storage_version;
struct IDiscordStoreEvents* store_events;
DiscordVersion store_version;
struct IDiscordVoiceEvents* voice_events;
DiscordVersion voice_version;
struct IDiscordAchievementEvents* achievement_events;
DiscordVersion achievement_version;
};
#ifdef __cplusplus
inline
#else
static
#endif
void DiscordCreateParamsSetDefault(struct DiscordCreateParams* params)
{
memset(params, 0, sizeof(struct DiscordCreateParams));
params->application_version = DISCORD_APPLICATION_MANAGER_VERSION;
params->user_version = DISCORD_USER_MANAGER_VERSION;
params->image_version = DISCORD_IMAGE_MANAGER_VERSION;
params->activity_version = DISCORD_ACTIVITY_MANAGER_VERSION;
params->relationship_version = DISCORD_RELATIONSHIP_MANAGER_VERSION;
params->lobby_version = DISCORD_LOBBY_MANAGER_VERSION;
params->network_version = DISCORD_NETWORK_MANAGER_VERSION;
params->overlay_version = DISCORD_OVERLAY_MANAGER_VERSION;
params->storage_version = DISCORD_STORAGE_MANAGER_VERSION;
params->store_version = DISCORD_STORE_MANAGER_VERSION;
params->voice_version = DISCORD_VOICE_MANAGER_VERSION;
params->achievement_version = DISCORD_ACHIEVEMENT_MANAGER_VERSION;
}
enum EDiscordResult DiscordCreate(DiscordVersion version, struct DiscordCreateParams* params, struct IDiscordCore** result);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,98 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "achievement_manager.h"
#include "core.h"
#include <cstring>
#include <memory>
namespace discord {
class AchievementEvents final {
public:
static void OnUserAchievementUpdate(void* callbackData, DiscordUserAchievement* userAchievement)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->AchievementManager();
module.OnUserAchievementUpdate(*reinterpret_cast<UserAchievement const*>(userAchievement));
}
};
IDiscordAchievementEvents AchievementManager::events_{
&AchievementEvents::OnUserAchievementUpdate,
};
void AchievementManager::SetUserAchievement(Snowflake achievementId,
std::uint8_t percentComplete,
std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->set_user_achievement(
internal_, achievementId, percentComplete, cb.release(), wrapper);
}
void AchievementManager::FetchUserAchievements(std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->fetch_user_achievements(internal_, cb.release(), wrapper);
}
void AchievementManager::CountUserAchievements(std::int32_t* count)
{
if (!count) {
return;
}
internal_->count_user_achievements(internal_, reinterpret_cast<int32_t*>(count));
}
Result AchievementManager::GetUserAchievement(Snowflake userAchievementId,
UserAchievement* userAchievement)
{
if (!userAchievement) {
return Result::InternalError;
}
auto result = internal_->get_user_achievement(
internal_, userAchievementId, reinterpret_cast<DiscordUserAchievement*>(userAchievement));
return static_cast<Result>(result);
}
Result AchievementManager::GetUserAchievementAt(std::int32_t index,
UserAchievement* userAchievement)
{
if (!userAchievement) {
return Result::InternalError;
}
auto result = internal_->get_user_achievement_at(
internal_, index, reinterpret_cast<DiscordUserAchievement*>(userAchievement));
return static_cast<Result>(result);
}
} // namespace discord

View File

@ -0,0 +1,34 @@
#pragma once
#include "types.h"
namespace discord {
class AchievementManager final {
public:
~AchievementManager() = default;
void SetUserAchievement(Snowflake achievementId,
std::uint8_t percentComplete,
std::function<void(Result)> callback);
void FetchUserAchievements(std::function<void(Result)> callback);
void CountUserAchievements(std::int32_t* count);
Result GetUserAchievement(Snowflake userAchievementId, UserAchievement* userAchievement);
Result GetUserAchievementAt(std::int32_t index, UserAchievement* userAchievement);
Event<UserAchievement const&> OnUserAchievementUpdate;
private:
friend class Core;
AchievementManager() = default;
AchievementManager(AchievementManager const& rhs) = delete;
AchievementManager& operator=(AchievementManager const& rhs) = delete;
AchievementManager(AchievementManager&& rhs) = delete;
AchievementManager& operator=(AchievementManager&& rhs) = delete;
IDiscordAchievementManager* internal_;
static IDiscordAchievementEvents events_;
};
} // namespace discord

View File

@ -0,0 +1,177 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "activity_manager.h"
#include "core.h"
#include <cstring>
#include <memory>
namespace discord {
class ActivityEvents final {
public:
static void OnActivityJoin(void* callbackData, char const* secret)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->ActivityManager();
module.OnActivityJoin(static_cast<const char*>(secret));
}
static void OnActivitySpectate(void* callbackData, char const* secret)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->ActivityManager();
module.OnActivitySpectate(static_cast<const char*>(secret));
}
static void OnActivityJoinRequest(void* callbackData, DiscordUser* user)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->ActivityManager();
module.OnActivityJoinRequest(*reinterpret_cast<User const*>(user));
}
static void OnActivityInvite(void* callbackData,
EDiscordActivityActionType type,
DiscordUser* user,
DiscordActivity* activity)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->ActivityManager();
module.OnActivityInvite(static_cast<ActivityActionType>(type),
*reinterpret_cast<User const*>(user),
*reinterpret_cast<Activity const*>(activity));
}
};
IDiscordActivityEvents ActivityManager::events_{
&ActivityEvents::OnActivityJoin,
&ActivityEvents::OnActivitySpectate,
&ActivityEvents::OnActivityJoinRequest,
&ActivityEvents::OnActivityInvite,
};
Result ActivityManager::RegisterCommand(char const* command)
{
auto result = internal_->register_command(internal_, const_cast<char*>(command));
return static_cast<Result>(result);
}
Result ActivityManager::RegisterSteam(std::uint32_t steamId)
{
auto result = internal_->register_steam(internal_, steamId);
return static_cast<Result>(result);
}
void ActivityManager::UpdateActivity(Activity const& activity, std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->update_activity(internal_,
reinterpret_cast<DiscordActivity*>(const_cast<Activity*>(&activity)),
cb.release(),
wrapper);
}
void ActivityManager::ClearActivity(std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->clear_activity(internal_, cb.release(), wrapper);
}
void ActivityManager::SendRequestReply(UserId userId,
ActivityJoinRequestReply reply,
std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->send_request_reply(internal_,
userId,
static_cast<EDiscordActivityJoinRequestReply>(reply),
cb.release(),
wrapper);
}
void ActivityManager::SendInvite(UserId userId,
ActivityActionType type,
char const* content,
std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->send_invite(internal_,
userId,
static_cast<EDiscordActivityActionType>(type),
const_cast<char*>(content),
cb.release(),
wrapper);
}
void ActivityManager::AcceptInvite(UserId userId, std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->accept_invite(internal_, userId, cb.release(), wrapper);
}
} // namespace discord

View File

@ -0,0 +1,42 @@
#pragma once
#include "types.h"
namespace discord {
class ActivityManager final {
public:
~ActivityManager() = default;
Result RegisterCommand(char const* command);
Result RegisterSteam(std::uint32_t steamId);
void UpdateActivity(Activity const& activity, std::function<void(Result)> callback);
void ClearActivity(std::function<void(Result)> callback);
void SendRequestReply(UserId userId,
ActivityJoinRequestReply reply,
std::function<void(Result)> callback);
void SendInvite(UserId userId,
ActivityActionType type,
char const* content,
std::function<void(Result)> callback);
void AcceptInvite(UserId userId, std::function<void(Result)> callback);
Event<char const*> OnActivityJoin;
Event<char const*> OnActivitySpectate;
Event<User const&> OnActivityJoinRequest;
Event<ActivityActionType, User const&, Activity const&> OnActivityInvite;
private:
friend class Core;
ActivityManager() = default;
ActivityManager(ActivityManager const& rhs) = delete;
ActivityManager& operator=(ActivityManager const& rhs) = delete;
ActivityManager(ActivityManager&& rhs) = delete;
ActivityManager& operator=(ActivityManager&& rhs) = delete;
IDiscordActivityManager* internal_;
static IDiscordActivityEvents events_;
};
} // namespace discord

View File

@ -0,0 +1,78 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "application_manager.h"
#include "core.h"
#include <cstring>
#include <memory>
namespace discord {
void ApplicationManager::ValidateOrExit(std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->validate_or_exit(internal_, cb.release(), wrapper);
}
void ApplicationManager::GetCurrentLocale(char locale[128])
{
if (!locale) {
return;
}
internal_->get_current_locale(internal_, reinterpret_cast<DiscordLocale*>(locale));
}
void ApplicationManager::GetCurrentBranch(char branch[4096])
{
if (!branch) {
return;
}
internal_->get_current_branch(internal_, reinterpret_cast<DiscordBranch*>(branch));
}
void ApplicationManager::GetOAuth2Token(std::function<void(Result, OAuth2Token const&)> callback)
{
static auto wrapper =
[](void* callbackData, EDiscordResult result, DiscordOAuth2Token* oauth2Token) -> void {
std::unique_ptr<std::function<void(Result, OAuth2Token const&)>> cb(
reinterpret_cast<std::function<void(Result, OAuth2Token const&)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result), *reinterpret_cast<OAuth2Token const*>(oauth2Token));
};
std::unique_ptr<std::function<void(Result, OAuth2Token const&)>> cb{};
cb.reset(new std::function<void(Result, OAuth2Token const&)>(std::move(callback)));
internal_->get_oauth2_token(internal_, cb.release(), wrapper);
}
void ApplicationManager::GetTicket(std::function<void(Result, char const*)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result, char const* data) -> void {
std::unique_ptr<std::function<void(Result, char const*)>> cb(
reinterpret_cast<std::function<void(Result, char const*)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result), static_cast<const char*>(data));
};
std::unique_ptr<std::function<void(Result, char const*)>> cb{};
cb.reset(new std::function<void(Result, char const*)>(std::move(callback)));
internal_->get_ticket(internal_, cb.release(), wrapper);
}
} // namespace discord

View File

@ -0,0 +1,30 @@
#pragma once
#include "types.h"
namespace discord {
class ApplicationManager final {
public:
~ApplicationManager() = default;
void ValidateOrExit(std::function<void(Result)> callback);
void GetCurrentLocale(char locale[128]);
void GetCurrentBranch(char branch[4096]);
void GetOAuth2Token(std::function<void(Result, OAuth2Token const&)> callback);
void GetTicket(std::function<void(Result, char const*)> callback);
private:
friend class Core;
ApplicationManager() = default;
ApplicationManager(ApplicationManager const& rhs) = delete;
ApplicationManager& operator=(ApplicationManager const& rhs) = delete;
ApplicationManager(ApplicationManager&& rhs) = delete;
ApplicationManager& operator=(ApplicationManager&& rhs) = delete;
IDiscordApplicationManager* internal_;
static IDiscordApplicationEvents events_;
};
} // namespace discord

View File

@ -0,0 +1,182 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "core.h"
#include <cstring>
#include <memory>
namespace discord {
Result Core::Create(ClientId clientId, std::uint64_t flags, Core** instance)
{
if (!instance) {
return Result::InternalError;
}
(*instance) = new Core();
DiscordCreateParams params{};
DiscordCreateParamsSetDefault(&params);
params.client_id = clientId;
params.flags = flags;
params.events = nullptr;
params.event_data = *instance;
params.user_events = &UserManager::events_;
params.activity_events = &ActivityManager::events_;
params.relationship_events = &RelationshipManager::events_;
params.lobby_events = &LobbyManager::events_;
params.network_events = &NetworkManager::events_;
params.overlay_events = &OverlayManager::events_;
params.store_events = &StoreManager::events_;
params.voice_events = &VoiceManager::events_;
params.achievement_events = &AchievementManager::events_;
auto result = DiscordCreate(DISCORD_VERSION, &params, &((*instance)->internal_));
if (result != DiscordResult_Ok || !(*instance)->internal_) {
delete (*instance);
(*instance) = nullptr;
}
return static_cast<Result>(result);
}
Core::~Core()
{
if (internal_) {
internal_->destroy(internal_);
internal_ = nullptr;
}
}
Result Core::RunCallbacks()
{
auto result = internal_->run_callbacks(internal_);
return static_cast<Result>(result);
}
void Core::SetLogHook(LogLevel minLevel, std::function<void(LogLevel, char const*)> hook)
{
setLogHook_.DisconnectAll();
setLogHook_.Connect(std::move(hook));
static auto wrapper =
[](void* callbackData, EDiscordLogLevel level, char const* message) -> void {
auto cb(reinterpret_cast<decltype(setLogHook_)*>(callbackData));
if (!cb) {
return;
}
(*cb)(static_cast<LogLevel>(level), static_cast<const char*>(message));
};
internal_->set_log_hook(
internal_, static_cast<EDiscordLogLevel>(minLevel), &setLogHook_, wrapper);
}
discord::ApplicationManager& Core::ApplicationManager()
{
if (!applicationManager_.internal_) {
applicationManager_.internal_ = internal_->get_application_manager(internal_);
}
return applicationManager_;
}
discord::UserManager& Core::UserManager()
{
if (!userManager_.internal_) {
userManager_.internal_ = internal_->get_user_manager(internal_);
}
return userManager_;
}
discord::ImageManager& Core::ImageManager()
{
if (!imageManager_.internal_) {
imageManager_.internal_ = internal_->get_image_manager(internal_);
}
return imageManager_;
}
discord::ActivityManager& Core::ActivityManager()
{
if (!activityManager_.internal_) {
activityManager_.internal_ = internal_->get_activity_manager(internal_);
}
return activityManager_;
}
discord::RelationshipManager& Core::RelationshipManager()
{
if (!relationshipManager_.internal_) {
relationshipManager_.internal_ = internal_->get_relationship_manager(internal_);
}
return relationshipManager_;
}
discord::LobbyManager& Core::LobbyManager()
{
if (!lobbyManager_.internal_) {
lobbyManager_.internal_ = internal_->get_lobby_manager(internal_);
}
return lobbyManager_;
}
discord::NetworkManager& Core::NetworkManager()
{
if (!networkManager_.internal_) {
networkManager_.internal_ = internal_->get_network_manager(internal_);
}
return networkManager_;
}
discord::OverlayManager& Core::OverlayManager()
{
if (!overlayManager_.internal_) {
overlayManager_.internal_ = internal_->get_overlay_manager(internal_);
}
return overlayManager_;
}
discord::StorageManager& Core::StorageManager()
{
if (!storageManager_.internal_) {
storageManager_.internal_ = internal_->get_storage_manager(internal_);
}
return storageManager_;
}
discord::StoreManager& Core::StoreManager()
{
if (!storeManager_.internal_) {
storeManager_.internal_ = internal_->get_store_manager(internal_);
}
return storeManager_;
}
discord::VoiceManager& Core::VoiceManager()
{
if (!voiceManager_.internal_) {
voiceManager_.internal_ = internal_->get_voice_manager(internal_);
}
return voiceManager_;
}
discord::AchievementManager& Core::AchievementManager()
{
if (!achievementManager_.internal_) {
achievementManager_.internal_ = internal_->get_achievement_manager(internal_);
}
return achievementManager_;
}
} // namespace discord

View File

@ -0,0 +1,64 @@
#pragma once
#include "types.h"
#include "application_manager.h"
#include "user_manager.h"
#include "image_manager.h"
#include "activity_manager.h"
#include "relationship_manager.h"
#include "lobby_manager.h"
#include "network_manager.h"
#include "overlay_manager.h"
#include "storage_manager.h"
#include "store_manager.h"
#include "voice_manager.h"
#include "achievement_manager.h"
namespace discord {
class Core final {
public:
static Result Create(ClientId clientId, std::uint64_t flags, Core** instance);
~Core();
Result RunCallbacks();
void SetLogHook(LogLevel minLevel, std::function<void(LogLevel, char const*)> hook);
discord::ApplicationManager& ApplicationManager();
discord::UserManager& UserManager();
discord::ImageManager& ImageManager();
discord::ActivityManager& ActivityManager();
discord::RelationshipManager& RelationshipManager();
discord::LobbyManager& LobbyManager();
discord::NetworkManager& NetworkManager();
discord::OverlayManager& OverlayManager();
discord::StorageManager& StorageManager();
discord::StoreManager& StoreManager();
discord::VoiceManager& VoiceManager();
discord::AchievementManager& AchievementManager();
private:
Core() = default;
Core(Core const& rhs) = delete;
Core& operator=(Core const& rhs) = delete;
Core(Core&& rhs) = delete;
Core& operator=(Core&& rhs) = delete;
IDiscordCore* internal_;
Event<LogLevel, char const*> setLogHook_;
discord::ApplicationManager applicationManager_;
discord::UserManager userManager_;
discord::ImageManager imageManager_;
discord::ActivityManager activityManager_;
discord::RelationshipManager relationshipManager_;
discord::LobbyManager lobbyManager_;
discord::NetworkManager networkManager_;
discord::OverlayManager overlayManager_;
discord::StorageManager storageManager_;
discord::StoreManager storeManager_;
discord::VoiceManager voiceManager_;
discord::AchievementManager achievementManager_;
};
} // namespace discord

View File

@ -0,0 +1,16 @@
#pragma once
#include "types.h"
#include "core.h"
#include "application_manager.h"
#include "user_manager.h"
#include "image_manager.h"
#include "activity_manager.h"
#include "relationship_manager.h"
#include "lobby_manager.h"
#include "network_manager.h"
#include "overlay_manager.h"
#include "storage_manager.h"
#include "store_manager.h"
#include "voice_manager.h"
#include "achievement_manager.h"

View File

@ -0,0 +1,59 @@
#pragma once
#include <functional>
#include <vector>
namespace discord {
template <typename... Args>
class Event final {
public:
using Token = int;
Event() { slots_.reserve(4); }
Event(Event const&) = default;
Event(Event&&) = default;
~Event() = default;
Event& operator=(Event const&) = default;
Event& operator=(Event&&) = default;
template <typename EventHandler>
Token Connect(EventHandler slot)
{
slots_.emplace_back(Slot{nextToken_, std::move(slot)});
return nextToken_++;
}
void Disconnect(Token token)
{
for (auto& slot : slots_) {
if (slot.token == token) {
slot = slots_.back();
slots_.pop_back();
break;
}
}
}
void DisconnectAll() { slots_ = {}; }
void operator()(Args... args)
{
for (auto const& slot : slots_) {
slot.fn(std::forward<Args>(args)...);
}
}
private:
struct Slot {
Token token;
std::function<void(Args...)> fn;
};
Token nextToken_{};
std::vector<Slot> slots_{};
};
} // namespace discord

View File

@ -0,0 +1,942 @@
#ifndef _DISCORD_GAME_SDK_H_
#define _DISCORD_GAME_SDK_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <string.h>
#ifndef __cplusplus
#include <stdbool.h>
#endif
#define DISCORD_VERSION 2
#define DISCORD_APPLICATION_MANAGER_VERSION 1
#define DISCORD_USER_MANAGER_VERSION 1
#define DISCORD_IMAGE_MANAGER_VERSION 1
#define DISCORD_ACTIVITY_MANAGER_VERSION 1
#define DISCORD_RELATIONSHIP_MANAGER_VERSION 1
#define DISCORD_LOBBY_MANAGER_VERSION 1
#define DISCORD_NETWORK_MANAGER_VERSION 1
#define DISCORD_OVERLAY_MANAGER_VERSION 1
#define DISCORD_STORAGE_MANAGER_VERSION 1
#define DISCORD_STORE_MANAGER_VERSION 1
#define DISCORD_VOICE_MANAGER_VERSION 1
#define DISCORD_ACHIEVEMENT_MANAGER_VERSION 1
enum EDiscordResult {
DiscordResult_Ok = 0,
DiscordResult_ServiceUnavailable = 1,
DiscordResult_InvalidVersion = 2,
DiscordResult_LockFailed = 3,
DiscordResult_InternalError = 4,
DiscordResult_InvalidPayload = 5,
DiscordResult_InvalidCommand = 6,
DiscordResult_InvalidPermissions = 7,
DiscordResult_NotFetched = 8,
DiscordResult_NotFound = 9,
DiscordResult_Conflict = 10,
DiscordResult_InvalidSecret = 11,
DiscordResult_InvalidJoinSecret = 12,
DiscordResult_NoEligibleActivity = 13,
DiscordResult_InvalidInvite = 14,
DiscordResult_NotAuthenticated = 15,
DiscordResult_InvalidAccessToken = 16,
DiscordResult_ApplicationMismatch = 17,
DiscordResult_InvalidDataUrl = 18,
DiscordResult_InvalidBase64 = 19,
DiscordResult_NotFiltered = 20,
DiscordResult_LobbyFull = 21,
DiscordResult_InvalidLobbySecret = 22,
DiscordResult_InvalidFilename = 23,
DiscordResult_InvalidFileSize = 24,
DiscordResult_InvalidEntitlement = 25,
DiscordResult_NotInstalled = 26,
DiscordResult_NotRunning = 27,
DiscordResult_InsufficientBuffer = 28,
DiscordResult_PurchaseCanceled = 29,
DiscordResult_InvalidGuild = 30,
DiscordResult_InvalidEvent = 31,
DiscordResult_InvalidChannel = 32,
DiscordResult_InvalidOrigin = 33,
DiscordResult_RateLimited = 34,
DiscordResult_OAuth2Error = 35,
DiscordResult_SelectChannelTimeout = 36,
DiscordResult_GetGuildTimeout = 37,
DiscordResult_SelectVoiceForceRequired = 38,
DiscordResult_CaptureShortcutAlreadyListening = 39,
DiscordResult_UnauthorizedForAchievement = 40,
DiscordResult_InvalidGiftCode = 41,
DiscordResult_PurchaseError = 42,
DiscordResult_TransactionAborted = 43,
};
enum EDiscordCreateFlags {
DiscordCreateFlags_Default = 0,
DiscordCreateFlags_NoRequireDiscord = 1,
};
enum EDiscordLogLevel {
DiscordLogLevel_Error = 1,
DiscordLogLevel_Warn,
DiscordLogLevel_Info,
DiscordLogLevel_Debug,
};
enum EDiscordUserFlag {
DiscordUserFlag_Partner = 2,
DiscordUserFlag_HypeSquadEvents = 4,
DiscordUserFlag_HypeSquadHouse1 = 64,
DiscordUserFlag_HypeSquadHouse2 = 128,
DiscordUserFlag_HypeSquadHouse3 = 256,
};
enum EDiscordPremiumType {
DiscordPremiumType_None = 0,
DiscordPremiumType_Tier1 = 1,
DiscordPremiumType_Tier2 = 2,
};
enum EDiscordImageType {
DiscordImageType_User,
};
enum EDiscordActivityType {
DiscordActivityType_Playing,
DiscordActivityType_Streaming,
DiscordActivityType_Listening,
DiscordActivityType_Watching,
};
enum EDiscordActivityActionType {
DiscordActivityActionType_Join = 1,
DiscordActivityActionType_Spectate,
};
enum EDiscordActivityJoinRequestReply {
DiscordActivityJoinRequestReply_No,
DiscordActivityJoinRequestReply_Yes,
DiscordActivityJoinRequestReply_Ignore,
};
enum EDiscordStatus {
DiscordStatus_Offline = 0,
DiscordStatus_Online = 1,
DiscordStatus_Idle = 2,
DiscordStatus_DoNotDisturb = 3,
};
enum EDiscordRelationshipType {
DiscordRelationshipType_None,
DiscordRelationshipType_Friend,
DiscordRelationshipType_Blocked,
DiscordRelationshipType_PendingIncoming,
DiscordRelationshipType_PendingOutgoing,
DiscordRelationshipType_Implicit,
};
enum EDiscordLobbyType {
DiscordLobbyType_Private = 1,
DiscordLobbyType_Public,
};
enum EDiscordLobbySearchComparison {
DiscordLobbySearchComparison_LessThanOrEqual = -2,
DiscordLobbySearchComparison_LessThan,
DiscordLobbySearchComparison_Equal,
DiscordLobbySearchComparison_GreaterThan,
DiscordLobbySearchComparison_GreaterThanOrEqual,
DiscordLobbySearchComparison_NotEqual,
};
enum EDiscordLobbySearchCast {
DiscordLobbySearchCast_String = 1,
DiscordLobbySearchCast_Number,
};
enum EDiscordLobbySearchDistance {
DiscordLobbySearchDistance_Local,
DiscordLobbySearchDistance_Default,
DiscordLobbySearchDistance_Extended,
DiscordLobbySearchDistance_Global,
};
enum EDiscordEntitlementType {
DiscordEntitlementType_Purchase = 1,
DiscordEntitlementType_PremiumSubscription,
DiscordEntitlementType_DeveloperGift,
DiscordEntitlementType_TestModePurchase,
DiscordEntitlementType_FreePurchase,
DiscordEntitlementType_UserGift,
DiscordEntitlementType_PremiumPurchase,
};
enum EDiscordSkuType {
DiscordSkuType_Application = 1,
DiscordSkuType_DLC,
DiscordSkuType_Consumable,
DiscordSkuType_Bundle,
};
enum EDiscordInputModeType {
DiscordInputModeType_VoiceActivity = 0,
DiscordInputModeType_PushToTalk,
};
typedef int64_t DiscordClientId;
typedef int32_t DiscordVersion;
typedef int64_t DiscordSnowflake;
typedef int64_t DiscordTimestamp;
typedef DiscordSnowflake DiscordUserId;
typedef char DiscordLocale[128];
typedef char DiscordBranch[4096];
typedef DiscordSnowflake DiscordLobbyId;
typedef char DiscordLobbySecret[128];
typedef char DiscordMetadataKey[256];
typedef char DiscordMetadataValue[4096];
typedef uint64_t DiscordNetworkPeerId;
typedef uint8_t DiscordNetworkChannelId;
typedef char DiscordPath[4096];
typedef char DiscordDateTime[64];
struct DiscordUser {
DiscordUserId id;
char username[256];
char discriminator[8];
char avatar[128];
bool bot;
};
struct DiscordOAuth2Token {
char access_token[128];
char scopes[1024];
DiscordTimestamp expires;
};
struct DiscordImageHandle {
enum EDiscordImageType type;
int64_t id;
uint32_t size;
};
struct DiscordImageDimensions {
uint32_t width;
uint32_t height;
};
struct DiscordActivityTimestamps {
DiscordTimestamp start;
DiscordTimestamp end;
};
struct DiscordActivityAssets {
char large_image[128];
char large_text[128];
char small_image[128];
char small_text[128];
};
struct DiscordPartySize {
int32_t current_size;
int32_t max_size;
};
struct DiscordActivityParty {
char id[128];
struct DiscordPartySize size;
};
struct DiscordActivitySecrets {
char match[128];
char join[128];
char spectate[128];
};
struct DiscordActivity {
enum EDiscordActivityType type;
int64_t application_id;
char name[128];
char state[128];
char details[128];
struct DiscordActivityTimestamps timestamps;
struct DiscordActivityAssets assets;
struct DiscordActivityParty party;
struct DiscordActivitySecrets secrets;
bool instance;
};
struct DiscordPresence {
enum EDiscordStatus status;
struct DiscordActivity activity;
};
struct DiscordRelationship {
enum EDiscordRelationshipType type;
struct DiscordUser user;
struct DiscordPresence presence;
};
struct DiscordLobby {
DiscordLobbyId id;
enum EDiscordLobbyType type;
DiscordUserId owner_id;
DiscordLobbySecret secret;
uint32_t capacity;
bool locked;
};
struct DiscordFileStat {
char filename[260];
uint64_t size;
uint64_t last_modified;
};
struct DiscordEntitlement {
DiscordSnowflake id;
enum EDiscordEntitlementType type;
DiscordSnowflake sku_id;
};
struct DiscordSkuPrice {
uint32_t amount;
char currency[16];
};
struct DiscordSku {
DiscordSnowflake id;
enum EDiscordSkuType type;
char name[256];
struct DiscordSkuPrice price;
};
struct DiscordInputMode {
enum EDiscordInputModeType type;
char shortcut[256];
};
struct DiscordUserAchievement {
DiscordSnowflake user_id;
DiscordSnowflake achievement_id;
uint8_t percent_complete;
DiscordDateTime unlocked_at;
};
struct IDiscordLobbyTransaction {
enum EDiscordResult (*set_type)(struct IDiscordLobbyTransaction* lobby_transaction,
enum EDiscordLobbyType type);
enum EDiscordResult (*set_owner)(struct IDiscordLobbyTransaction* lobby_transaction,
DiscordUserId owner_id);
enum EDiscordResult (*set_capacity)(struct IDiscordLobbyTransaction* lobby_transaction,
uint32_t capacity);
enum EDiscordResult (*set_metadata)(struct IDiscordLobbyTransaction* lobby_transaction,
DiscordMetadataKey key,
DiscordMetadataValue value);
enum EDiscordResult (*delete_metadata)(struct IDiscordLobbyTransaction* lobby_transaction,
DiscordMetadataKey key);
enum EDiscordResult (*set_locked)(struct IDiscordLobbyTransaction* lobby_transaction,
bool locked);
};
struct IDiscordLobbyMemberTransaction {
enum EDiscordResult (*set_metadata)(
struct IDiscordLobbyMemberTransaction* lobby_member_transaction,
DiscordMetadataKey key,
DiscordMetadataValue value);
enum EDiscordResult (*delete_metadata)(
struct IDiscordLobbyMemberTransaction* lobby_member_transaction,
DiscordMetadataKey key);
};
struct IDiscordLobbySearchQuery {
enum EDiscordResult (*filter)(struct IDiscordLobbySearchQuery* lobby_search_query,
DiscordMetadataKey key,
enum EDiscordLobbySearchComparison comparison,
enum EDiscordLobbySearchCast cast,
DiscordMetadataValue value);
enum EDiscordResult (*sort)(struct IDiscordLobbySearchQuery* lobby_search_query,
DiscordMetadataKey key,
enum EDiscordLobbySearchCast cast,
DiscordMetadataValue value);
enum EDiscordResult (*limit)(struct IDiscordLobbySearchQuery* lobby_search_query,
uint32_t limit);
enum EDiscordResult (*distance)(struct IDiscordLobbySearchQuery* lobby_search_query,
enum EDiscordLobbySearchDistance distance);
};
typedef void* IDiscordApplicationEvents;
struct IDiscordApplicationManager {
void (*validate_or_exit)(struct IDiscordApplicationManager* manager,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*get_current_locale)(struct IDiscordApplicationManager* manager, DiscordLocale* locale);
void (*get_current_branch)(struct IDiscordApplicationManager* manager, DiscordBranch* branch);
void (*get_oauth2_token)(struct IDiscordApplicationManager* manager,
void* callback_data,
void (*callback)(void* callback_data,
enum EDiscordResult result,
struct DiscordOAuth2Token* oauth2_token));
void (*get_ticket)(struct IDiscordApplicationManager* manager,
void* callback_data,
void (*callback)(void* callback_data,
enum EDiscordResult result,
const char* data));
};
struct IDiscordUserEvents {
void (*on_current_user_update)(void* event_data);
};
struct IDiscordUserManager {
enum EDiscordResult (*get_current_user)(struct IDiscordUserManager* manager,
struct DiscordUser* current_user);
void (*get_user)(struct IDiscordUserManager* manager,
DiscordUserId user_id,
void* callback_data,
void (*callback)(void* callback_data,
enum EDiscordResult result,
struct DiscordUser* user));
enum EDiscordResult (*get_current_user_premium_type)(struct IDiscordUserManager* manager,
enum EDiscordPremiumType* premium_type);
enum EDiscordResult (*current_user_has_flag)(struct IDiscordUserManager* manager,
enum EDiscordUserFlag flag,
bool* has_flag);
};
typedef void* IDiscordImageEvents;
struct IDiscordImageManager {
void (*fetch)(struct IDiscordImageManager* manager,
struct DiscordImageHandle handle,
bool refresh,
void* callback_data,
void (*callback)(void* callback_data,
enum EDiscordResult result,
struct DiscordImageHandle handle_result));
enum EDiscordResult (*get_dimensions)(struct IDiscordImageManager* manager,
struct DiscordImageHandle handle,
struct DiscordImageDimensions* dimensions);
enum EDiscordResult (*get_data)(struct IDiscordImageManager* manager,
struct DiscordImageHandle handle,
uint8_t* data,
uint32_t data_length);
};
struct IDiscordActivityEvents {
void (*on_activity_join)(void* event_data, const char* secret);
void (*on_activity_spectate)(void* event_data, const char* secret);
void (*on_activity_join_request)(void* event_data, struct DiscordUser* user);
void (*on_activity_invite)(void* event_data,
enum EDiscordActivityActionType type,
struct DiscordUser* user,
struct DiscordActivity* activity);
};
struct IDiscordActivityManager {
enum EDiscordResult (*register_command)(struct IDiscordActivityManager* manager,
const char* command);
enum EDiscordResult (*register_steam)(struct IDiscordActivityManager* manager,
uint32_t steam_id);
void (*update_activity)(struct IDiscordActivityManager* manager,
struct DiscordActivity* activity,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*clear_activity)(struct IDiscordActivityManager* manager,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*send_request_reply)(struct IDiscordActivityManager* manager,
DiscordUserId user_id,
enum EDiscordActivityJoinRequestReply reply,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*send_invite)(struct IDiscordActivityManager* manager,
DiscordUserId user_id,
enum EDiscordActivityActionType type,
const char* content,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*accept_invite)(struct IDiscordActivityManager* manager,
DiscordUserId user_id,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
};
struct IDiscordRelationshipEvents {
void (*on_refresh)(void* event_data);
void (*on_relationship_update)(void* event_data, struct DiscordRelationship* relationship);
};
struct IDiscordRelationshipManager {
void (*filter)(struct IDiscordRelationshipManager* manager,
void* filter_data,
bool (*filter)(void* filter_data, struct DiscordRelationship* relationship));
enum EDiscordResult (*count)(struct IDiscordRelationshipManager* manager, int32_t* count);
enum EDiscordResult (*get)(struct IDiscordRelationshipManager* manager,
DiscordUserId user_id,
struct DiscordRelationship* relationship);
enum EDiscordResult (*get_at)(struct IDiscordRelationshipManager* manager,
uint32_t index,
struct DiscordRelationship* relationship);
};
struct IDiscordLobbyEvents {
void (*on_lobby_update)(void* event_data, int64_t lobby_id);
void (*on_lobby_delete)(void* event_data, int64_t lobby_id, uint32_t reason);
void (*on_member_connect)(void* event_data, int64_t lobby_id, int64_t user_id);
void (*on_member_update)(void* event_data, int64_t lobby_id, int64_t user_id);
void (*on_member_disconnect)(void* event_data, int64_t lobby_id, int64_t user_id);
void (*on_lobby_message)(void* event_data,
int64_t lobby_id,
int64_t user_id,
uint8_t* data,
uint32_t data_length);
void (*on_speaking)(void* event_data, int64_t lobby_id, int64_t user_id, bool speaking);
void (*on_network_message)(void* event_data,
int64_t lobby_id,
int64_t user_id,
uint8_t channel_id,
uint8_t* data,
uint32_t data_length);
};
struct IDiscordLobbyManager {
enum EDiscordResult (*get_lobby_create_transaction)(
struct IDiscordLobbyManager* manager,
struct IDiscordLobbyTransaction** transaction);
enum EDiscordResult (*get_lobby_update_transaction)(
struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
struct IDiscordLobbyTransaction** transaction);
enum EDiscordResult (*get_member_update_transaction)(
struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
DiscordUserId user_id,
struct IDiscordLobbyMemberTransaction** transaction);
void (*create_lobby)(struct IDiscordLobbyManager* manager,
struct IDiscordLobbyTransaction* transaction,
void* callback_data,
void (*callback)(void* callback_data,
enum EDiscordResult result,
struct DiscordLobby* lobby));
void (*update_lobby)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
struct IDiscordLobbyTransaction* transaction,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*delete_lobby)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*connect_lobby)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
DiscordLobbySecret secret,
void* callback_data,
void (*callback)(void* callback_data,
enum EDiscordResult result,
struct DiscordLobby* lobby));
void (*connect_lobby_with_activity_secret)(struct IDiscordLobbyManager* manager,
DiscordLobbySecret activity_secret,
void* callback_data,
void (*callback)(void* callback_data,
enum EDiscordResult result,
struct DiscordLobby* lobby));
void (*disconnect_lobby)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
enum EDiscordResult (*get_lobby)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
struct DiscordLobby* lobby);
enum EDiscordResult (*get_lobby_activity_secret)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
DiscordLobbySecret* secret);
enum EDiscordResult (*get_lobby_metadata_value)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
DiscordMetadataKey key,
DiscordMetadataValue* value);
enum EDiscordResult (*get_lobby_metadata_key)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
int32_t index,
DiscordMetadataKey* key);
enum EDiscordResult (*lobby_metadata_count)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
int32_t* count);
enum EDiscordResult (*member_count)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
int32_t* count);
enum EDiscordResult (*get_member_user_id)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
int32_t index,
DiscordUserId* user_id);
enum EDiscordResult (*get_member_user)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
DiscordUserId user_id,
struct DiscordUser* user);
enum EDiscordResult (*get_member_metadata_value)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
DiscordUserId user_id,
DiscordMetadataKey key,
DiscordMetadataValue* value);
enum EDiscordResult (*get_member_metadata_key)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
DiscordUserId user_id,
int32_t index,
DiscordMetadataKey* key);
enum EDiscordResult (*member_metadata_count)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
DiscordUserId user_id,
int32_t* count);
void (*update_member)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
DiscordUserId user_id,
struct IDiscordLobbyMemberTransaction* transaction,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*send_lobby_message)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
uint8_t* data,
uint32_t data_length,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
enum EDiscordResult (*get_search_query)(struct IDiscordLobbyManager* manager,
struct IDiscordLobbySearchQuery** query);
void (*search)(struct IDiscordLobbyManager* manager,
struct IDiscordLobbySearchQuery* query,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*lobby_count)(struct IDiscordLobbyManager* manager, int32_t* count);
enum EDiscordResult (*get_lobby_id)(struct IDiscordLobbyManager* manager,
int32_t index,
DiscordLobbyId* lobby_id);
void (*connect_voice)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*disconnect_voice)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
enum EDiscordResult (*connect_network)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id);
enum EDiscordResult (*disconnect_network)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id);
enum EDiscordResult (*flush_network)(struct IDiscordLobbyManager* manager);
enum EDiscordResult (*open_network_channel)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
uint8_t channel_id,
bool reliable);
enum EDiscordResult (*send_network_message)(struct IDiscordLobbyManager* manager,
DiscordLobbyId lobby_id,
DiscordUserId user_id,
uint8_t channel_id,
uint8_t* data,
uint32_t data_length);
};
struct IDiscordNetworkEvents {
void (*on_message)(void* event_data,
DiscordNetworkPeerId peer_id,
DiscordNetworkChannelId channel_id,
uint8_t* data,
uint32_t data_length);
void (*on_route_update)(void* event_data, const char* route_data);
};
struct IDiscordNetworkManager {
/**
* Get the local peer ID for this process.
*/
void (*get_peer_id)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId* peer_id);
/**
* Send pending network messages.
*/
enum EDiscordResult (*flush)(struct IDiscordNetworkManager* manager);
/**
* Open a connection to a remote peer.
*/
enum EDiscordResult (*open_peer)(struct IDiscordNetworkManager* manager,
DiscordNetworkPeerId peer_id,
const char* route_data);
/**
* Update the route data for a connected peer.
*/
enum EDiscordResult (*update_peer)(struct IDiscordNetworkManager* manager,
DiscordNetworkPeerId peer_id,
const char* route_data);
/**
* Close the connection to a remote peer.
*/
enum EDiscordResult (*close_peer)(struct IDiscordNetworkManager* manager,
DiscordNetworkPeerId peer_id);
/**
* Open a message channel to a connected peer.
*/
enum EDiscordResult (*open_channel)(struct IDiscordNetworkManager* manager,
DiscordNetworkPeerId peer_id,
DiscordNetworkChannelId channel_id,
bool reliable);
/**
* Close a message channel to a connected peer.
*/
enum EDiscordResult (*close_channel)(struct IDiscordNetworkManager* manager,
DiscordNetworkPeerId peer_id,
DiscordNetworkChannelId channel_id);
/**
* Send a message to a connected peer over an opened message channel.
*/
enum EDiscordResult (*send_message)(struct IDiscordNetworkManager* manager,
DiscordNetworkPeerId peer_id,
DiscordNetworkChannelId channel_id,
uint8_t* data,
uint32_t data_length);
};
struct IDiscordOverlayEvents {
void (*on_toggle)(void* event_data, bool locked);
};
struct IDiscordOverlayManager {
void (*is_enabled)(struct IDiscordOverlayManager* manager, bool* enabled);
void (*is_locked)(struct IDiscordOverlayManager* manager, bool* locked);
void (*set_locked)(struct IDiscordOverlayManager* manager,
bool locked,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*open_activity_invite)(struct IDiscordOverlayManager* manager,
enum EDiscordActivityActionType type,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*open_guild_invite)(struct IDiscordOverlayManager* manager,
const char* code,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*open_voice_settings)(struct IDiscordOverlayManager* manager,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
};
typedef void* IDiscordStorageEvents;
struct IDiscordStorageManager {
enum EDiscordResult (*read)(struct IDiscordStorageManager* manager,
const char* name,
uint8_t* data,
uint32_t data_length,
uint32_t* read);
void (*read_async)(struct IDiscordStorageManager* manager,
const char* name,
void* callback_data,
void (*callback)(void* callback_data,
enum EDiscordResult result,
uint8_t* data,
uint32_t data_length));
void (*read_async_partial)(struct IDiscordStorageManager* manager,
const char* name,
uint64_t offset,
uint64_t length,
void* callback_data,
void (*callback)(void* callback_data,
enum EDiscordResult result,
uint8_t* data,
uint32_t data_length));
enum EDiscordResult (*write)(struct IDiscordStorageManager* manager,
const char* name,
uint8_t* data,
uint32_t data_length);
void (*write_async)(struct IDiscordStorageManager* manager,
const char* name,
uint8_t* data,
uint32_t data_length,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
enum EDiscordResult (*delete_)(struct IDiscordStorageManager* manager, const char* name);
enum EDiscordResult (*exists)(struct IDiscordStorageManager* manager,
const char* name,
bool* exists);
void (*count)(struct IDiscordStorageManager* manager, int32_t* count);
enum EDiscordResult (*stat)(struct IDiscordStorageManager* manager,
const char* name,
struct DiscordFileStat* stat);
enum EDiscordResult (*stat_at)(struct IDiscordStorageManager* manager,
int32_t index,
struct DiscordFileStat* stat);
enum EDiscordResult (*get_path)(struct IDiscordStorageManager* manager, DiscordPath* path);
};
struct IDiscordStoreEvents {
void (*on_entitlement_create)(void* event_data, struct DiscordEntitlement* entitlement);
void (*on_entitlement_delete)(void* event_data, struct DiscordEntitlement* entitlement);
};
struct IDiscordStoreManager {
void (*fetch_skus)(struct IDiscordStoreManager* manager,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*count_skus)(struct IDiscordStoreManager* manager, int32_t* count);
enum EDiscordResult (*get_sku)(struct IDiscordStoreManager* manager,
DiscordSnowflake sku_id,
struct DiscordSku* sku);
enum EDiscordResult (*get_sku_at)(struct IDiscordStoreManager* manager,
int32_t index,
struct DiscordSku* sku);
void (*fetch_entitlements)(struct IDiscordStoreManager* manager,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*count_entitlements)(struct IDiscordStoreManager* manager, int32_t* count);
enum EDiscordResult (*get_entitlement)(struct IDiscordStoreManager* manager,
DiscordSnowflake entitlement_id,
struct DiscordEntitlement* entitlement);
enum EDiscordResult (*get_entitlement_at)(struct IDiscordStoreManager* manager,
int32_t index,
struct DiscordEntitlement* entitlement);
enum EDiscordResult (*has_sku_entitlement)(struct IDiscordStoreManager* manager,
DiscordSnowflake sku_id,
bool* has_entitlement);
void (*start_purchase)(struct IDiscordStoreManager* manager,
DiscordSnowflake sku_id,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
};
struct IDiscordVoiceEvents {
void (*on_settings_update)(void* event_data);
};
struct IDiscordVoiceManager {
enum EDiscordResult (*get_input_mode)(struct IDiscordVoiceManager* manager,
struct DiscordInputMode* input_mode);
void (*set_input_mode)(struct IDiscordVoiceManager* manager,
struct DiscordInputMode input_mode,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
enum EDiscordResult (*is_self_mute)(struct IDiscordVoiceManager* manager, bool* mute);
enum EDiscordResult (*set_self_mute)(struct IDiscordVoiceManager* manager, bool mute);
enum EDiscordResult (*is_self_deaf)(struct IDiscordVoiceManager* manager, bool* deaf);
enum EDiscordResult (*set_self_deaf)(struct IDiscordVoiceManager* manager, bool deaf);
enum EDiscordResult (*is_local_mute)(struct IDiscordVoiceManager* manager,
DiscordSnowflake user_id,
bool* mute);
enum EDiscordResult (*set_local_mute)(struct IDiscordVoiceManager* manager,
DiscordSnowflake user_id,
bool mute);
enum EDiscordResult (*get_local_volume)(struct IDiscordVoiceManager* manager,
DiscordSnowflake user_id,
uint8_t* volume);
enum EDiscordResult (*set_local_volume)(struct IDiscordVoiceManager* manager,
DiscordSnowflake user_id,
uint8_t volume);
};
struct IDiscordAchievementEvents {
void (*on_user_achievement_update)(void* event_data,
struct DiscordUserAchievement* user_achievement);
};
struct IDiscordAchievementManager {
void (*set_user_achievement)(struct IDiscordAchievementManager* manager,
DiscordSnowflake achievement_id,
uint8_t percent_complete,
void* callback_data,
void (*callback)(void* callback_data, enum EDiscordResult result));
void (*fetch_user_achievements)(struct IDiscordAchievementManager* manager,
void* callback_data,
void (*callback)(void* callback_data,
enum EDiscordResult result));
void (*count_user_achievements)(struct IDiscordAchievementManager* manager, int32_t* count);
enum EDiscordResult (*get_user_achievement)(struct IDiscordAchievementManager* manager,
DiscordSnowflake user_achievement_id,
struct DiscordUserAchievement* user_achievement);
enum EDiscordResult (*get_user_achievement_at)(struct IDiscordAchievementManager* manager,
int32_t index,
struct DiscordUserAchievement* user_achievement);
};
typedef void* IDiscordCoreEvents;
struct IDiscordCore {
void (*destroy)(struct IDiscordCore* core);
enum EDiscordResult (*run_callbacks)(struct IDiscordCore* core);
void (*set_log_hook)(struct IDiscordCore* core,
enum EDiscordLogLevel min_level,
void* hook_data,
void (*hook)(void* hook_data,
enum EDiscordLogLevel level,
const char* message));
struct IDiscordApplicationManager* (*get_application_manager)(struct IDiscordCore* core);
struct IDiscordUserManager* (*get_user_manager)(struct IDiscordCore* core);
struct IDiscordImageManager* (*get_image_manager)(struct IDiscordCore* core);
struct IDiscordActivityManager* (*get_activity_manager)(struct IDiscordCore* core);
struct IDiscordRelationshipManager* (*get_relationship_manager)(struct IDiscordCore* core);
struct IDiscordLobbyManager* (*get_lobby_manager)(struct IDiscordCore* core);
struct IDiscordNetworkManager* (*get_network_manager)(struct IDiscordCore* core);
struct IDiscordOverlayManager* (*get_overlay_manager)(struct IDiscordCore* core);
struct IDiscordStorageManager* (*get_storage_manager)(struct IDiscordCore* core);
struct IDiscordStoreManager* (*get_store_manager)(struct IDiscordCore* core);
struct IDiscordVoiceManager* (*get_voice_manager)(struct IDiscordCore* core);
struct IDiscordAchievementManager* (*get_achievement_manager)(struct IDiscordCore* core);
};
struct DiscordCreateParams {
DiscordClientId client_id;
uint64_t flags;
IDiscordCoreEvents* events;
void* event_data;
IDiscordApplicationEvents* application_events;
DiscordVersion application_version;
struct IDiscordUserEvents* user_events;
DiscordVersion user_version;
IDiscordImageEvents* image_events;
DiscordVersion image_version;
struct IDiscordActivityEvents* activity_events;
DiscordVersion activity_version;
struct IDiscordRelationshipEvents* relationship_events;
DiscordVersion relationship_version;
struct IDiscordLobbyEvents* lobby_events;
DiscordVersion lobby_version;
struct IDiscordNetworkEvents* network_events;
DiscordVersion network_version;
struct IDiscordOverlayEvents* overlay_events;
DiscordVersion overlay_version;
IDiscordStorageEvents* storage_events;
DiscordVersion storage_version;
struct IDiscordStoreEvents* store_events;
DiscordVersion store_version;
struct IDiscordVoiceEvents* voice_events;
DiscordVersion voice_version;
struct IDiscordAchievementEvents* achievement_events;
DiscordVersion achievement_version;
};
#ifdef __cplusplus
inline
#else
static
#endif
void
DiscordCreateParamsSetDefault(struct DiscordCreateParams* params)
{
memset(params, 0, sizeof(struct DiscordCreateParams));
params->application_version = DISCORD_APPLICATION_MANAGER_VERSION;
params->user_version = DISCORD_USER_MANAGER_VERSION;
params->image_version = DISCORD_IMAGE_MANAGER_VERSION;
params->activity_version = DISCORD_ACTIVITY_MANAGER_VERSION;
params->relationship_version = DISCORD_RELATIONSHIP_MANAGER_VERSION;
params->lobby_version = DISCORD_LOBBY_MANAGER_VERSION;
params->network_version = DISCORD_NETWORK_MANAGER_VERSION;
params->overlay_version = DISCORD_OVERLAY_MANAGER_VERSION;
params->storage_version = DISCORD_STORAGE_MANAGER_VERSION;
params->store_version = DISCORD_STORE_MANAGER_VERSION;
params->voice_version = DISCORD_VOICE_MANAGER_VERSION;
params->achievement_version = DISCORD_ACHIEVEMENT_MANAGER_VERSION;
}
enum EDiscordResult DiscordCreate(DiscordVersion version,
struct DiscordCreateParams* params,
struct IDiscordCore** result);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,57 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "image_manager.h"
#include "core.h"
#include <cstring>
#include <memory>
namespace discord {
void ImageManager::Fetch(ImageHandle handle,
bool refresh,
std::function<void(Result, ImageHandle)> callback)
{
static auto wrapper =
[](void* callbackData, EDiscordResult result, DiscordImageHandle handleResult) -> void {
std::unique_ptr<std::function<void(Result, ImageHandle)>> cb(
reinterpret_cast<std::function<void(Result, ImageHandle)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result), *reinterpret_cast<ImageHandle const*>(&handleResult));
};
std::unique_ptr<std::function<void(Result, ImageHandle)>> cb{};
cb.reset(new std::function<void(Result, ImageHandle)>(std::move(callback)));
internal_->fetch(internal_,
*reinterpret_cast<DiscordImageHandle const*>(&handle),
(refresh ? 1 : 0),
cb.release(),
wrapper);
}
Result ImageManager::GetDimensions(ImageHandle handle, ImageDimensions* dimensions)
{
if (!dimensions) {
return Result::InternalError;
}
auto result = internal_->get_dimensions(internal_,
*reinterpret_cast<DiscordImageHandle const*>(&handle),
reinterpret_cast<DiscordImageDimensions*>(dimensions));
return static_cast<Result>(result);
}
Result ImageManager::GetData(ImageHandle handle, std::uint8_t* data, std::uint32_t dataLength)
{
auto result = internal_->get_data(internal_,
*reinterpret_cast<DiscordImageHandle const*>(&handle),
reinterpret_cast<uint8_t*>(data),
dataLength);
return static_cast<Result>(result);
}
} // namespace discord

View File

@ -0,0 +1,28 @@
#pragma once
#include "types.h"
namespace discord {
class ImageManager final {
public:
~ImageManager() = default;
void Fetch(ImageHandle handle, bool refresh, std::function<void(Result, ImageHandle)> callback);
Result GetDimensions(ImageHandle handle, ImageDimensions* dimensions);
Result GetData(ImageHandle handle, std::uint8_t* data, std::uint32_t dataLength);
private:
friend class Core;
ImageManager() = default;
ImageManager(ImageManager const& rhs) = delete;
ImageManager& operator=(ImageManager const& rhs) = delete;
ImageManager(ImageManager&& rhs) = delete;
ImageManager& operator=(ImageManager&& rhs) = delete;
IDiscordImageManager* internal_;
static IDiscordImageEvents events_;
};
} // namespace discord

View File

@ -0,0 +1,547 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "lobby_manager.h"
#include "core.h"
#include <cstring>
#include <memory>
namespace discord {
class LobbyEvents final {
public:
static void OnLobbyUpdate(void* callbackData, int64_t lobbyId)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->LobbyManager();
module.OnLobbyUpdate(lobbyId);
}
static void OnLobbyDelete(void* callbackData, int64_t lobbyId, uint32_t reason)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->LobbyManager();
module.OnLobbyDelete(lobbyId, reason);
}
static void OnMemberConnect(void* callbackData, int64_t lobbyId, int64_t userId)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->LobbyManager();
module.OnMemberConnect(lobbyId, userId);
}
static void OnMemberUpdate(void* callbackData, int64_t lobbyId, int64_t userId)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->LobbyManager();
module.OnMemberUpdate(lobbyId, userId);
}
static void OnMemberDisconnect(void* callbackData, int64_t lobbyId, int64_t userId)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->LobbyManager();
module.OnMemberDisconnect(lobbyId, userId);
}
static void OnLobbyMessage(void* callbackData,
int64_t lobbyId,
int64_t userId,
uint8_t* data,
uint32_t dataLength)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->LobbyManager();
module.OnLobbyMessage(lobbyId, userId, data, dataLength);
}
static void OnSpeaking(void* callbackData, int64_t lobbyId, int64_t userId, bool speaking)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->LobbyManager();
module.OnSpeaking(lobbyId, userId, (speaking != 0));
}
static void OnNetworkMessage(void* callbackData,
int64_t lobbyId,
int64_t userId,
uint8_t channelId,
uint8_t* data,
uint32_t dataLength)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->LobbyManager();
module.OnNetworkMessage(lobbyId, userId, channelId, data, dataLength);
}
};
IDiscordLobbyEvents LobbyManager::events_{
&LobbyEvents::OnLobbyUpdate,
&LobbyEvents::OnLobbyDelete,
&LobbyEvents::OnMemberConnect,
&LobbyEvents::OnMemberUpdate,
&LobbyEvents::OnMemberDisconnect,
&LobbyEvents::OnLobbyMessage,
&LobbyEvents::OnSpeaking,
&LobbyEvents::OnNetworkMessage,
};
Result LobbyManager::GetLobbyCreateTransaction(LobbyTransaction* transaction)
{
if (!transaction) {
return Result::InternalError;
}
auto result = internal_->get_lobby_create_transaction(internal_, transaction->Receive());
return static_cast<Result>(result);
}
Result LobbyManager::GetLobbyUpdateTransaction(LobbyId lobbyId, LobbyTransaction* transaction)
{
if (!transaction) {
return Result::InternalError;
}
auto result =
internal_->get_lobby_update_transaction(internal_, lobbyId, transaction->Receive());
return static_cast<Result>(result);
}
Result LobbyManager::GetMemberUpdateTransaction(LobbyId lobbyId,
UserId userId,
LobbyMemberTransaction* transaction)
{
if (!transaction) {
return Result::InternalError;
}
auto result =
internal_->get_member_update_transaction(internal_, lobbyId, userId, transaction->Receive());
return static_cast<Result>(result);
}
void LobbyManager::CreateLobby(LobbyTransaction const& transaction,
std::function<void(Result, Lobby const&)> callback)
{
static auto wrapper =
[](void* callbackData, EDiscordResult result, DiscordLobby* lobby) -> void {
std::unique_ptr<std::function<void(Result, Lobby const&)>> cb(
reinterpret_cast<std::function<void(Result, Lobby const&)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result), *reinterpret_cast<Lobby const*>(lobby));
};
std::unique_ptr<std::function<void(Result, Lobby const&)>> cb{};
cb.reset(new std::function<void(Result, Lobby const&)>(std::move(callback)));
internal_->create_lobby(
internal_, const_cast<LobbyTransaction&>(transaction).Internal(), cb.release(), wrapper);
}
void LobbyManager::UpdateLobby(LobbyId lobbyId,
LobbyTransaction const& transaction,
std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->update_lobby(internal_,
lobbyId,
const_cast<LobbyTransaction&>(transaction).Internal(),
cb.release(),
wrapper);
}
void LobbyManager::DeleteLobby(LobbyId lobbyId, std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->delete_lobby(internal_, lobbyId, cb.release(), wrapper);
}
void LobbyManager::ConnectLobby(LobbyId lobbyId,
LobbySecret secret,
std::function<void(Result, Lobby const&)> callback)
{
static auto wrapper =
[](void* callbackData, EDiscordResult result, DiscordLobby* lobby) -> void {
std::unique_ptr<std::function<void(Result, Lobby const&)>> cb(
reinterpret_cast<std::function<void(Result, Lobby const&)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result), *reinterpret_cast<Lobby const*>(lobby));
};
std::unique_ptr<std::function<void(Result, Lobby const&)>> cb{};
cb.reset(new std::function<void(Result, Lobby const&)>(std::move(callback)));
internal_->connect_lobby(internal_, lobbyId, const_cast<char*>(secret), cb.release(), wrapper);
}
void LobbyManager::ConnectLobbyWithActivitySecret(
LobbySecret activitySecret,
std::function<void(Result, Lobby const&)> callback)
{
static auto wrapper =
[](void* callbackData, EDiscordResult result, DiscordLobby* lobby) -> void {
std::unique_ptr<std::function<void(Result, Lobby const&)>> cb(
reinterpret_cast<std::function<void(Result, Lobby const&)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result), *reinterpret_cast<Lobby const*>(lobby));
};
std::unique_ptr<std::function<void(Result, Lobby const&)>> cb{};
cb.reset(new std::function<void(Result, Lobby const&)>(std::move(callback)));
internal_->connect_lobby_with_activity_secret(
internal_, const_cast<char*>(activitySecret), cb.release(), wrapper);
}
void LobbyManager::DisconnectLobby(LobbyId lobbyId, std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->disconnect_lobby(internal_, lobbyId, cb.release(), wrapper);
}
Result LobbyManager::GetLobby(LobbyId lobbyId, Lobby* lobby)
{
if (!lobby) {
return Result::InternalError;
}
auto result = internal_->get_lobby(internal_, lobbyId, reinterpret_cast<DiscordLobby*>(lobby));
return static_cast<Result>(result);
}
Result LobbyManager::GetLobbyActivitySecret(LobbyId lobbyId, char secret[128])
{
if (!secret) {
return Result::InternalError;
}
auto result = internal_->get_lobby_activity_secret(
internal_, lobbyId, reinterpret_cast<DiscordLobbySecret*>(secret));
return static_cast<Result>(result);
}
Result LobbyManager::GetLobbyMetadataValue(LobbyId lobbyId, MetadataKey key, char value[4096])
{
if (!value) {
return Result::InternalError;
}
auto result = internal_->get_lobby_metadata_value(
internal_, lobbyId, const_cast<char*>(key), reinterpret_cast<DiscordMetadataValue*>(value));
return static_cast<Result>(result);
}
Result LobbyManager::GetLobbyMetadataKey(LobbyId lobbyId, std::int32_t index, char key[256])
{
if (!key) {
return Result::InternalError;
}
auto result = internal_->get_lobby_metadata_key(
internal_, lobbyId, index, reinterpret_cast<DiscordMetadataKey*>(key));
return static_cast<Result>(result);
}
Result LobbyManager::LobbyMetadataCount(LobbyId lobbyId, std::int32_t* count)
{
if (!count) {
return Result::InternalError;
}
auto result =
internal_->lobby_metadata_count(internal_, lobbyId, reinterpret_cast<int32_t*>(count));
return static_cast<Result>(result);
}
Result LobbyManager::MemberCount(LobbyId lobbyId, std::int32_t* count)
{
if (!count) {
return Result::InternalError;
}
auto result = internal_->member_count(internal_, lobbyId, reinterpret_cast<int32_t*>(count));
return static_cast<Result>(result);
}
Result LobbyManager::GetMemberUserId(LobbyId lobbyId, std::int32_t index, UserId* userId)
{
if (!userId) {
return Result::InternalError;
}
auto result =
internal_->get_member_user_id(internal_, lobbyId, index, reinterpret_cast<int64_t*>(userId));
return static_cast<Result>(result);
}
Result LobbyManager::GetMemberUser(LobbyId lobbyId, UserId userId, User* user)
{
if (!user) {
return Result::InternalError;
}
auto result =
internal_->get_member_user(internal_, lobbyId, userId, reinterpret_cast<DiscordUser*>(user));
return static_cast<Result>(result);
}
Result LobbyManager::GetMemberMetadataValue(LobbyId lobbyId,
UserId userId,
MetadataKey key,
char value[4096])
{
if (!value) {
return Result::InternalError;
}
auto result =
internal_->get_member_metadata_value(internal_,
lobbyId,
userId,
const_cast<char*>(key),
reinterpret_cast<DiscordMetadataValue*>(value));
return static_cast<Result>(result);
}
Result LobbyManager::GetMemberMetadataKey(LobbyId lobbyId,
UserId userId,
std::int32_t index,
char key[256])
{
if (!key) {
return Result::InternalError;
}
auto result = internal_->get_member_metadata_key(
internal_, lobbyId, userId, index, reinterpret_cast<DiscordMetadataKey*>(key));
return static_cast<Result>(result);
}
Result LobbyManager::MemberMetadataCount(LobbyId lobbyId, UserId userId, std::int32_t* count)
{
if (!count) {
return Result::InternalError;
}
auto result = internal_->member_metadata_count(
internal_, lobbyId, userId, reinterpret_cast<int32_t*>(count));
return static_cast<Result>(result);
}
void LobbyManager::UpdateMember(LobbyId lobbyId,
UserId userId,
LobbyMemberTransaction const& transaction,
std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->update_member(internal_,
lobbyId,
userId,
const_cast<LobbyMemberTransaction&>(transaction).Internal(),
cb.release(),
wrapper);
}
void LobbyManager::SendLobbyMessage(LobbyId lobbyId,
std::uint8_t* data,
std::uint32_t dataLength,
std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->send_lobby_message(
internal_, lobbyId, reinterpret_cast<uint8_t*>(data), dataLength, cb.release(), wrapper);
}
Result LobbyManager::GetSearchQuery(LobbySearchQuery* query)
{
if (!query) {
return Result::InternalError;
}
auto result = internal_->get_search_query(internal_, query->Receive());
return static_cast<Result>(result);
}
void LobbyManager::Search(LobbySearchQuery const& query, std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->search(
internal_, const_cast<LobbySearchQuery&>(query).Internal(), cb.release(), wrapper);
}
void LobbyManager::LobbyCount(std::int32_t* count)
{
if (!count) {
return;
}
internal_->lobby_count(internal_, reinterpret_cast<int32_t*>(count));
}
Result LobbyManager::GetLobbyId(std::int32_t index, LobbyId* lobbyId)
{
if (!lobbyId) {
return Result::InternalError;
}
auto result = internal_->get_lobby_id(internal_, index, reinterpret_cast<int64_t*>(lobbyId));
return static_cast<Result>(result);
}
void LobbyManager::ConnectVoice(LobbyId lobbyId, std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->connect_voice(internal_, lobbyId, cb.release(), wrapper);
}
void LobbyManager::DisconnectVoice(LobbyId lobbyId, std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->disconnect_voice(internal_, lobbyId, cb.release(), wrapper);
}
Result LobbyManager::ConnectNetwork(LobbyId lobbyId)
{
auto result = internal_->connect_network(internal_, lobbyId);
return static_cast<Result>(result);
}
Result LobbyManager::DisconnectNetwork(LobbyId lobbyId)
{
auto result = internal_->disconnect_network(internal_, lobbyId);
return static_cast<Result>(result);
}
Result LobbyManager::FlushNetwork()
{
auto result = internal_->flush_network(internal_);
return static_cast<Result>(result);
}
Result LobbyManager::OpenNetworkChannel(LobbyId lobbyId, std::uint8_t channelId, bool reliable)
{
auto result =
internal_->open_network_channel(internal_, lobbyId, channelId, (reliable ? 1 : 0));
return static_cast<Result>(result);
}
Result LobbyManager::SendNetworkMessage(LobbyId lobbyId,
UserId userId,
std::uint8_t channelId,
std::uint8_t* data,
std::uint32_t dataLength)
{
auto result = internal_->send_network_message(
internal_, lobbyId, userId, channelId, reinterpret_cast<uint8_t*>(data), dataLength);
return static_cast<Result>(result);
}
} // namespace discord

View File

@ -0,0 +1,88 @@
#pragma once
#include "types.h"
namespace discord {
class LobbyManager final {
public:
~LobbyManager() = default;
Result GetLobbyCreateTransaction(LobbyTransaction* transaction);
Result GetLobbyUpdateTransaction(LobbyId lobbyId, LobbyTransaction* transaction);
Result GetMemberUpdateTransaction(LobbyId lobbyId,
UserId userId,
LobbyMemberTransaction* transaction);
void CreateLobby(LobbyTransaction const& transaction,
std::function<void(Result, Lobby const&)> callback);
void UpdateLobby(LobbyId lobbyId,
LobbyTransaction const& transaction,
std::function<void(Result)> callback);
void DeleteLobby(LobbyId lobbyId, std::function<void(Result)> callback);
void ConnectLobby(LobbyId lobbyId,
LobbySecret secret,
std::function<void(Result, Lobby const&)> callback);
void ConnectLobbyWithActivitySecret(LobbySecret activitySecret,
std::function<void(Result, Lobby const&)> callback);
void DisconnectLobby(LobbyId lobbyId, std::function<void(Result)> callback);
Result GetLobby(LobbyId lobbyId, Lobby* lobby);
Result GetLobbyActivitySecret(LobbyId lobbyId, char secret[128]);
Result GetLobbyMetadataValue(LobbyId lobbyId, MetadataKey key, char value[4096]);
Result GetLobbyMetadataKey(LobbyId lobbyId, std::int32_t index, char key[256]);
Result LobbyMetadataCount(LobbyId lobbyId, std::int32_t* count);
Result MemberCount(LobbyId lobbyId, std::int32_t* count);
Result GetMemberUserId(LobbyId lobbyId, std::int32_t index, UserId* userId);
Result GetMemberUser(LobbyId lobbyId, UserId userId, User* user);
Result GetMemberMetadataValue(LobbyId lobbyId,
UserId userId,
MetadataKey key,
char value[4096]);
Result GetMemberMetadataKey(LobbyId lobbyId, UserId userId, std::int32_t index, char key[256]);
Result MemberMetadataCount(LobbyId lobbyId, UserId userId, std::int32_t* count);
void UpdateMember(LobbyId lobbyId,
UserId userId,
LobbyMemberTransaction const& transaction,
std::function<void(Result)> callback);
void SendLobbyMessage(LobbyId lobbyId,
std::uint8_t* data,
std::uint32_t dataLength,
std::function<void(Result)> callback);
Result GetSearchQuery(LobbySearchQuery* query);
void Search(LobbySearchQuery const& query, std::function<void(Result)> callback);
void LobbyCount(std::int32_t* count);
Result GetLobbyId(std::int32_t index, LobbyId* lobbyId);
void ConnectVoice(LobbyId lobbyId, std::function<void(Result)> callback);
void DisconnectVoice(LobbyId lobbyId, std::function<void(Result)> callback);
Result ConnectNetwork(LobbyId lobbyId);
Result DisconnectNetwork(LobbyId lobbyId);
Result FlushNetwork();
Result OpenNetworkChannel(LobbyId lobbyId, std::uint8_t channelId, bool reliable);
Result SendNetworkMessage(LobbyId lobbyId,
UserId userId,
std::uint8_t channelId,
std::uint8_t* data,
std::uint32_t dataLength);
Event<std::int64_t> OnLobbyUpdate;
Event<std::int64_t, std::uint32_t> OnLobbyDelete;
Event<std::int64_t, std::int64_t> OnMemberConnect;
Event<std::int64_t, std::int64_t> OnMemberUpdate;
Event<std::int64_t, std::int64_t> OnMemberDisconnect;
Event<std::int64_t, std::int64_t, std::uint8_t*, std::uint32_t> OnLobbyMessage;
Event<std::int64_t, std::int64_t, bool> OnSpeaking;
Event<std::int64_t, std::int64_t, std::uint8_t, std::uint8_t*, std::uint32_t> OnNetworkMessage;
private:
friend class Core;
LobbyManager() = default;
LobbyManager(LobbyManager const& rhs) = delete;
LobbyManager& operator=(LobbyManager const& rhs) = delete;
LobbyManager(LobbyManager&& rhs) = delete;
LobbyManager& operator=(LobbyManager&& rhs) = delete;
IDiscordLobbyManager* internal_;
static IDiscordLobbyEvents events_;
};
} // namespace discord

View File

@ -0,0 +1,103 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "network_manager.h"
#include "core.h"
#include <cstring>
#include <memory>
namespace discord {
class NetworkEvents final {
public:
static void OnMessage(void* callbackData,
DiscordNetworkPeerId peerId,
DiscordNetworkChannelId channelId,
uint8_t* data,
uint32_t dataLength)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->NetworkManager();
module.OnMessage(peerId, channelId, data, dataLength);
}
static void OnRouteUpdate(void* callbackData, char const* routeData)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->NetworkManager();
module.OnRouteUpdate(static_cast<const char*>(routeData));
}
};
IDiscordNetworkEvents NetworkManager::events_{
&NetworkEvents::OnMessage,
&NetworkEvents::OnRouteUpdate,
};
void NetworkManager::GetPeerId(NetworkPeerId* peerId)
{
if (!peerId) {
return;
}
internal_->get_peer_id(internal_, reinterpret_cast<uint64_t*>(peerId));
}
Result NetworkManager::Flush()
{
auto result = internal_->flush(internal_);
return static_cast<Result>(result);
}
Result NetworkManager::OpenPeer(NetworkPeerId peerId, char const* routeData)
{
auto result = internal_->open_peer(internal_, peerId, const_cast<char*>(routeData));
return static_cast<Result>(result);
}
Result NetworkManager::UpdatePeer(NetworkPeerId peerId, char const* routeData)
{
auto result = internal_->update_peer(internal_, peerId, const_cast<char*>(routeData));
return static_cast<Result>(result);
}
Result NetworkManager::ClosePeer(NetworkPeerId peerId)
{
auto result = internal_->close_peer(internal_, peerId);
return static_cast<Result>(result);
}
Result NetworkManager::OpenChannel(NetworkPeerId peerId, NetworkChannelId channelId, bool reliable)
{
auto result = internal_->open_channel(internal_, peerId, channelId, (reliable ? 1 : 0));
return static_cast<Result>(result);
}
Result NetworkManager::CloseChannel(NetworkPeerId peerId, NetworkChannelId channelId)
{
auto result = internal_->close_channel(internal_, peerId, channelId);
return static_cast<Result>(result);
}
Result NetworkManager::SendMessage(NetworkPeerId peerId,
NetworkChannelId channelId,
std::uint8_t* data,
std::uint32_t dataLength)
{
auto result = internal_->send_message(
internal_, peerId, channelId, reinterpret_cast<uint8_t*>(data), dataLength);
return static_cast<Result>(result);
}
} // namespace discord

View File

@ -0,0 +1,63 @@
#pragma once
#include "types.h"
namespace discord {
class NetworkManager final {
public:
~NetworkManager() = default;
/**
* Get the local peer ID for this process.
*/
void GetPeerId(NetworkPeerId* peerId);
/**
* Send pending network messages.
*/
Result Flush();
/**
* Open a connection to a remote peer.
*/
Result OpenPeer(NetworkPeerId peerId, char const* routeData);
/**
* Update the route data for a connected peer.
*/
Result UpdatePeer(NetworkPeerId peerId, char const* routeData);
/**
* Close the connection to a remote peer.
*/
Result ClosePeer(NetworkPeerId peerId);
/**
* Open a message channel to a connected peer.
*/
Result OpenChannel(NetworkPeerId peerId, NetworkChannelId channelId, bool reliable);
/**
* Close a message channel to a connected peer.
*/
Result CloseChannel(NetworkPeerId peerId, NetworkChannelId channelId);
/**
* Send a message to a connected peer over an opened message channel.
*/
Result SendMessage(NetworkPeerId peerId,
NetworkChannelId channelId,
std::uint8_t* data,
std::uint32_t dataLength);
Event<NetworkPeerId, NetworkChannelId, std::uint8_t*, std::uint32_t> OnMessage;
Event<char const*> OnRouteUpdate;
private:
friend class Core;
NetworkManager() = default;
NetworkManager(NetworkManager const& rhs) = delete;
NetworkManager& operator=(NetworkManager const& rhs) = delete;
NetworkManager(NetworkManager&& rhs) = delete;
NetworkManager& operator=(NetworkManager&& rhs) = delete;
IDiscordNetworkManager* internal_;
static IDiscordNetworkEvents events_;
};
} // namespace discord

View File

@ -0,0 +1,112 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "overlay_manager.h"
#include "core.h"
#include <cstring>
#include <memory>
namespace discord {
class OverlayEvents final {
public:
static void OnToggle(void* callbackData, bool locked)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->OverlayManager();
module.OnToggle((locked != 0));
}
};
IDiscordOverlayEvents OverlayManager::events_{
&OverlayEvents::OnToggle,
};
void OverlayManager::IsEnabled(bool* enabled)
{
if (!enabled) {
return;
}
internal_->is_enabled(internal_, reinterpret_cast<bool*>(enabled));
}
void OverlayManager::IsLocked(bool* locked)
{
if (!locked) {
return;
}
internal_->is_locked(internal_, reinterpret_cast<bool*>(locked));
}
void OverlayManager::SetLocked(bool locked, std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->set_locked(internal_, (locked ? 1 : 0), cb.release(), wrapper);
}
void OverlayManager::OpenActivityInvite(ActivityActionType type,
std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->open_activity_invite(
internal_, static_cast<EDiscordActivityActionType>(type), cb.release(), wrapper);
}
void OverlayManager::OpenGuildInvite(char const* code, std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->open_guild_invite(internal_, const_cast<char*>(code), cb.release(), wrapper);
}
void OverlayManager::OpenVoiceSettings(std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->open_voice_settings(internal_, cb.release(), wrapper);
}
} // namespace discord

View File

@ -0,0 +1,33 @@
#pragma once
#include "types.h"
namespace discord {
class OverlayManager final {
public:
~OverlayManager() = default;
void IsEnabled(bool* enabled);
void IsLocked(bool* locked);
void SetLocked(bool locked, std::function<void(Result)> callback);
void OpenActivityInvite(ActivityActionType type, std::function<void(Result)> callback);
void OpenGuildInvite(char const* code, std::function<void(Result)> callback);
void OpenVoiceSettings(std::function<void(Result)> callback);
Event<bool> OnToggle;
private:
friend class Core;
OverlayManager() = default;
OverlayManager(OverlayManager const& rhs) = delete;
OverlayManager& operator=(OverlayManager const& rhs) = delete;
OverlayManager(OverlayManager&& rhs) = delete;
OverlayManager& operator=(OverlayManager&& rhs) = delete;
IDiscordOverlayManager* internal_;
static IDiscordOverlayEvents events_;
};
} // namespace discord

View File

@ -0,0 +1,90 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "relationship_manager.h"
#include "core.h"
#include <cstring>
#include <memory>
namespace discord {
class RelationshipEvents final {
public:
static void OnRefresh(void* callbackData)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->RelationshipManager();
module.OnRefresh();
}
static void OnRelationshipUpdate(void* callbackData, DiscordRelationship* relationship)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->RelationshipManager();
module.OnRelationshipUpdate(*reinterpret_cast<Relationship const*>(relationship));
}
};
IDiscordRelationshipEvents RelationshipManager::events_{
&RelationshipEvents::OnRefresh,
&RelationshipEvents::OnRelationshipUpdate,
};
void RelationshipManager::Filter(std::function<bool(Relationship const&)> filter)
{
static auto wrapper = [](void* callbackData, DiscordRelationship* relationship) -> bool {
auto cb(reinterpret_cast<std::function<bool(Relationship const&)>*>(callbackData));
if (!cb || !(*cb)) {
return {};
}
return (*cb)(*reinterpret_cast<Relationship const*>(relationship));
};
std::unique_ptr<std::function<bool(Relationship const&)>> cb{};
cb.reset(new std::function<bool(Relationship const&)>(std::move(filter)));
internal_->filter(internal_, cb.get(), wrapper);
}
Result RelationshipManager::Count(std::int32_t* count)
{
if (!count) {
return Result::InternalError;
}
auto result = internal_->count(internal_, reinterpret_cast<int32_t*>(count));
return static_cast<Result>(result);
}
Result RelationshipManager::Get(UserId userId, Relationship* relationship)
{
if (!relationship) {
return Result::InternalError;
}
auto result =
internal_->get(internal_, userId, reinterpret_cast<DiscordRelationship*>(relationship));
return static_cast<Result>(result);
}
Result RelationshipManager::GetAt(std::uint32_t index, Relationship* relationship)
{
if (!relationship) {
return Result::InternalError;
}
auto result =
internal_->get_at(internal_, index, reinterpret_cast<DiscordRelationship*>(relationship));
return static_cast<Result>(result);
}
} // namespace discord

View File

@ -0,0 +1,32 @@
#pragma once
#include "types.h"
namespace discord {
class RelationshipManager final {
public:
~RelationshipManager() = default;
void Filter(std::function<bool(Relationship const&)> filter);
Result Count(std::int32_t* count);
Result Get(UserId userId, Relationship* relationship);
Result GetAt(std::uint32_t index, Relationship* relationship);
Event<> OnRefresh;
Event<Relationship const&> OnRelationshipUpdate;
private:
friend class Core;
RelationshipManager() = default;
RelationshipManager(RelationshipManager const& rhs) = delete;
RelationshipManager& operator=(RelationshipManager const& rhs) = delete;
RelationshipManager(RelationshipManager&& rhs) = delete;
RelationshipManager& operator=(RelationshipManager&& rhs) = delete;
IDiscordRelationshipManager* internal_;
static IDiscordRelationshipEvents events_;
};
} // namespace discord

View File

@ -0,0 +1,158 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "storage_manager.h"
#include "core.h"
#include <cstring>
#include <memory>
namespace discord {
Result StorageManager::Read(char const* name,
std::uint8_t* data,
std::uint32_t dataLength,
std::uint32_t* read)
{
if (!read) {
return Result::InternalError;
}
auto result = internal_->read(internal_,
const_cast<char*>(name),
reinterpret_cast<uint8_t*>(data),
dataLength,
reinterpret_cast<uint32_t*>(read));
return static_cast<Result>(result);
}
void StorageManager::ReadAsync(char const* name,
std::function<void(Result, std::uint8_t*, std::uint32_t)> callback)
{
static auto wrapper =
[](void* callbackData, EDiscordResult result, uint8_t* data, uint32_t dataLength) -> void {
std::unique_ptr<std::function<void(Result, std::uint8_t*, std::uint32_t)>> cb(
reinterpret_cast<std::function<void(Result, std::uint8_t*, std::uint32_t)>*>(
callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result), data, dataLength);
};
std::unique_ptr<std::function<void(Result, std::uint8_t*, std::uint32_t)>> cb{};
cb.reset(new std::function<void(Result, std::uint8_t*, std::uint32_t)>(std::move(callback)));
internal_->read_async(internal_, const_cast<char*>(name), cb.release(), wrapper);
}
void StorageManager::ReadAsyncPartial(
char const* name,
std::uint64_t offset,
std::uint64_t length,
std::function<void(Result, std::uint8_t*, std::uint32_t)> callback)
{
static auto wrapper =
[](void* callbackData, EDiscordResult result, uint8_t* data, uint32_t dataLength) -> void {
std::unique_ptr<std::function<void(Result, std::uint8_t*, std::uint32_t)>> cb(
reinterpret_cast<std::function<void(Result, std::uint8_t*, std::uint32_t)>*>(
callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result), data, dataLength);
};
std::unique_ptr<std::function<void(Result, std::uint8_t*, std::uint32_t)>> cb{};
cb.reset(new std::function<void(Result, std::uint8_t*, std::uint32_t)>(std::move(callback)));
internal_->read_async_partial(
internal_, const_cast<char*>(name), offset, length, cb.release(), wrapper);
}
Result StorageManager::Write(char const* name, std::uint8_t* data, std::uint32_t dataLength)
{
auto result = internal_->write(
internal_, const_cast<char*>(name), reinterpret_cast<uint8_t*>(data), dataLength);
return static_cast<Result>(result);
}
void StorageManager::WriteAsync(char const* name,
std::uint8_t* data,
std::uint32_t dataLength,
std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->write_async(internal_,
const_cast<char*>(name),
reinterpret_cast<uint8_t*>(data),
dataLength,
cb.release(),
wrapper);
}
Result StorageManager::Delete(char const* name)
{
auto result = internal_->delete_(internal_, const_cast<char*>(name));
return static_cast<Result>(result);
}
Result StorageManager::Exists(char const* name, bool* exists)
{
if (!exists) {
return Result::InternalError;
}
auto result =
internal_->exists(internal_, const_cast<char*>(name), reinterpret_cast<bool*>(exists));
return static_cast<Result>(result);
}
void StorageManager::Count(std::int32_t* count)
{
if (!count) {
return;
}
internal_->count(internal_, reinterpret_cast<int32_t*>(count));
}
Result StorageManager::Stat(char const* name, FileStat* stat)
{
if (!stat) {
return Result::InternalError;
}
auto result =
internal_->stat(internal_, const_cast<char*>(name), reinterpret_cast<DiscordFileStat*>(stat));
return static_cast<Result>(result);
}
Result StorageManager::StatAt(std::int32_t index, FileStat* stat)
{
if (!stat) {
return Result::InternalError;
}
auto result = internal_->stat_at(internal_, index, reinterpret_cast<DiscordFileStat*>(stat));
return static_cast<Result>(result);
}
Result StorageManager::GetPath(char path[4096])
{
if (!path) {
return Result::InternalError;
}
auto result = internal_->get_path(internal_, reinterpret_cast<DiscordPath*>(path));
return static_cast<Result>(result);
}
} // namespace discord

View File

@ -0,0 +1,46 @@
#pragma once
#include "types.h"
namespace discord {
class StorageManager final {
public:
~StorageManager() = default;
Result Read(char const* name,
std::uint8_t* data,
std::uint32_t dataLength,
std::uint32_t* read);
void ReadAsync(char const* name,
std::function<void(Result, std::uint8_t*, std::uint32_t)> callback);
void ReadAsyncPartial(char const* name,
std::uint64_t offset,
std::uint64_t length,
std::function<void(Result, std::uint8_t*, std::uint32_t)> callback);
Result Write(char const* name, std::uint8_t* data, std::uint32_t dataLength);
void WriteAsync(char const* name,
std::uint8_t* data,
std::uint32_t dataLength,
std::function<void(Result)> callback);
Result Delete(char const* name);
Result Exists(char const* name, bool* exists);
void Count(std::int32_t* count);
Result Stat(char const* name, FileStat* stat);
Result StatAt(std::int32_t index, FileStat* stat);
Result GetPath(char path[4096]);
private:
friend class Core;
StorageManager() = default;
StorageManager(StorageManager const& rhs) = delete;
StorageManager& operator=(StorageManager const& rhs) = delete;
StorageManager(StorageManager&& rhs) = delete;
StorageManager& operator=(StorageManager&& rhs) = delete;
IDiscordStorageManager* internal_;
static IDiscordStorageEvents events_;
};
} // namespace discord

View File

@ -0,0 +1,160 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "store_manager.h"
#include "core.h"
#include <cstring>
#include <memory>
namespace discord {
class StoreEvents final {
public:
static void OnEntitlementCreate(void* callbackData, DiscordEntitlement* entitlement)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->StoreManager();
module.OnEntitlementCreate(*reinterpret_cast<Entitlement const*>(entitlement));
}
static void OnEntitlementDelete(void* callbackData, DiscordEntitlement* entitlement)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->StoreManager();
module.OnEntitlementDelete(*reinterpret_cast<Entitlement const*>(entitlement));
}
};
IDiscordStoreEvents StoreManager::events_{
&StoreEvents::OnEntitlementCreate,
&StoreEvents::OnEntitlementDelete,
};
void StoreManager::FetchSkus(std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->fetch_skus(internal_, cb.release(), wrapper);
}
void StoreManager::CountSkus(std::int32_t* count)
{
if (!count) {
return;
}
internal_->count_skus(internal_, reinterpret_cast<int32_t*>(count));
}
Result StoreManager::GetSku(Snowflake skuId, Sku* sku)
{
if (!sku) {
return Result::InternalError;
}
auto result = internal_->get_sku(internal_, skuId, reinterpret_cast<DiscordSku*>(sku));
return static_cast<Result>(result);
}
Result StoreManager::GetSkuAt(std::int32_t index, Sku* sku)
{
if (!sku) {
return Result::InternalError;
}
auto result = internal_->get_sku_at(internal_, index, reinterpret_cast<DiscordSku*>(sku));
return static_cast<Result>(result);
}
void StoreManager::FetchEntitlements(std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->fetch_entitlements(internal_, cb.release(), wrapper);
}
void StoreManager::CountEntitlements(std::int32_t* count)
{
if (!count) {
return;
}
internal_->count_entitlements(internal_, reinterpret_cast<int32_t*>(count));
}
Result StoreManager::GetEntitlement(Snowflake entitlementId, Entitlement* entitlement)
{
if (!entitlement) {
return Result::InternalError;
}
auto result = internal_->get_entitlement(
internal_, entitlementId, reinterpret_cast<DiscordEntitlement*>(entitlement));
return static_cast<Result>(result);
}
Result StoreManager::GetEntitlementAt(std::int32_t index, Entitlement* entitlement)
{
if (!entitlement) {
return Result::InternalError;
}
auto result = internal_->get_entitlement_at(
internal_, index, reinterpret_cast<DiscordEntitlement*>(entitlement));
return static_cast<Result>(result);
}
Result StoreManager::HasSkuEntitlement(Snowflake skuId, bool* hasEntitlement)
{
if (!hasEntitlement) {
return Result::InternalError;
}
auto result =
internal_->has_sku_entitlement(internal_, skuId, reinterpret_cast<bool*>(hasEntitlement));
return static_cast<Result>(result);
}
void StoreManager::StartPurchase(Snowflake skuId, std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->start_purchase(internal_, skuId, cb.release(), wrapper);
}
} // namespace discord

View File

@ -0,0 +1,38 @@
#pragma once
#include "types.h"
namespace discord {
class StoreManager final {
public:
~StoreManager() = default;
void FetchSkus(std::function<void(Result)> callback);
void CountSkus(std::int32_t* count);
Result GetSku(Snowflake skuId, Sku* sku);
Result GetSkuAt(std::int32_t index, Sku* sku);
void FetchEntitlements(std::function<void(Result)> callback);
void CountEntitlements(std::int32_t* count);
Result GetEntitlement(Snowflake entitlementId, Entitlement* entitlement);
Result GetEntitlementAt(std::int32_t index, Entitlement* entitlement);
Result HasSkuEntitlement(Snowflake skuId, bool* hasEntitlement);
void StartPurchase(Snowflake skuId, std::function<void(Result)> callback);
Event<Entitlement const&> OnEntitlementCreate;
Event<Entitlement const&> OnEntitlementDelete;
private:
friend class Core;
StoreManager() = default;
StoreManager(StoreManager const& rhs) = delete;
StoreManager& operator=(StoreManager const& rhs) = delete;
StoreManager(StoreManager&& rhs) = delete;
StoreManager& operator=(StoreManager&& rhs) = delete;
IDiscordStoreManager* internal_;
static IDiscordStoreEvents events_;
};
} // namespace discord

View File

@ -0,0 +1,769 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "types.h"
#include <cstring>
#include <memory>
namespace discord {
void User::SetId(UserId id)
{
internal_.id = id;
}
UserId User::GetId() const
{
return internal_.id;
}
void User::SetUsername(char const* username)
{
strncpy(internal_.username, username, 256);
internal_.username[256 - 1] = '\0';
}
char const* User::GetUsername() const
{
return internal_.username;
}
void User::SetDiscriminator(char const* discriminator)
{
strncpy(internal_.discriminator, discriminator, 8);
internal_.discriminator[8 - 1] = '\0';
}
char const* User::GetDiscriminator() const
{
return internal_.discriminator;
}
void User::SetAvatar(char const* avatar)
{
strncpy(internal_.avatar, avatar, 128);
internal_.avatar[128 - 1] = '\0';
}
char const* User::GetAvatar() const
{
return internal_.avatar;
}
void User::SetBot(bool bot)
{
internal_.bot = bot;
}
bool User::GetBot() const
{
return internal_.bot != 0;
}
void OAuth2Token::SetAccessToken(char const* accessToken)
{
strncpy(internal_.access_token, accessToken, 128);
internal_.access_token[128 - 1] = '\0';
}
char const* OAuth2Token::GetAccessToken() const
{
return internal_.access_token;
}
void OAuth2Token::SetScopes(char const* scopes)
{
strncpy(internal_.scopes, scopes, 1024);
internal_.scopes[1024 - 1] = '\0';
}
char const* OAuth2Token::GetScopes() const
{
return internal_.scopes;
}
void OAuth2Token::SetExpires(Timestamp expires)
{
internal_.expires = expires;
}
Timestamp OAuth2Token::GetExpires() const
{
return internal_.expires;
}
void ImageHandle::SetType(ImageType type)
{
internal_.type = static_cast<EDiscordImageType>(type);
}
ImageType ImageHandle::GetType() const
{
return static_cast<ImageType>(internal_.type);
}
void ImageHandle::SetId(std::int64_t id)
{
internal_.id = id;
}
std::int64_t ImageHandle::GetId() const
{
return internal_.id;
}
void ImageHandle::SetSize(std::uint32_t size)
{
internal_.size = size;
}
std::uint32_t ImageHandle::GetSize() const
{
return internal_.size;
}
void ImageDimensions::SetWidth(std::uint32_t width)
{
internal_.width = width;
}
std::uint32_t ImageDimensions::GetWidth() const
{
return internal_.width;
}
void ImageDimensions::SetHeight(std::uint32_t height)
{
internal_.height = height;
}
std::uint32_t ImageDimensions::GetHeight() const
{
return internal_.height;
}
void ActivityTimestamps::SetStart(Timestamp start)
{
internal_.start = start;
}
Timestamp ActivityTimestamps::GetStart() const
{
return internal_.start;
}
void ActivityTimestamps::SetEnd(Timestamp end)
{
internal_.end = end;
}
Timestamp ActivityTimestamps::GetEnd() const
{
return internal_.end;
}
void ActivityAssets::SetLargeImage(char const* largeImage)
{
strncpy(internal_.large_image, largeImage, 128);
internal_.large_image[128 - 1] = '\0';
}
char const* ActivityAssets::GetLargeImage() const
{
return internal_.large_image;
}
void ActivityAssets::SetLargeText(char const* largeText)
{
strncpy(internal_.large_text, largeText, 128);
internal_.large_text[128 - 1] = '\0';
}
char const* ActivityAssets::GetLargeText() const
{
return internal_.large_text;
}
void ActivityAssets::SetSmallImage(char const* smallImage)
{
strncpy(internal_.small_image, smallImage, 128);
internal_.small_image[128 - 1] = '\0';
}
char const* ActivityAssets::GetSmallImage() const
{
return internal_.small_image;
}
void ActivityAssets::SetSmallText(char const* smallText)
{
strncpy(internal_.small_text, smallText, 128);
internal_.small_text[128 - 1] = '\0';
}
char const* ActivityAssets::GetSmallText() const
{
return internal_.small_text;
}
void PartySize::SetCurrentSize(std::int32_t currentSize)
{
internal_.current_size = currentSize;
}
std::int32_t PartySize::GetCurrentSize() const
{
return internal_.current_size;
}
void PartySize::SetMaxSize(std::int32_t maxSize)
{
internal_.max_size = maxSize;
}
std::int32_t PartySize::GetMaxSize() const
{
return internal_.max_size;
}
void ActivityParty::SetId(char const* id)
{
strncpy(internal_.id, id, 128);
internal_.id[128 - 1] = '\0';
}
char const* ActivityParty::GetId() const
{
return internal_.id;
}
PartySize& ActivityParty::GetSize()
{
return reinterpret_cast<PartySize&>(internal_.size);
}
PartySize const& ActivityParty::GetSize() const
{
return reinterpret_cast<PartySize const&>(internal_.size);
}
void ActivitySecrets::SetMatch(char const* match)
{
strncpy(internal_.match, match, 128);
internal_.match[128 - 1] = '\0';
}
char const* ActivitySecrets::GetMatch() const
{
return internal_.match;
}
void ActivitySecrets::SetJoin(char const* join)
{
strncpy(internal_.join, join, 128);
internal_.join[128 - 1] = '\0';
}
char const* ActivitySecrets::GetJoin() const
{
return internal_.join;
}
void ActivitySecrets::SetSpectate(char const* spectate)
{
strncpy(internal_.spectate, spectate, 128);
internal_.spectate[128 - 1] = '\0';
}
char const* ActivitySecrets::GetSpectate() const
{
return internal_.spectate;
}
void Activity::SetType(ActivityType type)
{
internal_.type = static_cast<EDiscordActivityType>(type);
}
ActivityType Activity::GetType() const
{
return static_cast<ActivityType>(internal_.type);
}
void Activity::SetApplicationId(std::int64_t applicationId)
{
internal_.application_id = applicationId;
}
std::int64_t Activity::GetApplicationId() const
{
return internal_.application_id;
}
void Activity::SetName(char const* name)
{
strncpy(internal_.name, name, 128);
internal_.name[128 - 1] = '\0';
}
char const* Activity::GetName() const
{
return internal_.name;
}
void Activity::SetState(char const* state)
{
strncpy(internal_.state, state, 128);
internal_.state[128 - 1] = '\0';
}
char const* Activity::GetState() const
{
return internal_.state;
}
void Activity::SetDetails(char const* details)
{
strncpy(internal_.details, details, 128);
internal_.details[128 - 1] = '\0';
}
char const* Activity::GetDetails() const
{
return internal_.details;
}
ActivityTimestamps& Activity::GetTimestamps()
{
return reinterpret_cast<ActivityTimestamps&>(internal_.timestamps);
}
ActivityTimestamps const& Activity::GetTimestamps() const
{
return reinterpret_cast<ActivityTimestamps const&>(internal_.timestamps);
}
ActivityAssets& Activity::GetAssets()
{
return reinterpret_cast<ActivityAssets&>(internal_.assets);
}
ActivityAssets const& Activity::GetAssets() const
{
return reinterpret_cast<ActivityAssets const&>(internal_.assets);
}
ActivityParty& Activity::GetParty()
{
return reinterpret_cast<ActivityParty&>(internal_.party);
}
ActivityParty const& Activity::GetParty() const
{
return reinterpret_cast<ActivityParty const&>(internal_.party);
}
ActivitySecrets& Activity::GetSecrets()
{
return reinterpret_cast<ActivitySecrets&>(internal_.secrets);
}
ActivitySecrets const& Activity::GetSecrets() const
{
return reinterpret_cast<ActivitySecrets const&>(internal_.secrets);
}
void Activity::SetInstance(bool instance)
{
internal_.instance = instance;
}
bool Activity::GetInstance() const
{
return internal_.instance != 0;
}
void Presence::SetStatus(Status status)
{
internal_.status = static_cast<EDiscordStatus>(status);
}
Status Presence::GetStatus() const
{
return static_cast<Status>(internal_.status);
}
Activity& Presence::GetActivity()
{
return reinterpret_cast<Activity&>(internal_.activity);
}
Activity const& Presence::GetActivity() const
{
return reinterpret_cast<Activity const&>(internal_.activity);
}
void Relationship::SetType(RelationshipType type)
{
internal_.type = static_cast<EDiscordRelationshipType>(type);
}
RelationshipType Relationship::GetType() const
{
return static_cast<RelationshipType>(internal_.type);
}
User& Relationship::GetUser()
{
return reinterpret_cast<User&>(internal_.user);
}
User const& Relationship::GetUser() const
{
return reinterpret_cast<User const&>(internal_.user);
}
Presence& Relationship::GetPresence()
{
return reinterpret_cast<Presence&>(internal_.presence);
}
Presence const& Relationship::GetPresence() const
{
return reinterpret_cast<Presence const&>(internal_.presence);
}
void Lobby::SetId(LobbyId id)
{
internal_.id = id;
}
LobbyId Lobby::GetId() const
{
return internal_.id;
}
void Lobby::SetType(LobbyType type)
{
internal_.type = static_cast<EDiscordLobbyType>(type);
}
LobbyType Lobby::GetType() const
{
return static_cast<LobbyType>(internal_.type);
}
void Lobby::SetOwnerId(UserId ownerId)
{
internal_.owner_id = ownerId;
}
UserId Lobby::GetOwnerId() const
{
return internal_.owner_id;
}
void Lobby::SetSecret(LobbySecret secret)
{
strncpy(internal_.secret, secret, 128);
internal_.secret[128 - 1] = '\0';
}
LobbySecret Lobby::GetSecret() const
{
return internal_.secret;
}
void Lobby::SetCapacity(std::uint32_t capacity)
{
internal_.capacity = capacity;
}
std::uint32_t Lobby::GetCapacity() const
{
return internal_.capacity;
}
void Lobby::SetLocked(bool locked)
{
internal_.locked = locked;
}
bool Lobby::GetLocked() const
{
return internal_.locked != 0;
}
void FileStat::SetFilename(char const* filename)
{
strncpy(internal_.filename, filename, 260);
internal_.filename[260 - 1] = '\0';
}
char const* FileStat::GetFilename() const
{
return internal_.filename;
}
void FileStat::SetSize(std::uint64_t size)
{
internal_.size = size;
}
std::uint64_t FileStat::GetSize() const
{
return internal_.size;
}
void FileStat::SetLastModified(std::uint64_t lastModified)
{
internal_.last_modified = lastModified;
}
std::uint64_t FileStat::GetLastModified() const
{
return internal_.last_modified;
}
void Entitlement::SetId(Snowflake id)
{
internal_.id = id;
}
Snowflake Entitlement::GetId() const
{
return internal_.id;
}
void Entitlement::SetType(EntitlementType type)
{
internal_.type = static_cast<EDiscordEntitlementType>(type);
}
EntitlementType Entitlement::GetType() const
{
return static_cast<EntitlementType>(internal_.type);
}
void Entitlement::SetSkuId(Snowflake skuId)
{
internal_.sku_id = skuId;
}
Snowflake Entitlement::GetSkuId() const
{
return internal_.sku_id;
}
void SkuPrice::SetAmount(std::uint32_t amount)
{
internal_.amount = amount;
}
std::uint32_t SkuPrice::GetAmount() const
{
return internal_.amount;
}
void SkuPrice::SetCurrency(char const* currency)
{
strncpy(internal_.currency, currency, 16);
internal_.currency[16 - 1] = '\0';
}
char const* SkuPrice::GetCurrency() const
{
return internal_.currency;
}
void Sku::SetId(Snowflake id)
{
internal_.id = id;
}
Snowflake Sku::GetId() const
{
return internal_.id;
}
void Sku::SetType(SkuType type)
{
internal_.type = static_cast<EDiscordSkuType>(type);
}
SkuType Sku::GetType() const
{
return static_cast<SkuType>(internal_.type);
}
void Sku::SetName(char const* name)
{
strncpy(internal_.name, name, 256);
internal_.name[256 - 1] = '\0';
}
char const* Sku::GetName() const
{
return internal_.name;
}
SkuPrice& Sku::GetPrice()
{
return reinterpret_cast<SkuPrice&>(internal_.price);
}
SkuPrice const& Sku::GetPrice() const
{
return reinterpret_cast<SkuPrice const&>(internal_.price);
}
void InputMode::SetType(InputModeType type)
{
internal_.type = static_cast<EDiscordInputModeType>(type);
}
InputModeType InputMode::GetType() const
{
return static_cast<InputModeType>(internal_.type);
}
void InputMode::SetShortcut(char const* shortcut)
{
strncpy(internal_.shortcut, shortcut, 256);
internal_.shortcut[256 - 1] = '\0';
}
char const* InputMode::GetShortcut() const
{
return internal_.shortcut;
}
void UserAchievement::SetUserId(Snowflake userId)
{
internal_.user_id = userId;
}
Snowflake UserAchievement::GetUserId() const
{
return internal_.user_id;
}
void UserAchievement::SetAchievementId(Snowflake achievementId)
{
internal_.achievement_id = achievementId;
}
Snowflake UserAchievement::GetAchievementId() const
{
return internal_.achievement_id;
}
void UserAchievement::SetPercentComplete(std::uint8_t percentComplete)
{
internal_.percent_complete = percentComplete;
}
std::uint8_t UserAchievement::GetPercentComplete() const
{
return internal_.percent_complete;
}
void UserAchievement::SetUnlockedAt(DateTime unlockedAt)
{
strncpy(internal_.unlocked_at, unlockedAt, 64);
internal_.unlocked_at[64 - 1] = '\0';
}
DateTime UserAchievement::GetUnlockedAt() const
{
return internal_.unlocked_at;
}
Result LobbyTransaction::SetType(LobbyType type)
{
auto result = internal_->set_type(internal_, static_cast<EDiscordLobbyType>(type));
return static_cast<Result>(result);
}
Result LobbyTransaction::SetOwner(UserId ownerId)
{
auto result = internal_->set_owner(internal_, ownerId);
return static_cast<Result>(result);
}
Result LobbyTransaction::SetCapacity(std::uint32_t capacity)
{
auto result = internal_->set_capacity(internal_, capacity);
return static_cast<Result>(result);
}
Result LobbyTransaction::SetMetadata(MetadataKey key, MetadataValue value)
{
auto result =
internal_->set_metadata(internal_, const_cast<char*>(key), const_cast<char*>(value));
return static_cast<Result>(result);
}
Result LobbyTransaction::DeleteMetadata(MetadataKey key)
{
auto result = internal_->delete_metadata(internal_, const_cast<char*>(key));
return static_cast<Result>(result);
}
Result LobbyTransaction::SetLocked(bool locked)
{
auto result = internal_->set_locked(internal_, (locked ? 1 : 0));
return static_cast<Result>(result);
}
Result LobbyMemberTransaction::SetMetadata(MetadataKey key, MetadataValue value)
{
auto result =
internal_->set_metadata(internal_, const_cast<char*>(key), const_cast<char*>(value));
return static_cast<Result>(result);
}
Result LobbyMemberTransaction::DeleteMetadata(MetadataKey key)
{
auto result = internal_->delete_metadata(internal_, const_cast<char*>(key));
return static_cast<Result>(result);
}
Result LobbySearchQuery::Filter(MetadataKey key,
LobbySearchComparison comparison,
LobbySearchCast cast,
MetadataValue value)
{
auto result = internal_->filter(internal_,
const_cast<char*>(key),
static_cast<EDiscordLobbySearchComparison>(comparison),
static_cast<EDiscordLobbySearchCast>(cast),
const_cast<char*>(value));
return static_cast<Result>(result);
}
Result LobbySearchQuery::Sort(MetadataKey key, LobbySearchCast cast, MetadataValue value)
{
auto result = internal_->sort(internal_,
const_cast<char*>(key),
static_cast<EDiscordLobbySearchCast>(cast),
const_cast<char*>(value));
return static_cast<Result>(result);
}
Result LobbySearchQuery::Limit(std::uint32_t limit)
{
auto result = internal_->limit(internal_, limit);
return static_cast<Result>(result);
}
Result LobbySearchQuery::Distance(LobbySearchDistance distance)
{
auto result =
internal_->distance(internal_, static_cast<EDiscordLobbySearchDistance>(distance));
return static_cast<Result>(result);
}
} // namespace discord

View File

@ -0,0 +1,491 @@
#pragma once
#include "ffi.h"
#include "event.h"
namespace discord {
enum class Result {
Ok = 0,
ServiceUnavailable = 1,
InvalidVersion = 2,
LockFailed = 3,
InternalError = 4,
InvalidPayload = 5,
InvalidCommand = 6,
InvalidPermissions = 7,
NotFetched = 8,
NotFound = 9,
Conflict = 10,
InvalidSecret = 11,
InvalidJoinSecret = 12,
NoEligibleActivity = 13,
InvalidInvite = 14,
NotAuthenticated = 15,
InvalidAccessToken = 16,
ApplicationMismatch = 17,
InvalidDataUrl = 18,
InvalidBase64 = 19,
NotFiltered = 20,
LobbyFull = 21,
InvalidLobbySecret = 22,
InvalidFilename = 23,
InvalidFileSize = 24,
InvalidEntitlement = 25,
NotInstalled = 26,
NotRunning = 27,
InsufficientBuffer = 28,
PurchaseCanceled = 29,
InvalidGuild = 30,
InvalidEvent = 31,
InvalidChannel = 32,
InvalidOrigin = 33,
RateLimited = 34,
OAuth2Error = 35,
SelectChannelTimeout = 36,
GetGuildTimeout = 37,
SelectVoiceForceRequired = 38,
CaptureShortcutAlreadyListening = 39,
UnauthorizedForAchievement = 40,
InvalidGiftCode = 41,
PurchaseError = 42,
TransactionAborted = 43,
};
enum class CreateFlags {
Default = 0,
NoRequireDiscord = 1,
};
enum class LogLevel {
Error = 1,
Warn,
Info,
Debug,
};
enum class UserFlag {
Partner = 2,
HypeSquadEvents = 4,
HypeSquadHouse1 = 64,
HypeSquadHouse2 = 128,
HypeSquadHouse3 = 256,
};
enum class PremiumType {
None = 0,
Tier1 = 1,
Tier2 = 2,
};
enum class ImageType {
User,
};
enum class ActivityType {
Playing,
Streaming,
Listening,
Watching,
};
enum class ActivityActionType {
Join = 1,
Spectate,
};
enum class ActivityJoinRequestReply {
No,
Yes,
Ignore,
};
enum class Status {
Offline = 0,
Online = 1,
Idle = 2,
DoNotDisturb = 3,
};
enum class RelationshipType {
None,
Friend,
Blocked,
PendingIncoming,
PendingOutgoing,
Implicit,
};
enum class LobbyType {
Private = 1,
Public,
};
enum class LobbySearchComparison {
LessThanOrEqual = -2,
LessThan,
Equal,
GreaterThan,
GreaterThanOrEqual,
NotEqual,
};
enum class LobbySearchCast {
String = 1,
Number,
};
enum class LobbySearchDistance {
Local,
Default,
Extended,
Global,
};
enum class EntitlementType {
Purchase = 1,
PremiumSubscription,
DeveloperGift,
TestModePurchase,
FreePurchase,
UserGift,
PremiumPurchase,
};
enum class SkuType {
Application = 1,
DLC,
Consumable,
Bundle,
};
enum class InputModeType {
VoiceActivity = 0,
PushToTalk,
};
using ClientId = std::int64_t;
using Version = std::int32_t;
using Snowflake = std::int64_t;
using Timestamp = std::int64_t;
using UserId = Snowflake;
using Locale = char const*;
using Branch = char const*;
using LobbyId = Snowflake;
using LobbySecret = char const*;
using MetadataKey = char const*;
using MetadataValue = char const*;
using NetworkPeerId = std::uint64_t;
using NetworkChannelId = std::uint8_t;
using Path = char const*;
using DateTime = char const*;
class User final {
public:
void SetId(UserId id);
UserId GetId() const;
void SetUsername(char const* username);
char const* GetUsername() const;
void SetDiscriminator(char const* discriminator);
char const* GetDiscriminator() const;
void SetAvatar(char const* avatar);
char const* GetAvatar() const;
void SetBot(bool bot);
bool GetBot() const;
private:
DiscordUser internal_;
};
class OAuth2Token final {
public:
void SetAccessToken(char const* accessToken);
char const* GetAccessToken() const;
void SetScopes(char const* scopes);
char const* GetScopes() const;
void SetExpires(Timestamp expires);
Timestamp GetExpires() const;
private:
DiscordOAuth2Token internal_;
};
class ImageHandle final {
public:
void SetType(ImageType type);
ImageType GetType() const;
void SetId(std::int64_t id);
std::int64_t GetId() const;
void SetSize(std::uint32_t size);
std::uint32_t GetSize() const;
private:
DiscordImageHandle internal_;
};
class ImageDimensions final {
public:
void SetWidth(std::uint32_t width);
std::uint32_t GetWidth() const;
void SetHeight(std::uint32_t height);
std::uint32_t GetHeight() const;
private:
DiscordImageDimensions internal_;
};
class ActivityTimestamps final {
public:
void SetStart(Timestamp start);
Timestamp GetStart() const;
void SetEnd(Timestamp end);
Timestamp GetEnd() const;
private:
DiscordActivityTimestamps internal_;
};
class ActivityAssets final {
public:
void SetLargeImage(char const* largeImage);
char const* GetLargeImage() const;
void SetLargeText(char const* largeText);
char const* GetLargeText() const;
void SetSmallImage(char const* smallImage);
char const* GetSmallImage() const;
void SetSmallText(char const* smallText);
char const* GetSmallText() const;
private:
DiscordActivityAssets internal_;
};
class PartySize final {
public:
void SetCurrentSize(std::int32_t currentSize);
std::int32_t GetCurrentSize() const;
void SetMaxSize(std::int32_t maxSize);
std::int32_t GetMaxSize() const;
private:
DiscordPartySize internal_;
};
class ActivityParty final {
public:
void SetId(char const* id);
char const* GetId() const;
PartySize& GetSize();
PartySize const& GetSize() const;
private:
DiscordActivityParty internal_;
};
class ActivitySecrets final {
public:
void SetMatch(char const* match);
char const* GetMatch() const;
void SetJoin(char const* join);
char const* GetJoin() const;
void SetSpectate(char const* spectate);
char const* GetSpectate() const;
private:
DiscordActivitySecrets internal_;
};
class Activity final {
public:
void SetType(ActivityType type);
ActivityType GetType() const;
void SetApplicationId(std::int64_t applicationId);
std::int64_t GetApplicationId() const;
void SetName(char const* name);
char const* GetName() const;
void SetState(char const* state);
char const* GetState() const;
void SetDetails(char const* details);
char const* GetDetails() const;
ActivityTimestamps& GetTimestamps();
ActivityTimestamps const& GetTimestamps() const;
ActivityAssets& GetAssets();
ActivityAssets const& GetAssets() const;
ActivityParty& GetParty();
ActivityParty const& GetParty() const;
ActivitySecrets& GetSecrets();
ActivitySecrets const& GetSecrets() const;
void SetInstance(bool instance);
bool GetInstance() const;
private:
DiscordActivity internal_;
};
class Presence final {
public:
void SetStatus(Status status);
Status GetStatus() const;
Activity& GetActivity();
Activity const& GetActivity() const;
private:
DiscordPresence internal_;
};
class Relationship final {
public:
void SetType(RelationshipType type);
RelationshipType GetType() const;
User& GetUser();
User const& GetUser() const;
Presence& GetPresence();
Presence const& GetPresence() const;
private:
DiscordRelationship internal_;
};
class Lobby final {
public:
void SetId(LobbyId id);
LobbyId GetId() const;
void SetType(LobbyType type);
LobbyType GetType() const;
void SetOwnerId(UserId ownerId);
UserId GetOwnerId() const;
void SetSecret(LobbySecret secret);
LobbySecret GetSecret() const;
void SetCapacity(std::uint32_t capacity);
std::uint32_t GetCapacity() const;
void SetLocked(bool locked);
bool GetLocked() const;
private:
DiscordLobby internal_;
};
class FileStat final {
public:
void SetFilename(char const* filename);
char const* GetFilename() const;
void SetSize(std::uint64_t size);
std::uint64_t GetSize() const;
void SetLastModified(std::uint64_t lastModified);
std::uint64_t GetLastModified() const;
private:
DiscordFileStat internal_;
};
class Entitlement final {
public:
void SetId(Snowflake id);
Snowflake GetId() const;
void SetType(EntitlementType type);
EntitlementType GetType() const;
void SetSkuId(Snowflake skuId);
Snowflake GetSkuId() const;
private:
DiscordEntitlement internal_;
};
class SkuPrice final {
public:
void SetAmount(std::uint32_t amount);
std::uint32_t GetAmount() const;
void SetCurrency(char const* currency);
char const* GetCurrency() const;
private:
DiscordSkuPrice internal_;
};
class Sku final {
public:
void SetId(Snowflake id);
Snowflake GetId() const;
void SetType(SkuType type);
SkuType GetType() const;
void SetName(char const* name);
char const* GetName() const;
SkuPrice& GetPrice();
SkuPrice const& GetPrice() const;
private:
DiscordSku internal_;
};
class InputMode final {
public:
void SetType(InputModeType type);
InputModeType GetType() const;
void SetShortcut(char const* shortcut);
char const* GetShortcut() const;
private:
DiscordInputMode internal_;
};
class UserAchievement final {
public:
void SetUserId(Snowflake userId);
Snowflake GetUserId() const;
void SetAchievementId(Snowflake achievementId);
Snowflake GetAchievementId() const;
void SetPercentComplete(std::uint8_t percentComplete);
std::uint8_t GetPercentComplete() const;
void SetUnlockedAt(DateTime unlockedAt);
DateTime GetUnlockedAt() const;
private:
DiscordUserAchievement internal_;
};
class LobbyTransaction final {
public:
Result SetType(LobbyType type);
Result SetOwner(UserId ownerId);
Result SetCapacity(std::uint32_t capacity);
Result SetMetadata(MetadataKey key, MetadataValue value);
Result DeleteMetadata(MetadataKey key);
Result SetLocked(bool locked);
IDiscordLobbyTransaction** Receive() { return &internal_; }
IDiscordLobbyTransaction* Internal() { return internal_; }
private:
IDiscordLobbyTransaction* internal_;
};
class LobbyMemberTransaction final {
public:
Result SetMetadata(MetadataKey key, MetadataValue value);
Result DeleteMetadata(MetadataKey key);
IDiscordLobbyMemberTransaction** Receive() { return &internal_; }
IDiscordLobbyMemberTransaction* Internal() { return internal_; }
private:
IDiscordLobbyMemberTransaction* internal_;
};
class LobbySearchQuery final {
public:
Result Filter(MetadataKey key,
LobbySearchComparison comparison,
LobbySearchCast cast,
MetadataValue value);
Result Sort(MetadataKey key, LobbySearchCast cast, MetadataValue value);
Result Limit(std::uint32_t limit);
Result Distance(LobbySearchDistance distance);
IDiscordLobbySearchQuery** Receive() { return &internal_; }
IDiscordLobbySearchQuery* Internal() { return internal_; }
private:
IDiscordLobbySearchQuery* internal_;
};
} // namespace discord

View File

@ -0,0 +1,80 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "user_manager.h"
#include "core.h"
#include <cstring>
#include <memory>
namespace discord {
class UserEvents final {
public:
static void OnCurrentUserUpdate(void* callbackData)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->UserManager();
module.OnCurrentUserUpdate();
}
};
IDiscordUserEvents UserManager::events_{
&UserEvents::OnCurrentUserUpdate,
};
Result UserManager::GetCurrentUser(User* currentUser)
{
if (!currentUser) {
return Result::InternalError;
}
auto result =
internal_->get_current_user(internal_, reinterpret_cast<DiscordUser*>(currentUser));
return static_cast<Result>(result);
}
void UserManager::GetUser(UserId userId, std::function<void(Result, User const&)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result, DiscordUser* user) -> void {
std::unique_ptr<std::function<void(Result, User const&)>> cb(
reinterpret_cast<std::function<void(Result, User const&)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result), *reinterpret_cast<User const*>(user));
};
std::unique_ptr<std::function<void(Result, User const&)>> cb{};
cb.reset(new std::function<void(Result, User const&)>(std::move(callback)));
internal_->get_user(internal_, userId, cb.release(), wrapper);
}
Result UserManager::GetCurrentUserPremiumType(PremiumType* premiumType)
{
if (!premiumType) {
return Result::InternalError;
}
auto result = internal_->get_current_user_premium_type(
internal_, reinterpret_cast<EDiscordPremiumType*>(premiumType));
return static_cast<Result>(result);
}
Result UserManager::CurrentUserHasFlag(UserFlag flag, bool* hasFlag)
{
if (!hasFlag) {
return Result::InternalError;
}
auto result = internal_->current_user_has_flag(
internal_, static_cast<EDiscordUserFlag>(flag), reinterpret_cast<bool*>(hasFlag));
return static_cast<Result>(result);
}
} // namespace discord

View File

@ -0,0 +1,31 @@
#pragma once
#include "types.h"
namespace discord {
class UserManager final {
public:
~UserManager() = default;
Result GetCurrentUser(User* currentUser);
void GetUser(UserId userId, std::function<void(Result, User const&)> callback);
Result GetCurrentUserPremiumType(PremiumType* premiumType);
Result CurrentUserHasFlag(UserFlag flag, bool* hasFlag);
Event<> OnCurrentUserUpdate;
private:
friend class Core;
UserManager() = default;
UserManager(UserManager const& rhs) = delete;
UserManager& operator=(UserManager const& rhs) = delete;
UserManager(UserManager&& rhs) = delete;
UserManager& operator=(UserManager&& rhs) = delete;
IDiscordUserManager* internal_;
static IDiscordUserEvents events_;
};
} // namespace discord

View File

@ -0,0 +1,124 @@
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "voice_manager.h"
#include "core.h"
#include <cstring>
#include <memory>
namespace discord {
class VoiceEvents final {
public:
static void OnSettingsUpdate(void* callbackData)
{
auto* core = reinterpret_cast<Core*>(callbackData);
if (!core) {
return;
}
auto& module = core->VoiceManager();
module.OnSettingsUpdate();
}
};
IDiscordVoiceEvents VoiceManager::events_{
&VoiceEvents::OnSettingsUpdate,
};
Result VoiceManager::GetInputMode(InputMode* inputMode)
{
if (!inputMode) {
return Result::InternalError;
}
auto result =
internal_->get_input_mode(internal_, reinterpret_cast<DiscordInputMode*>(inputMode));
return static_cast<Result>(result);
}
void VoiceManager::SetInputMode(InputMode inputMode, std::function<void(Result)> callback)
{
static auto wrapper = [](void* callbackData, EDiscordResult result) -> void {
std::unique_ptr<std::function<void(Result)>> cb(
reinterpret_cast<std::function<void(Result)>*>(callbackData));
if (!cb || !(*cb)) {
return;
}
(*cb)(static_cast<Result>(result));
};
std::unique_ptr<std::function<void(Result)>> cb{};
cb.reset(new std::function<void(Result)>(std::move(callback)));
internal_->set_input_mode(
internal_, *reinterpret_cast<DiscordInputMode const*>(&inputMode), cb.release(), wrapper);
}
Result VoiceManager::IsSelfMute(bool* mute)
{
if (!mute) {
return Result::InternalError;
}
auto result = internal_->is_self_mute(internal_, reinterpret_cast<bool*>(mute));
return static_cast<Result>(result);
}
Result VoiceManager::SetSelfMute(bool mute)
{
auto result = internal_->set_self_mute(internal_, (mute ? 1 : 0));
return static_cast<Result>(result);
}
Result VoiceManager::IsSelfDeaf(bool* deaf)
{
if (!deaf) {
return Result::InternalError;
}
auto result = internal_->is_self_deaf(internal_, reinterpret_cast<bool*>(deaf));
return static_cast<Result>(result);
}
Result VoiceManager::SetSelfDeaf(bool deaf)
{
auto result = internal_->set_self_deaf(internal_, (deaf ? 1 : 0));
return static_cast<Result>(result);
}
Result VoiceManager::IsLocalMute(Snowflake userId, bool* mute)
{
if (!mute) {
return Result::InternalError;
}
auto result = internal_->is_local_mute(internal_, userId, reinterpret_cast<bool*>(mute));
return static_cast<Result>(result);
}
Result VoiceManager::SetLocalMute(Snowflake userId, bool mute)
{
auto result = internal_->set_local_mute(internal_, userId, (mute ? 1 : 0));
return static_cast<Result>(result);
}
Result VoiceManager::GetLocalVolume(Snowflake userId, std::uint8_t* volume)
{
if (!volume) {
return Result::InternalError;
}
auto result =
internal_->get_local_volume(internal_, userId, reinterpret_cast<uint8_t*>(volume));
return static_cast<Result>(result);
}
Result VoiceManager::SetLocalVolume(Snowflake userId, std::uint8_t volume)
{
auto result = internal_->set_local_volume(internal_, userId, volume);
return static_cast<Result>(result);
}
} // namespace discord

View File

@ -0,0 +1,37 @@
#pragma once
#include "types.h"
namespace discord {
class VoiceManager final {
public:
~VoiceManager() = default;
Result GetInputMode(InputMode* inputMode);
void SetInputMode(InputMode inputMode, std::function<void(Result)> callback);
Result IsSelfMute(bool* mute);
Result SetSelfMute(bool mute);
Result IsSelfDeaf(bool* deaf);
Result SetSelfDeaf(bool deaf);
Result IsLocalMute(Snowflake userId, bool* mute);
Result SetLocalMute(Snowflake userId, bool mute);
Result GetLocalVolume(Snowflake userId, std::uint8_t* volume);
Result SetLocalVolume(Snowflake userId, std::uint8_t volume);
Event<> OnSettingsUpdate;
private:
friend class Core;
VoiceManager() = default;
VoiceManager(VoiceManager const& rhs) = delete;
VoiceManager& operator=(VoiceManager const& rhs) = delete;
VoiceManager(VoiceManager&& rhs) = delete;
VoiceManager& operator=(VoiceManager&& rhs) = delete;
IDiscordVoiceManager* internal_;
static IDiscordVoiceEvents events_;
};
} // namespace discord

View File

@ -0,0 +1,12 @@
using System;
namespace Discord
{
public partial class ActivityManager
{
public void RegisterCommand()
{
RegisterCommand(null);
}
}
}

View File

@ -0,0 +1,9 @@
using System;
namespace Discord
{
static class Constants
{
public const string DllName = "discord_game_sdk";
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
using System;
using System.Runtime.InteropServices;
#if UNITY_EDITOR || UNITY_STANDALONE
using UnityEngine;
#endif
namespace Discord
{
public partial struct ImageHandle
{
static public ImageHandle User(Int64 id)
{
return User(id, 128);
}
static public ImageHandle User(Int64 id, UInt32 size)
{
return new ImageHandle
{
Type = ImageType.User,
Id = id,
Size = size,
};
}
}
public partial class ImageManager
{
public void Fetch(ImageHandle handle, FetchHandler callback)
{
Fetch(handle, false, callback);
}
public byte[] GetData(ImageHandle handle)
{
var dimensions = GetDimensions(handle);
var data = new byte[dimensions.Width * dimensions.Height * 4];
GetData(handle, data);
return data;
}
#if UNITY_EDITOR || UNITY_STANDALONE
public Texture2D GetTexture(ImageHandle handle)
{
var dimensions = GetDimensions(handle);
var texture = new Texture2D((int)dimensions.Width, (int)dimensions.Height, TextureFormat.RGBA32, false, true);
texture.LoadRawTextureData(GetData(handle));
texture.Apply();
return texture;
}
#endif
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
namespace Discord
{
public partial class LobbyManager
{
public IEnumerable<User> GetMemberUsers(Int64 lobbyID)
{
var memberCount = MemberCount(lobbyID);
var members = new List<User>();
for (var i = 0; i < memberCount; i++)
{
members.Add(GetMemberUser(lobbyID, GetMemberUserId(lobbyID, i)));
}
return members;
}
public void SendLobbyMessage(Int64 lobbyID, string data, SendLobbyMessageHandler handler)
{
SendLobbyMessage(lobbyID, Encoding.UTF8.GetBytes(data), handler);
}
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Discord
{
public partial class StorageManager
{
public IEnumerable<FileStat> Files()
{
var fileCount = Count();
var files = new List<FileStat>();
for (var i = 0; i < fileCount; i++)
{
files.Add(StatAt(i));
}
return files;
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
namespace Discord
{
public partial class StoreManager
{
public IEnumerable<Entitlement> GetEntitlements()
{
var count = CountEntitlements();
var entitlements = new List<Entitlement>();
for (var i = 0; i < count; i++)
{
entitlements.Add(GetEntitlementAt(i));
}
return entitlements;
}
public IEnumerable<Sku> GetSkus()
{
var count = CountSkus();
var skus = new List<Sku>();
for (var i = 0; i < count; i++)
{
skus.Add(GetSkuAt(i));
}
return skus;
}
}
}

View File

@ -0,0 +1,155 @@
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include "discord_game_sdk.h"
#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#include <string.h>
#endif
#define DISCORD_REQUIRE(x) assert(x == DiscordResult_Ok)
struct Application {
struct IDiscordCore* core;
struct IDiscordUserManager* users;
struct IDiscordAchievementManager* achievements;
struct IDiscordActivityManager* activities;
struct IDiscordRelationshipManager* relationships;
struct IDiscordApplicationManager* application;
struct IDiscordLobbyManager* lobbies;
DiscordUserId user_id;
};
void UpdateActivityCallback(void* data, enum EDiscordResult result)
{
DISCORD_REQUIRE(result);
}
int RelationshipPassFilter(void* data, struct DiscordRelationship* relationship)
{
return (relationship->type == DiscordRelationshipType_Friend);
}
int RelationshipSnowflakeFilter(void* data, struct DiscordRelationship* relationship)
{
struct Application* app = (struct Application*)data;
return (relationship->type == DiscordRelationshipType_Friend &&
relationship->user.id < app->user_id);
}
void OnRelationshipsRefresh(void* data)
{
struct Application* app = (struct Application*)data;
struct IDiscordRelationshipManager* module = app->relationships;
module->filter(module, app, RelationshipPassFilter);
int32_t unfiltered_count = 0;
DISCORD_REQUIRE(module->count(module, &unfiltered_count));
module->filter(module, app, RelationshipSnowflakeFilter);
int32_t filtered_count = 0;
DISCORD_REQUIRE(module->count(module, &filtered_count));
printf("=== Cool Friends ===\n");
for (int32_t i = 0; i < filtered_count; i += 1) {
struct DiscordRelationship relationship;
DISCORD_REQUIRE(module->get_at(module, i, &relationship));
printf("%lld %s#%s\n",
relationship.user.id,
relationship.user.username,
relationship.user.discriminator);
}
printf("(%d friends less cool than you omitted)\n", unfiltered_count - filtered_count);
struct DiscordActivity activity;
memset(&activity, 0, sizeof(activity));
sprintf(activity.details, "Cooler than %d friends", unfiltered_count - filtered_count);
sprintf(activity.state, "%d friends total", unfiltered_count);
app->activities->update_activity(app->activities, &activity, app, UpdateActivityCallback);
}
void OnUserUpdated(void* data)
{
struct Application* app = (struct Application*)data;
struct DiscordUser user;
app->users->get_current_user(app->users, &user);
app->user_id = user.id;
}
void OnOAuth2Token(void* data, enum EDiscordResult result, struct DiscordOAuth2Token* token)
{
if (result == DiscordResult_Ok) {
printf("OAuth2 token: %s\n", token->access_token);
}
else {
printf("GetOAuth2Token failed with %d\n", (int)result);
}
}
void OnLobbyConnect(void* data, enum EDiscordResult result, struct DiscordLobby* lobby)
{
printf("LobbyConnect returned %d\n", (int)result);
}
int main(int argc, char** argv)
{
struct Application app;
memset(&app, 0, sizeof(app));
struct IDiscordUserEvents users_events;
memset(&users_events, 0, sizeof(users_events));
users_events.on_current_user_update = OnUserUpdated;
struct IDiscordActivityEvents activities_events;
memset(&activities_events, 0, sizeof(activities_events));
struct IDiscordRelationshipEvents relationships_events;
memset(&relationships_events, 0, sizeof(relationships_events));
relationships_events.on_refresh = OnRelationshipsRefresh;
struct DiscordCreateParams params;
DiscordCreateParamsSetDefault(&params);
params.client_id = 418559331265675294;
params.flags = DiscordCreateFlags_Default;
params.event_data = &app;
params.activity_events = &activities_events;
params.relationship_events = &relationships_events;
params.user_events = &users_events;
DISCORD_REQUIRE(DiscordCreate(DISCORD_VERSION, &params, &app.core));
app.users = app.core->get_user_manager(app.core);
app.achievements = app.core->get_achievement_manager(app.core);
app.activities = app.core->get_activity_manager(app.core);
app.application = app.core->get_application_manager(app.core);
app.lobbies = app.core->get_lobby_manager(app.core);
app.lobbies->connect_lobby_with_activity_secret(
app.lobbies, "invalid_secret", &app, OnLobbyConnect);
app.application->get_oauth2_token(app.application, &app, OnOAuth2Token);
DiscordBranch branch;
app.application->get_current_branch(app.application, &branch);
printf("Current branch %s\n", branch);
app.relationships = app.core->get_relationship_manager(app.core);
for (;;) {
DISCORD_REQUIRE(app.core->run_callbacks(app.core));
#ifdef _WIN32
Sleep(16);
#else
usleep(16 * 1000);
#endif
}
return 0;
}

View File

@ -0,0 +1,297 @@
#define _CRT_SECURE_NO_WARNINGS
#include <array>
#include <cassert>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <thread>
#include <vector>
#include "discord.h"
#if defined(_WIN32)
#pragma pack(push, 1)
struct BitmapImageHeader {
uint32_t const structSize{sizeof(BitmapImageHeader)};
int32_t width{0};
int32_t height{0};
uint16_t const planes{1};
uint16_t const bpp{32};
uint32_t const pad0{0};
uint32_t const pad1{0};
uint32_t const hres{2835};
uint32_t const vres{2835};
uint32_t const pad4{0};
uint32_t const pad5{0};
BitmapImageHeader& operator=(BitmapImageHeader const&) = delete;
};
struct BitmapFileHeader {
uint8_t const magic0{'B'};
uint8_t const magic1{'M'};
uint32_t size{0};
uint32_t const pad{0};
uint32_t const offset{sizeof(BitmapFileHeader) + sizeof(BitmapImageHeader)};
BitmapFileHeader& operator=(BitmapFileHeader const&) = delete;
};
#pragma pack(pop)
#endif
struct DiscordState {
discord::User currentUser;
std::unique_ptr<discord::Core> core;
};
namespace {
volatile bool interrupted{false};
}
int main(int, char**)
{
DiscordState state{};
discord::Core* core{};
auto result = discord::Core::Create(310270644849737729, DiscordCreateFlags_Default, &core);
state.core.reset(core);
if (!state.core) {
std::cout << "Failed to instantiate discord core! (err " << static_cast<int>(result)
<< ")\n";
std::exit(-1);
}
state.core->SetLogHook(
discord::LogLevel::Debug, [](discord::LogLevel level, const char* message) {
std::cerr << "Log(" << static_cast<uint32_t>(level) << "): " << message << "\n";
});
core->UserManager().OnCurrentUserUpdate.Connect([&state]() {
state.core->UserManager().GetCurrentUser(&state.currentUser);
std::cout << "Current user updated: " << state.currentUser.GetUsername() << "#"
<< state.currentUser.GetDiscriminator() << "\n";
state.core->UserManager().GetUser(130050050968518656,
[](discord::Result result, discord::User const& user) {
if (result == discord::Result::Ok) {
std::cout << "Get " << user.GetUsername() << "\n";
}
else {
std::cout << "Failed to get David!\n";
}
});
discord::ImageHandle handle{};
handle.SetId(state.currentUser.GetId());
handle.SetType(discord::ImageType::User);
handle.SetSize(256);
state.core->ImageManager().Fetch(
handle, true, [&state](discord::Result res, discord::ImageHandle handle) {
if (res == discord::Result::Ok) {
discord::ImageDimensions dims{};
state.core->ImageManager().GetDimensions(handle, &dims);
std::cout << "Fetched " << dims.GetWidth() << "x" << dims.GetHeight()
<< " avatar!\n";
std::vector<uint8_t> data;
data.reserve(dims.GetWidth() * dims.GetHeight() * 4);
uint8_t* d = data.data();
state.core->ImageManager().GetData(handle, d, data.size());
#if defined(_WIN32)
auto fileSize =
data.size() + sizeof(BitmapImageHeader) + sizeof(BitmapFileHeader);
BitmapImageHeader imageHeader;
imageHeader.width = static_cast<int32_t>(dims.GetWidth());
imageHeader.height = static_cast<int32_t>(dims.GetHeight());
BitmapFileHeader fileHeader;
fileHeader.size = static_cast<uint32_t>(fileSize);
FILE* fp = fopen("avatar.bmp", "wb");
fwrite(&fileHeader, sizeof(BitmapFileHeader), 1, fp);
fwrite(&imageHeader, sizeof(BitmapImageHeader), 1, fp);
for (auto y = 0u; y < dims.GetHeight(); ++y) {
auto pixels = reinterpret_cast<uint32_t const*>(data.data());
auto invY = dims.GetHeight() - y - 1;
fwrite(
&pixels[invY * dims.GetWidth()], sizeof(uint32_t) * dims.GetWidth(), 1, fp);
}
fflush(fp);
fclose(fp);
#endif
}
else {
std::cout << "Failed fetching avatar. (err " << static_cast<int>(res) << ")\n";
}
});
});
state.core->ActivityManager().RegisterCommand("run/command/foo/bar/baz/here.exe");
state.core->ActivityManager().RegisterSteam(123123321);
state.core->ActivityManager().OnActivityJoin.Connect(
[](const char* secret) { std::cout << "Join " << secret << "\n"; });
state.core->ActivityManager().OnActivitySpectate.Connect(
[](const char* secret) { std::cout << "Spectate " << secret << "\n"; });
state.core->ActivityManager().OnActivityJoinRequest.Connect([](discord::User const& user) {
std::cout << "Join Request " << user.GetUsername() << "\n";
});
state.core->ActivityManager().OnActivityInvite.Connect(
[](discord::ActivityActionType, discord::User const& user, discord::Activity const&) {
std::cout << "Invite " << user.GetUsername() << "\n";
});
state.core->LobbyManager().OnLobbyUpdate.Connect(
[](std::int64_t lobbyId) { std::cout << "Lobby update " << lobbyId << "\n"; });
state.core->LobbyManager().OnLobbyDelete.Connect(
[](std::int64_t lobbyId, std::uint32_t reason) {
std::cout << "Lobby delete " << lobbyId << " (reason: " << reason << ")\n";
});
state.core->LobbyManager().OnMemberConnect.Connect(
[](std::int64_t lobbyId, std::int64_t userId) {
std::cout << "Lobby member connect " << lobbyId << " userId " << userId << "\n";
});
state.core->LobbyManager().OnMemberUpdate.Connect(
[](std::int64_t lobbyId, std::int64_t userId) {
std::cout << "Lobby member update " << lobbyId << " userId " << userId << "\n";
});
state.core->LobbyManager().OnMemberDisconnect.Connect(
[](std::int64_t lobbyId, std::int64_t userId) {
std::cout << "Lobby member disconnect " << lobbyId << " userId " << userId << "\n";
});
state.core->LobbyManager().OnLobbyMessage.Connect([&](std::int64_t lobbyId,
std::int64_t userId,
std::uint8_t* payload,
std::uint32_t payloadLength) {
std::vector<uint8_t> buffer{};
buffer.resize(payloadLength);
memcpy(buffer.data(), payload, payloadLength);
std::cout << "Lobby message " << lobbyId << " from " << userId << " of length "
<< payloadLength << " bytes.\n";
char fourtyNinetySix[4096];
state.core->LobbyManager().GetLobbyMetadataValue(lobbyId, "foo", fourtyNinetySix);
std::cout << "Metadata for key foo is " << fourtyNinetySix << "\n";
});
state.core->LobbyManager().OnSpeaking.Connect(
[&](std::int64_t, std::int64_t userId, bool speaking) {
std::cout << "User " << userId << " is " << (speaking ? "" : "NOT ") << "speaking.\n";
});
discord::Activity activity{};
activity.SetDetails("Fruit Tarts");
activity.SetState("Pop Snacks");
activity.GetAssets().SetSmallImage("the");
activity.GetAssets().SetSmallText("i mage");
activity.GetAssets().SetLargeImage("the");
activity.GetAssets().SetLargeText("u mage");
activity.SetType(discord::ActivityType::Playing);
state.core->ActivityManager().UpdateActivity(activity, [](discord::Result result) {
std::cout << ((result == discord::Result::Ok) ? "Succeeded" : "Failed")
<< " updating activity!\n";
});
discord::LobbyTransaction lobby{};
state.core->LobbyManager().GetLobbyCreateTransaction(&lobby);
lobby.SetCapacity(2);
lobby.SetMetadata("foo", "bar");
lobby.SetMetadata("baz", "bat");
lobby.SetType(discord::LobbyType::Public);
state.core->LobbyManager().CreateLobby(
lobby, [&state](discord::Result result, discord::Lobby const& lobby) {
if (result == discord::Result::Ok) {
std::cout << "Created lobby with secret " << lobby.GetSecret() << "\n";
std::array<uint8_t, 234> data{};
state.core->LobbyManager().SendLobbyMessage(
lobby.GetId(),
reinterpret_cast<uint8_t*>(data.data()),
data.size(),
[](discord::Result result) {
std::cout << "Sent message. Result: " << static_cast<int>(result) << "\n";
});
}
else {
std::cout << "Failed creating lobby. (err " << static_cast<int>(result) << ")\n";
}
discord::LobbySearchQuery query{};
state.core->LobbyManager().GetSearchQuery(&query);
query.Limit(1);
state.core->LobbyManager().Search(query, [&state](discord::Result result) {
if (result == discord::Result::Ok) {
std::int32_t lobbyCount{};
state.core->LobbyManager().LobbyCount(&lobbyCount);
std::cout << "Lobby search succeeded with " << lobbyCount << " lobbies.\n";
for (auto i = 0; i < lobbyCount; ++i) {
discord::LobbyId lobbyId{};
state.core->LobbyManager().GetLobbyId(i, &lobbyId);
std::cout << " " << lobbyId << "\n";
}
}
else {
std::cout << "Lobby search failed. (err " << static_cast<int>(result) << ")\n";
}
});
});
state.core->RelationshipManager().OnRefresh.Connect([&]() {
std::cout << "Relationships refreshed!\n";
state.core->RelationshipManager().Filter(
[](discord::Relationship const& relationship) -> bool {
return relationship.GetType() == discord::RelationshipType::Friend;
});
std::int32_t friendCount{0};
state.core->RelationshipManager().Count(&friendCount);
state.core->RelationshipManager().Filter(
[&](discord::Relationship const& relationship) -> bool {
return relationship.GetType() == discord::RelationshipType::Friend &&
relationship.GetUser().GetId() < state.currentUser.GetId();
});
std::int32_t filteredCount{0};
state.core->RelationshipManager().Count(&filteredCount);
discord::Relationship relationship{};
for (auto i = 0; i < filteredCount; ++i) {
state.core->RelationshipManager().GetAt(i, &relationship);
std::cout << relationship.GetUser().GetId() << " "
<< relationship.GetUser().GetUsername() << "#"
<< relationship.GetUser().GetDiscriminator() << "\n";
}
});
state.core->RelationshipManager().OnRelationshipUpdate.Connect(
[](discord::Relationship const& relationship) {
std::cout << "Relationship with " << relationship.GetUser().GetUsername()
<< " updated!\n";
});
std::signal(SIGINT, [](int) { interrupted = true; });
do {
state.core->RunCallbacks();
std::this_thread::sleep_for(std::chrono::milliseconds(16));
} while (!interrupted);
return 0;
}

View File

@ -0,0 +1,412 @@
using System;
using System.Linq;
using System.Threading;
using System.Text;
using System.Runtime.InteropServices;
class Program
{
// Request user's avatar data. Sizes can be powers of 2 between 16 and 2048
static void FetchAvatar(Discord.ImageManager imageManager, Int64 userID)
{
imageManager.Fetch(Discord.ImageHandle.User(userID), (result, handle) =>
{
{
if (result == Discord.Result.Ok)
{
// You can also use GetTexture2D within Unity.
// These return raw RGBA.
var data = imageManager.GetData(handle);
Console.WriteLine("image updated {0} {1}", handle.Id, data.Length);
}
else
{
Console.WriteLine("image error {0}", handle.Id);
}
}
});
}
// Update user's activity for your game.
// Party and secrets are vital.
// Read https://discordapp.com/developers/docs/rich-presence/how-to for more details.
static void UpdateActivity(Discord.Discord discord, Discord.Lobby lobby)
{
var activityManager = discord.GetActivityManager();
var lobbyManager = discord.GetLobbyManager();
var activity = new Discord.Activity
{
State = "olleh",
Details = "foo details",
Timestamps =
{
Start = 5,
End = 6,
},
Assets =
{
LargeImage = "foo largeImageKey",
LargeText = "foo largeImageText",
SmallImage = "foo smallImageKey",
SmallText = "foo smallImageText",
},
Party = {
Id = lobby.Id.ToString(),
Size = {
CurrentSize = lobbyManager.MemberCount(lobby.Id),
MaxSize = (int)lobby.Capacity,
},
},
Secrets = {
Join = lobbyManager.GetLobbyActivitySecret(lobby.Id),
},
Instance = true,
};
activityManager.UpdateActivity(activity, result =>
{
Console.WriteLine("Update Activity {0}", result);
// Send an invite to another user for this activity.
// Receiver should see an invite in their DM.
// Use a relationship user's ID for this.
// activityManager
// .SendInvite(
// 364843917537050624,
// Discord.ActivityActionType.Join,
// "",
// inviteResult =>
// {
// Console.WriteLine("Invite {0}", inviteResult);
// }
// );
});
}
static void Main(string[] args)
{
// Use your client ID from Discord's developer site.
var clientID = Environment.GetEnvironmentVariable("DISCORD_CLIENT_ID");
if (clientID == null)
{
clientID = "418559331265675294";
}
var discord = new Discord.Discord(Int64.Parse(clientID), (UInt64)Discord.CreateFlags.Default);
discord.SetLogHook(Discord.LogLevel.Debug, (level, message) =>
{
Console.WriteLine("Log[{0}] {1}", level, message);
});
var applicationManager = discord.GetApplicationManager();
// Get the current locale. This can be used to determine what text or audio the user wants.
Console.WriteLine("Current Locale: {0}", applicationManager.GetCurrentLocale());
// Get the current branch. For example alpha or beta.
Console.WriteLine("Current Branch: {0}", applicationManager.GetCurrentBranch());
// If you want to verify information from your game's server then you can
// grab the access token and send it to your server.
//
// This automatically looks for an environment variable passed by the Discord client,
// if it does not exist the Discord client will focus itself for manual authorization.
//
// By-default the SDK grants the identify and rpc scopes.
// Read more at https://discordapp.com/developers/docs/topics/oauth2
// applicationManager.GetOAuth2Token((Discord.Result result, ref Discord.OAuth2Token oauth2Token) =>
// {
// Console.WriteLine("Access Token {0}", oauth2Token.AccessToken);
// });
var activityManager = discord.GetActivityManager();
var lobbyManager = discord.GetLobbyManager();
// Received when someone accepts a request to join or invite.
// Use secrets to receive back the information needed to add the user to the group/party/match
activityManager.OnActivityJoin += secret =>
{
Console.WriteLine("OnJoin {0}", secret);
lobbyManager.ConnectLobbyWithActivitySecret(secret, (Discord.Result result, ref Discord.Lobby lobby) =>
{
Console.WriteLine("Connected to lobby: {0}", lobby.Id);
lobbyManager.ConnectNetwork(lobby.Id);
lobbyManager.OpenNetworkChannel(lobby.Id, 0, true);
foreach (var user in lobbyManager.GetMemberUsers(lobby.Id))
{
lobbyManager.SendNetworkMessage(lobby.Id, user.Id, 0,
Encoding.UTF8.GetBytes(String.Format("Hello, {0}!", user.Username)));
}
UpdateActivity(discord, lobby);
});
};
// Received when someone accepts a request to spectate
activityManager.OnActivitySpectate += secret =>
{
Console.WriteLine("OnSpectate {0}", secret);
};
// A join request has been received. Render the request on the UI.
activityManager.OnActivityJoinRequest += (ref Discord.User user) =>
{
Console.WriteLine("OnJoinRequest {0} {1}", user.Id, user.Username);
};
// An invite has been received. Consider rendering the user / activity on the UI.
activityManager.OnActivityInvite += (Discord.ActivityActionType Type, ref Discord.User user, ref Discord.Activity activity2) =>
{
Console.WriteLine("OnInvite {0} {1} {2}", Type, user.Username, activity2.Name);
// activityManager.AcceptInvite(user.Id, result =>
// {
// Console.WriteLine("AcceptInvite {0}", result);
// });
};
// This is used to register the game in the registry such that Discord can find it.
// This is only needed by games acquired from other platforms, like Steam.
// activityManager.RegisterCommand();
var imageManager = discord.GetImageManager();
var userManager = discord.GetUserManager();
// The auth manager fires events as information about the current user changes.
// This event will fire once on init.
//
// GetCurrentUser will error until this fires once.
userManager.OnCurrentUserUpdate += () =>
{
var currentUser = userManager.GetCurrentUser();
Console.WriteLine(currentUser.Username);
Console.WriteLine(currentUser.Id);
};
// If you store Discord user ids in a central place like a leaderboard and want to render them.
// The users manager can be used to fetch arbitrary Discord users. This only provides basic
// information and does not automatically update like relationships.
userManager.GetUser(450795363658366976, (Discord.Result result, ref Discord.User user) =>
{
if (result == Discord.Result.Ok)
{
Console.WriteLine("user fetched: {0}", user.Username);
// Request users's avatar data.
// This can only be done after a user is successfully fetched.
FetchAvatar(imageManager, user.Id);
}
else
{
Console.WriteLine("user fetch error: {0}", result);
}
});
var relationshipManager = discord.GetRelationshipManager();
// It is important to assign this handle right away to get the initial relationships refresh.
// This callback will only be fired when the whole list is initially loaded or was reset
relationshipManager.OnRefresh += () =>
{
// Filter a user's relationship list to be just friends
relationshipManager.Filter((ref Discord.Relationship relationship) => { return relationship.Type == Discord.RelationshipType.Friend; });
// Loop over all friends a user has.
Console.WriteLine("relationships updated: {0}", relationshipManager.Count());
for (var i = 0; i < Math.Min(relationshipManager.Count(), 10); i++)
{
// Get an individual relationship from the list
var r = relationshipManager.GetAt((uint)i);
Console.WriteLine("relationships: {0} {1} {2} {3}", r.Type, r.User.Username, r.Presence.Status, r.Presence.Activity.Name);
// Request relationship's avatar data.
FetchAvatar(imageManager, r.User.Id);
}
};
// All following relationship updates are delivered individually.
// These are fired when a user gets a new friend, removes a friend, or a relationship's presence changes.
relationshipManager.OnRelationshipUpdate += (ref Discord.Relationship r) =>
{
Console.WriteLine("relationship updated: {0} {1} {2} {3}", r.Type, r.User.Username, r.Presence.Status, r.Presence.Activity.Name);
};
lobbyManager.OnLobbyMessage += (lobbyID, userID, data) =>
{
Console.WriteLine("lobby message: {0} {1}", lobbyID, Encoding.UTF8.GetString(data));
};
lobbyManager.OnNetworkMessage += (lobbyId, userId, channelId, data) =>
{
Console.WriteLine("network message: {0} {1} {2} {3}", lobbyId, userId, channelId, Encoding.UTF8.GetString(data));
};
lobbyManager.OnSpeaking += (lobbyID, userID, speaking) =>
{
Console.WriteLine("lobby speaking: {0} {1} {2}", lobbyID, userID, speaking);
};
// Create a lobby.
var transaction = lobbyManager.GetLobbyCreateTransaction();
transaction.SetCapacity(6);
transaction.SetType(Discord.LobbyType.Public);
transaction.SetMetadata("a", "123");
transaction.SetMetadata("a", "456");
transaction.SetMetadata("b", "111");
transaction.SetMetadata("c", "222");
lobbyManager.CreateLobby(transaction, (Discord.Result result, ref Discord.Lobby lobby) =>
{
if (result != Discord.Result.Ok)
{
return;
}
// Check the lobby's configuration.
Console.WriteLine("lobby {0} with capacity {1} and secret {2}", lobby.Id, lobby.Capacity, lobby.Secret);
// Check lobby metadata.
foreach (var key in new string[] { "a", "b", "c" })
{
Console.WriteLine("{0} = {1}", key, lobbyManager.GetLobbyMetadataValue(lobby.Id, key));
}
// Print all the members of the lobby.
foreach (var user in lobbyManager.GetMemberUsers(lobby.Id))
{
Console.WriteLine("lobby member: {0}", user.Username);
}
// Send everyone a message.
lobbyManager.SendLobbyMessage(lobby.Id, "Hello from C#!", (_) =>
{
Console.WriteLine("sent message");
});
// Update lobby.
var lobbyTransaction = lobbyManager.GetLobbyUpdateTransaction(lobby.Id);
lobbyTransaction.SetMetadata("d", "e");
lobbyTransaction.SetCapacity(16);
lobbyManager.UpdateLobby(lobby.Id, lobbyTransaction, (_) =>
{
Console.WriteLine("lobby has been updated");
});
// Update a member.
var lobbyID = lobby.Id;
var userID = lobby.OwnerId;
var memberTransaction = lobbyManager.GetMemberUpdateTransaction(lobbyID, userID);
memberTransaction.SetMetadata("hello", "there");
lobbyManager.UpdateMember(lobbyID, userID, memberTransaction, (_) =>
{
Console.WriteLine("lobby member has been updated: {0}", lobbyManager.GetMemberMetadataValue(lobbyID, userID, "hello"));
});
// Search lobbies.
var query = lobbyManager.GetSearchQuery();
// Filter by a metadata value.
query.Filter("metadata.a", Discord.LobbySearchComparison.GreaterThan, Discord.LobbySearchCast.Number, "455");
query.Sort("metadata.a", Discord.LobbySearchCast.Number, "0");
// Only return 1 result max.
query.Limit(1);
lobbyManager.Search(query, (_) =>
{
Console.WriteLine("search returned {0} lobbies", lobbyManager.LobbyCount());
if (lobbyManager.LobbyCount() == 1)
{
Console.WriteLine("first lobby secret: {0}", lobbyManager.GetLobby(lobbyManager.GetLobbyId(0)).Secret);
}
});
// Connect to voice chat.
lobbyManager.ConnectVoice(lobby.Id, (_) =>
{
Console.WriteLine("Connected to voice chat!");
});
// Setup networking.
lobbyManager.ConnectNetwork(lobby.Id);
lobbyManager.OpenNetworkChannel(lobby.Id, 0, true);
// Update activity.
UpdateActivity(discord, lobby);
});
/*
var overlayManager = discord.GetOverlayManager();
overlayManager.OnOverlayLocked += locked =>
{
Console.WriteLine("Overlay Locked: {0}", locked);
};
overlayManager.SetLocked(false);
*/
var storageManager = discord.GetStorageManager();
var contents = new byte[20000];
var random = new Random();
random.NextBytes(contents);
Console.WriteLine("storage path: {0}", storageManager.GetPath());
storageManager.WriteAsync("foo", contents, res =>
{
var files = storageManager.Files();
foreach (var file in files)
{
Console.WriteLine("file: {0} size: {1} last_modified: {2}", file.Filename, file.Size, file.LastModified);
}
storageManager.ReadAsyncPartial("foo", 400, 50, (result, data) =>
{
Console.WriteLine("partial contents of foo match {0}", Enumerable.SequenceEqual(data, new ArraySegment<byte>(contents, 400, 50)));
});
storageManager.ReadAsync("foo", (result, data) =>
{
Console.WriteLine("length of contents {0} data {1}", contents.Length, data.Length);
Console.WriteLine("contents of foo match {0}", Enumerable.SequenceEqual(data, contents));
Console.WriteLine("foo exists? {0}", storageManager.Exists("foo"));
storageManager.Delete("foo");
Console.WriteLine("post-delete foo exists? {0}", storageManager.Exists("foo"));
});
});
var storeManager = discord.GetStoreManager();
storeManager.OnEntitlementCreate += (ref Discord.Entitlement entitlement) =>
{
Console.WriteLine("Entitlement Create1: {0}", entitlement.Id);
};
// Start a purchase flow.
// storeManager.StartPurchase(487507201519255552, result =>
// {
// if (result == Discord.Result.Ok)
// {
// Console.WriteLine("Purchase Complete");
// }
// else
// {
// Console.WriteLine("Purchase Canceled");
// }
// });
// Get all entitlements.
storeManager.FetchEntitlements(result =>
{
if (result == Discord.Result.Ok)
{
foreach (var entitlement in storeManager.GetEntitlements())
{
Console.WriteLine("entitlement: {0} - {1} {2}", entitlement.Id, entitlement.Type, entitlement.SkuId);
}
}
});
// Get all SKUs.
storeManager.FetchSkus(result =>
{
if (result == Discord.Result.Ok)
{
foreach (var sku in storeManager.GetSkus())
{
Console.WriteLine("sku: {0} - {1} {2}", sku.Name, sku.Price.Amount, sku.Price.Currency);
}
}
});
// Pump the event look to ensure all callbacks continue to get fired.
try
{
while (true)
{
discord.RunCallbacks();
lobbyManager.FlushNetwork();
Thread.Sleep(1000 / 60);
}
}
finally
{
discord.Dispose();
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -6,14 +6,17 @@ bgm = {
}
local current_bgm = nil
local pitch = 1
local bgm_locked = false
local unfocused = false
function switchBGM(sound, subsound)
if bgm_locked then
return
end
if current_bgm ~= nil then
current_bgm:stop()
end
if bgm_locked or config.bgm_volume <= 0 then
if config.bgm_volume <= 0 then
current_bgm = nil
elseif sound ~= nil then
if subsound ~= nil then
@ -67,25 +70,28 @@ function processBGMFadeout(dt)
fadeout_time = 0
fading_bgm = false
end
current_bgm:setVolume(fadeout_time * config.bgm_volume / total_fadeout_time)
current_bgm:setVolume(
fadeout_time * config.bgm_volume / total_fadeout_time
)
end
end
function pauseBGM(f)
if f then
unfocused = true
end
function pauseBGM()
if current_bgm ~= nil then
current_bgm:pause()
end
end
function resumeBGM(f)
if f and scene.paused and unfocused then
unfocused = false
return
end
function resumeBGM()
if current_bgm ~= nil then
current_bgm:play()
current_bgm:setPitch(pitch)
end
end
function pitchBGM(new_pitch)
pitch = new_pitch
if current_bgm ~= nil then
current_bgm:setPitch(pitch)
end
end

View File

@ -26,8 +26,18 @@ font_3x5_4 = love.graphics.newImageFont(
-4
)
font_8x11 = love.graphics.newImageFont(
"res/fonts/8x11_medium.png",
"0123456789:.",
-- this would be font_8x11 with the other one as 8x11_2
-- but that would break compatibility :(
font_8x11_small = love.graphics.newImageFont(
"res/fonts/8x11.png",
" 0123456789:;.,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" ..
"?!/\\^@$%<=>()*-+[]_&",
1
)
font_8x11 = love.graphics.newImageFont(
"res/fonts/8x11_medium.png",
" 0123456789:;.,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" ..
"?!/\\^@$%<=>()*-+[]_&",
1
)

13
load/gamesdk.lua Normal file
View File

@ -0,0 +1,13 @@
print("Loading Discord GameSDK...")
DiscordGameSDK = {
loaded = false
}
local success, libDiscordGameSDK = pcall(require, "libs.discordGameSDK")
if success then
DiscordGameSDK.loaded = true
print("Discord GameSDK successfully loaded")
else
print("Discord GameSDK failed to load!")
end

View File

@ -1,29 +1,106 @@
backgrounds = {
[0] = love.graphics.newImage("res/backgrounds/0.png"),
love.graphics.newImage("res/backgrounds/100.png"),
love.graphics.newImage("res/backgrounds/200.png"),
love.graphics.newImage("res/backgrounds/300.png"),
love.graphics.newImage("res/backgrounds/400.png"),
love.graphics.newImage("res/backgrounds/500.png"),
love.graphics.newImage("res/backgrounds/600.png"),
love.graphics.newImage("res/backgrounds/700.png"),
love.graphics.newImage("res/backgrounds/800.png"),
love.graphics.newImage("res/backgrounds/900.png"),
love.graphics.newImage("res/backgrounds/1000.png"),
love.graphics.newImage("res/backgrounds/1100.png"),
love.graphics.newImage("res/backgrounds/1200.png"),
love.graphics.newImage("res/backgrounds/1300.png"),
love.graphics.newImage("res/backgrounds/1400.png"),
love.graphics.newImage("res/backgrounds/1500.png"),
love.graphics.newImage("res/backgrounds/1600.png"),
love.graphics.newImage("res/backgrounds/1700.png"),
love.graphics.newImage("res/backgrounds/1800.png"),
love.graphics.newImage("res/backgrounds/1900.png"),
title = love.graphics.newImage("res/backgrounds/title.png"),
snow = love.graphics.newImage("res/backgrounds/snow.png"),
input_config = love.graphics.newImage("res/backgrounds/options-input.png"),
game_config = love.graphics.newImage("res/backgrounds/options-game.png"),
named_backgrounds = {
"title", "title_no_icon", "title_night",
"snow", "options_input", "options_game"
}
current_playing_bgs = {}
extended_bgs = {}
image_formats = {".jpg", ".png"}
bgpath = "res/backgrounds/"
dir = love.filesystem.getDirectoryItems(bgpath)
backgrounds = {}
local function loadExtendedBgs()
extended_bgs = require("res.backgrounds.extend_section_bg")
end
-- error handling for if there is no extend_section_bg
if pcall(loadExtendedBgs) then end
-- helper method to populate backgrounds
local function createBackgroundIfExists(name, file_name)
local format_index = 1
-- see if background is an extension of another background
if extended_bgs[file_name] ~= nil then
copy_bg = extended_bgs[file_name]
copy_bg = copy_bg / 100
backgrounds[name] = backgrounds[copy_bg]
return true
end
-- try creating image backgrounds
while format_index <= #image_formats do
for num, existing_file in pairs(dir) do
if existing_file == (file_name..image_formats[format_index]) then
local tempBgPath = bgpath .. file_name .. image_formats[format_index]
backgrounds[name] = love.graphics.newImage(tempBgPath)
return true
end
end
format_index = format_index + 1
end
-- try creating video background
if love.filesystem.getInfo(bgpath .. file_name .. ".ogv") then
for num, existing_file in pairs(dir) do
if existing_file == (file_name..".ogv") then
local tempBgPath = bgpath .. file_name .. ".ogv"
backgrounds[name] = love.graphics.newVideo(
tempBgPath, {["audio"] = false}
)
-- you can set audio to true, but the video will not loop
-- properly if audio extends beyond video frames
return true
end
end
end
return false
end
local function stopOtherBgs(bg)
if #current_playing_bgs == 0 and bg:typeOf("Video") then
current_playing_bgs[#current_playing_bgs+1] = bg
end
if #current_playing_bgs >= 1 then
while current_playing_bgs[1] ~= bg and #current_playing_bgs >= 1 do
current_playing_bgs[1]:pause()
current_playing_bgs[1]:rewind()
table.remove(current_playing_bgs, 1)
end
end
end
function fetchBackgroundAndLoop(id)
bg = backgrounds[id]
if bg:typeOf("Video") and not bg:isPlaying() then
bg:rewind()
bg:play()
end
stopOtherBgs(bg)
return bg
end
-- create section backgrounds
local section = 0
while (createBackgroundIfExists(section, section*100)) do
section = section + 1
end
-- create named backgrounds
local nbgIndex = 1
while nbgIndex <= #named_backgrounds do
createBackgroundIfExists(
named_backgrounds[nbgIndex],
string.gsub(named_backgrounds[nbgIndex], "_", "-")
)
nbgIndex = nbgIndex + 1
end
-- in order, the colors are:
-- red, orange, yellow, green, cyan, blue
@ -118,5 +195,19 @@ misc_graphics = {
go = love.graphics.newImage("res/img/go.png"),
select_mode = love.graphics.newImage("res/img/select_mode.png"),
strike = love.graphics.newImage("res/img/strike.png"),
santa = love.graphics.newImage("res/img/santa.png")
}
santa = love.graphics.newImage("res/img/santa.png"),
icon = love.graphics.newImage("res/img/cambridge_transparent.png")
}
-- utility function to allow any size background to be used
-- this will stretch the background to 4:3 aspect ratio
function drawBackground(id)
local bg_object = fetchBackgroundAndLoop(id)
local width = bg_object:getWidth()
local height = bg_object:getHeight()
love.graphics.draw(
bg_object,
0, 0, 0,
640 / width, 480 / height
)
end

View File

@ -1,63 +1,98 @@
sounds = {
sound_paths = {
blocks = {
I = love.audio.newSource("res/se/piece_i.wav", "static"),
J = love.audio.newSource("res/se/piece_j.wav", "static"),
L = love.audio.newSource("res/se/piece_l.wav", "static"),
O = love.audio.newSource("res/se/piece_o.wav", "static"),
S = love.audio.newSource("res/se/piece_s.wav", "static"),
T = love.audio.newSource("res/se/piece_t.wav", "static"),
Z = love.audio.newSource("res/se/piece_z.wav", "static")
I = "res/se/piece_i.wav",
J = "res/se/piece_j.wav",
L = "res/se/piece_l.wav",
O = "res/se/piece_o.wav",
S = "res/se/piece_s.wav",
T = "res/se/piece_t.wav",
Z = "res/se/piece_z.wav"
},
move = love.audio.newSource("res/se/move.wav", "static"),
bottom = love.audio.newSource("res/se/bottom.wav", "static"),
cursor = love.audio.newSource("res/se/cursor.wav", "static"),
cursor_lr = love.audio.newSource("res/se/cursor_lr.wav", "static"),
main_decide = love.audio.newSource("res/se/main_decide.wav", "static"),
mode_decide = love.audio.newSource("res/se/mode_decide.wav", "static"),
lock = love.audio.newSource("res/se/lock.wav", "static"),
hold = love.audio.newSource("res/se/hold.wav", "static"),
erase = love.audio.newSource("res/se/erase.wav", "static"),
fall = love.audio.newSource("res/se/fall.wav", "static"),
ready = love.audio.newSource("res/se/ready.wav", "static"),
go = love.audio.newSource("res/se/go.wav", "static"),
irs = love.audio.newSource("res/se/irs.wav", "static"),
ihs = love.audio.newSource("res/se/ihs.wav", "static"),
move = "res/se/move.wav",
rotate = "res/se/rotate.wav",
kick = "res/se/kick.wav",
bottom = "res/se/bottom.wav",
cursor = "res/se/cursor.wav",
cursor_lr = "res/se/cursor_lr.wav",
main_decide = "res/se/main_decide.wav",
mode_decide = "res/se/mode_decide.wav",
lock = "res/se/lock.wav",
hold = "res/se/hold.wav",
erase = {
single = "res/se/single.wav",
double = "res/se/double.wav",
triple = "res/se/triple.wav",
quad = "res/se/quad.wav"
},
fall = "res/se/fall.wav",
ready = "res/se/ready.wav",
go = "res/se/go.wav",
irs = "res/se/irs.wav",
ihs = "res/se/ihs.wav",
-- a secret sound!
welcome = love.audio.newSource("res/se/welcomeToCambridge.wav", "static"),
welcome = "res/se/welcomeToCambridge.wav",
}
sounds = {}
-- Replace each sound effect string with its love audiosource counterpart, but only if it exists. This lets the game handle missing SFX.
for k,v in pairs(sound_paths) do
if(type(v) == "table") then
-- list of subsounds
for k2,v2 in pairs(v) do
if(love.filesystem.getInfo(sound_paths[k][k2])) then
-- this file exists
sounds[k] = sounds[k] or {}
sounds[k][k2] = love.audio.newSource(sound_paths[k][k2], "static")
end
end
else
if(love.filesystem.getInfo(sound_paths[k])) then
-- this file exists
sounds[k] = love.audio.newSource(sound_paths[k], "static")
end
end
end
function playSE(sound, subsound)
if sound ~= nil then
if subsound ~= nil then
sounds[sound][subsound]:setVolume(config.sfx_volume)
if sounds[sound][subsound]:isPlaying() then
sounds[sound][subsound]:stop()
if sounds[sound] then
if subsound ~= nil then
if sounds[sound][subsound] then
sounds[sound][subsound]:setVolume(config.sfx_volume)
if sounds[sound][subsound]:isPlaying() then
sounds[sound][subsound]:stop()
end
sounds[sound][subsound]:play()
end
else
sounds[sound]:setVolume(config.sfx_volume)
if sounds[sound]:isPlaying() then
sounds[sound]:stop()
end
sounds[sound]:play()
end
sounds[sound][subsound]:play()
else
sounds[sound]:setVolume(config.sfx_volume)
if sounds[sound]:isPlaying() then
sounds[sound]:stop()
end
sounds[sound]:play()
end
end
end
function playSEOnce(sound, subsound)
if sound ~= nil then
if subsound ~= nil then
sounds[sound][subsound]:setVolume(config.sfx_volume)
if sounds[sound][subsound]:isPlaying() then
return
if sounds[sound] then
if subsound ~= nil then
if sounds[sound][subsound] then
sounds[sound][subsound]:setVolume(config.sfx_volume)
if sounds[sound][subsound]:isPlaying() then
return
end
sounds[sound][subsound]:play()
end
else
sounds[sound]:setVolume(config.sfx_volume)
if sounds[sound]:isPlaying() then
return
end
sounds[sound]:play()
end
sounds[sound][subsound]:play()
else
sounds[sound]:setVolume(config.sfx_volume)
if sounds[sound]:isPlaying() then
return
end
sounds[sound]:play()
end
end
end

View File

@ -1 +1 @@
version = "v0.3-beta6"
version = "v0.3.4"

View File

@ -1,6 +1,6 @@
function love.load()
math.randomseed(os.time())
highscores = {}
love.graphics.setDefaultFilter("linear", "nearest")
require "load.rpc"
require "load.graphics"
require "load.fonts"
@ -23,6 +23,11 @@ function love.load()
-- used for screenshots
GLOBAL_CANVAS = love.graphics.newCanvas()
-- aliasing to prevent people using math.random by accident
math.random = love.math.random
math.randomseed = love.math.setRandomSeed
math.randomseed(os.time())
-- init config
initConfig()
@ -34,6 +39,8 @@ function love.load()
end
function initModules()
-- replays are not loaded here, but they are cleared
replays = {}
game_modes = {}
mode_list = love.filesystem.getDirectoryItems("tetris/modes")
for i=1,#mode_list do
@ -63,7 +70,6 @@ function love.draw()
love.graphics.push()
-- get offset matrix
love.graphics.setDefaultFilter("linear", "nearest")
local width = love.graphics.getWidth()
local height = love.graphics.getHeight()
local scale_factor = math.min(width / 640, height / 480)
@ -74,6 +80,16 @@ function love.draw()
love.graphics.scale(scale_factor)
scene:render()
if config.gamesettings.display_gamemode == 1 or scene.title == "Title" then
love.graphics.setFont(font_3x5_2)
love.graphics.setColor(1, 1, 1, 1)
love.graphics.printf(
string.format("%.2f", 1.0 / love.timer.getAverageDelta()) ..
"fps - " .. version, 0, 460, 635, "right"
)
end
love.graphics.pop()
love.graphics.setCanvas()
@ -90,22 +106,23 @@ function love.keypressed(key, scancode)
elseif scancode == "f2" and scene.title ~= "Input Config" and scene.title ~= "Game" then
scene = InputConfigScene()
switchBGM(nil)
loadSave()
-- secret sound playing :eyes:
elseif scancode == "f8" and scene.title == "Title" then
config.secret = not config.secret
saveConfig()
scene.restart_message = true
if config.secret then playSE("mode_decide")
else playSE("erase") end
-- f12 is reserved for saving screenshots
elseif scancode == "f12" then
local ss_name = os.date("ss/%Y-%m-%d_%H-%M-%S.png")
else playSE("erase", "single") end
-- f12 is reserved for saving screenshots
elseif scancode == "f12" then
local ss_name = os.date("ss/%Y-%m-%d_%H-%M-%S.png")
local info = love.filesystem.getInfo("ss", "directory")
if not info then
love.filesystem.remove("ss")
love.filesystem.createDirectory("ss")
end
print("Saving screenshot as "..ss_name)
print("Saving screenshot as "..love.filesystem.getSaveDirectory().."/"..ss_name)
GLOBAL_CANVAS:newImageData():encode("png", ss_name)
-- function keys are reserved
elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then
@ -263,21 +280,17 @@ function love.wheelmoved(x, y)
scene:onInputPress({input=nil, type="wheel", x=x, y=y})
end
function love.focus(f)
if f then
resumeBGM(true)
else
pauseBGM(true)
end
end
function love.resize(w, h)
GLOBAL_CANVAS:release()
GLOBAL_CANVAS = love.graphics.newCanvas(w, h)
GLOBAL_CANVAS:release()
GLOBAL_CANVAS = love.graphics.newCanvas(w, h)
end
-- higher values of TARGET_FPS will make the game run "faster"
-- since the game is mostly designed for 60 FPS
local TARGET_FPS = 60
local FRAME_DURATION = 1.0 / TARGET_FPS
-- custom run function; optimizes game by syncing draw/update calls
function love.run()
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
@ -286,7 +299,7 @@ function love.run()
local dt = 0
local last_time = love.timer.getTime()
local time_accumulator = 0
local time_accumulator = 0.0
return function()
if love.event then
love.event.pump()
@ -306,25 +319,40 @@ function love.run()
if scene and scene.update and love.timer then
scene:update()
local frame_duration = 1.0 / TARGET_FPS
if time_accumulator < frame_duration then
if time_accumulator < FRAME_DURATION then
if love.graphics and love.graphics.isActive() and love.draw then
love.graphics.origin()
love.graphics.clear(love.graphics.getBackgroundColor())
love.draw()
love.graphics.present()
end
local end_time = last_time + frame_duration
local time = love.timer.getTime()
while time < end_time do
love.timer.sleep(0.001)
time = love.timer.getTime()
-- request 1ms delays first but stop short of overshooting, then do "0ms" delays without overshooting (0ms requests generally do a delay of some nonzero amount of time, but maybe less than 1ms)
for milliseconds=0.001,0.000,-0.001 do
local max_delay = 0.0
while max_delay < FRAME_DURATION do
local delay_start_time = love.timer.getTime()
if delay_start_time - last_time < FRAME_DURATION - max_delay then
love.timer.sleep(milliseconds)
local last_delay = love.timer.getTime() - delay_start_time
if last_delay > max_delay then
max_delay = last_delay
end
else
break
end
end
end
while love.timer.getTime() - last_time < FRAME_DURATION do
-- busy loop, do nothing here until delay is finished; delays above stop short of finishing, so this part can finish it off precisely
end
time_accumulator = time_accumulator + time - last_time
end
time_accumulator = time_accumulator - frame_duration
local finish_delay_time = love.timer.getTime()
local real_frame_duration = finish_delay_time - last_time
time_accumulator = time_accumulator + real_frame_duration - FRAME_DURATION
last_time = finish_delay_time
end
last_time = love.timer.getTime()
end
end

View File

@ -1 +1,3 @@
#!/bin/sh
zip -r cambridge.love libs load res scene tetris conf.lua main.lua scene.lua funcs.lua

View File

@ -1,4 +1,6 @@
./package
#!/bin/sh
./package-love.sh
mkdir dist
mkdir dist/windows
mkdir dist/win32
@ -8,4 +10,4 @@ zip dist/cambridge-windows.zip dist/windows/* SOURCES.md LICENSE.md
cat dist/win32/love.exe cambridge.love > dist/win32/cambridge.exe
zip dist/cambridge-win32.zip dist/win32/* SOURCES.md LICENSE.md
cp cambridge.love dist/other/
zip dist/cambridge-other.zip cambridge.love libs/discord-rpc.* SOURCES.md LICENSE.md
zip dist/cambridge-other.zip cambridge.love libs/discord-rpc.* SOURCES.md LICENSE.md

View File

@ -0,0 +1,14 @@
-- ex: extend_section_bg[100] = 0
-- extend_section_bg[200] = 0
-- the video background associated with section 0 will continue playing into 100 and 200 without restarting.
-- will also cause any existing level 100, 200 backgrounds specified to NOT render.
-- please also note that you cannot currently extend any "named" backgrounds, such as "title" and "options-input"
extend_section_bg = {}
-- extend_section_bg[100] = 0
-- extend_section_bg[200] = 0
-- remove the dashes
return extend_section_bg

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 591 B

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 734 B

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
res/img/rpc/1year.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

BIN
res/img/rpc/ingame-0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
res/img/rpc/ingame-100.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 816 KiB

BIN
res/img/rpc/ingame-1000.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
res/img/rpc/ingame-1100.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

BIN
res/img/rpc/ingame-1200.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
res/img/rpc/ingame-1300.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 KiB

BIN
res/img/rpc/ingame-1400.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
res/img/rpc/ingame-1500.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
res/img/rpc/ingame-1600.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
res/img/rpc/ingame-1700.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
res/img/rpc/ingame-1800.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
res/img/rpc/ingame-1900.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
res/img/rpc/ingame-200.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 KiB

BIN
res/img/rpc/ingame-300.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

BIN
res/img/rpc/ingame-400.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
res/img/rpc/ingame-500.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
res/img/rpc/ingame-600.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

BIN
res/img/rpc/ingame-700.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 KiB

BIN
res/img/rpc/ingame-800.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
res/img/rpc/ingame-900.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
res/img/rpc/snow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
res/se/double.wav Normal file

Binary file not shown.

BIN
res/se/quad.wav Normal file

Binary file not shown.

BIN
res/se/single.wav Normal file

Binary file not shown.

BIN
res/se/triple.wav Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More