Compare commits

..

262 Commits

Author SHA1 Message Date
dfsek 6bac82da25 fix terrascript loading logging 2021-01-01 19:55:33 -07:00
dfsek a51727b636 fix exporting weirdness 2021-01-01 18:09:58 -07:00
dfsek ec722014e6 finalize commands 2021-01-01 17:45:06 -07:00
dfsek 256761eb5b fix version command 2021-01-01 17:43:10 -07:00
dfsek 07731c06c0 implement biome commands 2021-01-01 17:36:53 -07:00
dfsek 556584f9f5 improve BukkitAdapter, fix LocateCommand 2021-01-01 16:05:42 -07:00
dfsek 61c93b47ca implement EntityFunction 2021-01-01 03:28:06 -07:00
dfsek 044aa738a3 cleanup & add entity support 2021-01-01 01:50:01 -07:00
dfsek 8da2b63f31 refactor 2021-01-01 00:27:36 -07:00
dfsek ce033b0956 implement LootFunction 2021-01-01 00:08:03 -07:00
dfsek a9df684b80 reimplement loot tables 2020-12-31 23:20:16 -07:00
dfsek 356771bcea work on inventory stuff 2020-12-31 20:37:14 -07:00
dfsek 166c0f7dfb reimplement structure spawn command 2020-12-31 16:10:45 -07:00
dfsek aa41cc4d3d only allow loop flow control in loop 2020-12-31 02:49:48 -07:00
dfsek 0c3e3f2bc6 fix flow keyword issues 2020-12-31 02:44:33 -07:00
dfsek 792b6efd12 allow data to be returned 2020-12-31 02:30:41 -07:00
dfsek 122fbd841c correct scope wackiness in for loops 2020-12-31 02:06:53 -07:00
dfsek ad5823055d do precedence better 2020-12-31 02:03:47 -07:00
dfsek 92afe1c9ab refactor blockdata 2020-12-31 01:50:47 -07:00
dfsek 1826adf1c2 remove more logging 2020-12-30 21:38:23 -07:00
dfsek 97f6cda4ad remove debug logging 2020-12-30 21:10:52 -07:00
dfsek bccfcdf9a1 implement check cache 2020-12-30 21:03:28 -07:00
dfsek 8049824170 improve Transformer st handling 2020-12-30 20:32:55 -07:00
dfsek 99acadaf59 fix tscript comment issues 2020-12-30 18:05:32 -07:00
dfsek 2be4b36d1a configurable blending distance 2020-12-30 17:57:16 -07:00
dfsek c283f37390 fix spawn checks at biome edge 2020-12-30 13:55:15 -07:00
dfsek d16c28aebd cleanup generation code 2020-12-30 03:19:39 -07:00
dfsek ce45bacc6f better biome blending 2020-12-30 01:45:20 -07:00
dfsek a68b85c522 elevation tweaks & general cleanup 2020-12-30 00:03:02 -07:00
dfsek 7d0149b59d brain moment 2020-12-29 19:23:37 -07:00
dfsek 447c82f74a StructureFunction returns boolean based on pass/fail 2020-12-27 21:08:48 -07:00
dfsek 8db263e19b fix EOF issues 2020-12-27 20:55:01 -07:00
dfsek 7cf34dbd8a allow single statement loops 2020-12-27 20:52:35 -07:00
dfsek 283495832f Add else if and else 2020-12-27 20:42:42 -07:00
dfsek f6312a01d7 reimplement locate command 2020-12-27 00:27:58 -07:00
dfsek c7d43142f2 remove structure bound 2020-12-26 22:43:51 -07:00
dfsek c4da858095 reimplement structure probability collections 2020-12-26 22:22:17 -07:00
dfsek 5ff47bad18 improve cache configs 2020-12-26 21:36:15 -07:00
dfsek 18819ae53d fabric implementations 2020-12-26 03:06:25 -07:00
dfsek ddc2cea427 implement all Bukkit block data 2020-12-26 01:38:54 -07:00
dfsek bc17597923 Implement structure caching mechanism 2020-12-25 22:39:52 -07:00
dfsek 49f3c16a38 Implement BukkitOrientable 2020-12-25 21:47:56 -07:00
dfsek 5db1494341 implement script structures with chunkification(tm) 2020-12-25 20:43:41 -07:00
dfsek cccb706ad5 pass random to structure gen 2020-12-25 20:22:19 -07:00
dfsek c6d7d1a947 implement PullFunction 2020-12-25 17:46:29 -07:00
dfsek 9685dbbb9d Fix IntermediateBuffer 2020-12-25 17:46:22 -07:00
dfsek a18d459343 implement BukkitDirectional and BukkitRotatable 2020-12-25 17:06:23 -07:00
dfsek 4b5013231c implement Marks 2020-12-25 15:26:58 -07:00
dfsek a04bcf5b23 fix bukkit slab implementation 2020-12-25 13:06:15 -07:00
dfsek 1c579e8e5b improve ParseException 2020-12-25 12:08:22 -07:00
dfsek bbab6e39ff enforce scope definitions in for loop declarations 2020-12-25 02:51:52 -07:00
dfsek 2e68a0db5d parser cleanup 2020-12-25 02:40:29 -07:00
dfsek abc59901c1 Add for loops 2020-12-25 00:12:28 -07:00
dfsek aaa0c99524 Add FailKeyword 2020-12-24 23:10:14 -07:00
dfsek 0780539326 reimplement sapling override 2020-12-24 14:58:53 -07:00
dfsek c8434e73ef implement robust equals and hashcode in Vector3 2020-12-24 02:49:27 -07:00
dfsek 058ec9f24d store structures in Buffer 2020-12-24 02:40:28 -07:00
dfsek 7127943298 remove chunk apply method 2020-12-24 02:17:46 -07:00
dfsek 9adc03d56b Reimplement structure trees with TerraScripts 2020-12-24 02:06:19 -07:00
dfsek 5d6b060dee Add math functions 2020-12-24 02:06:05 -07:00
dfsek fc82eff93b add remapShadedJar task to Fabric 2020-12-23 23:03:42 -07:00
dfsek 1c316e52a9 Exporting 2020-12-23 23:02:58 -07:00
dfsek 76afd54d3c use epsilon for numeric equals 2020-12-23 15:19:33 -07:00
dfsek 7fe7dac57a implement RecursionsFunction 2020-12-23 15:09:42 -07:00
dfsek 63e59692e2 Implement StructureFunction and temp RandomFunction 2020-12-23 03:08:31 -07:00
dfsek 405a96034c Load structure scripts into registry 2020-12-23 02:35:07 -07:00
dfsek e9dc7428b8 document new tokens 2020-12-23 01:43:53 -07:00
dfsek b4342a36aa implement break, return, and continue 2020-12-23 01:37:51 -07:00
dfsek 1158ae958a refactor rotations, reimplement RotationUtil 2020-12-22 22:48:31 -07:00
dfsek 062c9b5efb Pass rotation to Item#apply 2020-12-22 22:41:51 -07:00
dfsek 66e8647517 rework loaders to allow traversing filenames 2020-12-22 20:11:01 -07:00
dfsek f47b975fe7 implement block & check functions 2020-12-22 17:32:17 -07:00
dfsek e5d9ae62fa more cleanup 2020-12-22 15:13:01 -07:00
dfsek 9c1eab04b9 Cleanup & fix grouping related operator precedence issues 2020-12-22 14:49:58 -07:00
dfsek 72d4370878 fix various tokenizer issues 2020-12-22 02:58:42 -07:00
dfsek 88da796923 Implement variable reassignment and while loops 2020-12-22 02:39:53 -07:00
dfsek 2ab4ed871c check if var/function is already defined in scope. 2020-12-22 02:20:46 -07:00
dfsek 0ecd275c56 Fix comment whitespace tokenizer issues 2020-12-22 02:13:35 -07:00
dfsek 4f40bcbe5e Implement variables 2020-12-22 02:00:40 -07:00
dfsek cb7b3de48c better type checking for function args 2020-12-21 22:30:02 -07:00
dfsek 13fbb9bf54 Implement boolean binary operations AND and OR 2020-12-21 21:08:43 -07:00
dfsek be8ed913e5 allow grouping binary operations 2020-12-21 20:55:51 -07:00
dfsek fe17683d27 cleanup, refactor, remove logging 2020-12-21 20:36:48 -07:00
dfsek 7d72a91bb7 implement comparison operators 2020-12-21 20:31:57 -07:00
dfsek 7a75f20a2c implement operator precedence 2020-12-21 16:22:08 -07:00
dfsek 8a7499d874 binary operations work now 2020-12-21 02:01:42 -07:00
dfsek adc5f0becc more parsing reworks 2020-12-21 01:28:40 -07:00
dfsek 6d710ca442 set up framework for binary operations 2020-12-20 16:46:44 -07:00
dfsek 7cbf8dffbe parse things in a less dumb way 2020-12-20 14:04:33 -07:00
dfsek e1cb46c8fd basic structure implementation 2020-12-20 02:21:29 -07:00
dfsek 8b97d74e0a allow constant expressions in if statements 2020-12-20 01:50:41 -07:00
dfsek c4f927e72c account for dangling opening/closing brace 2020-12-20 01:43:50 -07:00
dfsek 2880c29f8c if statements with code blocks 2020-12-20 01:08:37 -07:00
dfsek 474962db39 add escape character to parser string literals 2020-12-19 21:03:14 -07:00
dfsek f970838ecf Working parser/tokenizer 2020-12-19 20:04:58 -07:00
dfsek 29e2746e72 working tokenizer 2020-12-19 01:50:56 -07:00
dfsek 1ce884d1c7 Merge branch 'structure-rewrite' into agnostic
# Conflicts:
#	common/src/test/java/structure/LookaheadTest.java
#	platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/structure/v2/Function.java
#	platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/structure/v2/Parser.java
#	platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/structure/v2/tokenizer/Char.java
#	platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/structure/v2/tokenizer/Lookahead.java
#	platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/structure/v2/tokenizer/Position.java
#	platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/structure/v2/tokenizer/Token.java
#	platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/structure/v2/tokenizer/Tokenizer.java
#	platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/structure/v2/tokenizer/Tokens.java
#	platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/command/structure/v2/tokenizer/exceptions/TokenizerException.java
2020-12-18 20:50:41 -07:00
dfsek 24697ae60f Refactor API 2020-12-18 19:57:42 -07:00
dfsek 53c554f25c Gaea is gone 2020-12-18 19:46:19 -07:00
dfsek d1af8c1224 Begin absorbing Gaea into Terra 2020-12-18 19:36:27 -07:00
dfsek 9ac098f1ca Fix fractal trees 2020-12-18 16:55:36 -07:00
dfsek 300fe10da5 Cleanup 2020-12-18 15:44:16 -07:00
dfsek b33c8d6b77 fix population order 2020-12-18 15:35:09 -07:00
dfsek b06a755154 Trees work on Fabric now 2020-12-18 15:31:12 -07:00
dfsek 817b962c4a Move all pops to feature 2020-12-18 15:13:59 -07:00
dfsek 56c52e860d Version bump (releasing minor config update to fix config issues) 2020-12-18 02:27:19 -07:00
dfsek fd89c1128a fix order of population in FabricChunkGeneratorWrapper 2020-12-18 02:07:20 -07:00
dfsek beec1a97d4 Implement flora as a Feature on Fabric 2020-12-16 02:38:48 -07:00
dfsek b955e3d9b9 Register Fabric biomes as actual modded biomes. 2020-12-16 01:07:04 -07:00
dfsek b12079694c Add Validator API & cleanup Fabric 2020-12-16 00:26:05 -07:00
dfsek 7a83584317 Fix minor build issues 2020-12-15 11:02:14 -07:00
dfsek 1c4cc090af Merge remote-tracking branch 'origin/agnostic' into agnostic 2020-12-15 02:37:46 -07:00
solonovamax a614d7dddd Completely redo how gradle works (#40)
* make getWorldEdit() never null.

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>

* Locate commands work like vanilla

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>

* Completely rework all the gradle stuff for the subprojects

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>

* Update gradle version

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>

* make :common an api in the bukkit build.gradle

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>

* Move git clone function to CommonConfig.kt + make processResources depend on downloadDefaultPacks

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>

* clean up common build.gradle.kts

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>

* remove sponge

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>

* rename fabric group from com.dfsek.terra.bukkit to com.dfsek.terra.fabric

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>

* idk why this was removed some how?

It shows it's still in the main repo, but it was removed for me /shrug

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>

* Fix shading issues.

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>

* Fix issues with fabric-loom being stupid and requiring the plugin on the root project.

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>
2020-12-15 02:37:38 -07:00
dfsek ae21b8305a Begin work on not jank world implementation 2020-12-15 02:37:21 -07:00
dfsek 6f6767ab86 Trees no longer crash fabric. they are incredibly dumb on fabric so i will do them later 2020-12-15 02:03:54 -07:00
dfsek ee35c371ec Trees on Bukkit 2020-12-14 23:53:01 -07:00
dfsek 4d59c27a13 Reimplement fractal trees 2020-12-14 22:51:45 -07:00
dfsek 0dc0742e81 Implement Transformer API 2020-12-14 22:51:25 -07:00
dfsek 3b0abb7a20 Add access widener to mod.json 2020-12-14 18:19:34 -07:00
dfsek 42231cf319 fabric slabs & MultipleFacing 2020-12-14 17:09:47 -07:00
dfsek 11c8025ef4 Fix Fabric carver cache flushing 2020-12-14 16:33:19 -07:00
dfsek eda976bb5d Fix Fabric main config loading 2020-12-14 16:33:08 -07:00
dfsek 49c445d0f7 Implement some BlockData stuff on Fabric, make stuff less jank 2020-12-14 15:38:40 -07:00
dfsek 875e1feafe population order/invocation is now per-platform 2020-12-14 12:44:16 -07:00
dfsek 5f5504100b Codec stuff 2020-12-14 12:28:57 -07:00
dfsek 2215c8a98c fix mem leak & increase perf 2020-12-14 02:19:18 -07:00
dfsek ebe887def0 Remove unused constructor param from FabricBlock 2020-12-14 02:00:42 -07:00
dfsek 1dded41311 Flora and ores on Fabric 2020-12-14 01:27:28 -07:00
dfsek 6db4755109 Fix biome gen 2020-12-13 23:13:02 -07:00
dfsek a01dee9a27 Custom carving implemented in Fabric 2020-12-13 22:40:57 -07:00
dfsek 582bde8d0e register features 2020-12-13 21:16:33 -07:00
dfsek f609727afb Vanilla biome setting (sort of) works on Fabric now 2020-12-13 17:18:19 -07:00
dfsek a058f1c58b BiomeGrid no longer needs World object. 2020-12-13 15:21:55 -07:00
dfsek 70abf69dc7 Terra on Fabric 2020-12-13 03:52:10 -07:00
dfsek 269ec257b5 fabric stuff 2020-12-13 03:44:49 -07:00
dfsek 2c15a9fc0c Successful default config load in Fabric 2020-12-13 02:00:15 -07:00
SkytAsul 0826246cbe Created and completed fr_fr.yml (#39) 2020-12-12 20:13:01 -07:00
dfsek a3add9b20f Begin Sponge implementation 2020-12-12 19:23:28 -07:00
dfsek 6c20b5911f Sponge 2020-12-12 16:54:39 -07:00
dfsek d779b3ea27 testWithPaper task moved to Bukkit subproject 2020-12-12 16:24:01 -07:00
dfsek 618e7ed12e Fabric stuff still doesnt work, but eh 2020-12-12 15:31:00 -07:00
dfsek d84dd3a526 Super basic Fabric stuff 2020-12-12 01:44:56 -07:00
dfsek 27dbd494bd Rotation & tree stuff 2020-12-11 19:31:25 -07:00
dfsek 15100caf32 Ocean 2020-12-11 17:51:09 -07:00
dfsek 4e9c7e0b91 Carving 2020-12-11 17:45:49 -07:00
dfsek 0261ecdcbb for some reason these werent in the changelist 2020-12-11 17:31:06 -07:00
dfsek 5bf699cba9 Look ma, no Bukkit API in the core package 2020-12-11 17:30:17 -07:00
dfsek 7ee1d2c391 Predefined Flora 2020-12-11 00:11:37 -07:00
dfsek 5c9c47d078 Fix Location clone issue 2020-12-10 23:13:35 -07:00
dfsek af5309ff21 Populators work now 2020-12-10 23:09:53 -07:00
dfsek c7539dc5dd haha yes it works sort of 2020-12-10 22:47:53 -07:00
dfsek 4b2c2d8ba2 Actually register loaders 2020-12-10 21:46:09 -07:00
dfsek ee529a5973 refactor 2020-12-10 21:39:31 -07:00
dfsek 3e04dc6b46 it compiles now B) 2020-12-10 21:35:14 -07:00
dfsek dbf4b4dd3b Implementation go brrrr 2020-12-10 20:39:55 -07:00
dfsek 560fdf17fa Implement a whole bunch of stuff 2020-12-10 18:13:54 -07:00
dfsek 7a61a2548b Implement more stuff 2020-12-10 15:23:43 -07:00
solonovamax 31361286b5 Slight change to how world edit is loaded + make locate commands like vanilla (#38)
* make getWorldEdit() never null.

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>

* Locate commands work like vanilla

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>
2020-12-10 14:57:05 -07:00
dfsek abd29c1cb4 Do a whole bunch of stuff [DOES NOT COMPILE] 2020-12-10 14:15:02 -07:00
dfsek 9f4e120283 Implement Block interface 2020-12-10 12:28:59 -07:00
dfsek d9f585e4b2 make Handle separate interface 2020-12-10 11:51:30 -07:00
dfsek f4456f46a7 API stuff 2020-12-10 11:42:17 -07:00
dfsek 3dc27f2b0a Fix minor Gaea related issues 2020-12-10 10:52:02 -07:00
dfsek 95e39324c7 Dump Gaea into Terra. 2020-12-10 10:46:56 -07:00
dfsek 392ba59741 Begin reimplementing agnostic versions of Bukkit classes with delegate implementations 2020-12-10 10:19:16 -07:00
dfsek 26228d2c71 Tokenizer stuff 2020-12-10 09:49:46 -07:00
dfsek 8f58ba17a8 Begin work on tokenizer 2020-12-10 01:26:39 -07:00
dfsek 75f39640b0 Allow registering custom WorldHandle 2020-12-10 00:25:15 -07:00
dfsek 42dcc159e9 Implement WorldHandle 2020-12-09 22:13:10 -07:00
dfsek 791faa6dfd Apparently Walls have a separate rotation thing too 2020-12-09 17:18:04 -07:00
dfsek aea2b23fc3 Flora rotation options 2020-12-09 14:07:33 -07:00
dfsek 47438b7db9 Fix reloading issues 2020-12-09 01:36:21 -07:00
dfsek df3d3c6398 Fix profiler 2020-12-08 21:26:42 -07:00
dfsek 1457a10b0b hold PluginConfig instance in Terra plugin instance 2020-12-08 20:59:23 -07:00
dfsek 2b6e8eb67c Dependency injection moment 2020-12-08 20:35:18 -07:00
dfsek 11cb11bc2b Merge remote-tracking branch 'origin/master'
# Conflicts:
#	build.gradle.kts
2020-12-08 20:12:09 -07:00
dfsek bb5552c8bc Fix build issue causing lang to not be bundled 2020-12-08 20:10:55 -07:00
dfsek 8f5a9b7b8e Hold ConfigRegistry in Terra instance 2020-12-08 19:48:46 -07:00
dfsek 7e365c351d Ceiling ocean slabs 2020-12-08 19:36:06 -07:00
dfsek a0f0206ed8 Add GridSpawn seed option 2020-12-08 19:10:56 -07:00
dfsek 554628c486 Slabs can generate on ceiling in ocean 2020-12-08 19:10:46 -07:00
dfsek 37c2d945ec Bump version 2020-12-08 12:32:51 -07:00
Glare 59a24ef37f Implemented alternative ProcessResources (#36) 2020-12-08 09:26:16 -07:00
dfsek ad58a1efeb Fix raw loading issue 2020-12-07 18:51:34 -07:00
dfsek 682b155deb Fix structure features 2020-12-07 18:21:59 -07:00
dfsek 0e0d84fea7 Fix structure pull infinite loop 2020-12-07 00:59:27 -07:00
dfsek 4ceb4e22d4 make TerraBiomeGrid abstract, add TerraRadialBiomeGrid implementation & config options
Also adds lots of BiomeGrid validation stuff
2020-12-07 00:24:40 -07:00
solonovamax 2ae2801058 Remove editor specific files (#34)
* removed Terra.iml

* removed .idea directory
2020-12-06 16:58:24 -07:00
dfsek 5189aa5003 Use CodeMC for dependencies 2020-12-06 16:57:24 -07:00
dfsek 87cc2d01cb Don't do events in non-Terra worlds 2020-12-06 15:22:35 -07:00
dfsek f86fe4db32 Fix carving shift blocks 2020-12-06 02:52:21 -07:00
dfsek 1940309954 Remove singleton getter 2020-12-06 02:47:14 -07:00
dfsek d946ea9b15 Refactor Debug class, set up framework for Paper-specific events. 2020-12-06 02:25:15 -07:00
dfsek 0f8ce8966a Use Tectonic for world configs 2020-12-06 02:15:34 -07:00
dfsek c9b2c83dc4 Fix structure location issue. 2020-12-06 01:45:43 -07:00
dfsek 2d24a7bf00 Add more info to biome info command 2020-12-05 17:53:35 -07:00
dfsek 4c80a71bca Fix carving issues 2020-12-05 17:53:16 -07:00
dfsek 264f1df172 Update profiler target times 2020-12-05 16:13:17 -07:00
dfsek 5b17d87a97 Carving is now very much optimized 2020-12-05 16:11:56 -07:00
dfsek 0e4df43ddb carvers go brrrrrrr 2020-12-05 15:59:48 -07:00
dfsek 3d7796d8c3 carver speedup finalization 2020-12-05 03:19:39 -07:00
dfsek 4e647620f0 speed up carving even more 2020-12-05 02:56:58 -07:00
dfsek a38fcef6f1 Don't extract ZIPs, just bundle them 2020-12-04 22:30:30 -07:00
dfsek b5fdeef535 Re-add gradle wrapper because for some reason it was deleted 2020-12-04 21:46:12 -07:00
dfsek 5d3ae11374 Merge pull request #31 from PolyhedralDev/tectonic
Tectonic Implementation
2020-12-04 21:35:42 -07:00
dfsek 7db75ab21b Fix minor loading issue 2020-12-04 21:34:48 -07:00
dfsek 3d12af6b21 Add version key to config pack. 2020-12-04 21:09:35 -07:00
dfsek 601eb3e7ff Remove unneeded logging 2020-12-04 21:05:09 -07:00
dfsek 5754a95f48 Add seed variable to carver 2020-12-04 13:54:14 -07:00
dfsek b3e76f6485 Add packs list command. 2020-12-04 00:34:09 -07:00
dfsek 47b3278f96 Fix erosion NPE, add missing config 2020-12-03 22:31:03 -07:00
dfsek 27e31fef9f Improve flora placement algorithm 2020-12-03 01:13:25 -07:00
dfsek 3807b8c277 slabs and stairs generate on ceiling 2020-12-02 21:34:45 -07:00
dfsek 7db83c1dee Bump tectonic version 2020-12-02 15:29:07 -07:00
dfsek 496cd486b1 Carver go brrrr 2020-12-02 01:57:52 -07:00
dfsek 034f1072bf Carvers stop upon entering biome they arent present in. 2020-12-02 00:21:53 -07:00
dfsek b5c99c87e1 Structure features 2020-12-01 23:59:57 -07:00
dfsek c5fe86272e Loot tables 2020-12-01 23:45:09 -07:00
dfsek 15840302e0 Sapling growing and structure location 2020-12-01 23:38:30 -07:00
dfsek 0f526ca616 Cleanup and fix minor issues 2020-12-01 19:36:23 -07:00
dfsek bc3d694f7f Update to latest Tectonic 2020-12-01 01:57:04 -07:00
dfsek 7f880c23b8 Ore fixes 2020-12-01 01:56:51 -07:00
dfsek 7c6aa3a425 fix wacky biome location issue 2020-12-01 00:55:36 -07:00
dfsek 9636c808fe Structures! 2020-12-01 00:43:53 -07:00
dfsek f49ba88cb4 Add author option to config pack 2020-11-30 19:59:28 -07:00
dfsek 0cbc225408 Refactoring n stuff 2020-11-30 17:36:32 -07:00
dfsek f85d047ee6 Fix various issues 2020-11-30 17:23:57 -07:00
dfsek f033b8219c More flora controls 2020-11-30 14:37:28 -07:00
dfsek 1357e7f84e custom trees 2020-11-30 12:29:15 -07:00
dfsek 3eaab219f1 trees 2020-11-30 12:26:46 -07:00
dfsek ce97732da7 Use Tectonic validation API to validate Biome noise equations 2020-11-29 23:57:03 -07:00
dfsek 7fe2fa493e Prevent carvers crossing biomes 2020-11-29 20:08:04 -07:00
dfsek 78acf59f98 Working ZIP file loading 2020-11-29 18:17:29 -07:00
dfsek 1c0954d0cf Extra fancy loading 2020-11-29 15:24:33 -07:00
dfsek fe6ea9511b ZIP file loading should(tm) work now 2020-11-29 14:49:11 -07:00
dfsek 1c9c183d66 more sensitive derivative stuff 2020-11-29 14:12:01 -07:00
dfsek 67ff426894 Calculate derivative for slant palettes 2020-11-29 00:01:21 -07:00
dfsek 6eb5c0e0ec Equation-defined cave radii 2020-11-28 18:56:02 -07:00
dfsek 4e11d5c1cf implement ores, sort of 2020-11-28 18:05:19 -07:00
dfsek 155b293b61 new loading system, begin ZIP loading implementation 2020-11-28 16:45:35 -07:00
dfsek 282bfe9c5d begin work on ores 2020-11-28 02:34:43 -07:00
dfsek 4ddace2a92 Flora 2020-11-28 02:03:05 -07:00
dfsek 4b7b0ee7e9 live reloading 2020-11-27 15:53:52 -07:00
dfsek af6ba33921 carvers 2020-11-27 15:40:14 -07:00
dfsek 622e65e7a5 slab 2020-11-27 15:17:16 -07:00
dfsek 2f9f89042c probably a good idea to actually register variables 2020-11-27 14:32:31 -07:00
dfsek 538000ed32 Merge remote-tracking branch 'origin/tectonic' into tectonic 2020-11-27 14:17:12 -07:00
solonovamax fe676db0ce Vanilla ore (#28)
* Vanilla ore

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>

* Fast math

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>
2020-11-27 14:17:01 -07:00
dfsek 30e89a0b69 fix typo 2020-11-27 13:29:57 -07:00
dfsek 8e49f7ec26 Add BIOME: identifier to BiomeGridRegistry 2020-11-27 13:06:20 -07:00
dfsek 86088d1dcd Ocean 2020-11-27 02:30:31 -07:00
dfsek 5c6ea59d30 make perf not suck 2020-11-27 02:17:41 -07:00
dfsek f364420007 Actually gets to world gen now B) 2020-11-27 02:08:25 -07:00
dfsek 96ff875d2b More loading stuff 2020-11-27 01:17:32 -07:00
dfsek 717ece9d1f More loaders 'n stuff 2020-11-27 00:59:15 -07:00
dfsek 013216ad8c Registries are pretty cool, I guess 2020-11-26 22:05:18 -07:00
dfsek 16d8d56832 Add a bunch of type loaders 2020-11-26 21:26:01 -07:00
dfsek 06d9fa1d98 Actually load configs on startup 2020-11-26 20:51:06 -07:00
dfsek 59141f99bd That's quite the commit you got there 2020-11-26 19:07:43 -07:00
dfsek dbbe7dbd0d Implement Tectonic for master config. 2020-11-25 01:57:02 -07:00
dfsek c46161fc87 Include latest parsii 2020-11-24 17:08:02 -07:00
solonovamax 70ec483581 Action (should work) (#25)
Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>
2020-11-24 17:03:04 -07:00
588 changed files with 23148 additions and 8112 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = false
max_line_length = 120
max_line_length = 140
tab_width = 4
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
+4 -3
View File
@@ -21,7 +21,7 @@ jobs:
java-version: 1.8
- name: Build Terra
run: ./gradlew build -x test && ./gradlew build -x test
run: gradle shadowJar
- name: Upload artifacts
uses: actions/upload-artifact@v2
@@ -34,6 +34,7 @@ jobs:
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
prerelease: false
files: |
build/libs/Terra-*-shaded.jar
files: |
build/libs/Terra-*.jar
LICENSE
+2
View File
@@ -137,3 +137,5 @@ build
!lib/*.jar
.idea/Terra.iml
/run/
.idea/**.iml
-8
View File
@@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="1.8" />
</component>
</project>
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="PROJECT_FILES" />
</component>
</project>
-18
View File
@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="/usr/share/java/gradle" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>
-23
View File
@@ -1,23 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<Languages>
<language minSize="54" name="Java" />
</Languages>
</inspection_tool>
<inspection_tool class="NonSerializableObjectPassedToObjectStream" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SerialVersionUIDNotStaticFinal" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SerializableHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreAnonymousInnerClasses" value="false" />
<option name="superClassString" value="java.awt.Component" />
</inspection_tool>
<inspection_tool class="SerializableInnerClassHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreAnonymousInnerClasses" value="false" />
<option name="superClassString" value="java.awt.Component" />
</inspection_tool>
<inspection_tool class="SerializableStoresNonSerializable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TransientFieldInNonSerializableClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TransientFieldNotInitialized" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>
-95
View File
@@ -1,95 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="BintrayJCenter" />
<option name="name" value="BintrayJCenter" />
<option name="url" value="https://jcenter.bintray.com/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="papermc" />
<option name="name" value="papermc" />
<option name="url" value="https://papermc.io/repo/repository/maven-public/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="parsii.local" />
<option name="name" value="parsii" />
<option name="url" value="file:$PROJECT_DIR$/../parsii/repo" />
</remote-repository>
<remote-repository>
<option name="id" value="local" />
<option name="name" value="local" />
<option name="url" value="file:lib" />
</remote-repository>
<remote-repository>
<option name="id" value="aikar" />
<option name="name" value="aikar" />
<option name="url" value="https://repo.aikar.co/content/groups/aikar/" />
</remote-repository>
<remote-repository>
<option name="id" value="enginehub-maven" />
<option name="name" value="enginehub-maven" />
<option name="url" value="http://maven.enginehub.org/repo/" />
</remote-repository>
<remote-repository>
<option name="id" value="spigotmc-repo" />
<option name="name" value="spigotmc-repo" />
<option name="url" value="https://hub.spigotmc.org/nexus/content/repositories/snapshots/" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="enginehub" />
<option name="name" value="enginehub" />
<option name="url" value="https://maven.enginehub.org/repo/" />
</remote-repository>
<remote-repository>
<option name="id" value="minecraft-repo" />
<option name="name" value="minecraft-repo" />
<option name="url" value="https://libraries.minecraft.net/" />
</remote-repository>
<remote-repository>
<option name="id" value="gaea.local" />
<option name="name" value="gaea" />
<option name="url" value="file:$PROJECT_DIR$/../Gaea/repo" />
</remote-repository>
<remote-repository>
<option name="id" value="gaea.local" />
<option name="name" value="gaea-local" />
<option name="url" value="file:$PROJECT_DIR$/../Gaea/repo" />
</remote-repository>
<remote-repository>
<option name="id" value="CodeMC" />
<option name="name" value="CodeMC" />
<option name="url" value="https://repo.codemc.org/repository/maven-public" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenLocal" />
<option name="name" value="MavenLocal" />
<option name="url" value="file:$MAVEN_REPOSITORY$/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven5" />
<option name="name" value="maven5" />
<option name="url" value="https://maven.pkg.github.com/solonovamax/Gaea" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
</component>
</project>
-25
View File
@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0">
<entry_point TYPE="field" FQNAME="com.dfsek.terra.util.StructureTypeEnum NETHER_FORTRESS" />
</entry_points>
<list size="1">
<item index="0" class="java.lang.String" itemvalue="org.bukkit.event.EventHandler" />
</list>
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
-124
View File
@@ -1,124 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>
Generated
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CommitMessageInspectionProfile">
<profile version="1.0">
<inspection_tool class="GrazieCommit" enabled="true" level="TYPO" enabled_by_default="true" />
</profile>
</component>
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
-17
View File
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="CheckStyle-IDEA-Module">
<option name="configuration">
<map />
</option>
</component>
<component name="FacetManager">
<facet type="minecraft" name="Minecraft">
<configuration>
<autoDetectTypes>
<platformType>SPIGOT</platformType>
</autoDetectTypes>
</configuration>
</facet>
</component>
</module>
+6 -237
View File
@@ -1,211 +1,11 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import java.io.ByteArrayOutputStream
import java.net.URL
import java.nio.channels.Channels
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardCopyOption
//import java.util.zip.ZipFile
import java.util.zip.ZipInputStream
import com.dfsek.terra.getGitHash
plugins {
java
maven
id("com.github.johnrengelman.shadow").version("6.1.0")
val versionObj = Version("3", "0", "0", true)
allprojects {
version = versionObj
group = "com.dfsek.terra"
}
repositories {
flatDir {
dirs("lib")
}
maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") }
maven { url = uri("http://maven.enginehub.org/repo/") }
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
// maven { url = uri("https://maven.pkg.github.com/solonovamax/Gaea") }
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
val versionObj = Version("1", "5", "0", true)
version = versionObj
dependencies {
val gaeaVersion = "1.14.3"
compileOnly(name = "Gaea-${gaeaVersion}", group = "")
testImplementation(name = "Gaea-${gaeaVersion}", group = "")
compileOnly("org.jetbrains:annotations:20.1.0")
implementation("commons-io:commons-io:2.4")
implementation("org.apache.commons:commons-imaging:1.0-alpha2")
compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.2.0-SNAPSHOT")
implementation("org.bstats:bstats-bukkit:1.7")
compileOnly("com.googlecode.json-simple:json-simple:1.1")
implementation(name = "parsii-1.2.1", group = "")
compileOnly("org.spigotmc:spigot-api:1.16.2-R0.1-SNAPSHOT")
implementation("io.papermc:paperlib:1.0.5")
implementation("net.jafama:jafama:2.3.2")
// JUnit.
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0")
}
val compileJava: JavaCompile by tasks
val mainSourceSet: SourceSet = sourceSets["main"]
val tokenizeJavaSources = task<Copy>(name = "tokenizeJavaSources") {
from(mainSourceSet.allSource) {
include("**/plugin.yml")
println("version: $versionObj")
val tokens = mapOf("VERSION" to versionObj.toString())
filter(org.apache.tools.ant.filters.ReplaceTokens::class, "tokens" to tokens)
}
into("build/tokenizedSources")
includeEmptyDirs = false
}
compileJava.apply {
dependsOn(tokenizeJavaSources)
options.encoding = "UTF-8"
doFirst {
options.compilerArgs = mutableListOf("-Xlint:all")
}
}
tasks.test {
useJUnitPlatform()
maxHeapSize = "4G"
ignoreFailures = false
failFast = true
maxParallelForks = 12
}
val downloadDefaultPacks = tasks.create("downloadDefaultPacks") {
doFirst {
file("${buildDir}/resources/main/packs/").deleteRecursively()
val defaultPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/default.zip")
downloadAndUnzipPack(defaultPackUrl)
val netherPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/nether.zip")
downloadAndUnzipPack(netherPackUrl)
}
file("${buildDir}/resources/main/packs/").deleteRecursively()
val defaultPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/default.zip")
downloadAndUnzipPack(defaultPackUrl)
val netherPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/nether.zip")
downloadAndUnzipPack(netherPackUrl)
}
tasks.compileJava {
dependsOn(downloadDefaultPacks)
}
tasks.named<ShadowJar>("shadowJar") {
from(tokenizeJavaSources.destinationDir)
dependsOn(downloadDefaultPacks)
archiveClassifier.set("shaded")
archiveBaseName.set("Terra")
setVersion(project.version)
relocate("org.apache.commons", "com.dfsek.terra.lib.commons")
relocate("org.bstats.bukkit", "com.dfsek.terra.lib.bstats")
relocate("parsii", "com.dfsek.terra.lib.parsii")
relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib")
relocate("net.jafama", "com.dfsek.terra.lib.jafama")
minimize {
exclude(project(":"))
}
}
val testDir = "target/server/"
val setupServer = tasks.create("setupServer") {
dependsOn(tasks.shadowJar)
doFirst {
// clean
file("${testDir}/").deleteRecursively()
file("${testDir}/plugins").mkdirs()
// Downloading latest paper jar.
val paperUrl = URL("https://papermc.io/api/v1/paper/1.16.4/latest/download")
val paperReadableByteChannel = Channels.newChannel(paperUrl.openStream())
val paperFile = file("${testDir}/paper.jar")
val paperFileOutputStream = paperFile.outputStream()
val paperFileChannel = paperFileOutputStream.channel
paperFileChannel.transferFrom(paperReadableByteChannel, 0, Long.MAX_VALUE)
// Cloning test setup.
gitClone("https://github.com/PolyhedralDev/WorldGenTestServer")
// Copying plugins
Files.move(Paths.get("WorldGenTestServer/plugins"),
Paths.get("$testDir/plugins"),
StandardCopyOption.REPLACE_EXISTING)
// Copying config
val serverText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/server.properties").readText()
file("${testDir}/server.properties").writeText(serverText)
val bukkitText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/bukkit.yml").readText()
file("${testDir}/bukkit.yml").writeText(bukkitText.replace("\${world}", "world").replace("\${gen}", "Terra:DEFAULT"))
File("${testDir}/eula.txt").writeText("eula=true")
// clean up
file("WorldGenTestServer").deleteRecursively()
}
}
tasks.build {
dependsOn(tasks.shadowJar)
dependsOn(downloadDefaultPacks)
tasks.shadowJar.get().mustRunAfter(downloadDefaultPacks)
// dependsOn(testWithPaper)
// testWithPaper.mustRunAfter(tasks.shadowJar)
}
val testWithPaper = task<JavaExec>(name = "testWithPaper") {
standardInput = System.`in`
dependsOn(tasks.shadowJar)
// Copy Terra into dir
doFirst {
copy {
from("${buildDir}/libs/Terra-${versionObj}.jar")
into("${testDir}/plugins/")
}
}
main = "io.papermc.paperclip.Paperclip"
jvmArgs = listOf("-XX:+UseG1GC", "-XX:+ParallelRefProcEnabled", "-XX:MaxGCPauseMillis=200",
"-XX:+UnlockExperimentalVMOptions", "-XX:+DisableExplicitGC", "-XX:+AlwaysPreTouch",
"-XX:G1NewSizePercent=30", "-XX:G1MaxNewSizePercent=40", "-XX:G1HeapRegionSize=8M",
"-XX:G1ReservePercent=20", "-XX:G1HeapWastePercent=5", "-XX:G1MixedGCCountTarget=4",
"-XX:InitiatingHeapOccupancyPercent=15", "-XX:G1MixedGCLiveThresholdPercent=90",
"-XX:G1RSetUpdatingPauseTimePercent=5", "-XX:SurvivorRatio=32", "-XX:+PerfDisableSharedMem",
"-XX:MaxTenuringThreshold=1", "-Dusing.aikars.flags=https://mcflags.emc.gs",
"-Daikars.new.flags=true", "-DIReallyKnowWhatIAmDoingISwear")
maxHeapSize = "2G"
args = listOf("nogui")
workingDir = file("${testDir}/")
classpath = files("${testDir}/paper.jar")
}
/**
* Version class that does version stuff.
*/
@@ -218,35 +18,4 @@ class Version(val major: String, val minor: String, val revision: String, val pr
else //Only use git hash if it's a prerelease.
"$major.$minor.$revision-BETA+${getGitHash()}"
}
}
fun getGitHash(): String {
val stdout = ByteArrayOutputStream()
exec {
commandLine = mutableListOf("git", "rev-parse", "--short", "HEAD")
standardOutput = stdout
}
return stdout.toString().trim()
}
fun gitClone(name: String) {
val stdout = ByteArrayOutputStream()
exec {
commandLine = mutableListOf("git", "clone", name)
standardOutput = stdout
}
}
fun downloadAndUnzipPack(packUrl: URL) {
ZipInputStream(packUrl.openStream()).use { zip ->
while (true) {
val entry = zip.nextEntry ?: break
if (entry.isDirectory)
file("${buildDir}/resources/main/packs/${entry.name}").mkdirs()
else
file("${buildDir}/resources/main/packs/${entry.name}").outputStream().use { output ->
output.write(zip.readBytes())
}
}
}
}
+13
View File
@@ -0,0 +1,13 @@
plugins {
`kotlin-dsl`
kotlin("jvm") version embeddedKotlinVersion
}
repositories {
mavenCentral()
gradlePluginPortal()
}
dependencies {
"implementation"("com.github.jengelman.gradle.plugins:shadow:+")
}
@@ -0,0 +1,47 @@
package com.dfsek.terra
import org.gradle.api.Project
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.withType
import java.io.ByteArrayOutputStream
fun Project.configureCommon() {
apply(plugin = "java-library")
apply(plugin = "maven-publish")
apply(plugin = "idea")
configureDependencies()
configureCompilation()
configureDistribution()
version = rootProject.version
tasks.withType<Test>().configureEach {
useJUnitPlatform()
maxHeapSize = "2G"
ignoreFailures = false
failFast = true
maxParallelForks = 12
}
}
fun Project.getGitHash(): String {
val stdout = java.io.ByteArrayOutputStream()
exec {
commandLine = mutableListOf("git", "rev-parse", "--short", "HEAD")
standardOutput = stdout
}
return stdout.toString().trim()
}
fun Project.gitClone(name: String) {
val stdout = ByteArrayOutputStream()
exec {
commandLine = mutableListOf("git", "clone", name)
standardOutput = stdout
}
}
@@ -0,0 +1,27 @@
package com.dfsek.terra
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.withType
fun Project.configureCompilation() {
configure<JavaPluginConvention> {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
doFirst {
options.compilerArgs = mutableListOf("-Xlint:all")
}
}
tasks.withType<Javadoc> {
options.encoding = "UTF-8"
}
}
@@ -0,0 +1,25 @@
package com.dfsek.terra
import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.repositories
fun Project.configureDependencies() {
repositories {
maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") }
maven { url = uri("http://maven.enginehub.org/repo/") }
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
maven { url = uri("https://maven.fabricmc.net/") }
gradlePluginPortal()
jcenter()
mavenCentral()
}
dependencies {
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.7.0")
"testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.7.0")
"compileOnly"("org.jetbrains:annotations:20.1.0")
}
}
@@ -0,0 +1,87 @@
package com.dfsek.terra
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.plugins.BasePluginConvention
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.kotlin.dsl.*
import java.io.File
import java.net.URL
fun Project.configureDistribution() {
apply(plugin = "java-library")
apply(plugin = "com.github.johnrengelman.shadow")
// configurations.create("shaded")
configurations {
val shaded = create("shaded")
getByName("compile").extendsFrom(shaded)
// shaded.extendsFrom(getByName("compile"))
val shadedApi = create("shadedApi")
shaded.extendsFrom(shadedApi)
getByName("api").extendsFrom(shadedApi)
val shadedImplementation = create("shadedImplementation")
shaded.extendsFrom(shadedImplementation)
getByName("implementation").extendsFrom(shadedImplementation)
}
// tasks.withType<JavaCompile> {
// classpath +=
// }
val downloadDefaultPacks = tasks.create("downloadDefaultPacks") {
doFirst {
file("${buildDir}/resources/main/packs/").deleteRecursively()
val defaultPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/default.zip")
downloadPack(defaultPackUrl, project)
val netherPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/nether.zip")
downloadPack(netherPackUrl, project)
}
}
tasks["processResources"].dependsOn(downloadDefaultPacks)
tasks.register<Jar>("sourcesJar") {
archiveClassifier.set("sources")
}
tasks.withType<Jar> {
from("../LICENSE", "../../LICENSE")
}
tasks.register<Jar>("javadocJar") {
dependsOn("javadoc")
archiveClassifier.set("javadoc")
from(tasks.getByName<Javadoc>("javadoc").destinationDir)
}
tasks.named<ShadowJar>("shadowJar") {
// Tell shadow to download the packs
dependsOn(downloadDefaultPacks)
configurations = listOf(project.configurations["shaded"])
archiveClassifier.set("shaded")
setVersion(project.version)
relocate("org.apache.commons", "com.dfsek.terra.lib.commons")
relocate("parsii", "com.dfsek.terra.lib.parsii")
relocate("net.jafama", "com.dfsek.terra.lib.jafama")
minimize()
}
convention.getPlugin<BasePluginConvention>().archivesBaseName = project.name
tasks.named<DefaultTask>("build") {
dependsOn(tasks["shadowJar"])
}
}
fun downloadPack(packUrl: URL, project: Project) {
val fileName = packUrl.file.substring(packUrl.file.lastIndexOf("/"))
val file = File("${project.buildDir}/resources/main/packs/${fileName}")
file.parentFile.mkdirs()
file.outputStream().write(packUrl.readBytes())
}
+23
View File
@@ -0,0 +1,23 @@
import com.dfsek.terra.configureCommon
plugins {
`java-library`
}
configureCommon()
group = "com.dfsek.terra.common"
dependencies {
"shadedApi"("org.apache.commons:commons-rng-core:1.3")
"shadedApi"("commons-io:commons-io:2.4")
"shadedApi"("com.scireum:parsii:1.2.1")
"shadedApi"("com.dfsek:Tectonic:1.0.3")
"shadedApi"("net.jafama:jafama:2.3.2")
"shadedApi"("org.yaml:snakeyaml:1.27")
"compileOnly"("com.googlecode.json-simple:json-simple:1.1")
"shadedApi"("com.google.guava:guava:30.0-jre")
}
@@ -0,0 +1,4 @@
package com.dfsek.terra;
public interface CommandHandler {
}
@@ -0,0 +1,19 @@
package com.dfsek.terra;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.profiler.DataType;
import com.dfsek.terra.api.profiler.Measurement;
import com.dfsek.terra.api.profiler.WorldProfiler;
public class TerraProfiler extends WorldProfiler {
public TerraProfiler(World w) {
super(w);
this
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "FloraTime")
.addMeasurement(new Measurement(10000000, DataType.PERIOD_MILLISECONDS), "TreeTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "OreTime")
.addMeasurement(new Measurement(5000000, DataType.PERIOD_MILLISECONDS), "CaveTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "StructureTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "ElevationTime");
}
}
@@ -0,0 +1,55 @@
package com.dfsek.terra;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.generator.GeneratorWrapper;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.biome.BiomeZone;
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
import com.dfsek.terra.config.base.ConfigPack;
public class TerraWorld {
private final TerraBiomeGrid grid;
private final BiomeZone zone;
private final ConfigPack config;
private final boolean safe;
private final TerraProfiler profiler;
private final World world;
public TerraWorld(World w, ConfigPack c, TerraPlugin main) {
config = c;
profiler = new TerraProfiler(w);
this.grid = new TerraBiomeGrid.TerraBiomeGridBuilder(w.getSeed(), c, main).build();
this.zone = grid.getZone();
this.world = w;
safe = true;
}
public World getWorld() {
return world;
}
public static boolean isTerraWorld(World w) {
return w.getGenerator().getHandle() instanceof GeneratorWrapper;
}
public TerraBiomeGrid getGrid() {
return grid;
}
public ConfigPack getConfig() {
return config;
}
public BiomeZone getZone() {
return zone;
}
public boolean isSafe() {
return safe;
}
public TerraProfiler getProfiler() {
return profiler;
}
}
@@ -0,0 +1,8 @@
package com.dfsek.terra.api;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.Handle;
public interface Entity extends Handle {
Location getLocation();
}
@@ -0,0 +1,20 @@
package com.dfsek.terra.api;
import com.dfsek.terra.api.platform.world.World;
import java.io.File;
public class Gaea {
private static boolean debug;
public static File getGaeaFolder(World w) {
File f = new File(w.getWorldFolder(), "gaea");
f.mkdirs();
return f;
}
public static boolean isDebug() {
return debug;
}
}
@@ -0,0 +1,63 @@
package com.dfsek.terra.api;
import com.dfsek.tectonic.loading.TypeRegistry;
import com.dfsek.terra.api.math.ProbabilityCollection;
import com.dfsek.terra.api.math.Range;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
import com.dfsek.terra.biome.palette.PaletteHolder;
import com.dfsek.terra.biome.palette.PaletteLayer;
import com.dfsek.terra.carving.CarverPalette;
import com.dfsek.terra.config.loaders.ImageLoaderLoader;
import com.dfsek.terra.config.loaders.MaterialSetLoader;
import com.dfsek.terra.config.loaders.ProbabilityCollectionLoader;
import com.dfsek.terra.config.loaders.RangeLoader;
import com.dfsek.terra.config.loaders.config.FloraLayerLoader;
import com.dfsek.terra.config.loaders.config.GridSpawnLoader;
import com.dfsek.terra.config.loaders.config.NoiseBuilderLoader;
import com.dfsek.terra.config.loaders.config.OreConfigLoader;
import com.dfsek.terra.config.loaders.config.OreHolderLoader;
import com.dfsek.terra.config.loaders.config.TreeLayerLoader;
import com.dfsek.terra.config.loaders.palette.CarverPaletteLoader;
import com.dfsek.terra.config.loaders.palette.PaletteHolderLoader;
import com.dfsek.terra.config.loaders.palette.PaletteLayerLoader;
import com.dfsek.terra.generation.config.NoiseBuilder;
import com.dfsek.terra.generation.items.flora.FloraLayer;
import com.dfsek.terra.generation.items.flora.TerraFlora;
import com.dfsek.terra.generation.items.ores.Ore;
import com.dfsek.terra.generation.items.ores.OreConfig;
import com.dfsek.terra.generation.items.ores.OreHolder;
import com.dfsek.terra.generation.items.tree.TreeLayer;
import com.dfsek.terra.image.ImageLoader;
import com.dfsek.terra.procgen.GridSpawn;
import com.dfsek.terra.util.MaterialSet;
public class GenericLoaders implements LoaderRegistrar {
private final TerraPlugin main;
public GenericLoaders(TerraPlugin main) {
this.main = main;
}
@Override
public void register(TypeRegistry registry) {
registry.registerLoader(ProbabilityCollection.class, new ProbabilityCollectionLoader())
.registerLoader(Range.class, new RangeLoader())
.registerLoader(CarverPalette.class, new CarverPaletteLoader())
.registerLoader(GridSpawn.class, new GridSpawnLoader())
.registerLoader(PaletteHolder.class, new PaletteHolderLoader())
.registerLoader(PaletteLayer.class, new PaletteLayerLoader())
.registerLoader(FloraLayer.class, new FloraLayerLoader())
.registerLoader(Ore.Type.class, (t, o, l) -> Ore.Type.valueOf((String) o))
.registerLoader(OreConfig.class, new OreConfigLoader())
.registerLoader(NoiseBuilder.class, new NoiseBuilderLoader())
.registerLoader(TreeLayer.class, new TreeLayerLoader(main))
.registerLoader(MaterialSet.class, new MaterialSetLoader())
.registerLoader(OreHolder.class, new OreHolderLoader())
.registerLoader(ImageLoader.class, new ImageLoaderLoader())
.registerLoader(TerraBiomeGrid.Type.class, (t, o, l) -> TerraBiomeGrid.Type.valueOf((String) o))
.registerLoader(ImageLoader.Channel.class, (t, o, l) -> ImageLoader.Channel.valueOf((String) o))
.registerLoader(ImageLoader.Align.class, (t, o, l) -> ImageLoader.Align.valueOf((String) o))
.registerLoader(TerraFlora.Search.class, (t, o, l) -> TerraFlora.Search.valueOf((String) o));
}
}
@@ -0,0 +1,7 @@
package com.dfsek.terra.api;
import com.dfsek.tectonic.loading.TypeRegistry;
public interface LoaderRegistrar {
void register(TypeRegistry registry);
}
@@ -0,0 +1,4 @@
package com.dfsek.terra.api;
public interface Player extends Entity {
}
@@ -0,0 +1,40 @@
package com.dfsek.terra.api.lang;
import com.dfsek.tectonic.config.Configuration;
import com.dfsek.terra.api.platform.CommandSender;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Language {
private final Configuration configuration;
public Language(File file) throws IOException {
configuration = new Configuration(new FileInputStream(file));
}
@SuppressWarnings("unchecked")
public Message getMessage(String id) {
Message temp = null;
if(configuration.contains(id)) {
Object m = configuration.get(id);
if(m instanceof List) {
temp = new MultiLineMessage((List<String>) m);
} else if(m instanceof String) {
temp = new SingleLineMessage((String) m);
} else return new SingleLineMessage("message:" + id + ":translation_undefined");
}
if(temp == null || temp.isEmpty()) return new SingleLineMessage("message:" + id + ":translation_undefined");
return temp;
}
public void log(String messageID, Level level, Logger logger, String... args) {
getMessage(messageID).log(logger, level, args);
}
public void send(String messageID, CommandSender sender, String... args) {
getMessage(messageID).send(sender, args);
}
}
@@ -0,0 +1,13 @@
package com.dfsek.terra.api.lang;
import com.dfsek.terra.api.platform.CommandSender;
import java.util.logging.Level;
import java.util.logging.Logger;
public interface Message {
void log(Logger logger, Level level, String... args);
void send(CommandSender sender, String... args);
boolean isEmpty();
}
@@ -0,0 +1,33 @@
package com.dfsek.terra.api.lang;
import com.dfsek.terra.api.platform.CommandSender;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MultiLineMessage implements Message {
private final List<String> message;
public MultiLineMessage(List<String> message) {
this.message = message;
}
@Override
public void log(Logger logger, Level level, String... args) {
for(String line: message) {
logger.log(level, String.format(line, Arrays.asList(args).toArray()));
}
}
@Override
public void send(CommandSender sender, String... args) {
for(String line: message) {
sender.sendMessage(String.format(line, Arrays.asList(args).toArray()));
}
}
@Override
public boolean isEmpty() {
return message == null || message.isEmpty();
}
}
@@ -0,0 +1,29 @@
package com.dfsek.terra.api.lang;
import com.dfsek.terra.api.platform.CommandSender;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SingleLineMessage implements Message {
private final String message;
public SingleLineMessage(String message) {
this.message = message;
}
@Override
public void log(Logger logger, Level level, String... args) {
logger.log(level, String.format(message, Arrays.asList(args).toArray()));
}
@Override
public void send(CommandSender sender, String... args) {
sender.sendMessage(String.format(message, Arrays.asList(args).toArray()));
}
@Override
public boolean isEmpty() {
return message == null || message.equals("");
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,71 @@
package com.dfsek.terra.api.math;
import com.dfsek.terra.api.util.FastRandom;
import net.jafama.FastMath;
import java.util.Random;
/**
* Utility class for mathematical functions.
*/
public final class MathUtil {
private static final double EPSILON = 0.1E-5;
/**
* Gets the standard deviation of an array of doubles.
*
* @param numArray The array of numbers to calculate the standard deviation of.
* @return double - The standard deviation.
*/
public static double standardDeviation(double[] numArray) {
double sum = 0.0, standardDeviation = 0.0;
int length = numArray.length;
for(double num : numArray) {
sum += num;
}
double mean = sum / length;
for(double num : numArray) {
standardDeviation += FastMath.pow(num - mean, 2);
}
return FastMath.sqrt(standardDeviation / length);
}
/**
* Gets the carver seed for a chunk.
*
* @param chunkX Chunk's X coordinate
* @param chunkZ Chunk's Z coordinate
* @param seed World seed
* @return long - The carver seed.
*/
public static long getCarverChunkSeed(int chunkX, int chunkZ, long seed) {
Random r = new FastRandom(seed);
return chunkX * r.nextLong() ^ chunkZ * r.nextLong() ^ seed;
}
public static long hashToLong(String s) {
if(s == null) {
return 0;
}
long hash = 0;
for(char c : s.toCharArray()) {
hash = 31L * hash + c;
}
return hash;
}
/**
* Compare 2 floating-point values with epsilon to account for rounding errors
*
* @param a Value 1
* @param b Value 2
* @return Whether these values are equal
*/
public static boolean equals(double a, double b) {
return a == b || FastMath.abs(a - b) < EPSILON;
}
}
@@ -0,0 +1,49 @@
package com.dfsek.terra.api.math;
import com.dfsek.terra.api.world.biome.NormalizationUtil;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
@SuppressWarnings("unchecked")
public class ProbabilityCollection<E> {
private final Set<Object> cont = new HashSet<>();
private Object[] array = new Object[0];
private int size;
public com.dfsek.terra.api.math.ProbabilityCollection<E> add(E item, int probability) {
if(!cont.contains(item)) size++;
cont.add(item);
int oldLength = array.length;
Object[] newArray = new Object[array.length + probability];
System.arraycopy(array, 0, newArray, 0, array.length); // Expand array.
array = newArray;
for(int i = oldLength; i < array.length; i++) array[i] = item;
return this;
}
public E get() {
if(array.length == 0) return null;
return (E) array[ThreadLocalRandom.current().nextInt(array.length)];
}
public E get(Random r) {
if(array.length == 0) return null;
return (E) array[r.nextInt(array.length)];
}
public E get(FastNoiseLite n, double x, double z) {
if(array.length == 0) return null;
return (E) array[NormalizationUtil.normalize(n.getNoise(x, z), array.length, 1)];
}
public int getTotalProbability() {
return array.length;
}
public int size() {
return size;
}
}
@@ -0,0 +1,123 @@
package com.dfsek.terra.api.math;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
import java.util.Iterator;
import java.util.Random;
public class Range implements Iterable<Integer> {
private int min;
private int max;
public Range(int min, int max) {
if(min > max) throw new IllegalArgumentException("Minimum must not be grater than maximum!");
this.max = max;
this.min = min;
}
public boolean isInRange(int test) {
return test >= min && test < max;
}
public int getMax() {
return max;
}
public com.dfsek.terra.api.math.Range setMax(int max) {
this.max = max;
return this;
}
public int getMin() {
return min;
}
public com.dfsek.terra.api.math.Range setMin(int min) {
this.min = min;
return this;
}
public int getRange() {
return max - min;
}
public com.dfsek.terra.api.math.Range multiply(int mult) {
min *= mult;
max *= mult;
return this;
}
public com.dfsek.terra.api.math.Range reflect(int pt) {
return new com.dfsek.terra.api.math.Range(2 * pt - this.getMax(), 2 * pt - this.getMin());
}
public int get(Random r) {
return r.nextInt((max - min) + 1) + min;
}
public com.dfsek.terra.api.math.Range intersects(com.dfsek.terra.api.math.Range other) {
try {
return new com.dfsek.terra.api.math.Range(FastMath.max(this.getMin(), other.getMin()), FastMath.min(this.getMax(), other.getMax()));
} catch(IllegalArgumentException e) {
return null;
}
}
public com.dfsek.terra.api.math.Range add(int add) {
this.min += add;
this.max += add;
return this;
}
public com.dfsek.terra.api.math.Range sub(int sub) {
this.min -= sub;
this.max -= sub;
return this;
}
@Override
public String toString() {
return "Min: " + getMin() + ", Max:" + getMax();
}
@Override
public int hashCode() {
return min * 31 + max;
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof com.dfsek.terra.api.math.Range)) return false;
com.dfsek.terra.api.math.Range other = (com.dfsek.terra.api.math.Range) obj;
return other.getMin() == this.getMin() && other.getMax() == this.getMax();
}
@NotNull
@Override
public Iterator<Integer> iterator() {
return new RangeIterator(this);
}
private static class RangeIterator implements Iterator<Integer> {
private final com.dfsek.terra.api.math.Range m;
private Integer current;
public RangeIterator(com.dfsek.terra.api.math.Range m) {
this.m = m;
current = m.getMin();
}
@Override
public boolean hasNext() {
return current < m.getMax();
}
@Override
public Integer next() {
current++;
return current - 1;
}
}
}
@@ -0,0 +1,163 @@
package com.dfsek.terra.api.math.vector;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.world.World;
import java.util.Objects;
public class Location implements Cloneable {
private World world;
private Vector3 vector;
private double pitch;
private double yaw;
public Location(World w, double x, double y, double z) {
this.world = w;
this.vector = new Vector3(x, y, z);
}
public Location(World w, Vector3 vector) {
this.world = w;
this.vector = vector;
}
public void setWorld(World world) {
this.world = world;
}
public Vector3 getVector() {
return vector;
}
public void setVector(Vector3 vector) {
this.vector = vector;
}
@Override
public Location clone() {
try {
Location other = (Location) super.clone();
other.setVector(other.getVector().clone());
return other;
} catch(CloneNotSupportedException e) {
throw new Error(e);
}
}
public int getBlockX() {
return vector.getBlockX();
}
public int getBlockY() {
return vector.getBlockY();
}
public int getBlockZ() {
return vector.getBlockZ();
}
public double getY() {
return vector.getY();
}
public Location setY(double y) {
vector.setY(y);
return this;
}
public double getX() {
return vector.getX();
}
public Location setX(double x) {
vector.setX(x);
return this;
}
public double getZ() {
return vector.getZ();
}
public Location setZ(double z) {
vector.setZ(z);
return this;
}
public World getWorld() {
return world;
}
public Location add(double x, double y, double z) {
vector.add(x, y, z);
return this;
}
public Block getBlock() {
return world.getBlockAt(this);
}
public Location subtract(int x, int y, int z) {
vector.subtract(x, y, z);
return this;
}
public Location add(Vector3 add) {
vector.add(add);
return this;
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof Location)) {
return false;
}
final Location other = (Location) obj;
World world = this.world;
World otherWorld = other.world;
if(!Objects.equals(world, otherWorld)) {
return false;
}
if(Double.doubleToLongBits(this.vector.getX()) != Double.doubleToLongBits(other.vector.getX())) {
return false;
}
if(Double.doubleToLongBits(this.vector.getY()) != Double.doubleToLongBits(other.vector.getY())) {
return false;
}
return Double.doubleToLongBits(this.vector.getZ()) == Double.doubleToLongBits(other.vector.getZ());
}
public double getPitch() {
return pitch;
}
public void setPitch(double pitch) {
this.pitch = pitch;
}
public double getYaw() {
return yaw;
}
public void setYaw(double yaw) {
this.yaw = yaw;
}
@Override
public int hashCode() {
int hash = 3;
World world = (this.world == null) ? null : this.world;
hash = 19 * hash + (world != null ? world.hashCode() : 0);
hash = 19 * hash + (int) (Double.doubleToLongBits(this.vector.getX()) ^ (Double.doubleToLongBits(this.vector.getX()) >>> 32));
hash = 19 * hash + (int) (Double.doubleToLongBits(this.vector.getY()) ^ (Double.doubleToLongBits(this.vector.getY()) >>> 32));
hash = 19 * hash + (int) (Double.doubleToLongBits(this.vector.getZ()) ^ (Double.doubleToLongBits(this.vector.getZ()) >>> 32));
hash = 19 * hash + (int) (Double.doubleToLongBits(this.pitch) ^ Double.doubleToLongBits(this.pitch) >>> 32);
hash = 19 * hash + (int) (Double.doubleToLongBits(this.yaw) ^ Double.doubleToLongBits(this.yaw) >>> 32);
return hash;
}
public Vector3 toVector() {
return vector.clone();
}
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.procgen.math;
package com.dfsek.terra.api.math.vector;
import net.jafama.FastMath;
@@ -0,0 +1,344 @@
package com.dfsek.terra.api.math.vector;
import com.dfsek.terra.api.platform.world.World;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
public class Vector3 implements Cloneable {
/**
* Threshold for fuzzy equals().
*/
private static final double epsilon = 0.000001;
private double x;
private double y;
private double z;
public Vector3(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
/**
* Get the threshold used for equals().
*
* @return The epsilon.
*/
public static double getEpsilon() {
return epsilon;
}
public double getZ() {
return z;
}
public Vector3 setZ(double z) {
this.z = z;
return this;
}
public double getX() {
return x;
}
public Vector3 setX(double x) {
this.x = x;
return this;
}
public double getY() {
return y;
}
public Vector3 setY(double y) {
this.y = y;
return this;
}
public int getBlockX() {
return FastMath.floorToInt(x);
}
public int getBlockY() {
return FastMath.floorToInt(y);
}
public int getBlockZ() {
return FastMath.floorToInt(z);
}
public Vector3 multiply(double m) {
x *= m;
y *= m;
z *= m;
return this;
}
public Vector3 add(double x, double y, double z) {
this.x += x;
this.y += y;
this.z += z;
return this;
}
public Vector3 add(Vector3 other) {
this.x += other.getX();
this.y += other.getY();
this.z += other.getZ();
return this;
}
public Vector3 add(Vector2 other) {
this.x += other.getX();
this.z += other.getZ();
return this;
}
public double lengthSquared() {
return x * x + y * y + z * z;
}
@Override
public Vector3 clone() {
try {
return (Vector3) super.clone();
} catch(CloneNotSupportedException e) {
throw new Error(e);
}
}
public double length() {
return FastMath.sqrt(lengthSquared());
}
/**
* Returns if a vector is normalized
*
* @return whether the vector is normalised
*/
public boolean isNormalized() {
return Math.abs(this.lengthSquared() - 1) < getEpsilon();
}
/**
* Rotates the vector around the x axis.
* <p>
* This piece of math is based on the standard rotation matrix for vectors
* in three dimensional space. This matrix can be found here:
* <a href="https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">Rotation
* Matrix</a>.
*
* @param angle the angle to rotate the vector about. This angle is passed
* in radians
* @return the same vector
*/
@NotNull
public Vector3 rotateAroundX(double angle) {
double angleCos = Math.cos(angle);
double angleSin = Math.sin(angle);
double y = angleCos * getY() - angleSin * getZ();
double z = angleSin * getY() + angleCos * getZ();
return setY(y).setZ(z);
}
/**
* Rotates the vector around the y axis.
* <p>
* This piece of math is based on the standard rotation matrix for vectors
* in three dimensional space. This matrix can be found here:
* <a href="https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">Rotation
* Matrix</a>.
*
* @param angle the angle to rotate the vector about. This angle is passed
* in radians
* @return the same vector
*/
@NotNull
public Vector3 rotateAroundY(double angle) {
double angleCos = Math.cos(angle);
double angleSin = Math.sin(angle);
double x = angleCos * getX() + angleSin * getZ();
double z = -angleSin * getX() + angleCos * getZ();
return setX(x).setZ(z);
}
/**
* Rotates the vector around the z axis
* <p>
* This piece of math is based on the standard rotation matrix for vectors
* in three dimensional space. This matrix can be found here:
* <a href="https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">Rotation
* Matrix</a>.
*
* @param angle the angle to rotate the vector about. This angle is passed
* in radians
* @return the same vector
*/
@NotNull
public Vector3 rotateAroundZ(double angle) {
double angleCos = Math.cos(angle);
double angleSin = Math.sin(angle);
double x = angleCos * getX() - angleSin * getY();
double y = angleSin * getX() + angleCos * getY();
return setX(x).setY(y);
}
/**
* Get the distance between this vector and another. The value of this
* method is not cached and uses a costly square-root function, so do not
* repeatedly call this method to get the vector's magnitude. NaN will be
* returned if the inner result of the sqrt() function overflows, which
* will be caused if the distance is too long.
*
* @param o The other vector
* @return the distance
*/
public double distance(@NotNull Vector3 o) {
return FastMath.sqrt(FastMath.pow2(x - o.x) + FastMath.pow2(y - o.y) + FastMath.pow2(z - o.z));
}
/**
* Get the squared distance between this vector and another.
*
* @param o The other vector
* @return the distance
*/
public double distanceSquared(@NotNull Vector3 o) {
return FastMath.pow2(x - o.x) + FastMath.pow2(y - o.y) + FastMath.pow2(z - o.z);
}
/**
* Rotates the vector around a given arbitrary axis in 3 dimensional space.
*
* <p>
* Rotation will follow the general Right-Hand-Rule, which means rotation
* will be counterclockwise when the axis is pointing towards the observer.
* <p>
* This method will always make sure the provided axis is a unit vector, to
* not modify the length of the vector when rotating.
*
* @param axis the axis to rotate the vector around. If the passed vector is
* not of length 1, it gets copied and normalized before using it for the
* rotation. Please use {@link Vector3#normalize()} on the instance before
* passing it to this method
* @param angle the angle to rotate the vector around the axis
* @return the same vector
* @throws IllegalArgumentException if the provided axis vector instance is
* null
*/
@NotNull
public Vector3 rotateAroundAxis(@NotNull Vector3 axis, double angle) throws IllegalArgumentException {
return rotateAroundNonUnitAxis(axis.isNormalized() ? axis : axis.clone().normalize(), angle);
}
/**
* Rotates the vector around a given arbitrary axis in 3 dimensional space.
*
* <p>
* Rotation will follow the general Right-Hand-Rule, which means rotation
* will be counterclockwise when the axis is pointing towards the observer.
* <p>
* Note that the vector length will change accordingly to the axis vector
* length. If the provided axis is not a unit vector, the rotated vector
* will not have its previous length. The scaled length of the resulting
* vector will be related to the axis vector.
*
* @param axis the axis to rotate the vector around.
* @param angle the angle to rotate the vector around the axis
* @return the same vector
* @throws IllegalArgumentException if the provided axis vector instance is
* null
*/
@NotNull
public Vector3 rotateAroundNonUnitAxis(@NotNull Vector3 axis, double angle) throws IllegalArgumentException {
double x = getX(), y = getY(), z = getZ();
double x2 = axis.getX(), y2 = axis.getY(), z2 = axis.getZ();
double cosTheta = Math.cos(angle);
double sinTheta = Math.sin(angle);
double dotProduct = this.dot(axis);
double xPrime = x2 * dotProduct * (1d - cosTheta)
+ x * cosTheta
+ (-z2 * y + y2 * z) * sinTheta;
double yPrime = y2 * dotProduct * (1d - cosTheta)
+ y * cosTheta
+ (z2 * x - x2 * z) * sinTheta;
double zPrime = z2 * dotProduct * (1d - cosTheta)
+ z * cosTheta
+ (-y2 * x + x2 * y) * sinTheta;
return setX(xPrime).setY(yPrime).setZ(zPrime);
}
/**
* Calculates the dot product of this vector with another. The dot product
* is defined as x1*x2+y1*y2+z1*z2. The returned value is a scalar.
*
* @param other The other vector
* @return dot product
*/
public double dot(@NotNull Vector3 other) {
return x * other.x + y * other.y + z * other.z;
}
public Location toLocation(World world) {
return new Location(world, this.clone());
}
public Vector3 normalize() {
return this.multiply(1D / this.length());
}
public Vector3 subtract(int x, int y, int z) {
this.x -= x;
this.y -= y;
this.z -= z;
return this;
}
public Vector3 subtract(Vector3 end) {
x -= end.x;
y -= end.y;
z -= end.z;
return this;
}
/**
* Returns a hash code for this vector
*
* @return hash code
*/
@Override
public int hashCode() {
int hash = 7;
hash = 79 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32));
hash = 79 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32));
hash = 79 * hash + (int) (Double.doubleToLongBits(this.z) ^ (Double.doubleToLongBits(this.z) >>> 32));
return hash;
}
/**
* Checks to see if two objects are equal.
* <p>
* Only two Vectors can ever return true. This method uses a fuzzy match
* to account for floating point errors. The epsilon can be retrieved
* with epsilon.
*/
@Override
public boolean equals(Object obj) {
if(!(obj instanceof Vector3)) {
return false;
}
Vector3 other = (Vector3) obj;
return Math.abs(x - other.x) < epsilon && Math.abs(y - other.y) < epsilon && Math.abs(z - other.z) < epsilon && (this.getClass().equals(obj.getClass()));
}
}
@@ -0,0 +1,5 @@
package com.dfsek.terra.api.platform;
public interface CommandSender extends Handle {
void sendMessage(String message);
}
@@ -0,0 +1,8 @@
package com.dfsek.terra.api.platform;
/**
* An interface that contains a platform delegate.
*/
public interface Handle {
Object getHandle();
}
@@ -0,0 +1,41 @@
package com.dfsek.terra.api.platform;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.api.LoaderRegistrar;
import com.dfsek.terra.api.lang.Language;
import com.dfsek.terra.api.platform.handle.ItemHandle;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.config.base.PluginConfig;
import com.dfsek.terra.registry.ConfigRegistry;
import java.io.File;
import java.util.logging.Logger;
public interface TerraPlugin extends LoaderRegistrar {
WorldHandle getWorldHandle();
boolean isEnabled();
TerraWorld getWorld(World world);
Logger getLogger();
PluginConfig getTerraConfig();
File getDataFolder();
boolean isDebug();
Language getLanguage();
ConfigRegistry getRegistry();
void reload();
ItemHandle getItemHandle();
void saveDefaultConfig();
String platformName();
}
@@ -0,0 +1,5 @@
package com.dfsek.terra.api.platform.block;
public enum Axis {
X, Y, Z
}
@@ -0,0 +1,31 @@
package com.dfsek.terra.api.platform.block;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.block.state.BlockState;
public interface Block extends Handle {
void setBlockData(BlockData data, boolean physics);
BlockData getBlockData();
BlockState getState();
Block getRelative(BlockFace face);
Block getRelative(BlockFace face, int len);
boolean isEmpty();
Location getLocation();
MaterialData getType();
int getX();
int getZ();
int getY();
boolean isPassable();
}
@@ -0,0 +1,11 @@
package com.dfsek.terra.api.platform.block;
import com.dfsek.terra.api.platform.Handle;
public interface BlockData extends Cloneable, Handle {
MaterialData getMaterial();
boolean matches(MaterialData materialData);
BlockData clone();
}
@@ -0,0 +1,148 @@
package com.dfsek.terra.api.platform.block;
import com.dfsek.terra.api.math.vector.Vector3;
import org.jetbrains.annotations.NotNull;
public enum BlockFace {
NORTH(0, 0, -1),
EAST(1, 0, 0),
SOUTH(0, 0, 1),
WEST(-1, 0, 0),
UP(0, 1, 0),
DOWN(0, -1, 0),
NORTH_EAST(NORTH, EAST),
NORTH_WEST(NORTH, WEST),
SOUTH_EAST(SOUTH, EAST),
SOUTH_WEST(SOUTH, WEST),
WEST_NORTH_WEST(WEST, NORTH_WEST),
NORTH_NORTH_WEST(NORTH, NORTH_WEST),
NORTH_NORTH_EAST(NORTH, NORTH_EAST),
EAST_NORTH_EAST(EAST, NORTH_EAST),
EAST_SOUTH_EAST(EAST, SOUTH_EAST),
SOUTH_SOUTH_EAST(SOUTH, SOUTH_EAST),
SOUTH_SOUTH_WEST(SOUTH, SOUTH_WEST),
WEST_SOUTH_WEST(WEST, SOUTH_WEST),
SELF(0, 0, 0);
private final int modX;
private final int modY;
private final int modZ;
BlockFace(final int modX, final int modY, final int modZ) {
this.modX = modX;
this.modY = modY;
this.modZ = modZ;
}
BlockFace(final BlockFace face1, final BlockFace face2) {
this.modX = face1.getModX() + face2.getModX();
this.modY = face1.getModY() + face2.getModY();
this.modZ = face1.getModZ() + face2.getModZ();
}
/**
* Get the amount of X-coordinates to modify to get the represented block
*
* @return Amount of X-coordinates to modify
*/
public int getModX() {
return modX;
}
/**
* Get the amount of Y-coordinates to modify to get the represented block
*
* @return Amount of Y-coordinates to modify
*/
public int getModY() {
return modY;
}
/**
* Get the amount of Z-coordinates to modify to get the represented block
*
* @return Amount of Z-coordinates to modify
*/
public int getModZ() {
return modZ;
}
/**
* Gets the normal vector corresponding to this block face.
*
* @return the normal vector
*/
@NotNull
public Vector3 getDirection() {
Vector3 direction = new Vector3(modX, modY, modZ);
if(modX != 0 || modY != 0 || modZ != 0) {
direction.normalize();
}
return direction;
}
@NotNull
public BlockFace getOppositeFace() {
switch(this) {
case NORTH:
return BlockFace.SOUTH;
case SOUTH:
return BlockFace.NORTH;
case EAST:
return BlockFace.WEST;
case WEST:
return BlockFace.EAST;
case UP:
return BlockFace.DOWN;
case DOWN:
return BlockFace.UP;
case NORTH_EAST:
return BlockFace.SOUTH_WEST;
case NORTH_WEST:
return BlockFace.SOUTH_EAST;
case SOUTH_EAST:
return BlockFace.NORTH_WEST;
case SOUTH_WEST:
return BlockFace.NORTH_EAST;
case WEST_NORTH_WEST:
return BlockFace.EAST_SOUTH_EAST;
case NORTH_NORTH_WEST:
return BlockFace.SOUTH_SOUTH_EAST;
case NORTH_NORTH_EAST:
return BlockFace.SOUTH_SOUTH_WEST;
case EAST_NORTH_EAST:
return BlockFace.WEST_SOUTH_WEST;
case EAST_SOUTH_EAST:
return BlockFace.WEST_NORTH_WEST;
case SOUTH_SOUTH_EAST:
return BlockFace.NORTH_NORTH_WEST;
case SOUTH_SOUTH_WEST:
return BlockFace.NORTH_NORTH_EAST;
case WEST_SOUTH_WEST:
return BlockFace.EAST_NORTH_EAST;
case SELF:
return BlockFace.SELF;
}
return BlockFace.SELF;
}
}
@@ -0,0 +1,17 @@
package com.dfsek.terra.api.platform.block;
import com.dfsek.terra.api.platform.Handle;
public interface MaterialData extends Handle {
boolean matches(MaterialData other);
boolean matches(BlockData other);
boolean isSolid();
boolean isAir();
double getMaxDurability();
BlockData createBlockData();
}
@@ -0,0 +1,9 @@
package com.dfsek.terra.api.platform.block.data;
import com.dfsek.terra.api.platform.block.BlockData;
public interface AnaloguePowerable extends BlockData {
int getMaximumPower();
int getPower();
void setPower(int power);
}
@@ -0,0 +1,20 @@
package com.dfsek.terra.api.platform.block.data;
import com.dfsek.terra.api.platform.block.BlockData;
public interface Bisected extends BlockData {
Half getHalf();
void setHalf(Half half);
enum Half {
/**
* The top half of the block, normally with the higher y coordinate.
*/
TOP,
/**
* The bottom half of the block, normally with the lower y coordinate.
*/
BOTTOM
}
}
@@ -0,0 +1,10 @@
package com.dfsek.terra.api.platform.block.data;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.BlockFace;
public interface Directional extends BlockData {
BlockFace getFacing();
void setFacing(BlockFace facing);
}
@@ -0,0 +1,16 @@
package com.dfsek.terra.api.platform.block.data;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.BlockFace;
import java.util.Set;
public interface MultipleFacing extends BlockData {
Set<BlockFace> getFaces();
void setFace(BlockFace face, boolean facing);
Set<BlockFace> getAllowedFaces();
boolean hasFace(BlockFace f);
}
@@ -0,0 +1,14 @@
package com.dfsek.terra.api.platform.block.data;
import com.dfsek.terra.api.platform.block.Axis;
import com.dfsek.terra.api.platform.block.BlockData;
import java.util.Set;
public interface Orientable extends BlockData {
Set<Axis> getAxes();
Axis getAxis();
void setAxis(Axis axis);
}
@@ -0,0 +1,22 @@
package com.dfsek.terra.api.platform.block.data;
import com.dfsek.terra.api.platform.block.BlockData;
public interface Rail extends BlockData {
Shape getShape();
void setShape(Shape newShape);
enum Shape {
ASCENDING_EAST,
ASCENDING_NORTH,
ASCENDING_SOUTH,
ASCENDING_WEST,
EAST_WEST,
NORTH_EAST,
NORTH_SOUTH,
NORTH_WEST,
SOUTH_EAST,
SOUTH_WEST
}
}
@@ -0,0 +1,15 @@
package com.dfsek.terra.api.platform.block.data;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.BlockFace;
import java.util.Set;
public interface RedstoneWire extends BlockData, AnaloguePowerable {
Set<BlockFace> getAllowedFaces();
Connection getFace(BlockFace face);
void setFace(BlockFace face, Connection connection);
enum Connection {
NONE, SIDE, UP
}
}
@@ -0,0 +1,10 @@
package com.dfsek.terra.api.platform.block.data;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.BlockFace;
public interface Rotatable extends BlockData {
BlockFace getRotation();
void setRotation(BlockFace face);
}
@@ -0,0 +1,11 @@
package com.dfsek.terra.api.platform.block.data;
public interface Slab extends Waterlogged {
Type getType();
void setType(Type type);
enum Type {
TOP, BOTTOM, DOUBLE
}
}
@@ -0,0 +1,30 @@
package com.dfsek.terra.api.platform.block.data;
public interface Stairs extends Waterlogged, Directional, Bisected {
Shape getShape();
void setShape(Shape shape);
enum Shape {
/**
* Regular stair block.
*/
STRAIGHT,
/**
* Inner corner stair block with higher left side.
*/
INNER_LEFT,
/**
* Inner corner stair block with higher right side.
*/
INNER_RIGHT,
/**
* Outer corner stair block with higher left side.
*/
OUTER_LEFT,
/**
* Outer corner stair block with higher right side.
*/
OUTER_RIGHT
}
}
@@ -0,0 +1,15 @@
package com.dfsek.terra.api.platform.block.data;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.BlockFace;
public interface Wall extends BlockData, Waterlogged {
boolean isUp();
void setHeight(BlockFace face, Height height);
Height getHeight(BlockFace face);
void setUp(boolean up);
enum Height {
LOW, NONE, TALL
}
}
@@ -0,0 +1,9 @@
package com.dfsek.terra.api.platform.block.data;
import com.dfsek.terra.api.platform.block.BlockData;
public interface Waterlogged extends BlockData {
boolean isWaterlogged();
void setWaterlogged(boolean waterlogged);
}
@@ -0,0 +1,19 @@
package com.dfsek.terra.api.platform.block.state;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.block.BlockData;
public interface BlockState extends Handle {
Block getBlock();
int getX();
int getY();
int getZ();
BlockData getBlockData();
boolean update(boolean applyPhysics);
}
@@ -0,0 +1,6 @@
package com.dfsek.terra.api.platform.block.state;
import com.dfsek.terra.api.platform.inventory.BlockInventoryHolder;
public interface Container extends BlockState, BlockInventoryHolder {
}
@@ -0,0 +1,11 @@
package com.dfsek.terra.api.platform.generator;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import java.util.Random;
public interface BlockPopulator extends Handle {
void populate(World world, Random random, Chunk chunk);
}
@@ -0,0 +1,71 @@
package com.dfsek.terra.api.platform.generator;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.world.BiomeGrid;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Random;
public interface ChunkGenerator extends Handle {
boolean isParallelCapable();
boolean shouldGenerateCaves();
boolean shouldGenerateDecorations();
boolean shouldGenerateMobs();
boolean shouldGenerateStructures();
ChunkData generateChunkData(@NotNull World world, @NotNull Random random, int x, int z, @NotNull BiomeGrid biome);
List<BlockPopulator> getDefaultPopulators(World world);
@Nullable
TerraChunkGenerator getTerraGenerator();
interface ChunkData {
Object getHandle();
/**
* Get the maximum height for the chunk.
* <p>
* Setting blocks at or above this height will do nothing.
*
* @return the maximum height
*/
int getMaxHeight();
/**
* Set the block at x,y,z in the chunk data to material.
* <p>
* Setting blocks outside the chunk's bounds does nothing.
*
* @param x the x location in the chunk from 0-15 inclusive
* @param y the y location in the chunk from 0 (inclusive) - maxHeight (exclusive)
* @param z the z location in the chunk from 0-15 inclusive
* @param blockData the type to set the block to
*/
void setBlock(int x, int y, int z, @NotNull BlockData blockData);
/**
* Get the type and data of the block at x, y, z.
* <p>
* Getting blocks outside the chunk's bounds returns air.
*
* @param x the x location in the chunk from 0-15 inclusive
* @param y the y location in the chunk from 0 (inclusive) - maxHeight (exclusive)
* @param z the z location in the chunk from 0-15 inclusive
* @return the data of the block or the BlockData for air if x, y or z are outside the chunk's bounds
*/
@NotNull BlockData getBlockData(int x, int y, int z);
}
}
@@ -0,0 +1,6 @@
package com.dfsek.terra.api.platform.generator;
import com.dfsek.terra.api.platform.Handle;
public interface GeneratorWrapper extends Handle {
}
@@ -0,0 +1,8 @@
package com.dfsek.terra.api.platform.handle;
import com.dfsek.terra.api.platform.block.MaterialData;
import com.dfsek.terra.api.platform.inventory.ItemStack;
public interface ItemHandle {
ItemStack newItemStack(MaterialData material, int amount);
}
@@ -0,0 +1,26 @@
package com.dfsek.terra.api.platform.handle;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.MaterialData;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.api.platform.world.entity.EntityType;
/**
* Interface to be implemented for world manipulation.
*/
public interface WorldHandle {
void setBlockData(Block block, BlockData data, boolean physics);
BlockData getBlockData(Block block);
MaterialData getType(Block block);
BlockData createBlockData(String data);
MaterialData createMaterialData(String data);
Tree getTree(String id);
EntityType getEntity(String id);
}
@@ -0,0 +1,7 @@
package com.dfsek.terra.api.platform.inventory;
import com.dfsek.terra.api.platform.block.Block;
public interface BlockInventoryHolder extends InventoryHolder {
Block getBlock();
}
@@ -0,0 +1,11 @@
package com.dfsek.terra.api.platform.inventory;
import com.dfsek.terra.api.platform.Handle;
public interface Inventory extends Handle {
int getSize();
ItemStack getItem(int slot);
void setItem(int slot, ItemStack newStack);
}
@@ -0,0 +1,7 @@
package com.dfsek.terra.api.platform.inventory;
import com.dfsek.terra.api.platform.Handle;
public interface InventoryHolder extends Handle {
Inventory getInventory();
}
@@ -0,0 +1,19 @@
package com.dfsek.terra.api.platform.inventory;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.block.MaterialData;
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
public interface ItemStack extends Handle, Cloneable {
int getAmount();
void setAmount(int i);
MaterialData getType();
ItemStack clone();
ItemMeta getItemMeta();
void setItemMeta(ItemMeta meta);
}
@@ -0,0 +1,11 @@
package com.dfsek.terra.api.platform.inventory.item;
import com.dfsek.terra.api.platform.Handle;
public interface Damageable extends Handle {
int getDamage();
void setDamage(int damage);
boolean hasDamage();
}
@@ -0,0 +1,6 @@
package com.dfsek.terra.api.platform.inventory.item;
import com.dfsek.terra.api.platform.Handle;
public interface ItemMeta extends Handle {
}
@@ -0,0 +1,4 @@
/**
* API for platform implementations. Mostly interfaces to be implemented by platform delegates.
*/
package com.dfsek.terra.api.platform;
@@ -0,0 +1,6 @@
package com.dfsek.terra.api.platform.world;
import com.dfsek.terra.api.platform.Handle;
public interface Biome extends Handle {
}
@@ -0,0 +1,46 @@
package com.dfsek.terra.api.platform.world;
import com.dfsek.terra.api.platform.Handle;
import org.jetbrains.annotations.NotNull;
public interface BiomeGrid extends Handle {
/**
* Get biome at x, z within chunk being generated
*
* @param x - 0-15
* @param z - 0-15
* @return Biome value
*/
@NotNull
Biome getBiome(int x, int z);
/**
* Get biome at x, z within chunk being generated
*
* @param x - 0-15
* @param y - 0-255
* @param z - 0-15
* @return Biome value
*/
@NotNull
Biome getBiome(int x, int y, int z);
/**
* Set biome at x, z within chunk being generated
*
* @param x - 0-15
* @param z - 0-15
* @param bio - Biome value
*/
void setBiome(int x, int z, @NotNull Biome bio);
/**
* Set biome at x, z within chunk being generated
*
* @param x - 0-15
* @param y - 0-255
* @param z - 0-15
* @param bio - Biome value
*/
void setBiome(int x, int y, int z, @NotNull Biome bio);
}
@@ -0,0 +1,14 @@
package com.dfsek.terra.api.platform.world;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.block.Block;
public interface Chunk extends Handle {
int getX();
int getZ();
World getWorld();
Block getBlock(int x, int y, int z);
}
@@ -0,0 +1,6 @@
package com.dfsek.terra.api.platform.world;
import com.dfsek.terra.api.platform.Handle;
public interface Tree extends Handle, com.dfsek.terra.api.world.tree.Tree {
}
@@ -0,0 +1,37 @@
package com.dfsek.terra.api.platform.world;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.generator.ChunkGenerator;
import com.dfsek.terra.api.platform.world.entity.Entity;
import com.dfsek.terra.api.platform.world.entity.EntityType;
import java.io.File;
import java.util.UUID;
public interface World extends Handle {
long getSeed();
int getMaxHeight();
ChunkGenerator getGenerator();
String getName();
UUID getUID();
boolean isChunkGenerated(int x, int z);
Chunk getChunkAt(int x, int z);
File getWorldFolder();
Block getBlockAt(int x, int y, int z);
Block getBlockAt(Location l);
boolean generateTree(Location l, Tree vanillaTreeType);
Entity spawnEntity(Location location, EntityType entityType);
}
@@ -0,0 +1,6 @@
package com.dfsek.terra.api.platform.world.entity;
import com.dfsek.terra.api.platform.Handle;
public interface Entity extends Handle {
}
@@ -0,0 +1,6 @@
package com.dfsek.terra.api.platform.world.entity;
import com.dfsek.terra.api.platform.Handle;
public interface EntityType extends Handle {
}
@@ -0,0 +1,36 @@
package com.dfsek.terra.api.profiler;
/**
* Class to hold a profiler data value. Contains formatting method to highlight value based on desired range.
*/
public class DataHolder {
private final long desired;
private final DataType type;
private final double desiredRangePercent;
/**
* Constructs a DataHolder with a DataType and a desired value, including a percentage around the desired value considered acceptable
*
* @param type The type of data held in this instance.
* @param desired The desired value. This should be the average value of whatever is being measured.
* @param desiredRangePercent The percentage around the desired value to be considered acceptable.
*/
public DataHolder(DataType type, long desired, double desiredRangePercent) {
this.desired = desired;
this.type = type;
this.desiredRangePercent = desiredRangePercent;
}
/**
* Returns a String, formatted with Bungee ChatColors.<br>
* GREEN if the value is better than desired and outside of acceptable range.<br>
* YELLOW if the value is better or worse than desired, and within acceptable range.<br>
* RED if the value is worse than desired and outside of acceptable range.<br>
*
* @param data The data to format.
* @return String - The formatted data.
*/
public String getFormattedData(long data) {
return type.getFormatted(data);
}
}
@@ -0,0 +1,24 @@
package com.dfsek.terra.api.profiler;
import net.jafama.FastMath;
public enum DataType {
PERIOD_MILLISECONDS(Desire.LOW, 1000000, "ms"), PERIOD_NANOSECONDS(Desire.LOW, 1, "ns");
private final Desire desire;
private final long divisor;
private final String unit;
DataType(Desire d, long divisor, String unit) {
this.desire = d;
this.divisor = divisor;
this.unit = unit;
}
public String getFormatted(long value) {
return (double) FastMath.round(((double) value / divisor) * 100D) / 100D + unit;
}
public Desire getDesire() {
return desire;
}
}
@@ -0,0 +1,10 @@
package com.dfsek.terra.api.profiler;
/**
* Enum to represent the "goal" of a value, whether it is desirable for the value to be high (e.g. Frequency), or low (e.g. Period)
*/
public enum Desire {
LOW, HIGH
}
@@ -0,0 +1,92 @@
package com.dfsek.terra.api.profiler;
import com.dfsek.terra.api.math.MathUtil;
import com.dfsek.terra.api.util.GlueList;
import net.jafama.FastMath;
import java.math.BigInteger;
import java.util.List;
/**
* Class to record and hold all data for a single type of measurement performed by the profiler.
*/
public class Measurement {
private final List<Long> measurements;
private final long desirable;
private final DataType type;
private long min = Long.MAX_VALUE;
private long max = Long.MIN_VALUE;
/**
* Constructs a new Measurement with a desired value and DataType.
*
* @param desirable The desired value of the measurement.
* @param type The type of data the measurement is holding.
*/
public Measurement(long desirable, DataType type) {
this.desirable = desirable;
this.type = type;
measurements = new GlueList<>();
}
public void record(long value) {
max = FastMath.max(value, max);
min = FastMath.min(value, min);
measurements.add(value);
}
public int size() {
return measurements.size();
}
public ProfileFuture beginMeasurement() {
ProfileFuture future = new ProfileFuture();
long current = System.nanoTime();
future.thenRun(() -> record(System.nanoTime() - current));
return future;
}
public void reset() {
min = Long.MAX_VALUE;
max = Long.MIN_VALUE;
measurements.clear();
}
public DataHolder getDataHolder() {
return new DataHolder(type, desirable, 0.25);
}
public long getMin() {
if(min == Long.MAX_VALUE) return 0;
return min;
}
public long getMax() {
if(max == Long.MIN_VALUE) return 0;
return max;
}
public long average() {
BigInteger running = new BigInteger("0");
List<Long> mTemp = new GlueList<>(measurements);
for(Long l : mTemp) {
running = running.add(BigInteger.valueOf(l));
}
if(measurements.size() == 0) return 0;
return running.divide(BigInteger.valueOf(measurements.size())).longValue();
}
public double getStdDev() {
List<Long> mTemp = new GlueList<>(measurements);
double[] vals = new double[mTemp.size()];
for(int i = 0; i < mTemp.size(); i++) {
vals[i] = mTemp.get(i);
}
return MathUtil.standardDeviation(vals);
}
public int entries() {
return measurements.size();
}
}
@@ -0,0 +1,18 @@
package com.dfsek.terra.api.profiler;
import java.util.concurrent.CompletableFuture;
public class ProfileFuture extends CompletableFuture<Boolean> implements AutoCloseable {
public ProfileFuture() {
super();
}
public boolean complete() {
return super.complete(true);
}
@Override
public void close() {
this.complete();
}
}
@@ -0,0 +1,81 @@
package com.dfsek.terra.api.profiler;
import com.dfsek.terra.api.platform.world.World;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import net.jafama.FastMath;
import java.util.Map;
public class WorldProfiler {
private final BiMap<String, Measurement> measures = HashBiMap.create();
private final World world;
private boolean isProfiling;
public WorldProfiler(World w) {
if(w.getGenerator().getTerraGenerator() == null)
throw new IllegalArgumentException("Attempted to instantiate profiler on non-Gaea managed world!");
this.addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "TotalChunkGenTime")
.addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "ChunkBaseGenTime")
.addMeasurement(new Measurement(2000000, DataType.PERIOD_MILLISECONDS), "BiomeApplyTime")
.addMeasurement(new Measurement(2000000, DataType.PERIOD_MILLISECONDS), "PopulationManagerTime");
isProfiling = false;
this.world = w;
}
public String getResultsFormatted() {
if(! isProfiling) return "Profiler is not currently running.";
StringBuilder result = new StringBuilder("Gaea World Profiler Results (Min / Avg / Max / Std Dev): \n");
for(Map.Entry<String, Measurement> e : measures.entrySet()) {
result
.append(e.getKey())
.append(": ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().getMin()))
.append(" / ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().average()))
.append(" / ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().getMax()))
.append(" / ")
.append((double) FastMath.round((e.getValue().getStdDev() / 1000000) * 100D) / 100D)
.append("ms")
.append(" (x").append(e.getValue().size()).append(")\n");
}
return result.toString();
}
public void reset() {
for(Map.Entry<String, Measurement> e : measures.entrySet()) {
e.getValue().reset();
}
}
public com.dfsek.terra.api.profiler.WorldProfiler addMeasurement(Measurement m, String name) {
measures.put(name, m);
return this;
}
public void setMeasurement(String id, long value) {
if(isProfiling) measures.get(id).record(value);
}
public ProfileFuture measure(String id) {
if(isProfiling) return measures.get(id).beginMeasurement();
else return null;
}
public String getID(Measurement m) {
return measures.inverse().get(m);
}
public boolean isProfiling() {
return isProfiling;
}
public void setProfiling(boolean enabled) {
this.isProfiling = enabled;
}
public World getWorld() {
return world;
}
}
@@ -0,0 +1,93 @@
package com.dfsek.terra.api.structures.loot;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.block.MaterialData;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import com.dfsek.terra.api.structures.loot.functions.AmountFunction;
import com.dfsek.terra.api.structures.loot.functions.DamageFunction;
import com.dfsek.terra.api.structures.loot.functions.Function;
import com.dfsek.terra.api.util.GlueList;
import net.jafama.FastMath;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.util.List;
import java.util.Random;
/**
* Representation of a single item entry within a Loot Table pool.
*/
public class Entry {
private final MaterialData item;
private final long weight;
private final List<Function> functions = new GlueList<>();
private final TerraPlugin main;
/**
* Instantiates an Entry from a JSON representation.
*
* @param entry The JSON Object to instantiate from.
*/
public Entry(JSONObject entry, TerraPlugin main) {
this.main = main;
String id = entry.get("name").toString();
this.item = main.getWorldHandle().createMaterialData(id);
long weight1;
try {
weight1 = (long) entry.get("weight");
} catch(NullPointerException e) {
weight1 = 1;
}
this.weight = weight1;
if(entry.containsKey("functions")) {
for(Object function : (JSONArray) entry.get("functions")) {
switch(((String) ((JSONObject) function).get("function"))) {
case "minecraft:set_count":
case "set_count":
Object loot = ((JSONObject) function).get("count");
long max, min;
if(loot instanceof Long) {
max = (Long) loot;
min = (Long) loot;
} else {
max = (long) ((JSONObject) loot).get("max");
min = (long) ((JSONObject) loot).get("min");
}
functions.add(new AmountFunction(FastMath.toIntExact(min), FastMath.toIntExact(max)));
break;
case "minecraft:set_damage":
case "set_damage":
long maxDamage = (long) ((JSONObject) ((JSONObject) function).get("damage")).get("max");
long minDamage = (long) ((JSONObject) ((JSONObject) function).get("damage")).get("min");
functions.add(new DamageFunction(FastMath.toIntExact(minDamage), FastMath.toIntExact(maxDamage)));
break;
}
}
}
}
/**
* Fetches a single ItemStack from the Entry, applying all functions to it.
*
* @param r The Random instance to apply functions with
* @return ItemStack - The ItemStack with all functions applied.
*/
public ItemStack getItem(Random r) {
ItemStack item = main.getItemHandle().newItemStack(this.item, 1);
for(Function f : functions) {
item = f.apply(item, r);
}
return item;
}
/**
* Gets the weight attribute of the Entry.
*
* @return long - The weight of the Entry.
*/
public long getWeight() {
return this.weight;
}
}
@@ -0,0 +1,78 @@
package com.dfsek.terra.api.structures.loot;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.inventory.Inventory;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import com.dfsek.terra.api.util.GlueList;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.util.List;
import java.util.Random;
/**
* Class representation of a Loot Table to populate chest loot.
*/
public class LootTable {
private final List<Pool> pools = new GlueList<>();
/**
* Instantiates a LootTable from a JSON String.
*
* @param json The JSON String representing the loot table.
* @throws ParseException if malformed JSON is passed.
*/
public LootTable(String json, TerraPlugin main) throws ParseException {
JSONParser jsonParser = new JSONParser();
Object tableJSON = jsonParser.parse(json);
JSONArray poolArray = (JSONArray) ((JSONObject) tableJSON).get("pools");
for(Object pool : poolArray) {
pools.add(new Pool((JSONObject) pool, main));
}
}
/**
* Fetches a list of ItemStacks from the loot table using the given Random instance.
*
* @param r The Random instance to use.
* @return List&lt;ItemStack&gt; - The list of loot fetched.
*/
public List<ItemStack> getLoot(Random r) {
List<ItemStack> itemList = new GlueList<>();
for(Pool pool : pools) {
itemList.addAll(pool.getItems(r));
}
return itemList;
}
/**
* Fills an Inventory with loot.
*
* @param i The Inventory to fill.
* @param r The The Random instance to use.
*/
public void fillInventory(Inventory i, Random r) {
List<ItemStack> loot = getLoot(r);
for(ItemStack stack : loot) {
int attempts = 0;
while(stack.getAmount() != 0 && attempts < 10) {
ItemStack newStack = stack.clone();
newStack.setAmount(1);
int slot = r.nextInt(i.getSize());
ItemStack slotItem = i.getItem(slot);
if(slotItem == null) {
i.setItem(slot, newStack);
stack.setAmount(stack.getAmount() - 1);
} else if(slotItem.getType().equals(newStack.getType())) {
ItemStack dep = newStack.clone();
dep.setAmount(newStack.getAmount() + slotItem.getAmount());
i.setItem(slot, dep);
stack.setAmount(stack.getAmount() - 1);
}
attempts++;
}
}
}
}
@@ -0,0 +1,59 @@
package com.dfsek.terra.api.structures.loot;
import com.dfsek.terra.api.math.ProbabilityCollection;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import com.dfsek.terra.api.util.GlueList;
import net.jafama.FastMath;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.util.List;
import java.util.Random;
/**
* Representation of a Loot Table pool, or a set of items to be fetched independently.
*/
public class Pool {
private final int max;
private final int min;
private final ProbabilityCollection<Entry> entries;
/**
* Instantiates a Pool from a JSON representation.
*
* @param pool The JSON Object to instantiate from.
*/
public Pool(JSONObject pool, TerraPlugin main) {
entries = new ProbabilityCollection<>();
Object amount = pool.get("rolls");
if(amount instanceof Long) {
max = FastMath.toIntExact((Long) amount);
min = FastMath.toIntExact((Long) amount);
} else {
max = FastMath.toIntExact((Long) ((JSONObject) amount).get("max"));
min = FastMath.toIntExact((Long) ((JSONObject) amount).get("min"));
}
for(Object entryJSON : (JSONArray) pool.get("entries")) {
Entry entry = new Entry((JSONObject) entryJSON, main);
entries.add(entry, FastMath.toIntExact(entry.getWeight()));
}
}
/**
* Fetches a list of items from the pool using the provided Random instance.
*
* @param r The Random instance to use.
* @return List&lt;ItemStack&gt; - The list of items fetched.
*/
public List<ItemStack> getItems(Random r) {
int rolls = r.nextInt(max - min + 1) + min;
List<ItemStack> items = new GlueList<>();
for(int i = 0; i < rolls; i++) {
items.add(entries.get(r).getItem(r));
}
return items;
}
}
@@ -0,0 +1,38 @@
package com.dfsek.terra.api.structures.loot.functions;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import java.util.Random;
/**
* Loot Function fot setting the amount of an item.
*/
public class AmountFunction implements Function {
private final int max;
private final int min;
/**
* Instantiates an AmountFunction.
*
* @param min Minimum amount.
* @param max Maximum amount.
*/
public AmountFunction(int min, int max) {
this.min = min;
this.max = max;
}
/**
* Applies the function to an ItemStack.
*
* @param original The ItemStack on which to apply the function.
* @param r The Random instance to use.
* @return - ItemStack - The mutated ItemStack.
*/
@Override
public ItemStack apply(ItemStack original, Random r) {
original.setAmount(r.nextInt(max - min + 1) + min);
return original;
}
}
@@ -0,0 +1,42 @@
package com.dfsek.terra.api.structures.loot.functions;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import com.dfsek.terra.api.platform.inventory.item.Damageable;
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
import java.util.Random;
/**
* Loot Function for setting the damage on items in Loot Tables
*/
public class DamageFunction implements Function {
private final int max;
private final int min;
/**
* Instantiates a DamageFunction.
*
* @param min Minimum amount of damage (percentage, out of 100)
* @param max Maximum amount of damage (percentage, out of 100)
*/
public DamageFunction(int min, int max) {
this.min = min;
this.max = max;
}
/**
* Applies the function to an ItemStack.
*
* @param original The ItemStack on which to apply the function.
* @param r The Random instance to use.
* @return - ItemStack - The mutated ItemStack.
*/
@Override
public ItemStack apply(ItemStack original, Random r) {
double itemDurability = (r.nextDouble() * (max - min)) + min;
Damageable damage = (Damageable) original.getItemMeta();
damage.setDamage((int) (original.getType().getMaxDurability() - (itemDurability / 100) * original.getType().getMaxDurability()));
original.setItemMeta((ItemMeta) damage);
return original;
}
}
@@ -0,0 +1,20 @@
package com.dfsek.terra.api.structures.loot.functions;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import java.util.Random;
/**
* Interface for mutating items in Loot Tables.
*/
public interface Function {
/**
* Applies the function to an ItemStack.
*
* @param original The ItemStack on which to apply the function.
* @param r The Random instance to use.
* @return - ItemStack - The mutated ItemStack.
*/
ItemStack apply(ItemStack original, Random r);
}
@@ -0,0 +1,477 @@
package com.dfsek.terra.api.structures.parser;
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
import com.dfsek.terra.api.structures.parser.lang.Block;
import com.dfsek.terra.api.structures.parser.lang.Item;
import com.dfsek.terra.api.structures.parser.lang.Keyword;
import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.constants.BooleanConstant;
import com.dfsek.terra.api.structures.parser.lang.constants.ConstantExpression;
import com.dfsek.terra.api.structures.parser.lang.constants.NumericConstant;
import com.dfsek.terra.api.structures.parser.lang.constants.StringConstant;
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.api.structures.parser.lang.functions.builtin.AbsFunction;
import com.dfsek.terra.api.structures.parser.lang.functions.builtin.PowFunction;
import com.dfsek.terra.api.structures.parser.lang.functions.builtin.SqrtFunction;
import com.dfsek.terra.api.structures.parser.lang.keywords.flow.BreakKeyword;
import com.dfsek.terra.api.structures.parser.lang.keywords.flow.ContinueKeyword;
import com.dfsek.terra.api.structures.parser.lang.keywords.flow.FailKeyword;
import com.dfsek.terra.api.structures.parser.lang.keywords.flow.ReturnKeyword;
import com.dfsek.terra.api.structures.parser.lang.keywords.looplike.ForKeyword;
import com.dfsek.terra.api.structures.parser.lang.keywords.looplike.IfKeyword;
import com.dfsek.terra.api.structures.parser.lang.keywords.looplike.WhileKeyword;
import com.dfsek.terra.api.structures.parser.lang.operations.BinaryOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.BooleanAndOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.BooleanNotOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.BooleanOrOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.ConcatenationOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.DivisionOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.MultiplicationOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.NumberAdditionOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.SubtractionOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.statements.EqualsStatement;
import com.dfsek.terra.api.structures.parser.lang.operations.statements.GreaterOrEqualsThanStatement;
import com.dfsek.terra.api.structures.parser.lang.operations.statements.GreaterThanStatement;
import com.dfsek.terra.api.structures.parser.lang.operations.statements.LessThanOrEqualsStatement;
import com.dfsek.terra.api.structures.parser.lang.operations.statements.LessThanStatement;
import com.dfsek.terra.api.structures.parser.lang.operations.statements.NotEqualsStatement;
import com.dfsek.terra.api.structures.parser.lang.variables.Assignment;
import com.dfsek.terra.api.structures.parser.lang.variables.BooleanVariable;
import com.dfsek.terra.api.structures.parser.lang.variables.Getter;
import com.dfsek.terra.api.structures.parser.lang.variables.NumberVariable;
import com.dfsek.terra.api.structures.parser.lang.variables.StringVariable;
import com.dfsek.terra.api.structures.parser.lang.variables.Variable;
import com.dfsek.terra.api.structures.tokenizer.Position;
import com.dfsek.terra.api.structures.tokenizer.Token;
import com.dfsek.terra.api.structures.tokenizer.Tokenizer;
import com.dfsek.terra.api.structures.tokenizer.exceptions.TokenizerException;
import com.dfsek.terra.api.util.GlueList;
import com.google.common.collect.Sets;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SuppressWarnings("unchecked")
public class Parser {
private final String data;
private final Map<String, FunctionBuilder<? extends Function<?>>> functions = new HashMap<>();
private final Set<String> builtinFunctions = Sets.newHashSet("abs", "sqrt", "pow");
private String id;
public Parser(String data) {
this.data = data;
}
public Parser addFunction(String name, FunctionBuilder<? extends Function<?>> functionBuilder) {
functions.put(name, functionBuilder);
return this;
}
public String getID() {
return id;
}
/**
* Parse input
*
* @return executable {@link Block}
* @throws ParseException If parsing fails.
*/
public Block parse() throws ParseException {
Tokenizer tokenizer = new Tokenizer(data);
TokenHolder tokens = new TokenHolder();
try {
Token t = tokenizer.fetch();
while(t != null) {
tokens.add(t);
t = tokenizer.fetch();
}
} catch(TokenizerException e) {
throw new ParseException("Failed to tokenize input", new Position(0, 0), e);
}
// Parse ID
ParserUtil.checkType(tokens.consume(), Token.Type.ID); // First token must be ID
Token idToken = tokens.get();
ParserUtil.checkType(tokens.consume(), Token.Type.STRING); // Second token must be string literal containing ID
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
this.id = idToken.getContent();
// Check for dangling brackets
int blockLevel = 0;
for(Token t : tokens.getTokens()) {
if(t.getType().equals(Token.Type.BLOCK_BEGIN)) blockLevel++;
else if(t.getType().equals(Token.Type.BLOCK_END)) blockLevel--;
if(blockLevel < 0) throw new ParseException("Dangling closing brace", t.getPosition());
}
if(blockLevel != 0)
throw new ParseException("Dangling opening brace", tokens.getTokens().get(tokens.getTokens().size() - 1).getPosition());
return parseBlock(tokens, new HashMap<>(), false);
}
private Keyword<?> parseLoopLike(TokenHolder tokens, Map<String, Variable<?>> variableMap, boolean loop) throws ParseException {
Token identifier = tokens.consume();
ParserUtil.checkType(identifier, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP);
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN);
switch(identifier.getType()) {
case FOR_LOOP:
return parseForLoop(tokens, variableMap, identifier.getPosition());
case IF_STATEMENT:
return parseIfStatement(tokens, variableMap, identifier.getPosition(), loop);
case WHILE_LOOP:
return parseWhileLoop(tokens, variableMap, identifier.getPosition());
default:
throw new UnsupportedOperationException("Unknown keyword " + identifier.getContent() + ": " + identifier.getPosition());
}
}
private WhileKeyword parseWhileLoop(TokenHolder tokens, Map<String, Variable<?>> variableMap, Position start) throws ParseException {
Returnable<?> first = parseExpression(tokens, true, variableMap);
ParserUtil.checkReturnType(first, Returnable.ReturnType.BOOLEAN);
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
return new WhileKeyword(parseStatementBlock(tokens, variableMap, true), (Returnable<Boolean>) first, start); // While loop
}
private IfKeyword parseIfStatement(TokenHolder tokens, Map<String, Variable<?>> variableMap, Position start, boolean loop) throws ParseException {
Returnable<?> condition = parseExpression(tokens, true, variableMap);
ParserUtil.checkReturnType(condition, Returnable.ReturnType.BOOLEAN);
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
Block elseBlock = null;
Block statement = parseStatementBlock(tokens, variableMap, loop);
List<IfKeyword.Pair<Returnable<Boolean>, Block>> elseIf = new GlueList<>();
while(tokens.hasNext() && tokens.get().getType().equals(Token.Type.ELSE)) {
tokens.consume(); // Consume else.
if(tokens.get().getType().equals(Token.Type.IF_STATEMENT)) {
tokens.consume(); // Consume if.
Returnable<?> elseCondition = parseExpression(tokens, true, variableMap);
ParserUtil.checkReturnType(elseCondition, Returnable.ReturnType.BOOLEAN);
elseIf.add(new IfKeyword.Pair<>((Returnable<Boolean>) elseCondition, parseStatementBlock(tokens, variableMap, loop)));
} else {
elseBlock = parseStatementBlock(tokens, variableMap, loop);
break; // Else must be last.
}
}
return new IfKeyword(statement, (Returnable<Boolean>) condition, elseIf, elseBlock, start); // If statement
}
private Block parseStatementBlock(TokenHolder tokens, Map<String, Variable<?>> variableMap, boolean loop) throws ParseException {
if(tokens.get().getType().equals(Token.Type.BLOCK_BEGIN)) {
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_BEGIN);
Block block = parseBlock(tokens, variableMap, loop);
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_END);
return block;
} else {
Position position = tokens.get().getPosition();
Block block = new Block(Collections.singletonList(parseItem(tokens, variableMap, loop)), position);
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
return block;
}
}
private ForKeyword parseForLoop(TokenHolder tokens, Map<String, Variable<?>> old, Position start) throws ParseException {
Map<String, Variable<?>> variableMap = new HashMap<>(old); // New scope
Token f = tokens.get();
ParserUtil.checkType(f, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.IDENTIFIER);
Item<?> initializer;
if(f.isVariableDeclaration()) {
Variable<?> forVar = parseVariableDeclaration(tokens, ParserUtil.getVariableReturnType(f));
ParserUtil.checkType(tokens.consume(), Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
Token name = tokens.get();
if(functions.containsKey(name.getContent()) || variableMap.containsKey(name.getContent()) || builtinFunctions.contains(name.getContent()))
throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition());
initializer = parseAssignment(forVar, tokens, variableMap);
variableMap.put(name.getContent(), forVar);
} else initializer = parseExpression(tokens, true, variableMap);
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
Returnable<?> conditional = parseExpression(tokens, true, variableMap);
ParserUtil.checkReturnType(conditional, Returnable.ReturnType.BOOLEAN);
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
Item<?> incrementer;
Token token = tokens.get();
if(variableMap.containsKey(token.getContent())) { // Assume variable assignment
Variable<?> variable = variableMap.get(token.getContent());
incrementer = parseAssignment(variable, tokens, variableMap);
} else incrementer = parseFunction(tokens, true, variableMap);
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
return new ForKeyword(parseStatementBlock(tokens, variableMap, true), initializer, (Returnable<Boolean>) conditional, incrementer, start);
}
private Returnable<?> parseExpression(TokenHolder tokens, boolean full, Map<String, Variable<?>> variableMap) throws ParseException {
boolean booleanInverted = false; // Check for boolean not operator
if(tokens.get().getType().equals(Token.Type.BOOLEAN_NOT)) {
booleanInverted = true;
tokens.consume();
}
Token id = tokens.get();
ParserUtil.checkType(id, Token.Type.IDENTIFIER, Token.Type.BOOLEAN, Token.Type.STRING, Token.Type.NUMBER, Token.Type.GROUP_BEGIN);
Returnable<?> expression;
if(id.isConstant()) {
expression = parseConstantExpression(tokens);
} else if(id.getType().equals(Token.Type.GROUP_BEGIN)) { // Parse grouped expression
expression = parseGroup(tokens, variableMap);
} else {
if(functions.containsKey(id.getContent()) || builtinFunctions.contains(id.getContent()))
expression = parseFunction(tokens, false, variableMap);
else if(variableMap.containsKey(id.getContent())) {
ParserUtil.checkType(tokens.consume(), Token.Type.IDENTIFIER);
expression = new Getter(variableMap.get(id.getContent()));
} else throw new ParseException("Unexpected token \" " + id.getContent() + "\"", id.getPosition());
}
if(booleanInverted) { // Invert operation if boolean not detected
ParserUtil.checkReturnType(expression, Returnable.ReturnType.BOOLEAN);
expression = new BooleanNotOperation((Returnable<Boolean>) expression, expression.getPosition());
}
if(full && tokens.get().isBinaryOperator()) { // Parse binary operations
return parseBinaryOperation(expression, tokens, variableMap);
}
return expression;
}
private ConstantExpression<?> parseConstantExpression(TokenHolder tokens) throws ParseException {
Token constantToken = tokens.consume();
Position position = constantToken.getPosition();
switch(constantToken.getType()) {
case NUMBER:
String content = constantToken.getContent();
return new NumericConstant(content.contains(".") ? Double.parseDouble(content) : Integer.parseInt(content), position);
case STRING:
return new StringConstant(constantToken.getContent(), position);
case BOOLEAN:
return new BooleanConstant(Boolean.parseBoolean(constantToken.getContent()), position);
default:
throw new UnsupportedOperationException("Unsupported constant token: " + constantToken.getType() + " at position: " + position);
}
}
private Returnable<?> parseGroup(TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN);
Returnable<?> expression = parseExpression(tokens, true, variableMap); // Parse inside of group as a separate expression
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
return expression;
}
private BinaryOperation<?, ?> parseBinaryOperation(Returnable<?> left, TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
Token binaryOperator = tokens.consume();
ParserUtil.checkBinaryOperator(binaryOperator);
Returnable<?> right = parseExpression(tokens, false, variableMap);
Token other = tokens.get();
if(ParserUtil.hasPrecedence(binaryOperator.getType(), other.getType())) {
return assemble(left, parseBinaryOperation(right, tokens, variableMap), binaryOperator);
} else if(other.isBinaryOperator()) {
return parseBinaryOperation(assemble(left, right, binaryOperator), tokens, variableMap);
}
return assemble(left, right, binaryOperator);
}
private BinaryOperation<?, ?> assemble(Returnable<?> left, Returnable<?> right, Token binaryOperator) throws ParseException {
if(binaryOperator.isStrictNumericOperator())
ParserUtil.checkArithmeticOperation(left, right, binaryOperator); // Numeric type checking
if(binaryOperator.isStrictBooleanOperator()) ParserUtil.checkBooleanOperation(left, right, binaryOperator); // Boolean type checking
switch(binaryOperator.getType()) {
case ADDITION_OPERATOR:
if(left.returnType().equals(Returnable.ReturnType.NUMBER) && right.returnType().equals(Returnable.ReturnType.NUMBER)) {
return new NumberAdditionOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
}
return new ConcatenationOperation((Returnable<Object>) left, (Returnable<Object>) right, binaryOperator.getPosition());
case SUBTRACTION_OPERATOR:
return new SubtractionOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
case MULTIPLICATION_OPERATOR:
return new MultiplicationOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
case DIVISION_OPERATOR:
return new DivisionOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
case EQUALS_OPERATOR:
return new EqualsStatement((Returnable<Object>) left, (Returnable<Object>) right, binaryOperator.getPosition());
case NOT_EQUALS_OPERATOR:
return new NotEqualsStatement((Returnable<Object>) left, (Returnable<Object>) right, binaryOperator.getPosition());
case GREATER_THAN_OPERATOR:
return new GreaterThanStatement((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
case LESS_THAN_OPERATOR:
return new LessThanStatement((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
case GREATER_THAN_OR_EQUALS_OPERATOR:
return new GreaterOrEqualsThanStatement((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
case LESS_THAN_OR_EQUALS_OPERATOR:
return new LessThanOrEqualsStatement((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
case BOOLEAN_AND:
return new BooleanAndOperation((Returnable<Boolean>) left, (Returnable<Boolean>) right, binaryOperator.getPosition());
case BOOLEAN_OR:
return new BooleanOrOperation((Returnable<Boolean>) left, (Returnable<Boolean>) right, binaryOperator.getPosition());
default:
throw new UnsupportedOperationException("Unsupported binary operator: " + binaryOperator.getType());
}
}
private Variable<?> parseVariableDeclaration(TokenHolder tokens, Returnable.ReturnType type) throws ParseException {
ParserUtil.checkVarType(tokens.get(), type); // Check for type mismatch
switch(type) {
case NUMBER:
return new NumberVariable(0d, tokens.get().getPosition());
case STRING:
return new StringVariable("", tokens.get().getPosition());
case BOOLEAN:
return new BooleanVariable(false, tokens.get().getPosition());
}
throw new UnsupportedOperationException("Unsupported variable type: " + type);
}
private Block parseBlock(TokenHolder tokens, Map<String, Variable<?>> superVars, boolean loop) throws ParseException {
List<Item<?>> parsedItems = new GlueList<>();
Map<String, Variable<?>> parsedVariables = new HashMap<>(superVars); // New hashmap as to not mutate parent scope's declarations.
Token first = tokens.get();
while(tokens.hasNext()) {
Token token = tokens.get();
if(token.getType().equals(Token.Type.BLOCK_END)) break; // Stop parsing at block end.
parsedItems.add(parseItem(tokens, parsedVariables, loop));
if(tokens.hasNext() && !token.isLoopLike()) ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
}
return new Block(parsedItems, first.getPosition());
}
private Item<?> parseItem(TokenHolder tokens, Map<String, Variable<?>> variableMap, boolean loop) throws ParseException {
Token token = tokens.get();
if(loop) ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP,
Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.RETURN, Token.Type.BREAK, Token.Type.CONTINUE, Token.Type.FAIL);
else ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP,
Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.RETURN, Token.Type.FAIL);
if(token.isLoopLike()) { // Parse loop-like tokens (if, while, etc)
return parseLoopLike(tokens, variableMap, loop);
} else if(token.isIdentifier()) { // Parse identifiers
if(variableMap.containsKey(token.getContent())) { // Assume variable assignment
Variable<?> variable = variableMap.get(token.getContent());
return parseAssignment(variable, tokens, variableMap);
} else return parseFunction(tokens, true, variableMap);
} else if(token.isVariableDeclaration()) {
Variable<?> temp = parseVariableDeclaration(tokens, ParserUtil.getVariableReturnType(token));
ParserUtil.checkType(tokens.consume(), Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
Token name = tokens.get();
ParserUtil.checkType(name, Token.Type.IDENTIFIER); // Name must be an identifier.
if(functions.containsKey(name.getContent()) || variableMap.containsKey(name.getContent()) || builtinFunctions.contains(name.getContent()))
throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition());
variableMap.put(name.getContent(), temp);
return parseAssignment(temp, tokens, variableMap);
} else if(token.getType().equals(Token.Type.RETURN)) return new ReturnKeyword(tokens.consume().getPosition());
else if(token.getType().equals(Token.Type.BREAK)) return new BreakKeyword(tokens.consume().getPosition());
else if(token.getType().equals(Token.Type.CONTINUE)) return new ContinueKeyword(tokens.consume().getPosition());
else if(token.getType().equals(Token.Type.FAIL)) return new FailKeyword(tokens.consume().getPosition());
else throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition());
}
private Assignment<?> parseAssignment(Variable<?> variable, TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
Token name = tokens.get();
ParserUtil.checkType(tokens.consume(), Token.Type.IDENTIFIER);
ParserUtil.checkType(tokens.consume(), Token.Type.ASSIGNMENT);
Returnable<?> expression = parseExpression(tokens, true, variableMap);
ParserUtil.checkReturnType(expression, variable.getType());
return new Assignment<>((Variable<Object>) variable, (Returnable<Object>) expression, name.getPosition());
}
private Function<?> parseFunction(TokenHolder tokens, boolean fullStatement, Map<String, Variable<?>> variableMap) throws ParseException {
Token identifier = tokens.consume();
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); // First token must be identifier
if(!functions.containsKey(identifier.getContent()) && !builtinFunctions.contains(identifier.getContent()))
throw new ParseException("No such function \"" + identifier.getContent() + "\"", identifier.getPosition());
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN); // Second is body begin
List<Returnable<?>> args = getArgs(tokens, variableMap); // Extract arguments, consume the rest.
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); // Remove body end
if(fullStatement) ParserUtil.checkType(tokens.get(), Token.Type.STATEMENT_END);
if(functions.containsKey(identifier.getContent())) {
FunctionBuilder<?> builder = functions.get(identifier.getContent());
if(builder.argNumber() != -1 && args.size() != builder.argNumber())
throw new ParseException("Expected " + builder.argNumber() + " arguments, found " + args.size(), identifier.getPosition());
for(int i = 0; i < args.size(); i++) {
Returnable<?> argument = args.get(i);
if(builder.getArgument(i) == null)
throw new ParseException("Unexpected argument at position " + i + " in function " + identifier.getContent(), identifier.getPosition());
ParserUtil.checkReturnType(argument, builder.getArgument(i));
}
return builder.build(args, identifier.getPosition());
} else {
switch(identifier.getContent()) {
case "abs":
ParserUtil.checkReturnType(args.get(0), Returnable.ReturnType.NUMBER);
if(args.size() != 1)
throw new ParseException("Expected 1 argument; found " + args.size(), identifier.getPosition());
return new AbsFunction(identifier.getPosition(), (Returnable<Number>) args.get(0));
case "sqrt":
ParserUtil.checkReturnType(args.get(0), Returnable.ReturnType.NUMBER);
if(args.size() != 1)
throw new ParseException("Expected 1 argument; found " + args.size(), identifier.getPosition());
return new SqrtFunction(identifier.getPosition(), (Returnable<Number>) args.get(0));
case "pow":
ParserUtil.checkReturnType(args.get(0), Returnable.ReturnType.NUMBER);
ParserUtil.checkReturnType(args.get(1), Returnable.ReturnType.NUMBER);
if(args.size() != 2)
throw new ParseException("Expected 1 argument; found " + args.size(), identifier.getPosition());
return new PowFunction(identifier.getPosition(), (Returnable<Number>) args.get(0), (Returnable<Number>) args.get(1));
default:
throw new UnsupportedOperationException("Unsupported function: " + identifier.getContent());
}
}
}
private List<Returnable<?>> getArgs(TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
List<Returnable<?>> args = new GlueList<>();
while(!tokens.get().getType().equals(Token.Type.GROUP_END)) {
args.add(parseExpression(tokens, true, variableMap));
ParserUtil.checkType(tokens.get(), Token.Type.SEPARATOR, Token.Type.GROUP_END);
if(tokens.get().getType().equals(Token.Type.SEPARATOR)) tokens.consume();
}
return args;
}
}
@@ -0,0 +1,88 @@
package com.dfsek.terra.api.structures.parser;
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.tokenizer.Token;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ParserUtil {
private static final Map<Token.Type, List<Token.Type>> PRECEDENCE = new HashMap<>();
private static final List<Token.Type> ARITHMETIC = Arrays.asList(Token.Type.ADDITION_OPERATOR, Token.Type.SUBTRACTION_OPERATOR, Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR);
private static final List<Token.Type> COMPARISON = Arrays.asList(Token.Type.EQUALS_OPERATOR, Token.Type.NOT_EQUALS_OPERATOR, Token.Type.LESS_THAN_OPERATOR, Token.Type.LESS_THAN_OR_EQUALS_OPERATOR, Token.Type.GREATER_THAN_OPERATOR, Token.Type.GREATER_THAN_OR_EQUALS_OPERATOR);
static { // Setup precedence
PRECEDENCE.put(Token.Type.ADDITION_OPERATOR, Arrays.asList(Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR));
PRECEDENCE.put(Token.Type.SUBTRACTION_OPERATOR, Arrays.asList(Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR));
PRECEDENCE.put(Token.Type.EQUALS_OPERATOR, ARITHMETIC);
PRECEDENCE.put(Token.Type.NOT_EQUALS_OPERATOR, ARITHMETIC);
PRECEDENCE.put(Token.Type.GREATER_THAN_OPERATOR, ARITHMETIC);
PRECEDENCE.put(Token.Type.GREATER_THAN_OR_EQUALS_OPERATOR, ARITHMETIC);
PRECEDENCE.put(Token.Type.LESS_THAN_OPERATOR, ARITHMETIC);
PRECEDENCE.put(Token.Type.LESS_THAN_OR_EQUALS_OPERATOR, ARITHMETIC);
PRECEDENCE.put(Token.Type.BOOLEAN_AND, COMPARISON);
PRECEDENCE.put(Token.Type.BOOLEAN_OR, COMPARISON);
}
public static void checkType(Token token, Token.Type... expected) throws ParseException {
for(Token.Type type : expected) if(token.getType().equals(type)) return;
throw new ParseException("Expected " + Arrays.toString(expected) + " but found " + token.getType(), token.getPosition());
}
public static void checkReturnType(Returnable<?> returnable, Returnable.ReturnType... types) throws ParseException {
for(Returnable.ReturnType type : types) if(returnable.returnType().equals(type)) return;
throw new ParseException("Expected " + Arrays.toString(types) + " but found " + returnable.returnType(), returnable.getPosition());
}
public static void checkArithmeticOperation(Returnable<?> left, Returnable<?> right, Token operation) throws ParseException {
if(!left.returnType().equals(Returnable.ReturnType.NUMBER) || !right.returnType().equals(Returnable.ReturnType.NUMBER)) {
throw new ParseException("Operation " + operation.getType() + " not supported between " + left.returnType() + " and " + right.returnType(), operation.getPosition());
}
}
public static void checkBooleanOperation(Returnable<?> left, Returnable<?> right, Token operation) throws ParseException {
if(!left.returnType().equals(Returnable.ReturnType.BOOLEAN) || !right.returnType().equals(Returnable.ReturnType.BOOLEAN)) {
throw new ParseException("Operation " + operation.getType() + " not supported between " + left.returnType() + " and " + right.returnType(), operation.getPosition());
}
}
public static void checkVarType(Token token, Returnable.ReturnType returnType) throws ParseException {
if(returnType.equals(Returnable.ReturnType.STRING) && token.getType().equals(Token.Type.STRING_VARIABLE)) return;
if(returnType.equals(Returnable.ReturnType.NUMBER) && token.getType().equals(Token.Type.NUMBER_VARIABLE)) return;
if(returnType.equals(Returnable.ReturnType.BOOLEAN) && token.getType().equals(Token.Type.BOOLEAN_VARIABLE)) return;
throw new ParseException("Type mismatch, cannot convert from " + returnType + " to " + token.getType(), token.getPosition());
}
/**
* Checks if token is a binary operator
*
* @param token Token to check
* @throws ParseException If token isn't a binary operator
*/
public static void checkBinaryOperator(Token token) throws ParseException {
if(!token.isBinaryOperator())
throw new ParseException("Expected binary operator, found " + token.getType(), token.getPosition());
}
public static Returnable.ReturnType getVariableReturnType(Token varToken) throws ParseException {
switch(varToken.getType()) {
case NUMBER_VARIABLE:
return Returnable.ReturnType.NUMBER;
case STRING_VARIABLE:
return Returnable.ReturnType.STRING;
case BOOLEAN_VARIABLE:
return Returnable.ReturnType.BOOLEAN;
default:
throw new ParseException("Unexpected token " + varToken.getType() + "; expected variable declaration", varToken.getPosition());
}
}
public static boolean hasPrecedence(Token.Type first, Token.Type second) {
if(!PRECEDENCE.containsKey(first)) return false;
return PRECEDENCE.get(first).contains(second);
}
}
@@ -0,0 +1,59 @@
package com.dfsek.terra.api.structures.parser;
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
import com.dfsek.terra.api.structures.tokenizer.Position;
import com.dfsek.terra.api.structures.tokenizer.Token;
import com.dfsek.terra.api.util.GlueList;
import java.util.List;
/**
* Data structure to hold tokens, where items are inserted at the top and removed from the bottom.
*/
public class TokenHolder {
private final List<Token> tokens = new GlueList<>();
private Position last;
/**
* Add a token to the top of the stack.
*
* @param token Token to add
*/
public void add(Token token) {
tokens.add(token);
}
/**
* Get the token at the bottom of the stack.
*
* @return First token
* @throws ParseException If stack is empty
*/
public Token get() throws ParseException {
if(!hasNext()) throw new ParseException("Unexpected end of input", last);
Token token = tokens.get(0);
last = token.getPosition();
return token;
}
/**
* Consume (get and remove) the token at the bottom of the stack.
*
* @return First token
* @throws ParseException If stack is empty
*/
public Token consume() throws ParseException {
if(!hasNext()) throw new ParseException("Unexpected end of input", last);
Token token = tokens.remove(0);
last = token.getPosition();
return token;
}
public List<Token> getTokens() {
return tokens;
}
public boolean hasNext() {
return tokens.size() > 0;
}
}
@@ -0,0 +1,26 @@
package com.dfsek.terra.api.structures.parser.exceptions;
import com.dfsek.terra.api.structures.tokenizer.Position;
public class ParseException extends Exception {
private final Position position;
public ParseException(String message, Position position) {
super(message);
this.position = position;
}
public ParseException(String message, Position position, Throwable cause) {
super(message, cause);
this.position = position;
}
@Override
public String getMessage() {
return super.getMessage() + ": " + position;
}
public Position getPosition() {
return position;
}
}
@@ -0,0 +1,71 @@
package com.dfsek.terra.api.structures.parser.lang;
import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.structure.buffer.Buffer;
import com.dfsek.terra.api.structures.tokenizer.Position;
import java.util.List;
import java.util.Random;
public class Block implements Item<Block.ReturnInfo<?>> {
private final List<Item<?>> items;
private final Position position;
public Block(List<Item<?>> items, Position position) {
this.items = items;
this.position = position;
}
public List<Item<?>> getItems() {
return items;
}
@Override
public synchronized ReturnInfo<?> apply(Buffer buffer, Rotation rotation, Random random, int recursions) {
for(Item<?> item : items) {
Object result = item.apply(buffer, rotation, random, recursions);
if(result instanceof ReturnInfo) {
ReturnInfo<?> level = (ReturnInfo<?>) result;
if(!level.getLevel().equals(ReturnLevel.NONE)) return level;
}
}
return new ReturnInfo<>(ReturnLevel.NONE, null);
}
@Override
public Position getPosition() {
return position;
}
public static class ReturnInfo<T> {
private final ReturnLevel level;
private final T data;
public ReturnInfo(ReturnLevel level, T data) {
this.level = level;
this.data = data;
}
public ReturnLevel getLevel() {
return level;
}
public T getData() {
return data;
}
}
public enum ReturnLevel {
NONE(false), BREAK(false), CONTINUE(false), RETURN(true), FAIL(true);
private final boolean returnFast;
ReturnLevel(boolean returnFast) {
this.returnFast = returnFast;
}
public boolean isReturnFast() {
return returnFast;
}
}
}
@@ -0,0 +1,13 @@
package com.dfsek.terra.api.structures.parser.lang;
import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.structure.buffer.Buffer;
import com.dfsek.terra.api.structures.tokenizer.Position;
import java.util.Random;
public interface Item<T> {
T apply(Buffer buffer, Rotation rotation, Random random, int recursions);
Position getPosition();
}
@@ -0,0 +1,4 @@
package com.dfsek.terra.api.structures.parser.lang;
public interface Keyword<T> extends Returnable<T> {
}
@@ -0,0 +1,19 @@
package com.dfsek.terra.api.structures.parser.lang;
public interface Returnable<T> extends Item<T> {
ReturnType returnType();
enum ReturnType {
NUMBER(true), STRING(true), BOOLEAN(false), VOID(false), OBJECT(false);
private final boolean comparable;
ReturnType(boolean comparable) {
this.comparable = comparable;
}
public boolean isComparable() {
return comparable;
}
}
}

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