Compare commits

..

195 Commits

Author SHA1 Message Date
minjaesong
97a7a36030 version tag on app configuration 2023-08-17 15:47:31 +09:00
minjaesong
662069466a skybox size adjustment 2023-08-17 02:04:05 +09:00
minjaesong
52cff00338 commit 2023-08-16 22:39:31 +09:00
minjaesong
1a40334f8e auto zip for .app packaging 2023-08-16 22:26:27 +09:00
minjaesong
763f512419 script for assets_release 2023-08-16 22:17:09 +09:00
minjaesong
620a1c6956 GL_UNSIGNED_SHORT works just fine on macOS?! 2023-08-16 21:56:04 +09:00
minjaesong
5f4fcdba69 apple m chip workaround (2) 2023-08-16 21:46:54 +09:00
minjaesong
7a79f444b2 apple m chip workaround 2023-08-16 21:38:23 +09:00
minjaesong
e4b947ce69 Float16FrameBuffer 2023-08-16 17:51:31 +09:00
minjaesong
fdfec960ca reverse gravity adaptation of the last commit 2023-08-16 16:33:53 +09:00
minjaesong
75021ecfa2 fixing issue #48 2023-08-16 16:03:54 +09:00
minjaesong
c90ef21bfa calendar UI mouseover 2023-08-15 19:02:25 +09:00
minjaesong
3fce5d7e95 calendar UI 2023-08-15 14:58:50 +09:00
minjaesong
8db1228e70 calendar wip 2023-08-15 04:54:43 +09:00
minjaesong
5f7f724058 tileatlas: atlas size will automatically expand if it's too small 2023-08-14 18:47:39 +09:00
minjaesong
fab4179068 fixing issue #47 using new tag on blocks.csv 2023-08-14 18:16:05 +09:00
minjaesong
32803b6f18 incomplete fix for horizontal bouncing on T-shaped platform arrangement 2023-08-14 04:10:10 +09:00
minjaesong
f8f75fb7b6 options to change atlas texture size 2023-08-14 03:53:25 +09:00
minjaesong
9919a99032 fix: phys ccd would only trigger on its last iteration due to a stupid oversight 2023-08-13 16:54:46 +09:00
minjaesong
6a43d1a5bd calendar sprite removing a spring 2023-08-13 15:36:24 +09:00
minjaesong
24c971e4b8 oh wait thats not it 2023-08-11 21:08:35 +09:00
minjaesong
62f0fd7c68 hiding the phys artefact by forcefully holding down-key for long enough 2023-08-11 21:05:47 +09:00
minjaesong
3dec312989 phys glitch kinda fixed but i'm no longer sure about that 2023-08-11 17:03:51 +09:00
minjaesong
77b51a45dd no highp on blur shader 2023-08-11 13:03:45 +09:00
minjaesong
d1b4ce3404 something's fixed but have no idea what 2023-08-11 12:35:36 +09:00
minjaesong
fd7b88307c . 2023-08-11 09:29:30 +09:00
minjaesong
579b6b5b29 somehow fixed but now jumping while walking against wall changes jump behav 2023-08-11 01:04:34 +09:00
minjaesong
cef58f6a73 phys debugging; see L818@ActorWithBody.kt 2023-08-10 23:49:43 +09:00
minjaesong
c0c98c3b80 some locale changes; remoCon changes on load menu 2023-08-08 17:44:23 +09:00
minjaesong
88d844cc09 actor draw planting offset 2023-08-08 17:14:13 +09:00
minjaesong
2411db17a7 calendar fixture wip 2023-08-08 16:41:40 +09:00
minjaesong
53d372be38 there's no way #33 is fixed so easily but im committing it anyway 2023-08-08 12:09:22 +09:00
minjaesong
88831051c8 revised ingame date format 2023-08-08 09:01:34 +09:00
minjaesong
87d92ecb74 some random ideas for future self 2023-08-08 01:39:33 +09:00
minjaesong
6672dffdbc new passwd for new version 2023-08-07 14:45:07 +09:00
minjaesong
cd00ab4c7f fix: hq2x results graphical issue on some systems 2023-08-07 14:30:36 +09:00
minjaesong
014306c209 2k skybox tex; trilinear blending of atmos vars 2023-08-07 13:59:45 +09:00
minjaesong
30fb57eca3 skybox: two different setup for AM/PN 2023-08-06 18:37:56 +09:00
minjaesong
52ad8f0c46 improved skybox model 2023-08-05 17:20:35 +09:00
minjaesong
1b08039018 updating numbers for v0.3.3 2023-08-05 00:45:35 +09:00
minjaesong
c701519cb9 unloading test_texture 2023-08-05 00:25:25 +09:00
minjaesong
75e6669d49 temp fix: platform-ladder not working 2023-08-05 00:16:00 +09:00
minjaesong
18631064d4 hosek skybox moved outside of basegame; moonlight impl 2023-08-04 13:43:14 +09:00
minjaesong
9fe6618cc9 fix: splash goes black when hq2x is enabled 2023-08-04 12:53:44 +09:00
minjaesong
7b8d6d6913 fix: bad number formatting on debug window 2023-08-04 00:53:30 +09:00
minjaesong
385a882937 stars: more realistic twinkle, change of axial tilt changes starmap 'altitude' 2023-08-03 23:55:19 +09:00
minjaesong
c73461a407 const-ifying shaders 2023-08-03 18:37:23 +09:00
minjaesong
f7e4987785 less crazy twinkling 2023-08-03 00:29:27 +09:00
minjaesong
78bd88858b twinkling stars 2023-08-03 00:11:17 +09:00
minjaesong
d2b1346252 diurnal motion on stars 2023-08-02 22:44:04 +09:00
minjaesong
fb28fd8a76 brought 'sunset orange' back 2023-08-02 22:14:25 +09:00
minjaesong
36d25c6479 the stars are rendered but still some works left 2023-08-02 18:55:41 +09:00
minjaesong
2ade76147c fix: skybox edge case on deg ±75 2023-08-02 18:44:12 +09:00
minjaesong
59d9adbbd1 stars wip 2023-08-02 17:52:42 +09:00
minjaesong
821c7c77d8 much more elegant solution than stretching texture using batch 2023-08-02 16:37:15 +09:00
minjaesong
3308f09e08 some other 'weather' elements (assets only) 2023-08-02 10:57:52 +09:00
minjaesong
37d45e22ad backdrop is stretched far enought so that the stretchedness is not observable 2023-08-01 22:01:56 +09:00
minjaesong
1ac861fa82 skybox lut 2023-08-01 17:22:45 +09:00
minjaesong
451808cd1c skybox atlas texture generation 2023-08-01 16:50:37 +09:00
minjaesong
0c00b3b7cc borders on quickslot images 2023-07-31 21:49:11 +09:00
minjaesong
1669f7fdd0 actual maths solution for the smoothLinear 2023-07-30 22:52:00 +09:00
minjaesong
f4bfe84009 better smooth-linear function 2023-07-30 18:35:36 +09:00
minjaesong
91cf08e93a 64 pixels for gradmap instead of 128 2023-07-30 03:36:31 +09:00
minjaesong
33a8112454 skybox: taller grad window, smooth grad clamping 2023-07-30 03:29:14 +09:00
minjaesong
439cde09fc this is the best curve 🫠 2023-07-26 15:10:15 +09:00
minjaesong
2a62435712 wtf was that 2023-07-26 00:58:17 +09:00
minjaesong
5495552db5 yet another sky model changes 2023-07-26 00:09:47 +09:00
minjaesong
e04d0284bb another experiments with the hosek model 2023-07-25 22:11:10 +09:00
minjaesong
ad601ffd7e oops forgot about the alpha channel 2023-07-25 16:57:13 +09:00
minjaesong
987ec1fd98 more sky model changes 2023-07-25 16:53:02 +09:00
minjaesong
4fb30821f1 sky model update 2023-07-25 15:15:12 +09:00
minjaesong
a73c536941 skybox model changes on negative deg 2023-07-25 03:47:59 +09:00
minjaesong
4c1f16fe91 executable renamed from 'java' to 'Terrarum' 2023-07-24 00:56:01 +09:00
minjaesong
6df78b59a9 screenshot taking extracted to its own function 2023-07-22 14:19:09 +09:00
minjaesong
28c4d8f11b texture2D -> texture 2023-07-22 03:45:21 +09:00
minjaesong
cdfc86398c hq2x shader using modernised syntax 2023-07-22 03:41:09 +09:00
minjaesong
91d94d2dab partially working hq2x, may not work on macOS tho 2023-07-21 20:29:17 +09:00
minjaesong
0af2e57368 wtf is going on 2023-07-21 17:41:22 +09:00
minjaesong
fbce707cac option for screen filtering mode 2023-07-21 13:14:02 +09:00
minjaesong
9d7bd37394 automated menuwork for control panel 2023-07-15 20:21:29 +09:00
minjaesong
df8bcf79af titlescreen: weather change is reflected to the skybox AND daylight 2023-07-15 13:33:09 +09:00
minjaesong
e328457259 improved control panel making 2023-07-14 17:03:04 +09:00
minjaesong
9baec6c7a1 improved slider mouse op 2023-07-14 16:50:25 +09:00
minjaesong
d05364f43f horizontal slider 2023-07-14 14:34:28 +09:00
minjaesong
e7ed3d8eae spinners will now round to nearest valid number 2023-07-13 21:08:41 +09:00
minjaesong
da6da79186 fix: previous 'centering' attempt was 8 pixels off 2023-07-13 20:08:20 +09:00
minjaesong
0767521441 uiloadmanage: going back to list will reset the list scroll 2023-07-13 16:34:01 +09:00
minjaesong
30aca57cbc savegame renaming 2023-07-13 15:45:35 +09:00
minjaesong
e512c6c7ad fix: textinput contained by sliding panel would not get text input 2023-07-13 15:12:30 +09:00
minjaesong
6ebf79a8e3 savelist cell width now matches management buttons; buttons and thumnail now well positioned 2023-07-13 14:13:37 +09:00
minjaesong
e5d5feeb38 fix: crafting UI is not centred 2023-07-13 13:49:50 +09:00
minjaesong
8e9d2371c8 mem gauge size changed to match the radiobutton-bar 2023-07-13 00:21:12 +09:00
minjaesong
1f5d032ad8 teleporter: no new world if memory is full 2023-07-12 21:45:22 +09:00
minjaesong
7993ccd2e5 memory gauge on teleporter world search 2023-07-12 21:30:50 +09:00
minjaesong
c77f1ffd23 removing auto/manual save selection: is practically useless 2023-07-12 10:40:21 +09:00
minjaesong
4eb7a8a77e fix: if two savegame has identical lastmodifiedtime, file with lower number will be preferred 2023-07-12 10:00:47 +09:00
minjaesong
10f92a11a9 loadlist: version number of the savegame 2023-07-12 02:23:49 +09:00
minjaesong
c5659e2833 loadlost: preloading game screenshots 2023-07-11 21:11:19 +09:00
minjaesong
173f99f87d two getthumbnail funs merget into one 2023-07-11 19:52:56 +09:00
minjaesong
64e05a4f17 load list: thumbnail on management scr 2023-07-11 15:18:44 +09:00
minjaesong
c033260ec5 debugpanel: solar altitude and atmos turbidity 2023-07-11 12:01:08 +09:00
minjaesong
22191bd377 daylight model edited to match the skybox 2023-07-11 01:55:15 +09:00
minjaesong
79f19120f2 replacing min/max usage with kotlin's 2023-07-11 01:54:46 +09:00
minjaesong
d96b7d1b84 fix: creating new game works again 2023-07-11 00:34:32 +09:00
minjaesong
2b62b4f413 fix: model having wrong turbidity value 2023-07-10 23:14:56 +09:00
minjaesong
f0fa5830bd moving hosek datasets to assets dir 2023-07-10 21:38:50 +09:00
minjaesong
ec24dc9870 no day-night cycle on titlescreen demo 2023-07-10 20:44:35 +09:00
minjaesong
6bc3d0e6ad deploying new skybox model 2023-07-10 19:47:44 +09:00
minjaesong
64c610e77e model improvements 2023-07-10 04:00:49 +09:00
minjaesong
b25ea9654c model improvements 2023-07-10 03:16:10 +09:00
minjaesong
b6b98562a2 preliminary skybox model 1 2023-07-10 02:57:41 +09:00
minjaesong
c93b70f537 world portal: rename and delete now working 2023-07-09 19:17:13 +09:00
minjaesong
fb67b0ef5a fix: not having IME set would cause NPE 2023-07-09 02:27:26 +09:00
minjaesong
7c7b3de68d swapping save delete/cancel button so that accidental double click would not delete the save 2023-07-09 02:20:38 +09:00
minjaesong
71df31b93d working autosave chooser 2023-07-08 23:26:47 +09:00
minjaesong
9b24014191 keyboard control symbol for IME will follow the current IME selection 2023-07-08 22:24:16 +09:00
minjaesong
02308a7918 autosave marker on save list 2023-07-08 22:12:08 +09:00
minjaesong
03c6061a12 game loading is back but newgame is broken 2023-07-08 21:53:19 +09:00
minjaesong
325e67f999 damaged savegame is handled by the management scr 2023-07-08 18:49:56 +09:00
minjaesong
211f936bd3 save manage scr 2023-07-08 16:12:15 +09:00
minjaesong
1f6fa49d19 minor improvements 2023-07-08 14:20:53 +09:00
minjaesong
13810fc09b working loading spinner; closing menu while loading will gracefully kill the loading thread 2023-07-08 14:04:14 +09:00
minjaesong
f95bc36c98 and now fa and fis works the same? wtf? 2023-07-08 03:33:02 +09:00
minjaesong
d507d84950 the file io is cursed 2023-07-08 03:12:15 +09:00
minjaesong
b31da6ffec . 2023-07-07 15:44:42 +09:00
minjaesong
3593894c0f hopefully more lightweight init 2023-07-07 12:27:54 +09:00
minjaesong
c28b286553 changes in fade-slide transition container 2023-07-07 00:19:56 +09:00
minjaesong
c0a3da1b66 fix: inscript - s key had wrong glyph 2023-07-06 22:43:08 +09:00
minjaesong
02cf5fdce5 tamil99 2023-07-06 22:07:21 +09:00
minjaesong
1e6f51e16c oops now it's broken but I still had to commit lol 2023-07-05 21:35:41 +09:00
minjaesong
c61c169048 more elegant UILoadSavegame wip 2023-07-05 20:16:53 +09:00
minjaesong
5c58c3006b inscript: ime update 2023-07-05 13:29:43 +09:00
minjaesong
742cabb81f is this the way? 2023-07-05 01:15:48 +09:00
minjaesong
07d5e571d6 windows build: smaller exe file 2023-07-05 01:11:06 +09:00
minjaesong
305242045f inscript keyboard layout for hindi 2023-07-05 00:44:13 +09:00
minjaesong
67388999f0 lang update 2023-07-04 21:50:20 +09:00
minjaesong
b0cc1180bb fix: app wont launch if its path contains whitespaces 2023-07-04 21:32:38 +09:00
minjaesong
453459e3b6 fix: some UIs won't fade in/out on open/close 2023-07-03 21:35:46 +09:00
minjaesong
bad72dd353 simple SAVING ui for teleportation 2023-07-03 20:26:30 +09:00
minjaesong
13185f0565 preliminary gui thing for teleportation 2023-07-03 17:46:57 +09:00
minjaesong
fcaf4c97f1 seemingly working world teleporter (no saving... ui tho) 2023-07-03 00:10:46 +09:00
minjaesong
9c396e7b8d new world via teleporter wip 2023-07-02 18:54:04 +09:00
minjaesong
afb7dff5d2 some comment elaboration 2023-07-02 01:25:34 +09:00
minjaesong
5d0514040c lang split into two files 2023-06-30 16:20:57 +09:00
minjaesong
7c1806946b worldportal: showing tooltip to tell why the button is disabled 2023-06-30 03:07:45 +09:00
minjaesong
e5e02681b8 weather only change on titlescreen 2023-06-30 00:53:46 +09:00
minjaesong
6db3baf691 clearing up interpolation functions 2023-06-30 00:14:28 +09:00
minjaesong
07cbcbe79b better title screen camera smoothing 2023-06-29 22:50:44 +09:00
minjaesong
57a9f7febc graph guidance colour scheme change; added easter egg where the camera might pan towards left 2023-06-29 02:56:33 +09:00
minjaesong
16cfaaea27 titlescreen follows the terrain better 2023-06-28 22:49:45 +09:00
minjaesong
72c742897e fix: load menu buttons are pushed when they should not listen to the touchdown event 2023-06-28 17:47:04 +09:00
minjaesong
23af64deb4 proper savegame backups sorting 2023-06-28 16:42:38 +09:00
minjaesong
bb017fa9b7 gui for load savegame 2023-06-28 16:10:15 +09:00
minjaesong
1745bb16db save deletion works but gui is still wip 2023-06-28 11:05:28 +09:00
minjaesong
370583d1af actual red button for DELETE 2023-06-28 00:55:36 +09:00
minjaesong
66b651c627 delete character file gui wip 2023-06-27 22:46:16 +09:00
minjaesong
c5874a7f3d finally working again: create new character
todo: make delete character work
2023-06-27 21:13:51 +09:00
minjaesong
057905c3b7 thumb generation for player saves 2023-06-27 01:21:05 +09:00
minjaesong
2b50562002 save juggling for autosaves 2023-06-26 23:10:52 +09:00
minjaesong
73a8198378 fix: loading a game would load the oldest backup save 2023-06-26 21:43:25 +09:00
minjaesong
1ef479124e actually working load manual/auto button 2023-06-26 20:18:00 +09:00
minjaesong
e5e8028b3f fix: clickOnceListener would not fired if screen is magnified 2023-06-26 19:07:25 +09:00
minjaesong
739b51af95 manual/auto selection for savegame loading 2023-06-26 18:18:59 +09:00
minjaesong
f9f49ab63c new savegame loader is not quite working yet 2023-06-26 01:09:47 +09:00
minjaesong
a497463349 some ui updates 2023-06-25 20:46:52 +09:00
minjaesong
253db56c4f the baloon now has opacity control 2023-06-25 13:58:37 +09:00
minjaesong
3d13941060 new savegame loading wip 2023-06-24 23:44:48 +09:00
minjaesong
592e489411 warning for apple rosetta 2023-06-24 02:06:22 +09:00
minjaesong
49b2011ea0 a little bit generalised titlescreen warning printing 2023-06-24 01:12:43 +09:00
minjaesong
61e6255b52 some warning for apple rosetta 2023-06-24 01:03:58 +09:00
minjaesong
2e956f89f5 fix for edge case where 64-bit x86 CPU not reporting itself as AMD64 2023-06-24 00:40:59 +09:00
minjaesong
e8ffd1f844 proper bootstrap codes 2023-06-23 18:44:05 +09:00
minjaesong
0882145f9c some autosave stuffs; bootloader to actually use bundled runtime 2023-06-23 17:29:49 +09:00
minjaesong
28e2179e44 don't xstartonfirstthread the bootstrapper 2023-06-23 12:11:19 +09:00
minjaesong
48eb1ffd8f printout child proc's out and err to console 2023-06-22 23:11:34 +09:00
minjaesong
6daccb2e62 locales 2023-06-22 22:27:56 +09:00
minjaesong
8c9d5a26fb more code trimming 2023-06-22 22:05:10 +09:00
minjaesong
ee3e5b14cd rm unused code snippet 2023-06-22 21:21:09 +09:00
minjaesong
5c39df9080 bootstrapper for the App so that the user can change the max heap in-game 2023-06-22 21:08:09 +09:00
minjaesong
5d77694316 windows build script now produces .exe 2023-06-21 23:49:42 +09:00
minjaesong
cf111d2507 world portal writing current world to actorvalue 'worldportaldict' if it's not there 2023-06-20 13:45:32 +09:00
minjaesong
724ace3f00 for now ui simply closes on teleport target selection 2023-06-20 13:22:14 +09:00
minjaesong
1457cbffb3 worldportal: submitting teleportrequest works, needs UI refinement 2023-06-20 00:15:53 +09:00
minjaesong
7a42066392 electric: rising/falling edge and level detection 2023-06-19 18:42:08 +09:00
minjaesong
528b975350 wiresim: signal sinking actors are only getting updated when the sim calls for 2023-06-19 16:34:39 +09:00
minjaesong
9e9064dd55 world portal: world search is now new world 2023-06-19 00:50:55 +09:00
minjaesong
138c6d22d2 some font stuffs for ui 2023-06-18 21:40:06 +09:00
minjaesong
a33f0e7ab4 world search ui integrated to world portal ui 2023-06-18 21:29:18 +09:00
minjaesong
93c427473d inventory backdrop is now image 2023-06-18 16:02:25 +09:00
minjaesong
6b8798a19e single screen ui for world portal 2023-06-18 01:28:51 +09:00
minjaesong
376595d7cd fix: scroll controller for portal listing is 2 px shorter that it should 2023-06-18 00:40:55 +09:00
minjaesong
4cc52b5585 fix: storage chest ui would be shifted to left and any mouse button would trigger the action 2023-06-17 23:19:09 +09:00
minjaesong
0ff71f39fe list scroll for portallisting 2023-06-17 17:10:13 +09:00
minjaesong
13f487a562 inventory navbar to its own uiitem 2023-06-17 16:46:15 +09:00
minjaesong
0599ce91b1 reflection function update 2023-06-12 15:08:42 +09:00
264 changed files with 9856 additions and 3081 deletions

View File

@@ -13,6 +13,10 @@
<element id="extracted-dir" path="$PROJECT_DIR$/lib/gdx-controllers-desktop-2.2.1.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/GetCpuName.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/jxinput-1.0.0.jar" path-in-jar="/" />
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-stdlib.jar" path-in-jar="/" />
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-reflect.jar" path-in-jar="/" />
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk7.jar" path-in-jar="/" />
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk8.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/commons-csv-1.8.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/prtree.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/Terrarum_Joise.jar" path-in-jar="/" />
@@ -72,21 +76,17 @@
<element id="extracted-dir" path="$PROJECT_DIR$/lib/gdx-platform-1.11.0-natives-armeabi-v7a.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/gdx-platform-1.11.0-natives-desktop.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/gdx-platform-1.11.0-natives-x86_64.jar" path-in-jar="/" />
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.8.21/kotlin-stdlib-1.8.21.jar" path-in-jar="/" />
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" path-in-jar="/" />
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.8.21/kotlin-stdlib-common-1.8.21.jar" path-in-jar="/" />
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-test/1.8.21/kotlin-test-1.8.21.jar" path-in-jar="/" />
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.8.21/kotlin-reflect-1.8.21.jar" path-in-jar="/" />
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk8.jar" path-in-jar="/" />
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-reflect.jar" path-in-jar="/" />
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk7.jar" path-in-jar="/" />
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-stdlib.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/graal-sdk-22.3.1.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/icu4j-71.1.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/js-22.3.1-edit.jar" path-in-jar="/" />
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.8.21/kotlin-stdlib-1.8.21.jar" path-in-jar="/" />
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.8.21/kotlin-stdlib-common-1.8.21.jar" path-in-jar="/" />
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" path-in-jar="/" />
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-test/1.8.21/kotlin-test-1.8.21.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/js-scriptengine-22.3.1.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/regex-22.3.1-edit.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/truffle-api-22.3.1.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/icu4j-71.1.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/regex-22.3.1-edit.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/js-22.3.1-edit.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/graal-sdk-22.3.1.jar" path-in-jar="/" />
</root>
</artifact>
</component>

19
.idea/runConfigurations/Principii.xml generated Normal file
View File

