Compare commits

..

258 commits

Author SHA1 Message Date
ROllerozxa
462369618e Turn TMS_USE_GLES compile-time option into a runtime use_gles setting
This of course requires support from the SDL library Principia is linked to, but should still make it more accessible to switch between the two on Linux
2026-06-23 23:38:23 +02:00
ROllerozxa
5865ce72ac Remove unused GUI sprite textures cache code
Never has been used and it doesn't seem like it really needs to be cached either
2026-06-23 00:26:40 +02:00
ROllerozxa
ac9f350134 Make user data storage persistent on Emscripten 2026-06-23 00:23:33 +02:00
ROllerozxa
e36bf6a9bc [ci skip] Add a CONTRIBUTING.md that just links to the wiki page 2026-06-22 20:20:51 +02:00
ROllerozxa
1b5dd42b4e [ci skip] Tell issue reporters not to use LLMs to write or "improve" the report 2026-06-22 20:14:12 +02:00
ROllerozxa
ff2e8252de occured -> occurred 2026-06-22 19:31:19 +02:00
ROllerozxa
ec68f7ca47 Some TMS header cleanups
Remove mostly redundant backend.h header, move print.h into core
2026-06-22 19:30:37 +02:00
ROllerozxa
b0cded7e5f Dehardcode some touchscreen-specific codepaths and put them behind touch_controls setting 2026-06-22 00:06:36 +02:00
ROllerozxa
21942f4c0e Fix the "Browse community levels" button glitching when resizing 2026-06-21 23:28:52 +02:00
ROllerozxa
b19e8106dc Fix Android CI 2026-06-21 21:59:53 +02:00
ROllerozxa
e7ddb1a19b Cleanup and hopefully improve the package level select menu
Unfortunately it doesn't entirely adapt to window resizing, but it's slightly better now... ;)
2026-06-21 21:56:36 +02:00
ROllerozxa
40928c047e Remove Luasocket library
This was never really used by anyone and considering it hasn't been updated ever since it was checked into the source tree in 2014 it's a bit of a security issue. It has been hidden behind a level flag for some time, no levels on the community site have the level flag set, and new levels with the flag are blocked from being uploaded.
2026-06-21 17:06:37 +02:00
ROllerozxa
7f87a48538 Add program for portable Windows builds to register a per-user protocol handler
Replaces the old play_community_level.bat Batch script that was bundled with portable
2026-06-21 16:13:53 +02:00
ROllerozxa
713331fe0e Installer: Properly scale and center logo based on display scaling 2026-06-21 00:23:12 +02:00
ROllerozxa
90fd1d87b9 Fix Windows CI 2026-06-20 21:35:41 +02:00
ROllerozxa
c209ca04ce Redesign Windows installer 2026-06-20 21:16:45 +02:00
ROllerozxa
068524c0a1 Call SDL_SetAppMetadata with metadata instead of just setting SDL_HINT_APP_NAME 2026-06-20 21:15:52 +02:00
ROllerozxa
0f0ee6a9aa Fix main menu background not adapting to window resize
Replace hardcoded shader global with uniform
2026-06-20 21:14:07 +02:00
ROllerozxa
99e16dc5a3 Merge branch 'backport-2026-06-19' 2026-06-19 20:00:25 +02:00
ROllerozxa
1596df98f6 Principia 2026.06.19 2026-06-19 19:21:18 +02:00
ROllerozxa
2be3199384 Make network header comparisons case insensitive 2026-06-19 19:06:38 +02:00
ROllerozxa
dc4d71e3e7 Make network header comparisons case insensitive 2026-06-19 19:00:48 +02:00
ROllerozxa
5b209b5e62 Uncomment sound thing in GTK dialogs
Was commented out during the SDL3 migration while sound was disabled
2026-06-19 17:27:25 +02:00
ROllerozxa
9422867597 Refactor Android Java code
Move everything Principia-specific from SDLActivity into PrincipiaActivity and update any references in the dialog code
2026-06-19 17:03:15 +02:00
ROllerozxa
6fb9160601 Rework main entrypoint to use SDL's callbacks instead
Means no special workaround needed on Emscripten to manage the main loop, among other things...
2026-06-19 16:35:33 +02:00
ROllerozxa
1e4dfe80e1 Replace custom UTF-8 step function with SDL_StepUTF8 2026-06-19 16:20:55 +02:00
ROllerozxa
55b1506b0d Fix black level background when doing unity build 2026-06-19 16:12:02 +02:00
ROllerozxa
303b9d2a2f Fix building utils 2026-06-19 00:31:59 +02:00
ROllerozxa
d623a95857 Use filename extensions for determining image format rather than magic 2026-06-19 00:13:04 +02:00
ROllerozxa
22c192b6d2 Remove unused main menu contest stuff
This was never used and didn't really work all that great when I tried implementing it in the featured list creator. Just clean up all references of it.
2026-06-18 22:09:35 +02:00
ROllerozxa
e9d944afa8 Turn some stray C source files in the main src directory into C++ 2026-06-18 21:58:57 +02:00
ROllerozxa
494de12927 Fix zoom and Apparatus grid salute gestures on Android 2026-06-18 20:10:52 +02:00
ROllerozxa
1add6eff33 Hopefully fix Linux CI 2026-06-18 19:30:43 +02:00
ROllerozxa
e1c948f166 Clean up Win32 API usage, explicitly use -W functions rather than defining UNICODE
Also fixes linkage issues with SDL's main wrapper
2026-06-18 19:30:18 +02:00
ROllerozxa
1968f347d2 Try to fix failing CI builds 2026-06-18 00:48:41 +02:00
ROllerozxa
d631ca3d55 Fix SDL3 Android build
Pinch to zoom no longer works which seems to be due to SDL finger IDs changing. There is a new pinch event specifically for this which should be used instead.
2026-06-18 00:28:38 +02:00
ROllerozxa
8dccfb17a4 Use SDL_SetWindowFillDocument on Emscripten to fill browser window 2026-06-18 00:05:25 +02:00
ROllerozxa
c07486f02f Fix SDL3 Windows build 2026-06-18 00:04:19 +02:00
ROllerozxa
73f0dd1195 Fix up CI builds to build with SDL3
Adds a new CMake option to build with a vendored copy of the latest version of SDL3, which gets downloaded during configuration.
2026-06-18 00:04:03 +02:00
ROllerozxa
e00585b9fe Make audio work again on SDL3
Currently using the legacy `sdl2-api-on-sdl3` branch of SDL_mixer, which isn't recommended to be used but works for now as the real SDL3_mixer has a completely different API.
2026-06-17 21:19:16 +02:00
ROllerozxa
15600f1682 Update SDL_image to latest in upstream
There were two indexed images with transparency that became messed up with the new SDL_image. I'm not sure why but I resaved them as non-indexed in GIMP, they grew a bit but now look fine.

