Compare commits

...

160 Commits

Author SHA1 Message Date
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
236 changed files with 8461 additions and 2437 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

@@ -195,17 +195,10 @@ internal class UIHomeComputer : UICanvas(
}
override fun doOpening(delta: Float) {
super.doOpening(delta)
fixture.startVM()
}
override fun doClosing(delta: Float) {
}
override fun endOpening(delta: Float) {
}
override fun endClosing(delta: Float) {
}
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,40 @@
{
"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_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,36 @@
{
"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_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

@@ -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"
1 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
23 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
24 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
25 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
26 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 SAND,NATURAL,WARM
27 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 SAND,NATURAL,WARM
28 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 SAND,NATURAL,WARM
29 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 SAND,NATURAL,WARM
30 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 SAND,NATURAL,WARM
31 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 SAND,NATURAL,WARM
32 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
33 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
34 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 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
45 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
46 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
47 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 SNOW,NATURAL,COLD
48 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 ICE,NATURAL,FRAGILE,COLD
49 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 ICE,NATURAL,COLD
50 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 ICE,COLD
51 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
52 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
53 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

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

@@ -0,0 +1,31 @@
{
"GAME_ITEM_CALENDAR": "Calendar",
"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_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"
}

View File

@@ -17,7 +17,7 @@
"GAME_ACTION_CRAFT": "Craft",
"GAME_CRAFTING": "Crafting",
"GAME_CRAFTABLE_ITEMS": "Craftable Items",
"CONTEXT_WORLD_SEARCH": "World Search",
"CONTEXT_WORLD_LIST": "Worlds List",
"MENU_LABEL_RENAME": "Rename"
"MENU_LABEL_RENAME": "Rename",
"GAME_ACTION_TELEPORT": "Teleport",
"CONTEXT_PLACE_COORDINATE": "Coordinate"
}

View File

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

View File

@@ -0,0 +1,14 @@
{
"GAME_ITEM_CALENDAR": "달력",
"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": "겨울"
}

View File

@@ -17,5 +17,8 @@
"GAME_ACTION_QUICKSEL": "빠른 선택",
"GAME_ACTION_CRAFT": "제작하기",
"GAME_CRAFTING": "제작",
"GAME_CRAFTABLE_ITEMS": "제작 가능한 아이템"
"GAME_CRAFTABLE_ITEMS": "제작 가능한 아이템",
"MENU_LABEL_RENAME": "이름 바꾸기",
"GAME_ACTION_TELEPORT": "텔레포트하기",
"CONTEXT_PLACE_COORDINATE": "좌표"
}

View File

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

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

@@ -25,11 +25,13 @@ 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/
echo "Build successful: $DESTDIR"

View File

@@ -25,11 +25,13 @@ 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/
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

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