@@ -0,0 +1,19 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Principii" type="Application" factoryName="Application" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="net.torvald.terrarum.Principii" />
<module name="TerrarumBuild" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="net.torvald.terrarum.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="BuildArtifacts" enabled="true">
<artifact name="ModuleComputers" />
<artifact name="TerrarumBuild" />
</option>
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -1,26 +1,17 @@
package net.torvald.terrarum.modulecomputers.gameactors
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.*
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.badlogic.gdx.utils.Disposable
import kotlin.coroutines.*
import net.torvald.terrarum.*
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.gameactors.BlockBox
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
import net.torvald.terrarum.ui.Toolkit
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarum.modulecomputers.ui.UIHomeComputer
import net.torvald.tsvm.*
import net.torvald.tsvm.peripheral.AdapterConfig
import net.torvald.tsvm.peripheral.GraphicsAdapter
import net.torvald.tsvm.peripheral.VMProgramRom
import net.torvald.unicode.*
/**
* Created by minjaesong on 2021-12-04.
@@ -131,84 +122,3 @@ class FixtureHomeComputer : FixtureBase {
}
}
internal class UIHomeComputer : UICanvas(
toggleKeyLiteral = Input.Keys.ESCAPE, // FIXME why do I have specify ESC for it to function? ESC should be work as the default key
toggleButtonLiteral = App.getConfigInt("control_gamepad_start"),
) {
override var width = 640
override var height = 480
override var openCloseTime = 0f
private val drawOffX = (width - 560).div(2).toFloat()
private val drawOffY = (height - 448).div(2).toFloat()
private var batch: FlippingSpriteBatch
private var camera: OrthographicCamera
internal lateinit var vm: VM
internal lateinit var fixture: FixtureHomeComputer
init {
batch = FlippingSpriteBatch()
camera = OrthographicCamera(width.toFloat(), height.toFloat())
//val m = Matrix4()
//m.setToOrtho2D(0f, 0f, width.toFloat(), height.toFloat())
batch.projectionMatrix = camera.combined
}
private val fbo = FrameBuffer(Pixmap.Format.RGBA8888, width, height, false)
private val controlHelp =
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}\u3000 " +
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_T$KEYCAP_R Terminate\u3000" +
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_R$KEYCAP_S Reset\u3000" +
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_R$KEYCAP_Q SysRq"
override fun updateUI(delta: Float) {
}
override fun renderUI(otherBatch: SpriteBatch, otherCamera: Camera) {
otherBatch.end()
fbo.inAction(camera, batch) {
Gdx.gl.glClearColor(0f,0f,0f,1f)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) // to hide the crap might be there
(vm.peripheralTable[1].peripheral as? GraphicsAdapter)?.let { gpu ->
val clearCol = gpu.getBackgroundColour()
Gdx.gl.glClearColor(clearCol.r, clearCol.g, clearCol.b, clearCol.a)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
gpu.render(Gdx.graphics.deltaTime, batch, drawOffX, drawOffY, true, fbo) // gpu.render will internally end() the fbo then begin() again before using the batch I've fed in
}
}
otherBatch.begin()
otherBatch.shader = null
blendNormalStraightAlpha(otherBatch)
otherBatch.color = Color.WHITE
otherBatch.draw(fbo.colorBufferTexture, posX.toFloat(), posY.toFloat(), width.toFloat(), height.toFloat())
otherBatch.color = Toolkit.Theme.COL_INACTIVE
Toolkit.drawBoxBorder(otherBatch, posX - 1, posY - 1, width + 2, height + 2)
App.fontGame.draw(otherBatch, controlHelp, posX, posY + height + 4)
}
override fun doOpening(delta: Float) {
fixture.startVM()
}
override fun doClosing(delta: Float) {
}
override fun endOpening(delta: Float) {
}
override fun endClosing(delta: Float) {
}
override fun dispose() {
fbo.dispose()
}
}

View File

@@ -0,0 +1,93 @@
package net.torvald.terrarum.modulecomputers.ui
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.*
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import net.torvald.terrarum.App
import net.torvald.terrarum.FlippingSpriteBatch
import net.torvald.terrarum.blendNormalStraightAlpha
import net.torvald.terrarum.inAction
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulecomputers.gameactors.FixtureHomeComputer
import net.torvald.terrarum.ui.Toolkit
import net.torvald.terrarum.ui.UICanvas
import net.torvald.tsvm.VM
import net.torvald.tsvm.peripheral.GraphicsAdapter
import net.torvald.unicode.*
internal class UIHomeComputer : UICanvas(
toggleKeyLiteral = Input.Keys.ESCAPE, // FIXME why do I have specify ESC for it to function? ESC should be work as the default key
toggleButtonLiteral = App.getConfigInt("control_gamepad_start"),
) {
override var width = 640
override var height = 480
override var openCloseTime = 0f
private val drawOffX = (width - 560).div(2).toFloat()
private val drawOffY = (height - 448).div(2).toFloat()
private var batch: FlippingSpriteBatch
private var camera: OrthographicCamera
internal lateinit var vm: VM
internal lateinit var fixture: FixtureHomeComputer
init {
batch = FlippingSpriteBatch()
camera = OrthographicCamera(width.toFloat(), height.toFloat())
//val m = Matrix4()
//m.setToOrtho2D(0f, 0f, width.toFloat(), height.toFloat())
batch.projectionMatrix = camera.combined
}
private val fbo = FrameBuffer(Pixmap.Format.RGBA8888, width, height, false)
private val controlHelp =
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}\u3000 " +
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_T$KEYCAP_R Terminate\u3000" +
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_R$KEYCAP_S Reset\u3000" +
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_R$KEYCAP_Q SysRq"
override fun updateUI(delta: Float) {
}
override fun renderUI(otherBatch: SpriteBatch, otherCamera: Camera) {
otherBatch.end()
fbo.inAction(camera, batch) {
Gdx.gl.glClearColor(0f,0f,0f,1f)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) // to hide the crap might be there
(vm.peripheralTable[1].peripheral as? GraphicsAdapter)?.let { gpu ->
val clearCol = gpu.getBackgroundColour()
Gdx.gl.glClearColor(clearCol.r, clearCol.g, clearCol.b, clearCol.a)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
gpu.render(Gdx.graphics.deltaTime, batch, drawOffX, drawOffY, true, fbo) // gpu.render will internally end() the fbo then begin() again before using the batch I've fed in
}
}
otherBatch.begin()
otherBatch.shader = null
blendNormalStraightAlpha(otherBatch)
otherBatch.color = Color.WHITE
otherBatch.draw(fbo.colorBufferTexture, posX.toFloat(), posY.toFloat(), width.toFloat(), height.toFloat())
otherBatch.color = Toolkit.Theme.COL_INACTIVE
Toolkit.drawBoxBorder(otherBatch, posX - 1, posY - 1, width + 2, height + 2)
App.fontGame.draw(otherBatch, controlHelp, posX, posY + height + 4)
}
override fun doOpening(delta: Float) {
super.doOpening(delta)
fixture.startVM()
}
override fun dispose() {
fbo.dispose()
}
}

BIN
assets/clut/skybox.png LFS Normal file

Binary file not shown.

BIN
assets/graphics/astrum.png LFS Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -379,11 +379,11 @@ let isDiacritics = (s) => s !== undefined && inRange(s.charCodeAt(0), 0x0300, 0x
return Object.freeze({"n":"\uDBBF\uDFC1Бъл. Многоезична\uDBBF\uDFC0","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"t":dislplayKeyLayouts,
"l":"bgBG",
// return: [displayed output, composed output]
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin + 2*altgrin
let s = states.keylayouts[headkey][layer]
let s = (states.keylayouts[headkey][layer] || states.keylayouts[headkey][1*shiftin]) || states.keylayouts[headkey][0]
// typing seq for diacritics: diacritics THEN a character
if (isDiacritics(s)) {

View File

@@ -58,7 +58,7 @@ let isDiacritics = (s) => s !== undefined && inRange(s.charCodeAt(0), 0x0300, 0x
return Object.freeze({"n":"Ελ. Φωνητικό","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"tf":states.layouttable,
"l":"elGR",
// return: [displayed output, composed output]
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin,lowlayerkey)=>{
let layer = 1*shiftin + 2*altgrin

View File

@@ -0,0 +1,283 @@
let states = {"keylayouts":[[""],[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
["0",")","\u0966",")"],
["1","\u090D","\u0967","!"],
["2","\u0945","\u0968","@"],
["3","\u094D\u0930","\u0969","#"],
["4","\u0930\u094D","\u096A","$"],
["5","\u091C\u094D\u091E","\u096B","%"],
["6","\u0924\u094D\u0930","\u096C","^"],
["7","\u0915\u094D\u0937","\u096D","&"],
["8","\u0936\u094D\u0930","\u096E","*"],
["9","(","\u096F","("],
["*"],
["#"],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
["\u094B","\u0913"],
["\u0935","\u0934"],
["\u092E","\u0923","\u0954","\u0923"],
["\u094D","\u0905"],
["\u093E","\u0906"],
["\u093F","\u0907","\u0962","\u090C"],
["\u0941","\u0909"],
["\u092A","\u092B","\u092A","\u095E"],
["\u0917","\u0918","\u095A","\u0918"],
["\u0930","\u0931"],
["\u0915","\u0916","\u0958","\u0959"],
["\u0924","\u0925"],
["\u0938","\u0936"],
["\u0932","\u0933"],
["\u0926","\u0927"],
["\u091C","\u091D","\u095B","\u091D"],
["\u094C","\u0914"],
["\u0940","\u0908","\u0963","\u0961"],
["\u0947","\u090F"],
["\u0942","\u090A"],
["\u0939","\u0919"],
["\u0928","\u0929"],
["\u0948","\u0910"],
["\u0902","\u0901","\u0902","\u0950"],
["\u092C","\u092D"],
["\u0946","\u090E","\u0953","\u090E"],
[",","\u0937","\u0970","\u0970"],
[".","\u0964","\u0965","\u093D"],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[" "],
[undefined],
[undefined],
[undefined],
["\n"],
["\x08"],
["\u094A","\u0912"],
["-","\u0903"],
["\u0943","\u090B","\u0944","\u0960"],
["\u0921","\u0922","\u095C","\u095D"],
["\u093C","\u091E"],
["\u0949","\u0911"],
["\u091A","\u091B","\u0952","\u091B"],
["\u091F","\u0920","\u0951","\u0920"],
["\u092F","\u095F"],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
["0"],
["1"],
["2"],
["3"],
["4"],
["5"],
["6"],
["7"],
["8"],
["9"],
["/"],
["*"],
["-"],
["+"],
["."],
["."],
["\n"],
["="],
["("],
[")"],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined]
],
"code":""} // practically unused as long as there are no diacritics on the keyboard
let reset = () => {
states.code = 0
}
let inRange = (s,a,b) => (a <= s && s <= b)
return Object.freeze({"n":"इनस्क्रिप्ट","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"t":states.keylayouts.slice(0,10).concat([["3","\uDBBF\uDE01\u094D\u0930","\u0969","#"], ["4","\u0930\u094D\uDBBF\uDE01","\u096A","$"]], states.keylayouts.slice(12)),
"l":"hiIN",
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin + 2*altgrin
let s = (states.keylayouts[headkey][layer] || states.keylayouts[headkey][1*shiftin]) || states.keylayouts[headkey][0]
return ['0', s]
},
"backspace":()=>{
reset()
return ''
},
"end":()=>{
reset()
return ''
},
"reset":()=>{ reset() },
"composing":()=>(states.code!='')
})

View File

@@ -346,12 +346,12 @@ let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" :
return Object.freeze({"n":"두벌식 표준","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"t":states.keylayouts.map(it => [it[0],it[1]]),
"l":"koKR",
// return: [displayed output, composed output]
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin// + 2*altgrin
states.code = 1
let s = states.keylayouts[headkey][layer]
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
if (isHangul(s)) {
let bufIndex = (isJongseongConsonant(s) && isConsonant(states.buf[0]) && undefined !== states.buf[1]) ? 2 :

View File

@@ -346,12 +346,12 @@ let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" :
return Object.freeze({"n":"두벌식 수정 표준","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"t":states.keylayouts.map(it => [it[0],it[1]]),
"l":"koKR",
// return: [displayed output, composed output]
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin// + 2*altgrin
states.code = 1
let s = states.keylayouts[headkey][layer]
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
if (isHangul(s)) {
let bufIndex = (isJongseongConsonant(s) && isConsonant(states.buf[0]) && undefined !== states.buf[1]) ? 2 :

View File

@@ -375,12 +375,12 @@ let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" :
return Object.freeze({"n":"세벌식 3-90","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"t":states.keylayouts.map(it => [it[0],it[1]]),
"l":"koKR",
// return: [displayed output, composed output]
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin// + 2*altgrin
states.code = 1
let s = states.keylayouts[headkey][layer]
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
let bufIndex = isJungseong(s) ? 1 : isJongseong(s) ? 2 : 0
if (isHangul(s)) {

View File

@@ -375,12 +375,12 @@ let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" :
return Object.freeze({"n":"세벌식 공자판","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"t":states.keylayouts.map(it => [it[0],it[1]]),
"l":"koKR",
// return: [displayed output, composed output]
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin// + 2*altgrin
states.code = 1
let s = states.keylayouts[headkey][layer]
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
let bufIndex = isJungseong(s) ? 1 : isJongseong(s) ? 2 : 0
if (isHangul(s)) {

View File

@@ -385,12 +385,12 @@ let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" :
return Object.freeze({"n":"신세벌식 03","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"t":states.keylayouts.map(it => [it[0],it[1]]),
"l":"koKR",
// return: [displayed output, composed output]
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin// + 2*altgrin
states.code = 1
let s = states.keylayouts[headkey][layer]
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
let s2 = states.keylayouts[headkey][2]
let bufIndex = isJungseong(s) ? 1 : isJongseong(s) ? 2 : 0

View File

@@ -385,12 +385,12 @@ let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" :
return Object.freeze({"n":"신세벌식 P2","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"t":states.keylayouts.map(it => [it[0],it[1]]),
"l":"koKR",
// return: [displayed output, composed output]
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin// + 2*altgrin
states.code = 1
let s = states.keylayouts[headkey][layer]
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
let s2 = states.keylayouts[headkey][2]
let bufIndex = isJungseong(s) ? 1 : isJongseong(s) ? 2 : 0

View File

@@ -375,11 +375,11 @@ let isDiacritics = (s) => s !== undefined && inRange(s.charCodeAt(0), 0x0300, 0x
return Object.freeze({"n":"ЙЦУКЕН Многоязычна","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"t":states.keylayouts,
"l":"ruRU",
// return: [displayed output, composed output]
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin + 2*altgrin
let s = states.keylayouts[headkey][layer]
let s = (states.keylayouts[headkey][layer] || states.keylayouts[headkey][1*shiftin]) || states.keylayouts[headkey][0]
// typing seq for diacritics: diacritics THEN a character
if (isDiacritics(s)) {

View File

@@ -27,7 +27,7 @@ let states = {"keylayouts":[[""],[undefined],
[undefined],
[undefined],
["ф","Ф","ƒ","ƒ"],
["и","И"],
["и","И","и","И"],
["с","С","≠","≠"],
["в","В","ћ","Ћ"],
["у","У","ќ","Ќ"],
@@ -69,10 +69,10 @@ let states = {"keylayouts":[[""],[undefined],
["-","_","—",""],
["=","+","»","«"],
["х","Х","“","“"],
["ъ","Ъ"],
["ё","Ё"],
["ъ","Ъ","ъ","Ъ"],
["ё","Ё","ё","Ё"],
["ж","Ж","…","…"],
["э",'Э'],
["э",'Э',"э",'Э'],
["/","?","„","„"],
[undefined],
[undefined],
@@ -263,12 +263,12 @@ let isDiacritics = (s) => s !== undefined && inRange(s.charCodeAt(0), 0x0300, 0x
return Object.freeze({"n":"ЙЦУКЕН (Рус. Apple)","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"t":states.keylayouts,
"l":"ruRU",
// return: [displayed output, composed output]
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin + 2*altgrin
states.code = 1
let s = states.keylayouts[headkey][layer]
let s = (states.keylayouts[headkey][layer] || states.keylayouts[headkey][1*shiftin]) || states.keylayouts[headkey][0]
if (isDiacritics(s)) {
return ['1', '']

View File

@@ -33,7 +33,7 @@ let isDiacritics = (s) => s !== undefined && inRange(s.charCodeAt(0), 0x0300, 0x
return Object.freeze({"n":"Рус. Фонетическая","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"tf":states.layouttable,
"l":"ruRU",
// return: [displayed output, composed output]
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin,lowlayerkey)=>{
let layer = 1*shiftin// + 2*altgrin
states.code = 1

View File

@@ -0,0 +1,290 @@
let states = {"keylayouts":[[""],[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
["0",")"],
["1","!"],
["2","@"],
["3","#"],
["4","$"],
["5","%"],
["6","^"],
["7","&"],
["8","*"],
["9","("],
["*"],
["#"],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
["\u0B85","\u0BF9"],
["\u0B99","\u0BF7"],
["\u0B92","\u0BF5","\u0BCA"],
["\u0B89","\u0BF8","\u0BC1"],
["\u0B8A","\u0B9C","\u0BC2"],
["\u0BCD","\u0B83"],
["\u0B8E","\u0B8E","\u0BC6"],
["\u0B95","\u0B95"],
["\u0BA9","\u0BA9"],
["\u0BAA","\u0BAA"],
["\u0BAE",'"'],
["\u0BA4",":"],
["\u0BB0","/"],
["\u0BB2","\u0BB2"],
["\u0B9F","["],
["\u0BA3","]"],
["\u0B86","\u0BB8","\u0BBE"],
["\u0B90","\u0BB9","\u0BC8"],
["\u0B87","\u0BFA","\u0BBF"],
["\u0B8F","\u0B95\u0BCD\u0BB7","\u0BC7"],
["\u0BB1","\u0BB1"],
["\u0BB5","\u0BF6"],
["\u0B88","\u0BB7","\u0BC0"],
["\u0B93","\u0BF4","\u0BCB"],
["\u0BB3","\u0BB8\u0BCD\u0BB0\u0BC0"],
["\u0B94","\u0BF3","\u0BCC"],
[",","<"],
[".",">"],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[" "],
[undefined],
[undefined],
[undefined],
["\n"],
["\x08"],
["`","~"],
["-","_"],
["=","+"],
["\u0B9A","{"],
["\u0B9E","}"],
["\\","|"],
["\u0BA8",";"],
["\u0BAF","'"],
["\u0BB4","?"],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
["0"],
["1"],
["2"],
["3"],
["4"],
["5"],
["6"],
["7"],
["8"],
["9"],
["/"],
["*"],
["-"],
["+"],
["."],
["."],
["\n"],
["="],
["("],
[")"],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined],
[undefined]
],
"code":""} // the last character typed
let reset = () => {
states.code = ""
}
let inRange = (s,a,b) => (a <= s && s <= b)
let isConsonant = (s) => s !== undefined && (inRange(s, 0x0B95, 0x0BB9) || s == 0x0BD0 || inRange(s, 0x0BE6, 0x0BFA)) // determines the behaviour of the vowel key
return Object.freeze({"n":"தமிழ் 99","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"t":states.keylayouts,
"l":"taIN",
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
if (layer == 0 && states.code != "" && isConsonant(states.code.charCodeAt(states.code.length - 1))) {
s = states.keylayouts[headkey][2] || states.keylayouts[headkey][0]
}
states.code = s
return ['0', s]
},
"backspace":()=>{
reset()
return ''
},
"end":()=>{
reset()
return ''
},
"reset":()=>{ reset() },
"composing":()=>(states.code!='')
})

View File

@@ -269,12 +269,12 @@ let isDiacritics = (s) => s !== undefined && inRange(s.charCodeAt(0), 0x0300, 0x
return Object.freeze({"n":"แป้นพิมพ์เกษมณี","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"t":states.keylayouts,
"l":"thTH",
// return: [displayed output, composed output]
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin + 2*altgrin // use AltGr to type conventional numbers
states.code = 0
let s = states.keylayouts[headkey][layer]
let s = (states.keylayouts[headkey][layer] || states.keylayouts[headkey][1*shiftin]) || states.keylayouts[headkey][0]
return ['0', s]
},
"backspace":()=>{

View File

@@ -269,12 +269,12 @@ let isDiacritics = (s) => s !== undefined && (inRange(s.charCodeAt(0), 0x0E31, 0
return Object.freeze({"n":"แป้นพิมพ์ปัตตะโชติ","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
"t":states.keylayouts,
"l":"thTH",
// return: [displayed output, composed output]
// return: [delete count, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin + 2*altgrin // use AltGr to type conventional numbers
states.code = 0
let s = states.keylayouts[headkey][layer]
let s = (states.keylayouts[headkey][layer] || states.keylayouts[headkey][1*shiftin]) || states.keylayouts[headkey][0]
return ['0', s]
},
"backspace":()=>{

View File

@@ -276,7 +276,7 @@ return Object.freeze({"n":"五仓简体 Qwerty","v":"many","c":"CuriousTo\uA75Bv
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin// + 2*altgrin
let cjkey = states.keylayouts[headkey][layer]
let cjkey = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
let cjkeyAsc = cjkey.codePointAt(0)
if (states.code == 1 && 48 <= cjkeyAsc && cjkeyAsc <= 57) {

View File

@@ -276,7 +276,7 @@ return Object.freeze({"n":"五倉正體 Qwerty","v":"many","c":"CuriousTo\uA75Bv
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin// + 2*altgrin
let cjkey = states.keylayouts[headkey][layer]
let cjkey = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
let cjkeyAsc = cjkey.codePointAt(0)
if (states.code == 1 && 48 <= cjkeyAsc && cjkeyAsc <= 57) {

View File

@@ -0,0 +1,4 @@
{
"INPUT_KEYBOARD_DEFAULT_LAYOUT": "en_intl_qwertz",
"INPUT_KEYBOARD_DEFAULT_IME": "none"
}

View File

@@ -1,31 +1,41 @@
{
"APP_WARNING_HEALTH_AND_SAFETY": "WARNING-HEALTH AND SAFETY",
"CONTEXT_CHARACTER": "Character",
"MENU_LABEL_COPYRIGHT": "Copyright",
"CONTEXT_TIME_MINUTE_PLURAL": "Minutes",
"CONTEXT_TIME_SECOND_PLURAL": "Seconds",
"COPYRIGHT_ALL_RIGHTS_RESERVED": "All rights reserved",
"COPYRIGHT_GNU_GPL_3": "Distributed under GNU GPL 3",
"APP_WARNING_HEALTH_AND_SAFETY": "WARNING-HEALTH AND SAFETY",
"MENU_LABEL_PRESS_START_SYMBOL": "Press >",
"MENU_MODULES" : "Modules",
"MENU_CREDIT_GPL_DNT" : "GPL",
"GAME_ACTION_MOVE_VERB" : "Move",
"GAME_ACTION_ZOOM" : "Zoom",
"MENU_LABEL_RESET" : "Reset",
"GAME_32BIT_WARNING1": "It looks like youre running a 32-Bit version of Java.",
"GAME_32BIT_WARNING2": "Please download and install the latest 64-Bit Java at:",
"GAME_32BIT_WARNING3": "https://www.java.com/en/download/",
"MENU_OPTION_STREAMERS_LAYOUT": "Chat Overlay",
"MENU_LABEL_RESTART_REQUIRED": "Restart Required",
"MENU_LABEL_KEYBOARD_LAYOUT": "Keyboard Layout",
"MENU_LABEL_IME": "IME",
"MENU_OPTIONS_DITHER": "Dithering",
"MENU_OPTIONS_BLUR": "Blur",
"MENU_OPTIONS_PARTICLES": "Particles",
"MENU_IO_AUTOSAVE": "Autosave",
"MENU_IO_IMPORT": "Import",
"APP_NOMODULE_1": "No Module is currently loaded.",
"APP_NOMODULE_2": "Please configure your Load Order and restart:",
"MENU_LABEL_KEYCONFIG_HELP1": "Click On the Keycap to Assign Actions",
"MENU_IO_MANUAL_SAVE": "Manual Save",
"MENU_LABEL_COPYRIGHT": "Copyright",
"MENU_LABEL_DELETE": "Delete",
"MENU_LABEL_EXTRA_JVM_ARGUMENTS": "Extra Arguments",
"MENU_LABEL_IME": "IME",
"MENU_LABEL_IME_TOGGLE": "Toggle IME",
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "Paste from Cliboard",
"MENU_LABEL_KEYBOARD_LAYOUT": "Keyboard Layout",
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "Paste from Clipboard",
"MENU_LABEL_PRESS_START_SYMBOL": "Press >",
"MENU_LABEL_RESET" : "Reset",
"MENU_LABEL_RESTART_REQUIRED": "Restart Required",
"MENU_LABEL_STREAMING": "Livestreaming",
"MENU_LABEL_SYSTEM_INFO": "System Info",
"MENU_MODULES" : "Modules",
"MENU_OPTIONS_ATLAS_TEXTURE_SIZE": "Atlas Texture Size",
"MENU_OPTIONS_AUTOSAVE": "Autosave",
"MENU_OPTIONS_BLUR": "Blur",
"MENU_OPTIONS_DEBUG_CONSOLE": "Debug Console",
"MENU_OPTIONS_DITHER": "Dithering",
"MENU_OPTIONS_JVM_HEAP_MAX": "Max Heap Memory",
"MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION": "Show notification for",
"MENU_OPTIONS_PARTICLES": "Particles",
"MENU_OPTIONS_PERFORMANCE": "Performance",
"MENU_LABEL_DELETE": "Delete"
"MENU_OPTIONS_STREAMERS_LAYOUT": "Chat Overlay",
"MENU_OPTIONS_NONE" : "None",
"MENU_CREDIT_GPL_DNT" : "GPL",
"MENU_LABEL_JVM_DNT" : "JVM",
"MENU_OPTIONS_FILTERING_HQ2X_DNT" : "Hq2x"
}

View File

@@ -0,0 +1,16 @@
{
"GAME_32BIT_WARNING1": "It looks like youre running a 32-Bit version of Java.",
"GAME_32BIT_WARNING2": "Please download and install the latest 64-Bit Java at:",
"GAME_32BIT_WARNING3": "https://www.java.com/en/download/",
"GAME_APPLE_ROSETTA_WARNING1": "It seems you are using a Mac with Apple Silicon but running the x86 build of the game.",
"GAME_APPLE_ROSETTA_WARNING2": "Please use the native build for improved performance and gameplay experiences.",
"APP_NOMODULE_1": "No Module is currently loaded.",
"APP_NOMODULE_2": "Please configure your Load Order and restart:",
"MENU_LABEL_KEYCONFIG_HELP1": "Click On the Keycap to Assign Actions",
"GAME_PREV_SAVE_WAS_LOADED1": "The most recently saved game was corrupted.",
"GAME_PREV_SAVE_WAS_LOADED2": "The previously saved game was loaded.",
"GAME_MORE_RECENT_AUTOSAVE1": "The Autosave is more recent than the manual save.",
"GAME_MORE_RECENT_AUTOSAVE2": "Please select the saved game you wish to play:",
"MENU_LABEL_SAVE_WILL_BE_DELETED": "The selected save file will be deleted.",
"MENU_LABEL_UNSAVED_PROGRESS_WILL_BE_LOST": "Unsaved progress will be lost."
}

View File

@@ -9,7 +9,7 @@
"GAME_ACTION_MOVE_VERB" : "हिलना",
"GAME_ACTION_ZOOM" : "ज़ूम",
"MENU_LABEL_RESET" : "रीसेट",
"MENU_OPTION_STREAMERS_LAYOUT": "Chat Overlay",
"MENU_OPTIONS_STREAMERS_LAYOUT": "Chat Overlay",
"MENU_LABEL_RESTART_REQUIRED": "पुनः शुरआत जरुरी है",
"MENU_LABEL_KEYBOARD_LAYOUT": "कीबोर्ड विन्यास",
"MENU_LABEL_IME": "इनपुट विधि",

View File

@@ -2335,7 +2335,7 @@
},
{
"n": "MENU_OPTIONS",
"s": "Stillingar "
"s": "Valkostir "
},
{
"n": "MENU_OPTIONS_ADVANCEDGRAPHICS",
@@ -2395,11 +2395,11 @@
},
{
"n": "MENU_OPTIONS_GAMEPLAY",
"s": "Gameplay Options"
"s": "Leikvalkostir"
},
{
"n": "MENU_OPTIONS_GRAPHICS",
"s": "Grafíkstillingar"
"s": "Grafíkvalkostir"
},
{
"n": "MENU_OPTIONS_HUD",

View File

@@ -15,5 +15,15 @@
"MENU_OPTIONS_DITHER": "Dither",
"MENU_OPTIONS_BLUR": "Óskýrt",
"MENU_OPTIONS_PARTICLES": "Eind",
"MENU_IO_IMPORT": "Flytja inn"
"MENU_IO_IMPORT": "Flytja inn",
"APP_NOMODULE_1": "Engin eining er hlaðin eins og er.",
"APP_NOMODULE_2": "Vinsamlega stilltu hleðslupöntunina þína og endurræstu:",
"MENU_LABEL_KEYCONFIG_HELP1": "Smelltu á lyklalokið til að úthluta aðgerðum",
"MENU_LABEL_IME_TOGGLE": "Breyttu IME",
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "Límdu frá klemmuspjald",
"MENU_OPTIONS_PERFORMANCE": "Afköst",
"MENU_LABEL_DELETE": "Eyða",
"MENU_OPTIONS_JVM_HEAP_MAX": "Hámarks hrúguminni",
"MENU_OPTIONS_AUTOSAVE": "Sjálfvirk vistun",
"CONTEXT_TIME_MINUTE_PLURAL": "Mínútur"
}

View File

@@ -1,29 +1,37 @@
{
"APP_WARNING_HEALTH_AND_SAFETY": "경고—건강과 안전을 위하여",
"CONTEXT_CHARACTER": "캐릭터",
"MENU_LABEL_COPYRIGHT": "저작권",
"CONTEXT_TIME_MINUTE_PLURAL": "",
"CONTEXT_TIME_SECOND_PLURAL": "초",
"COPYRIGHT_ALL_RIGHTS_RESERVED": "모든 권리 보유",
"COPYRIGHT_GNU_GPL_3": "GNU GPL 3에 따라 배포됨",
"APP_WARNING_HEALTH_AND_SAFETY": "경고—건강과 안전을 위하여",
"MENU_LABEL_PRESS_START_SYMBOL": ">을 누르세요",
"MENU_MODULES" : "모듈",
"GAME_ACTION_MOVE_VERB" : "이동하기",
"GAME_ACTION_ZOOM" : "확대·축소",
"MENU_LABEL_RESET" : "재설정",
"GAME_32BIT_WARNING1": "32비트 버전의 Java를 사용중인 것 같습니다.",
"GAME_32BIT_WARNING2": "아래 링크에서 최신 64비트 Java를 내려받아 설치해주세요.",
"GAME_32BIT_WARNING3": "https://www.java.com/ko/download/",
"MENU_OPTION_STREAMERS_LAYOUT": "채팅창 오버레이",
"MENU_LABEL_RESTART_REQUIRED": "재시작 필요",
"MENU_LABEL_KEYBOARD_LAYOUT": "자판 배열",
"MENU_LABEL_IME": "입력기",
"MENU_OPTIONS_DITHER": "디더링",
"MENU_OPTIONS_BLUR": "흐림",
"MENU_OPTIONS_PARTICLES": "입자 수",
"MENU_IO_AUTOSAVE": "자동 저장",
"MENU_IO_IMPORT": "가져오기",
"APP_NOMODULE_1": "현재 불러와진 모듈이 없습니다.",
"APP_NOMODULE_2": "다음의 파일에서 불러오기 순서를 설정하고 게임을 재시작하십시오.",
"MENU_LABEL_KEYCONFIG_HELP1": "키캡을 클릭해 컨트롤을 배정하십시오",
"MENU_IO_MANUAL_SAVE": "수동 저장",
"MENU_LABEL_COPYRIGHT": "저작권",
"MENU_LABEL_DELETE": "삭제",
"MENU_LABEL_EXTRA_JVM_ARGUMENTS": "추가 명령 인수",
"MENU_LABEL_IME": "입력기",
"MENU_LABEL_IME_TOGGLE": "입력기 켜고 끄기",
"MENU_LABEL_KEYBOARD_LAYOUT": "자판 배열",
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "복사한 텍스트 붙여넣기",
"MENU_OPTIONS_PERFORMANCE": "성능"
"MENU_LABEL_PRESS_START_SYMBOL": ">을 누르세요",
"MENU_LABEL_RESET" : "재설정",
"MENU_LABEL_RESTART_REQUIRED": "재시작 필요",
"MENU_LABEL_STREAMING": "실시간 방송",
"MENU_LABEL_SYSTEM_INFO": "시스템 정보",
"MENU_MODULES" : "모듈",
"MENU_OPTIONS_ATLAS_TEXTURE_SIZE": "아틀라스 텍스처 크기",
"MENU_OPTIONS_AUTOSAVE": "자동 저장",
"MENU_OPTIONS_BLUR": "흐림",
"MENU_OPTIONS_DEBUG_CONSOLE": "디버그 콘솔",
"MENU_OPTIONS_DITHER": "디더링",
"MENU_OPTIONS_JVM_HEAP_MAX": "최대 힙 메모리",
"MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION": "알림 표시 시간",
"MENU_OPTIONS_PARTICLES": "입자 수",
"MENU_OPTIONS_PERFORMANCE": "성능",
"MENU_OPTIONS_STREAMERS_LAYOUT": "채팅창 오버레이",
"MENU_OPTIONS_NONE" : "없음"
}

View File

@@ -0,0 +1,16 @@
{
"GAME_32BIT_WARNING1": "32비트 버전의 Java를 사용중인 것 같습니다.",
"GAME_32BIT_WARNING2": "아래 링크에서 최신 64비트 Java를 내려받아 설치해주세요.",
"GAME_32BIT_WARNING3": "https://www.java.com/ko/download/",
"GAME_APPLE_ROSETTA_WARNING1": "Apple Silicon이 탑재된 Mac을 사용 중이지만 x86 빌드의 게임을 실행 중입니다.",
"GAME_APPLE_ROSETTA_WARNING2": "최적의 성능과 게임 경험을 위해 Apple Silicon용 빌드의 게임을 이용해 주십시오.",
"APP_NOMODULE_1": "현재 불러와진 모듈이 없습니다.",
"APP_NOMODULE_2": "다음의 파일에서 불러오기 순서를 설정하고 게임을 재시작하십시오.",
"MENU_LABEL_KEYCONFIG_HELP1": "키캡을 클릭해 컨트롤을 배정하십시오",
"GAME_PREV_SAVE_WAS_LOADED1": "가장 최근에 저장된 게임이 손상되었습니다.",
"GAME_PREV_SAVE_WAS_LOADED2": "이전에 저장된 게임을 불러왔습니다.",
"GAME_MORE_RECENT_AUTOSAVE1": "자동 저장된 게임이 수동으로 저장한 게임보다 더 최신입니다.",
"GAME_MORE_RECENT_AUTOSAVE2": "불러올 게임을 선택해 주십시오.",
"MENU_LABEL_SAVE_WILL_BE_DELETED": "선택된 세이브가 삭제됩니다.",
"MENU_LABEL_UNSAVED_PROGRESS_WILL_BE_LOST": "저장하지 않은 진행 상황을 잃게 됩니다."
}

View File

@@ -15,7 +15,7 @@
"GAME_32BIT_WARNING1": "看起来您正在运行32位版本的Java。",
"GAME_32BIT_WARNING2": "请下载并安装最新的64位Java :",
"GAME_32BIT_WARNING3": "https://www.java.com/en/download/",
"MENU_OPTION_STREAMERS_LAYOUT": "聊天叠加",
"MENU_OPTIONS_STREAMERS_LAYOUT": "聊天叠加",
"MENU_LABEL_RESTART_REQUIRED": "需要重新启动",
"MENU_LABEL_KEYBOARD_LAYOUT": "键盘布局",
"MENU_LABEL_IME": "输入法",

View File

@@ -11,7 +11,7 @@
"GAME_32BIT_WARNING1": "看起來您正在運行32位版本的Java。",
"GAME_32BIT_WARNING2": "請下載並安裝最新的64位Java :",
"GAME_32BIT_WARNING3": "https://www.java.com/en/download/",
"MENU_OPTION_STREAMERS_LAYOUT": "聊天疊加",
"MENU_OPTIONS_STREAMERS_LAYOUT": "聊天疊加",
"MENU_LABEL_RESTART_REQUIRED": "需要重新啟動",
"MENU_LABEL_KEYBOARD_LAYOUT": "鍵盤配置",
"MENU_LABEL_IME": "輸入法",

View File

@@ -1,5 +1,5 @@
"id";"drop";"spawn";"name";"shdr";"shdg";"shdb";"shduv";"str";"dsty";"mate";"solid";"wall";"grav";"dlfn";"fv";"fr";"lumr";"lumg";"lumb";"lumuv";"colour";"vscs";"refl";"tags"
"0";"0";"0";"BLOCK_AIR";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";""
"0";"0";"0";"BLOCK_AIR";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"INCONSEQUENTIAL"
"16";"17";"17";"BLOCK_STONE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ROCK,NATURAL"
"17";"17";"17";"BLOCK_STONE_QUARRIED";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ROCK"
"18";"18";"18";"BLOCK_STONE_TILE_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.18";"STONE"
@@ -23,12 +23,12 @@
"65";"65";"65";"BLOCK_TRUNK_EBONY";"0.0312";"0.0312";"0.0312";"0.0312";"19";"1200";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,NATURAL"
"66";"66";"66";"BLOCK_TRUNK_BIRCH";"0.0312";"0.0312";"0.0312";"0.0312";"15";"670";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,NATURAL"
"67";"67";"67";"BLOCK_TRUNK_BLOODROSE";"0.0312";"0.0312";"0.0312";"0.0312";"17";"900";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,NATURAL"
"80";"80";"80";"BLOCK_SAND";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL"
"81";"81";"81";"BLOCK_SAND_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL"
"82";"82";"82";"BLOCK_SAND_RED";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL"
"83";"83";"83";"BLOCK_SAND_DESERT";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL"
"84";"84";"84";"BLOCK_SAND_BLACK";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL"
"85";"85";"85";"BLOCK_SAND_GREEN";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL"
"80";"80";"80";"BLOCK_SAND";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL,WARM"
"81";"81";"81";"BLOCK_SAND_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL,WARM"
"82";"82";"82";"BLOCK_SAND_RED";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL,WARM"
"83";"83";"83";"BLOCK_SAND_DESERT";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL,WARM"
"84";"84";"84";"BLOCK_SAND_BLACK";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL,WARM"
"85";"85";"85";"BLOCK_SAND_GREEN";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL,WARM"
"96";"96";"96";"BLOCK_GRAVEL";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"GRVL";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRAVEL,NATURAL"
"97";"97";"97";"BLOCK_GRAVEL_GREY";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"GRVL";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRAVEL,NATURAL"
"112";"112";"112";"BLOCK_ORE_MALACHITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
@@ -44,10 +44,10 @@
"132";"132";"132";"BLOCK_GEM_DIAMOND";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
"133";"133";"133";"BLOCK_GEM_AMETHYST";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
"134";"134";"134";"BLOCK_GEM_QUARTZ";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
"144";"144";"144";"BLOCK_SNOW";"0.1252";"0.1252";"0.1252";"0.1252";"24";"500";"SNOW";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SNOW,NATURAL"
"145";"N/A";"N/A";"BLOCK_ICE_FRAGILE";"0.0508";"0.0508";"0.0508";"0.0508";"5";"930";"ICEI";"1";"0";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ICE,NATURAL,FRAGIEL"
"146";"146";"146";"BLOCK_ICE_NATURAL";"0.1016";"0.1016";"0.1016";"0.1016";"35";"930";"ICEI";"1";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ICE,NATURAL"
"147";"147";"147";"BLOCK_ICE_CLEAR_MAGICAL";"0.1252";"0.1252";"0.1252";"0.1252";"48";"3720";"ICEX";"1";"1";"N/A";"0";"0";"4";"0.0744";"0.1252";"0.2268";"0.0000";"N/A";"N/A";"0.0";"ICE"
"144";"144";"144";"BLOCK_SNOW";"0.1252";"0.1252";"0.1252";"0.1252";"24";"500";"SNOW";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SNOW,NATURAL,COLD"
"145";"N/A";"N/A";"BLOCK_ICE_FRAGILE";"0.0508";"0.0508";"0.0508";"0.0508";"5";"930";"ICEI";"1";"0";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ICE,NATURAL,FRAGILE,COLD"
"146";"146";"146";"BLOCK_ICE_NATURAL";"0.1016";"0.1016";"0.1016";"0.1016";"35";"930";"ICEI";"1";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ICE,NATURAL,COLD"
"147";"147";"147";"BLOCK_ICE_CLEAR_MAGICAL";"0.1252";"0.1252";"0.1252";"0.1252";"48";"3720";"ICEX";"1";"1";"N/A";"0";"0";"4";"0.0744";"0.1252";"0.2268";"0.0000";"N/A";"N/A";"0.0";"ICE,COLD"
"148";"148";"148";"BLOCK_GLASS_CRUDE";"0.0876";"0.0424";"0.0876";"0.1252";"5";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GLASS"
"149";"149";"149";"BLOCK_GLASS_CLEAN";"0.0424";"0.0424";"0.0424";"0.0636";"5";"2203";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GLASS"
"160";"160";"160";"BLOCK_PLATFORM_STONE";"0.0312";"0.0312";"0.0312";"0.0312";"5";"2400";"ROCK";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"PLATFORM"
@@ -188,6 +188,7 @@
## Some tags are reserved for internal use, which are:
## - INTERNAL: denotes that the tile is internal-use. Will not be rendered unless debug window is on.
## - DORENDER: this internal tile must go through the standard-issue tile drawing routine.
## - INCONSEQUENTIAL: denotes that this tile can be overwritten without dropping it. Usually used with flower tiles.
#
#
## References ##
Can't render this file because it contains an unexpected character in line 179 and column 37.

View File

@@ -22,6 +22,8 @@ Seed
SetAV
SetBulletin
SetScale
SetSol
SetTurb
SetTime
SetTimeDelta
SpawnPhysTestBall
1 CatStdout
22 SetAV
23 SetBulletin
24 SetScale
25 SetSol
26 SetTurb
27 SetTime
28 SetTimeDelta
29 SpawnPhysTestBall

Binary file not shown.

View File

@@ -8,6 +8,7 @@ id;classname
8;net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalEmitter
9;net.torvald.terrarum.modulebasegame.gameitems.WireCutterAll
10;net.torvald.terrarum.modulebasegame.gameitems.ItemTypewriter
11;net.torvald.terrarum.modulebasegame.gameitems.ItemWallCalendar
256;net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorOak
257;net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorEbony
1 id classname
8 8 net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalEmitter
9 9 net.torvald.terrarum.modulebasegame.gameitems.WireCutterAll
10 10 net.torvald.terrarum.modulebasegame.gameitems.ItemTypewriter
11 11 net.torvald.terrarum.modulebasegame.gameitems.ItemWallCalendar
12 256 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorOak
13 257 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorEbony
14 258 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorBirch

View File

@@ -0,0 +1,34 @@
{
"MENU_CALENDAR_CALENDAR": "Calendar",
"MENU_CALENDAR_EVENTS": "Events",
"MENU_CALENDAR_ADD_NEW_EVENT": "Add New Event",
"CONTEXT_CALENDAR_SEASON_SPRING": "Spring",
"CONTEXT_CALENDAR_SEASON_SUMMER": "Summer",
"CONTEXT_CALENDAR_SEASON_AUTUMN": "Autumn",
"CONTEXT_CALENDAR_SEASON_WINTER": "Winter",
"CONTEXT_CALENDAR_SEASON_SPRI": "Spri",
"CONTEXT_CALENDAR_SEASON_SUMM": "Summ",
"CONTEXT_CALENDAR_SEASON_AUTM": "Autm",
"CONTEXT_CALENDAR_SEASON_WINT": "Wint",
"CONTEXT_CALENDAR_DATE_FORMAT_Y": "Year {0}",
"CONTEXT_CALENDAR_DATE_FORMAT_YMD": "Year {0} {1} {2}",
"CONTEXT_CALENDAR_DATE_FORMAT_YMD_DDD": "Year {0} {1} {2} {3}",
"CONTEXT_CALENDAR_DAY_MONDAG_DNT": "Mondag",
"CONTEXT_CALENDAR_DAY_TYSDAG_DNT": "Tysdag",
"CONTEXT_CALENDAR_DAY_MIDTVEKE_DNT": "Midtveke",
"CONTEXT_CALENDAR_DAY_TORSDAG_DNT": "Torsdag",
"CONTEXT_CALENDAR_DAY_FREDAG_DNT": "Fredag",
"CONTEXT_CALENDAR_DAY_LAURDAG_DNT": "Laurdag",
"CONTEXT_CALENDAR_DAY_SUNDAG_DNT": "Sundag",
"CONTEXT_CALENDAR_DAY_VERDDAG_DNT": "Verddag",
"CONTEXT_CALENDAR_DAY_MON_DNT": "Mon",
"CONTEXT_CALENDAR_DAY_TYS_DNT": "Tys",
"CONTEXT_CALENDAR_DAY_MID_DNT": "Mid",
"CONTEXT_CALENDAR_DAY_TOR_DNT": "Tor",
"CONTEXT_CALENDAR_DAY_FRE_DNT": "Fre",
"CONTEXT_CALENDAR_DAY_LAU_DNT": "Lau",
"CONTEXT_CALENDAR_DAY_SUN_DNT": "Sun",
"CONTEXT_CALENDAR_DAY_VER_DNT": "Ver",
"CONTEXT_CALENDAR_DATE_FORMAT_YMD_SHORT_DNT": "ɣ{0}-{1}-{2}"
}

View File

@@ -1,23 +1,24 @@
{
"CONTEXT_GENERATOR_SEED": "Seed",
"CONTEXT_ITEM_MAP": "Map",
"CONTEXT_ITEM_TOOL_PLURAL": "Tools",
"CONTEXT_PLACE_COORDINATE": "Coordinate",
"CONTEXT_WORLD_COUNT": "Worlds: ",
"CONTEXT_WORLD_NEW": "New World",
"MENU_LABEL_DELETE_WORLD": "Delete World",
"CONTEXT_WORLD_COUNT": "Worlds: ",
"GAME_INVENTORY_INGREDIENTS": "Ingredients",
"GAME_INVENTORY_POTIONS": "Potions",
"GAME_INVENTORY_BLOCKS": "Blocks",
"GAME_INVENTORY_WALLS": "Walls",
"CONTEXT_ITEM_TOOL_PLURAL": "Tools",
"GAME_INVENTORY_FAVORITES": "Favorites",
"GAME_INVENTORY_REGISTER": "Register",
"CONTEXT_ITEM_MAP": "Map",
"MENU_LABEL_MENU": "Menu",
"CONTEXT_GENERATOR_SEED": "Seed",
"MENU_LABEL_PREV_SAVES": "Previous Saves",
"MENU_LABEL_RENAME": "Rename",
"GAME_ACTION_CRAFT": "Craft",
"GAME_ACTION_GRAPPLE": "Grapple",
"GAME_ACTION_QUICKSEL": "Quick Select",
"GAME_ACTION_CRAFT": "Craft",
"GAME_CRAFTING": "Crafting",
"GAME_ACTION_TELEPORT": "Teleport",
"GAME_CRAFTABLE_ITEMS": "Craftable Items",
"CONTEXT_WORLD_SEARCH": "World Search",
"CONTEXT_WORLD_LIST": "Worlds List",
"MENU_LABEL_RENAME": "Rename"
"GAME_CRAFTING": "Crafting",
"GAME_INVENTORY_BLOCKS": "Blocks",
"GAME_INVENTORY_FAVORITES": "Favorites",
"GAME_INVENTORY_INGREDIENTS": "Ingredients",
"GAME_INVENTORY_POTIONS": "Potions",
"GAME_INVENTORY_REGISTER": "Register",
"GAME_INVENTORY_WALLS": "Walls"
}

View File

@@ -1,18 +1,20 @@
{
"BLOCK_STONE_DEEP": "Deepstone",
"BLOCK_SCAFFOLDING_NORMAL": "Scaffolding",
"BLOCK_STONE_MARBLE": "Marble",
"ITEM_CALENDAR": "Calendar",
"ITEM_LOGIC_SIGNAL_EMITTER": "Logic Signal Emitter",
"ITEM_STORAGE_CHEST": "Storage Chest",
"ITEM_TIKI_TORCH": "Tiki Torch",
"ITEM_TYPEWRITER": "Typewriter",
"ITEM_WIRE": "Wire",
"ITEM_WIRE_CUTTER": "Wire Cutter",
"ACTORBLOCK_ALLOW_MOVE_DOWN": "Urist Arôlcustith",
"ACTORBLOCK_FULL_COLLISION": "Urist Berdanrifot",
"ACTORBLOCK_NO_COLLISION": "Urist Zafal",
"ACTORBLOCK_NO_PASS_RIGHT": "Urist McPassLeft",
"ACTORBLOCK_NO_PASS_LEFT": "Urist McPassRight",
"ACTORBLOCK_TILING_PLACEHOLDER": "Urist Berdanurdim",
"BLOCK_STONE_DEEP": "Deepstone",
"BLOCK_SCAFFOLDING_NORMAL": "Scaffolding",
"BLOCK_STONE_MARBLE": "Marble",
"ITEM_STORAGE_CHEST": "Storage Chest",
"ITEM_WIRE": "Wire",
"ITEM_WIRE_CUTTER": "Wire Cutter",
"ITEM_LOGIC_SIGNAL_EMITTER": "Logic Signal Emitter",
"ITEM_TIKI_TORCH": "Tiki Torch"
"ACTORBLOCK_TILING_PLACEHOLDER": "Urist Berdanurdim"
}

View File

@@ -0,0 +1,3 @@
{
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "This is a world currently playing."
}

View File

@@ -0,0 +1,16 @@
{
"MENU_CALENDAR_CALENDAR": "달력",
"MENU_CALENDAR_EVENTS": "일정",
"MENU_CALENDAR_ADD_NEW_EVENT": "새 일정 추가",
"CONTEXT_CALENDAR_SEASON_SPRING": "봄",
"CONTEXT_CALENDAR_SEASON_SUMMER": "여름",
"CONTEXT_CALENDAR_SEASON_AUTUMN": "가을",
"CONTEXT_CALENDAR_SEASON_WINTER": "겨울",
"CONTEXT_CALENDAR_SEASON_SPRI": "봄",
"CONTEXT_CALENDAR_SEASON_SUMM": "여름",
"CONTEXT_CALENDAR_SEASON_AUTM": "가을",
"CONTEXT_CALENDAR_SEASON_WINT": "겨울",
"CONTEXT_CALENDAR_DATE_FORMAT_Y": "{0}년",
"CONTEXT_CALENDAR_DATE_FORMAT_YMD": "{0}년 {1} {2}일",
"CONTEXT_CALENDAR_DATE_FORMAT_YMD_DDD": "{0}년 {1} {2}일 {3}"
}

View File

@@ -1,21 +1,25 @@
{
"CONTEXT_GENERATOR_SEED": "시드",
"CONTEXT_ITEM_MAP": "지도",
"CONTEXT_ITEM_TOOL_PLURAL": "도구",
"CONTEXT_PLACE_COORDINATE": "좌표",
"CONTEXT_WORLD_COUNT": "새계: ",
"CONTEXT_WORLD_NEW": "새 세계",
"MENU_LABEL_DELETE_WORLD": "새계 삭제",
"CONTEXT_WORLD_COUNT": "새계: ",
"MENU_MONITOR_CALI_TITLE": "모니터 확인",
"GAME_INVENTORY_INGREDIENTS": "재료",
"GAME_INVENTORY_POTIONS": "물약",
"GAME_INVENTORY_BLOCKS": "블록",
"GAME_INVENTORY_WALLS": "벽지",
"CONTEXT_ITEM_TOOL_PLURAL": "도구",
"GAME_INVENTORY_FAVORITES": "즐겨찾기",
"GAME_INVENTORY_REGISTER": "등록하기",
"MENU_LABEL_MENU": "메뉴",
"CONTEXT_ITEM_MAP": "지도",
"CONTEXT_GENERATOR_SEED": "시드",
"MENU_LABEL_PREV_SAVES": "이전 세이브",
"MENU_LABEL_RENAME": "이름 바꾸기",
"MENU_MONITOR_CALI_TITLE": "모니터 확인",
"GAME_ACTION_CRAFT": "제작하기",
"GAME_ACTION_GRAPPLE": "매달리기",
"GAME_ACTION_QUICKSEL": "빠른 선택",
"GAME_ACTION_CRAFT": "제작하기",
"GAME_ACTION_TELEPORT": "텔레포트하기",
"GAME_CRAFTABLE_ITEMS": "제작 가능한 아이템",
"GAME_CRAFTING": "제작",
"GAME_CRAFTABLE_ITEMS": "제작 가능한 아이템"
"GAME_INVENTORY_BLOCKS": "블록",
"GAME_INVENTORY_FAVORITES": "즐겨찾기",
"GAME_INVENTORY_INGREDIENTS": "재료",
"GAME_INVENTORY_POTIONS": "물약",
"GAME_INVENTORY_REGISTER": "등록하기",
"GAME_INVENTORY_WALLS": "벽지"
}

View File

@@ -3,9 +3,11 @@
"BLOCK_SCAFFOLDING_NORMAL": "발판",
"BLOCK_STONE_MARBLE": "대리석",
"ITEM_STORAGE_CHEST": "보관상자",
"ITEM_WIRE": "전선",
"ITEM_WIRE_CUTTER": "전선 절단기",
"ITEM_CALENDAR": "달력",
"ITEM_LOGIC_SIGNAL_EMITTER": "신호발생기",
"ITEM_TIKI_TORCH": "티키 토치"
"ITEM_STORAGE_CHEST": "보관상자",
"ITEM_TIKI_TORCH": "티키 토치",
"ITEM_TYPEWRITER": "타자기",
"ITEM_WIRE": "전선",
"ITEM_WIRE_CUTTER": "전선 절단기"
}

View File

@@ -0,0 +1,3 @@
{
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "현재 플레이 중인 월드입니다."
}

Binary file not shown.

View File

@@ -1,5 +1,6 @@
{
"skyboxGradColourMap": "generic_skybox.tga",
"daylightClut": "clut_daylight.tga",
"classification": "generic",
"extraImages": [

Binary file not shown.

View File

@@ -23,12 +23,14 @@ cp $SRCFILES/AppRun $DESTDIR/AppRun
chmod +x $DESTDIR/AppRun
# Copy over a Java runtime
cp -r "../out/$RUNTIME" $DESTDIR/
mkdir $DESTDIR/out
cp -r "../out/$RUNTIME" $DESTDIR/out/
mv $DESTDIR/out/$RUNTIME/bin/java $DESTDIR/out/$RUNTIME/bin/Terrarum
# Copy over all the assets and a jarfile
cp -r "../assets_release" $DESTDIR/
mv $DESTDIR/assets_release $DESTDIR/assets
cp -r "../out/TerrarumBuild.jar" $DESTDIR/assets/
cp "../out/TerrarumBuild.jar" $DESTDIR/out/
# Pack everything to AppImage
ARCH=arm_aarch64 "./$APPIMAGETOOL" $DESTDIR "out/$DESTDIR.AppImage" || { echo 'Building AppImage failed' >&2; exit 1; }

View File

@@ -23,12 +23,14 @@ cp $SRCFILES/AppRun $DESTDIR/AppRun
chmod +x $DESTDIR/AppRun
# Copy over a Java runtime
cp -r "../out/$RUNTIME" $DESTDIR/
mkdir $DESTDIR/out
cp -r "../out/$RUNTIME" $DESTDIR/out/
mv $DESTDIR/out/$RUNTIME/bin/java $DESTDIR/out/$RUNTIME/bin/Terrarum
# Copy over all the assets and a jarfile
cp -r "../assets_release" $DESTDIR/
mv $DESTDIR/assets_release $DESTDIR/assets
cp -r "../out/TerrarumBuild.jar" $DESTDIR/assets/
cp "../out/TerrarumBuild.jar" $DESTDIR/out/
# Pack everything to AppImage
"./$APPIMAGETOOL" $DESTDIR "out/$DESTDIR.AppImage" || { echo 'Building AppImage failed' >&2; exit 1; }

View File

@@ -3,7 +3,8 @@ if (( $EUID == 0 )); then echo "The build process is not meant to be run with ro
cd "${0%/*}"
SRCFILES="terrarummac_arm"
DESTDIR="out/TerrarumMac.arm.app"
APPDIR="./TerrarumMac.arm.app"
DESTDIR="out/$APPDIR"
RUNTIME="runtime-osx-arm"
if [ ! -d "../assets_release" ]; then
@@ -25,11 +26,17 @@ cp $SRCFILES/Terrarum.sh $DESTDIR/Contents/MacOS/
chmod +x $DESTDIR/Contents/MacOS/Terrarum.sh
# Copy over a Java runtime
cp -r "../out/$RUNTIME" $DESTDIR/Contents/MacOS/
mkdir $DESTDIR/Contents/MacOS/out
cp -r "../out/$RUNTIME" $DESTDIR/Contents/MacOS/out/
mv $DESTDIR/Contents/MacOS/out/$RUNTIME/bin/java $DESTDIR/Contents/MacOS/out/$RUNTIME/bin/Terrarum
# Copy over all the assets and a jarfile
cp -r "../assets_release" $DESTDIR/Contents/MacOS/
mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets
cp -r "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/assets/
cp "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/out/
cd "out"
rm $APPDIR.zip
7z a -tzip $APPDIR.zip $APPDIR
echo "Build successful: $DESTDIR"

View File

@@ -3,7 +3,8 @@ if (( $EUID == 0 )); then echo "The build process is not meant to be run with ro
cd "${0%/*}"
SRCFILES="terrarummac_x86"
DESTDIR="out/TerrarumMac.x86.app"
APPDIR="./TerrarumMac.x86.app"
DESTDIR="out/$APPDIR"
RUNTIME="runtime-osx-x86"
if [ ! -d "../assets_release" ]; then
@@ -25,11 +26,17 @@ cp $SRCFILES/Terrarum.sh $DESTDIR/Contents/MacOS/
chmod +x $DESTDIR/Contents/MacOS/Terrarum.sh
# Copy over a Java runtime
cp -r "../out/$RUNTIME" $DESTDIR/Contents/MacOS/
mkdir $DESTDIR/Contents/MacOS/out
cp -r "../out/$RUNTIME" $DESTDIR/Contents/MacOS/out/
mv $DESTDIR/Contents/MacOS/out/$RUNTIME/bin/java $DESTDIR/Contents/MacOS/out/$RUNTIME/bin/Terrarum
# Copy over all the assets and a jarfile
cp -r "../assets_release" $DESTDIR/Contents/MacOS/
mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets
cp -r "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/assets/
cp "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/out/
cd "out"
rm $APPDIR.zip
7z a -tzip $APPDIR.zip $APPDIR
echo "Build successful: $DESTDIR"

View File

@@ -16,15 +16,23 @@ rm -rf $DESTDIR || true
mkdir $DESTDIR
# Prepare an application
cp $SRCFILES/Terrarum.bat $DESTDIR/
if ! command -v x86_64-w64-mingw32-gcc &> /dev/null
then
echo 'Mingw32 not found; please install mingw64-cross-gcc (or similar) to your system' >&2; exit 1;
fi
x86_64-w64-mingw32-gcc -Os -s -o $DESTDIR/Terrarum.exe $SRCFILES/Terrarum.c || { echo 'Building EXE failed' >&2; exit 1; }
# TODO add icon to the exe (use x86_64-w64-mingw32-windres?)
# Copy over a Java runtime
cp -r "../out/$RUNTIME" $DESTDIR/
mkdir $DESTDIR/out
cp -r "../out/$RUNTIME" $DESTDIR/out/
mv $DESTDIR/out/$RUNTIME/bin/java.exe $DESTDIR/out/$RUNTIME/bin/Terrarum.exe
# Copy over all the assets and a jarfile
cp -r "../assets_release" $DESTDIR/
mv $DESTDIR/assets_release $DESTDIR/assets
cp -r "../out/TerrarumBuild.jar" $DESTDIR/assets/
cp "../out/TerrarumBuild.jar" $DESTDIR/out/
# Temporary solution: zip everything
zip -r -9 -l "out/TerrarumWindows.x86.zip" $DESTDIR

25
buildapp/make_assets_release.sh Executable file
View File

@@ -0,0 +1,25 @@
#!/bin/bash
if (( $EUID == 0 )); then echo "The build process is not meant to be run with root privilege, exiting now." >&2; exit 1; fi
cd "${0%/*}"
DESTDIR="../assets_release"
rm -r $DESTDIR
cp -r "../assets" $DESTDIR
rm $DESTDIR/loopey.wav
rm $DESTDIR/ktGrepExample.kts
rm $DESTDIR/batchtest.txt
rm $DESTDIR/test_texture.tga
rm $DESTDIR/worldbacktest.tga
rm -r $DESTDIR/books
rm $DESTDIR/clut/skybox.tga
rm $DESTDIR/graphics/*.bat
rm $DESTDIR/keylayout/*.not_ime
rm $DESTDIR/mods/basegame/blocks/*.gz
rm $DESTDIR/mods/basegame/blocks/*.txt
rm -r $DESTDIR/mods/basegame/sounds
rm -r $DESTDIR/mods/dwarventech

View File

@@ -1,3 +1,3 @@
#!/bin/bash
cd "${0%/*}"
./runtime-linux-arm/bin/java -Xms1G -Xmx6G -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./assets/TerrarumBuild.jar
./out/runtime-linux-arm/bin/Terrarum -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./out/TerrarumBuild.jar

View File

@@ -1,3 +1,3 @@
#!/bin/bash
cd "${0%/*}"
./runtime-linux-x86/bin/java -Xms1G -Xmx6G -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./assets/TerrarumBuild.jar
./out/runtime-linux-x86/bin/Terrarum -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./out/TerrarumBuild.jar

View File

@@ -1,3 +1,3 @@
#!/bin/bash
cd "${0%/*}"
./runtime-osx-arm/bin/java -XstartOnFirstThread -Xms1G -Xmx6G -jar ./assets/TerrarumBuild.jar
./out/runtime-osx-arm/bin/Terrarum -jar ./out/TerrarumBuild.jar

View File

@@ -1,3 +1,3 @@
#!/bin/bash
cd "${0%/*}"
./runtime-osx-x86/bin/java -XstartOnFirstThread -Xms1G -Xmx6G -jar ./assets/TerrarumBuild.jar
./out/runtime-osx-x86/bin/Terrarum -jar ./out/TerrarumBuild.jar

View File

@@ -1,2 +0,0 @@
cd /D "%~dp0"
.\runtime-windows-x86\bin\java -Xms1G -Xmx6G -jar .\assets\TerrarumBuild.jar

View File

@@ -0,0 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
int main() {
return system(".\\out\\runtime-windows-x86\\bin\\Terrarum.exe -jar .\\out\\TerrarumBuild.jar");
}

View File

@@ -1,3 +1,3 @@
Manifest-Version: 1.0
Main-Class: net.torvald.terrarum.App
Main-Class: net.torvald.terrarum.Principii

View File

@@ -0,0 +1,72 @@
package com.badlogic.gdx.graphics.glutils;
import com.badlogic.gdx.Application;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.utils.GdxRuntimeException;
import net.torvald.terrarum.App;
// typealias Float16FrameBuffer = FloatFrameBuffer
/**
* Created by minjaesong on 2023-08-16.
*/
public class Float16FrameBuffer extends FrameBuffer {
Float16FrameBuffer () {
}
/** Creates a GLFrameBuffer from the specifications provided by bufferBuilder
*
* @param bufferBuilder **/
protected Float16FrameBuffer (GLFrameBufferBuilder<? extends GLFrameBuffer<Texture>> bufferBuilder) {
super(bufferBuilder);
}
/** Creates a new FrameBuffer with a float backing texture, having the given dimensions and potentially a depth buffer
* attached.
*
* @param width the width of the framebuffer in pixels
* @param height the height of the framebuffer in pixels
* @param hasDepth whether to attach a depth buffer
* @throws GdxRuntimeException in case the FrameBuffer could not be created */
public Float16FrameBuffer (int width, int height, boolean hasDepth) {
if (App.isAppleM) { // disable float framebuffer for Apple M chips
FrameBufferBuilder bufferBuilder = new FrameBufferBuilder(width, height);
bufferBuilder.addColorTextureAttachment(GL20.GL_RGBA, GL20.GL_RGBA, GL20.GL_UNSIGNED_SHORT); // but 16bpp int works perfectly?!
if (hasDepth) bufferBuilder.addBasicDepthRenderBuffer();
this.bufferBuilder = bufferBuilder;
}
else {
FloatFrameBufferBuilder bufferBuilder = new FloatFrameBufferBuilder(width, height);
bufferBuilder.addFloatAttachment(GL30.GL_RGBA16F, GL30.GL_RGBA, GL30.GL_FLOAT, false); // FIXME sporadic black screen on GL_RGBA16F? or maybe it was Plasma bugging out?
if (hasDepth) bufferBuilder.addBasicDepthRenderBuffer();
this.bufferBuilder = bufferBuilder;
}
build();
}
@Override
protected Texture createTexture (FrameBufferTextureAttachmentSpec attachmentSpec) {
if (App.isAppleM) {
GLOnlyTextureData data = new GLOnlyTextureData(bufferBuilder.width, bufferBuilder.height, 0, attachmentSpec.internalFormat,
attachmentSpec.format, attachmentSpec.type);
Texture result = new Texture(data);
result.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
result.setWrap(Texture.TextureWrap.ClampToEdge, Texture.TextureWrap.ClampToEdge);
return result;
}
else {
FloatTextureData data = new FloatTextureData(bufferBuilder.width, bufferBuilder.height, attachmentSpec.internalFormat,
attachmentSpec.format, attachmentSpec.type, attachmentSpec.isGpuOnly);
Texture result = new Texture(data);
result.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
result.setWrap(Texture.TextureWrap.ClampToEdge, Texture.TextureWrap.ClampToEdge);
return result;
}
}
}