Also replace savepng with SDL_image's IMG_SavePNG.
2026-06-17 20:10:28 +02:00
ROllerozxa
641b449286 Another round of SDL3 migration 2026-06-17 19:53:41 +02:00
ROllerozxa
74c7cdb517 Incomplete SDL3 port
WIP, Some things have been stubbed out for now.
2026-06-17 14:53:45 +02:00
ROllerozxa
f75299ee8d Add fallback for Windows cache dir if LOCALAPPDATA is undefined 2026-06-10 00:02:15 +02:00
ROllerozxa
0922b84a69 Fix building Dear Imgui backend on Windows 2026-06-09 23:45:23 +02:00
ROllerozxa
b55735c2a0 Fix unity build on Windows 2026-06-09 23:43:23 +02:00
ROllerozxa
4c395f09af Build TMS as a unity build too
The C portion of TMS is its own unity build chunk while the portions of TMS in C++ are lumped into the main chunk
2026-06-07 21:13:52 +02:00
ROllerozxa
1505be8191 Use #pragma once in TMS sources 2026-06-07 20:55:02 +02:00
ROllerozxa
a2b7870842 Clean up TMS includes in Principia code
Always only `#include <tms/cpp.hh>` in C++ source files to make sure everything gets included with the correct declarations (i.e. `extern "C"` for TMS C stuff)
2026-06-07 20:50:17 +02:00
ROllerozxa
9ffb133da5 Add experimental unity build support behind UNITY_BUILD compile option
It will build most of the main C++ codebase in one chunk, as well as build the entirety of Box2D in its own chunk. This should significantly improve build times for full builds.
2026-06-07 19:20:21 +02:00
ROllerozxa
76bd4d9c70 Undefine preprocessor defines that conflict across source files 2026-06-07 16:34:45 +02:00
ROllerozxa
df00758dfe Move some static global variables that cause collisions into static class members 2026-06-07 16:12:32 +02:00
ROllerozxa
e1ceb49cd2 Rename and deduplicate name colliding vert structs 2026-06-07 00:51:15 +02:00
ROllerozxa
a22c9ed7e6 Principia 2026.06.06 2026-06-06 13:24:48 +02:00
ROllerozxa
d54405e45c Add fastlane changelog for upcoming version 2026-06-06 13:03:35 +02:00
ROllerozxa
0ad08adab8 Deduplicate base LuaScript sprite verts 2026-06-05 21:43:09 +02:00
ROllerozxa
422e95b14c Clean up commented out code in wall pivot source file
Likely half-remaining remnants from when the wall pivot was like the static motor in Apparatus
2026-06-05 20:23:40 +02:00
ROllerozxa
a9fffcd18f Cleanup and minor refactoring in model.cc/hh 2026-06-05 20:22:28 +02:00
ROllerozxa
89ea9eebbd Move "initialized" variables for static class init into a class member 2026-06-05 19:49:33 +02:00
ROllerozxa
9580040c73 Readd #include <time.h> in pkgman.hh 2026-06-05 16:55:21 +02:00
ROllerozxa
689163b24e Extract some pkginfo methods out of header
Removes the dependency on progress.hh in pkgman.hh
2026-06-05 16:52:26 +02:00
ROllerozxa
a3ffe63962 Disable vsync when in a loading screen
This used to be the case but I removed it in 006f12e8d6 which made e.g. initial loading unnecessarily slow. Bring it back for now.
2026-06-05 16:25:45 +02:00
ROllerozxa
d14bf51465 Cleanups and minor refactoring in object_factory.cc/hh 2026-06-05 16:24:41 +02:00
ROllerozxa
f3e13c4a80 Cleanups and minor refactoring in main.cc/hh 2026-06-05 16:22:31 +02:00
ROllerozxa
eca1b4807b Bump Windows deps 2026-06-04 23:43:16 +02:00
ROllerozxa
c6be936430 Merge branch 'master' of github.com:Bithack/principia 2026-06-04 23:41:19 +02:00
ROllerozxa
6689542b27 Bump Android deps 2026-06-04 23:40:51 +02:00
Dimitris Dafnis
08ab103f44
Guard external URL launch in the in-game WebView (#215)
When the WebView opens a URL that is neither a principia: link nor a
community-host page, it hands it to an external app with
startActivity(ACTION_VIEW). On a device with no app able to open the URI
that call throws ActivityNotFoundException and the activity crashes.

Wrap the launch in a try/catch so an unresolvable link is logged and the
WebView dialog still closes cleanly.
2026-06-04 20:37:22 +02:00
ROllerozxa
de03bb63fe Remove unnecessary Windows-specific codepath for getting level modification date
mingw-w64 has historically provided polyfills for this, but seems like UCRT also provides this functionality nowadays, so no reason to keep this around
2026-06-03 20:51:14 +02:00
ROllerozxa
ef59cc871a Use real GL types for pipeline uniform functions 2026-06-03 19:07:00 +02:00
ROllerozxa
8246880adc Don't link against GTK3 libs if we're doing a desktop build with Imgui backend 2026-06-03 19:05:18 +02:00
ROllerozxa
814eaea412 Remove some unnecessary FILE_IN_ASSET usages
These methods are never used for loading the main puzzle package or levels on Android
2026-06-02 22:12:16 +02:00
ROllerozxa
63d60d6a45 Add progress-dump tool for dumping data.bin progress data 2026-06-02 21:29:56 +02:00
ROllerozxa
cfcc169661 Cleanup and minor refactoring of progress.cc/hh
Also document some stuff in the progress.hh header
2026-06-02 21:23:20 +02:00
ROllerozxa
2a8ad3df09 Deduplicate and reduce indentation in some pkgman methods 2026-06-02 21:09:48 +02:00
ROllerozxa
a9408d30ca Import Kaitai Struct files into utils/kaitai/
Originally maintained at https://github.com/principia-game/kaitai
2026-06-02 16:52:24 +02:00
ROllerozxa
10e05d687b Add package-creator tool for making package files from JSON data
Rewritten from the PackageCreator Python script to use Principia's own package writing utilities instead
2026-06-02 16:14:56 +02:00
ROllerozxa
6ea828e4d3 Fix up usage instructions for featured-list-creator
Make it more in line with how it is for the other util programs
2026-06-02 00:38:18 +02:00
ROllerozxa
66923575b4 Merge in featured-list-creator into utils/
Originally a C program (previously Python script) at https://github.com/principia-game/featured-list-creator for creating fl.cache files for the community site, merge into the main repository so it is with all the other util programs.
2026-06-02 00:31:44 +02:00
ROllerozxa
f564ba2e3f Fix move_matching_files Windows codepath in migration code
Need to turn strings wide for the UTF-16 Win32 API functions...
2026-05-31 21:49:16 +02:00
ROllerozxa
734fb3f8d7 Add lvlbuf-decompressor tool for decompressing level buffer
Rewritten from the original `level-decompressor` Python script into C++ using Principia's own level reader
2026-05-31 01:14:08 +02:00
ROllerozxa
71be99541b Add compiler flags for dead code removal in util programs 2026-05-31 00:17:48 +02:00
ROllerozxa
0051979187 Add lvl-icon-extractor tool for extracting icon from level files
Rewritten from the original `level-screenshot-converter` Python script into C++ using Principia's own level reader and libpng directly
2026-05-31 00:17:18 +02:00
ROllerozxa
01236f4b31 Move util programs back into main repository
Also includes new Makefiles for building them and a README in the main utils dir
2026-05-30 01:04:34 +02:00
ROllerozxa
f2413ac302 Cleanups in pkgman source file
Code cleanups, convert comments into annotations consumable by Doxygen, etc...
2026-05-30 00:49:13 +02:00
goodusername123
2a5a1e98ff
make Windows installer high DPI aware. (#213)
also flips on `XPStyle` to ensure newer styled UI controls are used.
2026-05-28 14:19:49 +02:00
ROllerozxa
cdb15b688b Fixes in imgui dialog code
Fixes for things that broke in a newer version of dear imgui & other bugfixes
2026-05-17 22:37:24 +02:00
ROllerozxa
b86f959b6f Update Dear Imgui to 93e396f 2026-05-17 22:35:13 +02:00
ROllerozxa
8771027650 Cleanups in entity source file
Code cleanups, convert comments into annotations consumable by Doxygen where applicable, renames and splits up the shape extruder object's class into a separate source files, etc...
2026-05-16 17:31:48 +02:00
ROllerozxa
fac177b9f1 Fix CI 2026-05-11 17:09:19 +02:00
ROllerozxa
1888998337 Comment out archive: false in CI workflows
nightly.link doesn't support bare artifacts yet
2026-05-11 16:55:11 +02:00
ROllerozxa
4eee1846ff Bump GitHub Actions action versions
Also use new `archive: false` for artifact uploading where appropriate to prevent nested zips from happening
2026-04-27 20:36:25 +02:00
ROllerozxa
e7a5b860c3 Flip suction cup model so that sockets are not inverted 2026-04-15 21:54:59 +02:00
ROllerozxa
e9893fc481 Fix Windows build on Clang 22 2026-04-15 21:41:44 +02:00
ROllerozxa
2c99bf67c4 Android: Open links outside of community host in external browser
The community site has links to all sorts of external websites that really does not like the webview, and the user likely wants them to be opened in an external browser in this case rather than be confined to the app's webview.
2026-03-25 00:18:55 +01:00
ROllerozxa
e83b594ef0 Refactor LuaScript code, split out API into separate files 2026-03-15 22:09:36 +01:00
ROllerozxa
b66c183655 Enable Luasocket on Android 2026-03-12 21:41:15 +01:00
ROllerozxa
f387183b5f Hide menu and quickadd buttons when category selector is open
Not a perfect way of doing it but gets them out of the way at least
2026-03-12 21:29:56 +01:00
ROllerozxa
647b1ca7ce Cleanup add_menu_item and related for items
Most of the stuff removed are remnants from when the objects in the sandbox menu was rendered live, so safe to remove. (The current sandbox menu texture creator does not make use of it either)
2026-03-12 21:28:33 +01:00
ROllerozxa
fbef2313e9 Minor fixes to the sandbox menu texture creation pipeline 2026-03-12 21:13:00 +01:00
ROllerozxa
7e54b9a3bc Revert "Remove remnants of unused "menu" pipeline"
This is still used by the sandbox menu texture creator
2026-03-12 17:06:50 +01:00
ROllerozxa
100f2815ab Add button to open external script folder in LuaScript dialog
For convenience...
2026-02-26 00:41:28 +01:00
ROllerozxa
1620ecaf5a Fix the Gearbox crashing when being placed down
Still very buggy and not available in the sandbox menu
2026-02-16 21:23:38 +01:00
ROllerozxa
24de6fb825 Minor preparations for being able to dynamically update UI scale
A lot of things in the game does not adapt to this quite yet
2026-02-16 20:26:42 +01:00
ROllerozxa
ba0c5e183b Try to fix the Principia window resizing during load on Windows
GTK will force DPI awareness so there's no way to do anything else other than enable it before GTK does
2026-02-16 00:16:02 +01:00
ROllerozxa
b46ecd8e05 Refactor out menu scale adjustment code into new function 2026-02-16 00:08:35 +01:00
ROllerozxa
b758f343a7 Make some more static variables in adventure non-static
These would break if xppcm and yppcm become dynamic sometime...
2026-02-16 00:06:23 +01:00
ROllerozxa
9584af22d1 Clean up some superfluous logging messages 2026-02-15 23:32:23 +01:00
ROllerozxa
8a174edb28 Fix font loading crash 2026-02-14 22:33:24 +01:00
ROllerozxa
45fc40fd59 Remove locked visibility check when trying to play a level
No point in these kinds of arbitrary checks in an open source project when it also inconveniences inspecting levels that have been locked
2026-01-15 23:56:51 +01:00
ROllerozxa
142e56b60f Rewrite sticky note text drawing code to not use SDL_ttf
Now uses the same font loading code that the GUI font uses, using the previously implemented extended charset to support extended ASCII (e.g. åäö). The easyspeech font does not support much beyond that so there should not be any difference in supported characters from before.
2026-01-11 20:59:08 +01:00
ROllerozxa
ba66b47246 Implement a special extended charset mode for font loading
Will load 256-CHAR_OFFSET amount of glyphs instead of the regular 128-CHAR_OFFSET (extended ASCII, or whatever you may call it). Regular GUI fonts won't use this for now.
2026-01-11 20:48:04 +01:00
ROllerozxa
9c421ffadc Increase the padding and spacing in imgui dialogs 2026-01-10 19:28:19 +01:00
ROllerozxa
786356968b Switch to imgui_freetype for rendering text in Imgui dialogs 2026-01-10 19:27:52 +01:00
ROllerozxa
3fd68448a0 Don't clear imgui login dialog fields if login failed 2026-01-10 19:15:08 +01:00
ROllerozxa
5ce14da7b5 Minor cleanups in some Imgui dialogs 2026-01-10 19:14:48 +01:00
ROllerozxa
c72b8f6646 Update Imgui to f5384544cb350dd2444c27c153ac563b91cf09da 2026-01-10 19:12:27 +01:00
ROllerozxa
c4e0a1ee01 Cleanup TMS_USE_GLES usage
Now that we use GLAD on both GL and GLES, we can rely on GL-only functions and constants existing when building, while remaining unused for GLES. The end goal would be making switching between GL and GLES a runtime setting on relevant platforms

Also cleanup some commented out GL code and sprinkled glGetError asserts
2026-01-10 16:45:27 +01:00
ROllerozxa
91695dafe7 Split off Imgui dialogs into one source file for each
Also refactor all other dialog backends into their own proper source files
2026-01-10 13:00:03 +01:00
ROllerozxa
820237874e Fix Emscripten build 2026-01-09 21:46:12 +01:00
ROllerozxa
5465fb7aef Use GLAD to retrieve glDiscardFramebufferEXT 2026-01-09 21:46:05 +01:00
ROllerozxa
d1c6804c33 Implement several dialogs in the imgui dialog backend
- DIALOG_ROBOT (#200)
- DIALOG_STICKY (#200)
- DIALOG_TREASURE_CHEST (#201)
- DIALOG_POLYGON (#202)
- Add register button to login dialog (#203)
- DIALOG_RUBBER (#204)
- DIALOG_DECORATION (#205)

Co-authored-by: gbsierra <gbatarseh@student.sierracollege.edu>
2026-01-02 21:22:01 +01:00
ROllerozxa
adf4e8ed23 Emscripten: Fix random lockups 2026-01-01 22:10:16 +01:00
ROllerozxa
3ea46595b8 Emscripten: Try to fill the page with the canvas window 2025-12-28 19:57:10 +01:00
ROllerozxa
296f930566 Emscripten: Build web version in CI 2025-12-28 19:55:32 +01:00
ROllerozxa
8b4b7f43ff Cleanup settings init and default values, adjust the defaults for emscripten 2025-12-28 19:28:19 +01:00
ROllerozxa
09dfe62860 Hardcode the default window size on Emscripten
Also minor cleanups to the main function and related things...
2025-12-28 19:22:11 +01:00
ROllerozxa
55c32eb8f3 Cleanup P.focused handling
Fixes P.focused never becoming true after logging in with GTK dialogs, also fixes P.focused never becoming true on emscripten because it had accidentally been moved to the curl init code
2025-12-28 19:15:23 +01:00
ROllerozxa
92e1e58c86 Add GL_ELEMENT_ARRAY_BUFFER to more index buffers
Fix more stuff in WebGL!
2025-12-28 18:49:24 +01:00
ROllerozxa
81d7731665 Emscripten: Implement downloading community levels
Adding ?play=[id] to the deployed HTML file will download and play that specific ID from the community site
2025-12-27 21:39:02 +01:00
ROllerozxa
848dce5262 Add GL_ELEMENT_ARRAY_BUFFER to index buffers
Fixes more or less all WebGL rendering issues when building Principia for the web
2025-12-27 21:29:38 +01:00
ROllerozxa
faba0b247e Use Imgui dialog backend for the web version 2025-12-27 17:12:31 +01:00
ROllerozxa
c55e5fff76 Set graphics settings to their lowest for the web version 2025-12-27 17:07:55 +01:00
ROllerozxa
9e5a166ba6 Minor refactoring of adventure mode GUI drawing 2025-12-27 17:02:55 +01:00
ROllerozxa
ecaef6d33a Don't update username if login isn't actually successful 2025-12-27 15:50:56 +01:00
ROllerozxa
cffeaf50d3 New storage directory and structure, migration of old storage dir
Closes #188
2025-12-04 22:27:31 +01:00
ROllerozxa
365856fffc Refactor some pkgman path code 2025-12-04 21:41:24 +01:00
ROllerozxa
894d974316 Strip the binary when building AppImage 2025-12-04 20:16:28 +01:00
ROllerozxa
a6704c8d8e Fix Imgui backend on GLES 2025-12-04 20:16:12 +01:00
ROllerozxa
2034ca87e6 Switch from GLEW to GLAD 2025-12-04 20:01:00 +01:00
ROllerozxa
8929a3bd86 set_version.lua: Update AppStream metainfo version info 2025-09-24 00:24:11 +02:00
ROllerozxa
8650947dae Upstream metainfo changes 2025-09-23 23:42:41 +02:00
ROllerozxa
3ca14754dd Bump Windows dependencies 2025-09-12 17:18:38 +02:00
ROllerozxa
250f1fb10b Use latest appimagetool with zstd compression 2025-09-12 17:15:54 +02:00
ROllerozxa
0104570ba2 Bump SDL2 Android version to 2.32.10 2025-09-12 17:14:47 +02:00
ROllerozxa
5d5e4cbb43 Add script to prepare release builds 2025-09-11 23:44:28 +02:00
ROllerozxa
55bb0c1ea7 Fix navigation bar obscuring game on Android 15
Closes #206, #211
2025-09-11 23:43:04 +02:00
krisbug4
f9e2feffd6
Make ore scaling proportional (#209) 2025-07-03 19:55:00 +02:00
krisbug4
04687679f2
Improve the appearance of simplebg borders (#207) 2025-07-03 15:13:41 +02:00
ROllerozxa
6154fd9654 Set SDL_HINT_APP_NAME 2025-07-01 16:09:45 +02:00
ROllerozxa
c15f657c17 [ci skip] Update Mastodon links 2025-07-01 16:06:57 +02:00
gbsierra
5f71326243
implement DIALOG_ANIMAL for imgui (#199)
Co-authored-by: ROllerozxa <rollerozxa@voxelmanip.se>
2025-04-17 14:20:59 +02:00
ROllerozxa
565ea8f229
Compile out fullscreen switching on Android
Fixes #197
2025-04-09 09:52:54 +02:00
ROllerozxa
f71e177c43 Principia 2025.04.05 2025-04-05 13:05:07 +02:00
ROllerozxa
aa39fe1c05 Show puzzle level buttons in Imgui dialogs 2025-04-04 00:04:44 +02:00
ROllerozxa
18ce9bcc5b Rename adventure level types in GTK3 new level dialog 2025-04-04 00:01:47 +02:00
ROllerozxa
d0cb87557a Use TMS_FAST_MATH implementations on Android too 2025-04-03 23:51:09 +02:00
ROllerozxa
ddee2705fa Add fastlane changelog for upcoming version
so I don't forget about it
2025-04-02 22:05:08 +02:00
ROllerozxa
41e7fca1ef Switch to CLANG64 on Windows 2025-04-02 20:22:42 +02:00
ROllerozxa
8341ffd839 Switch to Clang for Linux CI 2025-04-02 13:00:48 +02:00
ROllerozxa
1258b3dc04 Disable optimisation that breaks polygon rendering 2025-04-02 00:35:46 +02:00
ROllerozxa
d5ad479b9a Adjust numfeed text to window resize 2025-04-01 23:50:58 +02:00
ROllerozxa
4b01060fbf Adjust right-hand RC widgets to window resize 2025-04-01 23:50:45 +02:00
ROllerozxa
a41094c301 Adjust loading screen text to window resize 2025-04-01 23:15:15 +02:00
ROllerozxa
6f1398a2b2 Adjust toast message to window resize 2025-04-01 23:12:20 +02:00
ROllerozxa
4468e7dfae Fix play keybind not working like the play button in puzzle mode 2025-04-01 21:56:56 +02:00
ROllerozxa
5539861524 Revert "Restore always being able to resize the window"
"Most glaring issues with resizing have now been fixed" No they have not.
2025-03-29 17:17:36 +01:00
ROllerozxa
e178851a2c Put common ui::open_url impl into ui.cc, add toast for notifying 2025-03-29 17:07:47 +01:00
ROllerozxa
b410bd72da Show classic puzzles button in menu after player has opened it from community site 2025-03-29 17:05:50 +01:00
ROllerozxa
b2fcbc6aee Merge level info dialog into UiMessage in imgui dialogs 2025-03-29 16:05:55 +01:00
gbsierra
c4a50dd59d Implement UiConfirm for imgui 2025-03-29 15:58:39 +01:00
gbsierra
485039bbe7 Update Physics tab in UiLevelProperties 2025-03-28 21:32:48 +01:00
ROllerozxa
3e1e053ac2 Remove ui::open_help_dialog, use regular ui::open_dialog instead
Also call the dialog consistently info/level info
2025-03-27 21:53:43 +01:00
gbsierra
f468d2fdd0 Implement UiHelp dialog for imgui 2025-03-27 21:05:31 +01:00
ROllerozxa
293a563342 Update puzzle levels 1-21 and do some tweaks where necessary 2025-03-26 22:27:09 +01:00
gbsierra
2fc887dc23 Implement context menu for removing bookmarks in Imgui dialog 2025-03-26 21:30:29 +01:00
gbsierra
6eaf5e1067 Implement some unimplemented goto menu items in Imgui dialog 2025-03-26 21:23:59 +01:00
gbsierra
6b54f51ea6 Play click sound when pressing package level button 2025-03-26 21:11:36 +01:00
ROllerozxa
ba3a78c69b Fix browse community button to actually do anything 2025-03-25 00:02:28 +01:00
ROllerozxa
58a55cc33d Rework play menu buttons 2025-03-24 21:14:08 +01:00
ROllerozxa
c0d667a511 Rename adventure buttons in create menu 2025-03-24 21:05:18 +01:00
ROllerozxa
3a8f57e934 Update SDL2 to 2.32.2 on Android 2025-03-22 22:18:15 +01:00
ROllerozxa
90c9a7cad8 Restore always being able to resize the window
Most glaring issues with resizing have now been fixed
2025-03-22 21:56:49 +01:00
ROllerozxa
a1404b55f9 Merge Android backend into unified backend 2025-03-22 21:53:28 +01:00
ROllerozxa
043d64ead6 Store cache data in a separate folder 2025-03-22 20:49:20 +01:00
ROllerozxa
ac2efc7cf3 Refactor data storage into separate source file 2025-03-22 20:46:08 +01:00
ROllerozxa
818a1517ee Fix textured pixel properties not copying when using copy command 2025-03-22 17:17:23 +01:00
ROllerozxa
5e107f1d9e Don't allow deleting objects when playing puzzle 2025-03-22 17:12:17 +01:00
ROllerozxa
75bc7c740b Fix game crashing on startup on Android 2025-03-21 22:23:32 +01:00
ROllerozxa
2421a1cae0 Fix playing puzzles from the community site
With this, puzzles should be fully functional again! Closes #91.
2025-03-21 21:30:09 +01:00
ROllerozxa
e1fe879b27 Double max chunks render limit on PC
Reduces likelihood of seeing chunk gaps significantly, but I'm unsure if this will lead to more memory usage. This should probably be dynamic and configurable but doubling it on PC makes sense for now.
2025-03-21 21:07:50 +01:00
ROllerozxa
bb8230e2c1 Remove weird check for end of level byte
No idea what this was meant to be, probably some weird kind of DRM or anti-cheat measure. Fixes #147
2025-03-21 20:44:40 +01:00
ROllerozxa
23cf7074c1 Cleanup puzzle code from yesterday, introduce puzzle_state variable 2025-03-21 18:23:55 +01:00
ROllerozxa
3950f1fcdc Remove unused puzzle play dialog 2025-03-21 18:12:24 +01:00
ROllerozxa
db3671b6b8 Don't show cam markers when playing a puzzle 2025-03-21 18:00:31 +01:00
ROllerozxa
a0979fc604 Try to make all GTK dialogs show up above game window
(also some cleanups to use apply_dialog_defaults in more places)
2025-03-21 17:59:02 +01:00
ROllerozxa
523bc86eee Clean out remaining iOS dialog code 2025-03-21 17:30:09 +01:00
ROllerozxa
d4ef3ce1b2 Expand level description text field and enable word wrap 2025-03-21 17:29:32 +01:00
ROllerozxa
48647533ff Quick & dirty new movable object texture 2025-03-20 23:10:59 +01:00
ROllerozxa
7d9cef28a4 Hide hamburger menu in puzzle levels 2025-03-20 23:07:19 +01:00
ROllerozxa
c5f37c3de4 Add puzzle level type to create menu and sandbox dialogs 2025-03-20 19:58:42 +01:00
ROllerozxa
4ca11cadfd Make puzzles just about work in the sandbox 2025-03-20 19:55:19 +01:00
ROllerozxa
8c57cc8ad3 [ci skip] Update issue templates 2025-03-18 00:43:14 +01:00
ROllerozxa
926bcdf7d4 Fix crash when destroying a dead robot's bomb
Fixes #162
2025-03-17 22:51:28 +01:00
ROllerozxa
5ddec073f9 Fix crash after deleting a selected cable entity
Fixes #33
2025-03-17 22:43:06 +01:00
ROllerozxa
1feee634ba Fix rubber objects crashing the game when graphics are reloaded
Fixes #190
2025-03-17 22:22:45 +01:00
ROllerozxa
716b103599 Fix making portable Windows release 2025-03-14 16:37:33 +01:00
ROllerozxa
9648b16f1b Don't redirect logging output when compiling for the web 2025-03-11 21:24:00 +01:00
ROllerozxa
4e6f127a91 Use Emscripten ports for all web dependencies & disable cURL 2025-03-10 23:21:07 +01:00
ROllerozxa
07e7921719 Emscripten build fixes, merge Emscripten backend into shared backend 2025-03-10 22:05:42 +01:00
ROllerozxa
81d0cf49da Speed up model loading on Android 2025-03-09 22:23:28 +01:00
ROllerozxa
006f12e8d6 Minor vsync'ing cleanups 2025-03-09 22:23:00 +01:00
ROllerozxa
c4d8ed02e2 Remove remnants of unused "menu" pipeline
Was assumedly used for the rendering of objects in the sandbox menu, but sandbox icons are now prerendered from textures instead
2025-03-09 21:30:01 +01:00
ROllerozxa
958f4f5056 Remove references to unused "GI" graphics effect
Assumedly abbreviation of "global illumination", some kind of alternative to the current way of drawing the shadows. Doesn't work very well when enabled, remove it.
2025-03-09 20:55:04 +01:00
ROllerozxa
345f93a8ab Remove some unused and commented out shadow shader code 2025-03-09 20:17:41 +01:00
ROllerozxa
8b056328fc Drop unused shadow_quality 2
No idea what it was supposed to do, and enabling it just gives broken shadows
2025-03-09 20:17:05 +01:00
ROllerozxa
ca3b7580f0 Fix RC widget edit screen breaking on resize
Fixes #66
2025-03-09 17:22:16 +01:00
ROllerozxa
9b0adb1adf Reenable dynamic lighting in shader code
Fixes level manager being able to set the ambient and diffuse lighting.
2025-03-09 00:43:28 +01:00
ROllerozxa
15bfab9e60 Move in-tree libraries to lib/, move main codebase into root of src/ 2025-03-05 20:23:30 +01:00
ROllerozxa
0101aeb9b1 Rename Android project folder to just android 2025-03-04 23:17:47 +01:00
ROllerozxa
22d7d57e37 Clean out some old notes in doc, move some Doxygen stuff 2025-03-04 23:02:41 +01:00
ROllerozxa
e4bb88b9d4 Move out testmaps from source tree 2025-03-04 22:52:01 +01:00
ROllerozxa
7e7aca613f Merge data-pc into data
Android now uses the JPEG textures that the PC version used, instead of the ETC1 encoded images in `data-mobile`. ETC1 texture loading is also removed as it is now unused.
2025-03-04 22:50:32 +01:00
ROllerozxa
523f2dc01c data-shared -> data 2025-03-04 21:51:19 +01:00
ROllerozxa
55388ba923 Add incomplete Dear Imgui dialog backend
Co-authored-by: griffi-gh <prasol258@gmail.com>
2025-03-04 21:35:07 +01:00
ROllerozxa
d81049a3a7 Fix Windows build 2025-03-04 00:19:45 +01:00
ROllerozxa
6837f9b8ae Minor CMake cleanups 2025-03-03 22:22:27 +01:00
ROllerozxa
6e11074ca1 Actually define SCREENSHOT_BUILD for screenshot builds
oops
2025-03-03 22:07:02 +01:00
ROllerozxa
561dd5be4b Update Gradle wrapper and Android Gradle Plugin version 2025-03-03 22:05:46 +01:00
ROllerozxa
d2bdf059c8 Remove LINUX_SS TMS backend
Use a SCREENSHOT_BUILD definition to control building screenshotter-specific code
2025-03-03 22:04:24 +01:00
ROllerozxa
1f1917bca8 Fix git commit detection for Windows CI 2024-12-08 17:32:06 +01:00
ROllerozxa
6b61fe8ca7 Enable HTTPS certificate validation on desktop platforms 2024-12-08 16:35:01 +01:00
ROllerozxa
7085fbabe3 Upload debug symbols for Linux artifact 2024-12-05 16:08:59 +01:00
ROllerozxa
0b0c9a15a2 Revise README 2024-12-05 16:03:57 +01:00
ROllerozxa
ce6dcedf4a Update Android SDK versions and rebuild with new deps 2024-12-05 15:37:12 +01:00
ROllerozxa
b9317a3d2b Give some more scrolling room in package level dialog 2024-10-17 00:16:07 +02:00
ROllerozxa
5cb81c6141 Disable resizable window by default 2024-10-16 23:27:47 +02:00
ROllerozxa
8ecccc1653 Distinguish builds with commit rather than build date 2024-10-16 22:04:52 +02:00
ROllerozxa
9ff71b6d94 Clamp some more signaling object sockets 2024-09-08 21:44:05 +02:00
ROllerozxa
f4c79f9c7b Minor cleanups of header includes 2024-09-03 22:52:56 +02:00
ROllerozxa
6bfa36e03c Split up most gate objects into separate source files 2024-09-03 22:46:15 +02:00
ROllerozxa
d1cdbe27e8 Extend weight multiplier to 2.5 2024-09-01 21:48:13 +02:00
ROllerozxa
40c26c0b7e Clamp some input sockets for safety 2024-09-01 21:46:30 +02:00
ROllerozxa
81233f5f21 Fix sqrt gate outputting NaN 2024-09-01 21:33:41 +02:00
ROllerozxa
a82a20b398 Reduce rebuilds when changing version info 2024-09-01 21:32:24 +02:00
ROllerozxa
592b467c3d Use SDL_GetPlatform() for getting platform name 2024-09-01 20:53:23 +02:00
ROllerozxa
2ab1fc11f3 Move Box2D up into src/ 2024-09-01 20:48:01 +02:00
ROllerozxa
d6a16f824c Add security policy 2024-09-01 00:34:45 +02:00
ROllerozxa
1ca6c463d6 Update cURL Windows dependency to 8.9.1 2024-08-06 20:58:37 +02:00
ROllerozxa
a6ea7240af Revert temporary version code bump 2024-08-06 18:24:53 +02:00
ROllerozxa
6a88d7026d Put Linear decay clamp fix behind new level version 2024-08-06 18:23:20 +02:00
ROllerozxa
3d6a1ebe90 Update SDL Android glue code to 2.30.6, update deps submodule 2024-08-06 17:57:42 +02:00
ROllerozxa
c17bb97b49 Increase maximum Max value of Condenser to 32 2024-08-06 15:46:48 +02:00
ROllerozxa
466c59d699 Clamp final value of linear decay between 0.0-1.0 2024-08-06 15:44:12 +02:00
ROllerozxa
5884291da0 Fix allow_derivatives always being 0 on non-new level 2024-08-06 15:43:22 +02:00
ROllerozxa
d0d303db5c Fix incorrect plastic density value in Android multiselect dialog 2024-08-06 15:29:32 +02:00
ROllerozxa
93da889308 Bump Android version code for F-Droid rebuild 2024-07-17 16:12:13 +02:00
ROllerozxa
b2ae0136c9 Add Android dependency repo as submodule
So F-Droid knows which exact commit to build them off of for each release
2024-07-17 15:58:14 +02:00
1903 changed files with 133862 additions and 35974 deletions

6
.gitattributes vendored
View file

@ -1,7 +1,3 @@
# Exclude vendored libraries from GitHub language detection
src/lua/* linguist-vendored
src/luasocket/* linguist-vendored
src/SDL_image/* linguist-vendored
src/SDL_mixer/* linguist-vendored
src/SDL-mobile/* linguist-vendored
lib/* linguist-vendored

2
.github/CONTRIBUTING.md vendored Normal file
View file

@ -0,0 +1,2 @@
# Contributing to Principia
Contributions are welcome! Please see [Contributing to the Game](https://principia-web.se/wiki/Contributing_to_the_Game) on the Principia Wiki for more information.

View file

@ -1,28 +0,0 @@
---
name: Bug report
about: If you are reporting a bug, please fill out this form with the necessary details.
title: ''
labels: Bug
assignees: ''
---
##### Principia version
<!--
Describe the version you are running here. Are you on a 1.5.2 Beta build downloaded
from principia-web or have you built from source? If you're reporting something from
1.5.1 make sure it still exists in the open source version.
-->
##### OS / Hardware
<!-- General information about your hardware and operating system -->
- Platform:
- Operating system:
<!-- For graphical issues only, feel free to omit if not graphical -->
- GPU model:
##### Summary
<!-- Describe your problem here -->
##### Steps to reproduce
<!-- Explain the steps one could take to reproduce it. If reporting a Lua issue, please give a minimal code example to reproduce it. -->

40
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View file

@ -0,0 +1,40 @@
name: Bug report
description: Reporting bugs, crashes and other related issues with the game
labels: ["Bug"]
body:
- type: markdown
attributes:
value: Thank you for helping to make the game better by reporting issues that you discover. Make sure to describe the necessary details about the bug such that it can be reproduced by others. Additionally please refrain from using LLMs ("AI") to write or "improve" your report, as they typically just make it more verbose without adding any useful information.
- type: input
attributes:
label: Principia version
description: Describe the version you are running here. Are you on a stable release or on a nightly build, or have you built from source? To determine where a non-release build was built off of you can press the version number in the bottom right corner of the main menu.
placeholder: "Example: 20XX.XX.XX"
validations:
required: true
- type: input
attributes:
label: Platform
description: A lot of times a issue can be specific to a particular platform. Please write the platform you're on, or list the platforms you can reproduce it on.
placeholder: "Example: Linux"
validations:
required: true
- type: input
attributes:
label: System information
description: Give some information about your device that may be relevant for your issue. For example it would be helpful to know your GPU vendor for graphical issues.
placeholder: "Example: AMD Radeon RX 560 with Mesa drivers"
validations:
required: false
- type: textarea
attributes:
label: Summary
description: Describe the problem here.
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce
description: Explain the steps one could take to reproduce it. If applicable, providing Lua code snippets or attaching a test level would also be helpful.
validations:
required: true

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: Questions
url: https://principia-web.se/forum/
about: For asking more general questions about Principia, please see the Principia forums.

11
.github/SECURITY.md vendored Normal file
View file

@ -0,0 +1,11 @@
# Security Policy
## Supported Versions
We only support the latest stable version for security issues.
## Reporting a Vulnerability
If you have found a bug that could be exploited by a malicious actor by playing a level or in any other way where an end-user could be victimised, then please responsibly disclose it privately by email to:
- ROllerozxa, project maintainer \<rollerozxa@voxelmanip.se\>
We will evaluate possible means of mitigating it on the community site and/or swiftly release a new version of Principia to fix the issue, depending on the severity. If it is deemed to not be a security-critical issue then we'll ask you to file a public bug report issue.

View file

@ -4,16 +4,18 @@ on:
push:
paths:
- 'src/**'
- 'build-android/**'
- 'data-*/**'
- 'lib/**'
- 'android/**'
- 'data/**'
- 'packaging/**'
- 'CMakeLists.txt'
- '.github/workflows/android.yml'
pull_request:
paths:
- 'src/**'
- 'build-android/**'
- 'data-*/**'
- 'lib/**'
- 'android/**'
- 'data/**'
- 'packaging/**'
- 'CMakeLists.txt'
- '.github/workflows/android.yml'
@ -22,21 +24,23 @@ jobs:
android:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
- name: Build with gradle
run: |
cd build-android
cd android
./gradlew assemblerelease
- name: Save apk artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: principia-release-unsigned.apk
path: build-android/principia/build/outputs/apk/release/principia-release-unsigned.apk
path: android/principia/build/outputs/apk/release/principia-release-unsigned.apk
#archive: false
if-no-files-found: error

34
.github/workflows/build_utils.yml vendored Normal file
View file

@ -0,0 +1,34 @@
name: build_utils
on:
push:
paths:
- 'src/**'
- 'utils/**'
pull_request:
paths:
- 'src/**'
- 'utils/**'
jobs:
build_utils:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6
- name: Install deps
run: |
sudo apt-get update
sudo apt-get install -y libjansson-dev
- name: Build
run: |
cd utils
make
- name: Upload output as artifact
uses: actions/upload-artifact@v7
with:
name: principia-utils
path: utils/bin/
if-no-files-found: error

View file

@ -4,14 +4,16 @@ on:
push:
paths:
- 'src/**'
- 'data-*/**'
- 'lib/**'
- 'data/**'
- 'packaging/**'
- 'CMakeLists.txt'
- '.github/workflows/linux.yml'
pull_request:
paths:
- 'src/**'
- 'data-*/**'
- 'lib/**'
- 'data/**'
- 'packaging/**'
- 'CMakeLists.txt'
- '.github/workflows/linux.yml'
@ -23,23 +25,35 @@ jobs:
image: debian:bullseye
env: { LANG: "C.UTF-8" }
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install deps
run: |
apt-get update
apt-get install -y g++ libgtk-3-dev libgl-dev libglew-dev libcurl4-openssl-dev libpng-dev libjpeg-dev libfreetype6-dev cmake ninja-build desktop-file-utils ca-certificates wget file --no-install-recommends
wget https://github.com/principia-game/linux-deps/releases/download/latest/deps.tar.gz -O linux-deps.tar.gz
tar -xaf linux-deps.tar.gz -C /
apt-get install -y \
clang-16 libgtk-3-dev libgl-dev libcurl4-openssl-dev libpng-dev libjpeg-dev libfreetype6-dev cmake ninja-build desktop-file-utils ca-certificates wget file \
libasound2-dev libpulse-dev libjack-dev libsndio-dev libx11-dev libxext-dev libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxtst-dev libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev libpipewire-0.3-dev libwayland-dev liburing-dev \
--no-install-recommends
- name: Build
run: |
mkdir build; cd build
../packaging/build-appimage.sh
env:
CC: clang-16
CXX: clang++-16
- name: Upload output as artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Principia-x86_64.AppImage
path: build/Principia-x86_64.AppImage
#archive: false
if-no-files-found: error
- name: Upload debug symbols as artifact
uses: actions/upload-artifact@v7
with:
name: linux-appimage-dbgsym
path: build/principia.debug
if-no-files-found: error

View file

@ -4,35 +4,40 @@ on:
push:
paths:
- 'src/**'
- 'data-*/**'
- 'lib/**'
- 'data/**'
- 'CMakeLists.txt'
- '.github/workflows/linux_ss.yml'
pull_request:
paths:
- 'src/**'
- 'data-*/**'
- 'lib/**'
- 'data/**'
- 'CMakeLists.txt'
- '.github/workflows/linux_ss.yml'
jobs:
linux_ss:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install deps
run: |
sudo apt-get update
sudo apt-get install -y g++ libgl-dev libpng-dev libjpeg-dev libfreetype6-dev libsdl2-dev cmake ninja-build --no-install-recommends
sudo apt-get install -y g++ libgl-dev libpng-dev libjpeg-dev libfreetype6-dev cmake ninja-build \
libx11-dev libxext-dev libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxtst-dev libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libegl1-mesa-dev \
--no-install-recommends
- name: Build
run: |
mkdir build; cd build
cmake .. -DSCREENSHOT_BUILD=ON -G Ninja
cmake .. -DSCREENSHOT_BUILD=ON -G Ninja -DUSE_VENDORED_SDL3=ON
ninja -j4
- name: Upload output as artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: screenshotter_artifact
path: build/principia
if-no-files-found: error

View file

@ -4,14 +4,16 @@ on:
push:
paths:
- 'src/**'
- 'data-*/**'
- 'lib/**'
- 'data/**'
- 'packaging/**'
- 'CMakeLists.txt'
- '.github/workflows/macos.yml'
pull_request:
paths:
- 'src/**'
- 'data-*/**'
- 'lib/**'
- 'data/**'
- 'packaging/**'
- 'CMakeLists.txt'
- '.github/workflows/macos.yml'
@ -20,16 +22,14 @@ jobs:
macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install deps
run: |
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew update --auto-update
brew install cmake ninja glew libpng libjpeg-turbo freetype sdl2 gtk+3
patch /opt/homebrew/include/GL/glew.h < packaging/glew_macos_fix.patch
brew install cmake ninja libpng libjpeg-turbo freetype sdl3 gtk+3
- name: Compile
run: |
@ -38,8 +38,7 @@ jobs:
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.14 \
-DCMAKE_FIND_FRAMEWORK=LAST \
-DCMAKE_INSTALL_PREFIX=../build/macos/ \
-DCMAKE_EXE_LINKER_FLAGS="-L/opt/homebrew/lib/" \
-DGLEW_LIBRARY_RELEASE=/opt/homebrew/lib/libGLEW.dylib
-DCMAKE_EXE_LINKER_FLAGS="-L/opt/homebrew/lib/"
ninja
- name: Package
@ -48,7 +47,9 @@ jobs:
ninja package
- name: Upload output as artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: principia-macos
path: build/*.zip
#archive: false
if-no-files-found: error

47
.github/workflows/web.yml vendored Normal file
View file

@ -0,0 +1,47 @@
name: web
on:
push:
paths:
- 'src/**'
- 'lib/**'
- 'data/**'
- 'packaging/**'
- 'CMakeLists.txt'
- '.github/workflows/web.yml'
pull_request:
paths:
- 'src/**'
- 'lib/**'
- 'data/**'
- 'packaging/**'
- 'CMakeLists.txt'
- '.github/workflows/web.yml'
jobs:
web:
runs-on: ubuntu-latest
container:
image: emscripten/emsdk:latest
env: { LANG: "C.UTF-8" }
steps:
- uses: actions/checkout@v6
- name: Install deps
run: |
sudo apt-get update
sudo apt-get install -y ninja-build
- name: Build
run: |
mkdir build; cd build
emcmake cmake .. -G Ninja -DCMAKE_INSTALL_PREFIX= -DUSE_VENDORED_SDL3=ON
ninja
DESTDIR=../web ninja install
- name: Save apk artifact
uses: actions/upload-artifact@v7
with:
name: principia-wasm
path: web/
if-no-files-found: error

View file

@ -4,14 +4,16 @@ on:
push:
paths:
- 'src/**'
- 'data-*/**'
- 'lib/**'
- 'data/**'
- 'packaging/**'
- 'CMakeLists.txt'
- '.github/workflows/windows.yml'
pull_request:
paths:
- 'src/**'
- 'data-*/**'
- 'lib/**'
- 'data/**'
- 'packaging/**'
- 'CMakeLists.txt'
- '.github/workflows/windows.yml'
@ -23,31 +25,29 @@ jobs:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: msys2/setup-msys2@v2
with:
update: true
release: false
msystem: UCRT64
msystem: CLANG64
pacboy: >-
git:
gcc:p
cmake:p
ninja:p
glew:p
zlib:p
gtk3:p
libpng:p
libjpeg-turbo:p
SDL2:p
sdl3:p
nsis:p
7zip:p
# custom built packages with less dependencies than MSYS' counterparts
- name: Install external packages
run: |
wget https://grejer.voxelmanip.se/msys-pkgs/mingw-w64-ucrt-x86_64-{curl-winssl-8.8.0-10,freetype-2.13.2-1}-any.pkg.tar.zst
pacman -U --noconfirm *.pkg.tar.zst
./packaging/windows-install-pkgs.sh
- name: Build
run: |
@ -62,13 +62,17 @@ jobs:
../packaging/windows_portable.sh
- name: Upload output as artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: principia-setup.exe
path: build/principia-setup.exe
#archive: false
if-no-files-found: error
- name: Upload output as artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: principia-portable.7z
path: build/principia-portable.7z
#archive: false
if-no-files-found: error

4
.gitignore vendored
View file

@ -11,8 +11,8 @@ opengl32.dll
compile_commands.json
# Doxygen documentation
doc/doxy/
doc/doxygen-awesome.css
doxy/
doxygen-awesome.css
# Model junk files
*.blend1

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "android/principia/deps-src"]
path = android/principia/deps-src
url = https://github.com/principia-game/android-deps

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.9)
cmake_minimum_required(VERSION 3.14)
project(principia)
@ -15,29 +15,43 @@ endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
include(DownloadLib)
add_custom_target(GenerateGitVersion
COMMAND ${CMAKE_COMMAND}
-D "GENERATE_VERSION_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}"
-D "GENERATE_VERSION_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}"
-P "${CMAKE_SOURCE_DIR}/cmake/Modules/GenerateGitVersion.cmake"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
option(UNITY_BUILD "Experimental unity build" FALSE)
mark_as_advanced(UNITY_BUILD)
option(USE_VENDORED_SDL3 "Build with vendored SDL3 library" FALSE)
# Find core dependencies
# ----------------------
if(USE_VENDORED_SDL3)
include(cmake/SDL.cmake)
else()
find_package(SDL3 REQUIRED)
endif()
if(ANDROID)
cmake_minimum_required(VERSION 3.20)
include(PrincipiaAndroidLibs)
else()
if(NOT EMSCRIPTEN)
find_package(SDL2 REQUIRED)
else()
include(PrincipiaEmscriptenLibs)
endif()
set(OpenGL_GL_PREFERENCE GLVND)
find_package(OpenGL REQUIRED)
endif()
find_package(Freetype REQUIRED)
find_package(JPEG REQUIRED)
find_package(PNG REQUIRED)
find_package(ZLIB REQUIRED)
if(NOT EMSCRIPTEN)
find_package(Freetype REQUIRED)
find_package(JPEG REQUIRED)
find_package(PNG REQUIRED)
find_package(ZLIB REQUIRED)
endif()
# Determine platform and backend
@ -49,14 +63,18 @@ else()
set(SCREENSHOT_BUILD FALSE)
endif()
if(EMSCRIPTEN)
set(BACKEND_IMGUI TRUE)
else()
option(BACKEND_IMGUI "Enable incomplete Dear Imgui dialog backend (Experimental)" FALSE)
endif()
set(TMS_FORMFACTOR "PC")
if(WIN32)
set(TMS_BACKEND "WINDOWS")
elseif(ANDROID)
set(TMS_BACKEND "ANDROID")
set(TMS_FORMFACTOR "MOBILE")
elseif(SCREENSHOT_BUILD)
set(TMS_BACKEND "LINUX_SS")
elseif(HAIKU)
set(TMS_BACKEND "HAIKU")
elseif(APPLE)
@ -82,116 +100,99 @@ endif()
# ----------------------------------
include_directories(
lib/
lib/GLAD/include/
lib/imgui/
lib/lua/
lib/SDL_image/
lib/SDL_mixer/
src/
src/lua/
src/SDL_image/
src/src/
${FREETYPE_INCLUDE_DIRS}
${JPEG_INCLUDE_DIRS}
${PNG_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS})
${CMAKE_CURRENT_BINARY_DIR})
file(GLOB SRCS
src/tms/core/*.c
src/tms/math/*.c
src/tms/util/*.c
src/tms/bindings/cpp/cpp.cc
src/tms/modules/3ds.c
src/lua/*.c
src/SDL_image/*.c
src/src/*.cc
src/src/*.c
src/src/Box2D/Collision/*.cc
src/src/Box2D/Collision/Shapes/*.cc
src/src/Box2D/Common/*.cc
src/src/Box2D/Dynamics/*.cc
src/src/Box2D/Dynamics/Contacts/*.cc
src/src/Box2D/Dynamics/Joints/*.cc
src/src/Box2D/Particle/*.cc
file(GLOB SRCS CONFIGURE_DEPENDS
lib/GLAD/src/gl.c
lib/lua/*.c
lib/SDL_image/*.c
)
# For non-Android, system SDL2 and OpenGL include dirs
include_directories(
${SDL2_INCLUDE_DIRS}
${OPENGL_INCLUDE_DIRS})
if(UNITY_BUILD)
list(APPEND SRCS
src/tms/_unity_chunk.c
src/_unity_chunk.cc
src/game.cc
src/game-gearbox-edit.cc
src/game-gui.cc
src/game-panel-edit.cc
src/menu_pkg.cc
src/repair_station.cc
src/solver_ingame.cc
lib/Box2D/_unity_chunk.cc)
else()
file(GLOB MAIN_SRCS CONFIGURE_DEPENDS
src/tms/core/*.c
src/tms/math/*.c
src/tms/cpp.cc
src/tms/modules/3ds.c
src/*.cc
src/luascript/*.cc
lib/Box2D/Collision/*.cc
lib/Box2D/Collision/Shapes/*.cc
lib/Box2D/Common/*.cc
lib/Box2D/Dynamics/*.cc
lib/Box2D/Dynamics/Contacts/*.cc
lib/Box2D/Dynamics/Joints/*.cc
lib/Box2D/Particle/*.cc)
list(APPEND SRCS ${MAIN_SRCS})
endif()
if(BACKEND_IMGUI)
file(GLOB IMGUI_SRCS CONFIGURE_DEPENDS
lib/imgui/*.cpp
lib/imgui/misc/freetype/*.cpp
src/ui/*.cc)
list(APPEND SRCS ${IMGUI_SRCS})
endif()
# Optional dependencies not found on Android or in the screenshot build
if(NOT SCREENSHOT_BUILD)
if(NOT ANDROID AND NOT EMSCRIPTEN)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
if(NOT BACKEND_IMGUI)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
endif()
find_package(GLEW REQUIRED)
include_directories(
${GLEW_INCLUDE_DIRS}
${GTK3_INCLUDE_DIRS})
if(NOT BACKEND_IMGUI)
include_directories(${GTK3_INCLUDE_DIRS})
endif()
endif()
find_package(CURL REQUIRED)
if(NOT EMSCRIPTEN)
find_package(CURL REQUIRED)
include_directories(${CURL_INCLUDE_DIR})
add_definitions(-DBUILD_CURL)
endif()
file(GLOB SDL_mixer_SRCS src/SDL_mixer/*.c)
set(SRCS ${SRCS} ${SDL_mixer_SRCS})
include_directories(
${CURL_INCLUDE_DIR}
src/SDL_mixer/)
add_definitions(-DBUILD_CURL)
file(GLOB SDL_mixer_SRCS CONFIGURE_DEPENDS lib/SDL_mixer/*.c)
list(APPEND SRCS ${SDL_mixer_SRCS})
endif()
# Optional luasocket functionality
if(NOT UNITY_BUILD)
if(SCREENSHOT_BUILD)
set(BACKEND_SRC main_screenshotter.cc)
else()
set(BACKEND_SRC main.cc)
list(APPEND SRCS src/tms/backend/pipe.cc)
endif()
if(NOT SCREENSHOT_BUILD AND NOT ANDROID AND NOT EMSCRIPTEN)
option(USE_LUASOCKET "Build with Luasocket support" TRUE)
else()
set(USE_LUASOCKET false)
list(APPEND SRCS src/tms/backend/${BACKEND_SRC})
endif()
if(USE_LUASOCKET)
add_definitions(-DBUILD_LUASOCKET)
file(GLOB LUASOCKET_SRCS
src/luasocket/*.c)
set(SRCS ${SRCS} ${LUASOCKET_SRCS})
endif()
if(ANDROID)
set(BACKEND_SRC main_android.cc)
elseif(SCREENSHOT_BUILD)
set(BACKEND_SRC main_screenshotter.cc)
elseif(EMSCRIPTEN)
set(CMAKE_EXECUTABLE_SUFFIX ".html")
set(BACKEND_SRC main_emscripten.cc)
else()
set(BACKEND_SRC main.cc)
set(SRCS ${SRCS} src/tms/backend/pipe.cc)
endif()
set(SRCS ${SRCS} src/tms/backend/${BACKEND_SRC})
if(WIN32)
# Windows manifest (resource and icon) for Windows builds
set(WINRESOURCE_FILE "packaging/principia.rc")
set(WINMANIFEST_FILE "packaging/principia.manifest")
if(NOT CMAKE_RC_COMPILER)
set(CMAKE_RC_COMPILER "windres.exe")
endif()
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/principia.rc.o
COMMAND ${CMAKE_RC_COMPILER} -I${CMAKE_CURRENT_SOURCE_DIR} -I${CMAKE_CURRENT_BINARY_DIR}
-i${WINRESOURCE_FILE}
-o ${CMAKE_CURRENT_BINARY_DIR}/principia.rc.o
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${WINRESOURCE_FILE} ${WINMANIFEST_FILE})
set(SRCS ${SRCS} ${CMAKE_CURRENT_BINARY_DIR}/principia.rc.o)
list(APPEND SRCS packaging/principia.rc)
endif()
@ -208,58 +209,60 @@ endif()
# Link libraries against executable
# ---------------------------------
target_link_libraries(
${PROJECT_NAME}
${FREETYPE_LIBRARIES}
${JPEG_LIBRARIES}
${PNG_LIBRARIES}
${ZLIB_LIBRARIES})
if(NOT SCREENSHOT_BUILD)
target_link_libraries(${PROJECT_NAME} ${CURL_LIBRARIES})
if(NOT ANDROID)
target_link_libraries(${PROJECT_NAME} ${GTK3_LIBRARIES})
endif()
if(NOT SHOULD_USE_GLES)
target_link_libraries(${PROJECT_NAME} ${GLEW_LIBRARIES})
endif()
endif()
if(NOT EMSCRIPTEN)
target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARIES})
set(LIBS
Freetype::Freetype
JPEG::JPEG
PNG::PNG
ZLIB::ZLIB)
if(NOT SCREENSHOT_BUILD AND NOT EMSCRIPTEN)
list(APPEND LIBS ${CURL_LIBRARIES})
if(NOT ANDROID AND NOT BACKEND_IMGUI)
list(APPEND LIBS ${GTK3_LIBRARIES})
endif()
endif()
endif()
list(APPEND LIBS SDL3::SDL3)
if(SHOULD_USE_GLES)
target_link_libraries(${PROJECT_NAME} -lGLESv2)
list(APPEND LIBS GLESv2)
else()
target_link_libraries(${PROJECT_NAME} ${OPENGL_LIBRARIES})
list(APPEND LIBS OpenGL::GL)
endif()
if(ANDROID)
list(APPEND LIBS android dl log OpenSLES)
endif()
target_link_libraries(${PROJECT_NAME} ${LIBS})
add_dependencies(${PROJECT_NAME} GenerateGitVersion)
# Compiler flags
# --------------
if(SHOULD_USE_GLES)
add_definitions(-DTMS_USE_GLES)
elseif(NOT SCREENSHOT_BUILD)
add_definitions(-DTMS_USE_GLEW)
endif()
if(ANDROID)
target_link_libraries(${PROJECT_NAME} -landroid -ldl -llog -lOpenSLES)
if(UNITY_BUILD)
add_definitions(-DUNITY_BUILD)
endif()
add_definitions(-DHAVE_GCC_ATOMICS)
else()
add_definitions(-DTMS_FAST_MATH)
if(WIN32)
add_definitions(-D_WIN32_WINNT=0x0501)
elseif(SCREENSHOT_BUILD)
add_definitions(-DNO_UI -DSCREENSHOT_BUILD)
endif()
if(WIN32)
target_link_libraries(${PROJECT_NAME} ws2_32.lib version.lib shlwapi.lib winmm.lib)
if(BACKEND_IMGUI)
add_definitions(-DPRINCIPIA_BACKEND_IMGUI -DIMGUI_DEFINE_MATH_OPERATORS)
add_definitions(-D_WIN32_WINNT=0x0501 -DUNICODE)
elseif(SCREENSHOT_BUILD)
add_definitions(-DNO_UI)
if(SHOULD_USE_GLES)
add_definitions(-DIMGUI_IMPL_OPENGL_ES2)
endif()
endif()
@ -268,6 +271,13 @@ add_definitions(-DTMS_BACKEND_${TMS_FORMFACTOR} -DTMS_BACKEND_${TMS_BACKEND})
# Use a safe subset of fast math flags
set(COMMON_FLAGS "-fno-math-errno -fno-trapping-math -fno-signed-zeros")
if(EMSCRIPTEN)
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "--preload-file ../data/")
set(LIBRARY_FLAGS "-sUSE_FREETYPE=1 -sUSE_LIBJPEG=1 -sUSE_LIBPNG=1 -sUSE_ZLIB=1 -pthread")
string(APPEND COMMON_FLAGS " ${LIBRARY_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS " ${LIBRARY_FLAGS} -pthread -sPTHREAD_POOL_SIZE=20 -sINITIAL_MEMORY=2013265920 -sALLOW_MEMORY_GROWTH=1 -sTOTAL_STACK=16Mb -sFETCH=1")
endif()
set(COMMON_FLAGS_DEBUG "${COMMON_FLAGS} -O0 -ggdb -DDEBUG=1")
set(COMMON_FLAGS_RELEASE "${COMMON_FLAGS} -DNDEBUG=1 -fomit-frame-pointer")
@ -279,24 +289,31 @@ set(CMAKE_CXX_FLAGS_RELEASE "${COMMON_FLAGS_RELEASE} -O2 -fno-rtti")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -g")
set(CMAKE_CXX_FLAGS_DEBUG "${COMMON_FLAGS_DEBUG}")
# macOS Clang's linker doesn't like these flags
if(NOT APPLE)
if(WIN32)
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-mwindows -Wl,-s")
else()
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-Wl,-s")
endif()
if(NOT DEFINED CMAKE_EXE_LINKER_FLAGS_RELEASE)
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "")
endif()
if(WIN32)
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE "-mwindows ")
endif()
# macOS Clang's linker doesn't like these flags
if(NOT APPLE)
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE "-Wl,-s ")
endif()
# Register protocol handler util on Windows
# -----------------------------------------
if(WIN32)
add_executable(register-protocol-handler
packaging/register-protocol-handler/main.c
packaging/register-protocol-handler/windows.rc)
endif()
# Installation
# ------------
if(EMSCRIPTEN)
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "--preload-file ../data-pc/ --preload-file ../data-shared/")
target_link_libraries(${PROJECT_NAME} -lemsocket -lssl -lcrypto)
endif()
if(APPLE)
set(BUNDLE_NAME ${PROJECT_NAME}.app)
set(BUNDLE_PATH "${BUNDLE_NAME}")
@ -304,19 +321,24 @@ if(APPLE)
set(BINDIR ${BUNDLE_NAME}/Contents/MacOS)
set(SHAREDIR ${BUNDLE_NAME}/Contents/Resources)
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data-pc" DESTINATION "${SHAREDIR}")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data-shared" DESTINATION "${SHAREDIR}")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data" DESTINATION "${SHAREDIR}")
install(FILES "packaging/principia.icns" DESTINATION "${SHAREDIR}")
install(FILES "packaging/Info.plist" DESTINATION "${BUNDLE_PATH}/Contents")
elseif(EMSCRIPTEN)
set(BINDIR .)
install(FILES "packaging/index.html" DESTINATION .)
install(FILES ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.wasm DESTINATION .)
install(FILES ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.data DESTINATION .)
else()
include(GNUInstallDirs)
set(SHAREDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}")
set(BINDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data-pc" DESTINATION "${SHAREDIR}/principia")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data-shared" DESTINATION "${SHAREDIR}/principia")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data" DESTINATION "${SHAREDIR}/principia")
install(FILES "packaging/principia.desktop" DESTINATION "${SHAREDIR}/applications")
install(FILES "packaging/principia-url-handler.desktop" DESTINATION "${SHAREDIR}/applications")

View file

@ -14,9 +14,7 @@ BUILTIN_STL_SUPPORT = YES
# Input
RECURSIVE = YES
STRIP_FROM_PATH = src
INPUT = doc/main_page.dox \
src/src/ src/tms/
EXCLUDE = src/src/Box2D/
INPUT = src/
# Dot graphs
HAVE_DOT = YES
@ -27,7 +25,7 @@ DOT_MULTI_TARGETS = YES
DOT_IMAGE_FORMAT = svg
# Output
OUTPUT_DIRECTORY = doc/doxy/ # /tmp/doxy/
OUTPUT_DIRECTORY = doxy/ # /tmp/doxy/
GENERATE_LATEX = NO
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
@ -36,4 +34,4 @@ DISABLE_INDEX = YES
GENERATE_TREEVIEW = YES
HTML_DYNAMIC_SECTIONS = YES
HTML_TIMESTAMP = YES
HTML_EXTRA_STYLESHEET = doc/doxygen-awesome.css
HTML_EXTRA_STYLESHEET = doxygen-awesome.css

View file

@ -20,22 +20,22 @@ Principia runs on anything with a recent enough version of Windows, Linux or And
* Codeberg mirror: https://codeberg.org/principia/principia
* Mastodon: https://fosstodon.org/@principia
* Mastodon: https://hachyderm.io/@principia
## Binary builds
Binary builds of Principia for Windows, Android and Linux are available on the [downloads page](https://principia-web.se/download).
Release builds builds of Principia for Windows, Android and Linux are available on the [download page](https://principia-web.se/download).
There are also nightly build artifacts for Windows, Android and Linux that get automatically built by GitHub CI on each commit, see [Actions](https://github.com/Bithack/principia/actions). Keep in mind these may be broken at times during development, and you are recommended to use the release builds instead.
There are also nightly build artifacts that get automatically built by GitHub Actions CI on each commit and are available for download, see [Nightly Builds](https://principia-web.se/wiki/Nightly_Builds) on the wiki.
## Getting involved
Feel free to fork this project and send in your pull requests. This is a community project and the community decides how the project evolves.
Most of our discussion and development happens in the `#development` channel of the [Principia Discord server](https://principia-web.se/discord), make sure to join it if you want to discuss and participate in the development of the game.
For a brief overview on how to get started with contributing to the game, see the [Contributing to the Game](https://principia-web.se/wiki/Contributing_to_the_Game) page on the wiki.
Also be sure to follow [@principia](https://fosstodon.org/@principia) on Fosstodon for more updates about the project.
Also be sure to follow [@principia](https://hachyderm.io/@principia) on Mastodon for more updates about the project.
## Building from source
See [Compiling Principia](https://principia-web.se/wiki/Compiling_Principia) on the Principia Wiki.
See [Compiling Principia](https://principia-web.se/wiki/Compiling_Principia) on the wiki for building from source on supported platforms.
(You can also view the plaintext Markdown document [here](https://raw.githubusercontent.com/principia-game/wiki/master/pages/Compiling_Principia.md))

View file

@ -1,6 +1,6 @@
.gradle/
.idea/
deps/
deps
principia/build/
*.apk
*.apk.idsig

View file

@ -10,8 +10,7 @@ buildscript {
}
plugins {
id 'com.android.application' version '8.5.0' apply false
id 'com.android.library' version '8.5.0' apply false
id 'com.android.application' version '8.8.1' apply false
}
tasks.register('clean', Delete) {

Binary file not shown.

View file

@ -1,6 +1,7 @@
#Sun Aug 07 11:51:41 CEST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

251
android/gradlew vendored Executable file
View file

@ -0,0 +1,251 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

View file

@ -4,21 +4,19 @@ plugins {
}
android {
compileSdk 34
ndkVersion "26.2.11394342"
compileSdk 35
ndkVersion "27.2.12479018"
namespace 'com.bithack.principia'
defaultConfig {
applicationId "com.bithack.principia"
minSdk 21
targetSdk 34
versionCode 37
versionName "2024.07.12"
targetSdk 35
versionCode 41
versionName "2026.06.19"
externalNativeBuild {
ndkBuild {
arguments '-j' + Runtime.getRuntime().availableProcessors()
}
cmake.arguments "-DUSE_VENDORED_SDL3=1"
}
ndk {

@ -0,0 +1 @@
Subproject commit f3e15935e822228400064b66677bd3e9d3d7a643

View file

@ -0,0 +1 @@
../../../../data

View file

@ -0,0 +1,933 @@
package com.bithack.principia;
import com.bithack.principia.shared.AutosaveDialog;
import com.bithack.principia.shared.CamTargeterDialog;
import com.bithack.principia.shared.ColorChooserDialog;
import com.bithack.principia.shared.CommandPadDialog;
import com.bithack.principia.shared.CommunityDialog;
import com.bithack.principia.shared.ConfirmDialog;
import com.bithack.principia.shared.ConfirmDialog.OnOptionSelectedListener;
import com.bithack.principia.shared.ConsumableDialog;
import com.bithack.principia.shared.DigitalDisplayDialog;
import com.bithack.principia.shared.EventListenerDialog;
import com.bithack.principia.shared.ExportDialog;
import com.bithack.principia.shared.FactoryDialog;
import com.bithack.principia.shared.FrequencyDialog;
import com.bithack.principia.shared.FrequencyRangeDialog;
import com.bithack.principia.shared.FxEmitterDialog;
import com.bithack.principia.shared.InfoDialog;
import com.bithack.principia.shared.ImportDialog;
import com.bithack.principia.shared.JumperDialog;
import com.bithack.principia.shared.Level;
import com.bithack.principia.shared.LevelDialog;
import com.bithack.principia.shared.LoginDialog;
import com.bithack.principia.shared.NewLevelDialog;
import com.bithack.principia.shared.OpenDialog;
import com.bithack.principia.shared.PkgLevelDialog;
import com.bithack.principia.shared.PlayDialog;
import com.bithack.principia.shared.PromptDialog;
import com.bithack.principia.shared.PromptSettingsDialog;
import com.bithack.principia.shared.PublishDialog;
import com.bithack.principia.shared.PublishedDialog;
import com.bithack.principia.shared.QuickaddDialog;
import com.bithack.principia.shared.RegisterDialog;
import com.bithack.principia.shared.ResourceDialog;
import com.bithack.principia.shared.RobotDialog;
import com.bithack.principia.shared.RubberDialog;
import com.bithack.principia.shared.SandboxTipsDialog;
import com.bithack.principia.shared.SaveAsDialog;
import com.bithack.principia.shared.ScriptDialog;
import com.bithack.principia.shared.SequencerDialog;
import com.bithack.principia.shared.SettingsDialog;
import com.bithack.principia.shared.Sfx2Dialog;
import com.bithack.principia.shared.SfxDialog;
import com.bithack.principia.shared.ShapeExtruderDialog;
import com.bithack.principia.shared.PolygonDialog;
import com.bithack.principia.shared.KeyListenerDialog;
import com.bithack.principia.shared.EmitterDialog;
import com.bithack.principia.shared.DecorationDialog;
import com.bithack.principia.shared.AnimalDialog;
import com.bithack.principia.shared.StickyDialog;
import com.bithack.principia.shared.SynthesizerDialog;
import com.bithack.principia.shared.TimerDialog;
import com.bithack.principia.shared.ToolDialog;
import com.bithack.principia.shared.TouchFieldDialog;
import com.bithack.principia.shared.VariableDialog;
import com.bithack.principia.shared.SoundManDialog;
import com.bithack.principia.shared.MultiSelectDialog;
import com.bithack.principia.shared.VendorDialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Locale;
import android.annotation.SuppressLint;
import android.app.*;
import android.content.*;
import android.content.DialogInterface.OnKeyListener;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.view.*;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.webkit.CookieManager;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import android.net.Uri;
import android.os.*;
import android.graphics.*;
import android.media.*;
import android.hardware.*;
import android.widget.ArrayAdapter;
import org.libsdl.app.SDLActivity;
import java.util.List;
public class PrincipiaActivity extends SDLActivity implements View.OnSystemUiVisibilityChangeListener, DialogInterface.OnDismissListener, DialogInterface.OnShowListener, OnSeekBarChangeListener {
private static final String TAG = "PrincipiaActivity";
public static Dialog wv_dialog;
public static WebView wv;
public static CookieManager wv_cm;
public static int num_dialogs = 0;
static Toast last_toast = null;
private static SettingsDialog settings_dialog;
public static final int LEVEL_LOCAL = 0;
public static final int LEVEL_DB = 1;
public static final int LEVEL_MAIN = 2;
public static final int LEVEL_SYS = 3;
public static final int LEVEL_PARTIAL = 4;
public static final int LEVEL_LOCAL_STATE = 100;
public static final int LEVEL_DB_STATE = 101;
public static final int LEVEL_MAIN_STATE = 102;
public static final int ACTION_OPEN = 1;
public static final int ACTION_RELOAD_GRAPHICS = 2;
public static final int ACTION_RELOAD_LEVEL = 3;
public static final int ACTION_SAVE = 4;
public static final int ACTION_NEW_LEVEL = 5;
public static final int ACTION_STICKY = 6;
public static final int ACTION_LOGIN = 7;
public static final int ACTION_SAVE_COPY = 8;
public static final int ACTION_CONSTRUCT_ENTITY = 9;
public static final int ACTION_OPEN_PLAY = 10;
public static final int ACTION_PUBLISH = 11;
public static final int ACTION_PLAY_PKG = 12;
public static final int ACTION_WARP = 13;
public static final int ACTION_PUBLISH_PKG = 14;
public static final int ACTION_PING = 15;
public static final int ACTION_UPGRADE_LEVEL = 16;
public static final int ACTION_DERIVE = 17;
public static final int ACTION_SET_STICKY_TEXT = 18;
public static final int ACTION_IMPORT_OBJECT = 19;
public static final int ACTION_EXPORT_OBJECT = 20;
public static final int ACTION_MULTIEMITTER_SET = 21;
public static final int ACTION_PUZZLEPLAY = 22;
public static final int ACTION_EDIT = 23;
public static final int ACTION_AUTOFIT_LEVEL_BORDERS = 24;
public static final int ACTION_RESTART_LEVEL = 25;
public static final int ACTION_BACK = 26;
public static final int ACTION_RESELECT = 27;
public static final int ACTION_HIGHLIGHT_SELECTED = 28;
public static final int ACTION_OPEN_AUTOSAVE = 31;
public static final int ACTION_REMOVE_AUTOSAVE = 32;
public static final int ACTION_GOTO_MAINMENU = 33;
public static final int ACTION_DELETE_LEVEL = 34;
public static final int ACTION_DELETE_PARTIAL = 35;
public static final int ACTION_SET_LEVEL_TYPE = 36;
public static final int ACTION_RELOAD_DISPLAY = 37;
public static final int ACTION_ENTITY_MODIFIED = 38;
public static final int ACTION_SET_MODE = 39;
public static final int ACTION_MAIN_MENU_PKG = 40;
public static final int ACTION_WORLD_PAUSE = 41;
public static final int ACTION_CONSTRUCT_ITEM = 45;
public static final int ACTION_SUBMIT_SCORE = 46;
public static final int ACTION_MULTI_DELETE = 47;
public static final int ACTION_OPEN_STATE = 48;
public static final int ACTION_AUTOSAVE = 49;
public static final int ACTION_MULTI_JOINT_STRENGTH = 50;
public static final int ACTION_MULTI_PLASTIC_COLOR = 51;
public static final int ACTION_MULTI_PLASTIC_DENSITY = 52;
public static final int ACTION_MULTI_CHANGE_CONNECTION_RENDER_TYPE = 53;
public static final int ACTION_MULTI_UNLOCK_ALL = 54;
public static final int ACTION_MULTI_DISCONNECT_ALL = 55;
public static final int ACTION_SAVE_STATE = 65;
public static final int ACTION_SELF_DESTRUCT = 71;
public static final int DIALOG_SANDBOX_MENU = 1;
public static final int DIALOG_QUICKADD = 100;
public static final int DIALOG_BEAM_COLOR = 101;
public static final int DIALOG_SAVE = 102;
public static final int DIALOG_OPEN = 103;
public static final int DIALOG_NEW_LEVEL = 104;
public static final int DIALOG_SET_FREQUENCY = 105;
public static final int DIALOG_PIXEL_COLOR = 106;
public static final int DIALOG_CONFIRM_QUIT = 107;
public static final int DIALOG_SET_COMMAND = 108;
public static final int DIALOG_STICKY = 109;
public static final int DIALOG_FXEMITTER = 110;
public static final int DIALOG_CAMTARGETER = 111;
public static final int DIALOG_SET_FREQ_RANGE = 112;
public static final int DIALOG_OPEN_OBJECT = 113;
public static final int DIALOG_EXPORT = 114;
public static final int DIALOG_SET_PKG_LEVEL = 115;
public static final int DIALOG_ROBOT = 116;
public static final int DIALOG_MULTIEMITTER = 117;
public static final int DIALOG_PUZZLE_PLAY = 118;
public static final int DIALOG_TIMER = 119;
public static final int DIALOG_EVENTLISTENER = 120;
public static final int DIALOG_SETTINGS = 121;
public static final int DIALOG_SAVE_COPY = 122;
public static final int DIALOG_LEVEL_PROPERTIES = 123;
public static final int DIALOG_LEVEL_INFO = 124;
public static final int DIALOG_DIGITAL_DISPLAY = 125;
public static final int DIALOG_PLAY_MENU = 126;
public static final int DIALOG_OPEN_AUTOSAVE = 127;
public static final int DIALOG_COMMUNITY = 128;
public static final int DIALOG_PROMPT_SETTINGS = 129;
public static final int DIALOG_PROMPT = 130;
public static final int DIALOG_SFX_EMITTER = 131;
public static final int DIALOG_VARIABLE = 132;
public static final int DIALOG_SYNTHESIZER = 133;
public static final int DIALOG_SEQUENCER = 134;
public static final int DIALOG_SHAPEEXTRUDER = 135;
public static final int DIALOG_JUMPER = 136;
public static final int DIALOG_PUBLISHED = 138;
public static final int DIALOG_TOUCHFIELD = 140;
public static final int DIALOG_ESCRIPT = 141;
public static final int DIALOG_ITEM = 142;
public static final int DIALOG_SANDBOX_MODE = 143;
public static final int DIALOG_RUBBER = 144;
public static final int DIALOG_SOUNDMAN = 148;
public static final int DIALOG_FACTORY = 149;
public static final int DIALOG_SET_FACTION = 150;
public static final int DIALOG_RESOURCE = 151;
public static final int DIALOG_VENDOR = 152;
public static final int DIALOG_ANIMAL = 153;
public static final int DIALOG_POLYGON = 154;
public static final int DIALOG_KEY_LISTENER = 155;
public static final int DIALOG_OPEN_STATE = 156;
public static final int DIALOG_POLYGON_COLOR = 157;
public static final int DIALOG_MULTI_CONFIG = 158;
public static final int DIALOG_EMITTER = 159;
public static final int DIALOG_TREASURE_CHEST = 160;
public static final int DIALOG_DECORATION = 161;
public static final int DIALOG_SFX_EMITTER_2 = 162; // New SFX Emitter dialog (1.5.1+)
public static final int DIALOG_PUBLISH = 300;
public static final int DIALOG_LOGIN = 301;
public static final int DIALOG_SANDBOX_TIPS = 302;
public static final int DIALOG_REGISTER = 303;
public static final int CLOSE_ALL_DIALOGS = 200;
public static final int CLOSE_ABSOLUTELY_ALL_DIALOGS = 201;
public static final int CLOSE_REGISTER_DIALOG = 202;
public static final int DISABLE_REGISTER_LOADER = 203;
public static final int PROMPT_RESPONSE_NONE = 0;
public static final int PROMPT_RESPONSE_A = 1;
public static final int PROMPT_RESPONSE_B = 2;
public static final int PROMPT_RESPONSE_C = 3;
@Override
protected String[] getLibraries() {
return new String[] {
"principia"
};
}
public static PrincipiaActivity mSingleton;
@Override
protected void onCreate(Bundle savedInstanceState) {
mSingleton = this;
super.onCreate(savedInstanceState);
this.init_webview();
this.handle_intent(this.getIntent());
open_adapter = new ArrayAdapter<Level>(SDLActivity.mSingleton,
android.R.layout.select_dialog_item);
QuickaddDialog.object_adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line);
}
public static void message(final String s, final int longd)
{
Log.v("tes message", s);
SDLActivity.mSingleton.runOnUiThread(new Runnable(){
public void run() {
if (last_toast != null) {
last_toast.setText(s);
} else {
last_toast = Toast.makeText(SDLActivity.mSingleton, s, longd==1?Toast.LENGTH_LONG:Toast.LENGTH_SHORT);
}
last_toast.show();
}
});
}
public static void emit_signal(final int signal_id)
{
SDLActivity.mSingleton.runOnUiThread(new Runnable(){
public void run() {
if (signal_id == 200) { // SIGNAL_QUICKADD_REFRESH
Log.v("Principia", "Quickadd refresh.");
QuickaddDialog.object_adapter.clear();
String[] objects = PrincipiaBackend.getObjects().split(",");
Log.v("Principia", String.format("Number of objects: %d", objects.length));
for (String name : objects) {
QuickaddDialog.object_adapter.add(name);
}
}
}
});
}
public static void open_url(final String url)
{
SDLActivity.mSingleton.runOnUiThread(new Runnable(){
public void run() {
String community_host = PrincipiaBackend.getCommunityHost();
if (wv_cm != null) {
String curl_token = PrincipiaBackend.getCookies();
if (curl_token != null) {
// we got relevant cookies from curl!
wv_cm.setCookie("."+community_host, "_PRINCSECURITY="+curl_token);
}
}
wv.stopLoading();
wv.loadUrl(url);
wv_dialog.show();
}
});
}
@SuppressLint("SetJavaScriptEnabled")
public void init_webview()
{
wv_dialog = new Dialog(this, android.R.style.Theme_NoTitleBar_Fullscreen) {
@Override
protected void onCreate(Bundle saved_instance) {
super.onCreate(saved_instance);
getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
};
View v = LayoutInflater.from(this).inflate(R.layout.webview, null);
LinearLayout ll = (LinearLayout)v.findViewById(R.id.wv_ll);
final ProgressBar pb = (ProgressBar)v.findViewById(R.id.wv_progress);
final TextView pb_tv = (TextView)v.findViewById(R.id.wv_progresstext);
wv = new WebView(this);
wv.getSettings().setJavaScriptEnabled(true);
int version = 0;
PackageInfo pi;
try {
pi = getPackageManager().getPackageInfo(getPackageName(), 0);
version = pi.versionCode;
} catch (NameNotFoundException e) {
version = 0;
}
wv.getSettings().setUserAgentString(String.format(Locale.US, "Principia WebView/%d (Android)", version));
wv.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Uri uri = Uri.parse(url);
String host = uri.getHost();
if (uri.getScheme().equals("principia")) {
Log.v("Principia", "set arg "+url);
PrincipiaBackend.setarg(url);
wv_dialog.dismiss();
} else if (host.contains(PrincipiaBackend.getCommunityHost())) {
Log.v("Principia", "Load url "+url);
view.stopLoading();
view.loadUrl(url);
} else {
Log.v(TAG, "unhandled url " + url);
Log.v(TAG, "host: '" + uri.getHost()+"'");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
try {
SDLActivity.mSingleton.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.v(TAG, "No app found to open url: " + url);
}
wv_dialog.dismiss();
}
return true;
}
@Override
public void onPageFinished(WebView view, String url)
{
Log.v("Principia", "page finished: " + url);
pb.setVisibility(View.GONE);
pb_tv.setVisibility(View.GONE);
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon)
{
Log.v("Principia", "page started: " + url);
pb.setVisibility(View.VISIBLE);
pb_tv.setVisibility(View.VISIBLE);
}
});
ll.addView(wv);
Button wv_close = (Button)v.findViewById(R.id.wv_close);
wv_close.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
wv_dialog.dismiss();
}
});
Button wv_reload = (Button)v.findViewById(R.id.wv_reload);
wv_reload.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
wv.reload();
}
});
wv_dialog.setContentView(v);
wv_dialog.setOnShowListener(this);
wv_dialog.setOnDismissListener(this);
wv_cm = CookieManager.getInstance();
wv_dialog.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode,
KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (wv.canGoBack()) {
wv.goBack();
} else {
wv_dialog.dismiss();
}
return true;
}
}
return false;
}
});
}
public static boolean is_cool = false;
public static void open_dialog(final int num)
{
open_dialog(num, false);
}
public static void open_dialog(final int num, final boolean is_cool)
{
PrincipiaActivity.is_cool = is_cool;
SDLActivity.mSingleton.runOnUiThread(new Runnable(){
public void run() {
if (num == DIALOG_PROMPT) {
try {SDLActivity.mSingleton.removeDialog(num);} catch(Exception e){};
}
if (num == DIALOG_PLAY_MENU) {
try {SDLActivity.mSingleton.removeDialog(num);} catch(Exception e){};
}
try {SDLActivity.mSingleton.removeDialog(DIALOG_OPEN);} catch(Exception e){};
try {SDLActivity.mSingleton.removeDialog(DIALOG_OPEN_STATE);} catch(Exception e){};
try {SDLActivity.mSingleton.removeDialog(DIALOG_MULTIEMITTER);} catch(Exception e){};
try {SDLActivity.mSingleton.removeDialog(DIALOG_OPEN_OBJECT);} catch(Exception e){};
SDLActivity.mSingleton.showDialog(num);
}
});
}
private List<Dialog> open_dialogs = new ArrayList<Dialog>();
public static void showInfoDialog(final String description)
{
SDLActivity.mSingleton.runOnUiThread(new Runnable(){
public void run() {
try {SDLActivity.mSingleton.removeDialog(DIALOG_LEVEL_INFO);} catch(Exception e){};
InfoDialog.description = description;
SDLActivity.mSingleton.showDialog(DIALOG_LEVEL_INFO);
}
});
}
public static void confirm(final String text, final String button1, final int action1, final long action1_data, final String button2, final int action2, final long action2_data, final String button3, final int action3, final long action3_data, final boolean dna_sandbox)
{
SDLActivity.mSingleton.runOnUiThread(new Runnable(){
public void run() {
new ConfirmDialog()
.set_listener(new OnOptionSelectedListener() {
@Override
public void onOptionSelected(int option) {
if (option == ConfirmDialog.OPTION_YES) {
PrincipiaBackend.addActionAsInt(action1, action1_data);
} else if (option == ConfirmDialog.OPTION_NO) {
PrincipiaBackend.addActionAsInt(action2, action2_data);
} else if (option == ConfirmDialog.OPTION_3) {
PrincipiaBackend.addActionAsInt(action3, action3_data);
}
}
})
.run(text, button1, button2, button3, dna_sandbox);
}
});
}
public static void showSandboxTips()
{
SDLActivity.mSingleton.runOnUiThread(new Runnable(){
public void run() {
try {SDLActivity.mSingleton.removeDialog(DIALOG_SANDBOX_TIPS);} catch(Exception e){};
SDLActivity.mSingleton.showDialog(DIALOG_SANDBOX_TIPS);
}
});
}
@Override
protected Dialog onCreateDialog(int num)
{
Dialog d = null;
switch (num) {
case DIALOG_SANDBOX_MENU:
{
AlertDialog.Builder bld = new AlertDialog.Builder(this);
final CharSequence[] items;
items = new CharSequence[] {
"Level properties",
"New level",
"Save",
"Save a copy",
"Open",
"Publish online",
"Settings",
"Log in",
"Help: Getting started",
"Help: Principia Wiki",
"Browse levels online",
"Back to menu",
"Quit"
};
bld.setItems(items, new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which) {
/* TODO: Use dialog fragments */
switch (which) {
case 0: showDialog(DIALOG_LEVEL_PROPERTIES); break;
case 1: showDialog(DIALOG_NEW_LEVEL); break;
case 2: if (PrincipiaBackend.getLevelName().isEmpty()) {SaveAsDialog.refresh_name=true; SaveAsDialog.copy=false; showDialog(DIALOG_SAVE);} else PrincipiaBackend.triggerSave(false); break;
case 3: SaveAsDialog.refresh_name = true; SaveAsDialog.copy = true; showDialog(DIALOG_SAVE_COPY); break;
case 4: try {SDLActivity.mSingleton.removeDialog(DIALOG_OPEN);} catch(Exception e){}; showDialog(DIALOG_OPEN); break;
case 5: showDialog(DIALOG_PUBLISH); break;
case 6: showDialog(DIALOG_SETTINGS); break;
case 7: showDialog(DIALOG_LOGIN); break;
case 8: open_url("https://principia-web.se/wiki/Getting_Started"); break;
case 9: open_url("https://principia-web.se/wiki/Main_Page"); break;
case 10: open_url("https://principia-web.se/"); break;
case 11: PrincipiaBackend.addActionAsInt(ACTION_GOTO_MAINMENU, 0); break;
// why
case 12: android.os.Process.killProcess(android.os.Process.myPid()); break;
}
dialog.dismiss();
}
});
d = bld.create();
break;
}
case DIALOG_SETTINGS:
if (settings_dialog == null) {
d = (settings_dialog = new SettingsDialog()).get_dialog();
}
break;
case DIALOG_QUICKADD: d = QuickaddDialog.get_dialog(); break;
case DIALOG_OPEN: d = (new OpenDialog(false)).get_dialog(); break;
case DIALOG_LEVEL_PROPERTIES: d = LevelDialog.get_dialog(); break;
case DIALOG_SAVE_COPY: d = SaveAsDialog.get_dialog(); break;
case DIALOG_SAVE: d = SaveAsDialog.get_dialog(); break;
case DIALOG_LEVEL_INFO: d = (new InfoDialog()).get_dialog(); break;
case DIALOG_STICKY: d = StickyDialog.get_dialog(); break;
case DIALOG_NEW_LEVEL: d = (new NewLevelDialog()).get_dialog(); break;
case DIALOG_ROBOT: d = RobotDialog.get_dialog(); break;
case DIALOG_CAMTARGETER: d = CamTargeterDialog.get_dialog(); break;
case DIALOG_SET_COMMAND: d = CommandPadDialog.get_dialog(); break;
case DIALOG_FXEMITTER: d = FxEmitterDialog.get_dialog(); break;
case DIALOG_EVENTLISTENER: d = EventListenerDialog.get_dialog(); break;
case DIALOG_SET_PKG_LEVEL: d = PkgLevelDialog.get_dialog(); break;
case DIALOG_PIXEL_COLOR: d = ColorChooserDialog.get_dialog(); break;
case DIALOG_BEAM_COLOR: d = ColorChooserDialog.get_dialog(); break;
case DIALOG_POLYGON_COLOR: d = ColorChooserDialog.get_dialog(); break;
case DIALOG_DIGITAL_DISPLAY: d = DigitalDisplayDialog.get_dialog(); break;
case DIALOG_SET_FREQUENCY: d = FrequencyDialog.get_dialog(); break;
case DIALOG_SET_FREQ_RANGE: d = FrequencyRangeDialog.get_dialog(); break;
case DIALOG_EXPORT: d = ExportDialog.get_dialog(); break;
case DIALOG_MULTIEMITTER: d = (new ImportDialog(true)).get_dialog(); break;
case DIALOG_OPEN_OBJECT: d = (new ImportDialog(false)).get_dialog(); break;
case DIALOG_TIMER: d = TimerDialog.get_dialog(); break;
case DIALOG_PLAY_MENU: d = (PlayDialog.create_dialog()); break;
case DIALOG_OPEN_AUTOSAVE: d = (new AutosaveDialog()).get_dialog(); break;
case DIALOG_COMMUNITY: d = (new CommunityDialog()).get_dialog(); break;
case DIALOG_PROMPT_SETTINGS: d = PromptSettingsDialog.get_dialog(); break;
case DIALOG_PROMPT: d = (new PromptDialog()).get_dialog(); break;
case DIALOG_SFX_EMITTER: d = SfxDialog.get_dialog(); break;
case DIALOG_SFX_EMITTER_2: d = Sfx2Dialog.get_dialog(); break;
case DIALOG_VARIABLE: d = VariableDialog.get_dialog(); break;
case DIALOG_SYNTHESIZER: d = SynthesizerDialog.get_dialog(); break;
case DIALOG_SEQUENCER: d = SequencerDialog.get_dialog(); break;
case DIALOG_JUMPER: d = JumperDialog.get_dialog(); break;
case DIALOG_TOUCHFIELD: d = TouchFieldDialog.get_dialog(); break;
case DIALOG_ESCRIPT: d = ScriptDialog.get_dialog(); break;
case DIALOG_ITEM: d = ConsumableDialog.get_dialog(); break;
case DIALOG_SANDBOX_MODE: d = (new ToolDialog()).get_dialog(); break;
case DIALOG_RUBBER: d = RubberDialog.get_dialog(); break;
case DIALOG_SHAPEEXTRUDER: d = ShapeExtruderDialog.get_dialog(); break;
case DIALOG_POLYGON: d = PolygonDialog.get_dialog(); break;
case DIALOG_KEY_LISTENER: d = KeyListenerDialog.get_dialog(); break;
case DIALOG_EMITTER: d = EmitterDialog.get_dialog(); break;
case DIALOG_DECORATION: d = DecorationDialog.get_dialog(); break;
case DIALOG_ANIMAL: d = AnimalDialog.get_dialog(); break;
case DIALOG_SOUNDMAN: d = SoundManDialog.get_dialog(); break;
case DIALOG_MULTI_CONFIG: d = MultiSelectDialog.get_dialog(); break;
case DIALOG_VENDOR: d = VendorDialog.get_dialog(); break;
case DIALOG_FACTORY: d = FactoryDialog.get_dialog(); break;
case DIALOG_RESOURCE: d = ResourceDialog.get_dialog(); break;
case DIALOG_OPEN_STATE: d = (new OpenDialog(true)).get_dialog(); break;
case DIALOG_PUBLISH: d = PublishDialog.get_dialog(); break;
case DIALOG_PUBLISHED: d = (new PublishedDialog()).get_dialog(); break;
case DIALOG_LOGIN: d = LoginDialog.get_dialog(); break;
case DIALOG_SANDBOX_TIPS: d = (new SandboxTipsDialog()).get_dialog(); break;
case DIALOG_REGISTER: d = RegisterDialog.get_dialog(); break;
case CLOSE_ALL_DIALOGS: break; /* do nothing */
case CLOSE_ABSOLUTELY_ALL_DIALOGS:
SDLActivity.mSingleton.runOnUiThread(new Runnable(){
public void run() {
Log.v("Principia", "Closing all dialogs.");
for (Dialog open_dialog : open_dialogs) {
Log.v("Principia", "Closing a dialog["+open_dialog.toString()+"]");
//open_dialog.dismiss();
}
open_dialogs.clear();
}
});
break;
case CLOSE_REGISTER_DIALOG:
SDLActivity.mSingleton.runOnUiThread(new Runnable(){
public void run() {
RegisterDialog.get_dialog().dismiss();
}
});
break;
case DISABLE_REGISTER_LOADER:
SDLActivity.mSingleton.runOnUiThread(new Runnable(){
public void run() {
RegisterDialog.progressbar.setVisibility(View.GONE);
}
});
break;
default: Log.e("Principia", "Unhandled UI Dialog: "+num); break;
}
if (d != null) {
Log.v("Principia", "Adding dialog: "+ d);
//this.open_dialogs.add(d);
if (d.getWindow() != null) {
d.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}
return d;
}
public static ArrayAdapter<Level> open_adapter;
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
if (v == OpenDialog.lv) {
AdapterContextMenuInfo aInfo = (AdapterContextMenuInfo) menuInfo;
final Level level = open_adapter.getItem(aInfo.position);
menu.setHeaderTitle("Options for " + level.get_name());
menu.add(1, 1, 1, "Delete")
.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
new ConfirmDialog()
.set_listener(new OnOptionSelectedListener() {
@Override
public void onOptionSelected(int option) {
if (option == ConfirmDialog.OPTION_YES) {
PrincipiaBackend.addActionAsTriple(ACTION_DELETE_LEVEL, level.get_level_type(), level.get_id(), level.get_save_id());
open_adapter.remove(level);
}
}
})
.run("Are you sure you want to delete this level?");
return false;
}
});
} else if (v == ImportDialog.lv) {
AdapterContextMenuInfo aInfo = (AdapterContextMenuInfo) menuInfo;
final Level level = ImportDialog.list_adapter.getItem(aInfo.position);
menu.setHeaderTitle("Options for " + level.get_name());
menu.add(1, 1, 1, "Delete")
.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
new ConfirmDialog()
.set_listener(new OnOptionSelectedListener() {
@Override
public void onOptionSelected(int option) {
if (option == ConfirmDialog.OPTION_YES) {
PrincipiaBackend.addActionAsInt(ACTION_DELETE_PARTIAL, level.get_id());
ImportDialog.list_adapter.remove(level);
}
}
})
.run("Are you sure you want to delete this object?");
return false;
}
});
}
/* For the details option:
* Level ID
* Level name
* Date modified
*/
}
@Override
public void onPrepareDialog(int d, Dialog dialog, Bundle bundle)
{
switch (d) {
case DIALOG_SETTINGS:
if (settings_dialog != null) {
settings_dialog.load();
}
break;
case DIALOG_QUICKADD: QuickaddDialog.prepare(dialog); break;
case DIALOG_LEVEL_PROPERTIES: LevelDialog.prepare(dialog); break;
case DIALOG_SAVE: SaveAsDialog.prepare(dialog); break;
case DIALOG_SAVE_COPY: SaveAsDialog.prepare(dialog); break;
case DIALOG_ROBOT: RobotDialog.prepare(dialog); break;
case DIALOG_CAMTARGETER: CamTargeterDialog.prepare(dialog); break;
case DIALOG_SET_COMMAND: CommandPadDialog.prepare(dialog); break;
case DIALOG_FXEMITTER: FxEmitterDialog.prepare(dialog); break;
case DIALOG_EVENTLISTENER: EventListenerDialog.prepare(dialog); break;
case DIALOG_SET_PKG_LEVEL: PkgLevelDialog.prepare(dialog); break;
case DIALOG_PIXEL_COLOR: ColorChooserDialog.prepare(dialog, true); break;
case DIALOG_BEAM_COLOR: ColorChooserDialog.prepare(dialog, false); break;
case DIALOG_POLYGON_COLOR: ColorChooserDialog.prepare(dialog, false); break;
case DIALOG_DIGITAL_DISPLAY: DigitalDisplayDialog.prepare(dialog); break;
case DIALOG_SET_FREQUENCY: FrequencyDialog.prepare(dialog); break;
case DIALOG_SET_FREQ_RANGE: FrequencyRangeDialog.prepare(dialog); break;
case DIALOG_EXPORT: ExportDialog.prepare(dialog); break;
case DIALOG_STICKY: StickyDialog.prepare(dialog); break;
case DIALOG_TIMER: TimerDialog.prepare(dialog); break;
case DIALOG_PROMPT_SETTINGS: PromptSettingsDialog.prepare(dialog); break;
case DIALOG_SFX_EMITTER: SfxDialog.prepare(dialog); break;
case DIALOG_SFX_EMITTER_2: Sfx2Dialog.prepare(dialog); break;
case DIALOG_VARIABLE: VariableDialog.prepare(dialog); break;
case DIALOG_SYNTHESIZER: SynthesizerDialog.prepare(dialog); break;
case DIALOG_SEQUENCER: SequencerDialog.prepare(dialog); break;
case DIALOG_JUMPER: JumperDialog.prepare(dialog); break;
case DIALOG_TOUCHFIELD: TouchFieldDialog.prepare(dialog); break;
case DIALOG_ESCRIPT: ScriptDialog.prepare(dialog); break;
case DIALOG_ITEM: ConsumableDialog.prepare(dialog); break;
case DIALOG_RUBBER: RubberDialog.prepare(dialog); break;
case DIALOG_SHAPEEXTRUDER: ShapeExtruderDialog.prepare(dialog); break;
case DIALOG_POLYGON: PolygonDialog.prepare(dialog); break;
case DIALOG_KEY_LISTENER: KeyListenerDialog.prepare(dialog); break;
case DIALOG_EMITTER: EmitterDialog.prepare(dialog); break;
case DIALOG_DECORATION: DecorationDialog.prepare(dialog); break;
case DIALOG_ANIMAL: AnimalDialog.prepare(dialog); break;
case DIALOG_SOUNDMAN: SoundManDialog.prepare(dialog); break;
case DIALOG_MULTI_CONFIG: MultiSelectDialog.prepare(dialog); break;
case DIALOG_VENDOR: VendorDialog.prepare(dialog); break;
case DIALOG_FACTORY: FactoryDialog.prepare(dialog); break;
case DIALOG_RESOURCE: ResourceDialog.prepare(dialog); break;
case DIALOG_PUBLISH: PublishDialog.prepare(dialog); break;
case DIALOG_LOGIN: LoginDialog.prepare(dialog); break;
}
/* Dialogs that need a separate onShowListener */
switch (d) {
case DIALOG_QUICKADD:
case DIALOG_PUBLISH:
case DIALOG_LOGIN:
case DIALOG_SANDBOX_TIPS:
case DIALOG_REGISTER:
case DIALOG_PROMPT_SETTINGS:
case DIALOG_OPEN:
case DIALOG_OPEN_STATE:
case DIALOG_OPEN_OBJECT:
case DIALOG_MULTIEMITTER:
break;
default: dialog.setOnShowListener(this); break;
}
/* Dialogs that need to dismiss HARD */
switch (d) {
default: dialog.setOnDismissListener(this); break;
}
//dialog.setOnCancelListener(this);
}
public void onDismiss(DialogInterface dialog)
{
Log.v("Principia", "dialog onDismiss called");
open_dialogs.remove(dialog);
num_dialogs --;
if (num_dialogs <= 0){
num_dialogs = 0;
PrincipiaBackend.focusGL(true);
}
}
public void onShow(DialogInterface dialog) {
Log.v("Principia", "dialog onShow called");
this.open_dialogs.add((Dialog) dialog);
num_dialogs ++;
if (num_dialogs == 1) {
PrincipiaBackend.focusGL(false);
}
}
public static void on_show(DialogInterface dialog) {
Log.v("Principia", "dialog onShow called");
num_dialogs ++;
if (num_dialogs == 1) {
PrincipiaBackend.focusGL(false);
}
}
@Override
public void onProgressChanged(SeekBar sb, int progress,
boolean fromUser) {
Log.v("Principia", "Progress changed");
if (sb == SynthesizerDialog.synth_pulse_width) {
SynthesizerDialog.synth_pulse_width_tv.setText(String.format(Locale.US, "%.3f", ((float)progress) / 100.f));
} else if (sb == SynthesizerDialog.synth_bitcrushing) {
SynthesizerDialog.synth_bitcrushing_tv.setText(Integer.toString(progress));
} else if (sb == SynthesizerDialog.synth_volume_vibrato_hz) {
SynthesizerDialog.synth_volume_vibrato_hz_tv.setText(Integer.toString(progress));
} else if (sb == SynthesizerDialog.synth_volume_vibrato_extent) {
SynthesizerDialog.synth_volume_vibrato_extent_tv.setText(String.format(Locale.US, "%.3f", ((float)progress) / 100.f));
} else if (sb == SynthesizerDialog.synth_freq_vibrato_hz) {
SynthesizerDialog.synth_freq_vibrato_hz_tv.setText(Integer.toString(progress));
} else if (sb == SynthesizerDialog.synth_freq_vibrato_extent) {
SynthesizerDialog.synth_freq_vibrato_extent_tv.setText(String.format(Locale.US, "%.3f", ((float)progress) / 100.f));
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
private void handle_intent(Intent i)
{
Log.v("Principia", "intent new!");
if (i != null) {
if (i.getScheme() != null && i.getScheme().equals("principia")) {
PrincipiaBackend.setarg(i.getDataString());
}
}
}
@Override
public void onNewIntent(Intent i)
{
super.onNewIntent(i);
handle_intent(i);
}
}

View file

@ -1,4 +1,4 @@
package org.libsdl.app;
package com.bithack.principia;
import com.bithack.principia.shared.Settings;
@ -87,7 +87,7 @@ public class PrincipiaBackend
float creature_absorb_time,
float player_respawn_time
);
public static native void setLevelAllowDerivatives(boolean state);
public static native void setLevelLocked(boolean state);
public static native void setarg(String arg);