@@ -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;
@@ -142,6 +141,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 +206,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 +239,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;
@@ -346,10 +352,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 +383,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 +392,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 +440,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 +472,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 +482,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 +555,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 +607,24 @@ public class App implements ApplicationListener {
}
private static void processScreenshotRequest(FrameBuffer fb) {
if (screenshotRequested) {
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();
Terrarum.INSTANCE.getIngame().sendNotification("Screenshot taken");
}
catch (Throwable e) {
e.printStackTrace();
Terrarum.INSTANCE.getIngame().sendNotification("Failed to take screenshot: "+e.getMessage());
}
FrameBufferManager.end();
screenshotRequested = false;
}
}
public static Texture getCurrentDitherTex() {
int hash = 31 + GLOBAL_RENDER_TIMER + 0x165667B1 + GLOBAL_RENDER_TIMER * 0xC2B2AE3D;
hash = Integer.rotateLeft(hash, 17) * 0x27D4EB2F;
@@ -767,12 +727,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,11 +739,11 @@ 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 ||
@@ -798,6 +755,11 @@ public class App implements ApplicationListener {
scr.getHeight(),
false
);
postProcessorOutFBO2 = new FloatFrameBuffer(
scr.getWidth() * 2,
scr.getHeight() * 2,
false
);
if (IS_DEVELOPMENT_BUILD) {
@@ -850,12 +812,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 +911,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 +1076,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 +1183,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 +1217,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 +1228,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,10 @@ 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
//////////////////////////////////////////////////////////
// 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

@@ -108,7 +108,7 @@ object BlockPropUtil {
return when (prop.dynamicLuminosityFunction) {
1 -> getTorchFlicker(prop)
2 -> (INGAME.world).globalLight.cpy() // current global light
3 -> WeatherMixer.getGlobalLightOfTime(INGAME.world, WorldTime.DAY_LENGTH / 2).cpy() // daylight at noon
3 -> WeatherMixer.getGlobalLightOfTimeOfNoon().cpy() // daylight at noon
4 -> getSlowBreath(prop)
5 -> getPulsate(prop)
else -> prop.baseLumCol

View File

@@ -151,4 +151,8 @@ class WireCodex {
printdbg(this, "Setting prop ${prop.id} ->>\t${prop.nameKey}")
}
fun getAllWiresThatAccepts(accept: String): List<Pair<ItemID, WireProp>> {
return wireProps.filter { it.value.accepts == accept }.toList()
}
}

View File

@@ -19,11 +19,12 @@ import net.torvald.terrarum.toInt
import java.util.concurrent.Callable
import java.util.concurrent.atomic.AtomicInteger
import kotlin.math.absoluteValue
import kotlin.math.max
import kotlin.math.roundToInt
object MinimapComposer : Disposable {
private val threadExecutor = ThreadExecutor(maxOf(1, App.THREAD_COUNT.times(2).div(3)))
private val threadExecutor = ThreadExecutor(max(1, App.THREAD_COUNT.times(2).div(3)))
const val SQUARE_SIZE = 13 // preferably in odd number

View File

@@ -0,0 +1,102 @@
package net.torvald.terrarum.clut
import net.torvald.colourutil.CIEXYZ
import net.torvald.colourutil.toColor
import net.torvald.colourutil.toRGB
import net.torvald.parametricsky.ArHosekSkyModel
import net.torvald.terrarum.abs
import net.torvald.terrarum.clut.Skybox.coerceInSmoothly
import net.torvald.terrarum.clut.Skybox.mapCircle
import net.torvald.terrarum.clut.Skybox.scaleToFit
import net.torvald.terrarum.modulebasegame.worldgenerator.HALF_PI
import net.torvald.terrarum.serialise.toLittle
import java.io.File
/**
* Created by minjaesong on 2023-08-01.
*/
fun main() {
// y: increasing turbidity (1.0 .. 10.0, in steps of 0.333)
// x: elevations (-75 .. 75 in steps of 1, then albedo of [0.1, 0.3, 0.5, 0.7, 0.9])
val texh = Skybox.gradSize * Skybox.turbCnt
val texw = Skybox.elevCnt * Skybox.albedoCnt * 2
val TGA_HEADER_SIZE = 18
val bytes = ByteArray(TGA_HEADER_SIZE + texw * texh * 4 + 26)
// write header
byteArrayOf(
0, // ID field
0, // colour map (none)
2, // colour type (unmapped RGB)
0,0,0,0,0, // colour map spec (empty)
0,0, // x origin (0)
0,0, // y origin (0)
(texw and 255).toByte(),(texw.ushr(8) and 255).toByte(), // width
(texh and 255).toByte(),(texh.ushr(8) and 255).toByte(), // height
32, // bits-per-pixel (8bpp RGBA)
8 // image descriptor
).forEachIndexed { i,b -> bytes[i] = b }
// write footer
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000TRUEVISION-XFILE\u002E\u0000".forEachIndexed { i, c -> bytes[18 + texw * texh * 4 + i] =
c.code.toByte()
}
println("Generating texture atlas ($texw x $texh)...")
// write pixels
for (gammaPair in 0..1) {
for (albedo0 in 0 until Skybox.albedoCnt) {
val albedo = Skybox.albedos[albedo0]
println("Albedo=$albedo")
for (turb0 in 0 until Skybox.turbCnt) {
val turbidity = Skybox.turbiditiesD[turb0]
println("....... Turbidity=$turbidity")
for (elev0 in 0 until Skybox.elevCnt) {
val elevationDeg = Skybox.elevationsD[elev0]
val elevationRad = Math.toRadians(elevationDeg)
// println("... Elevation: $elevationDeg")
val state =
ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevationRad.abs())
for (yp in 0 until Skybox.gradSize) {
val yi = yp - 10
val xf = -elevationDeg / 90.0
var yf = (yi / 58.0).coerceIn(0.0, 1.0).mapCircle().coerceInSmoothly(0.0, 0.95)
// experiments visualisation: https://www.desmos.com/calculator/5crifaekwa
// if (elevationDeg < 0) yf *= 1.0 - pow(xf, 0.333)
// if (elevationDeg < 0) yf *= -2.0 * asin(xf - 1.0) / PI
if (elevationDeg < 0) yf *= Skybox.superellipsoidDecay(1.0 / 3.0, xf)
val theta = yf * HALF_PI
// vertical angle, where 0 is zenith, ±90 is ground (which is odd)
// println("$yp\t$theta")
val xyz = CIEXYZ(
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, (gammaPair * 2f + 1f) * HALF_PI, 0).toFloat(),
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, (gammaPair * 2f + 1f) * HALF_PI, 1).toFloat(),
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, (gammaPair * 2f + 1f) * HALF_PI, 2).toFloat()
)
val xyz2 = xyz.scaleToFit(elevationDeg)
val rgb = xyz2.toRGB().toColor()
val colour = rgb.toIntBits().toLittle()
val imgOffX = albedo0 * Skybox.elevCnt + elev0 + Skybox.elevCnt * Skybox.albedoCnt * gammaPair
val imgOffY = texh - 1 - (Skybox.gradSize * turb0 + yp)
val fileOffset = TGA_HEADER_SIZE + 4 * (imgOffY * texw + imgOffX)
for (i in 0..3) {
bytes[fileOffset + i] = colour[bytesLut[i]]
}
}
}
}
}
}
println("Atlas generation done!")
File("./assets/clut/skybox.tga").writeBytes(bytes)
}
private val bytesLut = arrayOf(2,1,0,3,2,1,0,3) // For some reason BGRA order is what makes it work