View File

@@ -166,6 +166,19 @@ final public class FastMath {
return ((1f - scale) * startValue) + (scale * endValue);
}
public static double interpolateLinear(double scale, double startValue, double endValue) {
if (startValue == endValue) {
return startValue;
}
if (scale <= 0.0) {
return startValue;
}
if (scale >= 1.0) {
return endValue;
}
return ((1.0 - scale) * startValue) + (scale * endValue);
}
/**
* Linear interpolation from startValue to endValue by the given percent.
* Basically: ((1 - percent) * startValue) + (percent * endValue)
@@ -231,6 +244,10 @@ final public class FastMath {
return (float) (((c4 * u + c3) * u + c2) * u + c1);
}
public static float interpolateCatmullRom(float u, float p0, float p1, float p2, float p3) {
return interpolateCatmullRom(u, 0.5f, p0, p1, p2, p3);
}
/**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
* here is the interpolation matrix
* m = [ 0.0 1.0 0.0 0.0 ]
@@ -316,24 +333,25 @@ final public class FastMath {
public static float interpolateHermite(float scale, float p0, float p1, float p2, float p3) {
return interpolateHermite(scale, p0, p1, p2, p3, 1f, 0f);
}
public static float interpolateHermite(float scale, float p0, float p1, float p2, float p3, float tension, float bias) {
// return interpolateHermite(scale, p0, p1, p2, p3, 0f, 0f);
float mu2 = scale * scale;
float mu3 = mu2 * scale;
float biasTensionTerms = 0.5f;//(1f + bias) * (1f - tension) / 2f;
float m0 = (p1 - p0) * (1f + bias) * (1f - tension) / 2f;
m0 += (p2 - p1) * (1f + bias) * (1f - tension) / 2f;
float m1 = (p2 - p1) * (1f + bias) * (1f - tension) / 2f;
m1 += (p3 - p2) * (1f + bias) * (1f - tension) / 2f;
float m0 = (p1 - p0) * biasTensionTerms;
float mTemp = (p2 - p1) * biasTensionTerms;
m0 += mTemp;
float m1 = mTemp;
m1 += (p3 - p2) * biasTensionTerms;
float a0 = 2 * mu3 - 3 * mu2 + 1;
float a1 = mu3 - 2 * mu2 + scale;
float a2 = mu3 - mu2;
float a3 = -2 * mu3 + 3 * mu2;
float a0 = 2*mu3 - 3*mu2 + 1;
float a1 = 1*mu3 - 2*mu2 + scale;
float a2 = 1*mu3 - 1*mu2 + 0;
float a3 = -2*mu3 + 3*mu2 + 0;
return a0 * p1 + a1 * m0 + a2 * m1 + a3 * p2;
return a0*p1 + a1*m0 + a2*m1 + a3*p2;
}
//public static float interpolateHermite(float scale, float p0, float p1, float p2, float p3, float tension, float bias) {}
/**
@@ -795,28 +813,6 @@ final public class FastMath {
}
}
/**
* Take a float input and clamp it between min and max.
*
* @param input
* @param min
* @param max
* @return clamped input
*/
public static float clamp(float input, float min, float max) {
return (input < min) ? min : (input > max) ? max : input;
}
/**
* Clamps the given float to be between 0 and 1.
*
* @param input
* @return input clamped between 0 and 1.
*/
public static float saturate(float input) {
return clamp(input, 0f, 1f);
}
/**
* Converts a single precision (32 bit) floating point value
* into half precision (16 bit).
@@ -871,31 +867,6 @@ final public class FastMath {
| ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00)
| ((f >> 13) & 0x03ff));
}
public static float min(float... f) {
float min = f[0];
for (int i = 1; i < f.length; i++) min = (f[i] < min) ? f[i] : min;
return min;
}
public static float max(float... f) {
float max = f[0];
for (int i = 1; i < f.length; i++) max = (f[i] > max) ? f[i] : max;
return max;
}
public static int min(int... f) {
int min = f[0];
for (int i = 1; i < f.length; i++) min = (f[i] < min) ? f[i] : min;
return min;
}
public static int max(int... f) {
int max = f[0];
for (int i = 1; i < f.length; i++) max = (f[i] > max) ? f[i] : max;
return max;
}
public static int getGCD(int a, int b) {
while (a != b) {
if (a > b) a = a-b;

View File

@@ -81,7 +81,7 @@ fun Color.toXYZ(): CIEXYZ = RGB(this).toXYZ()
}
val step = value.clampOne() * 255f // 0.0 .. 255.0
val intStep = step.toInt() // 0 .. 255
val NeXTSTEP = minOf(intStep + 1, 255) // 1 .. 255
val NeXTSTEP = min(intStep + 1, 255) // 1 .. 255
out[i] = interpolateLinear(step - intStep, rgbLinLUT[intStep], rgbLinLUT[NeXTSTEP])
}
@@ -123,7 +123,7 @@ fun RGB.linearise(): RGB {
}
val step = value.clampOne() * 255f // 0.0 .. 255.0
val intStep = step.toInt() // 0 .. 255
val NeXTSTEP = minOf(intStep + 1, 255) // 1 .. 255
val NeXTSTEP = min(intStep + 1, 255) // 1 .. 255
out[i] = interpolateLinear(step - intStep, rgbUnLinLUT[intStep], rgbUnLinLUT[NeXTSTEP])
}
@@ -192,6 +192,16 @@ fun CIEXYZ.toColorRaw(): Color {
return Color(rgb.r, rgb.g, rgb.b, rgb.alpha)
}
fun CIEXYZ.toYXY(): CIEYXY {
val dot = this.X + this.Y + this.Z
return CIEYXY(
this.Y,
this.X / dot,
this.Y / dot,
this.alpha
)
}
fun CIEYXY.toXYZ(): CIEXYZ {
return CIEXYZ(x * yy / y, yy, (1f - x - y) * yy / y)
}

View File

@@ -2,6 +2,8 @@ package net.torvald.colourutil
import com.jme3.math.FastMath
import com.badlogic.gdx.graphics.Color
import kotlin.math.max
import kotlin.math.min
/**
* OBSOLETE; use CIELchUtil for natural-looking colour
@@ -75,8 +77,8 @@ object HSVUtil {
val g = color.g
val b = color.b
val rgbMin = FastMath.min(r, g, b)
val rgbMax = FastMath.max(r, g, b)
val rgbMin = min(min(r, g), b)
val rgbMax = max(max(r, g), b)
var h: Float
val s: Float

View File

@@ -110,7 +110,7 @@ public class HUSLColorConverter {
float x = intersectLineLine(line, new float[]{-1 / m1, 0});
float length = distanceFromPole(new float[]{x, b1 + x * m1});
min = FastMath.min(min, length);
min = Math.min(min, length);
}
return min;
@@ -125,7 +125,7 @@ public class HUSLColorConverter {
for (float[] bound : bounds) {
Length length = lengthOfRayUntilIntersect(hrad, bound);
if (length.greaterEqualZero) {
min = FastMath.min(min, length.length);
min = Math.min(min, length.length);
}
}

View File

@@ -55,6 +55,13 @@ class Cvec {
this.a = color.a
}
constructor(rgb: Color, alpha: Float) {
this.r = rgb.r
this.g = rgb.g
this.b = rgb.b
this.a = alpha
}
/** Constructor, sets the components of the color
*
* @param r the red component

View File

@@ -104,10 +104,10 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) {
// operators
fun max(x: Int, y: Int, other: Cvec) {
val a = toAddr(x, y)
array.setFloat(a + 0, maxOf(array.getFloat(a + 0), other.r))
array.setFloat(a + 1, maxOf(array.getFloat(a + 1), other.g))
array.setFloat(a + 2, maxOf(array.getFloat(a + 2), other.b))
array.setFloat(a + 3, maxOf(array.getFloat(a + 3), other.a))
array.setFloat(a + 0, kotlin.math.max(array.getFloat(a + 0), other.r))
array.setFloat(a + 1, kotlin.math.max(array.getFloat(a + 1), other.g))
array.setFloat(a + 2, kotlin.math.max(array.getFloat(a + 2), other.b))
array.setFloat(a + 3, kotlin.math.max(array.getFloat(a + 3), other.a))
}
fun mul(x: Int, y: Int, scalar: Float) {
val a = toAddr(x, y)
@@ -202,10 +202,10 @@ internal class TestCvecArr(val width: Int, val height: Int) {
// operators
inline fun max(x: Int, y: Int, other: Cvec) {
setR(x, y, maxOf(getR(x, y), other.r))
setG(x, y, maxOf(getG(x, y), other.g))
setB(x, y, maxOf(getB(x, y), other.b))
setA(x, y, maxOf(getA(x, y), other.a))
setR(x, y, kotlin.math.max(getR(x, y), other.r))
setG(x, y, kotlin.math.max(getG(x, y), other.g))
setB(x, y, kotlin.math.max(getB(x, y), other.b))
setA(x, y, kotlin.math.max(getA(x, y), other.a))
}
inline fun mul(x: Int, y: Int, scalar: Float) {
setR(x, y, getR(x, y) * scalar)

View File

@@ -12,24 +12,36 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.unicode.EMDASH
import net.torvald.colourutil.*
import net.torvald.parametricsky.datasets.DatasetCIEXYZ
import net.torvald.parametricsky.datasets.DatasetRGB
import net.torvald.parametricsky.datasets.DatasetSpectral
import net.torvald.terrarum.abs
import net.torvald.terrarum.clut.Skybox
import net.torvald.terrarum.clut.Skybox.coerceInSmoothly
import net.torvald.terrarum.clut.Skybox.mapCircle
import net.torvald.terrarum.inUse
import net.torvald.terrarum.modulebasegame.worldgenerator.HALF_PI
import net.torvald.terrarum.modulebasegame.worldgenerator.TWO_PI
import java.awt.BorderLayout
import java.awt.Dimension
import java.lang.Math.pow
import javax.swing.*
import kotlin.math.PI
import kotlin.math.pow
import kotlin.math.*
const val WIDTH = 1200
const val HEIGHT = 600
val INITIAL_TURBIDITY = 4.0
val INITIAL_ALBEDO = 0.1
val INITIAL_ELEV = 0.0
/**
* Created by minjaesong on 2018-08-01.
*/
class Application : Game() {
class Application(val WIDTH: Int, val HEIGHT: Int) : Game() {
private val HW = WIDTH / 2
private val HH = HEIGHT / 2
private val wf = WIDTH.toFloat()
private val hf = HEIGHT.toFloat()
private val hwf = HW.toFloat()
// private val hhf = HH.toFloat()
/* Variables:
* 1. Canvas Y (theta)
@@ -53,12 +65,12 @@ class Application : Game() {
private lateinit var oneScreen: Pixmap
private lateinit var batch: SpriteBatch
private lateinit var testTex: Texture
var turbidity = INITIAL_TURBIDITY
var albedo = INITIAL_ALBEDO
var elevation = Math.toRadians(INITIAL_ELEV)
var turbidity = 5.0
var albedo = 0.1
var elevation = 0.0
var scalefactor = 1f
var solarBearing = Math.toRadians(90.0)
var cameraHeading = Math.toRadians(90.0)
override fun getScreen(): Screen {
return super.getScreen()
@@ -68,20 +80,38 @@ class Application : Game() {
super.setScreen(screen)
}
var model = ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevation.abs())
fun regenerateModel() {
model = ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevation.abs())
}
override fun render() {
Gdx.graphics.setTitle("Daylight Model $EMDASH F: ${Gdx.graphics.framesPerSecond}")
if (turbidity <= 0) throw IllegalStateException()
// we need to use different modelstate to accomodate different albedo for each spectral band but oh well...
genTexLoop(ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevation))
// we need to use different model-state to accommodate different albedo for each spectral band but oh well...
genTexLoop(model, elevation)
// println("$elevation\t${ymaxDisp.text}\t${ymaxDisp2.text}")
/*for (elev in -75..75) {
val elevation = Math.toRadians(elev.toDouble())
val model = ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevation.abs())
genTexLoop(model, elevation)
println("$elev\t${ymaxDisp.text}\t${ymaxDisp2.text}")
}*/
val tex = Texture(oneScreen)
tex.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
tex.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
batch.inUse {
batch.draw(tex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat())
// batch.draw(tex, hwf, 0f, hwf, hf)
// batch.draw(tex, hwf, 0f, -hwf, hf)
batch.draw(tex, 0f, 0f, wf, hf)
}
tex.dispose()
@@ -103,14 +133,48 @@ class Application : Game() {
oneScreen.dispose()
}
val outTexWidth = 256
val outTexHeight = 256
val outTexWidth = 1
val outTexHeight = 128
private fun Float.scaleFun() =
(1f - 1f / 2f.pow(this/6f)) * 0.97f
private fun CIEXYZ.scaleToFit(elevation: Double): CIEXYZ {
return if (elevation >= 0) {
CIEXYZ(
this.X.scaleFun(),
this.Y.scaleFun(),
this.Z.scaleFun(),
this.alpha
)
}
else {
// maths model: https://www.desmos.com/calculator/cwi7iyzygg
val x = -Math.toDegrees(elevation).toFloat()
// val elevation2 = -Math.toDegrees(elevation) / 28.5
val p = 3.5f
val q = 7.5f
val s = -0.2f
val f = (1f - (1f - 1f / 1.8f.pow(x)) * 0.97f).toFloat()
// val g = (1.0 - (elevation2.pow(E) / E.pow(elevation2))*0.8).toFloat()
val h = ((x / q).pow(p) + 1f).pow(s)
CIEXYZ(
this.X.scaleFun() * f * h,
this.Y.scaleFun() * f * h,
this.Z.scaleFun() * f * h,
this.alpha
)
}
}
private fun Double.mapCircle() = sin(HALF_PI * this)
/**
* Generated texture is as if you took the panorama picture of sky: up 70deg to horizon, east-south-west;
* with sun not moving (sun is at exact south, sun's height is adjustable)
*/
private fun genTexLoop(state: ArHosekSkyModelState) {
private fun genTexLoop(state: ArHosekSkyModelState, elevation: Double) {
fun normaliseY(y: Double): Float {
var v = y.coerceAtLeast(0.0)
@@ -120,20 +184,49 @@ class Application : Game() {
return v.toFloat()
}
val ys = ArrayList<Float>()
val ys2 = ArrayList<Float>()
val halfHeight = oneScreen.height * 0.5
val elevationDeg = Math.toDegrees(elevation)
for (x in 0 until oneScreen.width) {
for (y in 0 until oneScreen.height) {
// sky-sphere mapping
/*val xf = ((x + 0.5) / oneScreen.width) * 2.0 - 1.0
val yf = ((y + 0.5) / oneScreen.height) * 2.0 - 1.0
val gamma = atan2(yf, xf) + PI
val theta = sqrt(xf*xf + yf*yf) * HALF_PI*/
// AM-PM mapping (use with WIDTH=1)
val yp = y % (oneScreen.height / 2)
val yi = yp - 3
val xf = -elevationDeg / 90.0
var yf = (yi / 58.0).coerceIn(0.0, 1.0).mapCircle().coerceInSmoothly(0.0, 0.95)
if (elevationDeg < 0) yf *= Skybox.superellipsoidDecay(1.0 / 3.0, xf)
val theta = yf * HALF_PI
val gamma = if (y < halfHeight) HALF_PI else 3 * HALF_PI
for (y in 0 until oneScreen.height) {
for (x in 0 until oneScreen.width) {
val gamma = (x / oneScreen.width.toDouble()) * TWO_PI // 0deg..360deg
val theta = (1.0 - (y / oneScreen.height.toDouble())) * HALF_PI // 90deg..0deg
val xyz = CIEXYZ(
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 0).toFloat().times(scalefactor / 10f),
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 1).toFloat().times(scalefactor / 10f),
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 2).toFloat().times(scalefactor / 10f)
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 0).toFloat(),
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 1).toFloat(),
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 2).toFloat(),
)
val rgb = xyz.toRGB().toColor()
val xyz2 = xyz.scaleToFit(elevation)
ys.add(xyz.Y)
ys2.add(xyz2.Y)
val rgb = xyz2.toRGB().toColor()
rgb.a = 1f
/*val rgb2 = Color(
((rgb.r * 255f).roundToInt() xor 0xAA) / 255f,
((rgb.g * 255f).roundToInt() xor 0xAA) / 255f,
((rgb.b * 255f).roundToInt() xor 0xAA) / 255f,
rgb.a
)*/
oneScreen.setColor(rgb)
oneScreen.drawPixel(x, y)
@@ -142,140 +235,148 @@ class Application : Game() {
}
ymaxDisp.text = "${ys.max()}"
ymaxDisp2.text = "${ys2.max()}"
//System.exit(0)
}
/**
* Generated texture is as if you took the panorama picture of sky: up 70deg to horizon, east-south-west;
* with sun not moving (sun is at exact south, sun's height is adjustable)
*/
/*private fun genTexLoop2(T: Double, theta_s: Double) {
fun hazeFun(T: Double): Double {
val T = T - 1
if (T >= 10) return 1.0
else return 2.0.pow(T).div(1024.0)
}
// loop thru gamma and theta
for (y in 0..outTexDim) { // theta
for (x in 0..outTexDim) { // gamma
val theta = Math.toRadians(y * (90.0 / outTexDim.toDouble())) // of observer
val gamma = Math.toRadians(x * (90.0 / outTexDim.toDouble())) // of observer
val Y_z = Model.getAbsoluteZenithLuminance(T, theta_s)
val x_z = Model.getZenithChromaX(T, theta_s)
val y_z = Model.getZenithChromaY(T, theta_s)
val Y_p = Y_z * Model.getFforLuma(theta, gamma, T) / Model.getFforLuma(0.0, theta_s, T)
val Y_oc = Y_z * (1.0 + 2.0 * Math.cos(theta)) / 3.0
val x_p = (x_z * Model.getFforChromaX(theta, gamma, T) / Model.getFforChromaX(0.0, theta_s, T)).coerceIn(0.0, 1.0)
val y_p = (y_z * Model.getFforChromaY(theta, gamma, T) / Model.getFforChromaY(0.0, theta_s, T)).coerceIn(0.0, 1.0)
val normalisedY = Y_p.toFloat().pow(0.5f).div(10f)
val normalisedY_oc = Y_oc.toFloat().pow(0.5f).div(10f)
//println("$Y_p -> $normalisedY, $x_p, $y_p")
if (T < 11) {
val rgbColour = CIEYXY(normalisedY, x_p.toFloat(), y_p.toFloat()).toXYZ().toColorRaw()
val hazeColour = CIEYXY(normalisedY_oc, 0.3128f, 0.3290f).toXYZ().toColorRaw()
val hazeAmount = hazeFun(T).toFloat()
val newColour = Color(
FastMath.interpolateLinear(hazeAmount, rgbColour.r, hazeColour.r),
FastMath.interpolateLinear(hazeAmount, rgbColour.g, hazeColour.g),
FastMath.interpolateLinear(hazeAmount, rgbColour.b, hazeColour.b),
1f
)
oneScreen.setColor(newColour)
oneScreen.drawPixel(x, y)
}
else {
val hazeColour = CIEYXY(normalisedY_oc, 0.3128f, 0.3290f).toXYZ().toColorRaw()
oneScreen.setColor(hazeColour)
oneScreen.drawPixel(x, y)
}
}
}
// end loop
}*/
override fun create() {
batch = SpriteBatch()
testTex = Texture(Gdx.files.internal("assets/test_texture.tga"))
oneScreen = Pixmap(outTexWidth * 2, outTexHeight, Pixmap.Format.RGBA8888)
oneScreen = Pixmap(outTexWidth, outTexHeight, Pixmap.Format.RGBA8888)
DatasetSpectral
// DatasetSpectral
DatasetCIEXYZ
DatasetRGB
// DatasetRGB
ApplicationController(this)
}
val ymaxDisp = JTextField().also {
it.preferredSize = Dimension(64, 20)
}
val ymaxDisp2 = JTextField().also {
it.preferredSize = Dimension(64, 20)
}
class ApplicationController(val app: Application) : JFrame() {
class ApplicationController(app: Application) : JFrame() {
val dialSize = Dimension(45, 20)
val mainPanel = JPanel()
val turbidityControl = JSpinner(SpinnerNumberModel(5.0, 1.0, 10.0, 0.1))
val albedoControl = JSpinner(SpinnerNumberModel(0.1, 0.0, 1.0, 0.05))
val elevationControl = JSpinner(SpinnerNumberModel(0.0, 0.0, 90.0, 0.5))
val scalefactorControl = JSpinner(SpinnerNumberModel(1.0, 0.0, 2.0, 0.01))
val turbidityControl = JSpinner(SpinnerNumberModel(INITIAL_TURBIDITY, 1.0, 10.0, 0.1)).also {
it.preferredSize = dialSize
it.addChangeListener { _ ->
app.turbidity = it.value as Double
app.regenerateModel()
}
}
val albedoControl = JSpinner(SpinnerNumberModel(INITIAL_ALBEDO, 0.0, 1.0, 0.05)).also {
it.preferredSize = dialSize
it.addChangeListener { _ ->
app.albedo = it.value as Double
app.regenerateModel()
}
}
val elevationControl = JSpinner(SpinnerNumberModel(INITIAL_ELEV, -75.0, 75.0, 0.5)).also {
it.preferredSize = dialSize
it.addChangeListener { _ ->
app.elevation = Math.toRadians(it.value as Double)
app.regenerateModel()
}
}
val solarBearing = JSpinner(SpinnerNumberModel(90.0, 0.0, 180.0, 1.0)).also {
it.preferredSize = dialSize
it.addChangeListener { _ ->
app.solarBearing = (it.value as Double)
}
}
val cameraHeading = JSpinner(SpinnerNumberModel(90.0, 0.0, 180.0, 1.0)).also {
it.preferredSize = dialSize
it.addChangeListener { _ ->
app.cameraHeading = (it.value as Double)
}
}
init {
val turbidityPanel = JPanel()
val albedoPanel = JPanel()
val elevationPanel = JPanel()
val scalefactorPanel = JPanel()
val atmosPanel = JPanel()
val turbidityPanel = JPanel().also {
it.add(JLabel("Turbidity (log_2)"))
it.add(turbidityControl)
atmosPanel.add(it)
}
val albedoPanel = JPanel().also {
it.add(JLabel("Albedo"))
it.add(albedoControl)
atmosPanel.add(it)
}
turbidityControl.preferredSize = Dimension(45, 18)
albedoControl.preferredSize = Dimension(45, 18)
elevationControl.preferredSize = Dimension(45, 18)
scalefactorControl.preferredSize = Dimension(45, 18)
val sunPanel = JPanel()
val elevationPanel = JPanel().also {
it.add(JLabel("Elevation"))
it.add(elevationControl)
sunPanel.add(it)
}
val scalefactorPanel = JPanel().also {
it.add(JLabel("Bearing"))
it.add(solarBearing)
sunPanel.add(it)
}
turbidityPanel.add(JLabel("Turbidity"))
turbidityPanel.add(turbidityControl)
val cameraPanel = JPanel()
val headingPanel = JPanel().also {
it.add(JLabel("Heading"))
it.add(cameraHeading)
cameraPanel.add(it)
}
albedoPanel.add(JLabel("Albedo"))
albedoPanel.add(albedoControl)
val statsPanel = JPanel()
val ymaxPanel = JPanel().also {
it.add(JLabel("Ymax (CIEXYZ)"))
it.add(app.ymaxDisp)
statsPanel.add(it)
}
val ymaxPanel2 = JPanel().also {
it.add(JLabel("Ymax (scaled)"))
it.add(app.ymaxDisp2)
statsPanel.add(it)
}
elevationPanel.add(JLabel("Elevation"))
elevationPanel.add(elevationControl)
val mainPanel = JPanel()
scalefactorPanel.add(JLabel("Scaling Factor"))
scalefactorPanel.add(scalefactorControl)
mainPanel.add(turbidityPanel)
mainPanel.add(albedoPanel)
mainPanel.add(elevationPanel)
mainPanel.add(scalefactorPanel)
mainPanel.layout = BoxLayout(mainPanel, BoxLayout.Y_AXIS)
JPanel().also {
it.layout = BorderLayout()
it.add(JPanel().also { it.add(JLabel("Atmosphere")) }, BorderLayout.NORTH)
it.add(atmosPanel, BorderLayout.CENTER)
it.add(JSeparator(), BorderLayout.SOUTH)
mainPanel.add(it)
}
JPanel().also {
it.layout = BorderLayout()
it.add(JPanel().also { it.add(JLabel("Sun")) }, BorderLayout.NORTH)
it.add(sunPanel, BorderLayout.CENTER)
it.add(JSeparator(), BorderLayout.SOUTH)
mainPanel.add(it)
}
JPanel().also {
it.layout = BorderLayout()
it.add(JPanel().also { it.add(JLabel("Camera")) }, BorderLayout.NORTH)
it.add(cameraPanel, BorderLayout.CENTER)
it.add(JSeparator(), BorderLayout.SOUTH)
mainPanel.add(it)
}
JPanel().also {
it.layout = BorderLayout()
it.add(JPanel().also { it.add(JLabel("Statistics")) }, BorderLayout.NORTH)
it.add(statsPanel, BorderLayout.CENTER)
mainPanel.add(it)
}
this.isVisible = true
this.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
this.size = Dimension(300, 400)
this.add(mainPanel)
turbidityControl.addChangeListener {
app.turbidity = turbidityControl.value as Double
}
albedoControl.addChangeListener {
app.albedo = albedoControl.value as Double
}
elevationControl.addChangeListener {
app.elevation = Math.toRadians(elevationControl.value as Double)
}
scalefactorControl.addChangeListener {
app.scalefactor = (scalefactorControl.value as Double).toFloat()
}
this.size = Dimension(300, 600)
this.add(mainPanel, BorderLayout.CENTER)
}
@@ -285,7 +386,10 @@ class Application : Game() {
fun main(args: Array<String>) {
val config = Lwjgl3ApplicationConfiguration()
config.setWindowedMode(WIDTH, HEIGHT)
Lwjgl3Application(Application(), config)
val WIDTH = 2048
val HEIGHT = 2048
config.setWindowedMode(WIDTH, HEIGHT)
Lwjgl3Application(Application(WIDTH, HEIGHT), config)
}

View File

@@ -11,8 +11,8 @@ object DatasetOp {
val entrysize = file.length().toInt() / 8
val fis = FileInputStream(file)
val inputbuf = ByteArray(8)
val ret = DoubleArray(entrysize) {
val inputbuf = ByteArray(8)
fis.read(inputbuf)
val rawnum = inputbuf.toLittleInt64()
Double.fromBits(rawnum)

View File

@@ -1,7 +1,7 @@
package net.torvald.random
import com.jme3.math.FastMath
import net.torvald.terrarum.floorInt
import net.torvald.terrarum.floorToInt
import net.torvald.terrarum.gameworld.fmod
import java.util.*
@@ -45,9 +45,9 @@ class TileableValueNoise(
try {
for (x in 0..width) {
val thisSampleStart: Int = // 0-256 -> 0-4 -> 0-256(qnt)
(x / width.toFloat() * samples).floorInt() * (width / samples)
(x / width.toFloat() * samples).floorToInt() * (width / samples)
val nextSampleStart: Int =
(x / width.toFloat() * samples).floorInt().plus(1) * (width / samples)
(x / width.toFloat() * samples).floorToInt().plus(1) * (width / samples)
val stepWithinWindow: Int = x % (nextSampleStart - thisSampleStart)
val windowScale: Float = stepWithinWindow.toFloat() / (width / samples)

View File

@@ -18,7 +18,7 @@ public class XXHash32 {
public static int hashGeoCoord(int x, int y) {
int p = ((x & 65535) << 16) | (y & 65535);
return hash(new byte[]{(byte) p, (byte)(p >>> 8), (byte)(p >>> 16), (byte)(p >>> 24)}, 10000);
return hash(new byte[]{(byte) p, (byte)(p >>> 8), (byte)(p >>> 16), (byte)(p >>> 24)}, x ^ y);
}
public static int hash(byte[] data, int seed) {

View File

@@ -3,15 +3,15 @@ package net.torvald.reflection
/**
* Created by minjaesong on 2023-03-25.
*/
fun Any.extortField(name: String): Any? { // yes I'm deliberately using negative words for the function name
inline fun <reified T> Any.extortField(name: String): T? { // yes I'm deliberately using negative words for the function name
return this.javaClass.getDeclaredField(name).let {
it.isAccessible = true
it.get(this)
it.get(this) as T?
}
}
fun Any.forceInvoke(name: String, params: Array<Any>): Any? { // yes I'm deliberately using negative words for the function name
inline fun <reified T> Any.forceInvoke(name: String, params: Array<Any>): T? { // yes I'm deliberately using negative words for the function name
return this.javaClass.getDeclaredMethod(name, *(params.map { it.javaClass }.toTypedArray())).let {
it.isAccessible = true
it.invoke(this, *params)
it.invoke(this, *params) as T?
}
}

View File

@@ -7,7 +7,7 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion
import com.badlogic.gdx.utils.GdxRuntimeException
import net.torvald.terrarum.ItemCodex
import net.torvald.terrarum.Second
import net.torvald.terrarum.floor
import net.torvald.terrarum.floorToFloat
import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.gameitems.GameItem
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
@@ -19,6 +19,7 @@ import net.torvald.terrarum.spriteassembler.ADProperties
import net.torvald.terrarum.spriteassembler.ADPropertyObject
import net.torvald.terrarum.spriteassembler.AssembleFrameBase
import net.torvald.terrarum.spriteassembler.AssembleSheetPixmap
import net.torvald.terrarum.tryDispose
import java.io.InputStream
import java.util.*
@@ -122,8 +123,8 @@ class AssembledSpriteAnimation(
val drawPos = adp.origin + bodypartPos // imgCentre for held items are (0,0)
val w = image.regionWidth * scale
val h = image.regionHeight * scale
val fposX = posX.floor() + drawPos.x * scale
val fposY = posY.floor() + drawPos.y * scale - h
val fposX = posX.floorToFloat() + drawPos.x * scale
val fposY = posY.floorToFloat() + drawPos.y * scale - h
// draw
if (flipHorizontal && flipVertical)
@@ -146,8 +147,8 @@ class AssembledSpriteAnimation(
val drawPos = adp.origin + bodypartPos - imgCentre
val w = image.regionWidth * scale
val h = image.regionHeight * scale
val fposX = posX.floor() + drawPos.x * scale
val fposY = posY.floor() + drawPos.y * scale
val fposX = posX.floorToFloat() + drawPos.x * scale
val fposY = posY.floorToFloat() + drawPos.y * scale
if (flipHorizontal && flipVertical)
batch.draw(image, fposX + txFlp, fposY + tyFlp, -w, -h)
@@ -172,7 +173,7 @@ class AssembledSpriteAnimation(
}
override fun dispose() {
res.values.forEach { try { it?.texture?.dispose() } catch (_: GdxRuntimeException) {} }
res.values.forEach { it?.texture?.tryDispose() }
}
companion object {

View File

@@ -31,7 +31,6 @@ import net.torvald.terrarum.langpack.Lang;
import net.torvald.terrarum.modulebasegame.IngameRenderer;
import net.torvald.terrarum.modulebasegame.TerrarumIngame;
import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory;
import net.torvald.terrarum.savegame.DiskSkimmer;
import net.torvald.terrarum.serialise.WriteConfig;
import net.torvald.terrarum.ui.Toolkit;
import net.torvald.terrarum.utils.JsonFetcher;
@@ -63,9 +62,11 @@ public class App implements ApplicationListener {
public static final String GAME_NAME = TerrarumAppConfiguration.GAME_NAME;
public static final long VERSION_RAW = TerrarumAppConfiguration.VERSION_RAW;
public static final String VERSION_TAG = TerrarumAppConfiguration.VERSION_TAG;
public static final String getVERSION_STRING() {
return String.format("%d.%d.%d", VERSION_RAW >>> 48, (VERSION_RAW & 0xffff000000L) >>> 24, VERSION_RAW & 0xffffffL);
return String.format("%d.%d.%d", VERSION_RAW >>> 48, (VERSION_RAW & 0xffff000000L) >>> 24, VERSION_RAW & 0xffffffL) +
(VERSION_TAG.isBlank() ? "" : "-"+VERSION_TAG);
}
/**
@@ -142,6 +143,12 @@ public class App implements ApplicationListener {
public static final int GLOBAL_FRAMERATE_LIMIT = 300;
private static String undesirableConditions;
public static String getUndesirableConditions() {
return undesirableConditions;
}
/**
* These languages won't distinguish regional differences (e.g. enUS and enUK, frFR and frCA)
*/
@@ -201,11 +208,11 @@ public class App implements ApplicationListener {
* Sorted by the lastplaytime, in reverse order (index 0 is the most recent game played)
*/
public static ArrayList<UUID> sortedSavegameWorlds = new ArrayList();
public static HashMap<UUID, DiskSkimmer> savegameWorlds = new HashMap<>(); // UNSORTED even with the TreeMap
public static HashMap<UUID, SavegameCollection> savegameWorlds = new HashMap<>(); // UNSORTED even with the TreeMap
public static HashMap<UUID, String> savegameWorldsName = new HashMap<>();
public static ArrayList<UUID> sortedPlayers = new ArrayList();
public static HashMap<UUID, DiskSkimmer> savegamePlayers = new HashMap<>();
public static HashMap<UUID, SavegameCollection> savegamePlayers = new HashMap<>();
public static HashMap<UUID, String> savegamePlayersName = new HashMap<>();
public static void updateListOfSavegames() {
@@ -234,6 +241,7 @@ public class App implements ApplicationListener {
public static ShaderProgram shaderColLUT;
public static ShaderProgram shaderReflect;
public static ShaderProgram shaderGhastlyWhite;
public static Hq2x hq2x;
public static Mesh fullscreenQuad;
private static OrthographicCamera camera;
@@ -261,12 +269,13 @@ public class App implements ApplicationListener {
Gdx.gl20.glViewport(0, 0, width, height);
}
public static final float UPDATE_RATE = 1f / 64f; // apparent framerate will be limited by update rate
public static final int TICKS = 64;
public static final float UPDATE_RATE = 1f / TICKS; // apparent framerate will be limited by update rate
private static float loadTimer = 0f;
private static final float showupTime = 100f / 1000f;
private static FloatFrameBuffer renderFBO;
private static Float16FrameBuffer renderFBO;
public static HashSet<File> tempFilePool = new HashSet<>();
@@ -346,10 +355,13 @@ public class App implements ApplicationListener {
processorVendor = "Unknown CPU";
}
if (processor.startsWith("Apple M") && Objects.equals(systemArch, "aarch64")) {
if (processor.startsWith("Apple M") && systemArch.equals("aarch64")) {
isAppleM = true;
System.out.println("Apple Proprietary "+processor+" detected; don't expect smooth sailing...");
}
if (processor.startsWith("Apple M") && !systemArch.equals("aarch64")) {
undesirableConditions = "apple_execution_through_rosetta";
}
if (!IS_DEVELOPMENT_BUILD) {
var p = UnsafeHelper.INSTANCE.allocate(64);
@@ -374,8 +386,8 @@ public class App implements ApplicationListener {
ShaderProgram.pedantic = false;
scr = new TerrarumScreenSize(getConfigInt("screenwidth"), getConfigInt("screenheight"));
int width = (int) Math.round(scr.getWidth() * scr.getMagn());
int height = (int) Math.round(scr.getHeight() * scr.getMagn());
int width = scr.getWindowW();
int height = scr.getWindowH();
Lwjgl3ApplicationConfiguration appConfig = new Lwjgl3ApplicationConfiguration();
//appConfig.useGL30 = false; // https://stackoverflow.com/questions/46753218/libgdx-should-i-use-gl30
@@ -383,6 +395,7 @@ public class App implements ApplicationListener {
appConfig.useVsync(getConfigBoolean("usevsync"));
appConfig.setResizable(false);
appConfig.setWindowedMode(width, height);
appConfig.setTransparentFramebuffer(false);
int fpsActive = Math.min(GLOBAL_FRAMERATE_LIMIT, getConfigInt("displayfps"));
if (fpsActive <= 0) fpsActive = GLOBAL_FRAMERATE_LIMIT;
int fpsBack = Math.min(GLOBAL_FRAMERATE_LIMIT, getConfigInt("displayfpsidle"));
@@ -430,13 +443,10 @@ public class App implements ApplicationListener {
glInfo.create();
CommonResourcePool.INSTANCE.addToLoadingList("blockmarkings_common", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/blocks/block_markings_common.tga"), 16, 16, 0, 0, 0, 0, false, false, false));
CommonResourcePool.INSTANCE.addToLoadingList("blockmarking_actor", () -> new BlockMarkerActor());
CommonResourcePool.INSTANCE.addToLoadingList("loading_circle_64", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/gui/loading_circle_64.tga"), 64, 64, 0, 0, 0, 0, false, false, false));
CommonResourcePool.INSTANCE.addToLoadingList("inline_loading_spinner", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/gui/inline_loading_spinner.tga"), 20, 20, 0, 0, 0, 0, false, false, false));
CommonResourcePool.INSTANCE.addToLoadingList("inventory_category", () -> new TextureRegionPack("./assets/graphics/gui/inventory/category.tga", 20, 20, 0, 0, 0, 0, false, false, false));
CommonResourcePool.INSTANCE.addToLoadingList("title_health1", () -> new Texture(Gdx.files.internal("./assets/graphics/gui/health_take_a_break.tga")));
CommonResourcePool.INSTANCE.addToLoadingList("title_health2", () -> new Texture(Gdx.files.internal("./assets/graphics/gui/health_distance.tga")));
// make loading list
CommonResourcePool.INSTANCE.loadAll();
newTempFile("wenquanyi.tga"); // temp file required by the font
@@ -465,12 +475,9 @@ public class App implements ApplicationListener {
shaderBayerSkyboxFill = loadShaderFromClasspath("shaders/default.vert",
"shaders/float_to_disp_dither_static.frag"
);
shaderHicolour = loadShaderFromClasspath("shaders/default.vert", "shaders/hicolour.frag");
shaderDebugDiff = loadShaderFromClasspath("shaders/default.vert", "shaders/diff.frag");
shaderPassthruRGBA = loadShaderFromClasspath("shaders/gl32spritebatch.vert", "shaders/gl32spritebatch.frag");
shaderColLUT = loadShaderFromClasspath("shaders/default.vert", "shaders/passthrurgb.frag");
shaderReflect = loadShaderFromClasspath("shaders/default.vert", "shaders/reflect.frag");
shaderGhastlyWhite = loadShaderFromClasspath("shaders/default.vert", "shaders/ghastlywhite.frag");
hq2x = new Hq2x(2);
fullscreenQuad = new Mesh(
true, 4, 6,
@@ -478,97 +485,21 @@ public class App implements ApplicationListener {
VertexAttribute.ColorUnpacked(),
VertexAttribute.TexCoords(0)
);
updateFullscreenQuad(scr.getWidth(), scr.getHeight());
updateFullscreenQuad(fullscreenQuad, scr.getWidth(), scr.getHeight());
// set up renderer info variables
renderer = Gdx.graphics.getGLVersion().getRendererString();
rendererVendor = Gdx.graphics.getGLVersion().getVendorString();
// make gamepad(s)
if (App.getConfigBoolean("usexinput")) {
try {
gamepad = new XinputControllerAdapter(XInputDevice.getDeviceFor(0));
}
catch (Throwable e) {
gamepad = null;
}
// nullify if not actually connected
try {
if (!((XinputControllerAdapter) gamepad).getC().isConnected()) {
gamepad = null;
}
}
catch (NullPointerException notQuiteWindows) {
gamepad = null;
}
}
if (gamepad == null) {
try {
gamepad = new GdxControllerAdapter(Controllers.getControllers().get(0));
}
catch (Throwable e) {
gamepad = null;
}
}
// tell the game that we have a gamepad
environment = RunningEnvironment.PC;
if (gamepad != null) {
String name = gamepad.getName().toLowerCase();
for (String allowedName : gamepadWhitelist) {
if (name.contains(allowedName)) {
environment = RunningEnvironment.CONSOLE;
break;
}
}
}
/*if (gamepad != null) {
environment = RunningEnvironment.CONSOLE;
// calibrate the sticks
printdbg(this, "Calibrating the gamepad...");
float[] axesZeroPoints = new float[]{
gamepad.getAxisRaw(0),
gamepad.getAxisRaw(1),
gamepad.getAxisRaw(2),
gamepad.getAxisRaw(3)
};
setConfig("control_gamepad_axiszeropoints", axesZeroPoints);
for (int i = 0; i < 4; i++) {
printdbg(this, "Axis " + i + ": " + axesZeroPoints[i]);
}
}
else {
environment = RunningEnvironment.PC;
}*/
fontGame = new TerrarumSansBitmap(FONT_DIR, false, false, false,
false,
256, false, 0.5f, false
);
fontUITitle = new TerrarumSansBitmap(FONT_DIR, false, false, false,
false,
64, false, 0.5f, false
);
fontUITitle.setInterchar(2);
fontGameFBO = new TerrarumSansBitmap(FONT_DIR, false, true, false,
false,
64, false, 203f/255f, false
);
Lang.invoke();
// make loading list
CommonResourcePool.INSTANCE.loadAll();
}
private FrameBuffer postProcessorOutFBO;
private FrameBuffer postProcessorOutFBO2;
@Override
public void render() {
@@ -627,30 +558,44 @@ public class App implements ApplicationListener {
FrameBufferManager.end();
// process screenshot request
if (screenshotRequested) {
FrameBufferManager.begin(postProcessorOutFBO);
screenshotRequested = false;
try {
Pixmap p = Pixmap.createFromFrameBuffer(0, 0, scr.getWidth(), scr.getHeight());
PixmapIO.writePNG(Gdx.files.absolute(defaultDir+"/Screenshot-"+String.valueOf(System.currentTimeMillis())+".png"), p, 9, true);
p.dispose();
Terrarum.INSTANCE.getIngame().sendNotification("Screenshot taken");
}
catch (Throwable e) {
e.printStackTrace();
Terrarum.INSTANCE.getIngame().sendNotification("Failed to take screenshot: "+e.getMessage());
}
processScreenshotRequest(postProcessorOutFBO);
if (getConfigString("screenmagnifyingfilter").equals("hq2x") ) {
FrameBufferManager.begin(postProcessorOutFBO2);
shaderPassthruRGBA.bind();
shaderPassthruRGBA.setUniformMatrix("u_projTrans", camera.combined);
shaderPassthruRGBA.setUniformi("u_texture", 0);
hq2x.renderToScreen(postProcessorOutFBO.getColorBufferTexture());
FrameBufferManager.end();
shaderPassthruRGBA.bind();
shaderPassthruRGBA.setUniformMatrix("u_projTrans", camera.combined);
shaderPassthruRGBA.setUniformi("u_texture", 0);
postProcessorOutFBO2.getColorBufferTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
postProcessorOutFBO2.getColorBufferTexture().bind(0);
fullscreenQuad.render(shaderPassthruRGBA, GL20.GL_TRIANGLES);
}
else if (getConfigDouble("screenmagnifying") < 1.01 || getConfigString("screenmagnifyingfilter").equals("none")) {
shaderPassthruRGBA.bind();
shaderPassthruRGBA.setUniformMatrix("u_projTrans", camera.combined);
shaderPassthruRGBA.setUniformi("u_texture", 0);
postProcessorOutFBO.getColorBufferTexture().setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
postProcessorOutFBO.getColorBufferTexture().bind(0);
fullscreenQuad.render(shaderPassthruRGBA, GL20.GL_TRIANGLES);
}
else if (getConfigString("screenmagnifyingfilter").equals("bilinear")) {
shaderPassthruRGBA.bind();
shaderPassthruRGBA.setUniformMatrix("u_projTrans", camera.combined);
shaderPassthruRGBA.setUniformi("u_texture", 0);
postProcessorOutFBO.getColorBufferTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
postProcessorOutFBO.getColorBufferTexture().bind(0);
fullscreenQuad.render(shaderPassthruRGBA, GL20.GL_TRIANGLES);
}
shaderPassthruRGBA.bind();
shaderPassthruRGBA.setUniformMatrix("u_projTrans", camera.combined);
shaderPassthruRGBA.setUniformi("u_texture", 0);
postProcessorOutFBO.getColorBufferTexture().bind(0);
fullscreenQuad.render(shaderPassthruRGBA, GL20.GL_TRIANGLES);
// process resize request
if (resizeRequested) {
@@ -665,6 +610,26 @@ public class App implements ApplicationListener {
}
private static void processScreenshotRequest(FrameBuffer fb) {
if (screenshotRequested) {
String msg = "Screenshot taken";
FrameBufferManager.begin(fb);
try {
Pixmap p = Pixmap.createFromFrameBuffer(0, 0, fb.getWidth(), fb.getHeight());
PixmapIO.writePNG(Gdx.files.absolute(defaultDir+"/Screenshot-"+String.valueOf(System.currentTimeMillis())+".png"), p, 9, true);
p.dispose();
}
catch (Throwable e) {
e.printStackTrace();
msg = ("Failed to take screenshot: "+e.getMessage());
}
FrameBufferManager.end();
screenshotRequested = false;
Terrarum.INSTANCE.getIngame().sendNotification(msg);
}
}
public static Texture getCurrentDitherTex() {
int hash = 31 + GLOBAL_RENDER_TIMER + 0x165667B1 + GLOBAL_RENDER_TIMER * 0xC2B2AE3D;
hash = Integer.rotateLeft(hash, 17) * 0x27D4EB2F;
@@ -767,12 +732,9 @@ public class App implements ApplicationListener {
@Override
public void resize(int w0, int h0) {
int w = (w0%2==0)?w0:w0+1;
int h = (h0%2==0)?h0:h0+1;
float magn = (float) getConfigDouble("screenmagnifying");
int width = Math.round(w / magn);
int height = Math.round(h / magn);
int width = (int) Math.floor(w0 / magn);
int height = (int) Math.floor(h0 / magn);
printdbg(this, "Resize called: "+width+","+height);
@@ -782,22 +744,27 @@ public class App implements ApplicationListener {
//initViewPort(width, height);
scr.setDimension(width, height, magn, w, h);
scr.setDimension(width, height, magn);
if (currentScreen != null) currentScreen.resize(scr.getWidth(), scr.getHeight());
TerrarumPostProcessor.INSTANCE.resize(scr.getWidth(), scr.getHeight());
updateFullscreenQuad(scr.getWidth(), scr.getHeight());
updateFullscreenQuad(fullscreenQuad, scr.getWidth(), scr.getHeight());
if (renderFBO == null ||
(renderFBO.getWidth() != scr.getWidth() ||
renderFBO.getHeight() != scr.getHeight())
) {
renderFBO = new FloatFrameBuffer(
renderFBO = new Float16FrameBuffer(
scr.getWidth(),
scr.getHeight(),
false
);
postProcessorOutFBO2 = new Float16FrameBuffer(
scr.getWidth() * 2,
scr.getHeight() * 2,
false
);
if (IS_DEVELOPMENT_BUILD) {
@@ -850,12 +817,13 @@ public class App implements ApplicationListener {
shaderColLUT.dispose();
shaderReflect.dispose();
shaderGhastlyWhite.dispose();
hq2x.dispose();
CommonResourcePool.INSTANCE.dispose();
fullscreenQuad.dispose();
logoBatch.dispose();
batch.dispose();
shapeRender.dispose();
// shapeRender.dispose();
fontGame.dispose();
fontGameFBO.dispose();
@@ -948,6 +916,93 @@ public class App implements ApplicationListener {
* Init stuffs which needs GL context
*/
private void postInit() {
CommonResourcePool.INSTANCE.addToLoadingList("blockmarkings_common", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/blocks/block_markings_common.tga"), 16, 16, 0, 0, 0, 0, false, false, false));
CommonResourcePool.INSTANCE.addToLoadingList("blockmarking_actor", () -> new BlockMarkerActor());
CommonResourcePool.INSTANCE.addToLoadingList("loading_circle_64", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/gui/loading_circle_64.tga"), 64, 64, 0, 0, 0, 0, false, false, false));
CommonResourcePool.INSTANCE.addToLoadingList("inline_loading_spinner", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/gui/inline_loading_spinner.tga"), 20, 20, 0, 0, 0, 0, false, false, false));
CommonResourcePool.INSTANCE.addToLoadingList("inventory_category", () -> new TextureRegionPack("./assets/graphics/gui/inventory/category.tga", 20, 20, 0, 0, 0, 0, false, false, false));
CommonResourcePool.INSTANCE.loadAll();
shaderHicolour = loadShaderFromClasspath("shaders/default.vert", "shaders/hicolour.frag");
shaderDebugDiff = loadShaderFromClasspath("shaders/default.vert", "shaders/diff.frag");
shaderColLUT = loadShaderFromClasspath("shaders/default.vert", "shaders/rgbonly.frag");
shaderGhastlyWhite = loadShaderFromClasspath("shaders/default.vert", "shaders/ghastlywhite.frag");
// make gamepad(s)
if (App.getConfigBoolean("usexinput")) {
try {
gamepad = new XinputControllerAdapter(XInputDevice.getDeviceFor(0));
}
catch (Throwable e) {
gamepad = null;
}
// nullify if not actually connected
try {
if (!((XinputControllerAdapter) gamepad).getC().isConnected()) {
gamepad = null;
}
}
catch (NullPointerException notQuiteWindows) {
gamepad = null;
}
}
if (gamepad == null) {
try {
gamepad = new GdxControllerAdapter(Controllers.getControllers().get(0));
}
catch (Throwable e) {
gamepad = null;
}
}
// tell the game that we have a gamepad
environment = RunningEnvironment.PC;
if (gamepad != null) {
String name = gamepad.getName().toLowerCase();
for (String allowedName : gamepadWhitelist) {
if (name.contains(allowedName)) {
environment = RunningEnvironment.CONSOLE;
break;
}
}
}
/*if (gamepad != null) {
environment = RunningEnvironment.CONSOLE;
// calibrate the sticks
printdbg(this, "Calibrating the gamepad...");
float[] axesZeroPoints = new float[]{
gamepad.getAxisRaw(0),
gamepad.getAxisRaw(1),
gamepad.getAxisRaw(2),
gamepad.getAxisRaw(3)
};
setConfig("control_gamepad_axiszeropoints", axesZeroPoints);
for (int i = 0; i < 4; i++) {
printdbg(this, "Axis " + i + ": " + axesZeroPoints[i]);
}
}
else {
environment = RunningEnvironment.PC;
}*/
fontUITitle = new TerrarumSansBitmap(FONT_DIR, false, false, false,
false,
64, false, 0.5f, false
);
fontUITitle.setInterchar(1);
fontGameFBO = new TerrarumSansBitmap(FONT_DIR, false, true, false,
false,
64, false, 203f/255f, false
);
Lang.invoke();
ModMgr.INSTANCE.invoke(); // invoke Module Manager
@@ -1026,14 +1081,14 @@ public class App implements ApplicationListener {
logoBatch.setProjectionMatrix(camera.combined);
}
private void updateFullscreenQuad(int WIDTH, int HEIGHT) { // NOT y-flipped quads!
fullscreenQuad.setVertices(new float[]{
private void updateFullscreenQuad(Mesh mesh, int WIDTH, int HEIGHT) { // NOT y-flipped quads!
mesh.setVertices(new float[]{
0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f, 1f,
WIDTH, 0f, 0f, 1f, 1f, 1f, 1f, 1f, 1f,
WIDTH, HEIGHT, 0f, 1f, 1f, 1f, 1f, 1f, 0f,
0f, HEIGHT, 0f, 1f, 1f, 1f, 1f, 0f, 0f
});
fullscreenQuad.setIndices(new short[]{0, 1, 2, 2, 3, 0});
mesh.setIndices(new short[]{0, 1, 2, 2, 3, 0});
}
public static void setGamepadButtonLabels() {
@@ -1133,6 +1188,11 @@ public class App implements ApplicationListener {
public static RunningEnvironment environment;
/** defaultDir + "/Recycled/Players" */
public static String recycledPlayersDir;
/** defaultDir + "/Recycled/Worlds" */
public static String recycledWorldsDir;
private static void getDefaultDirectory() {
String OS = OSName.toUpperCase();
if (OS.contains("WIN")) {
@@ -1162,6 +1222,8 @@ public class App implements ApplicationListener {
worldsDir = defaultDir + "/Worlds";
configDir = defaultDir + "/config.json";
loadOrderDir = defaultDir + "/LoadOrder.txt";
recycledPlayersDir = defaultDir + "/Recycled/Players";
recycledWorldsDir = defaultDir + "/Recycled/Worlds";
System.out.println(String.format("os.name = %s (with identifier %s)", OSName, operationSystem));
System.out.println(String.format("os.version = %s", OSVersion));
@@ -1171,10 +1233,12 @@ public class App implements ApplicationListener {
private static void createDirs() {
File[] dirs = {
new File(saveDir),
// new File(saveDir),
new File(saveSharedDir),
new File(playersDir),
new File(worldsDir)
new File(worldsDir),
new File(recycledPlayersDir),
new File(recycledWorldsDir),
};
for (File it : dirs) {

View File

@@ -33,9 +33,9 @@ object CommonResourcePool {
addToLoadingList("itemplaceholder_48") {
TextureRegion(Texture("assets/item_kari_48.tga")).also { it.flip(false, false) }
}
addToLoadingList("test_texture") {
/*addToLoadingList("test_texture") {
TextureRegion(Texture("assets/test_texture.tga")).also { it.flip(false, false) }
}
}*/
loadAll()
}

View File

@@ -1,5 +1,6 @@
package net.torvald.terrarum
import com.badlogic.gdx.Gdx
import net.torvald.unicode.BULLET
import net.torvald.unicode.ENDASH
@@ -223,6 +224,22 @@ Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
""").split('\n')
private val javaVersion = System.getProperty("java.version")
private val osName = App.OSName
private val osVersion = App.OSVersion
private val sysArch = App.systemArch
private val processor = App.processor
private val processorVendor = App.processorVendor
private val glinfo = Gdx.graphics.glVersion.debugVersionString
val systeminfo: List<String>; get() = """
JRE Version: $javaVersion
Operation System: $osName $osVersion
Architecture: $sysArch
Processor: $processor ($processorVendor)
GL Info: $glinfo
""".split('\n')
val gpl3: List<String>; get() = """ GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007

View File

@@ -10,6 +10,9 @@ import com.badlogic.gdx.Input
object DefaultConfig {
val hashMap = hashMapOf<String, Any>(
"jvm_xmx" to 4,
"jvm_extra_cmd" to "",
"displayfps" to 0, // 0: no limit, non-zero: limit
"displayfpsidle" to 0, // 0: no limit, non-zero: limit
"displaycolourdepth" to 8,
@@ -19,9 +22,9 @@ object DefaultConfig {
"atlastexsize" to 2048,
"language" to App.getSysLang(),
"notificationshowuptime" to 4096, // 4s
"selecteditemnameshowuptime" to 4096, // 4s
"autosaveinterval" to 262144, // 4m22s
"notificationshowuptime" to 4000, // 4s
"selecteditemnameshowuptime" to 4000, // 4s
"autosaveinterval" to 300000, // 5m
"multithread" to true,
"showhealthmessageonstartup" to true,
@@ -109,6 +112,7 @@ object DefaultConfig {
"inputmethod" to "none",
"screenmagnifying" to 1.0,
"screenmagnifyingfilter" to "none", // "none", "bilinear", "hq2x"
"fx_newlight" to false,
@@ -116,6 +120,12 @@ object DefaultConfig {
"debug_deltat_benchmark_sample_sizes" to 2048,
"mastervolume" to 1.0,
"musicvolume" to 1.0,
"bgmvolume" to 1.0,
"sfxvolume" to 1.0,
// settings regarding debugger
/*"buildingmakerfavs" to arrayOf(

View File

@@ -64,8 +64,8 @@ object GlslTilingTest : ApplicationAdapter() {
val tilesInHorizontal = (Gdx.graphics.width.toFloat() / TILING_SIZE).ceil() + 1f
val tilesInVertical = (Gdx.graphics.height.toFloat() / TILING_SIZE).ceil() + 1f
val tilesInHorizontal = (Gdx.graphics.width.toFloat() / TILING_SIZE).ceilToFloat() + 1f
val tilesInVertical = (Gdx.graphics.height.toFloat() / TILING_SIZE).ceilToFloat() + 1f
tilesQuad = Mesh(
true, 4, 6,
@@ -129,8 +129,8 @@ object GlslTilingTest : ApplicationAdapter() {
Gdx.gl.glEnable(GL20.GL_BLEND)
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA)
val tilesInHorizontal = (Gdx.graphics.width.toFloat() / TILING_SIZE).ceil() + 1f
val tilesInVertical = (Gdx.graphics.height.toFloat() / TILING_SIZE).ceil() + 1f
val tilesInHorizontal = (Gdx.graphics.width.toFloat() / TILING_SIZE).ceilToFloat() + 1f
val tilesInVertical = (Gdx.graphics.height.toFloat() / TILING_SIZE).ceilToFloat() + 1f

View File

@@ -0,0 +1,214 @@
package net.torvald.terrarum
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.graphics.*
import com.badlogic.gdx.graphics.VertexAttributes.Usage
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.badlogic.gdx.graphics.glutils.ShaderProgram
import com.badlogic.gdx.math.Matrix4
import com.badlogic.gdx.utils.Disposable
import com.badlogic.gdx.utils.GdxRuntimeException
/**
* [HQnX](https://en.wikipedia.org/wiki/Pixel-art_scaling_algorithms#hqnx_family)
* upscale algorithm GLSL implementation based on
* [CrossVR](https://github.com/CrossVR/hqx-shader/tree/master/glsl) project.
*/
class Hq2x : Disposable {
companion object {
private const val TEXTURE_HANDLE0 = 0
private const val TEXTURE_HANDLE1 = 1
private const val U_TEXTURE = "u_texture"
private const val U_LUT = "u_lut"
private const val U_TEXTURE_SIZE = "u_textureSize"
}
private val mesh = ViewportQuadMesh(
VertexAttribute(Usage.Position, 2, "a_position"),
VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoord0"))
private val program: ShaderProgram
private val lutTexture: Texture
private val scaleFactor: Int
private var dstBuffer: FrameBuffer? = null
private var dstWidth = 0
private var dstHeight = 0
/** @param scaleFactor should be 2, 3 or 4 value. */
constructor(scaleFactor: Int) {
if (scaleFactor !in 2..4) {
throw GdxRuntimeException("Scale factor should be 2, 3 or 4.")
}
program = compileShader(
Gdx.files.classpath("shaders/hq2x.vert"),
Gdx.files.classpath("shaders/hq2x.frag"),
"")
lutTexture = Texture(Gdx.files.classpath("shaders/hq${scaleFactor}x.png"))
this.scaleFactor = scaleFactor
}
override fun dispose() {
mesh.dispose()
program.dispose()
lutTexture.dispose()
dstBuffer?.dispose()
}
fun rebind() {
program.bind()
program.setUniformi(U_TEXTURE, TEXTURE_HANDLE0)
program.setUniformi(U_LUT, TEXTURE_HANDLE1)
program.setUniformf(U_TEXTURE_SIZE,
dstWidth / scaleFactor.toFloat(),
dstHeight / scaleFactor.toFloat())
}
fun renderToScreen(src: Texture) {
validate(src)
lutTexture.bind(TEXTURE_HANDLE1)
src.bind(TEXTURE_HANDLE0)
src.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
program.bind()
mesh.render(program)
}
fun renderToBuffer(src: Texture): Texture {
validate(src)
validateDstBuffer()
lutTexture.bind(TEXTURE_HANDLE1)
src.bind(TEXTURE_HANDLE0)
src.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
dstBuffer!!.begin()
program.bind()
mesh.render(program)
dstBuffer!!.end()
return dstBuffer!!.colorBufferTexture
}
private fun validate(src: Texture) {
val targetWidth = src.width * scaleFactor
val targetHeight = src.height * scaleFactor
// println("[Hq2x] $targetWidth x $targetHeight")
if (dstWidth != targetWidth || dstHeight != targetHeight) {
dstWidth = targetWidth
dstHeight = targetHeight
rebind()
}
}
private fun validateDstBuffer() {
if (dstBuffer == null || dstBuffer!!.width != dstWidth || dstBuffer!!.height != dstHeight) {
dstBuffer?.dispose()
dstBuffer = FrameBuffer(Pixmap.Format.RGB888, dstWidth, dstHeight, false)
dstBuffer!!.colorBufferTexture.setFilter(
Texture.TextureFilter.Nearest,
Texture.TextureFilter.Nearest)
}
}
}
/**
* Encapsulates a fullscreen quad mesh. Geometry is aligned to the viewport corners.
*
* @author bmanuel
* @author metaphore
*/
private class ViewportQuadMesh : Disposable {
companion object {
private const val VERT_SIZE = 16
private const val X1 = 0
private const val Y1 = 1
private const val U1 = 2
private const val V1 = 3
private const val X2 = 4
private const val Y2 = 5
private const val U2 = 6
private const val V2 = 7
private const val X3 = 8
private const val Y3 = 9
private const val U3 = 10
private const val V3 = 11
private const val X4 = 12
private const val Y4 = 13
private const val U4 = 14
private const val V4 = 15
private val verts: FloatArray
init {
verts = FloatArray(VERT_SIZE)
// Vertex coords
verts[X1] = -1f
verts[Y1] = -1f
verts[X2] = 1f
verts[Y2] = -1f
verts[X3] = 1f
verts[Y3] = 1f
verts[X4] = -1f
verts[Y4] = 1f
// Tex coords
verts[U1] = 0f
verts[V1] = 0f
verts[U2] = 1f
verts[V2] = 0f
verts[U3] = 1f
verts[V3] = 1f
verts[U4] = 0f
verts[V4] = 1f
}
}
private val mesh: Mesh
constructor(vararg attributes: VertexAttribute) {
mesh = Mesh(true, 4, 0, *attributes)
mesh.setVertices(verts)
}
override fun dispose() {
mesh.dispose()
}
/** Renders the quad with the specified shader program. */
fun render(program: ShaderProgram) {
mesh.render(program, GL20.GL_TRIANGLE_FAN, 0, 4)
}
}
private fun compileShader(vertexFile: FileHandle, fragmentFile: FileHandle, defines: String): ShaderProgram {
val sb = StringBuilder()
sb.append("Compiling \"").append(vertexFile.name()).append('/').append(fragmentFile.name()).append('\"')
if (defines.isNotEmpty()) {
sb.append(" w/ (").append(defines.replace("\n", ", ")).append(")")
}
sb.append("...")
Gdx.app.log("HqnxEffect", sb.toString())
val srcVert = vertexFile.readString()
val srcFrag = fragmentFile.readString()
val shader = ShaderProgram(
"$defines\n$srcVert".trimIndent(),
"$defines\n$srcFrag".trimIndent())
if (!shader.isCompiled) {
throw GdxRuntimeException("Shader compilation error: ${vertexFile.name()}/${fragmentFile.name()}\n${shader.log}")
}
return shader
}

View File

@@ -7,6 +7,7 @@ import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.gameactors.Actor
import net.torvald.terrarum.gameactors.ActorID
import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.gameactors.ActorWithBody.Companion.PHYS_EPSILON_DIST
import net.torvald.terrarum.gameactors.BlockMarkerActor
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
import net.torvald.terrarum.gameitems.ItemID
@@ -26,9 +27,12 @@ import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.IOException
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.util.*
import java.util.concurrent.locks.Lock
import java.util.function.Consumer
import kotlin.math.min
/**
* Although the game (as product) can have infinitely many stages/planets/etc., those stages must be manually managed by YOU;
@@ -49,8 +53,8 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
override fun getMax(axis: Int, t: ActorWithBody): Double =
when (axis) {
0 -> t.hitbox.endX
1 -> t.hitbox.endY
0 -> t.hitbox.endX - PHYS_EPSILON_DIST
1 -> t.hitbox.endY - PHYS_EPSILON_DIST
else -> throw IllegalArgumentException("nonexistent axis $axis for ${dimensions}-dimensional object")
}
}
@@ -61,7 +65,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
lateinit var playerDisk: VirtualDisk; internal set
lateinit var worldSavefileName: String; internal set
lateinit var playerSavefileName: String; internal set
var savegameNickname: String = "SplinesReticulated"; internal set
var worldName: String = "SplinesReticulated"; internal set // worldName is stored as a name of the disk
var screenZoom = 1.0f
val ZOOM_MAXIMUM = 4.0f
@@ -201,13 +205,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
actorContainerInactive.forEach { it.dispose() }
world.dispose()
disposables.forEach(Consumer {
try { it.dispose() }
catch (_: NullPointerException) { }
catch (_: IllegalArgumentException) { }
catch (_: GdxRuntimeException) { }
catch (_: ConcurrentModificationException) { }
})
disposables.forEach(Consumer { it.tryDispose() })
}
////////////
@@ -406,6 +404,14 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
return uiTooltip.message
}
open fun requestForceSave(callback: () -> Unit) {
}
open fun saveTheGame(onSuccessful: () -> Unit, onError: (Throwable) -> Unit) {
}
/**
* Copies most recent `save` to `save.1`, leaving `save` for overwriting, previous `save.1` will be copied to `save.2`
*/
@@ -422,25 +428,55 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
// do not overwrite clean .2 with dirty .1
val flags3 = FileInputStream(file3).let { it.skip(49L); val r = it.read(); it.close(); r }
val flags2 = FileInputStream(file2).let { it.skip(49L); val r = it.read(); it.close(); r }
if (!(flags3 == 0 && flags2 != 0) || !file3.exists()) file2.copyTo(file3, true)
if (!(flags3 == 0 && flags2 != 0) || !file3.exists()) Files.move(file2.toPath(), file3.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
} catch (e: NoSuchFileException) {} catch (e: FileNotFoundException) {}
try {
// do not overwrite clean .2 with dirty .1
val flags2 = FileInputStream(file2).let { it.skip(49L); val r = it.read(); it.close(); r }
val flags1 = FileInputStream(file1).let { it.skip(49L); val r = it.read(); it.close(); r }
if (!(flags2 == 0 && flags1 != 0) || !file2.exists()) file1.copyTo(file2, true)
if (!(flags2 == 0 && flags1 != 0) || !file2.exists()) Files.move(file1.toPath(), file2.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
} catch (e: NoSuchFileException) {} catch (e: FileNotFoundException) {}
try {
if (file2.exists() && !file3.exists())
file2.copyTo(file3, true)
Files.move(file2.toPath(), file3.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
if (file1.exists() && !file2.exists())
file1.copyTo(file2, true)
Files.move(file1.toPath(), file2.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
file.copyTo(file1, true)
} catch (e: IOException) {}
}
fun makeSavegameBackupCopyAuto(file0: File): File {
val file1 = File("${file0.absolutePath}.a")
val file2 = File("${file0.absolutePath}.b")
val file3 = File("${file0.absolutePath}.c")
try {
// do not overwrite clean .2 with dirty .1
val flags3 = FileInputStream(file3).let { it.skip(49L); val r = it.read(); it.close(); r }
val flags2 = FileInputStream(file2).let { it.skip(49L); val r = it.read(); it.close(); r }
if (!(flags3 == 0 && flags2 != 0) || !file3.exists()) Files.move(file2.toPath(), file3.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
} catch (e: NoSuchFileException) {} catch (e: FileNotFoundException) {}
try {
// do not overwrite clean .2 with dirty .1
val flags2 = FileInputStream(file2).let { it.skip(49L); val r = it.read(); it.close(); r }
val flags1 = FileInputStream(file1).let { it.skip(49L); val r = it.read(); it.close(); r }
if (!(flags2 == 0 && flags1 != 0) || !file2.exists()) Files.move(file1.toPath(), file2.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
} catch (e: NoSuchFileException) {} catch (e: FileNotFoundException) {}
try {
if (file2.exists() && !file3.exists())
Files.move(file2.toPath(), file3.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
if (file1.exists() && !file2.exists())
Files.move(file1.toPath(), file2.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
file0.copyTo(file1, true)
} catch (e: IOException) {}
return file1
}
// simple euclidean norm, squared
private val actorDistanceCalculator = DistanceCalculator<ActorWithBody> { t: ActorWithBody, p: PointND ->
@@ -449,7 +485,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
val dist2 = (p.getOrd(0) - (t.hitbox.centeredX - world.width * TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr()
val dist3 = (p.getOrd(0) - (t.hitbox.centeredX + world.width * TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr()
minOf(dist1, minOf(dist2, dist3))
min(min(dist1, dist2), dist3)
}
/**
@@ -467,7 +503,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
fun getActorsAt(worldX: Double, worldY: Double): List<ActorWithBody> {
val outList = ArrayList<ActorWithBody>()
try {
actorsRTree.find(worldX, worldY, worldX + 1.0, worldY + 1.0, outList)
actorsRTree.find(worldX, worldY, worldX, worldY, outList)
}
catch (e: NullPointerException) {}
return outList

View File

@@ -4,6 +4,7 @@ import com.badlogic.gdx.Gdx
import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.utils.JsonValue
import net.torvald.terrarum.App.*
import net.torvald.terrarum.App.setToGameConfig
import net.torvald.terrarum.blockproperties.BlockCodex
import net.torvald.terrarum.blockproperties.WireCodex
import net.torvald.terrarum.gameitems.GameItem

View File

@@ -1,5 +1,6 @@
package net.torvald.terrarum
import net.torvald.random.XXHash32
import org.dyn4j.geometry.Vector2
/**
@@ -115,6 +116,10 @@ class Point2i() {
return this
}
override fun hashCode(): Int = XXHash32.hashGeoCoord(x, y)
override fun toString() = "Point2i($x, $y)"
operator fun component1() = x
operator fun component2() = y
}

View File

@@ -0,0 +1,346 @@
package net.torvald.terrarum;
import com.badlogic.gdx.utils.JsonValue;
import net.torvald.terrarum.utils.JsonFetcher;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* Bootstrapper that launches the bundled JVM and injects VM configs such as -Xmx
*
* Created by minjaesong on 2023-06-22.
*/
public class Principii {
private static KVHashMap gameConfig = new KVHashMap();
private static String OSName = System.getProperty("os.name");
private static String operationSystem;
/** %appdata%/Terrarum, without trailing slash */
private static String defaultDir;
/** defaultDir + "/config.json" */
private static String configDir;
public static void getDefaultDirRoot() {
String OS = OSName.toUpperCase();
if (OS.contains("WIN")) {
operationSystem = "WINDOWS";
defaultDir = System.getenv("APPDATA") + "/Terrarum";
}
else if (OS.contains("OS X") || OS.contains("MACOS")) { // OpenJDK for mac will still report "Mac OS X" with version number "10.16", even on Big Sur and beyond
operationSystem = "OSX";
defaultDir = System.getProperty("user.home") + "/Library/Application Support/Terrarum";
}
else if (OS.contains("NUX") || OS.contains("NIX") || OS.contains("BSD")) {
operationSystem = "LINUX";
defaultDir = System.getProperty("user.home") + "/.Terrarum";
}
else if (OS.contains("SUNOS")) {
operationSystem = "SOLARIS";
defaultDir = System.getProperty("user.home") + "/.Terrarum";
}
else {
operationSystem = "UNKNOWN";
defaultDir = System.getProperty("user.home") + "/.Terrarum";
}
}
public static void main(String[] args) {
boolean devMode = false;
// if -ea flag is set, turn on all the debug prints
try {
assert false;
}
catch (AssertionError e) {
devMode = true;
}
String extracmd0 = devMode ? " -ea" : "";
String OS = OSName.toUpperCase();
String CPUARCH = System.getProperty("os.arch").toUpperCase();
String runtimeRoot;
String runtimeArch;
if (!CPUARCH.equals("AMD64") && !CPUARCH.equals("X86_64") && !CPUARCH.equals("AARCH64")) { // macOS Rosetta2 reports X86_64
System.err.println("Unsupported CPU architecture: " + CPUARCH);
System.exit(1);
return;
}
else {
runtimeArch = (CPUARCH.equals("AMD64") || CPUARCH.equals("X86_64")) ? "x86" : "arm";
}
if (OS.contains("WIN")) {
runtimeRoot = "runtime-windows-" + runtimeArch;
}
else if (OS.contains("OS X") || OS.contains("MACOS")) { // OpenJDK for mac will still report "Mac OS X" with version number "10.16", even on Big Sur and beyond
runtimeRoot = "runtime-osx-" + runtimeArch;
extracmd0 += " -XstartOnFirstThread";
}
else {
runtimeRoot = "runtime-linux-" + runtimeArch;
extracmd0 += " -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd";
}
String runtime = new File("out/"+runtimeRoot+"/bin/Terrarum").getAbsolutePath(); // /bin/Terrarum is just a renamed version of /bin/java
System.out.println("Runtime path: "+runtime);
getDefaultDirRoot();
configDir = defaultDir + "/config.json";
initialiseConfig();
readConfigJson();
int xmx = getConfigInt("jvm_xmx");
String userDefinedExtraCmd0 = getConfigString("jvm_extra_cmd").trim();
if (!userDefinedExtraCmd0.isEmpty()) userDefinedExtraCmd0 = " "+userDefinedExtraCmd0;
// String[] cmd = (runtime+extracmd0+userDefinedExtraCmd0+" -Xms1G -Xmx"+xmx+"G -cp ./out/TerrarumBuild.jar net.torvald.terrarum.App").split(" ");
List<String> extracmds = Arrays.stream(extracmd0.split(" ")).toList();
List<String> userDefinedExtraCmds = Arrays.stream(userDefinedExtraCmd0.split(" +")).filter((it) -> !it.isBlank()).toList();
ArrayList<String> cmd0 = new ArrayList<>();
cmd0.add(runtime);
cmd0.addAll(extracmds);
cmd0.addAll(userDefinedExtraCmds);
cmd0.add("-Xms1G");
cmd0.add("-Xmx"+xmx+"G");
cmd0.add("-cp");
cmd0.add("./out/TerrarumBuild.jar");
cmd0.add("net.torvald.terrarum.App");
var cmd = cmd0.stream().filter((it) -> !it.isBlank()).toList();
System.out.println(cmd);
try {
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.inheritIO();
System.exit(pb.start().waitFor());
}
catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
// CONFIG //
/**
* Return config from config set. If the config does not exist, default value will be returned.
* @param key
* *
* @return Config from config set or default config if it does not exist.
* *
* @throws NullPointerException if the specified config simply does not exist.
*/
private static int getConfigInt(String key) {
Object cfg = getConfigMaster(key);
if (cfg instanceof Integer) return ((int) cfg);
double value = (double) cfg;
if (Math.abs(value % 1.0) < 0.00000001)
return (int) Math.round(value);
return ((int) cfg);
}
/**
* Return config from config set. If the config does not exist, default value will be returned.
* @param key
* *
* @return Config from config set or default config if it does not exist.
* *
* @throws NullPointerException if the specified config simply does not exist.
*/
private static double getConfigDouble(String key) {
Object cfg = getConfigMaster(key);
return (cfg instanceof Integer) ? (((Integer) cfg) * 1.0) : ((double) (cfg));
}
/**
* Return config from config set. If the config does not exist, default value will be returned.
* @param key
* *
* @return Config from config set or default config if it does not exist.
* *
* @throws NullPointerException if the specified config simply does not exist.
*/
private static String getConfigString(String key) {
Object cfg = getConfigMaster(key);
return ((String) cfg);
}
/**
* Return config from config set. If the config does not exist, default value will be returned.
* @param key
* *
* @return Config from config set or default config if it does not exist. If the default value is undefined, will return false.
*/
private static boolean getConfigBoolean(String key) {
try {
Object cfg = getConfigMaster(key);
return ((boolean) cfg);
}
catch (NullPointerException keyNotFound) {
return false;
}
}
/*private static int[] getConfigIntArray(String key) {
Object cfg = getConfigMaster(key);
if (cfg instanceof JsonArray) {
JsonArray jsonArray = ((JsonArray) cfg).getAsJsonArray();
//return IntArray(jsonArray.size(), { i -> jsonArray[i].asInt })
int[] intArray = new int[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
intArray[i] = jsonArray.get(i).getAsInt();
}
return intArray;
}
else
return ((int[]) cfg);
}*/
private static double[] getConfigDoubleArray(String key) {
Object cfg = getConfigMaster(key);
return ((double[]) cfg);
}
private static int[] getConfigIntArray(String key) {
double[] a = getConfigDoubleArray(key);
int[] r = new int[a.length];
for (int i = 0; i < a.length; i++) {
r[i] = ((int) a[i]);
}
return r;
}
/*private static String[] getConfigStringArray(String key) {
Object cfg = getConfigMaster(key);
if (cfg instanceof JsonArray) {
JsonArray jsonArray = ((JsonArray) cfg).getAsJsonArray();
//return IntArray(jsonArray.size(), { i -> jsonArray[i].asInt })
String[] intArray = new String[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
intArray[i] = jsonArray.get(i).getAsString();
}
return intArray;
}
else
return ((String[]) cfg);
}*/
/**
* Get config from config file. If the entry does not exist, get from defaults; if the entry is not in the default, NullPointerException will be thrown
*/
private static HashMap<String, Object> getDefaultConfig() {
return DefaultConfig.INSTANCE.getHashMap();
}
private static Object getConfigMaster(String key1) {
String key = key1.toLowerCase();
Object config;
try {
config = gameConfig.get(key);
}
catch (NullPointerException e) {
config = null;
}
Object defaults;
try {
defaults = getDefaultConfig().get(key);
}
catch (NullPointerException e) {
defaults = null;
}
if (config == null) {
if (defaults == null) {
throw new NullPointerException("key not found: '" + key + "'");
}
else {
return defaults;
}
}
else {
return config;
}
}
/**
*
* @return true on successful, false on failure.
*/
private static Boolean readConfigJson() {
System.out.println("Config file: " + configDir);
try {
// read from disk and build config from it
JsonValue map = JsonFetcher.INSTANCE.invoke(configDir);
// make config
for (JsonValue entry = map.child; entry != null; entry = entry.next) {
setToGameConfigForced(entry, null);
}
return true;
}
catch (IOException e) {
// write default config to game dir. Call th.is method again to read config from it.
e.printStackTrace();
return false;
}
}
/**
* Reads DefaultConfig to populate the gameConfig
*/
private static void initialiseConfig() {
for (Map.Entry<String, Object> entry : DefaultConfig.INSTANCE.getHashMap().entrySet()) {
gameConfig.set(entry.getKey(), entry.getValue());
}
}
/**
* Will forcibly overwrite previously loaded config value.
*
* Key naming convention will be 'modName:propertyName'; if modName is null, the key will be just propertyName.
*
* @param value JsonValue (the key-value pair)
* @param modName module name, nullable
*/
private static void setToGameConfigForced(JsonValue value, String modName) {
gameConfig.set((modName == null) ? value.name : modName+":"+value.name,
value.isArray() ? value.asDoubleArray() :
value.isDouble() ? value.asDouble() :
value.isBoolean() ? value.asBoolean() :
value.isLong() ? value.asInt() :
value.asString()
);
}
}

View File

@@ -1,4 +1,4 @@
package net.torvald.terrarum.modulebasegame
package net.torvald.terrarum
import net.torvald.random.HQRNG
import java.util.*

View File

@@ -9,6 +9,7 @@ import com.jme3.math.FastMath
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.ui.Toolkit
import kotlin.math.max
/**
* Created by minjaesong on 2017-07-13.
@@ -46,7 +47,7 @@ object SanicLoadScreen : LoadScreenBase() {
textFbo = FrameBuffer(
Pixmap.Format.RGBA4444,
maxOf(
max(
App.fontGame.getWidth(Lang["MENU_IO_LOADING"]),
App.fontGame.getWidth(Lang["ERROR_GENERIC_TEXT"])
),
@@ -61,7 +62,7 @@ object SanicLoadScreen : LoadScreenBase() {
}
val textX: Float; get() = (App.scr.width * 0.72f).floor()
val textX: Float; get() = (App.scr.width * 0.72f).floorToFloat()
private var genuineSonic = false // the "NOW LOADING..." won't appear unless the arrow first run passes it

View File

@@ -0,0 +1,348 @@
package net.torvald.terrarum
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.TextureRegion
import com.badlogic.gdx.utils.JsonWriter
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.savegame.*
import net.torvald.terrarum.savegame.VDFileID.PLAYER_SCREENSHOT
import net.torvald.terrarum.savegame.VDFileID.ROOT
import net.torvald.terrarum.savegame.VDFileID.SAVEGAMEINFO
import net.torvald.terrarum.savegame.VDFileID.WORLD_SCREENSHOT
import net.torvald.terrarum.serialise.Common
import net.torvald.terrarum.utils.JsonFetcher
import net.torvald.terrarum.utils.forEachSiblings
import java.io.File
import java.io.IOException
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.util.*
import java.util.zip.GZIPInputStream
import kotlin.io.path.Path
import kotlin.math.roundToInt
/**
* Created by minjaesong on 2023-06-24.
*/
class SavegameCollection(files0: List<DiskSkimmer>) {
/** Sorted in reverse by the last modified time of the files, index zero being the most recent */
val files = files0.sortedBy { it.diskFile.name }.sortedByDescending {
it.getLastModifiedTime().shl(2) or
it.diskFile.extension.matches(Regex("^[abc]${'$'}")).toLong(1) or
it.diskFile.extension.isBlank().toLong(0)
}
/** Sorted in reverse by the last modified time of the files, index zero being the most recent */
val autoSaves = files.filter { it.diskFile.extension.matches(Regex("[a-z]")) }
/** Sorted in reverse by the last modified time of the files, index zero being the most recent */
val manualSaves = files.filter { !it.diskFile.extension.matches(Regex("[a-z]")) }
init {
files.forEach { it.rebuild() }
}
companion object {
fun collectFromBaseFilename(basedir: File, name: String): SavegameCollection {
val files = basedir.listFiles().filter { it.name.startsWith(name) }
.mapNotNull { try { DiskSkimmer(it, true) } catch (e: Throwable) { null } }
return SavegameCollection(files)
}
}
/**
* Returns the most recent not-corrupted file
*/
fun loadable(): DiskSkimmer {
return files.first()
}
fun moveToRecycle(basedir: String) {
files.forEach {
try {
Files.move(it.diskFile.toPath(), Path(basedir, it.diskFile.name), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
}
catch (e: IOException) {
e.printStackTrace()
}
}
}
fun getBaseFile(): DiskSkimmer {
return files.first { it.diskFile.extension.isBlank() }
}
fun getUUID(): UUID {
var uuid: UUID? = null
loadable().getFile(SAVEGAMEINFO)!!.let {
JsonFetcher.readFromJsonString(ByteArray64Reader(it.bytes, Common.CHARSET)).forEachSiblings { name, value ->
if (name == "worldIndex" || name == "uuid") uuid = UUID.fromString(value.asString())
}
}
return uuid!!
}
fun renamePlayer(name: String) {
files.forEach { skimmer ->
skimmer.rebuild()
skimmer.getFile(SAVEGAMEINFO)!!.let { file ->
val json = JsonFetcher.readFromJsonString(ByteArray64Reader(file.bytes, Common.CHARSET))
json["actorValue"]["hashMap"]["name"]["value"].set(name) // getChild() does NOT work as [] does
val jsonBytes = json.prettyPrint(JsonWriter.OutputType.json, 0).encodeToByteArray().toByteArray64()
val newEntry = DiskEntry(SAVEGAMEINFO, ROOT, skimmer.requestFile(SAVEGAMEINFO)!!.creationDate, App.getTIME_T(), EntryFile(jsonBytes))
skimmer.appendEntry(newEntry)
skimmer.setDiskName(name, Common.CHARSET)
}
}
}
fun renameWorld(name: String) {
files.forEach { skimmer ->
skimmer.setDiskName(name, Common.CHARSET)
}
}
fun getThumbnail(width: Int, height: Int, shrinkage: Double) = this.loadable().getThumbnail(width, height, shrinkage)
}
fun DiskSkimmer.getTgaGz(vid: EntryID, width: Int, height: Int, shrinkage: Double): TextureRegion? {
return this.requestFile(vid).let { file ->
if (file != null) {
val zippedTga = (file.contents as EntryFile).bytes
val gzin = GZIPInputStream(ByteArray64InputStream(zippedTga))
val tgaFileContents = gzin.readAllBytes(); gzin.close()
val pixmap = Pixmap(tgaFileContents, 0, tgaFileContents.size)
TextureRegion(Texture(pixmap)).also {
App.disposables.add(it.texture)
// do cropping and resizing
it.setRegion(
((pixmap.width - width*2) / shrinkage).roundToInt(),
((pixmap.height - height*2) / shrinkage).roundToInt(),
(width * shrinkage).roundToInt(),
(height * shrinkage).roundToInt()
)
}
}
else {
null
}
}
}
fun DiskSkimmer.getTgaGzPixmap(vid: EntryID, width: Int, height: Int, shrinkage: Double): Pixmap? {
return this.requestFile(vid).let { file ->
if (file != null) {
val zippedTga = (file.contents as EntryFile).bytes
val gzin = GZIPInputStream(ByteArray64InputStream(zippedTga))
val tgaFileContents = gzin.readAllBytes(); gzin.close()
val pixmap = Pixmap(tgaFileContents, 0, tgaFileContents.size)
return pixmap
}
else {
null
}
}
}
fun DiskSkimmer.getThumbnail(width: Int, height: Int, shrinkage: Double) =
when (this.getSaveKind()) {
1 -> this.getTgaGz(PLAYER_SCREENSHOT, width, height, shrinkage)
2 -> this.getTgaGz(WORLD_SCREENSHOT, width, height, shrinkage)
else -> throw IllegalArgumentException("Unknown save kind: ${this.getSaveKind()}")
}
fun DiskSkimmer.getThumbnailPixmap(width: Int, height: Int, shrinkage: Double) =
when (this.getSaveKind()) {
1 -> this.getTgaGzPixmap(PLAYER_SCREENSHOT, width, height, shrinkage)
2 -> this.getTgaGzPixmap(WORLD_SCREENSHOT, width, height, shrinkage)
else -> throw IllegalArgumentException("Unknown save kind: ${this.getSaveKind()}")
}
class SavegameCollectionPair(private val player: SavegameCollection?, private val world: SavegameCollection?) {
// private var manualPlayer: DiskSkimmer? = null
// private var manualWorld: DiskSkimmer? = null
// private var autoPlayer: DiskSkimmer? = null
// private var autoWorld: DiskSkimmer? = null
/* removing auto/manual discrimination: on Local Asynchronous Multiplayer, if newer autosave is available, there is
* no choice but loading one to preserve the data; then why bother having two? */
private var playerDisk: DiskSkimmer? = null; private set
private var worldDisk: DiskSkimmer? = null; private set
var status = 0 // 0: none available, 1: loadable manual save is newer than loadable auto; 2: loadable autosave is newer than loadable manual
private set
val newerSaveIsDamaged: Boolean // only when most recent save is corrupted
init {
if (player != null && world != null) {
printdbg(this, "player files: " + player.files.joinToString { it.diskFile.name })
printdbg(this, "world files:" + world.files.joinToString { it.diskFile.name })
var pc = 0
var wc = 0
playerDisk = player.files[pc]
worldDisk = world.files[wc]
while (pc < player.files.size && wc < world.files.size) {
// 0b pw
val dmgflag = playerDiskNotDamaged(playerDisk!!).toInt(1) or worldDiskNotDamaged(worldDisk!!).toInt()
when (dmgflag) {
3 -> break
2 -> {
worldDisk = world.files[++wc]
}
1 -> {
playerDisk = player.files[++pc]
}
0 -> {
worldDisk = world.files[++wc]
playerDisk = player.files[++pc]
}
}
// if it's time to exit the loop and all tested saves were damaged:
if (pc == player.files.size) playerDisk = null
if (wc == world.files.size) worldDisk = null
}
newerSaveIsDamaged = (pc + wc > 0)
}
else {
newerSaveIsDamaged = false
}
status = if (playerDisk != null && worldDisk != null && (playerDisk!!.isAutosaved() || worldDisk!!.isAutosaved()))
2
else (player != null && world != null).toInt()
printdbg(this, "playerDisk = ${playerDisk?.diskFile?.path}")
printdbg(this, "worldDisk = ${worldDisk?.diskFile?.path}")
printdbg(this, "status = $status")
}
/*init {
printdbg(this, "init ($player, $world)")
if (player != null && world != null) {
printdbg(this, "player files: " + player.files.joinToString { it.diskFile.name })
printdbg(this, "world files:" + world.files.joinToString { it.diskFile.name })
// if a pair of files were saved successfully, they must have identical lastModifiedTime()
var pc = 0; val pt = player.files[0].getLastModifiedTime()
var wc = 0; val wt = world.files[0].getLastModifiedTime()
while (pc < player.files.size && wc < world.files.size) {
val pcf = player.files[pc]
val pcm = pcf.getLastModifiedTime()
val wcf = world.files[wc]
val wcm = wcf.getLastModifiedTime()
printdbg(this, "pc=$pc, wc=$wc, pcm=$pcm, wcm=$wcm")
if (playerDiskNotDamaged(pcf) && worldDiskNotDamaged(wcf)) {
printdbg(this, "pcf.autosaved=${pcf.isAutosaved()}, wcf.autosaved=${wcf.isAutosaved()}")
when (pcf.isAutosaved().toInt(1) or wcf.isAutosaved().toInt()) {
3 -> {
if (autoPlayer == null && autoWorld == null) {
autoPlayer = pcf
autoWorld = wcf
}
pc += 1
wc += 1
}
0 -> {
if (manualPlayer == null && manualWorld == null) {
manualPlayer = pcf
manualWorld = wcf
}
pc += 1
wc += 1
}
else -> {
if (pcm > wcm)
pc += 1
else if (pcm == wcm) {
pc += 1
wc += 1
}
// world is modified after another player playing on the same world but only left an autosave
// there is no choice but loading the autosave in such scenario to preserve the data
else {
wc += 1
}
}
}
}
if (manualPlayer != null && manualWorld != null && autoPlayer != null && autoWorld != null)
break
}
if (manualPlayer != null && manualWorld != null && autoPlayer != null && autoWorld != null) {
status = if (manualPlayer!!.getLastModifiedTime() > autoPlayer!!.getLastModifiedTime()) 1 else 2
}
else if (manualPlayer != null && manualWorld != null || autoPlayer != null && autoWorld != null) {
status = 1
}
else {
status = 0
}
printdbg(this, "manualPlayer = ${manualPlayer?.diskFile?.path}")
printdbg(this, "manualWorld = ${manualWorld?.diskFile?.path}")
printdbg(this, "autoPlayer = ${autoPlayer?.diskFile?.path}")
printdbg(this, "autoWorld = ${autoWorld?.diskFile?.path}")
printdbg(this, "status = $status")
}
} */
private fun DiskSkimmer.isAutosaved() = this.getSaveMode().and(0b0000_0010) != 0
private fun playerDiskNotDamaged(disk: DiskSkimmer): Boolean {
return true
}
private fun worldDiskNotDamaged(disk: DiskSkimmer): Boolean {
return true
}
fun moreRecentAutosaveAvailable() = (status == 2)
fun saveAvaliable() = (status > 0)
/*fun getManualSave(): DiskPair? {
if (status == 0) return null
return DiskPair(manualPlayer!!, manualWorld!!)
}
fun getAutoSave(): DiskPair? {
if (status != 2) return null
return DiskPair(autoPlayer!!, autoWorld!!)
}
fun getLoadableSave(): DiskPair? {
if (status == 0) return null
return if (manualPlayer != null && manualWorld != null)
DiskPair(manualPlayer!!, manualWorld!!)
else
DiskPair(autoPlayer!!, autoWorld!!)
}*/
fun getLoadableSave(): DiskPair? {
return if (status == 0) null
else DiskPair(playerDisk!!, worldDisk!!)
}
}
data class DiskPair(val player: DiskSkimmer, val world: DiskSkimmer) {
}

View File

@@ -10,7 +10,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.badlogic.gdx.graphics.glutils.ShapeRenderer
import com.badlogic.gdx.utils.Disposable
import com.badlogic.gdx.utils.JsonReader
import com.badlogic.gdx.utils.GdxRuntimeException
import com.jme3.math.FastMath
import net.torvald.gdx.graphics.Cvec
import net.torvald.random.HQRNG
@@ -26,9 +26,7 @@ import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.itemproperties.CraftingCodex
import net.torvald.terrarum.itemproperties.ItemCodex
import net.torvald.terrarum.itemproperties.MaterialCodex
import net.torvald.terrarum.savegame.ByteArray64Reader
import net.torvald.terrarum.savegame.DiskSkimmer
import net.torvald.terrarum.savegame.VDFileID.SAVEGAMEINFO
import net.torvald.terrarum.serialise.Common
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarum.worlddrawer.WorldCamera
@@ -38,10 +36,7 @@ import net.torvald.util.CircularArray
import java.io.File
import java.io.PrintStream
import java.util.*
import kotlin.math.absoluteValue
import kotlin.math.round
import kotlin.math.roundToInt
import kotlin.math.*
typealias RGBA8888 = Int
@@ -62,11 +57,11 @@ object Terrarum : Disposable {
*/
const val PLAYER_REF_ID: Int = 0x91A7E2
inline fun inShapeRenderer(shapeRendererType: ShapeRenderer.ShapeType = ShapeRenderer.ShapeType.Filled, action: (ShapeRenderer) -> Unit) {
/*inline fun inShapeRenderer(shapeRendererType: ShapeRenderer.ShapeType = ShapeRenderer.ShapeType.Filled, action: (ShapeRenderer) -> Unit) {
shapeRender.begin(shapeRendererType)
action(shapeRender)
shapeRender.end()
}
}*/
var blockCodex = BlockCodex(); internal set
@@ -236,16 +231,16 @@ object Terrarum : Disposable {
get() = WorldCamera.zoomedY + (Gdx.input.y - Gdx.input.deltaY) / (ingame?.screenZoom ?: 1f).times(scr.magn.toDouble())
/** Position of the cursor in the world, rounded */
@JvmStatic val mouseTileX: Int
get() = (mouseX / TILE_SIZE).floorInt()
get() = (mouseX / TILE_SIZE).floorToInt()
/** Position of the cursor in the world */
@JvmStatic val mouseTileY: Int
get() = (mouseY / TILE_SIZE).floorInt()
get() = (mouseY / TILE_SIZE).floorToInt()
/** Position of the cursor in the world, rounded */
@JvmStatic val oldMouseTileX: Int
get() = (oldMouseX / TILE_SIZE).floorInt()
get() = (oldMouseX / TILE_SIZE).floorToInt()
/** Position of the cursor in the world */
@JvmStatic val oldMouseTileY: Int
get() = (oldMouseY / TILE_SIZE).floorInt()
get() = (oldMouseY / TILE_SIZE).floorToInt()
inline val mouseScreenX: Int
get() = Gdx.input.x.div(scr.magn).roundToInt()
inline val mouseScreenY: Int
@@ -319,8 +314,8 @@ object Terrarum : Disposable {
val mx = mouseX
val my = mouseY
val mtx = (mouseX / TILE_SIZE).floorInt()
val mty = (mouseY / TILE_SIZE).floorInt()
val mtx = (mouseX / TILE_SIZE).floorToInt()
val mty = (mouseY / TILE_SIZE).floorToInt()
val msx = mx fmod TILE_SIZED
val msy = my fmod TILE_SIZED
val vector = if (msx < SMALLGAP) { // X to the left
@@ -397,8 +392,10 @@ inline fun FrameBuffer.inAction(camera: OrthographicCamera?, batch: SpriteBatch?
//this.begin()
FrameBufferManager.begin(this)
val oldCamPos = camera?.position?.cpy()
camera?.setToOrtho(true, this.width.toFloat(), this.height.toFloat())
camera?.position?.set((this.width / 2f).round(), (this.height / 2f).round(), 0f) // TODO floor? ceil? round?
camera?.position?.set((this.width / 2f).roundToFloat(), (this.height / 2f).roundToFloat(), 0f) // TODO floor? ceil? round?
camera?.update()
batch?.projectionMatrix = camera?.combined
@@ -408,6 +405,7 @@ inline fun FrameBuffer.inAction(camera: OrthographicCamera?, batch: SpriteBatch?
FrameBufferManager.end()
camera?.setToOrtho(true, App.scr.wf, App.scr.hf)
camera?.position?.set(oldCamPos)
camera?.update()
batch?.projectionMatrix = camera?.combined
}
@@ -419,8 +417,10 @@ inline fun FrameBuffer.inActionF(camera: OrthographicCamera?, batch: SpriteBatch
//this.begin()
FrameBufferManager.begin(this)
val oldCamPos = camera?.position?.cpy()
camera?.setToOrtho(false, this.width.toFloat(), this.height.toFloat())
camera?.position?.set((this.width / 2f).round(), (this.height / 2f).round(), 0f) // TODO floor? ceil? round?
camera?.position?.set((this.width / 2f).roundToFloat(), (this.height / 2f).roundToFloat(), 0f) // TODO floor? ceil? round?
camera?.update()
batch?.projectionMatrix = camera?.combined
@@ -430,6 +430,7 @@ inline fun FrameBuffer.inActionF(camera: OrthographicCamera?, batch: SpriteBatch
FrameBufferManager.end()
camera?.setToOrtho(true, App.scr.wf, App.scr.hf)
camera?.position?.set(oldCamPos)
camera?.update()
batch?.projectionMatrix = camera?.combined
}
@@ -609,27 +610,28 @@ val emphVerb = TerrarumSansBitmap.toColorCode(0xFFF6)
typealias Second = Float
fun Int.sqr(): Int = this * this
fun Double.floorInt() = Math.floor(this).toInt()
fun Float.floorInt() = FastMath.floor(this)
fun Float.floor() = FastMath.floor(this).toFloat()
fun Double.ceilInt() = Math.ceil(this).toInt()
fun Float.ceil(): Float = FastMath.ceil(this).toFloat()
fun Float.ceilInt() = FastMath.ceil(this)
fun Float.round(): Float = round(this)
fun Double.round() = Math.round(this).toDouble()
fun Double.floor() = Math.floor(this)
fun Double.ceil() = this.floor() + 1.0
fun Double.abs() = Math.abs(this)
fun Double.sqr() = this * this
fun Float.sqr() = this * this
fun Double.sqrt() = Math.sqrt(this)
fun Float.sqrt() = FastMath.sqrt(this)
fun Int.abs() = this.absoluteValue
fun Double.bipolarClamp(limit: Double) = this.coerceIn(-limit, limit)
fun Boolean.toInt(shift: Int = 0) = if (this) 1.shl(shift) else 0
fun Int.bitCount() = java.lang.Integer.bitCount(this)
fun Long.bitCount() = java.lang.Long.bitCount(this)
inline fun Double.floorToInt() = floor(this).toInt()
inline fun Float.floorToInt() = FastMath.floor(this)
inline fun Double.ceilToInt() = Math.ceil(this).toInt()
inline fun Float.ceilToFloat(): Float = FastMath.ceil(this).toFloat()
inline fun Float.ceilToInt() = FastMath.ceil(this)
inline fun Float.floorToFloat() = FastMath.floor(this).toFloat()
inline fun Float.roundToFloat(): Float = round(this)
//inline fun Double.round() = Math.round(this).toDouble()
inline fun Double.floorToDouble() = floor(this)
inline fun Double.ceilToDouble() = ceil(this)
inline fun Int.sqr(): Int = this * this
inline fun Double.sqr() = this * this
inline fun Float.sqr() = this * this
inline fun Double.sqrt() = Math.sqrt(this)
inline fun Float.sqrt() = FastMath.sqrt(this)
inline fun Int.abs() = this.absoluteValue
inline fun Double.abs() = this.absoluteValue
inline fun Double.bipolarClamp(limit: Double) = this.coerceIn(-limit, limit)
inline fun Boolean.toInt(shift: Int = 0) = if (this) 1.shl(shift) else 0
inline fun Boolean.toLong(shift: Int = 0) = if (this) 1L.shl(shift) else 0L
inline fun Int.bitCount() = java.lang.Integer.bitCount(this)
inline fun Long.bitCount() = java.lang.Long.bitCount(this)
fun absMax(left: Double, right: Double): Double {
@@ -648,7 +650,6 @@ fun absMax(left: Double, right: Double): Double {
}
fun Double.magnSqr() = if (this >= 0.0) this.sqr() else -this.sqr()
fun Double.sign() = if (this > 0.0) 1.0 else if (this < 0.0) -1.0 else 0.0
fun interpolateLinear(scale: Double, startValue: Double, endValue: Double): Double {
if (startValue == endValue) {
return startValue
@@ -785,6 +786,7 @@ fun AppUpdateListOfSavegames() {
println("Listing saved worlds...")
// create list of worlds
File(worldsDir).listFiles().filter { !it.isDirectory && !it.name.contains('.') }.mapNotNull { file ->
try {
@@ -797,15 +799,20 @@ fun AppUpdateListOfSavegames() {
}
}.sortedByDescending { it.getLastModifiedTime() }.forEachIndexed { index, it ->
println("${index+1}.\t${it.diskFile.absolutePath}")
it.rebuild() // disk skimmer was created without initialisation, so do it now
// it.rebuild()
val jsonFile = it.getFile(SAVEGAMEINFO)!!
val json = JsonReader().parse(ByteArray64Reader(jsonFile.bytes, Common.CHARSET).readText())
val worldUUID = UUID.fromString(json.getString("worldIndex"))
// val jsonFile = it.getFile(SAVEGAMEINFO)!!
// var worldUUID: UUID? = null
// JsonFetcher.readFromJsonString(ByteArray64Reader(jsonFile.bytes, Common.CHARSET)).forEachSiblings { name, value ->
// if (name == "worldIndex") worldUUID = UUID.fromString(value.asString())
// }
val collection = SavegameCollection.collectFromBaseFilename(File(worldsDir), it.diskFile.name)
val worldUUID = collection.getUUID()
// if multiple valid savegames with same UUID exist, only the most recent one is retained
if (!App.savegameWorlds.contains(worldUUID)) {
App.savegameWorlds[worldUUID] = it
App.savegameWorlds[worldUUID] = collection
App.savegameWorldsName[worldUUID] = it.getDiskName(Common.CHARSET)
App.sortedSavegameWorlds.add(worldUUID)
}
@@ -827,20 +834,30 @@ fun AppUpdateListOfSavegames() {
}
}.sortedByDescending { it.getLastModifiedTime() }.forEachIndexed { index, it ->
println("${index+1}.\t${it.diskFile.absolutePath}")
it.rebuild() // disk skimmer was created without initialisation, so do it now
// it.rebuild()
val jsonFile = it.getFile(SAVEGAMEINFO)!!
val json = JsonReader().parse(ByteArray64Reader(jsonFile.bytes, Common.CHARSET).readText())
val playerUUID = UUID.fromString(json.getString("uuid"))
// val jsonFile = it.getFile(SAVEGAMEINFO)!!
// var playerUUID: UUID? = null
// JsonFetcher.readFromJsonString(ByteArray64Reader(jsonFile.bytes, Common.CHARSET)).forEachSiblings { name, value ->
// if (name == "uuid") playerUUID = UUID.fromString(value.asString())
// }
val collection = SavegameCollection.collectFromBaseFilename(File(playersDir), it.diskFile.name)
val playerUUID = collection.getUUID()
// if multiple valid savegames with same UUID exist, only the most recent one is retained
if (!App.savegamePlayers.contains(playerUUID)) {
App.savegamePlayers[playerUUID] = it
App.savegamePlayers[playerUUID] = collection
App.savegamePlayersName[playerUUID] = it.getDiskName(Common.CHARSET)
App.sortedPlayers.add(playerUUID)
}
}
println("SortedPlayers...")
App.sortedPlayers.forEach {
println(it)
}
}
/**
@@ -880,3 +897,11 @@ fun checkForSavegameDamage(skimmer: DiskSkimmer): Boolean {
return true
}
}
/**
* No lateinit!
*/
inline fun Disposable.tryDispose() {
try { this.dispose() }
catch (_: Throwable) {}
}

View File

@@ -31,7 +31,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
const val DEFAULT_LOADORDER_FILE = """# Load Order
# Modules are loaded from top to bottom.
# You can disable basegame, but we don't recommend.
# Name of the module corresponds with the name of the directory the module is stored in,
# typically under:
# 1. assets/mods of the installation path (the modules comes with the release of the game)
# 2. %APPDATA%/Modules (the modules installed by the user)
# where %APPDATA% is:
# Windows -- C:\Users\<username>\AppData\Roaming\Terrarum
# macOS -- /Users/<username>/Library/Application Support/Terrarum
# Linux -- /home/<username>/.Terrarum
# Please refrain from removing 'basegame' on the load order -- it may render the game unpalyable.
basegame
"""
@@ -54,9 +62,12 @@ basegame
* e.g. 0x02010034 will be translated as 2.1.52
*
*/
const val VERSION_RAW: Long = 0x0000_000003_000002
const val VERSION_RAW: Long = 0x0000_000003_000003
// Commit counts up to the Release 0.3.0: 2259
// Commit counts up to the Release 0.3.1: 2278
// Commit counts up to the Release 0.3.2: 2732
const val VERSION_TAG: String = "test001"
//////////////////////////////////////////////////////////
// CONFIGURATION FOR TILE MAKER //

View File

@@ -9,6 +9,7 @@ import com.badlogic.gdx.math.Matrix4
import com.badlogic.gdx.utils.Disposable
import com.jme3.math.FastMath
import net.torvald.random.HQRNG
import net.torvald.terrarum.App.IS_DEVELOPMENT_BUILD
import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.ui.BasicDebugInfoWindow
import net.torvald.terrarum.ui.Toolkit
@@ -63,7 +64,7 @@ object TerrarumPostProcessor : Disposable {
}
fun resize(w: Int, h: Int) {
try { outFBO.dispose() } catch (_: UninitializedPropertyAccessException) {}
if (::outFBO.isInitialized) outFBO.tryDispose()
outFBO = FrameBuffer(Pixmap.Format.RGBA8888, w, h, false)
}
@@ -71,10 +72,10 @@ object TerrarumPostProcessor : Disposable {
batch.dispose()
shapeRenderer.dispose()
functionRowHelper.dispose()
try { lutTex.dispose() } catch (_: UninitializedPropertyAccessException) {}
shaderPostDither.dispose()
shaderPostNoDither.dispose()
outFBO.dispose()
if (::lutTex.isInitialized) lutTex.tryDispose()
if (::outFBO.isInitialized) outFBO.dispose()
}
private var deltatBenchStr = "ΔF: Gathering data"
@@ -150,9 +151,10 @@ object TerrarumPostProcessor : Disposable {
}
// draw dev build notifiers
if (App.IS_DEVELOPMENT_BUILD && Terrarum.ingame != null) {
// omitting this screws up HQ2X render for some reason
if (Terrarum.ingame != null) {
batch.inUse {
batch.color = safeAreaCol
batch.color = if (IS_DEVELOPMENT_BUILD) safeAreaCol else colourNull
App.fontGame.draw(it, thisIsDebugStr, 5f, App.scr.height - 24f)
}
}
@@ -168,11 +170,11 @@ object TerrarumPostProcessor : Disposable {
val average = tallies.average()
val halfPos = 0.5f * INGAME.deltaTeeBenchmarks.size
val halfInd = halfPos.floorInt()
val halfInd = halfPos.floorToInt()
val low5pos = 0.05f * INGAME.deltaTeeBenchmarks.size
val low5ind = low5pos.floorInt()
val low5ind = low5pos.floorToInt()
val low1pos = 0.01f * INGAME.deltaTeeBenchmarks.size
val low1ind = low1pos.floorInt()
val low1ind = low1pos.floorToInt()
val median = FastMath.interpolateLinear(halfPos - halfInd, tallies[halfInd], tallies[halfInd + 1])
val low5 = FastMath.interpolateLinear(low5pos - low5ind, tallies[low5ind], tallies[low5ind + 1])
@@ -192,39 +194,40 @@ object TerrarumPostProcessor : Disposable {
return outFBO
}
private val rng = HQRNG()
private val colourNull = Color(0)
private fun Double.format(digits: Int) = "%.${digits}f".format(this)
private fun Float.format(digits: Int) = "%.${digits}f".format(this)
private val swizzler = intArrayOf(
1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1,
1,0,0,0, 0,1,0,0, 0,0,0,1, 0,0,1,0,
1,0,0,0, 0,0,1,0, 0,1,0,0, 0,0,0,1,
1,0,0,0, 0,0,1,0, 0,0,0,1, 0,1,0,0,
1,0,0,0, 0,0,0,1, 0,1,0,0, 0,0,1,0,
1,0,0,0, 0,0,0,1, 0,0,1,0, 0,1,0,0,
private val swizzler = floatArrayOf(
1f,0f,0f,0f, 0f,1f,0f,0f, 0f,0f,1f,0f, 0f,0f,0f,1f,
1f,0f,0f,0f, 0f,1f,0f,0f, 0f,0f,0f,1f, 0f,0f,1f,0f,
1f,0f,0f,0f, 0f,0f,1f,0f, 0f,1f,0f,0f, 0f,0f,0f,1f,
1f,0f,0f,0f, 0f,0f,1f,0f, 0f,0f,0f,1f, 0f,1f,0f,0f,
1f,0f,0f,0f, 0f,0f,0f,1f, 0f,1f,0f,0f, 0f,0f,1f,0f,
1f,0f,0f,0f, 0f,0f,0f,1f, 0f,0f,1f,0f, 0f,1f,0f,0f,
0,1,0,0, 1,0,0,0, 0,0,1,0, 0,0,0,1,
0,1,0,0, 1,0,0,0, 0,0,0,1, 0,0,1,0,
0,1,0,0, 0,0,1,0, 1,0,0,0, 0,0,0,1,
0,1,0,0, 0,0,1,0, 0,0,0,1, 1,0,0,0,
0,1,0,0, 0,0,0,1, 1,0,0,0, 0,0,1,0,
0,1,0,0, 0,0,0,1, 0,0,1,0, 1,0,0,0,
0f,1f,0f,0f, 1f,0f,0f,0f, 0f,0f,1f,0f, 0f,0f,0f,1f,
0f,1f,0f,0f, 1f,0f,0f,0f, 0f,0f,0f,1f, 0f,0f,1f,0f,
0f,1f,0f,0f, 0f,0f,1f,0f, 1f,0f,0f,0f, 0f,0f,0f,1f,
0f,1f,0f,0f, 0f,0f,1f,0f, 0f,0f,0f,1f, 1f,0f,0f,0f,
0f,1f,0f,0f, 0f,0f,0f,1f, 1f,0f,0f,0f, 0f,0f,1f,0f,
0f,1f,0f,0f, 0f,0f,0f,1f, 0f,0f,1f,0f, 1f,0f,0f,0f,
0,0,1,0, 1,0,0,0, 0,1,0,0, 0,0,0,1,
0,0,1,0, 1,0,0,0, 0,0,0,1, 0,1,0,0,
0,0,1,0, 0,1,0,0, 1,0,0,0, 0,0,0,1,
0,0,1,0, 0,1,0,0, 0,0,0,1, 1,0,0,0,
0,0,1,0, 0,0,0,1, 1,0,0,0, 0,1,0,0,
0,0,1,0, 0,0,0,1, 0,1,0,0, 1,0,0,0,
0f,0f,1f,0f, 1f,0f,0f,0f, 0f,1f,0f,0f, 0f,0f,0f,1f,
0f,0f,1f,0f, 1f,0f,0f,0f, 0f,0f,0f,1f, 0f,1f,0f,0f,
0f,0f,1f,0f, 0f,1f,0f,0f, 1f,0f,0f,0f, 0f,0f,0f,1f,
0f,0f,1f,0f, 0f,1f,0f,0f, 0f,0f,0f,1f, 1f,0f,0f,0f,
0f,0f,1f,0f, 0f,0f,0f,1f, 1f,0f,0f,0f, 0f,1f,0f,0f,
0f,0f,1f,0f, 0f,0f,0f,1f, 0f,1f,0f,0f, 1f,0f,0f,0f,
0,0,0,1, 1,0,0,0, 0,1,0,0, 0,0,1,0,
0,0,0,1, 1,0,0,0, 0,0,1,0, 0,1,0,0,
0,0,0,1, 0,1,0,0, 1,0,0,0, 0,0,1,0,
0,0,0,1, 0,1,0,0, 0,0,1,0, 1,0,0,0,
0,0,0,1, 0,0,1,0, 1,0,0,0, 0,1,0,0,
0,0,0,1, 0,0,1,0, 0,1,0,0, 1,0,0,0,
).map { it.toFloat() }.toFloatArray()
0f,0f,0f,1f, 1f,0f,0f,0f, 0f,1f,0f,0f, 0f,0f,1f,0f,
0f,0f,0f,1f, 1f,0f,0f,0f, 0f,0f,1f,0f, 0f,1f,0f,0f,
0f,0f,0f,1f, 0f,1f,0f,0f, 1f,0f,0f,0f, 0f,0f,1f,0f,
0f,0f,0f,1f, 0f,1f,0f,0f, 0f,0f,1f,0f, 1f,0f,0f,0f,
0f,0f,0f,1f, 0f,0f,1f,0f, 1f,0f,0f,0f, 0f,1f,0f,0f,
0f,0f,0f,1f, 0f,0f,1f,0f, 0f,1f,0f,0f, 1f,0f,0f,0f,
)
private fun postShader(projMat: Matrix4, fbo: FrameBuffer) {

View File

@@ -1,12 +1,13 @@
package net.torvald.terrarum
import net.torvald.terrarum.App.printdbg
import kotlin.math.max
import kotlin.math.roundToInt
class TerrarumScreenSize(scrw: Int = defaultW, scrh: Int = defaultH) {
companion object {
const val minimumW = 1080
const val minimumW = 1024
const val minimumH = 720
const val defaultW = 1280
const val defaultH = 720
@@ -33,14 +34,16 @@ class TerrarumScreenSize(scrw: Int = defaultW, scrh: Int = defaultH) {
val tvSafeActionWidth: Int; get() = Math.round(width * TV_SAFE_ACTION)
val tvSafeActionHeight: Int; get() = Math.round(height * TV_SAFE_ACTION)
/** Apparent window size. `roundToEven(width * magn)` */
var windowW: Int = 0; private set
/** Apparent window size. `roundToEven(height * magn)` */
var windowH: Int = 0; private set
init {
setDimension(maxOf(minimumW, scrw), maxOf(minimumH, scrh), App.getConfigDouble("screenmagnifying").toFloat(), maxOf(minimumW, scrw), maxOf(minimumH, scrh))
setDimension(max(minimumW, scrw), max(minimumH, scrh), App.getConfigDouble("screenmagnifying").toFloat())
}
fun setDimension(scrw: Int, scrh: Int, magn: Float, ww: Int, wh: Int) {
fun setDimension(scrw: Int, scrh: Int, magn: Float,) {
width = scrw and 0x7FFFFFFE
height = scrh and 0x7FFFFFFE
wf = scrw.toFloat()
@@ -54,11 +57,11 @@ class TerrarumScreenSize(scrw: Int = defaultW, scrh: Int = defaultH) {
this.magn = magn
windowW = ww
windowH = wh
windowW = (scrw * magn).ceilToInt() and 0x7FFFFFFE
windowH = (scrh * magn).ceilToInt() and 0x7FFFFFFE
printdbg(this, "Window dim: $ww x $wh, called by:")
printdbg(this, "Window dim: $windowW x $windowH, called by:")
printStackTrace(this)
}

View File

@@ -166,7 +166,7 @@ class UIItemInventoryCatBar(
// set up underlined indicator
init {
// procedurally generate texture
val pixmap = Pixmap(catIcons.tileW + buttonGapSize.floorInt(), 1, Pixmap.Format.RGBA8888)
val pixmap = Pixmap(catIcons.tileW + buttonGapSize.floorToInt(), 1, Pixmap.Format.RGBA8888)
for (x in 0 until pixmap.width.plus(1).ushr(1)) { // eqv. of ceiling the half-int
val col = /*if (x == 0)*/ /*0xffffff_80.toInt()*/
/*else if (x == 1)*/ /*0xffffff_c0.toInt()*/

View File

@@ -209,8 +209,8 @@ class BlockCodex {
prop.isSolid = record.boolVal("solid")
//prop.isClear = record.boolVal("clear")
prop.isPlatform = prop.tags.contains("PLATFORM")
prop.isActorBlock = prop.tags.contains("ACTORBLOCK")
prop.isPlatform = prop.hasTag("PLATFORM")
prop.isActorBlock = prop.hasTag("ACTORBLOCK")
prop.isWallable = record.boolVal("wall")
prop.maxSupport = record.intVal("grav")

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