View file

@ -1,9 +1,7 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.R;
import android.app.AlertDialog;
import android.app.Dialog;
@ -28,7 +26,7 @@ public class AnimalDialog {
s_animal = (Spinner)view.findViewById(R.id.s_animal);
String[] consumables = PrincipiaBackend.getAnimals().split(",.,");
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(SDLActivity.mSingleton, android.R.layout.select_dialog_item, consumables);
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(PrincipiaActivity.mSingleton, android.R.layout.select_dialog_item, consumables);
s_animal.setAdapter(spinnerArrayAdapter);
_dialog = new AlertDialog.Builder(PrincipiaActivity.mSingleton)

View file

@ -1,7 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
@ -20,12 +19,12 @@ public class AutosaveDialog
.setMessage("Autosave file detected. Open or remove?")
.setPositiveButton("Open", new OnClickListener(){
public void onClick(DialogInterface dialog, int which){
PrincipiaBackend.addActionAsInt(SDLActivity.ACTION_OPEN_AUTOSAVE, 0);
PrincipiaBackend.addActionAsInt(PrincipiaActivity.ACTION_OPEN_AUTOSAVE, 0);
}}
)
.setNegativeButton("Remove", new OnClickListener(){
public void onClick(DialogInterface dialog, int which){
PrincipiaBackend.addActionAsInt(SDLActivity.ACTION_REMOVE_AUTOSAVE, 0);
PrincipiaBackend.addActionAsInt(PrincipiaActivity.ACTION_REMOVE_AUTOSAVE, 0);
}}
)
.create();

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -3,7 +3,7 @@ package com.bithack.principia.shared;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -1,8 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import android.app.AlertDialog;
@ -20,13 +18,13 @@ public class CommunityDialog
.setMessage("Do you want to return to the community site or to the main menu?")
.setPositiveButton("Community", new OnClickListener(){
public void onClick(DialogInterface dialog, int which){
SDLActivity.wv.loadUrl(PrincipiaBackend.getCurrentCommunityUrl());
SDLActivity.wv_dialog.show();
PrincipiaActivity.wv.loadUrl(PrincipiaBackend.getCurrentCommunityUrl());
PrincipiaActivity.wv_dialog.show();
}}
)
.setNegativeButton("Main menu", new OnClickListener(){
public void onClick(DialogInterface dialog, int which){
PrincipiaBackend.addActionAsInt(SDLActivity.ACTION_GOTO_MAINMENU, 0);
PrincipiaBackend.addActionAsInt(PrincipiaActivity.ACTION_GOTO_MAINMENU, 0);
}}
)
.create();

View file

@ -2,8 +2,7 @@ package com.bithack.principia.shared;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.SDLActivity;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.content.DialogInterface;
@ -44,7 +43,7 @@ public class ConfirmDialog
{
final CheckBox cb;
AlertDialog dialog = new AlertDialog.Builder(SDLActivity.getContext()).create();
AlertDialog dialog = new AlertDialog.Builder(PrincipiaActivity.getContext()).create();
if (dna_sandbox_back) {
View view = LayoutInflater.from(PrincipiaActivity.mSingleton).inflate(R.layout.confirm_sandbox, null);
dialog.setView(view);
@ -55,8 +54,8 @@ public class ConfirmDialog
cb = null;
}
dialog.setCancelable(true);
dialog.setOnShowListener(SDLActivity.mSingleton);
dialog.setOnDismissListener(SDLActivity.mSingleton);
dialog.setOnShowListener(PrincipiaActivity.mSingleton);
dialog.setOnDismissListener(PrincipiaActivity.mSingleton);
dialog.setButton(DialogInterface.BUTTON_POSITIVE, button1, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int buttonId) {
if (mListener != null) {

View file

@ -1,8 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import android.app.AlertDialog;
@ -28,7 +26,7 @@ public class ConsumableDialog {
s_consumable = (Spinner)view.findViewById(R.id.s_consumable);
String[] consumables = PrincipiaBackend.getConsumables().split(",");
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(SDLActivity.mSingleton, android.R.layout.select_dialog_item, consumables);
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(PrincipiaActivity.mSingleton, android.R.layout.select_dialog_item, consumables);
s_consumable.setAdapter(spinnerArrayAdapter);
_dialog = new AlertDialog.Builder(PrincipiaActivity.mSingleton)

View file

@ -1,8 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import android.app.AlertDialog;
@ -28,7 +26,7 @@ public class DecorationDialog {
s_deco = (Spinner)view.findViewById(R.id.s_deco);
String[] consumables = PrincipiaBackend.getDecorations().split(",.,");
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(SDLActivity.mSingleton, android.R.layout.select_dialog_item, consumables);
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(PrincipiaActivity.mSingleton, android.R.layout.select_dialog_item, consumables);
s_deco.setAdapter(spinnerArrayAdapter);
_dialog = new AlertDialog.Builder(PrincipiaActivity.mSingleton)

View file

@ -4,8 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
@ -64,7 +63,7 @@ public class DigitalDisplayDialog {
ll_dd = (LinearLayout)view.findViewById(R.id.ll_dd);
ll_wrap = (LinearLayout)view.findViewById(R.id.display_ll_wrap);
np_initial_position = new com.bithack.principia.shared.NumberPicker(SDLActivity.getContext());
np_initial_position = new com.bithack.principia.shared.NumberPicker(PrincipiaActivity.getContext());
np_initial_position.setRange(MIN_INITIAL_POS, 40);
ll_dd.addView((View)np_initial_position);
@ -133,7 +132,7 @@ public class DigitalDisplayDialog {
new_str.setCharAt(y, (isChecked?'1':'0'));
symbols.set(cur_symbol, new_str.toString());
} catch (StringIndexOutOfBoundsException e) {
Log.e("Principia", "An unknown error occured: " + e.getMessage());
Log.e("Principia", "An unknown error occurred: " + e.getMessage());
}
}
});
@ -181,7 +180,7 @@ public class DigitalDisplayDialog {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (num_symbols == 40) {
SDLActivity.message("Maximum number of symbols reached.", 0);
PrincipiaActivity.message("Maximum number of symbols reached.", 0);
return false;
}
@ -200,7 +199,7 @@ public class DigitalDisplayDialog {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (num_symbols == 40) {
SDLActivity.message("Maximum number of symbols reached.", 0);
PrincipiaActivity.message("Maximum number of symbols reached.", 0);
return false;
}

View file

@ -4,7 +4,7 @@ import java.util.Locale;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -5,7 +5,7 @@ import java.util.ArrayList;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import android.app.Dialog;
import android.content.DialogInterface;

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -1,7 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
@ -23,7 +22,7 @@ public class ImportDialog
private final String[] level_names;
public static ListView lv;
public static ArrayAdapter<Level> list_adapter = new ArrayAdapter<Level>(SDLActivity.mSingleton,
public static ArrayAdapter<Level> list_adapter = new ArrayAdapter<Level>(PrincipiaActivity.mSingleton,
android.R.layout.select_dialog_item);
public ImportDialog(final boolean is_multiemitter)
@ -32,7 +31,7 @@ public class ImportDialog
AlertDialog.Builder bld = new AlertDialog.Builder(PrincipiaActivity.mSingleton);
String level_list = PrincipiaBackend.getLevels(SDLActivity.LEVEL_PARTIAL);
String level_list = PrincipiaBackend.getLevels(PrincipiaActivity.LEVEL_PARTIAL);
String[] levels = level_list.split("\n");
level_names = new String[levels.length];
@ -82,7 +81,7 @@ public class ImportDialog
this._dialog.setOnShowListener(new OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
SDLActivity.on_show(dialog);
PrincipiaActivity.on_show(dialog);
ListView lv = _dialog.getListView();
ImportDialog.lv = lv;
if (lv != null) {
@ -104,7 +103,7 @@ public class ImportDialog
}
});
lv.setAdapter(ImportDialog.list_adapter);
SDLActivity.mSingleton.registerForContextMenu(lv);
PrincipiaActivity.mSingleton.registerForContextMenu(lv);
} else {
Log.v("Principia", "listview = null");
}

View file

@ -8,23 +8,20 @@ import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.text.Html;
public class HelpDialog
public class InfoDialog
{
Dialog _dialog;
public static String description ="";
public static String title = "";
public static String description;
public HelpDialog()
public InfoDialog()
{
AlertDialog.Builder bld = new AlertDialog.Builder(PrincipiaActivity.mSingleton);
bld.setTitle(title);
bld.setMessage(Html.fromHtml((description.replaceAll("\n", "<br />"))));
bld.setTitle("Level description");
bld.setMessage(description);
bld.setNeutralButton("Close", new OnClickListener(){
public void onClick(DialogInterface dialog, int which)
{
}
public void onClick(DialogInterface dialog, int which) { }
});
this._dialog = bld.create();

View file

@ -2,7 +2,7 @@ package com.bithack.principia.shared;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;

View file

@ -2,7 +2,7 @@ package com.bithack.principia.shared;
import java.util.ArrayList;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -4,7 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -2,8 +2,7 @@ package com.bithack.principia.shared;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
@ -43,7 +42,7 @@ public class LoginDialog
_dialog.setOnShowListener(new OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
SDLActivity.on_show(dialog);
PrincipiaActivity.on_show(dialog);
Button b = _dialog.getButton(AlertDialog.BUTTON_POSITIVE);
@ -55,7 +54,7 @@ public class LoginDialog
String password = et_password.getText().toString().trim();
if (username.length() <= 0 || password.length() <= 0) {
SDLActivity.message("You must enter a valid username and password.", 0);
PrincipiaActivity.message("You must enter a valid username and password.", 0);
return;
}
@ -74,7 +73,7 @@ public class LoginDialog
btn_register_account.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SDLActivity.open_dialog(SDLActivity.DIALOG_REGISTER);
PrincipiaActivity.open_dialog(PrincipiaActivity.DIALOG_REGISTER);
_dialog.dismiss();
}
});

View file

@ -2,7 +2,7 @@ package com.bithack.principia.shared;
import java.util.ArrayList;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import android.util.Log;

View file

@ -24,7 +24,7 @@ import android.widget.ToggleButton;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import java.util.ArrayList;
@ -275,7 +275,7 @@ public class MultiSelectDialog implements OnSeekBarChangeListener, OnCheckedChan
break;
case PLASTIC_DENSITY:
PrincipiaBackend.addActionAsInt(PrincipiaActivity.ACTION_MULTI_PLASTIC_DENSITY, sb_plastic_density.getProgress());
PrincipiaBackend.addActionAsInt(PrincipiaActivity.ACTION_MULTI_PLASTIC_DENSITY, sb_plastic_density.getProgress()/10);
message = "Changed the density of all plastic entities.";
break;

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;

View file

@ -1,8 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import android.app.AlertDialog;
@ -25,11 +23,11 @@ public class OpenDialog
public OpenDialog(final boolean is_state)
{
SDLActivity.open_adapter.clear();
PrincipiaActivity.open_adapter.clear();
AlertDialog.Builder bld = new AlertDialog.Builder(PrincipiaActivity.mSingleton);
String level_list = PrincipiaBackend.getLevels(is_state ? SDLActivity.LEVEL_LOCAL_STATE : SDLActivity.LEVEL_LOCAL);
String level_list = PrincipiaBackend.getLevels(is_state ? PrincipiaActivity.LEVEL_LOCAL_STATE : PrincipiaActivity.LEVEL_LOCAL);
Log.v("Principia", "Level list: " + level_list);
String[] levels = level_list.split("\n");
@ -60,7 +58,7 @@ public class OpenDialog
Log.v("Principia", "Adding "+name);
SDLActivity.open_adapter.add(l);
PrincipiaActivity.open_adapter.add(l);
level_names[x] = name;
}
@ -82,7 +80,7 @@ public class OpenDialog
@Override
public void onShow(DialogInterface dialog)
{
SDLActivity.on_show(dialog);
PrincipiaActivity.on_show(dialog);
ListView lv = _dialog.getListView();
OpenDialog.lv = lv;
if (lv != null) {
@ -92,7 +90,7 @@ public class OpenDialog
int position, long id) {
Level level = (Level)parent.getAdapter().getItem(position);
if (is_state) {
PrincipiaBackend.openState(level.get_level_type(), level.get_id(), level.get_save_id(), SDLActivity.is_cool); /* XXX */
PrincipiaBackend.openState(level.get_level_type(), level.get_id(), level.get_save_id(), PrincipiaActivity.is_cool); /* XXX */
} else {
PrincipiaBackend.addActionAsInt(PrincipiaActivity.ACTION_OPEN, level.get_id());
}
@ -100,8 +98,8 @@ public class OpenDialog
}
});
lv.setAdapter(SDLActivity.open_adapter);
SDLActivity.mSingleton.registerForContextMenu(lv);
lv.setAdapter(PrincipiaActivity.open_adapter);
PrincipiaActivity.mSingleton.registerForContextMenu(lv);
}
}
});