View File

@@ -0,0 +1,284 @@
package net.torvald.terrarum.clut
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.TextureRegion
import com.badlogic.gdx.utils.Disposable
import com.jme3.math.FastMath
import net.torvald.colourutil.CIEXYZ
import net.torvald.colourutil.toColor
import net.torvald.colourutil.toRGB
import net.torvald.parametricsky.ArHosekSkyModel
import net.torvald.terrarum.App
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.abs
import net.torvald.terrarum.floorToInt
import net.torvald.terrarum.toInt
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import kotlin.math.*
/**
* Created by minjaesong on 2023-07-09.
*/
object Skybox : Disposable {
private const val HALF_PI = 1.5707963267948966
private const val PI = 3.141592653589793
private const val TWO_PI = 6.283185307179586
const val gradSize = 78
private lateinit var gradTexBinLowAlbedo: Array<TextureRegion>
private lateinit var gradTexBinHighAlbedo: Array<TextureRegion>
private lateinit var tex: Texture
private lateinit var texRegions: TextureRegionPack
private lateinit var texStripRegions: TextureRegionPack
fun loadlut() {
tex = Texture(Gdx.files.internal("assets/clut/skybox.png"))
tex.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
tex.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat)
texRegions = TextureRegionPack(tex, 2, gradSize - 2, 0, 2, 0, 1)
texStripRegions = TextureRegionPack(tex, elevCnt, gradSize - 2, 0, 2, 0, 1)
}
// use internal LUT
/*operator fun get(elevationDeg: Double, turbidity: Double, albedo: Double): TextureRegion {
val elev = elevationDeg.coerceIn(-elevBias, elevBias).times(2.0).roundToInt().plus(150)
val turb = turbidity.coerceIn(1.0, 10.0).minus(1.0).times(turbDivisor).roundToInt()
val alb = albedo.coerceIn(0.1, 0.9).minus(0.1).times(turbDivisor).roundToInt()
return gradTexBinLowAlbedo[elev * turbCnt + turb]
}*/
// use external LUT
operator fun get(elevationDeg: Double, turbidity: Double, albedo: Double, isAfternoon: Boolean): TextureRegion {
TODO()
}
data class SkyboxRenderInfo(
val texture: Texture,
val uvs: FloatArray,
val turbidityPoint: Float,
val albedoPoint: Float,
)
fun getUV(elevationDeg: Double, turbidity: Double, albedo: Double): SkyboxRenderInfo {
val turb = turbidity.coerceIn(turbiditiesD.first(), turbiditiesD.last()).minus(1.0).times(turbDivisor)
val turbLo = turb.floorToInt()
val turbHi = min(turbCnt - 1, turbLo + 1)
val alb = albedo.coerceIn(albedos.first(), albedos.last()).times(5.0)
val albLo = alb.floorToInt()
val albHi = min(albedoCnt - 1, albLo + 1)
val elev = elevationDeg.coerceIn(-elevMax, elevMax).plus(elevMax).div(elevations.last.toDouble()).div(albedoCnt * 2).times((elevCnt - 1.0) / elevCnt)
// A: morn, turbLow, albLow
// B: noon, turbLow, albLow
// C: morn, turbHigh, albLow
// D: noon, turbHigh, albLow
// E: morn, turbLow, albHigh
// F: noon, turbLow, albHigh
// G: morn, turbHigh, albHigh
// H: noon, turbHigh, albHigh
val regionA = texStripRegions.get(albLo + albedoCnt * 0, turbLo)
val regionB = texStripRegions.get(albLo + albedoCnt * 1, turbLo)
val regionC = texStripRegions.get(albLo + albedoCnt * 0, turbHi)
val regionD = texStripRegions.get(albLo + albedoCnt * 1, turbHi)
val regionE = texStripRegions.get(albHi + albedoCnt * 0, turbLo)
val regionF = texStripRegions.get(albHi + albedoCnt * 1, turbLo)
val regionG = texStripRegions.get(albHi + albedoCnt * 0, turbHi)
val regionH = texStripRegions.get(albHi + albedoCnt * 1, turbHi)
// (0.5f / tex.width): because of the nature of bilinear interpolation, half pixels from the edges must be discarded
val uA = regionA.u + (0.5f / tex.width) + elev.toFloat()
val uB = regionB.u + (0.5f / tex.width) + elev.toFloat()
val uC = regionC.u + (0.5f / tex.width) + elev.toFloat()
val uD = regionD.u + (0.5f / tex.width) + elev.toFloat()
val uE = regionE.u + (0.5f / tex.width) + elev.toFloat()
val uF = regionF.u + (0.5f / tex.width) + elev.toFloat()
val uG = regionG.u + (0.5f / tex.width) + elev.toFloat()
val uH = regionH.u + (0.5f / tex.width) + elev.toFloat()
return SkyboxRenderInfo(
tex,
floatArrayOf(
uA, regionA.v, uA, regionA.v2,
uB, regionB.v, uB, regionB.v2,
uC, regionC.v, uC, regionC.v2,
uD, regionD.v, uD, regionD.v2,
uE, regionE.v, uE, regionE.v2,
uF, regionF.v, uF, regionF.v2,
uG, regionG.v, uG, regionG.v2,
uH, regionH.v, uH, regionH.v2,
),
(turb - turbLo).toFloat(),
(alb - albLo).toFloat(),
)
}
private fun Float.scaleFun() =
(1f - 1f / 2f.pow(this/6f)) * 0.97f
internal fun CIEXYZ.scaleToFit(elevationDeg: Double): CIEXYZ {
return if (elevationDeg >= 0) {
CIEXYZ(
this.X.scaleFun(),
this.Y.scaleFun(),
this.Z.scaleFun(),
this.alpha
)
}
else {
// maths model: https://www.desmos.com/calculator/cwi7iyzygg
val x = -elevationDeg.toFloat()
// val elevation2 = elevationDeg.toFloat() / 28.5f
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
)
}
}
val elevations = (0..150)
val elevMax = elevations.last / 2.0
val elevationsD = elevations.map { -elevMax + it } // -75, -74, -73, ..., 74, 75 // (specifically using whole number of angles because angle units any finer than 1.0 would make "hack" sunsut happen too fast)
val turbidities = (0..25) // 1, 1.2, 1.4, 1.6, ..., 6.0
val turbDivisor = 5.0
val turbiditiesD = turbidities.map { 1.0 + it / turbDivisor }
val albedos = arrayOf(0.0, 0.2, 0.4, 0.6, 0.8, 1.0)
val elevCnt = elevations.count()
val turbCnt = turbidities.count()
val albedoCnt = albedos.size
val gamma = HALF_PI
internal fun Double.mapCircle() = sin(HALF_PI * this)
internal fun initiate() {
printdbg(this, "Initialising skybox model")
TODO()
App.disposables.add(this)
printdbg(this, "Skybox model generated!")
}
/**
* See https://www.desmos.com/calculator/lcvvsju3p1 for mathematical definition
* @param p decay point. 0.0..1.0
* @param q polynomial degree. 2+. Larger value means sharper transition around the point p
* @param x the 'x' value of the function, as in `y=f(x)`. 0.0..1.0
*/
internal fun polynomialDecay(p: Double, q: Int, x: Double): Double {
val sign = if (q % 2 == 1) -1 else 1
val a1 = -1.0 / p
val a2 = 1.0 / (1.0 - p)
val q = q.toDouble()
return if (x < p)
sign * a1.pow(q - 1.0) * x.pow(q) + 1.0
else
sign * a2.pow(q - 1.0) * (x - 1.0).pow(q)
}
internal fun polynomialDecay2(p: Double, q: Int, x: Double): Double {
val sign = if (q % 2 == 1) 1 else -1
val a1 = -1.0 / p
val a2 = 1.0 / (1.0 - p)
val q = q.toDouble()
return if (x < p)
sign * a1.pow(q - 1.0) * x.pow(q)
else
sign * a2.pow(q - 1.0) * (x - 1.0).pow(q) + 1.0
}
internal fun superellipsoidDecay(p: Double, x: Double): Double {
return 1.0 - (1.0 - (1.0 - x).pow(1.0 / p)).pow(p)
}
internal fun Double.coerceInSmoothly(low: Double, high: Double): Double {
val x = this.coerceIn(low, high)
val x2 = ((x - low) * (high - low).pow(-1.0))
// return FastMath.interpolateLinear(polynomialDecay2(0.5, 2, x2), low, high)
return FastMath.interpolateLinear(smoothLinear(0.2, x2), low, high)
}
/**
* To get the idea what the fuck is going on here, please refer to https://www.desmos.com/calculator/snqglcu2wl
*/
internal fun smoothLinear(p: Double, x0: Double): Double {
val x = x0 - 0.5
val p1 = sqrt(1.0 - 2.0 * p)
val t = 0.5 * p1
val y0 = if (x < -t)
(1.0 / p) * (x + 0.5).pow(2) - 0.5
else if (x > t)
-(1.0 / p) * (x - 0.5).pow(2) + 0.5
else
x * 2.0 / (1.0 + p1)
return y0 + 0.5
}
private fun getTexturmaps(albedo: Double): Array<TextureRegion> {
return Array(elevCnt * turbCnt) {
val elevationDeg = elevationsD[it / turbCnt]
val elevationRad = Math.toRadians(elevationDeg)
val turbidity = turbiditiesD[it % turbCnt]
val state = ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevationRad.abs())
val pixmap = Pixmap(1, gradSize, Pixmap.Format.RGBA8888)
// printdbg(this, "elev $elevationDeg turb $turbidity")
for (yp in 0 until gradSize) {
val yi = yp - 10
val xf = -elevationDeg / 90.0
var yf = (yi / 58.0).coerceIn(0.0, 1.0).mapCircle().coerceInSmoothly(0.0, 0.95)
// experiments visualisation: https://www.desmos.com/calculator/5crifaekwa
// if (elevationDeg < 0) yf *= 1.0 - pow(xf, 0.333)
// if (elevationDeg < 0) yf *= -2.0 * asin(xf - 1.0) / PI
if (elevationDeg < 0) yf *= superellipsoidDecay(1.0 / 3.0, xf)
val theta = yf * HALF_PI
// vertical angle, where 0 is zenith, ±90 is ground (which is odd)
// println("$yp\t$theta")
val xyz = CIEXYZ(
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 xyz2 = xyz.scaleToFit(elevationDeg)
val rgb = xyz2.toRGB().toColor()
// pixmap.setColor(if (yp in 17 until 17 + 94) Color.LIME else Color.CORAL)
pixmap.setColor(rgb)
pixmap.drawPixel(0, yp)
}
val texture = Texture(pixmap).also {
it.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
}
pixmap.dispose()
TextureRegion(texture)
}
}
override fun dispose() {
if (Skybox::gradTexBinLowAlbedo.isInitialized) gradTexBinLowAlbedo.forEach { it.texture.dispose() }
if (Skybox::gradTexBinHighAlbedo.isInitialized) gradTexBinHighAlbedo.forEach { it.texture.dispose() }
if (Skybox::tex.isInitialized) tex.dispose()
}
}

View File

@@ -16,7 +16,7 @@ object ScreencapNogui: ConsoleCommand {
PixmapIO2.writeTGA(Gdx.files.absolute(App.defaultDir + "/Exports/${args[1]}.tga"), p, true)
p.dispose()
}
IngameRenderer.screencapRequested = true
IngameRenderer.requestScreencap()
Echo("FBO exported to$ccG Exports/${args[1]}.tga")
}
else {

View File

@@ -30,7 +30,7 @@ internal object SetGlobalLightOverride : ConsoleCommand {
}
}
else if (args.size == 2 && args[1].trim().toLowerCase() == "none") {
else if (args.size == 2 && args[1].trim().lowercase() == "none") {
WeatherMixer.globalLightOverridden = false
}
else {

View File

@@ -24,6 +24,7 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import org.dyn4j.geometry.Vector2
import java.util.*
import kotlin.math.absoluteValue
import kotlin.math.max
import kotlin.math.roundToInt
@@ -442,7 +443,7 @@ open class ActorWithBody : Actor {
@Transient val feetPosPoint: Point2d = Point2d(0.0,0.0)
//get() = Point2d(hitbox.centeredX, hitbox.endY)
@Transient val feetPosTile: Point2i = Point2i(0,0)
//get() = Point2i(hIntTilewiseHitbox.centeredX.floorInt(), hIntTilewiseHitbox.endY.floorInt())
//get() = Point2i(hIntTilewiseHitbox.centeredX.floorToInt(), hIntTilewiseHitbox.endY.floorToInt())
override fun run() = update(App.UPDATE_RATE)
@@ -474,23 +475,23 @@ open class ActorWithBody : Actor {
hitbox.reassign(newHitbox)
hIntTilewiseHitbox.setFromTwoPoints(
hitbox.startX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
hitbox.startY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
hitbox.endX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
hitbox.endY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5
hitbox.startX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5,
hitbox.startY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5,
hitbox.endX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5,
hitbox.endY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5
)
intTilewiseHitbox.setFromTwoPoints(
hitbox.startX.div(TILE_SIZE).floor(),
hitbox.startY.div(TILE_SIZE).floor(),
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(),
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor()
hitbox.startX.div(TILE_SIZE).floorToDouble(),
hitbox.startY.div(TILE_SIZE).floorToDouble(),
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble(),
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble()
)
centrePosVector.set(hitbox.centeredX, hitbox.centeredY)
centrePosPoint.set(hitbox.centeredX, hitbox.centeredY)
feetPosVector.set(hitbox.centeredX, hitbox.endY)
feetPosPoint.set(hitbox.centeredX, hitbox.endY)
feetPosTile.set(hIntTilewiseHitbox.centeredX.floorInt(), hIntTilewiseHitbox.endY.floorInt())
feetPosTile.set(hIntTilewiseHitbox.centeredX.floorToInt(), hIntTilewiseHitbox.endY.floorToInt())
}
override fun update(delta: Float) {
@@ -618,23 +619,23 @@ open class ActorWithBody : Actor {
}
hIntTilewiseHitbox.setFromTwoPoints(
hitbox.startX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
hitbox.startY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
hitbox.endX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
hitbox.endY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5
hitbox.startX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5,
hitbox.startY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5,
hitbox.endX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5,
hitbox.endY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5
)
intTilewiseHitbox.setFromTwoPoints(
hitbox.startX.div(TILE_SIZE).floor(),
hitbox.startY.div(TILE_SIZE).floor(),
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(),
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor()
hitbox.startX.div(TILE_SIZE).floorToDouble(),
hitbox.startY.div(TILE_SIZE).floorToDouble(),
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble(),
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble()
)
centrePosVector.set(hitbox.centeredX, hitbox.centeredY)
centrePosPoint.set(hitbox.centeredX, hitbox.centeredY)
feetPosVector.set(hitbox.centeredX, hitbox.endY)
feetPosPoint.set(hitbox.centeredX, hitbox.endY)
feetPosTile.set(hIntTilewiseHitbox.centeredX.floorInt(), hIntTilewiseHitbox.endY.floorInt())
feetPosTile.set(hIntTilewiseHitbox.centeredX.floorToInt(), hIntTilewiseHitbox.endY.floorToInt())
if (mouseUp && this.tooltipText != null) INGAME.setTooltipMessage(this.tooltipText)
@@ -746,23 +747,23 @@ open class ActorWithBody : Actor {
fun BlockAddress.isFeetTile(hitbox: Hitbox): Boolean {
val (x, y) = LandUtil.resolveBlockAddr(world!!, this)
val newTilewiseHitbox = Hitbox.fromTwoPoints(
hitbox.startX.div(TILE_SIZE).floor(),
hitbox.startY.div(TILE_SIZE).floor(),
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(),
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(),
hitbox.startX.div(TILE_SIZE).floorToDouble(),
hitbox.startY.div(TILE_SIZE).floorToDouble(),
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble(),
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble(),
true
)
// offset 1 pixel to the down so that friction would work
val yMatch = if (gravitation.y >= 0.0)
hitbox.endY.plus(A_PIXEL).div(TILE_SIZE).floorInt()
hitbox.endY.plus(A_PIXEL).div(TILE_SIZE).floorToInt()
else
hitbox.startY.minus(A_PIXEL).div(TILE_SIZE).floorInt()
hitbox.startY.minus(A_PIXEL).div(TILE_SIZE).floorToInt()
return y == yMatch && // copied from forEachFeetTileNum
(x in newTilewiseHitbox.startX.toInt()..newTilewiseHitbox.endX.toInt()) // copied from forEachOccupyingTilePos
}
fun Double.modTile() = this.div(TILE_SIZE).floorInt().times(TILE_SIZE)
fun Double.modTile() = this.div(TILE_SIZE).floorToInt().times(TILE_SIZE)
fun Double.modTileDelta() = this - this.modTile()
@@ -776,7 +777,7 @@ open class ActorWithBody : Actor {
// the job of the ccd is that the "next hitbox" would not dig into the terrain greater than the tile size,
// in which the modTileDelta returns a wrong value
val vectorSum = (externalV + controllerV)
val ccdSteps = (vectorSum.magnitude / TILE_SIZE).floorInt().coerceIn(2, 16) // adaptive
val ccdSteps = (vectorSum.magnitude / TILE_SIZE).floorToInt().coerceIn(2, 16) // adaptive
@@ -906,15 +907,15 @@ open class ActorWithBody : Actor {
// points to the EDGE of the tile in world dimension (don't use this directly to get tilewise coord!!)
val offendingTileWorldX = if (selfCollisionStatus in listOf(6, 12))
newHitbox.endX.div(TILE_SIZE).floor() * TILE_SIZE - PHYS_EPSILON_DIST
newHitbox.endX.div(TILE_SIZE).floorToDouble() * TILE_SIZE - PHYS_EPSILON_DIST
else
newHitbox.startX.div(TILE_SIZE).ceil() * TILE_SIZE
newHitbox.startX.div(TILE_SIZE).ceilToDouble() * TILE_SIZE
// points to the EDGE of the tile in world dimension (don't use this directly to get tilewise coord!!)
val offendingTileWorldY = if (selfCollisionStatus in listOf(3, 6))
newHitbox.endY.div(TILE_SIZE).floor() * TILE_SIZE - PHYS_EPSILON_DIST
newHitbox.endY.div(TILE_SIZE).floorToDouble() * TILE_SIZE - PHYS_EPSILON_DIST
else
newHitbox.startY.div(TILE_SIZE).ceil() * TILE_SIZE
newHitbox.startY.div(TILE_SIZE).ceilToDouble() * TILE_SIZE
val offendingHitboxPointX = if (selfCollisionStatus in listOf(6, 12))
newHitbox.endX
@@ -1136,10 +1137,10 @@ open class ActorWithBody : Actor {
val y2 = hitbox.endY - A_PIXEL
// this commands and the commands on isWalled WILL NOT match (1 px gap on endX/Y). THIS IS INTENTIONAL!
val txStart = x1.plus(HALF_PIXEL).floorInt()
val txEnd = x2.plus(HALF_PIXEL).floorInt()
val tyStart = y1.plus(HALF_PIXEL).floorInt()
val tyEnd = y2.plus(HALF_PIXEL).floorInt()
val txStart = x1.plus(HALF_PIXEL).floorToInt()
val txEnd = x2.plus(HALF_PIXEL).floorToInt()
val tyStart = y1.plus(HALF_PIXEL).floorToInt()
val tyEnd = y2.plus(HALF_PIXEL).floorToInt()
return isCollidingInternalStairs(txStart, tyStart, txEnd, tyEnd, feet).first > 0
}
@@ -1203,10 +1204,10 @@ open class ActorWithBody : Actor {
}
else throw IllegalArgumentException()
val txStart = x1.plus(HALF_PIXEL).floorInt()
val txEnd = x2.plus(HALF_PIXEL).floorInt()
val tyStart = y1.plus(HALF_PIXEL).floorInt()
val tyEnd = y2.plus(HALF_PIXEL).floorInt()
val txStart = x1.plus(HALF_PIXEL).floorToInt()
val txEnd = x2.plus(HALF_PIXEL).floorToInt()
val tyStart = y1.plus(HALF_PIXEL).floorToInt()
val tyEnd = y2.plus(HALF_PIXEL).floorToInt()
return isCollidingInternalStairs(txStart, tyStart, txEnd, tyEnd, option == COLLIDING_BOTTOM).first == 2
}
@@ -1258,27 +1259,27 @@ open class ActorWithBody : Actor {
y2 = hitbox.endY - A_PIXEL
}
else if (option == COLLIDING_ALLSIDE) {
return maxOf(maxOf(isWalledStairs(hitbox, COLLIDING_LEFT).first,
return max(max(isWalledStairs(hitbox, COLLIDING_LEFT).first,
isWalledStairs(hitbox, COLLIDING_RIGHT).first),
maxOf(isWalledStairs(hitbox, COLLIDING_BOTTOM).first,
max(isWalledStairs(hitbox, COLLIDING_BOTTOM).first,
isWalledStairs(hitbox, COLLIDING_TOP).first)) to 0
}
else if (option == COLLIDING_LR) {
val v1 = isWalledStairs(hitbox, COLLIDING_LEFT)
val v2 = isWalledStairs(hitbox, COLLIDING_RIGHT)
return maxOf(v1.first, v2.first) to maxOf(v2.first, v2.second)
return max(v1.first, v2.first) to max(v2.first, v2.second)
}
else if (option == COLLIDING_UD) {
return maxOf(isWalledStairs(hitbox, COLLIDING_BOTTOM).first,
return max(isWalledStairs(hitbox, COLLIDING_BOTTOM).first,
isWalledStairs(hitbox, COLLIDING_TOP).first) to 0
}
else throw IllegalArgumentException("$option")
val pxStart = x1.plus(0.5f).floorInt()
val pxEnd = x2.plus(0.5f).floorInt()
val pyStart = y1.plus(0.5f).floorInt()
val pyEnd = y2.plus(0.5f).floorInt()
val pxStart = x1.plus(0.5f).floorToInt()
val pxEnd = x2.plus(0.5f).floorToInt()
val pyStart = y1.plus(0.5f).floorToInt()
val pyEnd = y2.plus(0.5f).floorToInt()
return isCollidingInternalStairs(pxStart, pyStart, pxEnd, pyEnd, gravitation.y >= 0.0 && option == COLLIDING_BOTTOM || gravitation.y < 0.0 && option == COLLIDING_TOP)
}
@@ -1890,10 +1891,10 @@ open class ActorWithBody : Actor {
val newTilewiseHitbox = Hitbox.fromTwoPoints(
hitbox.startX.div(TILE_SIZE).floor(),
hitbox.startY.div(TILE_SIZE).floor(),
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(),
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(),
hitbox.startX.div(TILE_SIZE).floorToDouble(),
hitbox.startY.div(TILE_SIZE).floorToDouble(),
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble(),
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble(),
true
) // NOT the same as intTilewiseHitbox !!
@@ -1914,7 +1915,7 @@ open class ActorWithBody : Actor {
val tiles = ArrayList<ItemID?>()
// offset 1 pixel to the down so that friction would work
val y = hitbox.endY.plus(1.0).div(TILE_SIZE).floorInt()
val y = hitbox.endY.plus(1.0).div(TILE_SIZE).floorToInt()
for (x in hIntTilewiseHitbox.startX.toInt()..hIntTilewiseHitbox.endX.toInt()) {
tiles.add(world!!.getTileFromTerrain(x, y))
@@ -1930,7 +1931,7 @@ open class ActorWithBody : Actor {
val tileProps = ArrayList<BlockProp?>()
// offset 1 pixel to the down so that friction would work
val y = hitbox.endY.plus(1.0).div(TILE_SIZE).floorInt()
val y = hitbox.endY.plus(1.0).div(TILE_SIZE).floorToInt()
for (x in hIntTilewiseHitbox.startX.toInt()..hIntTilewiseHitbox.endX.toInt()) {
tileProps.add(BlockCodex[world!!.getTileFromTerrain(x, y)])

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