View file

@ -2,8 +2,7 @@ package com.bithack.principia.shared;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
@ -27,7 +26,7 @@ public class PkgLevelDialog {
view = LayoutInflater.from(PrincipiaActivity.mSingleton).inflate(R.layout.pkg_level_id, null);
np_level_id = new com.bithack.principia.shared.NumberPicker(SDLActivity.getContext());
np_level_id = new com.bithack.principia.shared.NumberPicker(PrincipiaActivity.getContext());
np_level_id.setRange(0, 255);
np_level_id.setValue(1);

View file

@ -3,9 +3,8 @@ package com.bithack.principia.shared;
import java.util.ArrayList;
import java.util.List;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.R;
import android.app.AlertDialog;
@ -21,17 +20,17 @@ public class PlayDialog
*/
static final String[] shared_items = new String[] {
SDLActivity.mSingleton.getString(R.string.open_save),
SDLActivity.mSingleton.getString(R.string.back_to_sandbox),
SDLActivity.mSingleton.getString(R.string.back_to_main_menu),
SDLActivity.mSingleton.getString(R.string.cancel)
PrincipiaActivity.mSingleton.getString(R.string.open_save),
PrincipiaActivity.mSingleton.getString(R.string.back_to_sandbox),
PrincipiaActivity.mSingleton.getString(R.string.back_to_main_menu),
PrincipiaActivity.mSingleton.getString(R.string.cancel)
};
static final String save_state = SDLActivity.mSingleton.getString(R.string.save_state);
static final String save_state = PrincipiaActivity.mSingleton.getString(R.string.save_state);
static final String[] community_items = new String[] {
SDLActivity.mSingleton.getString(R.string.restart_level),
SDLActivity.mSingleton.getString(R.string.back_to_community)
PrincipiaActivity.mSingleton.getString(R.string.restart_level),
PrincipiaActivity.mSingleton.getString(R.string.back_to_community)
};
public static Dialog create_dialog()
@ -41,28 +40,28 @@ public class PlayDialog
if (source > 100) {
source -= 100;
}
AlertDialog.Builder bld = new AlertDialog.Builder(SDLActivity.mSingleton);
AlertDialog.Builder bld = new AlertDialog.Builder(PrincipiaActivity.mSingleton);
List<CharSequence> items = new ArrayList<CharSequence>();
if (PrincipiaBackend.getLevelFlag(33)) {
items.add(save_state);
}
items.add(SDLActivity.mSingleton.getString(R.string.open_save));
items.add(PrincipiaActivity.mSingleton.getString(R.string.open_save));
if (PrincipiaBackend.isAdventure()) {
items.add(SDLActivity.mSingleton.getString(R.string.selfdestruct));
items.add(PrincipiaActivity.mSingleton.getString(R.string.selfdestruct));
}
if (source == 1) {
items.add(SDLActivity.mSingleton.getString(R.string.restart_level));
items.add(SDLActivity.mSingleton.getString(R.string.back_to_community));
items.add(PrincipiaActivity.mSingleton.getString(R.string.restart_level));
items.add(PrincipiaActivity.mSingleton.getString(R.string.back_to_community));
} else if (source == 0) {
items.add(SDLActivity.mSingleton.getString(R.string.back_to_sandbox));
items.add(PrincipiaActivity.mSingleton.getString(R.string.back_to_sandbox));
}
items.add(SDLActivity.mSingleton.getString(R.string.back_to_main_menu));
items.add(SDLActivity.mSingleton.getString(R.string.cancel));
items.add(PrincipiaActivity.mSingleton.getString(R.string.back_to_main_menu));
items.add(PrincipiaActivity.mSingleton.getString(R.string.cancel));
final CharSequence[] real_items = items.toArray(new CharSequence[items.size()]);
@ -71,26 +70,26 @@ public class PlayDialog
String cool = real_items[which].toString();
if (cool.equalsIgnoreCase("open save")) {
SDLActivity.mSingleton.runOnUiThread(new Runnable(){
PrincipiaActivity.mSingleton.runOnUiThread(new Runnable(){
public void run() {
try { SDLActivity.mSingleton.removeDialog(SDLActivity.DIALOG_OPEN); } catch(Exception e) {};
try { SDLActivity.mSingleton.removeDialog(SDLActivity.DIALOG_OPEN_STATE); } catch(Exception e) {};
try { PrincipiaActivity.mSingleton.removeDialog(PrincipiaActivity.DIALOG_OPEN); } catch(Exception e) {};
try { PrincipiaActivity.mSingleton.removeDialog(PrincipiaActivity.DIALOG_OPEN_STATE); } catch(Exception e) {};
}
});
SDLActivity.mSingleton.showDialog(SDLActivity.DIALOG_OPEN_STATE);
PrincipiaActivity.mSingleton.showDialog(PrincipiaActivity.DIALOG_OPEN_STATE);
} else if (cool.equalsIgnoreCase("back to sandbox")) {
PrincipiaBackend.addActionAsInt(SDLActivity.ACTION_BACK, 0);
PrincipiaBackend.addActionAsInt(PrincipiaActivity.ACTION_BACK, 0);
} else if (cool.equalsIgnoreCase("back to community")) {
SDLActivity.wv.loadUrl(PrincipiaBackend.getCurrentCommunityUrl());
SDLActivity.wv_dialog.show();
PrincipiaActivity.wv.loadUrl(PrincipiaBackend.getCurrentCommunityUrl());
PrincipiaActivity.wv_dialog.show();
} else if (cool.equalsIgnoreCase("save state")) {
PrincipiaBackend.addActionAsInt(SDLActivity.ACTION_SAVE_STATE, 0);
PrincipiaBackend.addActionAsInt(PrincipiaActivity.ACTION_SAVE_STATE, 0);
} else if (cool.equalsIgnoreCase("back to main menu")) {
PrincipiaBackend.addActionAsInt(SDLActivity.ACTION_GOTO_MAINMENU, 0);
PrincipiaBackend.addActionAsInt(PrincipiaActivity.ACTION_GOTO_MAINMENU, 0);
} else if (cool.equalsIgnoreCase("restart level")) {
PrincipiaBackend.addActionAsInt(SDLActivity.ACTION_RESTART_LEVEL, 0);
PrincipiaBackend.addActionAsInt(PrincipiaActivity.ACTION_RESTART_LEVEL, 0);
} else if (cool.equalsIgnoreCase("self-destruct")) {
PrincipiaBackend.addActionAsInt(SDLActivity.ACTION_SELF_DESTRUCT, 0);
PrincipiaBackend.addActionAsInt(PrincipiaActivity.ACTION_SELF_DESTRUCT, 0);
} else {
Log.e("PRINCIPIA", "UNKNOWN THING: " + cool);
}
@ -110,7 +109,7 @@ public class PlayDialog
.setNeutralButton("Back", new OnClickListener(){
public void onClick(DialogInterface dialog, int which)
{
PrincipiaBackend.addActionAsInt(SDLActivity.ACTION_BACK, 0);
PrincipiaBackend.addActionAsInt(PrincipiaActivity.ACTION_BACK, 0);
}
})
.setNegativeButton("Cancel", new OnClickListener(){

View file

@ -4,7 +4,7 @@ import java.util.Locale;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;

View file

@ -6,7 +6,7 @@ import java.util.List;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;

View file

@ -2,8 +2,7 @@ package com.bithack.principia.shared;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
@ -41,7 +40,7 @@ public class PromptSettingsDialog
_dialog.setOnShowListener(new OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
SDLActivity.on_show(dialog);
PrincipiaActivity.on_show(dialog);
Button b = _dialog.getButton(AlertDialog.BUTTON_POSITIVE);
@ -59,12 +58,12 @@ public class PromptSettingsDialog
int message_len = message.length();
if (message_len <= 0) {
SDLActivity.message("You must enter a message for the prompt.", 0);
PrincipiaActivity.message("You must enter a message for the prompt.", 0);
return;
}
if (b1_len <= 0 && b2_len <= 0 && b3_len <= 0) {
SDLActivity.message("You must use at least one button.", 0);
PrincipiaActivity.message("You must use at least one button.", 0);
return;
}

View file

@ -2,8 +2,7 @@ package com.bithack.principia.shared;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
@ -41,7 +40,7 @@ public class PublishDialog
_dialog.setOnShowListener(new OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
SDLActivity.on_show(dialog);
PrincipiaActivity.on_show(dialog);
Button b = _dialog.getButton(AlertDialog.BUTTON_POSITIVE);
@ -53,7 +52,7 @@ public class PublishDialog
String descr = et_descr.getText().toString().trim();
if (name.length() <= 0) {
SDLActivity.message("You must enter a name for your level!", 0);
PrincipiaActivity.message("You must enter a name for your level!", 0);
return;
}
@ -61,7 +60,7 @@ public class PublishDialog
PrincipiaBackend.setLevelDescription(descr);
PrincipiaBackend.setLevelLocked(cb_locked.isChecked());
PrincipiaBackend.addActionAsInt(SDLActivity.ACTION_PUBLISH, 0);
PrincipiaBackend.addActionAsInt(PrincipiaActivity.ACTION_PUBLISH, 0);
_dialog.dismiss();
}

View file

@ -2,7 +2,7 @@ package com.bithack.principia.shared;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -2,8 +2,7 @@ package com.bithack.principia.shared;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
@ -44,7 +43,7 @@ public class RegisterDialog
_dialog.setOnShowListener(new OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
SDLActivity.on_show(dialog);
PrincipiaActivity.on_show(dialog);
Button b = _dialog.getButton(AlertDialog.BUTTON_POSITIVE);
@ -58,22 +57,22 @@ public class RegisterDialog
final String email = et_email.getText().toString().trim();
if (password.length() < 6 || password.length() > 100) {
SDLActivity.message("Your password must be at least 3 and at most 100 characters.", 0);
PrincipiaActivity.message("Your password must be at least 3 and at most 100 characters.", 0);
return;
}
if (!password.equals(password_confirm)) {
SDLActivity.message("The two passwords you entered don't match.", 0);
PrincipiaActivity.message("The two passwords you entered don't match.", 0);
return;
}
if (username.length() < 3 || username.length() > 20) {
SDLActivity.message("Your username must be at least 3 and at most 20 characters.", 0);
PrincipiaActivity.message("Your username must be at least 3 and at most 20 characters.", 0);
return;
}
if (!android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
SDLActivity.message("You must enter a valid email address.", 0);
PrincipiaActivity.message("You must enter a valid email address.", 0);
return;
}

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -4,7 +4,7 @@ import java.util.ArrayList;
import com.bithack.principia.shared.MultiSpinner.MultiSpinnerListener;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -2,7 +2,7 @@ package com.bithack.principia.shared;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;

View file

@ -2,8 +2,7 @@ package com.bithack.principia.shared;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
@ -34,13 +33,13 @@ public class SandboxTipsDialog
.setTitle("Tips & tricks")
.setPositiveButton("OK", new OnClickListener(){public void onClick(DialogInterface dialog, int which) {}})
.setNeutralButton("Next", null)
.setNegativeButton("More tips & tricks", new OnClickListener(){public void onClick(DialogInterface dialog, int which){SDLActivity.open_url("https://principia-web.se/wiki/Getting_Started");}})
.setNegativeButton("More tips & tricks", new OnClickListener(){public void onClick(DialogInterface dialog, int which){PrincipiaActivity.open_url("https://principia-web.se/wiki/Getting_Started");}})
.create();
_dialog.setOnShowListener(new OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
SDLActivity.on_show(dialog);
PrincipiaActivity.on_show(dialog);
Button b = _dialog.getButton(AlertDialog.BUTTON_NEUTRAL);

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -5,7 +5,7 @@ import com.bithack.principia.R;
import com.bithack.principia.shared.ConfirmDialog.OnOptionSelectedListener;
import com.bithack.principia.shared.CustomLinearLayout.OnKeyboardStateChangedListener;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import android.app.Dialog;
import android.content.DialogInterface;

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -2,7 +2,7 @@ package com.bithack.principia.shared;
import java.util.Locale;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -13,8 +13,7 @@ import android.widget.Spinner;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
public class Sfx2Dialog {
static Dialog _dialog;
@ -36,7 +35,7 @@ public class Sfx2Dialog {
s_sfx = (Spinner)view.findViewById(R.id.s_sfx);
String[] sound_effects = PrincipiaBackend.getSounds().split(",.,");
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(SDLActivity.mSingleton, android.R.layout.select_dialog_item, sound_effects);
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(PrincipiaActivity.mSingleton, android.R.layout.select_dialog_item, sound_effects);
s_sfx.setAdapter(spinnerArrayAdapter);
bld.setTitle("SFX Emitter");
@ -73,6 +72,6 @@ public class Sfx2Dialog {
PrincipiaBackend.setPropertyInt8(1, sfx_global.isChecked() ? 1 : 0);
//TODO: property_index 2 (sound chunk)
PrincipiaBackend.setPropertyInt8(3, sfx_loop.isChecked() ? 1 : 0);
SDLActivity.message("Saved properties for SFX Emitter.", 0);
PrincipiaActivity.message("Saved properties for SFX Emitter.", 0);
}
}

View file

@ -1,7 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
@ -33,7 +32,7 @@ public class SfxDialog {
s_sfx = (Spinner)view.findViewById(R.id.s_sfx);
String[] sound_effects = PrincipiaBackend.getSfxSounds().split(",");
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(SDLActivity.mSingleton, android.R.layout.select_dialog_item, sound_effects);
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(PrincipiaActivity.mSingleton, android.R.layout.select_dialog_item, sound_effects);
s_sfx.setAdapter(spinnerArrayAdapter);
bld.setTitle("SFX Emitter (Old)");
@ -68,6 +67,6 @@ public class SfxDialog {
{
PrincipiaBackend.setPropertyInt(0, s_sfx.getSelectedItemId());
PrincipiaBackend.setPropertyInt8(1, sfx_global.isChecked() ? 1 : 0);
SDLActivity.message("Saved properties for SFX Emitter.", 0);
PrincipiaActivity.message("Saved properties for SFX Emitter.", 0);
}
}

View file

@ -4,7 +4,7 @@ import java.util.Locale;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;

View file

@ -1,7 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
@ -33,7 +32,7 @@ public class SoundManDialog {
s_sounds = (Spinner)view.findViewById(R.id.sm_sounds);
String[] array_data = PrincipiaBackend.getSounds().split(",.,");
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(SDLActivity.mSingleton, android.R.layout.select_dialog_item, array_data);
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(PrincipiaActivity.mSingleton, android.R.layout.select_dialog_item, array_data);
s_sounds.setAdapter(spinnerArrayAdapter);
_dialog = new AlertDialog.Builder(PrincipiaActivity.mSingleton)

View file

@ -1,7 +1,7 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -2,8 +2,7 @@ package com.bithack.principia.shared;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import android.app.Dialog;
import android.os.Bundle;
@ -106,12 +105,12 @@ public class SynthesizerDialog {
synth_freq_vibrato_hz_tv = (TextView)view.findViewById(R.id.synth_freq_vibrato_hz_tv);
synth_freq_vibrato_extent_tv = (TextView)view.findViewById(R.id.synth_freq_vibrato_extent_tv);
synth_pulse_width.setOnSeekBarChangeListener(SDLActivity.mSingleton);
synth_bitcrushing.setOnSeekBarChangeListener(SDLActivity.mSingleton);
synth_volume_vibrato_hz.setOnSeekBarChangeListener(SDLActivity.mSingleton);
synth_volume_vibrato_extent.setOnSeekBarChangeListener(SDLActivity.mSingleton);
synth_freq_vibrato_hz.setOnSeekBarChangeListener(SDLActivity.mSingleton);
synth_freq_vibrato_extent.setOnSeekBarChangeListener(SDLActivity.mSingleton);
synth_pulse_width.setOnSeekBarChangeListener(PrincipiaActivity.mSingleton);
synth_bitcrushing.setOnSeekBarChangeListener(PrincipiaActivity.mSingleton);
synth_volume_vibrato_hz.setOnSeekBarChangeListener(PrincipiaActivity.mSingleton);
synth_volume_vibrato_extent.setOnSeekBarChangeListener(PrincipiaActivity.mSingleton);
synth_freq_vibrato_hz.setOnSeekBarChangeListener(PrincipiaActivity.mSingleton);
synth_freq_vibrato_extent.setOnSeekBarChangeListener(PrincipiaActivity.mSingleton);
sp_waveform = (Spinner)view.findViewById(R.id.synth_waveform);
sp_waveform.setOnItemSelectedListener(new OnItemSelectedListener() {
@ -131,7 +130,7 @@ public class SynthesizerDialog {
});
String[] waveforms = PrincipiaBackend.getSynthWaveforms().split(",");
ArrayAdapter<String> spinner_aa = new ArrayAdapter<String>(SDLActivity.getContext(), android.R.layout.select_dialog_item, waveforms);
ArrayAdapter<String> spinner_aa = new ArrayAdapter<String>(PrincipiaActivity.getContext(), android.R.layout.select_dialog_item, waveforms);
sp_waveform.setAdapter(spinner_aa);
}

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;

View file

@ -6,7 +6,7 @@ import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import com.bithack.principia.shared.RangeSeekBar.OnRangeSeekBarChangeListener;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;

View file

@ -2,8 +2,7 @@ package com.bithack.principia.shared;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;
import org.libsdl.app.PrincipiaBackend;
import org.libsdl.app.SDLActivity;
import com.bithack.principia.PrincipiaBackend;
import android.app.AlertDialog;
import android.app.Dialog;
@ -82,9 +81,9 @@ public class VariableDialog {
String s = et_name.getText().toString().trim().replaceAll("[^a-zA_Z0-9_-]", "");
if (s.length() > 0 && s.length() < 50) {
PrincipiaBackend.setPropertyString(0, s);
SDLActivity.message("Saved variable name.", 0);
PrincipiaActivity.message("Saved variable name.", 0);
} else {
SDLActivity.message("You must enter a valid variable name. a-zA-Z0-9_- allowed.", 0);
PrincipiaActivity.message("You must enter a valid variable name. a-zA-Z0-9_- allowed.", 0);
}
}
}

View file

@ -1,6 +1,6 @@
package com.bithack.principia.shared;
import org.libsdl.app.PrincipiaBackend;
import com.bithack.principia.PrincipiaBackend;
import com.bithack.principia.PrincipiaActivity;
import com.bithack.principia.R;

View file

@ -13,9 +13,8 @@ interface HIDDevice
public String getProductName();
public UsbDevice getDevice();
public boolean open();
public int sendFeatureReport(byte[] report);
public int sendOutputReport(byte[] report);
public boolean getFeatureReport(byte[] report);
public int writeReport(byte[] report, boolean feature);
public boolean readReport(byte[] report, boolean feature);
public void setFrozen(boolean frozen);
public void close();
public void shutdown();

View file

@ -19,9 +19,13 @@ import android.os.*;
import java.lang.Runnable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.UUID;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDevice {
private static final String TAG = "hidapi";
@ -33,10 +37,19 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
private boolean mIsConnected = false;
private boolean mIsChromebook = false;
private boolean mIsReconnecting = false;
private boolean mHasEnabledNotifications = false;
private boolean mHasSeenInputUpdate = false;
private boolean mFrozen = false;
private LinkedList<GattOperation> mOperations;
GattOperation mCurrentOperation = null;
private Handler mHandler;
private int mProductId = -1;
private int mReportId = 0;
private UUID mInputCharacteristic;
private static final int D0G_BLE2_PID = 0x1106;
private static final int TRITON_BLE_PID = 0x1303;
private static final int TRANSPORT_AUTO = 0;
private static final int TRANSPORT_BREDR = 1;
@ -44,11 +57,15 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
private static final int CHROMEBOOK_CONNECTION_CHECK_INTERVAL = 10000;
static public final UUID steamControllerService = UUID.fromString("100F6C32-1735-4313-B402-38567131E5F3");
static public final UUID inputCharacteristic = UUID.fromString("100F6C33-1735-4313-B402-38567131E5F3");
static public final UUID reportCharacteristic = UUID.fromString("100F6C34-1735-4313-B402-38567131E5F3");
static final UUID steamControllerService = UUID.fromString("100F6C32-1735-4313-B402-38567131E5F3");
static final UUID inputCharacteristicD0G = UUID.fromString("100F6C33-1735-4313-B402-38567131E5F3");
static final UUID inputCharacteristicTriton_0x45 = UUID.fromString("100F6C7A-1735-4313-B402-38567131E5F3");
static final UUID inputCharacteristicTriton_0x47 = UUID.fromString("100F6C7C-1735-4313-B402-38567131E5F3");
static final UUID reportCharacteristic = UUID.fromString("100F6C34-1735-4313-B402-38567131E5F3");
static private final byte[] enterValveMode = new byte[] { (byte)0xC0, (byte)0x87, 0x03, 0x08, 0x07, 0x00 };
private HashMap<Integer, BluetoothGattCharacteristic> mOutputReportChars = new HashMap<Integer, BluetoothGattCharacteristic>();
static class GattOperation {
private enum Operation {
CHR_READ,
@ -61,6 +78,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
byte[] mValue;
BluetoothGatt mGatt;
boolean mResult = true;
int mDelayMs = 0;
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid) {
mGatt = gatt;
@ -68,6 +86,13 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
mUuid = uuid;
}
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, int delayMs) {
mGatt = gatt;
mOp = operation;
mUuid = uuid;
mDelayMs = delayMs;
}
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, byte[] value) {
mGatt = gatt;
mOp = operation;
@ -75,6 +100,14 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
mValue = value;
}
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, byte[] value, int delayMs) {
mGatt = gatt;
mOp = operation;
mUuid = uuid;
mValue = value;
mDelayMs = delayMs;
}
public void run() {
// This is executed in main thread
BluetoothGattCharacteristic chr;
@ -136,6 +169,8 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
return mResult;
}
public int getDelayMs() { return mDelayMs; }
private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
BluetoothGattService valveService = mGatt.getService(steamControllerService);
if (valveService == null)
@ -154,32 +189,38 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
static public GattOperation enableNotification(BluetoothGatt gatt, UUID uuid) {
return new GattOperation(gatt, Operation.ENABLE_NOTIFICATION, uuid);
}
static public GattOperation enableNotification(BluetoothGatt gatt, UUID uuid, int delayMs) {
return new GattOperation(gatt, Operation.ENABLE_NOTIFICATION, uuid, delayMs);
}
}
public HIDDeviceBLESteamController(HIDDeviceManager manager, BluetoothDevice device) {
HIDDeviceBLESteamController(HIDDeviceManager manager, BluetoothDevice device) {
mManager = manager;
mDevice = device;
mDeviceId = mManager.getDeviceIDForIdentifier(getIdentifier());
mIsRegistered = false;
mIsChromebook = mManager.getContext().getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
mIsChromebook = SDLActivity.isChromebook();
mOperations = new LinkedList<GattOperation>();
mHandler = new Handler(Looper.getMainLooper());
mGatt = connectGatt();
mHasEnabledNotifications = false;
mHasSeenInputUpdate = false;
// final HIDDeviceBLESteamController finalThis = this;
// mHandler.postDelayed(new Runnable() {
// @Override
// public void run() {
// void run() {
// finalThis.checkConnectionForChromebookIssue();
// }
// }, CHROMEBOOK_CONNECTION_CHECK_INTERVAL);
}
public String getIdentifier() {
String getIdentifier() {
return String.format("SteamController.%s", mDevice.getAddress());
}
public BluetoothGatt getGatt() {
BluetoothGatt getGatt() {
return mGatt;
}
@ -219,7 +260,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
return btManager.getConnectionState(mDevice, BluetoothProfile.GATT);
}
public void reconnect() {
void reconnect() {
if (getConnectionState() != BluetoothProfile.STATE_CONNECTED) {
mGatt.disconnect();
@ -314,8 +355,45 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
Log.v(TAG, "Found Valve steam controller service " + service.getUuid());
for (BluetoothGattCharacteristic chr : service.getCharacteristics()) {
if (chr.getUuid().equals(inputCharacteristic)) {
Log.v(TAG, "Found input characteristic");
if (chr.getUuid().equals(inputCharacteristicTriton_0x45)) {
Log.v(TAG, "Found Triton input characteristic 0x45");
mProductId = TRITON_BLE_PID;
mReportId = 0x45;
mInputCharacteristic = chr.getUuid();
} else if (chr.getUuid().equals(inputCharacteristicTriton_0x47)) {
Log.v(TAG, "Found Triton input characteristic 0x47");
mProductId = TRITON_BLE_PID;
mReportId = 0x47;
mInputCharacteristic = chr.getUuid();
} else if (chr.getUuid().equals(inputCharacteristicD0G)) {
Log.v(TAG, "Found D0G input characteristic");
mProductId = D0G_BLE2_PID;
mReportId = 0x03;
mInputCharacteristic = chr.getUuid();
} else {
Pattern reportPattern = Pattern.compile("100F6C([0-9A-Z]{2})", Pattern.CASE_INSENSITIVE);
Matcher matcher = reportPattern.matcher(chr.getUuid().toString());
if (matcher.find()) {
try {
int reportId = Integer.parseInt(matcher.group(1), 16);
reportId -= 0x35;
if (reportId >= 0x80) {
// This is a Triton output report characteristic that we need to care about.
Log.v(TAG, "Found Triton output report 0x" + Integer.toString(reportId, 16));
mOutputReportChars.put(reportId, chr);
}
}
catch (NumberFormatException nfe) {
Log.w(TAG, "Could not parse report characteristic " + chr.getUuid().toString() + ": " + nfe.toString());
}
}
}
}
for (BluetoothGattCharacteristic chr : service.getCharacteristics()) {
if (chr.getUuid().equals(mInputCharacteristic)) {
// Start notifications
BluetoothGattDescriptor cccd = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
if (cccd != null) {
@ -372,21 +450,30 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
mCurrentOperation = mOperations.removeFirst();
}
// Run in main thread
mHandler.post(new Runnable() {
@Override
public void run() {
synchronized (mOperations) {
if (mCurrentOperation == null) {
Log.e(TAG, "Current operation null in executor?");
return;
}
Runnable gattOperationRunnable = new Runnable() {
@Override
public void run() {
synchronized (mOperations) {
if (mCurrentOperation == null) {
Log.e(TAG, "Current operation null in executor?");
return;
}
mCurrentOperation.run();
// now wait for the GATT callback and when it comes, finish this operation
mCurrentOperation.run();
// now wait for the GATT callback and when it comes, finish this operation
}
}
}
});
};
if (mCurrentOperation.getDelayMs() == 0) {
// Run in main thread
mHandler.post(gattOperationRunnable);
}
else {
// If we have a delay on this operation, wait before we post it.
mHandler.postDelayed(gattOperationRunnable, mCurrentOperation.getDelayMs());
}
}
private void queueGattOperation(GattOperation op) {
@ -397,16 +484,47 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
}
private void enableNotification(UUID chrUuid) {
GattOperation op = HIDDeviceBLESteamController.GattOperation.enableNotification(mGatt, chrUuid);
// Add a 500ms delay to notification write for Amazon Fire TV devices, as otherwise if we do this too quickly after connecting
// it will return success and then silently drop the operation on the floor.
GattOperation op = HIDDeviceBLESteamController.GattOperation.enableNotification(mGatt, chrUuid, 500);
queueGattOperation(op);
// Amazon Fire devices can also silently timeout on writeDescriptor, so
// set up a little delayed check that will attempt to write a second time.
//
// While this only seems to be needed on Amazon Fire TV devices at present, it
// doesn't hurt to have a retry on other devices as well.
//
final HIDDeviceBLESteamController finalThis = this;
final UUID finalUuid = chrUuid;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (!finalThis.mHasEnabledNotifications) {
if (finalThis.mHasSeenInputUpdate) {
// Amazon Five devices may have enabled notifications on the input characteristic and not given us a callback. If we've seen
// input reports, though, somewhat by definition notifications are enabled.
Log.w(TAG, "WriteDescriptor has never returned, but we've seen input reports. Moving on with controller initialization.");
finalThis.mHasEnabledNotifications = true;
finalThis.enableValveMode();
return;
}
// Give one more try.
GattOperation retry = HIDDeviceBLESteamController.GattOperation.enableNotification(finalThis.mGatt, finalUuid, 500);
finalThis.queueGattOperation(retry);
}
}
}, 1000);
}
public void writeCharacteristic(UUID uuid, byte[] value) {
void writeCharacteristic(UUID uuid, byte[] value) {
GattOperation op = HIDDeviceBLESteamController.GattOperation.writeCharacteristic(mGatt, uuid, value);
queueGattOperation(op);
}
public void readCharacteristic(UUID uuid) {
void readCharacteristic(UUID uuid) {
GattOperation op = HIDDeviceBLESteamController.GattOperation.readCharacteristic(mGatt, uuid);
queueGattOperation(op);
}
@ -415,6 +533,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
////////////// BluetoothGattCallback overridden methods
//////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onConnectionStateChange(BluetoothGatt g, int status, int newState) {
//Log.v(TAG, "onConnectionStateChange status=" + status + " newState=" + newState);
mIsReconnecting = false;
@ -437,6 +556,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
// Disconnection is handled in SteamLink using the ACTION_ACL_DISCONNECTED Intent.
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
//Log.v(TAG, "onServicesDiscovered status=" + status);
if (status == 0) {
@ -446,23 +566,33 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
mIsConnected = false;
gatt.disconnect();
mGatt = connectGatt(false);
}
else {
} else {
if (getProductId() == TRITON_BLE_PID) {
// Android will not properly play well with Data Length Extensions without manually requesting a large MTU,
// and Triton controllers require DLE support.
//
// 517 is basically a "magic number" as far as Android's bluetooth code is concerned, so do not change
// this value. It is functionally "please enable data length extensions" on some Android builds.
mGatt.requestMtu(517);
}
probeService(this);
}
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
//Log.v(TAG, "onCharacteristicRead status=" + status + " uuid=" + characteristic.getUuid());
if (characteristic.getUuid().equals(reportCharacteristic) && !mFrozen) {
mManager.HIDDeviceFeatureReport(getId(), characteristic.getValue());
mManager.HIDDeviceReportResponse(getId(), characteristic.getValue());
}
finishCurrentGattOperation();
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
//Log.v(TAG, "onCharacteristicWrite status=" + status + " uuid=" + characteristic.getUuid());
@ -470,7 +600,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
// Only register controller with the native side once it has been fully configured
if (!isRegistered()) {
Log.v(TAG, "Registering Steam Controller with ID: " + getId());
mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0, 0, 0, 0);
mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0, 0, 0, 0, true, mReportId);
setRegistered();
}
}
@ -478,44 +608,68 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
finishCurrentGattOperation();
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
// Enable this for verbose logging of controller input reports
//Log.v(TAG, "onCharacteristicChanged uuid=" + characteristic.getUuid() + " data=" + HexDump.dumpHexString(characteristic.getValue()));
if (characteristic.getUuid().equals(inputCharacteristic) && !mFrozen) {
if (characteristic.getUuid().equals(mInputCharacteristic) && !mFrozen) {
mHasSeenInputUpdate = true;
mManager.HIDDeviceInputReport(getId(), characteristic.getValue());
}
}
@Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
//Log.v(TAG, "onDescriptorRead status=" + status);
}
private void enableValveMode()
{
BluetoothGattService valveService = mGatt.getService(steamControllerService);
if (valveService == null)
return;
BluetoothGattCharacteristic reportChr = valveService.getCharacteristic(reportCharacteristic);
if (reportChr != null) {
if (getProductId() == TRITON_BLE_PID) {
// For Triton we just mark things registered.
Log.v(TAG, "Registering Triton Steam Controller with ID: " + getId());
mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0, 0, 0, 0, true, mReportId);
setRegistered();
} else {
// For the original controller, we need to manually enter Valve mode.
Log.v(TAG, "Writing report characteristic to enter valve mode");
reportChr.setValue(enterValveMode);
mGatt.writeCharacteristic(reportChr);
}
}
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
BluetoothGattCharacteristic chr = descriptor.getCharacteristic();
//Log.v(TAG, "onDescriptorWrite status=" + status + " uuid=" + chr.getUuid() + " descriptor=" + descriptor.getUuid());
if (chr.getUuid().equals(inputCharacteristic)) {
boolean hasWrittenInputDescriptor = true;
BluetoothGattCharacteristic reportChr = chr.getService().getCharacteristic(reportCharacteristic);
if (reportChr != null) {
Log.v(TAG, "Writing report characteristic to enter valve mode");
reportChr.setValue(enterValveMode);
gatt.writeCharacteristic(reportChr);
}
if (chr.getUuid().equals(mInputCharacteristic)) {
mHasEnabledNotifications = true;
enableValveMode();
}
finishCurrentGattOperation();
}
@Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
//Log.v(TAG, "onReliableWriteCompleted status=" + status);
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
//Log.v(TAG, "onReadRemoteRssi status=" + status);
}
@Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
//Log.v(TAG, "onMtuChanged status=" + status);
}
@ -538,9 +692,20 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
@Override
public int getProductId() {
// We don't have an easy way to query from the Bluetooth device, but we know what it is
final int D0G_BLE2_PID = 0x1106;
return D0G_BLE2_PID;
if (mProductId > 0) {
// We've already set a product ID.
return mProductId;
}
if (mDevice.getName().startsWith("Steam Ctrl")) {
// We're a newer Triton device
mProductId = TRITON_BLE_PID;
} else {
// We're an OG Steam Controller
mProductId = D0G_BLE2_PID;
}
return mProductId;
}
@Override
@ -575,50 +740,64 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
}
@Override
public int sendFeatureReport(byte[] report) {
public int writeReport(byte[] report, boolean feature) {
if (!isRegistered()) {
Log.e(TAG, "Attempted sendFeatureReport before Steam Controller is registered!");
Log.e(TAG, "Attempted writeReport before Steam Controller is registered!");
if (mIsConnected) {
probeService(this);
}
return -1;
}
// We need to skip the first byte, as that doesn't go over the air
byte[] actual_report = Arrays.copyOfRange(report, 1, report.length - 1);
//Log.v(TAG, "sendFeatureReport " + HexDump.dumpHexString(actual_report));
writeCharacteristic(reportCharacteristic, actual_report);
return report.length;
}
@Override
public int sendOutputReport(byte[] report) {
if (!isRegistered()) {
Log.e(TAG, "Attempted sendOutputReport before Steam Controller is registered!");
if (mIsConnected) {
probeService(this);
if (feature) {
// We need to skip the first byte, as that doesn't go over the air
byte[] actual_report = Arrays.copyOfRange(report, 1, report.length - 1);
//Log.v(TAG, "writeFeatureReport " + HexDump.dumpHexString(actual_report));
writeCharacteristic(reportCharacteristic, actual_report);
return report.length;
} else {
// If we're an original-recipe Steam Controller we just write to the characteristic directly.
if (getProductId() == D0G_BLE2_PID) {
//Log.v(TAG, "writeOutputReport " + HexDump.dumpHexString(report));
writeCharacteristic(reportCharacteristic, report);
return report.length;
}
// If we're a Triton, we need to find the correct report characteristic.
if (report.length > 0) {
int reportId = report[0] & 0xFF;
BluetoothGattCharacteristic targetedReportCharacteristic = mOutputReportChars.get(reportId);
if (targetedReportCharacteristic != null) {
byte[] actual_report = Arrays.copyOfRange(report, 1, report.length - 1);
//Log.v(TAG, "writeOutputReport 0x" + Integer.toString(reportId, 16) + " " + HexDump.dumpHexString(report));
writeCharacteristic(targetedReportCharacteristic.getUuid(), actual_report);
return report.length;
} else {
Log.w(TAG, "Got report write request for unknown report type 0x" + Integer.toString(reportId, 16));
}
}
return -1;
}
//Log.v(TAG, "sendFeatureReport " + HexDump.dumpHexString(report));
writeCharacteristic(reportCharacteristic, report);
return report.length;
return -1;
}
@Override
public boolean getFeatureReport(byte[] report) {
public boolean readReport(byte[] report, boolean feature) {
if (!isRegistered()) {
Log.e(TAG, "Attempted getFeatureReport before Steam Controller is registered!");
Log.e(TAG, "Attempted readReport before Steam Controller is registered!");
if (mIsConnected) {
probeService(this);
}
return false;
}
//Log.v(TAG, "getFeatureReport");
readCharacteristic(reportCharacteristic);
return true;
if (feature) {
readCharacteristic(reportCharacteristic);
return true;
} else {
// Not implemented
return false;
}
}
@Override

View file

@ -32,7 +32,7 @@ public class HIDDeviceManager {
private static HIDDeviceManager sManager;
private static int sManagerRefCount = 0;
public static HIDDeviceManager acquire(Context context) {
static public HIDDeviceManager acquire(Context context) {
if (sManagerRefCount == 0) {
sManager = new HIDDeviceManager(context);
}
@ -40,7 +40,7 @@ public class HIDDeviceManager {
return sManager;
}
public static void release(HIDDeviceManager manager) {
static public void release(HIDDeviceManager manager) {
if (manager == sManager) {
--sManagerRefCount;
if (sManagerRefCount == 0) {
@ -108,12 +108,12 @@ public class HIDDeviceManager {
HIDDeviceRegisterCallback();
mSharedPreferences = mContext.getSharedPreferences("hidapi", Context.MODE_PRIVATE);
mIsChromebook = mContext.getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
mIsChromebook = SDLActivity.isChromebook();
// if (shouldClear) {
// SharedPreferences.Editor spedit = mSharedPreferences.edit();
// spedit.clear();
// spedit.commit();
// spedit.apply();
// }
// else
{
@ -121,11 +121,11 @@ public class HIDDeviceManager {
}
}
public Context getContext() {
Context getContext() {
return mContext;
}
public int getDeviceIDForIdentifier(String identifier) {
int getDeviceIDForIdentifier(String identifier) {
SharedPreferences.Editor spedit = mSharedPreferences.edit();
int result = mSharedPreferences.getInt(identifier, 0);
@ -135,7 +135,7 @@ public class HIDDeviceManager {
}
spedit.putInt(identifier, result);
spedit.commit();
spedit.apply();
return result;
}
@ -193,7 +193,11 @@ public class HIDDeviceManager {
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction(HIDDeviceManager.ACTION_USB_PERMISSION);
mContext.registerReceiver(mUsbBroadcast, filter);
if (Build.VERSION.SDK_INT >= 33) { /* Android 13.0 (TIRAMISU) */
mContext.registerReceiver(mUsbBroadcast, filter, Context.RECEIVER_EXPORTED);
} else {
mContext.registerReceiver(mUsbBroadcast, filter);
}
for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
handleUsbDeviceAttached(usbDevice);
@ -252,6 +256,8 @@ public class HIDDeviceManager {
0x24c6, // PowerA
0x2c22, // Qanba
0x2dc8, // 8BitDo
0x3537, // GameSir
0x37d7, // Flydigi
0x9886, // ASTRO Gaming
};
@ -284,9 +290,13 @@ public class HIDDeviceManager {
0x1532, // Razer Wildcat
0x20d6, // PowerA
0x24c6, // PowerA
0x294b, // Snakebyte
0x2dc8, // 8BitDo
0x2e24, // Hyperkin
0x2e95, // SCUF
0x3285, // Nacon
0x3537, // GameSir
0x366c, // ByoWave
};
if (usbInterface.getId() == 0 &&
@ -351,7 +361,7 @@ public class HIDDeviceManager {
HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_index);
int id = device.getId();
mDevicesById.put(id, device);
HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), usbInterface.getId(), usbInterface.getInterfaceClass(), usbInterface.getInterfaceSubclass(), usbInterface.getInterfaceProtocol());
HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), usbInterface.getId(), usbInterface.getInterfaceClass(), usbInterface.getInterfaceSubclass(), usbInterface.getInterfaceProtocol(), false, 0);
}
}
}
@ -372,7 +382,7 @@ public class HIDDeviceManager {
return;
}
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE) || (Build.VERSION.SDK_INT < 18 /* Android 4.3 (JELLY_BEAN_MR2) */)) {
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Log.d(TAG, "Couldn't initialize Bluetooth, this version of Android does not support Bluetooth LE");
return;
}
@ -404,7 +414,11 @@ public class HIDDeviceManager {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
mContext.registerReceiver(mBluetoothBroadcast, filter);
if (Build.VERSION.SDK_INT >= 33) { /* Android 13.0 (TIRAMISU) */
mContext.registerReceiver(mBluetoothBroadcast, filter, Context.RECEIVER_EXPORTED);
} else {
mContext.registerReceiver(mBluetoothBroadcast, filter);
}
if (mIsChromebook) {
mHandler = new Handler(Looper.getMainLooper());
@ -431,7 +445,7 @@ public class HIDDeviceManager {
// Chromebooks do not pass along ACTION_ACL_CONNECTED / ACTION_ACL_DISCONNECTED properly.
// This function provides a sort of dummy version of that, watching for changes in the
// connected devices and attempting to add controllers as things change.
public void chromebookConnectionHandler() {
void chromebookConnectionHandler() {
if (!mIsChromebook) {
return;
}
@ -470,7 +484,7 @@ public class HIDDeviceManager {
}, 10000);
}
public boolean connectBluetoothDevice(BluetoothDevice bluetoothDevice) {
boolean connectBluetoothDevice(BluetoothDevice bluetoothDevice) {
Log.v(TAG, "connectBluetoothDevice device=" + bluetoothDevice);
synchronized (this) {
if (mBluetoothDevices.containsKey(bluetoothDevice)) {
@ -491,7 +505,7 @@ public class HIDDeviceManager {
return true;
}
public void disconnectBluetoothDevice(BluetoothDevice bluetoothDevice) {
void disconnectBluetoothDevice(BluetoothDevice bluetoothDevice) {
synchronized (this) {
HIDDeviceBLESteamController device = mBluetoothDevices.get(bluetoothDevice);
if (device == null)
@ -505,7 +519,7 @@ public class HIDDeviceManager {
}
}
public boolean isSteamController(BluetoothDevice bluetoothDevice) {
boolean isSteamController(BluetoothDevice bluetoothDevice) {
// Sanity check. If you pass in a null device, by definition it is never a Steam Controller.
if (bluetoothDevice == null) {
return false;
@ -516,7 +530,13 @@ public class HIDDeviceManager {
return false;
}
return bluetoothDevice.getName().equals("SteamController") && ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) != 0);
// Steam Controllers will always support Bluetooth Low Energy
if ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) == 0) {
return false;
}
// Match on the name either the original Steam Controller or the new second-generation one advertise with.
return bluetoothDevice.getName().equals("SteamController") || bluetoothDevice.getName().startsWith("Steam Ctrl");
}
private void close() {
@ -559,7 +579,7 @@ public class HIDDeviceManager {
////////// JNI interface functions
//////////////////////////////////////////////////////////////////////////////////////////////////////
public boolean initialize(boolean usb, boolean bluetooth) {
boolean initialize(boolean usb, boolean bluetooth) {
Log.v(TAG, "initialize(" + usb + ", " + bluetooth + ")");
if (usb) {
@ -571,7 +591,7 @@ public class HIDDeviceManager {
return true;
}
public boolean openDevice(int deviceID) {
boolean openDevice(int deviceID) {
Log.v(TAG, "openDevice deviceID=" + deviceID);
HIDDevice device = getDevice(deviceID);
if (device == null) {
@ -591,13 +611,10 @@ public class HIDDeviceManager {
} else {
flags = 0;
}
if (Build.VERSION.SDK_INT >= 33 /* Android 14.0 (U) */) {
Intent intent = new Intent(HIDDeviceManager.ACTION_USB_PERMISSION);
intent.setPackage(mContext.getPackageName());
mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, intent, flags));
} else {
mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), flags));
}
Intent intent = new Intent(HIDDeviceManager.ACTION_USB_PERMISSION);
intent.setPackage(mContext.getPackageName());
mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, intent, flags));
} catch (Exception e) {
Log.v(TAG, "Couldn't request permission for USB device " + usbDevice);
HIDDeviceOpenResult(deviceID, false);
@ -613,9 +630,9 @@ public class HIDDeviceManager {
return false;
}
public int sendOutputReport(int deviceID, byte[] report) {
int writeReport(int deviceID, byte[] report, boolean feature) {
try {
//Log.v(TAG, "sendOutputReport deviceID=" + deviceID + " length=" + report.length);
//Log.v(TAG, "writeReport deviceID=" + deviceID + " length=" + report.length);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
@ -623,33 +640,16 @@ public class HIDDeviceManager {
return -1;
}
return device.sendOutputReport(report);
return device.writeReport(report, feature);
} catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
}
return -1;
}
public int sendFeatureReport(int deviceID, byte[] report) {
boolean readReport(int deviceID, byte[] report, boolean feature) {
try {
//Log.v(TAG, "sendFeatureReport deviceID=" + deviceID + " length=" + report.length);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
HIDDeviceDisconnected(deviceID);
return -1;
}
return device.sendFeatureReport(report);
} catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
}
return -1;
}
public boolean getFeatureReport(int deviceID, byte[] report) {
try {
//Log.v(TAG, "getFeatureReport deviceID=" + deviceID);
//Log.v(TAG, "readReport deviceID=" + deviceID);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
@ -657,14 +657,14 @@ public class HIDDeviceManager {
return false;
}
return device.getFeatureReport(report);
return device.readReport(report, feature);
} catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
}
return false;
}
public void closeDevice(int deviceID) {
void closeDevice(int deviceID) {
try {
Log.v(TAG, "closeDevice deviceID=" + deviceID);
HIDDevice device;
@ -688,11 +688,11 @@ public class HIDDeviceManager {
private native void HIDDeviceRegisterCallback();
private native void HIDDeviceReleaseCallback();
native void HIDDeviceConnected(int deviceID, String identifier, int vendorId, int productId, String serial_number, int release_number, String manufacturer_string, String product_string, int interface_number, int interface_class, int interface_subclass, int interface_protocol);
native void HIDDeviceConnected(int deviceID, String identifier, int vendorId, int productId, String serial_number, int release_number, String manufacturer_string, String product_string, int interface_number, int interface_class, int interface_subclass, int interface_protocol, boolean bBluetooth, int reportID);
native void HIDDeviceOpenPending(int deviceID);
native void HIDDeviceOpenResult(int deviceID, boolean opened);
native void HIDDeviceDisconnected(int deviceID);
native void HIDDeviceInputReport(int deviceID, byte[] report);
native void HIDDeviceFeatureReport(int deviceID, byte[] report);
native void HIDDeviceReportResponse(int deviceID, byte[] report);
}

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