Compare commits

..

210 Commits

Author SHA1 Message Date
dfsek ed2fa85d81 cache value of ModDependentConfigSection 2021-06-01 01:33:54 -07:00
dfsek 788a3c2d48 switch to namespace based injection 2021-06-01 01:27:30 -07:00
dfsek 1bd5cf31fa move compat options to compat.yml 2021-06-01 01:16:52 -07:00
dfsek bb2601252a add ConfigPackLoadEvent#getLoader 2021-06-01 01:09:51 -07:00
dfsek 0600176e31 override entity spawning stuff 2021-05-28 13:34:12 -07:00
dfsek 51c51111a2 improve fabric/forge getHeight impl 2021-05-27 19:46:05 -07:00
dfsek d3e4270f44 cleanup ModDependentConfigSectionLoader 2021-05-27 19:27:15 -07:00
dfsek 4f3f555aa0 fix stronghold gen with vanilla.structures 2021-05-27 19:14:25 -07:00
dfsek cf0d5cd99c register mod dependent loader in GenericLoaders 2021-05-23 22:40:38 -07:00
dfsek e3bbedb56b make compat options mod dependent 2021-05-23 22:38:41 -07:00
dfsek 3f37907256 implement ModDependentConfigSection#withDefault 2021-05-23 15:57:36 -07:00
dfsek 486dcfc63d implement ModDependentConfigSection 2021-05-22 23:23:59 -07:00
dfsek 34947c2168 implement TerraPlugin#getMods 2021-05-22 23:09:30 -07:00
dfsek fa164e5281 Merge pull request #199 from PolyhedralDev/dev/forge-tweaks
Forge Tweaks
2021-05-22 21:48:12 -07:00
dfsek ec3b0e5d04 implement vanilla mob override 2021-05-22 21:37:16 -07:00
dfsek 4c63c2681f implement ForgeChunkGeneratorWrapper#getBaseColumn 2021-05-22 21:34:28 -07:00
dfsek dd661feaf1 implement dimension type injection/caching 2021-05-22 21:24:25 -07:00
dfsek 1f17bfff1b delegate strongholds to vanilla if vanilla structures are enabled 2021-05-22 21:12:44 -07:00
dfsek 809a0b375d implement identifier loader 2021-05-22 21:11:52 -07:00
dfsek d55b3415ac implement structure locate override on Forge 2021-05-22 21:08:51 -07:00
dfsek edcb818842 basic compatibility stuff on Forge 2021-05-22 18:03:34 -07:00
dfsek 1e429e1bb3 create forge compatibility configs 2021-05-22 17:11:50 -07:00
dfsek 3472859afb remove unused event handlers 2021-05-22 17:10:50 -07:00
dfsek 26025ec276 remove unused class 2021-05-22 00:19:38 -07:00
dfsek 3b3905b513 mixin injection on client in forge 2021-05-21 23:36:20 -07:00
dfsek ce3d09cf2e add background to pack selection GUI 2021-05-19 09:23:20 -07:00
dfsek 5dd00db8d2 Merge pull request #191 from PolyhedralDev/dev/fabric-compat
Options for mod compatibility on Fabric
2021-05-18 20:07:24 -07:00
dfsek 2dc7b50141 implement getColumnSample 2021-05-18 19:50:05 -07:00
dfsek b2ebcc63aa Merge remote-tracking branch 'origin/dev/fabric-compat' into dev/fabric-compat 2021-05-18 18:26:34 -07:00
dfsek f45bc0a0cc Merge remote-tracking branch 'origin/dev/fabric-compat' into dev/fabric-compat 2021-05-18 18:25:46 -07:00
dfsek bbe53cbca3 fix height again 2021-05-18 18:25:31 -07:00
dfsek 7354155c52 bump version 2021-05-18 18:19:25 -07:00
dfsek c1acfee910 Merge pull request #189 from Shadowhackercz/master
Creating new locale for Czech
2021-05-18 17:56:31 -07:00
dfsek 5287323865 only inject carvers if vanilla.caves is enabled 2021-05-18 09:24:20 -07:00
dfsek b09d0e42aa fix biome specific exclusions 2021-05-18 09:06:43 -07:00
dfsek a3f14061dd fix structure location 2021-05-17 23:04:21 -07:00
dfsek 557098de17 use debug logger for feature info 2021-05-17 22:48:03 -07:00
dfsek 2fdb96a850 cleanup and add per-biome exclusions 2021-05-17 22:45:39 -07:00
dfsek d93d064d97 fix getHeight 2021-05-17 20:50:27 -07:00
dfsek ae76fb7dc4 use dimensiontype to get world 2021-05-17 20:16:32 -07:00
dfsek 2626afd066 override entity generation 2021-05-17 19:41:45 -07:00
dfsek c0042cfb6b switch to DimensionType map 2021-05-17 19:39:46 -07:00
dfsek a549d2ef34 move client init code to MinecraftClientMixin 2021-05-17 19:26:25 -07:00
dfsek 4aa20c32b8 fix fabric debuglogger 2021-05-17 17:35:56 -07:00
dfsek ce7033b4ca filter out non-Terra biomes in TerraBiomeSource 2021-05-17 10:07:22 -07:00
dfsek 41a54f4b25 vanilla structures 2021-05-17 10:07:06 -07:00
dfsek f96740f1fa refactor util classes 2021-05-17 08:38:03 -07:00
Shadowhacker 8844cd5069 Creating new locale for Czech
I've created a new localization file for Czech language
2021-05-17 03:53:07 +02:00
dfsek 800d846af4 carver and structure compatibility options 2021-05-16 16:47:17 -07:00
dfsek 95d50a0391 resolve merge conflicts 2021-05-16 00:42:29 -07:00
dfsek 5a83eab1fe Merge remote-tracking branch 'origin/master' into dev/fabric-compat
# Conflicts:
#	platforms/fabric/src/main/java/com/dfsek/terra/fabric/TerraFabricPlugin.java
#	platforms/forge/src/main/java/com/dfsek/terra/forge/TerraForgePlugin.java
2021-05-16 00:34:42 -07:00
dfsek bac026a1f4 Merge pull request #187 from PolyhedralDev/dev/fabric-no-api
Remove dependency on Fabric API
2021-05-15 21:18:27 -07:00
dfsek 65482c493a remove dependency on Fabric API 2021-05-15 20:30:06 -07:00
dfsek a05f837ca2 Merge pull request #183 from PolyhedralDev/dev/cleanup/gradleproperties
Update mod description and use Gradle properties so we dont forget some platforms if we change things in the future
2021-05-15 14:20:44 -07:00
dfsek 6fbb5d712e add license, wiki, source and issue URLs to properties 2021-05-14 23:30:36 -07:00
dfsek 2c9d195474 remove unused command from bukkit manifest 2021-05-14 23:09:21 -07:00
dfsek b663d34320 add DESCRIPTION to processResources 2021-05-14 23:09:08 -07:00
dfsek 43095d0df1 add version stuff to plugin/mod manifests 2021-05-14 23:05:22 -07:00
dfsek 47e0dc862c add Terra description and mod ID to gradle.properties 2021-05-14 23:02:14 -07:00
dfsek 460b11b9c8 Merge pull request #182 from PolyhedralDev/dev/forge-mixins
Mixinify Forge implementation and fix several issues on Forge
2021-05-14 22:40:05 -07:00
dfsek d974a72cb9 fix commands on forge 2021-05-14 22:36:55 -07:00
dfsek e86f37fdfb Forge build hacks 2021-05-14 22:30:27 -07:00
dfsek 2ed120dc4c forge cleanup 2021-05-14 19:15:13 -07:00
dfsek 973ae785f4 Forge server fixes 2021-05-14 18:40:03 -07:00
dfsek 4835813e2e fix chunk generator reset on forge 2021-05-14 18:25:28 -07:00
dfsek 632409050b Merge remote-tracking branch 'origin/master' into dev/forge-mixins
# Conflicts:
#	gradle.properties
2021-05-14 17:47:50 -07:00
dfsek 9d991dbb97 Merge pull request #181 from PolyhedralDev/dev/fabric-worldedit
Implement WorldEdit integration for structure exporting on Fabric
2021-05-14 09:38:13 -07:00
dfsek cddf7c20e4 bump version 2021-05-13 22:10:35 -07:00
dfsek 5fd2fc59f4 worldedit integration on Fabric 2021-05-13 21:28:49 -07:00
dfsek 97d7ccacbf add worldedit dependency 2021-05-13 18:15:07 -07:00
dfsek 242e56b1d8 conditional biome injection 2021-05-12 09:27:20 -07:00
dfsek 4c7aa11353 clean up TerraFabricPlugin 2021-05-12 08:39:43 -07:00
dfsek cac84ffe03 fix typo 2021-05-12 00:55:14 -07:00
dfsek cf66e1e226 registry injection 2021-05-12 00:53:25 -07:00
dfsek fa647e1e2c make loadConfig less jank 2021-05-12 00:48:38 -07:00
dfsek 4203121d40 basic feature loading implementation 2021-05-12 00:33:00 -07:00
dfsek 82fe6d5aa4 add api to load custom values from pack manifest. 2021-05-12 00:09:21 -07:00
dfsek 32db83f091 remove NotNullValidator 2021-05-11 23:56:08 -07:00
dfsek 0ab949174a Update README.md 2021-05-11 16:06:37 -07:00
dfsek 2bfaa95a81 add forge disclaimer to README 2021-05-11 16:03:32 -07:00
dfsek 96de1554f1 disable configureondemand 2021-05-11 15:56:53 -07:00
dfsek f83dcd802c Merge remote-tracking branch 'origin/master' 2021-05-11 09:03:14 -07:00
dfsek 808aa50f5f update config.yml 2021-05-11 09:02:59 -07:00
dfsek e00271e493 Merge pull request #162 from PolyhedralDev/dev/fabric-late-init
initialize later
2021-05-10 23:14:57 -07:00
dfsek 76bf245e16 type check ChunkGenerator in PopulatorFeature 2021-05-10 22:52:34 -07:00
dfsek 37e441206a fix getHandle overwrite conflicts and annotate getHandle methods as @Intrinsic. 2021-05-10 01:11:22 -07:00
dfsek 5376f7e22e fix server init 2021-05-10 01:03:13 -07:00
dfsek 1186fc6624 bump version 2021-05-05 15:24:55 -07:00
dfsek a1b3680643 initialize later 2021-05-05 15:22:02 -07:00
dfsek 501399919f implement vanilla carver/structure options on Fabric & Forge (we will still yell at you if you use them) 2021-05-04 22:40:37 -07:00
dfsek 725d57d967 rename mixins for mojmap 2021-05-04 22:35:30 -07:00
dfsek a821501392 refactor forge stuff 2021-05-04 22:09:50 -07:00
dfsek d3458148bd default disable forge registry dump 2021-05-04 21:38:44 -07:00
dfsek df4da810ec fix forge mixin issues 2021-05-04 21:37:36 -07:00
dfsek 8f47c84c8e fix forge builds 2021-05-04 21:29:07 -07:00
dfsek f61a544a57 account for null ignored in StructureLocateEvent 2021-05-04 20:32:22 -07:00
dfsek 3217d66c69 forge mixins (probably dont work yet) 2021-05-04 19:22:10 -07:00
dfsek fd48f5f110 Merge pull request #158 from PolyhedralDev/dev/fabric-locate
Override structure location on Fabric
2021-05-04 16:45:25 -07:00
dfsek 77a4c95c4a override structure location on Fabric 2021-05-04 16:44:43 -07:00
dfsek dbc60b1d82 Merge pull request #153 from PolyhedralDev/dev/fabric-mixins
Implement Terra interfaces directly in Minecraft classes using Mixin.
2021-05-04 16:16:31 -07:00
dfsek ed942bb997 update README.md 2021-05-04 16:13:05 -07:00
dfsek 6866084872 SignBlockEntityMixin cleanup 2021-05-04 16:10:37 -07:00
dfsek 4c77419dcd fix sign getText on server 2021-05-04 15:04:53 -07:00
dfsek ecba6e0843 Merge remote-tracking branch 'origin/dev/fabric-mixins' into dev/fabric-mixins 2021-05-04 09:21:21 -07:00
dfsek 86dcb476f1 update README with modern build instructions and Forge download links 2021-05-04 09:21:12 -07:00
dfsek 13e0857882 merge FabricEnumAdapter into FabricAdapter 2021-05-03 22:49:21 -07:00
dfsek bf93a9239c bump version 2021-05-03 22:28:01 -07:00
dfsek 2d18aab709 fix funky yaml formatting 2021-05-03 22:13:42 -07:00
dfsek a1359da374 terrascript trig functions 2021-05-03 22:13:32 -07:00
dfsek f7bda835f9 fix itemmeta application 2021-05-03 20:52:03 -07:00
dfsek 7595896831 fix refmap issues 2021-05-03 20:40:56 -07:00
dfsek 6614d19845 suppress warnings 2021-05-03 20:14:06 -07:00
dfsek 6209b86560 mixin maintenance 2021-05-03 20:12:48 -07:00
dfsek a30859a3d4 dont try to remap Terra interfaces 2021-05-03 20:08:13 -07:00
dfsek ddbb46289b add package-info.java to implementation mixin package. 2021-05-03 20:03:25 -07:00
dfsek 64c35a9609 refactor Fabric project 2021-05-03 20:02:08 -07:00
dfsek f21069ab2e fix cache misses 2021-05-03 19:43:52 -07:00
dfsek 457729b832 replace most access wideners with mixins 2021-05-03 19:33:57 -07:00
dfsek 756f04a0b3 implement LockableContainerBlockEntityMixin 2021-05-03 18:38:40 -07:00
dfsek 5ee32cc3ba add ConfiguredFeatureMixin 2021-05-03 17:35:43 -07:00
dfsek 955558bc21 implement BlockMixin 2021-05-03 11:37:54 -07:00
dfsek c43a872c23 finish blockstate mixins 2021-05-03 11:27:36 -07:00
dfsek de41b92d5d add SignBlockEntityMixin 2021-05-03 10:27:40 -07:00
dfsek 03091230ed refactor mixins 2021-05-03 10:09:21 -07:00
dfsek a8c88915ea override chunkregion hashcode 2021-05-02 23:39:40 -07:00
dfsek 4cd4720101 fix loot NPE 2021-05-02 23:08:54 -07:00
dfsek 3b9280b19c start work on state mixins 2021-05-02 23:00:21 -07:00
dfsek 2d27e07441 implement BiomeMixin 2021-05-02 22:49:57 -07:00
dfsek 20a5762d2e refactor mixins 2021-05-02 22:48:21 -07:00
dfsek 146f71f704 finish World mixins 2021-05-02 22:45:34 -07:00
dfsek 1d4b0bc100 cleanup 2021-05-02 22:26:23 -07:00
dfsek 138ee0a448 refactor fabric handles 2021-05-02 22:22:32 -07:00
dfsek 2c8cae9d45 create ChunkGeneratorMixin 2021-05-02 22:21:50 -07:00
dfsek 061d2b6493 implement EntityTypeMixin 2021-05-02 21:48:06 -07:00
dfsek e71df936ab EnchantmentMixin 2021-05-02 21:35:39 -07:00
dfsek f4253acb78 item mixins 2021-05-02 21:27:25 -07:00
dfsek c12518fa49 delete FabricItem.java 2021-05-02 21:11:09 -07:00
dfsek 4704b2ebf7 implement ItemMixin 2021-05-02 21:10:48 -07:00
dfsek 89fdfdfb34 suppress warnings 2021-05-02 20:42:54 -07:00
dfsek 35d85f2aa3 PlayerEntityMixin and EntityMixin 2021-05-02 20:38:25 -07:00
dfsek c0368f1c6d implement ServerCommandSourceMixin 2021-05-02 20:17:59 -07:00
dfsek abc069046c add ProtoChunkMixin and WorldChunkMixin 2021-05-02 20:13:24 -07:00
dfsek 46d0b08068 implement ChunkRegionMixin 2021-05-02 19:49:59 -07:00
dfsek a7e3a0286e add -forge and -fabric to Modrinth version numbers. 2021-05-02 17:46:55 -07:00
dfsek 6da8924868 Merge pull request #145 from PolyhedralDev/dev/forge
Forge implementation
2021-05-02 17:38:56 -07:00
dfsek d9dd6afe4b Merge pull request #143 from solonovamax/improvement/better-gradle-performance
Improve gradle performance significantly
2021-05-02 17:37:36 -07:00
dfsek dfec26f789 fix forge modrinth task 2021-05-02 17:21:05 -07:00
dfsek d13be5e159 add Forge modrinth publish task 2021-05-02 17:16:03 -07:00
dfsek 51c5f70d64 forge jarfile nightmare "solution" 2021-05-02 17:08:59 -07:00
dfsek 05b1902c06 Merge pull request #151 from DJtheRedstoner/patch-mixin-ap
Fix mixin annotation processor issues
2021-05-02 15:47:32 -07:00
dfsek f4ae2cac68 add MixinGeneratorOptions 2021-05-02 15:46:03 -07:00
dfsek ea3995afce fix refmap name 2021-05-02 15:44:30 -07:00
dfsek c41d60c38f remove manual refmap 2021-05-02 15:43:12 -07:00
DJtheRedstoner 19edcbddd5 Fix mixin annotation processor issues
These issues were caused by CompilationConfig.configureCompilation()
overwriting JavaCompile's options.compilerArgs list which removed any
previously added arguments, including those added by fabric-loom and
mixingradle.
2021-05-02 18:17:18 -04:00
dfsek 4f65555e82 remove mixins until annotation processor gets fixed. 2021-05-02 14:37:34 -07:00
dfsek 9956cab507 dont use vanilla registries 2021-05-01 22:21:27 -07:00
dfsek fddf0c51b7 cleanup PopulationManager 2021-05-01 20:27:59 -07:00
dfsek e2a52afb67 remove methods only used for cursed Bukkit stuff from common World interface. 2021-05-01 19:07:19 -07:00
dfsek c8c3a33912 fix loot table issue 2021-05-01 18:40:31 -07:00
dfsek b178f69e47 Merge remote-tracking branch 'origin/dev/forge' into dev/forge 2021-05-01 18:20:23 -07:00
dfsek 049a56fcb0 Mixin on Forge 2021-05-01 18:20:11 -07:00
solonovamax 2d41dd8f08 Don't use all cores processors for tests
Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>
2021-05-01 16:53:45 -04:00
solonovamax aa9e33af1d Remove old and deprecated compile configuration + some minor refactoring
Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>
2021-05-01 16:53:45 -04:00
dfsek 02870805c7 hoist calculations in chunk generator 2021-04-30 09:35:15 -07:00
dfsek e493825ab7 bump version 2021-04-30 09:25:56 -07:00
dfsek 762b248641 update to latest Tectonic 2021-04-29 23:42:56 -07:00
dfsek f81ccee020 cleanup 2021-04-29 23:31:03 -07:00
dfsek 3561e5f30f commands on Forge 2021-04-29 23:19:49 -07:00
dfsek c67817b9d2 fix structure issues 2021-04-29 22:00:40 -07:00
dfsek 756619edb6 Forge actually loads to worlds now 2021-04-29 21:48:32 -07:00
dfsek ee1c889d54 world screen type 2021-04-29 21:11:26 -07:00
dfsek 9f3dcf07b6 Pack loading on Forge 2021-04-29 20:30:48 -07:00
dfsek 93a2f103f7 add pack.mcmeta 2021-04-29 16:41:14 -07:00
dfsek 3ea12ceeab start implementing terraplugin 2021-04-29 12:30:17 -07:00
dfsek ce8ec51ae4 forge actually loads now 2021-04-29 12:24:29 -07:00
dfsek 54bb4ef109 sort of working Forge project 2021-04-29 01:55:24 -07:00
dfsek 59b655ce5d working forge buildscript 2021-04-29 01:27:28 -07:00
solonovamax 4c1e1bb7d5 Improve gradle performance significantly
Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>
2021-04-28 20:43:53 -04:00
dfsek eee54f507e Merge pull request #138 from PolyhedralDev/dev/profilerimpl
Fancy stack-based profiler
2021-04-26 21:32:42 -07:00
dfsek 6f1b1611ab fix dumb gradle issue 2021-04-26 21:26:44 -07:00
dfsek 205499220d profile more things 2021-04-26 20:59:21 -07:00
dfsek a0c5631eba bump version 2021-04-26 20:46:36 -07:00
dfsek 9323abc788 document Profiler 2021-04-26 19:04:20 -07:00
dfsek 632f898dc8 implement Profiler#reset 2021-04-26 19:01:53 -07:00
dfsek 8737b0d984 resolve merge conflict 2021-04-25 17:12:42 -07:00
dfsek bcb68853d5 @SuppressWarnings go brrr 2021-04-25 17:11:50 -07:00
dfsek 8823d6d65e fix stack size assumption at profiler start 2021-04-25 17:11:50 -07:00
dfsek 5d3a2b6e84 profile more things 2021-04-25 17:11:50 -07:00
dfsek 23fb7753ab fancy unicode symbols B) 2021-04-25 17:11:50 -07:00
dfsek f8e7e343cb fix % parent issue 2021-04-25 17:11:50 -07:00
dfsek e5f4c5dc8d implement terrascript profiling 2021-04-25 17:11:49 -07:00
dfsek 8a10867e5f implement new profiler 2021-04-25 17:11:04 -07:00
dfsek da366a75e8 add autocloseable option 2021-04-25 17:09:08 -07:00
dfsek eb4bf74cc6 implement TerraPlugin#getProfier 2021-04-25 17:09:08 -07:00
dfsek 168c0ced13 improve performance in deep operations 2021-04-25 17:09:07 -07:00
dfsek 5d4bdb431b improve data output 2021-04-25 17:09:07 -07:00
dfsek 40188c671f basic profiler implementation 2021-04-25 17:09:07 -07:00
dfsek f396e0e5eb Merge pull request #133 from PolyhedralDev/ver/5.1.4
Fix minor Fabric issues
2021-04-16 09:01:29 -07:00
dfsek 942a8c9c8b Merge pull request #131 from xieve/fix-disable-config
Fixed populator disable config (#130)
2021-04-15 10:29:20 -07:00
dfsek 414dcdae3e use vanilla delegate spawn rules 2021-04-15 10:20:14 -07:00
dfsek 1195a6676f implement getHeight on Fabric 2021-04-15 10:00:22 -07:00
dfsek 5501f53056 implement TerraFabricPlugin#getWorld(long) 2021-04-15 09:59:13 -07:00
xieve 41d6e1c648 Fixed populator disable config (#130) 2021-04-15 18:18:27 +02:00
dfsek 5ac7257517 Merge pull request #119 from PolyhedralDev/ver/5.1.3
Fix Fabric Physics, add "dead" entry checking to registries.
2021-04-11 18:56:25 -07:00
dfsek 9f4f9702a6 bump version 2021-04-11 17:54:07 -07:00
dfsek 01d169256e properly relocate dependencies 2021-04-11 17:49:39 -07:00
dfsek 7a703ad091 add publication config to Fabric 2021-04-11 14:15:13 -07:00
dfsek ce9273c7e8 proper fluid updating on Fabric 2021-04-11 00:45:53 -07:00
dfsek 653a414ac1 should(tm) fix fabric physics 2021-04-10 23:49:02 -07:00
dfsek 2080db21ca warn about dead registry entries when debug mode is enabled 2021-04-10 19:22:41 -07:00
246 changed files with 6734 additions and 2869 deletions
+1 -1
View File
@@ -342,6 +342,6 @@ ij_json_wrap_long_lines = false
indent_size = 2
ij_yaml_keep_indents_on_empty_lines = true
ij_yaml_keep_line_breaks = true
ij_yaml_space_before_colon = true
ij_yaml_space_before_colon = false
ij_yaml_spaces_within_braces = true
ij_yaml_spaces_within_brackets = true
+25 -14
View File
@@ -7,29 +7,40 @@ to your specifications, with no knowledge of Java required.
* Paper+ servers (Paper, Tuinity, Purpur, etc): [SpigotMC](https://www.spigotmc.org/resources/85151/)
* Fabric: [Modrinth](https://modrinth.com/mod/terra) / [CurseForge](https://www.curseforge.com/minecraft/mc-mods/terra-world-generator)
* Forge **(ALPHA - NOT PRODUCTION-READY)**: [Modrinth](https://modrinth.com/mod/terra) / [CurseForge](https://www.curseforge.com/minecraft/mc-mods/terra-world-generator)
## Licensing
## Building and Running Terra
Terra as a whole is licensed under the GNU General Public License, version 3.0. Terra's API is licensed under the GNU Lesser General Public
License, version 3.0, in order to allow linking to the API without GPL infection.
To build, simply run `./gradlew build` (`gradlew.bat build` on Windows). This will build all platforms, and
produce JARs in `platforms/<platform>/build/libs`
## Building and running Terra
### Production JARs:
* Bukkit: `Terra-<version>-shaded.jar`
* Fabric: `Terra-<version>-shaded-mapped.jar`
* Forge: `Terra-<version>-shaded.jar`
To build, simply run `./gradlew build` (`gradlew.bat build` on Windows). This will produce a jar in `build/libs`
called `Terra-[CURRENT VERSION].jar`. You can put this right into your plugins dir, along with the correct Gaea version.
### Building a Specific Platform
To build a specific platform, run `gradlew :platforms:<platform>:build`.
If you would like to test it with a default server config, just run `./gradlew setupServer` or
`./gradlew.bat setupServer` to set up the server, then `./gradlew testWithPaper` or `gradlew.bat testWithPaper` to run the server. If you
want a clean installation of the server, re-run the `setupServer` task. This will download a default server config
from [here](https://github.com/PolyhedralDev/WorldGenTestServer)
and install the server in the `target/server` directory, along with all the needed plugins.
**Note: You will need to adjust the `NAME` variable `bukkit.yml` of the test server if you are not using the default Terra config.**
JARs are produced in `platforms/<platform>/build/libs`.
### Running Minecraft in the IDE
To run Minecraft with Terra in the IDE (for testing) use the following tasks:
* Bukkit
* `installPaper` - Install a [Paper](https://github.com/PaperMC/Paper) test server. (Only needs to be run once).
* `installPurpur` - Install a [Purpur](https://github.com/pl3xgaming/Purpur) test server. (Only needs to be run once).
* `runPaper` - Run the Paper test server with Terra (`installPaper` must have been run previously).
* `runPurpur` - Run the Purpur test server with Terra (`installPurpur` must have been run previously).
* Fabric
* `runClient` - Run a Minecraft Fabric client with Terra installed.
* `runServer` - Run a Minecraft Fabric server with Terra installed.
* Forge
* `runClient` - Run a Minecraft Forge client with Terra installed.
* `runServer` - Run a Minecraft Forge server with Terra installed.
## Contributing
Contributions are welcome! If you want to see a feature in Terra, please, open an issue, or implement it yourself and
submit a PR!
Join the discord [here](https://discord.gg/PXUEbbF) if you would like to talk more about the project!
## Beta
Terra is still in beta! While it is stable, it is not feature-complete. There is a lot to be added!
Terra is still in beta! While it is stable, it is not feature-complete. There is a lot to be added!
+18 -1
View File
@@ -1,10 +1,27 @@
import com.dfsek.terra.getGitHash
val versionObj = Version("5", "1", "2", true)
val versionObj = Version("5", "3", "3", true)
allprojects {
version = versionObj
group = "com.dfsek.terra"
tasks.withType<JavaCompile>().configureEach {
options.isFork = true
options.isIncremental = true
}
tasks.withType<Test>().configureEach {
useJUnitPlatform()
maxHeapSize = "2G"
ignoreFailures = false
failFast = true
maxParallelForks = (Runtime.getRuntime().availableProcessors() - 1).takeIf { it > 0 } ?: 1
reports.html.isEnabled = false
reports.junitXml.isEnabled = false
}
}
/**
* Version class that does version stuff.
@@ -7,26 +7,11 @@ 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 {
@@ -3,14 +3,16 @@ 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.bundling.Jar
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.filter
import org.gradle.kotlin.dsl.withType
import org.gradle.kotlin.dsl.*
import org.gradle.language.jvm.tasks.ProcessResources
fun Project.configureCompilation() {
apply(plugin = "maven-publish")
apply(plugin = "idea")
configure<JavaPluginConvention> {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
@@ -19,7 +21,7 @@ fun Project.configureCompilation() {
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
doFirst {
options.compilerArgs = mutableListOf("-Xlint:all")
options.compilerArgs.add("-Xlint:all")
}
}
@@ -27,7 +29,12 @@ fun Project.configureCompilation() {
include("**/*.*")
filter<org.apache.tools.ant.filters.ReplaceTokens>(
"tokens" to mapOf(
"VERSION" to project.version.toString()
"VERSION" to project.version.toString(),
"DESCRIPTION" to project.properties["terra.description"],
"WIKI" to project.properties["terra.wiki"],
"SOURCE" to project.properties["terra.source"],
"ISSUES" to project.properties["terra.issues"],
"LICENSE" to project.properties["terra.license"]
)
)
}
@@ -35,4 +42,19 @@ fun Project.configureCompilation() {
tasks.withType<Javadoc> {
options.encoding = "UTF-8"
}
tasks.withType<Jar> {
archiveBaseName.set("Terra-${archiveBaseName.get()}")
from("../LICENSE", "../../LICENSE")
}
tasks.register<Jar>("sourcesJar") {
archiveClassifier.set("sources")
}
tasks.register<Jar>("javadocJar") {
dependsOn("javadoc")
archiveClassifier.set("javadoc")
from(tasks.getByName<Javadoc>("javadoc").destinationDir)
}
}
@@ -1,13 +1,27 @@
package com.dfsek.terra
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.invoke
import org.gradle.kotlin.dsl.repositories
fun Project.configureDependencies() {
apply(plugin = "java")
apply(plugin = "java-library")
configurations {
val shaded = create("shaded")
val shadedApi = create("shadedApi")
shaded.extendsFrom(shadedApi)
getByName("api").extendsFrom(shadedApi)
val shadedImplementation = create("shadedImplementation")
shaded.extendsFrom(shadedImplementation)
getByName("implementation").extendsFrom(shadedImplementation)
}
repositories {
maven { url = uri("http://maven.enginehub.org/repo/") }
maven { url = uri("https://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/") }
@@ -18,9 +32,7 @@ fun Project.configureDependencies() {
dependencies {
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.7.0")
"testImplementation"("org.yaml:snakeyaml:1.27")
"testImplementation"("com.googlecode.json-simple:json-simple:1.1.1")
"testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.7.0")
"compileOnly"("org.jetbrains:annotations:20.1.0")
"testImplementation"("org.junit.jupiter:junit-jupiter-engine:5.7.0")
"api"("org.jetbrains:annotations:20.1.0")
}
}
@@ -14,17 +14,6 @@ fun Project.configureDistribution() {
apply(plugin = "java-library")
apply(plugin = "com.github.johnrengelman.shadow")
configurations {
val shaded = create("shaded")
getByName("compile").extendsFrom(shaded)
val shadedApi = create("shadedApi")
shaded.extendsFrom(shadedApi)
getByName("api").extendsFrom(shadedApi)
val shadedImplementation = create("shadedImplementation")
shaded.extendsFrom(shadedImplementation)
getByName("implementation").extendsFrom(shadedImplementation)
}
val downloadDefaultPacks = tasks.create("downloadDefaultPacks") {
group = "terra"
doFirst {
@@ -38,21 +27,6 @@ fun Project.configureDistribution() {
}
tasks["processResources"].dependsOn(downloadDefaultPacks)
tasks.withType<Jar> {
archiveBaseName.set("Terra-${archiveBaseName.get()}")
from("../LICENSE", "../../LICENSE")
}
tasks.register<Jar>("sourcesJar") {
archiveClassifier.set("sources")
}
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)
@@ -62,8 +36,14 @@ fun Project.configureDistribution() {
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")
relocate("org.objectweb.asm", "com.dfsek.terra.lib.asm")
relocate("com.google.errorprone", "com.dfsek.terra.lib.google.errorprone")
relocate("com.google.j2objc", "com.dfsek.terra.lib.google.j2objc")
relocate("org.checkerframework", "com.dfsek.terra.lib.checkerframework")
relocate("org.javax.annotation", "com.dfsek.terra.lib.javax.annotation")
relocate("org.json", "com.dfsek.terra.lib.json")
relocate("org.yaml", "com.dfsek.terra.lib.yaml")
minimize()
}
convention.getPlugin<BasePluginConvention>().archivesBaseName = project.name
+8 -4
View File
@@ -1,11 +1,14 @@
import com.dfsek.terra.configureCommon
import com.dfsek.terra.configureCompilation
import com.dfsek.terra.configureDependencies
plugins {
`java-library`
`maven-publish`
idea
}
configureCommon()
configureCompilation()
configureDependencies()
group = "com.dfsek.terra.common"
@@ -14,13 +17,14 @@ dependencies {
"shadedApi"("commons-io:commons-io:2.4")
"shadedApi"("com.dfsek:Paralithic:0.3.2")
"shadedApi"("com.dfsek:Tectonic:1.2.3")
"shadedApi"("com.dfsek:Tectonic:1.3.1")
"shadedApi"("net.jafama:jafama:2.3.2")
"shadedApi"("org.yaml:snakeyaml:1.27")
"shadedApi"("org.ow2.asm:asm:9.0")
"shadedApi"("commons-io:commons-io:2.6")
"compileOnly"("com.googlecode.json-simple:json-simple:1.1")
"shadedApi"("com.googlecode.json-simple:json-simple:1.1.1")
"shadedApi"("org.yaml:snakeyaml:1.27")
"compileOnly"("com.google.guava:guava:30.0-jre")
@@ -1,165 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
@@ -4,17 +4,25 @@ import com.dfsek.terra.api.addons.TerraAddon;
import com.dfsek.terra.api.event.EventManager;
import com.dfsek.terra.api.platform.handle.ItemHandle;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.modloader.Mod;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.LockedRegistry;
import com.dfsek.terra.api.util.JarUtil;
import com.dfsek.terra.api.util.logging.DebugLogger;
import com.dfsek.terra.api.util.logging.Logger;
import com.dfsek.terra.config.PluginConfig;
import com.dfsek.terra.config.lang.Language;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.profiler.Profiler;
import com.dfsek.terra.world.TerraWorld;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Set;
import java.util.jar.JarFile;
/**
* Represents a Terra mod/plugin instance.
@@ -64,4 +72,14 @@ public interface TerraPlugin extends LoaderRegistrar {
default void runPossiblyUnsafeTask(Runnable task) {
task.run();
}
Profiler getProfiler();
default JarFile getModJar() throws URISyntaxException, IOException {
return JarUtil.getJarFile();
}
default Set<Mod> getMods() {
return Collections.emptySet();
}
}
@@ -65,7 +65,7 @@ public class TerraCommandManager implements CommandManager {
return;
}
if(commandClass.isAnnotationPresent(WorldCommand.class) && (!(sender instanceof Player) || !TerraWorld.isTerraWorld(((Player) sender).getWorld()))) {
if(commandClass.isAnnotationPresent(WorldCommand.class) && (!(sender instanceof Player) || !(((Player) sender).getWorld()).isTerraWorld())) {
sender.sendMessage("Command must be executed in a Terra world.");
return;
}
@@ -1,6 +1,9 @@
package com.dfsek.terra.api.event.events.config;
import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.terra.api.event.events.PackEvent;
import com.dfsek.terra.config.fileloaders.Loader;
import com.dfsek.terra.config.pack.ConfigPack;
/**
@@ -8,13 +11,34 @@ import com.dfsek.terra.config.pack.ConfigPack;
*/
public abstract class ConfigPackLoadEvent implements PackEvent {
private final ConfigPack pack;
private final ExceptionalConsumer<ConfigTemplate> configLoader;
private final Loader loader;
public ConfigPackLoadEvent(ConfigPack pack) {
public ConfigPackLoadEvent(ConfigPack pack, ExceptionalConsumer<ConfigTemplate> configLoader, Loader loader) {
this.pack = pack;
this.configLoader = configLoader;
this.loader = loader;
}
@Override
public ConfigPack getPack() {
return pack;
}
/**
* Load a custom {@link ConfigTemplate} using the pack manifest.
*
* @param template Template to register.
*/
public void loadTemplate(ConfigTemplate template) throws ConfigException {
configLoader.accept(template);
}
public interface ExceptionalConsumer<T extends ConfigTemplate> {
void accept(T value) throws ConfigException;
}
public Loader getLoader() {
return loader;
}
}
@@ -1,12 +1,14 @@
package com.dfsek.terra.api.event.events.config;
import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.terra.config.fileloaders.Loader;
import com.dfsek.terra.config.pack.ConfigPack;
/**
* Called when a config pack has finished loading.
*/
public class ConfigPackPostLoadEvent extends ConfigPackLoadEvent {
public ConfigPackPostLoadEvent(ConfigPack pack) {
super(pack);
public ConfigPackPostLoadEvent(ConfigPack pack, ExceptionalConsumer<ConfigTemplate> configTemplateLoader, Loader loader) {
super(pack, configTemplateLoader, loader);
}
}
@@ -1,12 +1,14 @@
package com.dfsek.terra.api.event.events.config;
import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.terra.config.fileloaders.Loader;
import com.dfsek.terra.config.pack.ConfigPack;
/**
* Called before a config pack's registries are filled. At this point, the pack manifest has been loaded, and all registries are empty.
*/
public class ConfigPackPreLoadEvent extends ConfigPackLoadEvent {
public ConfigPackPreLoadEvent(ConfigPack pack) {
super(pack);
public ConfigPackPreLoadEvent(ConfigPack pack, ExceptionalConsumer<ConfigTemplate> configLoader, Loader loader) {
super(pack, configLoader, loader);
}
}
@@ -1,6 +1,7 @@
package com.dfsek.terra.api.platform.inventory;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.inventory.item.Damageable;
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
public interface ItemStack extends Handle {
@@ -13,4 +14,8 @@ public interface ItemStack extends Handle {
ItemMeta getItemMeta();
void setItemMeta(ItemMeta meta);
default boolean isDamageable() {
return getItemMeta() instanceof Damageable;
}
}
@@ -0,0 +1,9 @@
package com.dfsek.terra.api.platform.modloader;
public interface Mod {
String getID();
String getVersion();
String getName();
}
@@ -6,6 +6,8 @@ import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import java.io.File;
import java.util.UUID;
@@ -17,20 +19,12 @@ public interface World extends Handle {
ChunkGenerator getGenerator();
String getName();
UUID getUID();
boolean isChunkGenerated(int x, int z);
Chunk getChunkAt(int x, int z);
default Chunk getChunkAt(Location location) {
return getChunkAt(location.getBlockX() >> 4, location.getBlockZ() >> 4);
}
File getWorldFolder();
Block getBlockAt(int x, int y, int z);
default Block getBlockAt(Location l) {
@@ -40,4 +34,12 @@ public interface World extends Handle {
Entity spawnEntity(Location location, EntityType entityType);
int getMinHeight();
default boolean isTerraWorld() {
return getGenerator().getHandle() instanceof GeneratorWrapper;
}
default TerraChunkGenerator getTerraGenerator() {
return ((GeneratorWrapper) getGenerator().getHandle()).getHandle();
}
}
@@ -34,8 +34,8 @@ public class DamageFunction implements LootFunction {
@Override
public ItemStack apply(ItemStack original, Random r) {
if(original == null) return null;
if(!original.isDamageable()) return original;
ItemMeta meta = original.getItemMeta();
if(!(meta instanceof Damageable)) return original;
double itemDurability = (r.nextDouble() * (max - min)) + min;
Damageable damage = (Damageable) meta;
damage.setDamage((int) (original.getType().getMaxDurability() - (itemDurability / 100) * original.getType().getMaxDurability()));
@@ -29,6 +29,7 @@ import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.structure.buffer.Buffer;
import com.dfsek.terra.api.structures.structure.buffer.DirectBuffer;
import com.dfsek.terra.api.structures.structure.buffer.StructureBuffer;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.registry.config.FunctionRegistry;
import com.dfsek.terra.registry.config.LootRegistry;
import com.dfsek.terra.registry.config.ScriptRegistry;
@@ -39,6 +40,7 @@ import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Random;
import java.util.concurrent.ExecutionException;
@@ -52,7 +54,7 @@ public class StructureScript {
public StructureScript(InputStream inputStream, TerraPlugin main, ScriptRegistry registry, LootRegistry lootRegistry, FunctionRegistry functionRegistry) throws ParseException {
Parser parser;
try {
parser = new Parser(IOUtils.toString(inputStream));
parser = new Parser(IOUtils.toString(inputStream, Charset.defaultCharset()));
} catch(IOException e) {
throw new RuntimeException(e);
}
@@ -87,6 +89,12 @@ public class StructureScript {
.registerFunction("ceil", new UnaryNumberFunctionBuilder(number -> FastMath.ceil(number.doubleValue())))
.registerFunction("log", new UnaryNumberFunctionBuilder(number -> FastMath.log(number.doubleValue())))
.registerFunction("round", new UnaryNumberFunctionBuilder(number -> FastMath.round(number.doubleValue())))
.registerFunction("sin", new UnaryNumberFunctionBuilder(number -> FastMath.sin(number.doubleValue())))
.registerFunction("cos", new UnaryNumberFunctionBuilder(number -> FastMath.cos(number.doubleValue())))
.registerFunction("tan", new UnaryNumberFunctionBuilder(number -> FastMath.tan(number.doubleValue())))
.registerFunction("asin", new UnaryNumberFunctionBuilder(number -> FastMath.asin(number.doubleValue())))
.registerFunction("acos", new UnaryNumberFunctionBuilder(number -> FastMath.acos(number.doubleValue())))
.registerFunction("atan", new UnaryNumberFunctionBuilder(number -> FastMath.atan(number.doubleValue())))
.registerFunction("max", new BinaryNumberFunctionBuilder((number, number2) -> FastMath.max(number.doubleValue(), number2.doubleValue())))
.registerFunction("min", new BinaryNumberFunctionBuilder((number, number2) -> FastMath.min(number.doubleValue(), number2.doubleValue())));
@@ -104,22 +112,31 @@ public class StructureScript {
* @param rotation Rotation of structure
* @return Whether generation was successful
*/
@SuppressWarnings("try")
public boolean execute(Location location, Random random, Rotation rotation) {
StructureBuffer buffer = new StructureBuffer(location);
boolean level = applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
buffer.paste();
return level;
try(ProfileFrame ignore = main.getProfiler().profile("terrascript:" + id)) {
StructureBuffer buffer = new StructureBuffer(location);
boolean level = applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
buffer.paste();
return level;
}
}
@SuppressWarnings("try")
public boolean execute(Location location, Chunk chunk, Random random, Rotation rotation) {
StructureBuffer buffer = computeBuffer(location, random, rotation);
buffer.paste(chunk);
return buffer.succeeded();
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_chunk:" + id)) {
StructureBuffer buffer = computeBuffer(location, random, rotation);
buffer.paste(chunk);
return buffer.succeeded();
}
}
@SuppressWarnings("try")
public boolean test(Location location, Random random, Rotation rotation) {
StructureBuffer buffer = computeBuffer(location, random, rotation);
return buffer.succeeded();
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_test:" + id)) {
StructureBuffer buffer = computeBuffer(location, random, rotation);
return buffer.succeeded();
}
}
private StructureBuffer computeBuffer(Location location, Random random, Rotation rotation) {
@@ -134,13 +151,19 @@ public class StructureScript {
}
}
@SuppressWarnings("try")
public boolean executeInBuffer(Buffer buffer, Random random, Rotation rotation, int recursions) {
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, recursions));
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_recursive:" + id)) {
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, recursions));
}
}
@SuppressWarnings("try")
public boolean executeDirect(Location location, Random random, Rotation rotation) {
DirectBuffer buffer = new DirectBuffer(location);
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_direct:" + id)) {
DirectBuffer buffer = new DirectBuffer(location);
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
}
}
public String getId() {
@@ -19,6 +19,6 @@ public class BufferedEntity implements BufferedItem {
@Override
public void paste(Location origin) {
Entity entity = origin.clone().add(0.5, 0, 0.5).getWorld().spawnEntity(origin, type);
main.getEventManager().callEvent(new EntitySpawnEvent(main.getWorld(entity.getWorld()).getGenerator().getConfigPack(), entity, entity.getLocation()));
main.getEventManager().callEvent(new EntitySpawnEvent(entity.getWorld().getTerraGenerator().getConfigPack(), entity, entity.getLocation()));
}
}
@@ -32,7 +32,7 @@ public class BufferedLootApplication implements BufferedItem {
}
Container container = (Container) data;
LootPopulateEvent event = new LootPopulateEvent(block, container, table, main.getWorld(block.getLocation().getWorld()).getGenerator().getConfigPack(), structure);
LootPopulateEvent event = new LootPopulateEvent(block, container, table, block.getLocation().getWorld().getTerraGenerator().getConfigPack(), structure);
main.getEventManager().callEvent(event);
if(event.isCancelled()) return;
@@ -40,7 +40,7 @@ public class BufferedLootApplication implements BufferedItem {
data.update(false);
} catch(Exception e) {
main.logger().warning("Could not apply loot at " + origin + ": " + e.getMessage());
main.getDebugLogger().stack(e);
e.printStackTrace();
}
}
}
@@ -21,7 +21,7 @@ public class BufferedStateManipulator implements BufferedItem {
state.update(false);
} catch(Exception e) {
main.logger().warning("Could not apply BlockState at " + origin + ": " + e.getMessage());
main.getDebugLogger().stack(e);
e.printStackTrace();
}
}
}
@@ -1,8 +0,0 @@
package com.dfsek.terra.api.transform;
public class NotNullValidator<T> implements Validator<T> {
@Override
public boolean validate(T value) {
return !(value == null);
}
}
@@ -53,6 +53,7 @@ public class Transformer<F, T> {
private final LinkedHashMap<Transform<F, T>, List<Validator<T>>> transforms = new LinkedHashMap<>();
@SafeVarargs
@SuppressWarnings("varargs")
public final Builder<F, T> addTransform(Transform<F, T> transform, Validator<T>... validators) {
transforms.put(transform, Arrays.asList(validators));
return this;
@@ -1,6 +1,12 @@
package com.dfsek.terra.api.transform;
import java.util.Objects;
public interface Validator<T> {
boolean validate(T value) throws TransformException;
static <T> Validator<T> notNull() {
return Objects::nonNull;
}
}
@@ -1,9 +1,13 @@
package com.dfsek.terra.api.util;
import com.dfsek.terra.api.TerraPlugin;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -32,4 +36,12 @@ public class JarUtil {
}
}
}
public static JarFile getJarFile() throws URISyntaxException, IOException {
return new JarFile(new File(getJarURL().toURI()));
}
public static URL getJarURL() {
return TerraPlugin.class.getProtectionDomain().getCodeSource().getLocation();
}
}
@@ -4,16 +4,10 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileQueryCommand implements CommandTemplate {
@Inject
@@ -21,8 +15,9 @@ public class ProfileQueryCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
player.sendMessage(world.getProfiler().getResultsFormatted());
StringBuilder data = new StringBuilder("Terra Profiler data dump: \n");
main.getProfiler().getTimings().forEach((id, timings) -> data.append(id).append(": ").append(timings.toString()).append('\n'));
main.logger().info(data.toString());
sender.sendMessage("Profiler data dumped to console.");
}
}
@@ -4,16 +4,10 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileResetCommand implements CommandTemplate {
@Inject
@@ -21,9 +15,7 @@ public class ProfileResetCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
world.getProfiler().reset();
player.sendMessage("Profiler reset.");
main.getProfiler().reset();
sender.sendMessage("Profiler reset.");
}
}
@@ -4,16 +4,10 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileStartCommand implements CommandTemplate {
@Inject
@@ -21,9 +15,7 @@ public class ProfileStartCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
world.getProfiler().setProfiling(true);
player.sendMessage("Profiling enabled.");
main.getProfiler().start();
sender.sendMessage("Profiling enabled.");
}
}
@@ -4,16 +4,10 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileStopCommand implements CommandTemplate {
@Inject
@@ -21,9 +15,7 @@ public class ProfileStopCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
world.getProfiler().setProfiling(false);
player.sendMessage("Profiling disabled.");
main.getProfiler().stop();
sender.sendMessage("Profiling disabled.");
}
}
@@ -46,6 +46,8 @@ import com.dfsek.terra.config.loaders.config.sampler.templates.ImageSamplerTempl
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.ClampNormalizerTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.LinearNormalizerTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.NormalNormalizerTemplate;
import com.dfsek.terra.config.loaders.mod.ModDependentConfigSection;
import com.dfsek.terra.config.loaders.mod.ModDependentConfigSectionLoader;
import com.dfsek.terra.config.loaders.palette.CarverPaletteLoader;
import com.dfsek.terra.config.loaders.palette.PaletteHolderLoader;
import com.dfsek.terra.config.loaders.palette.PaletteLayerLoader;
@@ -108,7 +110,8 @@ public class GenericLoaders implements LoaderRegistrar {
if(main != null) {
registry.registerLoader(TerraAddon.class, main.getAddons())
.registerLoader(BlockType.class, (t, object, cf) -> main.getWorldHandle().createBlockData((String) object).getBlockType());
.registerLoader(BlockType.class, (t, object, cf) -> main.getWorldHandle().createBlockData((String) object).getBlockType())
.registerLoader(ModDependentConfigSection.class, new ModDependentConfigSectionLoader(main));
}
}
}
@@ -69,12 +69,12 @@ public class PluginConfig implements ConfigTemplate {
ConfigLoader loader = new ConfigLoader();
loader.load(this, file);
if(dumpDefaultConfig) { // Don't dump default config if already loaded.
try(JarFile jar = new JarFile(new File(TerraPlugin.class.getProtectionDomain().getCodeSource().getLocation().toURI()))) {
try(JarFile jar = main.getModJar()) {
JarUtil.copyResourcesToDirectory(jar, "packs", new File(main.getDataFolder(), "packs").toString());
} catch(IOException | URISyntaxException e) {
main.getDebugLogger().error("Failed to dump default config files!");
e.printStackTrace();
main.getDebugLogger().error("Report this to Terra!");
main.getDebugLogger().error("Either you're on Forge, or this is a bug. If it's the latter, report this to Terra!");
}
}
} catch(ConfigException | IOException e) {
@@ -1,147 +0,0 @@
package com.dfsek.terra.config.builder;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.noise.samplers.ExpressionSampler;
import com.dfsek.terra.api.math.noise.samplers.noise.ConstantSampler;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.palette.holder.PaletteHolder;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import com.dfsek.terra.world.generation.WorldGenerator;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class GeneratorBuilder {
private final Map<Long, WorldGenerator> gens = Collections.synchronizedMap(new HashMap<>());
private String noiseEquation;
private String elevationEquation;
private String carvingEquation;
private Scope varScope;
private Map<String, NoiseSeeded> noiseBuilderMap;
private Map<String, FunctionTemplate> functionTemplateMap;
private PaletteHolder palettes;
private PaletteHolder slantPalettes;
private boolean preventInterpolation;
private boolean interpolateElevation;
private NoiseSeeded biomeNoise;
private double elevationWeight;
private int blendDistance;
private int blendStep;
private double blendWeight;
public WorldGenerator build(long seed) {
synchronized(gens) {
return gens.computeIfAbsent(seed, k -> {
NoiseSampler noise;
NoiseSampler elevation;
NoiseSampler carving;
try {
noise = new ExpressionSampler(noiseEquation, varScope, seed, noiseBuilderMap, functionTemplateMap);
elevation = elevationEquation == null ? new ConstantSampler(0) : new ExpressionSampler(elevationEquation, varScope, seed, noiseBuilderMap, functionTemplateMap);
carving = new ExpressionSampler(carvingEquation, varScope, seed, noiseBuilderMap, functionTemplateMap);
} catch(ParseException e) {
throw new RuntimeException(e);
}
return new WorldGenerator(palettes, slantPalettes, noise, elevation, carving, biomeNoise.apply(seed), elevationWeight, blendDistance, blendStep, blendWeight);
});
}
}
public void setBlendWeight(double blendWeight) {
this.blendWeight = blendWeight;
}
public void setFunctionTemplateMap(Map<String, FunctionTemplate> functionTemplateMap) {
this.functionTemplateMap = functionTemplateMap;
}
public void setBlendStep(int blendStep) {
this.blendStep = blendStep;
}
public void setBlendDistance(int blendDistance) {
this.blendDistance = blendDistance;
}
public void setBiomeNoise(NoiseSeeded biomeNoise) {
this.biomeNoise = biomeNoise;
}
public void setElevationWeight(double elevationWeight) {
this.elevationWeight = elevationWeight;
}
public void setNoiseEquation(String noiseEquation) {
this.noiseEquation = noiseEquation;
}
public void setElevationEquation(String elevationEquation) {
this.elevationEquation = elevationEquation;
}
public void setCarvingEquation(String carvingEquation) {
this.carvingEquation = carvingEquation;
}
public Scope getVarScope() {
return varScope;
}
public void setVarScope(Scope varScope) {
this.varScope = varScope;
}
public void setNoiseBuilderMap(Map<String, NoiseSeeded> noiseBuilderMap) {
this.noiseBuilderMap = noiseBuilderMap;
}
public PaletteHolder getPalettes() {
return palettes;
}
public void setPalettes(PaletteHolder palettes) {
this.palettes = palettes;
}
public PaletteHolder getSlantPalettes() {
return slantPalettes;
}
public void setSlantPalettes(PaletteHolder slantPalettes) {
this.slantPalettes = slantPalettes;
}
public boolean isPreventInterpolation() {
return preventInterpolation;
}
public void setPreventInterpolation(boolean preventInterpolation) {
this.preventInterpolation = preventInterpolation;
}
public void setInterpolateElevation(boolean interpolateElevation) {
this.interpolateElevation = interpolateElevation;
}
public boolean interpolateElevation() {
return interpolateElevation;
}
}
@@ -9,9 +9,6 @@ import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper;
import java.io.File;
import java.util.UUID;
public class DummyWorld implements World {
@Override
public Object getHandle() {
@@ -33,31 +30,11 @@ public class DummyWorld implements World {
return () -> (GeneratorWrapper) () -> null;
}
@Override
public String getName() {
return "DUMMY";
}
@Override
public UUID getUID() {
return UUID.randomUUID();
}
@Override
public boolean isChunkGenerated(int x, int z) {
return false;
}
@Override
public Chunk getChunkAt(int x, int z) {
throw new UnsupportedOperationException("Cannot get chunk in DummyWorld");
}
@Override
public File getWorldFolder() {
throw new UnsupportedOperationException("Cannot get folder of DummyWorld");
}
@Override
public Block getBlockAt(int x, int y, int z) {
throw new UnsupportedOperationException("Cannot get block in DummyWorld");
@@ -1,5 +1,6 @@
package com.dfsek.terra.config.fileloaders;
import com.dfsek.tectonic.config.Configuration;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.terra.api.util.GlueList;
@@ -18,8 +19,12 @@ public abstract class Loader {
*
* @param consumer Something to do with the streams.
*/
public Loader then(ExceptionalConsumer<List<InputStream>> consumer) throws ConfigException {
consumer.accept(new GlueList<>(streams.values()));
public Loader then(ExceptionalConsumer<List<Configuration>> consumer) throws ConfigException {
List<Configuration> list = new GlueList<>();
streams.forEach((id, stream) -> {
list.add(new Configuration(stream, id));
});
consumer.accept(list);
return this;
}
@@ -1,5 +1,6 @@
package com.dfsek.terra.config.fileloaders;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
@@ -20,7 +21,7 @@ public class ZIPLoader extends Loader {
ZipEntry entry = entries.nextElement();
if(!entry.isDirectory() && entry.getName().equals(singleFile)) return file.getInputStream(entry);
}
throw new IllegalArgumentException("No such file: " + singleFile);
throw new FileNotFoundException("No such file: " + singleFile);
}
@Override
@@ -17,7 +17,7 @@ public final class LangUtil {
public static void load(String langID, TerraPlugin main) {
Logger logger = main.logger();
File file = new File(main.getDataFolder(), "lang");
try(JarFile jar = new JarFile(new File(TerraPlugin.class.getProtectionDomain().getCodeSource().getLocation().toURI()))) {
try(JarFile jar = main.getModJar()) {
copyResourcesToDirectory(jar, "lang", file.toString());
} catch(IOException | URISyntaxException e) {
main.getDebugLogger().error("Failed to dump language files!");
@@ -18,7 +18,7 @@ public class OreHolderLoader implements TypeLoader<OreHolder> {
Map<String, Object> map = (Map<String, Object>) o;
for(Map.Entry<String, Object> entry : map.entrySet()) {
holder.add(configLoader.loadClass(Ore.class, entry.getKey()), (OreConfig) configLoader.loadType(OreConfig.class, entry.getValue()));
holder.add(configLoader.loadClass(Ore.class, entry.getKey()), configLoader.loadClass(OreConfig.class, entry.getValue()), entry.getKey());
}
return holder;
@@ -0,0 +1,46 @@
package com.dfsek.terra.config.loaders.mod;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.platform.modloader.Mod;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class ModDependentConfigSection<T> {
private static final Object NULL = new Object(); // Null object
private final TerraPlugin main;
private final Map<String, T> results = new HashMap<>();
private final T defaultValue;
@SuppressWarnings("unchecked")
private T value = (T) NULL;
protected ModDependentConfigSection(TerraPlugin main, T defaultValue) {
this.main = main;
this.defaultValue = defaultValue;
}
public void add(String id, T value) {
results.put(id, value);
}
public static <T1> ModDependentConfigSection<T1> withDefault(T1 defaultValue) {
return new ModDependentConfigSection<>(null, defaultValue);
}
public T get() {
if(value == NULL) value = compute(); // Cache the value.
return value;
}
private T compute() {
if(main != null) {
Set<String> mods = main.getMods().stream().map(Mod::getID).collect(Collectors.toSet());
for(Map.Entry<String, T> entry : results.entrySet()) {
if(mods.contains(entry.getKey())) return entry.getValue();
}
}
return defaultValue;
}
}
@@ -0,0 +1,43 @@
package com.dfsek.terra.config.loaders.mod;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import com.dfsek.terra.api.TerraPlugin;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
public class ModDependentConfigSectionLoader implements TypeLoader<ModDependentConfigSection<?>> {
private final TerraPlugin main;
public ModDependentConfigSectionLoader(TerraPlugin main) {
this.main = main;
}
@SuppressWarnings("unchecked")
@Override
public ModDependentConfigSection<?> load(Type type, Object c, ConfigLoader loader) throws LoadException {
if(type instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) type;
Type generic = pType.getActualTypeArguments()[0];
if(c instanceof Map && ((Map<?, ?>) c).containsKey("default")) {
Map<String, ?> map = (Map<String, ?>) c;
ModDependentConfigSection<Object> configSection = new ModDependentConfigSection<>(main, loader.loadType(generic, map.get("default")));
if(map.containsKey("mods")) {
for(Map.Entry<String, ?> modEntry : ((Map<String, ?>) map.get("mods")).entrySet()) {
configSection.add(modEntry.getKey(), loader.loadType(generic, modEntry.getValue()));
}
}
return configSection;
} else {
return ModDependentConfigSection.withDefault(loader.loadType(generic, c)); // Load the original type otherwise.
}
} else throw new LoadException("Unable to load config! Could not retrieve parameterized type: " + type);
}
}
@@ -2,6 +2,7 @@ package com.dfsek.terra.config.pack;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.tectonic.abstraction.AbstractConfigLoader;
import com.dfsek.tectonic.config.Configuration;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
@@ -110,6 +111,8 @@ public class ConfigPack implements LoaderRegistrar {
private final TerraPlugin main;
private final Loader loader;
private final Configuration configuration;
private final BiomeProvider.BiomeProviderBuilder biomeProviderBuilder;
@@ -130,15 +133,20 @@ public class ConfigPack implements LoaderRegistrar {
File pack = new File(folder, "pack.yml");
try {
selfLoader.load(template, new FileInputStream(pack));
configuration = new Configuration(new FileInputStream(pack));
selfLoader.load(template, configuration);
main.logger().info("Loading config pack \"" + template.getID() + "\"");
main.getEventManager().callEvent(new ConfigPackPreLoadEvent(this, template -> selfLoader.load(template, configuration), loader));
load(l, main);
ConfigPackPostTemplate packPostTemplate = new ConfigPackPostTemplate();
selfLoader.load(packPostTemplate, new FileInputStream(pack));
biomeProviderBuilder = packPostTemplate.getProviderBuilder();
biomeProviderBuilder.build(0); // Build dummy provider to catch errors at load time.
checkDeadEntries(main);
} catch(FileNotFoundException e) {
throw new LoadException("No pack.yml file found in " + folder.getAbsolutePath(), e);
}
@@ -173,9 +181,12 @@ public class ConfigPack implements LoaderRegistrar {
if(pack == null) throw new LoadException("No pack.yml file found in " + file.getName());
selfLoader.load(template, file.getInputStream(pack));
configuration = new Configuration(file.getInputStream(pack));
selfLoader.load(template, configuration);
main.logger().info("Loading config pack \"" + template.getID() + "\"");
main.getEventManager().callEvent(new ConfigPackPreLoadEvent(this, template -> selfLoader.load(template, configuration), loader));
load(l, main);
ConfigPackPostTemplate packPostTemplate = new ConfigPackPostTemplate();
@@ -183,6 +194,7 @@ public class ConfigPack implements LoaderRegistrar {
selfLoader.load(packPostTemplate, file.getInputStream(pack));
biomeProviderBuilder = packPostTemplate.getProviderBuilder();
biomeProviderBuilder.build(0); // Build dummy provider to catch errors at load time.
checkDeadEntries(main);
} catch(IOException e) {
throw new LoadException("Unable to load pack.yml from ZIP file", e);
}
@@ -198,9 +210,17 @@ public class ConfigPack implements LoaderRegistrar {
for(C template : configTemplates) registry.add(template.getID(), factory.build(template, main));
}
private void load(long start, TerraPlugin main) throws ConfigException {
main.getEventManager().callEvent(new ConfigPackPreLoadEvent(this));
private void checkDeadEntries(TerraPlugin main) {
biomeRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in biome registry: '" + id + "'"));
paletteRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in palette registry: '" + id + "'"));
floraRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in flora registry: '" + id + "'"));
carverRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in carver registry: '" + id + "'"));
treeRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in tree registry: '" + id + "'"));
oreRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in ore registry: '" + id + "'"));
}
private void load(long start, TerraPlugin main) throws ConfigException {
for(Map.Entry<String, Double> var : template.getVariables().entrySet()) {
varScope.create(var.getKey(), var.getValue());
}
@@ -225,15 +245,15 @@ public class ConfigPack implements LoaderRegistrar {
}).close();
loader
.open("carving", ".yml").then(streams -> buildAll(new CarverFactory(this), carverRegistry, abstractConfigLoader.load(streams, CarverTemplate::new), main)).close()
.open("palettes", ".yml").then(streams -> buildAll(new PaletteFactory(), paletteRegistry, abstractConfigLoader.load(streams, PaletteTemplate::new), main)).close()
.open("ores", ".yml").then(streams -> buildAll(new OreFactory(), oreRegistry, abstractConfigLoader.load(streams, OreTemplate::new), main)).close()
.open("structures/trees", ".yml").then(streams -> buildAll(new TreeFactory(), treeRegistry, abstractConfigLoader.load(streams, TreeTemplate::new), main)).close()
.open("structures/structures", ".yml").then(streams -> buildAll(new StructureFactory(), structureRegistry, abstractConfigLoader.load(streams, StructureTemplate::new), main)).close()
.open("flora", ".yml").then(streams -> buildAll(new FloraFactory(), floraRegistry, abstractConfigLoader.load(streams, FloraTemplate::new), main)).close()
.open("biomes", ".yml").then(streams -> buildAll(new BiomeFactory(this), biomeRegistry, abstractConfigLoader.load(streams, () -> new BiomeTemplate(this, main)), main)).close();
.open("carving", ".yml").then(configs -> buildAll(new CarverFactory(this), carverRegistry, abstractConfigLoader.loadConfigs(configs, CarverTemplate::new), main)).close()
.open("palettes", ".yml").then(configs -> buildAll(new PaletteFactory(), paletteRegistry, abstractConfigLoader.loadConfigs(configs, PaletteTemplate::new), main)).close()
.open("ores", ".yml").then(configs -> buildAll(new OreFactory(), oreRegistry, abstractConfigLoader.loadConfigs(configs, OreTemplate::new), main)).close()
.open("structures/trees", ".yml").then(configs -> buildAll(new TreeFactory(), treeRegistry, abstractConfigLoader.loadConfigs(configs, TreeTemplate::new), main)).close()
.open("structures/structures", ".yml").then(configs -> buildAll(new StructureFactory(), structureRegistry, abstractConfigLoader.loadConfigs(configs, StructureTemplate::new), main)).close()
.open("flora", ".yml").then(configs -> buildAll(new FloraFactory(), floraRegistry, abstractConfigLoader.loadConfigs(configs, FloraTemplate::new), main)).close()
.open("biomes", ".yml").then(configs -> buildAll(new BiomeFactory(this), biomeRegistry, abstractConfigLoader.loadConfigs(configs, () -> new BiomeTemplate(this, main)), main)).close();
main.getEventManager().callEvent(new ConfigPackPostLoadEvent(this));
main.getEventManager().callEvent(new ConfigPackPostLoadEvent(this, template -> selfLoader.load(template, configuration), loader));
main.logger().info("Loaded config pack \"" + template.getID() + "\" v" + template.getVersion() + " by " + template.getAuthor() + " in " + (System.nanoTime() - start) / 1000000D + "ms.");
}
@@ -6,12 +6,14 @@ import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.terra.api.addons.TerraAddon;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import com.dfsek.terra.config.loaders.mod.ModDependentConfigSection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
public class ConfigPackTemplate implements ConfigTemplate {
@@ -39,7 +41,7 @@ public class ConfigPackTemplate implements ConfigTemplate {
@Value("structures.locatable")
@Default
private Map<String, String> locatable = new HashMap<>();
private Map<String, ModDependentConfigSection<String>> locatable = new HashMap<>();
@Value("blend.terrain.elevation")
@Default
@@ -47,19 +49,19 @@ public class ConfigPackTemplate implements ConfigTemplate {
@Value("vanilla.mobs")
@Default
private boolean vanillaMobs = true;
private ModDependentConfigSection<Boolean> vanillaMobs = ModDependentConfigSection.withDefault(true);
@Value("vanilla.caves")
@Default
private boolean vanillaCaves = false;
private ModDependentConfigSection<Boolean> vanillaCaves = ModDependentConfigSection.withDefault(false);
@Value("vanilla.decorations")
@Default
private boolean vanillaDecorations = false;
private ModDependentConfigSection<Boolean> vanillaDecorations = ModDependentConfigSection.withDefault(false);
@Value("vanilla.structures")
@Default
private boolean vanillaStructures = false;
private ModDependentConfigSection<Boolean> vanillaStructures = ModDependentConfigSection.withDefault(false);
@Value("author")
@Default
@@ -67,7 +69,7 @@ public class ConfigPackTemplate implements ConfigTemplate {
@Value("disable.sapling")
@Default
private boolean disableSaplings = false;
private ModDependentConfigSection<Boolean> disableSaplings = ModDependentConfigSection.withDefault(false);
@Value("version")
@Default
@@ -75,42 +77,42 @@ public class ConfigPackTemplate implements ConfigTemplate {
@Value("disable.carvers")
@Default
private boolean disableCarvers = false;
private ModDependentConfigSection<Boolean> disableCarvers = ModDependentConfigSection.withDefault(false);
@Value("disable.structures")
@Default
private boolean disableStructures = false;
private ModDependentConfigSection<Boolean> disableStructures = ModDependentConfigSection.withDefault(false);
@Value("disable.ores")
@Default
private boolean disableOres = false;
private ModDependentConfigSection<Boolean> disableOres = ModDependentConfigSection.withDefault(false);
@Value("disable.trees")
@Default
private boolean disableTrees = false;
private ModDependentConfigSection<Boolean> disableTrees = ModDependentConfigSection.withDefault(false);
@Value("disable.flora")
@Default
private boolean disableFlora = false;
private ModDependentConfigSection<Boolean> disableFlora = ModDependentConfigSection.withDefault(false);
public boolean disableCarvers() {
return disableCarvers;
return disableCarvers.get();
}
public boolean disableFlora() {
return disableFlora;
return disableFlora.get();
}
public boolean disableOres() {
return disableOres;
return disableOres.get();
}
public boolean disableStructures() {
return disableStructures;
return disableStructures.get();
}
public boolean disableTrees() {
return disableTrees;
return disableTrees.get();
}
public LinkedHashMap<String, FunctionTemplate> getFunctions() {
@@ -122,7 +124,7 @@ public class ConfigPackTemplate implements ConfigTemplate {
}
public boolean isDisableSaplings() {
return disableSaplings;
return disableSaplings.get();
}
public String getID() {
@@ -134,19 +136,19 @@ public class ConfigPackTemplate implements ConfigTemplate {
}
public boolean vanillaMobs() {
return vanillaMobs;
return vanillaMobs.get();
}
public boolean vanillaCaves() {
return vanillaCaves;
return vanillaCaves.get();
}
public boolean vanillaDecorations() {
return vanillaDecorations;
return vanillaDecorations.get();
}
public boolean vanillaStructures() {
return vanillaStructures;
return vanillaStructures.get();
}
public Map<String, NoiseSeeded> getNoiseBuilderMap() {
@@ -162,7 +164,7 @@ public class ConfigPackTemplate implements ConfigTemplate {
}
public Map<String, String> getLocatable() {
return locatable;
return locatable.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().get()));
}
public boolean doBetaCarvers() {
@@ -1,36 +0,0 @@
package com.dfsek.terra.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);
}
}
@@ -1,24 +0,0 @@
package com.dfsek.terra.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;
}
}
@@ -1,10 +0,0 @@
package com.dfsek.terra.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,24 @@
package com.dfsek.terra.profiler;
public class Frame {
private final String id;
private final long start;
public Frame(String id) {
this.id = id;
this.start = System.nanoTime();
}
public String getId() {
return id;
}
public long getStart() {
return start;
}
@Override
public String toString() {
return id;
}
}
@@ -1,87 +0,0 @@
package com.dfsek.terra.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.LinkedList;
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 = new LinkedList<>();
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;
}
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 = BigInteger.valueOf(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() {
return MathUtil.standardDeviation(new GlueList<>(measurements));
}
public int entries() {
return measurements.size();
}
}
@@ -0,0 +1,14 @@
package com.dfsek.terra.profiler;
public class ProfileFrame implements AutoCloseable {
private final Runnable action;
public ProfileFrame(Runnable action) {
this.action = action;
}
@Override
public void close() {
action.run();
}
}
@@ -1,18 +0,0 @@
package com.dfsek.terra.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,56 @@
package com.dfsek.terra.profiler;
import java.util.Map;
public interface Profiler {
/**
* Push a frame to this profiler.
*
* @param frame ID of frame.
*/
void push(String frame);
/**
* Pop a frame from this profiler.
*
* @param frame ID of frame. Must match ID
* at the top of the profiler stack.
*/
void pop(String frame);
/**
* Start profiling.
*/
void start();
/**
* Stop profiling.
*/
void stop();
/**
* Get the profiler data.
*
* @return Profiler data.
*/
Map<String, Timings> getTimings();
/**
* Return a {@link AutoCloseable} implementation that
* may be used in a try-with-resources statement for
* more intuitive profiling, with auto-push/pop.
*
* @param frame ID of frame.
* @return {@link AutoCloseable} implementation for use
* in try-with-resources.
*/
default ProfileFrame profile(String frame) {
push(frame);
return new ProfileFrame(() -> pop(frame));
}
/**
* Clear the profiler data.
*/
void reset();
}
@@ -0,0 +1,91 @@
package com.dfsek.terra.profiler;
import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.profiler.exception.MalformedStackException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
public class ProfilerImpl implements Profiler {
private static final ThreadLocal<Stack<Frame>> THREAD_STACK = ThreadLocal.withInitial(Stack::new);
private static final ThreadLocal<Map<String, List<Long>>> TIMINGS = ThreadLocal.withInitial(HashMap::new);
private final List<Map<String, List<Long>>> accessibleThreadMaps = new ArrayList<>();
private volatile boolean running = false;
private static boolean instantiated = false;
private static final ThreadLocal<Boolean> SAFE = ThreadLocal.withInitial(() -> false);
private static final ThreadLocal<MutableInteger> STACK_SIZE = ThreadLocal.withInitial(() -> new MutableInteger(0));
public ProfilerImpl() {
if(instantiated) throw new IllegalStateException("Only one instance of Profiler may exist!");
instantiated = true;
}
@Override
public void push(String frame) {
STACK_SIZE.get().increment();
if(running && SAFE.get()) {
Stack<Frame> stack = THREAD_STACK.get();
stack.push(new Frame(stack.isEmpty() ? frame : stack.peek().getId() + "." + frame));
} else SAFE.set(false);
}
@Override
public void pop(String frame) {
MutableInteger size = STACK_SIZE.get();
size.decrement();
if(running && SAFE.get()) {
long time = System.nanoTime();
Stack<Frame> stack = THREAD_STACK.get();
Map<String, List<Long>> timingsMap = TIMINGS.get();
if(timingsMap.size() == 0) {
synchronized(accessibleThreadMaps) {
accessibleThreadMaps.add(timingsMap);
}
}
Frame top = stack.pop();
if((stack.size() != 0 && !top.getId().endsWith("." + frame)) || (stack.size() == 0 && !top.getId().equals(frame)))
throw new MalformedStackException("Expected " + frame + ", found " + top);
List<Long> timings = timingsMap.computeIfAbsent(top.getId(), id -> new ArrayList<>());
timings.add(time - top.getStart());
}
if(size.get() == 0) SAFE.set(true);
}
@Override
public void start() {
running = true;
}
@Override
public void stop() {
running = false;
}
@Override
public Map<String, Timings> getTimings() {
Map<String, Timings> map = new HashMap<>();
accessibleThreadMaps.forEach(smap -> smap.forEach((key, list) -> {
String[] keys = key.split("\\.");
Timings timings = map.computeIfAbsent(keys[0], id -> new Timings());
for(int i = 1; i < keys.length; i++) {
timings = timings.getSubItem(keys[i]);
}
list.forEach(timings::addTime);
}));
return map;
}
@Override
public void reset() {
accessibleThreadMaps.forEach(Map::clear);
}
}
@@ -0,0 +1,73 @@
package com.dfsek.terra.profiler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Timings {
private final Map<String, Timings> subItems = new HashMap<>();
private final List<Long> timings = new ArrayList<>();
public void addTime(long time) {
timings.add(time);
}
public List<Long> getTimings() {
return timings;
}
public double average() {
return (double) timings.stream().reduce(0L, Long::sum) / timings.size();
}
public long max() {
return timings.stream().mapToLong(Long::longValue).max().orElse(0L);
}
public long min() {
return timings.stream().mapToLong(Long::longValue).min().orElse(0L);
}
public double sum() {
return timings.stream().mapToDouble(Long::doubleValue).sum();
}
public Timings getSubItem(String id) {
return subItems.computeIfAbsent(id, s -> new Timings());
}
public String toString(int indent, Timings parent, Set<Integer> branches) {
StringBuilder builder = new StringBuilder();
builder.append((double) min() / 1000000).append("ms min / ").append(average() / 1000000).append("ms avg / ")
.append((double) max() / 1000000).append("ms max (").append(timings.size()).append(" samples, ")
.append((sum() / parent.sum()) * 100).append("% of parent)");
List<String> frames = new ArrayList<>();
Set<Integer> newBranches = new HashSet<>(branches);
newBranches.add(indent);
subItems.forEach((id, timings) -> frames.add(id + ": " + timings.toString(indent + 1, this, newBranches)));
for(int i = 0; i < frames.size(); i++) {
builder.append('\n');
for(int j = 0; j < indent; j++) {
if(branches.contains(j)) builder.append("");
else builder.append(" ");
}
if(i == frames.size() - 1 && !frames.get(i).contains("\n")) builder.append("└───");
else builder.append("├───");
builder.append(frames.get(i));
}
return builder.toString();
}
@Override
public String toString() {
return toString(1, this, Collections.emptySet());
}
}
@@ -1,85 +0,0 @@
package com.dfsek.terra.profiler;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.world.TerraWorld;
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(!TerraWorld.isTerraWorld(w))
throw new IllegalArgumentException("Attempted to instantiate profiler on non-Terra managed world!");
this.addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "TotalChunkGenTime")
.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");
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.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,17 @@
package com.dfsek.terra.profiler.exception;
public class MalformedStackException extends ProfilerException {
private static final long serialVersionUID = -3009539681021691054L;
public MalformedStackException(String message) {
super(message);
}
public MalformedStackException(String message, Throwable cause) {
super(message, cause);
}
public MalformedStackException(Throwable cause) {
super(cause);
}
}
@@ -0,0 +1,17 @@
package com.dfsek.terra.profiler.exception;
public class ProfilerException extends RuntimeException {
private static final long serialVersionUID = 8206737998791649002L;
public ProfilerException(String message) {
super(message);
}
public ProfilerException(String message, Throwable cause) {
super(message, cause);
}
public ProfilerException(Throwable cause) {
super(cause);
}
}
@@ -7,18 +7,19 @@ import com.dfsek.terra.registry.exception.DuplicateEntryException;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* Registry implementation with read/write access. For internal use only.
* @param <T>
*/
public class OpenRegistry<T> implements Registry<T> {
private final Map<String, T> objects = new HashMap<>();
private final Map<String, Entry<T>> objects = new HashMap<>();
@Override
public T load(Type type, Object o, ConfigLoader configLoader) throws LoadException {
@@ -35,6 +36,10 @@ public class OpenRegistry<T> implements Registry<T> {
* @param value Value to add.
*/
public boolean add(String identifier, T value) {
return add(identifier, new Entry<>(value));
}
protected boolean add(String identifier, Entry<T> value) {
boolean exists = objects.containsKey(identifier);
objects.put(identifier, value);
return exists;
@@ -60,22 +65,24 @@ public class OpenRegistry<T> implements Registry<T> {
@Override
public T get(String identifier) {
return objects.get(identifier);
Entry<T> entry = objects.get(identifier);
if(entry == null) return null;
return entry.getValue();
}
@Override
public void forEach(Consumer<T> consumer) {
objects.forEach((id, obj) -> consumer.accept(obj));
objects.forEach((id, obj) -> consumer.accept(obj.getRaw()));
}
@Override
public void forEach(BiConsumer<String, T> consumer) {
objects.forEach(consumer);
objects.forEach((id, entry) -> consumer.accept(id, entry.getRaw()));
}
@Override
public Set<T> entries() {
return new HashSet<>(objects.values());
return objects.values().stream().map(Entry::getRaw).collect(Collectors.toSet());
}
@Override
@@ -83,10 +90,41 @@ public class OpenRegistry<T> implements Registry<T> {
return objects.keySet();
}
public Map<String, T> getDeadEntries() {
Map<String, T> dead = new HashMap<>();
objects.forEach((id, entry) -> {
if(entry.dead()) dead.put(id, entry.value); // dont increment value here.
});
return dead;
}
/**
* Clears all entries from the registry.
*/
public void clear() {
objects.clear();
}
protected static final class Entry<T> {
private final T value;
private final AtomicInteger access = new AtomicInteger(0);
public Entry(T value) {
this.value = value;
}
public T getValue() {
access.incrementAndGet();
return value;
}
private T getRaw() {
return value;
}
public boolean dead() {
return access.get() == 0;
}
}
}
@@ -57,7 +57,9 @@ public class FloraRegistry extends OpenRegistry<Flora> {
private void addItem(String id, Callable<ConstantFlora> flora) {
try {
add(id, flora.call());
Entry<Flora> entry = new Entry<>(flora.call());
entry.getValue(); // Mark as not dead.
add(id, entry);
} catch(Exception e) {
main.logger().warning("Failed to load Flora item: " + id + ": " + e.getMessage());
}
@@ -66,10 +68,4 @@ public class FloraRegistry extends OpenRegistry<Flora> {
private BlockData data(String s) {
return main.getWorldHandle().createBlockData(s);
}
@Override
public Flora get(String identifier) {
return super.get(identifier);
}
}
@@ -13,7 +13,6 @@ import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.profiler.WorldProfiler;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import net.jafama.FastMath;
@@ -21,33 +20,25 @@ public class TerraWorld {
private final BiomeProvider provider;
private final WorldConfig config;
private final boolean safe;
private final WorldProfiler profiler;
private final World world;
private final BlockData air;
public TerraWorld(World w, ConfigPack c, TerraPlugin main) {
if(!isTerraWorld(w)) throw new IllegalArgumentException("World " + w + " is not a Terra World!");
if(!w.isTerraWorld()) throw new IllegalArgumentException("World " + w + " is not a Terra World!");
this.world = w;
config = c.toWorldConfig(this);
this.provider = config.getProvider();
profiler = new WorldProfiler(w);
air = main.getWorldHandle().createBlockData("minecraft:air");
main.getEventManager().callEvent(new TerraWorldLoadEvent(this, c));
safe = true;
}
public static boolean isTerraWorld(World w) {
return w.getGenerator().getHandle() instanceof GeneratorWrapper;
}
public World getWorld() {
return world;
}
public TerraChunkGenerator getGenerator() {
return ((GeneratorWrapper) world.getGenerator().getHandle()).getHandle();
}
public BiomeProvider getBiomeProvider() {
return provider;
@@ -61,9 +52,6 @@ public class TerraWorld {
return safe;
}
public WorldProfiler getProfiler() {
return profiler;
}
/**
* Get a block at an ungenerated location
@@ -82,7 +70,7 @@ public class TerraWorld {
double noise = sampler.sample(fdX, y, fdZ);
if(noise > 0) {
int level = 0;
for(int yi = world.getMaxHeight(); yi > y; yi--) {
for(int yi = world.getMaxHeight()-1; yi > y; yi--) {
if(sampler.sample(fdX, yi, fdZ) > 0) level++;
else level = 0;
}
@@ -15,7 +15,7 @@ import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.Carver;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.carving.NoiseCarver;
@@ -94,7 +94,7 @@ public class DefaultChunkGenerator2D implements TerraChunkGenerator {
public ChunkData generateChunkData(@NotNull World world, Random random, int chunkX, int chunkZ, ChunkData chunk) {
TerraWorld tw = main.getWorld(world);
BiomeProvider grid = tw.getBiomeProvider();
try(ProfileFuture ignore = tw.getProfiler().measure("TotalChunkGenTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("chunk_base_2d")) {
if(!tw.isSafe()) return chunk;
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
@@ -23,7 +23,7 @@ import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.palette.SinglePalette;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.Carver;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.carving.NoiseCarver;
@@ -50,7 +50,6 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
private final Carver carver;
public DefaultChunkGenerator3D(ConfigPack c, TerraPlugin main) {
this.configPack = c;
this.main = main;
@@ -104,9 +103,10 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
@Override
@SuppressWarnings({"try"})
public ChunkData generateChunkData(@NotNull World world, Random random, int chunkX, int chunkZ, ChunkData chunk) {
TerraWorld tw = main.getWorld(world);
BiomeProvider grid = tw.getBiomeProvider();
try(ProfileFuture ignore = tw.getProfiler().measure("TotalChunkGenTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("chunk_base_3d")) {
TerraWorld tw = main.getWorld(world);
BiomeProvider grid = tw.getBiomeProvider();
if(!tw.isSafe()) return chunk;
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
@@ -120,7 +120,7 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
int cx = xOrig + x;
int cz = zOrig + z;
TerraBiome b = grid.getBiome(xOrig + x, zOrig + z);
TerraBiome b = grid.getBiome(cx, cz);
BiomeTemplate c = ((UserDefinedBiome) b).getConfig();
int sea = c.getSeaLevel();
@@ -227,17 +227,20 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
return false;
}
@SuppressWarnings({"try"})
static void biomes(@NotNull World world, int chunkX, int chunkZ, @NotNull BiomeGrid biome, TerraPlugin main) {
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
BiomeProvider grid = main.getWorld(world).getBiomeProvider();
for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) {
int cx = xOrig + (x << 2);
int cz = zOrig + (z << 2);
TerraBiome b = grid.getBiome(cx, cz);
try(ProfileFrame ignore = main.getProfiler().profile("biomes")) {
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
BiomeProvider grid = main.getWorld(world).getBiomeProvider();
for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) {
int cx = xOrig + (x << 2);
int cz = zOrig + (z << 2);
TerraBiome b = grid.getBiome(cx, cz);
biome.setBiome(cx, cz, b.getVanillaBiomes().get(b.getGenerator(world).getBiomeNoise(), cx, 0, cz));
biome.setBiome(cx, cz, b.getVanillaBiomes().get(b.getGenerator(world).getBiomeNoise(), cx, 0, cz));
}
}
}
}
@@ -25,7 +25,7 @@ public class SamplerCache {
public Sampler load(@NotNull Long key) {
int cx = (int) (key >> 32);
int cz = (int) key.longValue();
return world.getGenerator().createSampler(cx, cz, world.getBiomeProvider(), world.getWorld(), world.getConfig().getTemplate().getElevationBlend());
return world.getWorld().getTerraGenerator().createSampler(cx, cz, world.getBiomeProvider(), world.getWorld(), world.getConfig().getTemplate().getElevationBlend());
}
});
}
@@ -14,7 +14,7 @@ import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.config.templates.CarverTemplate;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import org.jetbrains.annotations.NotNull;
@@ -38,7 +38,7 @@ public class CavePopulator implements TerraBlockPopulator, Chunkified {
TerraWorld tw = main.getWorld(world);
WorldHandle handle = main.getWorldHandle();
BlockData AIR = handle.createBlockData("minecraft:air");
try(ProfileFuture ignored = tw.getProfiler().measure("CaveTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("carving")) {
Random random = PopulationUtil.getRandom(chunk);
if(!tw.isSafe()) return;
WorldConfig config = tw.getConfig();
@@ -49,38 +49,40 @@ public class CavePopulator implements TerraBlockPopulator, Chunkified {
Map<Location, BlockData> shiftCandidate = new HashMap<>();
Set<Block> updateNeeded = new HashSet<>();
c.carve(chunk.getX(), chunk.getZ(), world, (v, type) -> {
Block b = chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ());
BlockData m = b.getBlockData();
BlockType re = m.getBlockType();
switch(type) {
case CENTER:
if(template.getInner().canReplace(re)) {
b.setBlockData(template.getInner().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case WALL:
if(template.getOuter().canReplace(re)) {
b.setBlockData(template.getOuter().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case TOP:
if(template.getTop().canReplace(re)) {
b.setBlockData(template.getTop().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case BOTTOM:
if(template.getBottom().canReplace(re)) {
b.setBlockData(template.getBottom().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
try(ProfileFrame ignored = main.getProfiler().profile("carving:" + c.getConfig().getID())) {
Block b = chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ());
BlockData m = b.getBlockData();
BlockType re = m.getBlockType();
switch(type) {
case CENTER:
if(template.getInner().canReplace(re)) {
b.setBlockData(template.getInner().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case WALL:
if(template.getOuter().canReplace(re)) {
b.setBlockData(template.getOuter().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case TOP:
if(template.getTop().canReplace(re)) {
b.setBlockData(template.getTop().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case BOTTOM:
if(template.getBottom().canReplace(re)) {
b.setBlockData(template.getBottom().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
}
}
});
for(Map.Entry<Location, BlockData> entry : shiftCandidate.entrySet()) {
@@ -93,7 +95,7 @@ public class CavePopulator implements TerraBlockPopulator, Chunkified {
if(template.getShift().get(entry.getValue().getBlockType()).contains(mut.getBlock().getBlockData().getBlockType())) {
mut.getBlock().setBlockData(shiftStorage.computeIfAbsent(entry.getValue().getBlockType(), BlockType::getDefaultData), false);
}
} catch(NullPointerException ignore) {
} catch(NullPointerException ignored) {
}
}
for(Block b : updateNeeded) {
@@ -8,7 +8,7 @@ import com.dfsek.terra.api.util.world.PopulationUtil;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.population.items.flora.FloraLayer;
import org.jetbrains.annotations.NotNull;
@@ -32,8 +32,8 @@ public class FloraPopulator implements TerraBlockPopulator {
@Override
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("FloraTime")) {
if(tw.getConfig().getTemplate().disableCarvers()) return;
try(ProfileFrame ignore = main.getProfiler().profile("flora")) {
if(tw.getConfig().getTemplate().disableFlora()) return;
if(!tw.isSafe()) return;
BiomeProvider provider = tw.getBiomeProvider();
@@ -10,7 +10,7 @@ import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import org.jetbrains.annotations.NotNull;
@@ -27,8 +27,8 @@ public class OrePopulator implements TerraBlockPopulator {
@Override
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("OreTime")) {
if(tw.getConfig().getTemplate().disableCarvers()) return;
try(ProfileFrame ignore = main.getProfiler().profile("ore")) {
if(tw.getConfig().getTemplate().disableOres()) return;
if(!tw.isSafe()) return;
for(int cx = -1; cx <= 1; cx++) {
@@ -40,11 +40,13 @@ public class OrePopulator implements TerraBlockPopulator {
BiomeTemplate config = ((UserDefinedBiome) b).getConfig();
int finalCx = cx;
int finalCz = cz;
config.getOreHolder().forEach((ore, oreConfig) -> {
int amount = oreConfig.getAmount().get(random);
for(int i = 0; i < amount; i++) {
Vector3 location = new Vector3(random.nextInt(16) + 16 * finalCx, oreConfig.getHeight().get(random), random.nextInt(16) + 16 * finalCz);
ore.generate(location, chunk, random);
config.getOreHolder().forEach((id, orePair) -> {
try(ProfileFrame ignored = main.getProfiler().profile("ore:" + id)) {
int amount = orePair.getRight().getAmount().get(random);
for(int i = 0; i < amount; i++) {
Vector3 location = new Vector3(random.nextInt(16) + 16 * finalCx, orePair.getRight().getHeight().get(random), random.nextInt(16) + 16 * finalCz);
orePair.getLeft().generate(location, chunk, random);
}
}
});
}
@@ -11,9 +11,8 @@ import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.Chunkified;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.population.items.TerraStructure;
import net.jafama.FastMath;
@@ -32,8 +31,8 @@ public class StructurePopulator implements TerraBlockPopulator, Chunkified {
@Override
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("StructureTime")) {
if(tw.getConfig().getTemplate().disableCarvers()) return;
try(ProfileFrame ignore = main.getProfiler().profile("structure")) {
if(tw.getConfig().getTemplate().disableStructures()) return;
int cx = (chunk.getX() << 4);
int cz = (chunk.getZ() << 4);
@@ -8,7 +8,7 @@ import com.dfsek.terra.api.util.world.PopulationUtil;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.population.items.tree.TreeLayer;
import net.jafama.FastMath;
@@ -32,8 +32,8 @@ public class TreePopulator implements TerraBlockPopulator {
@SuppressWarnings("try")
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("TreeTime")) {
if(tw.getConfig().getTemplate().disableCarvers()) return;
try(ProfileFrame ignore = main.getProfiler().profile("tree")) {
if(tw.getConfig().getTemplate().disableTrees()) return;
if(!tw.isSafe()) return;
BiomeProvider provider = tw.getBiomeProvider();
@@ -42,8 +42,9 @@ public class TreePopulator implements TerraBlockPopulator {
for(int z = 0; z < 16; z += 2) {
UserDefinedBiome biome = (UserDefinedBiome) provider.getBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z);
for(TreeLayer layer : biome.getConfig().getTrees()) {
if(layer.getDensity() >= random.nextDouble() * 100)
if(layer.getDensity() >= random.nextDouble() * 100) {
layer.place(chunk, new Vector2(offset(random, x), offset(random, z)));
}
}
}
}
@@ -16,7 +16,6 @@ public abstract class Ore {
protected TerraPlugin main;
public Ore(BlockData material, MaterialSet replaceable, boolean applyGravity, TerraPlugin main) {
this.material = material;
this.replaceable = replaceable;
this.applyGravity = applyGravity;
@@ -1,6 +1,7 @@
package com.dfsek.terra.world.population.items.ores;
import com.dfsek.terra.api.util.GlueList;
import com.dfsek.terra.api.util.generic.pair.ImmutablePair;
import java.util.List;
import java.util.function.BiConsumer;
@@ -11,22 +12,24 @@ import java.util.function.BiConsumer;
public class OreHolder {
private final List<Entry> entries = new GlueList<>();
public void forEach(BiConsumer<Ore, OreConfig> consumer) {
entries.forEach(entry -> consumer.accept(entry.getOre(), entry.getConfig()));
public void forEach(BiConsumer<String, ImmutablePair<Ore, OreConfig>> consumer) {
entries.forEach(entry -> consumer.accept(entry.getId(), ImmutablePair.of(entry.getOre(), entry.getConfig())));
}
public OreHolder add(Ore ore, OreConfig config) {
entries.add(new Entry(ore, config));
public OreHolder add(Ore ore, OreConfig config, String id) {
entries.add(new Entry(ore, config, id));
return this;
}
private static final class Entry {
private final Ore ore;
private final OreConfig config;
private final String id;
private Entry(Ore ore, OreConfig config) {
private Entry(Ore ore, OreConfig config, String id) {
this.ore = ore;
this.config = config;
this.id = id;
}
public OreConfig getConfig() {
@@ -36,5 +39,9 @@ public class OreHolder {
public Ore getOre() {
return ore;
}
public String getId() {
return id;
}
}
}
+1 -2
View File
@@ -7,7 +7,6 @@ cache:
carver: 512
structure: 32
sampler: 128
master-disable:
caves: false
biome-provider: 32
script:
max-recursion: 1000
+122
View File
@@ -0,0 +1,122 @@
enable:
- "Pokud se vám líbí Terra, můžete nás podpořit na Patreon!"
- "Získáte přístup k experimentálním funkcím, než budou vydány!"
- "Podpořit projekt můžete zde: https://www.patreon.com/dfsek"
disable:
- "Děkujeme, že používáte Terra!"
command:
debug-only: "Tento příkaz musí být použit se zapnutým debug modem!"
player-only: "Tento příkaz je pouze pro hráče!"
invalid: "Neznámý příkaz. (Očekáváno %1$s argumentů, nalezeno %2$s)."
players-only: "Příkaz je pouze pro použití hráčem."
world: "Tento příkaz musí být použit v Terra světě!"
reload: "Obnoven Terra konfig."
reload-error: "Nastaly chyby při obnově Terra konfigurace. Podívejte se do logů pro více informací."
version: "Na tomto serveru běží Terra verze \"%1$s\", na platformě \"%2$s\""
main-menu:
- "--------------------Terra--------------------"
- "reload - Obnoví konfigurační data"
- "biome - Ukáže aktuální biom"
- "ore - Generuje žílu rud v lokaci, ve směru kam se koukáte (Pro debugging)"
- "save-data - Uložit populační data"
- "structure - Nahrát a exportovat struktury"
- "profile - Profiler možnosti"
- "image - Obrázek/GUI možnosti"
biome:
biome-found: "Lokalizován biom na (%1$s, %2$s)"
unable-to-locate: "Nelze lokalizovat biom."
invalid-radius: "Nesprávný radius: \"%s\""
invalid: "Nesprávné ID bomu: \"%s\""
in: "Jste v \"%s\""
packs:
main: "Aktuální instalované konfigurační balíčky:"
pack: " - %1$s v%3$s od %2$s"
none: "Žádné konfigurační balíčky nejsou nainstalovány."
ore:
main-menu:
- "---------------Terra/ore---------------"
- "Generuje žílu rud na bloku, na který koukáte."
out-of-range: "Blok mimo dosah"
invalid-ore: "Nelze nalézt Rudu \"%s\""
geometry:
main-menu:
- "---------------Terra/geometry----------------"
- "Různé voxel geometrické debugging příkazy"
- "sphere - Generuje kouli"
- "deformsphere - Generuje deformovanou kouli"
- "tube - Generuje válec"
deform:
invalid-radius: "Nesprávný radius: \"%s\""
invalid-deform: "Nesprávná deformace: \"%s\""
invalid-frequency: "Nesprávná frekvence: \"%s\""
sphere:
invalid-radius: "Nesprávný radius: \"%s\""
tube:
invalid-radius: "Nesprávný radius: \"%s\""
image:
main-menu:
- "---------------Terra/image---------------"
- "render - Vykreslí obrázek s danou šířkou a výškou, který může být později importován jako svět."
- "gui - Otevřít debug GUI (Musí být zapnuto v konfigu)"
gui:
main-menu:
- "-------------Terra/image/gui-------------"
- "raw - Otevře GUI s raw Biom daty"
- "step - Znovu vykreslí data k lepšímu zobrazení borderu"
debug: "Debug mod musí být zapnutý pro použití této možnosti! Debug GUI NENÍ PRODUKČNĚ BEZPEČNÉ!"
render:
save: "Uložen obrázek jako \"%s\""
error: "Nastala chyba při generování obrázku!"
profile:
main-menu:
- "---------------Terra/profile---------------"
- "start - Zapne profiler"
- "stop - Vypne profiler"
- "query - Ukáže profiler data"
- "reset - Resetuje profiler data"
reset: "Profiler byl resetován."
start: "Profiler byl zapnut."
stop: "Profiler byl vypnut."
structure:
main-menu:
- "---------------Terra/structure---------------"
- "export - Export vašeho výběru WorldEdit jako Terra struktura."
- "load - Načíst Terra strukturu"
invalid-radius: "Nesprávný radius: \"%s\""
invalid-rotation: "Nesprávná rotace: \"%s\""
invalid: "Nesprávné ID struktury: \"%s\""
export: "Uložena struktura do \"%s\""
world-config:
load: "Načteny konfigurační hodnoty světa pro svět \"%s\"..."
not-found: "Konfigurace pro svět \"%s\" nenalezena. Kopíruji defaultní konfig."
using-image: "Načítám svět z obrázku."
error: "Nelze načíst konfigurace pro svět %s"
done: "Načítání světa \"%1$s\" dokončeno. Uplynulý čas: %2$sms"
config-pack:
loaded: "Konfigurační balíček %1$s v%4$s od %3$s byl načten za %2$sms."
config:
loaded: "Načten %1$s ze souboru %2$s"
loaded-all: "Načteno %1$s %2$s(s) za %3$sms."
error:
invalid-failover: "Nesprávný typ failover: \"%s\""
duplicate: "Duplikační ID nalezeno v souboru: %s"
file:
- "Konfigurační chyba pro Terra objekt. Soubor: %1$s"
- "%2$s"
- "Opravte jej před pokračováním!"
generic:
- "Nastala chyba při načítání konfigurace."
- "Prosíme nahlašte to na Terra."
warning:
no-population: "Žádné populační chunky nebyly načteny. Pokud je to poprvé, co zapínáte server s Terra, či vytváříte nový svět, je tohle normální."
error:
severe-config: "Vážná konfigurační chyba zabránila Terra ze správné generace terénu na koordinátech: %1$s, %2$s. Prosíme zkontrolujte konfiguraci pro chyby. Jakékoli konfigurační chyby jsou vypsány výše."
debug:
data-save : "Uložena populační data."
use-paper:
- "Vypadá to, že používáte Spigot/CraftBukkit."
- "Ačkoli Terra &ofunguje&r na Spigot, některé funkce budou ztraceny. (Terra je netestována na CraftBukkit; žádná podpora nebude dána pro CraftBukkit)."
- "Pro nejvíce funkcí s Terra, použijte Paper."
- "Navíc, Paper přináší obrovské výkonnostní zlepešení než Spigot, a všechny Spigot pluginy by měli fungovat s Paper!"
- "Pro nejlepší zážitek s Terra a všemi pluginy, použijte prosím Paper."
- "Více info najdete na stránce Paperu: https://papermc.io/"
@@ -40,6 +40,7 @@ import com.dfsek.terra.config.loaders.config.sampler.NoiseSamplerBuilderLoader;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.AbstractableTemplate;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.profiler.Profiler;
import com.dfsek.terra.registry.config.BiomeRegistry;
import com.dfsek.terra.registry.config.NoiseRegistry;
import com.dfsek.terra.world.TerraWorld;
@@ -137,6 +138,11 @@ public class DistributionTest {
return null;
}
@Override
public Profiler getProfiler() {
return null;
}
@Override
public void register(TypeRegistry registry) {
@@ -153,7 +159,7 @@ public class DistributionTest {
new GenericLoaders(MAIN).register(loader);
BiomeRegistry biomeRegistry = new BiomeRegistry();
folderLoader.open("biomes", ".yml").then(inputStreams -> ConfigPack.buildAll((template, main) -> template, biomeRegistry, loader.load(inputStreams, TestBiome::new), MAIN));
folderLoader.open("biomes", ".yml").then(inputStreams -> ConfigPack.buildAll((template, main) -> template, biomeRegistry, loader.loadConfigs(inputStreams, TestBiome::new), MAIN));
BiomeProviderTemplate template = new BiomeProviderTemplate();
ConfigLoader pipeLoader = new ConfigLoader()
+1 -1
View File
@@ -46,7 +46,7 @@ public class ImageTest {
OpenRegistry<TerraBiome> biomeRegistry = new OpenRegistry<TerraBiome>() {
};
folderLoader.open("biomes", ".yml").then(inputStreams -> ConfigPack.buildAll((template, main) -> template, biomeRegistry, loader.load(inputStreams, TestBiome::new), null));
folderLoader.open("biomes", ".yml").then(inputStreams -> ConfigPack.buildAll((template, main) -> template, biomeRegistry, loader.loadConfigs(inputStreams, TestBiome::new), null));
return new ImageBiomeProvider(biomeRegistry.entries(), ImageIO.read(ImageTest.class.getResourceAsStream("/map.jpg")), 1, ImageBiomeProvider.Align.CENTER);
}
@@ -0,0 +1,63 @@
package profiler;
import com.dfsek.terra.profiler.Profiler;
import com.dfsek.terra.profiler.ProfilerImpl;
public class ProfilerTest {
private static final Profiler PROFILER = new ProfilerImpl();
//@Test
public static void main(String... a) throws InterruptedException {
//PROFILER.start();
for(int i = 0; i < 1000; i++) {
doThing();
}
for(int i = 0; i < 100; i++) {
doThirdOtherThing();
}
for(int i = 0; i < 100; i++) {
doOtherThing();
}
PROFILER.stop();
PROFILER.push("thing");
PROFILER.push("thing2");
PROFILER.start();
PROFILER.pop("thing2");
PROFILER.pop("thing");
PROFILER.push("thing4");
PROFILER.pop("thing4");
PROFILER.getTimings().forEach((id, timings) -> {
System.out.println(id + ": " + timings.toString());
});
}
private static void doThing() throws InterruptedException {
PROFILER.push("thing");
Thread.sleep(1);
doOtherThing();
thing4();
PROFILER.pop("thing");
}
private static void doOtherThing() throws InterruptedException {
PROFILER.push("thing2");
Thread.sleep(2);
doThirdOtherThing();
thing4();
PROFILER.pop("thing2");
}
private static void doThirdOtherThing() throws InterruptedException {
PROFILER.push("thing3");
Thread.sleep(2);
PROFILER.pop("thing3");
}
private static void thing4() throws InterruptedException {
PROFILER.push("thing4");
Thread.sleep(2);
PROFILER.pop("thing4");
}
}
@@ -13,6 +13,7 @@ import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -20,7 +21,7 @@ import java.util.Map;
public class ParserTest {
@Test
public void parse() throws IOException, ParseException {
Parser parser = new Parser(IOUtils.toString(getClass().getResourceAsStream("/test.tesf")));
Parser parser = new Parser(IOUtils.toString(getClass().getResourceAsStream("/test.tesf"), Charset.defaultCharset()));
parser.registerFunction("test", new FunctionBuilder<Test1>() {
@Override
+15
View File
@@ -0,0 +1,15 @@
# Magic options for more perf
org.gradle.jvmargs=-Xmx2048M -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC
org.gradle.vfs.watch=true
kapt.use.worker.api=true
kapt.include.compile.classpath=false
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.warning.mode=all
#org.gradle.logging.level=info
# Project information
terra.description=A fast, modern, extensible, platform-agnostic data-driven world generator
terra.source=https://github.com/PolyhedralDev/Terra
terra.issues=https://github.com/PolyhedralDev/Terra/issues
terra.wiki=https://github.com/PolyhedralDev/Terra/wiki
terra.license=GNU General Public License, version 3.0
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
org.gradle.jvmargs=-Xmx4096m
+9 -15
View File
@@ -16,19 +16,12 @@ configureCommon()
group = "com.dfsek.terra.bukkit"
val mcVersion = "1.16.5"
val testDir = "target/server/"
val testDir = "target/server"
val testMem = "3G"
val paperURL = "https://papermc.io/api/v1/paper/%version%/latest/download/"
val purpurURL = "https://ci.pl3x.net/job/Purpur/lastSuccessfulBuild/artifact/final/purpurclip.jar"
repositories {
mavenCentral()
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/") }
}
dependencies {
"shadedApi"(project(":common"))
@@ -39,17 +32,17 @@ dependencies {
"compileOnly"("com.sk89q.worldedit:worldedit-bukkit:7.2.0-SNAPSHOT")
"shadedImplementation"("com.google.guava:guava:30.0-jre")
"shadedApi"("com.google.guava:guava:30.0-jre")
}
val aikarsFlags = listOf("-XX:+UseG1GC", "-XX:+ParallelRefProcEnabled", "-XX:MaxGCPauseMillis=200",
val jvmFlags = 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")
"-Daikars.new.flags=true", "-DIReallyKnowWhatIAmDoingISwear", "-javaagent:paperclip.jar")
fun downloadPaperclip(url: String, dir: String) {
val clip = URL(url.replace("%version%", mcVersion))
@@ -77,8 +70,8 @@ fun installServer(dir: String) {
// Cloning test setup.
gitClone("https://github.com/PolyhedralDev/WorldGenTestServer")
// Copying plugins
Files.move(Paths.get("WorldGenTestServer/plugins"),
Paths.get("$testDir/$dir/plugins"),
Files.move(file("WorldGenTestServer/plugins").toPath(),
file("$testDir/$dir/plugins").toPath(),
StandardCopyOption.REPLACE_EXISTING)
// Copying config
val serverText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/server.properties").readText()
@@ -160,7 +153,7 @@ task<JavaExec>(name = "runPaper") {
}
main = "io.papermc.paperclip.Paperclip"
jvmArgs = aikarsFlags
jvmArgs = jvmFlags
maxHeapSize = testMem
minHeapSize = testMem
//args = listOf("nogui")
@@ -178,7 +171,7 @@ task<JavaExec>(name = "runPurpur") {
}
main = "io.papermc.paperclip.Paperclip"
jvmArgs = aikarsFlags
jvmArgs = jvmFlags
maxHeapSize = testMem
minHeapSize = testMem
//args = listOf("nogui")
@@ -189,6 +182,7 @@ task<JavaExec>(name = "runPurpur") {
tasks.named<ShadowJar>("shadowJar") {
relocate("org.bstats.bukkit", "com.dfsek.terra.lib.bstats")
relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib")
relocate("com.google.common", "com.dfsek.terra.lib.google.common")
}
publishing {
@@ -0,0 +1,27 @@
package com.dfsek.terra.bukkit;
import com.dfsek.terra.api.platform.modloader.Mod;
import org.bukkit.plugin.Plugin;
public class BukkitPlugin implements Mod {
private final Plugin plugin;
public BukkitPlugin(Plugin plugin) {
this.plugin = plugin;
}
@Override
public String getID() {
return plugin.getName();
}
@Override
public String getVersion() {
return plugin.getDescription().getVersion();
}
@Override
public String getName() {
return plugin.getName();
}
}
@@ -14,6 +14,7 @@ import com.dfsek.terra.api.event.TerraEventManager;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.handle.ItemHandle;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.modloader.Mod;
import com.dfsek.terra.api.platform.world.Biome;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.registry.CheckedRegistry;
@@ -34,12 +35,15 @@ import com.dfsek.terra.bukkit.listeners.SpigotListener;
import com.dfsek.terra.bukkit.listeners.TerraListener;
import com.dfsek.terra.bukkit.util.PaperUtil;
import com.dfsek.terra.bukkit.world.BukkitBiome;
import com.dfsek.terra.bukkit.world.BukkitWorld;
import com.dfsek.terra.commands.CommandUtil;
import com.dfsek.terra.config.GenericLoaders;
import com.dfsek.terra.config.PluginConfig;
import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.config.lang.Language;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.profiler.Profiler;
import com.dfsek.terra.profiler.ProfilerImpl;
import com.dfsek.terra.registry.master.AddonRegistry;
import com.dfsek.terra.registry.master.ConfigRegistry;
import com.dfsek.terra.world.TerraWorld;
@@ -54,9 +58,12 @@ import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
@@ -64,6 +71,8 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
private final Map<World, TerraWorld> worldMap = new HashMap<>();
private final Map<String, ConfigPack> worlds = new HashMap<>();
private final Profiler profiler = new ProfilerImpl();
private final ConfigRegistry registry = new ConfigRegistry();
private final CheckedRegistry<ConfigPack> checkedRegistry = new CheckedRegistry<>(registry);
@@ -141,6 +150,11 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
Bukkit.getScheduler().runTask(this, task);
}
@Override
public Profiler getProfiler() {
return profiler;
}
@Override
public void onDisable() {
BukkitChunkGeneratorWrapper.saveAll();
@@ -259,14 +273,15 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
return checkedRegistry;
}
public TerraWorld getWorld(World w) {
if(!TerraWorld.isTerraWorld(w))
public TerraWorld getWorld(World world) {
BukkitWorld w = (BukkitWorld) world;
if(!w.isTerraWorld())
throw new IllegalArgumentException("Not a Terra world! " + w.getGenerator());
if(!worlds.containsKey(w.getName())) {
getLogger().warning("Unexpected world load detected: \"" + w.getName() + "\"");
return new TerraWorld(w, ((TerraChunkGenerator) w.getGenerator().getHandle()).getConfigPack(), this);
}
return worldMap.computeIfAbsent(w, world -> new TerraWorld(w, worlds.get(w.getName()), this));
return worldMap.computeIfAbsent(w, w2 -> new TerraWorld(w, worlds.get(w.getName()), this));
}
@Override
@@ -295,6 +310,11 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
genericLoaders.register(registry);
}
@Override
public Set<Mod> getMods() {
return Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(BukkitPlugin::new).collect(Collectors.toSet());
}
@Override
public LockedRegistry<TerraAddon> getAddons() {
return addonLockedRegistry;
@@ -3,19 +3,11 @@ package com.dfsek.terra.bukkit.generator;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.bukkit.population.PopulationManager;
import com.dfsek.terra.bukkit.world.BukkitAdapter;
import com.dfsek.terra.bukkit.world.BukkitBiomeGrid;
import com.dfsek.terra.profiler.DataType;
import com.dfsek.terra.profiler.Measurement;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.population.CavePopulator;
import com.dfsek.terra.world.population.FloraPopulator;
import com.dfsek.terra.world.population.OrePopulator;
import com.dfsek.terra.world.population.StructurePopulator;
import com.dfsek.terra.world.population.TreePopulator;
import org.bukkit.World;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
@@ -24,13 +16,10 @@ import org.jetbrains.annotations.NotNull;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
public class BukkitChunkGeneratorWrapper extends ChunkGenerator implements GeneratorWrapper {
@@ -63,7 +52,7 @@ public class BukkitChunkGeneratorWrapper extends ChunkGenerator implements Gener
}
public static synchronized void fixChunk(Chunk c) {
if(!TerraWorld.isTerraWorld(c.getWorld())) throw new IllegalArgumentException();
if(!c.getWorld().isTerraWorld()) throw new IllegalArgumentException();
popMap.get(c.getWorld()).checkNeighbors(c.getX(), c.getZ(), c.getWorld());
}
@@ -76,8 +65,6 @@ public class BukkitChunkGeneratorWrapper extends ChunkGenerator implements Gener
e.printStackTrace();
}
popMap.put(w, popMan);
main.getWorld(w).getProfiler().addMeasurement(new Measurement(15000000, DataType.PERIOD_MILLISECONDS), "PopulationManagerTime");
popMan.attachProfiler(main.getWorld(w).getProfiler());
needsLoad = false;
}
@@ -44,7 +44,7 @@ public class CommonListener implements Listener {
public void onSaplingGrow(StructureGrowEvent e) {
if(e.isCancelled()) return;
World bukkit = BukkitAdapter.adapt(e.getWorld());
if(!TerraWorld.isTerraWorld(bukkit)) return;
if(!bukkit.isTerraWorld()) return;
TerraWorld tw = main.getWorld(bukkit);
WorldConfig c = tw.getConfig();
if(c.getTemplate().isDisableSaplings()) return;
@@ -18,8 +18,7 @@ public class PaperListener implements Listener {
@EventHandler
public void onStructureLocate(StructureLocateEvent e) {
if(!TerraWorld.isTerraWorld(BukkitAdapter.adapt(e.getWorld()))) return;
e.setResult(null); // Assume no result.
if(!BukkitAdapter.adapt(e.getWorld()).isTerraWorld()) return;
String name = "minecraft:" + e.getType().getName();
main.getDebugLogger().info("Overriding structure location for \"" + name + "\"");
TerraWorld tw = main.getWorld(BukkitAdapter.adapt(e.getWorld()));
@@ -32,10 +31,8 @@ public class PaperListener implements Listener {
}, main);
finder.run(); // Do this synchronously.
} else {
main.logger().warning("No overrides are defined for \"" + name + "\"");
e.setResult(e.getOrigin());
main.logger().warning("No overrides are defined for \"" + name + "\". Locating this structure will NOT work properly!");
}
}
}
@@ -34,7 +34,7 @@ public class SpigotListener implements Listener {
Entity entity = e.getEntity();
if(e.getEntityType().equals(EntityType.ENDER_SIGNAL)) {
main.getDebugLogger().info("Detected Ender Signal...");
if(!TerraWorld.isTerraWorld(BukkitAdapter.adapt(e.getEntity().getWorld()))) return;
if(!BukkitAdapter.adapt(e.getEntity().getWorld()).isTerraWorld()) return;
TerraWorld tw = main.getWorld(BukkitAdapter.adapt(e.getEntity().getWorld()));
EnderSignal signal = (EnderSignal) entity;
TerraStructure config = tw.getConfig().getStructureRegistry().get(tw.getConfig().getTemplate().getLocatable().get("STRONGHOLD"));
@@ -53,7 +53,7 @@ public class SpigotListener implements Listener {
@EventHandler
public void onCartographerChange(VillagerAcquireTradeEvent e) {
if(!TerraWorld.isTerraWorld(BukkitAdapter.adapt(e.getEntity().getWorld()))) return;
if(!BukkitAdapter.adapt(e.getEntity().getWorld()).isTerraWorld()) return;
if(!(e.getEntity() instanceof Villager)) return;
if(((Villager) e.getEntity()).getProfession().equals(Villager.Profession.CARTOGRAPHER)) {
main.logger().severe("Prevented server crash by stopping Cartographer villager from spawning.");
@@ -65,7 +65,7 @@ public class SpigotListener implements Listener {
@EventHandler
public void onCartographerLevel(VillagerCareerChangeEvent e) {
if(!TerraWorld.isTerraWorld(BukkitAdapter.adapt(e.getEntity().getWorld()))) return;
if(!BukkitAdapter.adapt(e.getEntity().getWorld()).isTerraWorld()) return;
if(e.getProfession().equals(Villager.Profession.CARTOGRAPHER)) {
main.logger().severe("Prevented server crash by stopping Cartographer villager from spawning.");
main.logger().severe("Please upgrade to Paper, which has a StructureLocateEvent that fixes this issue");
@@ -22,7 +22,9 @@ public class TerraListener implements EventListener {
public void injectTrees(ConfigPackPreLoadEvent event) {
for(TreeType value : TreeType.values()) {
try {
event.getPack().getTreeRegistry().add(BukkitAdapter.TREE_TRANSFORMER.translate(value), new BukkitTree(value, main));
String id = BukkitAdapter.TREE_TRANSFORMER.translate(value);
event.getPack().getTreeRegistry().add(id, new BukkitTree(value, main));
event.getPack().getTreeRegistry().get(id); // Platform trees should never be marked "dead"
} catch(DuplicateEntryException ignore) { // If another addon has already registered trees, do nothing.
}
}
@@ -2,6 +2,7 @@ package com.dfsek.terra.bukkit.population;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.bukkit.world.BukkitWorld;
import java.io.Serializable;
import java.util.UUID;
@@ -21,7 +22,7 @@ public class ChunkCoordinate implements Serializable {
public ChunkCoordinate(Chunk c) {
this.x = c.getX();
this.z = c.getZ();
this.worldID = c.getWorld().getUID();
this.worldID = ((BukkitWorld) c.getWorld()).getUID();
}
public UUID getWorldID() {
@@ -1,20 +0,0 @@
package com.dfsek.terra.bukkit.population;
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;
}
}
@@ -5,12 +5,11 @@ import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.util.FastRandom;
import com.dfsek.terra.api.world.generation.Chunkified;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.bukkit.TerraBukkitPlugin;
import com.dfsek.terra.bukkit.world.BukkitAdapter;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.WorldProfiler;
import com.dfsek.terra.bukkit.world.BukkitWorld;
import com.dfsek.terra.profiler.ProfileFrame;
import org.bukkit.generator.BlockPopulator;
import org.jetbrains.annotations.NotNull;
@@ -26,39 +25,36 @@ public class PopulationManager extends BlockPopulator {
private final TerraChunkGenerator generator;
private final HashSet<ChunkCoordinate> needsPop = new HashSet<>();
private final TerraPlugin main;
private WorldProfiler profiler;
public PopulationManager(TerraChunkGenerator generator, TerraPlugin main) {
this.generator = generator;
this.main = main;
}
private ProfileFuture measure() {
if(profiler != null) return profiler.measure("PopulationManagerTime");
return null;
}
public void attachProfiler(WorldProfiler p) {
this.profiler = p;
}
@SuppressWarnings("unchecked")
public synchronized void saveBlocks(World w) throws IOException {
File f = new File(Gaea.getGaeaFolder(w), "chunks.bin");
File f = new File(getDataFolder(w), "chunks.bin");
f.createNewFile();
SerializationUtil.toFile((HashSet<ChunkCoordinate>) needsPop.clone(), f);
}
@SuppressWarnings("unchecked")
public synchronized void loadBlocks(World w) throws IOException, ClassNotFoundException {
File f = new File(Gaea.getGaeaFolder(w), "chunks.bin");
File f = new File(getDataFolder(w), "chunks.bin");
needsPop.addAll((HashSet<ChunkCoordinate>) SerializationUtil.fromFile(f));
}
public static File getDataFolder(World w) {
File f = new File(((BukkitWorld) w).getWorldFolder(), "gaea");
f.mkdirs();
return f;
}
// Synchronize to prevent chunks from being queued for population multiple times.
public synchronized void checkNeighbors(int x, int z, World w) {
ChunkCoordinate c = new ChunkCoordinate(x, z, w.getUID());
public synchronized void checkNeighbors(int x, int z, World world) {
BukkitWorld w = (BukkitWorld) world;
ChunkCoordinate c = new ChunkCoordinate(x, z, (w).getUID());
if(w.isChunkGenerated(x + 1, z)
&& w.isChunkGenerated(x - 1, z)
&& w.isChunkGenerated(x, z + 1)
@@ -78,8 +74,9 @@ public class PopulationManager extends BlockPopulator {
}
@Override
@SuppressWarnings("try")
public void populate(org.bukkit.@NotNull World world, @NotNull Random random, org.bukkit.@NotNull Chunk source) {
try(ProfileFuture ignored = measure()) {
try(ProfileFrame ignore = main.getProfiler().profile("popman")) {
Chunk chunk = BukkitAdapter.adapt(source);
needsPop.add(new ChunkCoordinate(chunk));
int x = chunk.getX();
@@ -5,8 +5,10 @@ import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.profiler.ProfileFrame;
import org.bukkit.TreeType;
import java.util.Locale;
import java.util.Random;
public class BukkitTree implements Tree {
@@ -40,8 +42,11 @@ public class BukkitTree implements Tree {
}
@Override
@SuppressWarnings("try")
public boolean plant(Location l, Random r) {
return ((BukkitWorld) l.getWorld()).getHandle().generateTree(BukkitAdapter.adapt(l), delegate);
try(ProfileFrame ignore = main.getProfiler().profile("bukkit_tree:" + delegate.toString().toLowerCase(Locale.ROOT))) {
return ((BukkitWorld) l.getWorld()).getHandle().generateTree(BukkitAdapter.adapt(l), delegate);
}
}
@Override
@@ -37,17 +37,14 @@ public class BukkitWorld implements World {
return new BukkitChunkGenerator(delegate.getGenerator());
}
@Override
public String getName() {
return delegate.getName();
}
@Override
public UUID getUID() {
return delegate.getUID();
}
@Override
public boolean isChunkGenerated(int x, int z) {
return delegate.isChunkGenerated(x, z);
}
@@ -57,7 +54,6 @@ public class BukkitWorld implements World {
return BukkitAdapter.adapt(delegate.getChunkAt(x, z));
}
@Override
public File getWorldFolder() {
return delegate.getWorldFolder();
}
@@ -4,6 +4,7 @@ import com.dfsek.terra.api.platform.block.state.SerialState;
import com.dfsek.terra.api.platform.block.state.Sign;
import org.jetbrains.annotations.NotNull;
@SuppressWarnings("deprecation")
public class BukkitSign extends BukkitBlockState implements Sign {
protected BukkitSign(org.bukkit.block.Sign block) {
super(block);
@@ -3,16 +3,13 @@ main: "com.dfsek.terra.bukkit.TerraBukkitPlugin"
version: "@VERSION@"
load: "STARTUP"
author: dfsek
website: "@WIKI@"
api-version: "1.13"
description: "An insanely powerful free & open-source data-driven world generator."
description: "@DESCRIPTION@"
softdepend: [ "WorldEdit" ]
commands:
terra:
description: "Terra base command"
usage: "/terra "
aliases: [ "te" ]
permission: "terra.command"
locate:
description: "Locate a Terra Structure"
usage: "/locate <STRUCTURE_ID> <radius>"
permission: "terra.locate"
permission: "terra.command"
+35 -10
View File
@@ -6,6 +6,7 @@ import net.fabricmc.loom.task.RemapJarTask
plugins {
`java-library`
`maven-publish`
id("fabric-loom").version("0.6-SNAPSHOT")
id("com.modrinth.minotaur").version("1.1.0")
}
@@ -21,24 +22,24 @@ group = "com.dfsek.terra.fabric"
dependencies {
"shadedApi"(project(":common"))
"shadedImplementation"("org.yaml:snakeyaml:1.27")
"shadedImplementation"("com.googlecode.json-simple:json-simple:1.1.1")
"minecraft"("com.mojang:minecraft:1.16.5")
"mappings"("net.fabricmc:yarn:1.16.5+build.5:v2")
"modImplementation"("net.fabricmc:fabric-loader:0.11.2")
"modImplementation"("net.fabricmc.fabric-api:fabric-api:0.31.0+1.16")
}
tasks.named<ShadowJar>("shadowJar") {
relocate("org.json", "com.dfsek.terra.lib.json")
relocate("org.yaml", "com.dfsek.terra.lib.yaml")
"modCompileOnly"("com.sk89q.worldedit:worldedit-fabric-mc1.16:7.2.0-SNAPSHOT") {
exclude(group = "com.google.guava", module = "guava")
exclude(group = "com.google.code.gson", module = "gson")
exclude(group = "it.unimi.dsi", module = "fastutil")
exclude(group = "org.apache.logging.log4j", module = "log4j-api")
exclude(group = "org.apache.logging.log4j", module = "log4j-core")
}
}
configure<LoomGradleExtension> {
accessWidener("src/main/resources/terra.accesswidener")
refmapName = "terra-refmap.json"
}
val remapped = tasks.register<RemapJarTask>("remapShadedJar") {
@@ -52,15 +53,39 @@ val remapped = tasks.register<RemapJarTask>("remapShadedJar") {
}
tasks.register<TaskModrinthUpload>("publishModrinth") {
tasks.register<TaskModrinthUpload>("publishModrinthFabric") {
dependsOn("remapShadedJar")
group = "fabric"
token = System.getenv("MODRINTH_SECRET")
projectId = "FIlZB9L0"
versionNumber = project.version.toString()
versionNumber = "${project.version}-fabric"
uploadFile = remapped.get().archiveFile.get().asFile
releaseType = "beta"
addGameVersion("1.16.4")
addGameVersion("1.16.5")
addLoader("fabric")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifact(tasks["sourcesJar"])
artifact(tasks["jar"])
}
}
repositories {
val mavenUrl = "https://repo.codemc.io/repository/maven-releases/"
maven(mavenUrl) {
val mavenUsername: String? by project
val mavenPassword: String? by project
if (mavenUsername != null && mavenPassword != null) {
credentials {
username = mavenUsername
password = mavenPassword
}
}
}
}
}
@@ -0,0 +1,28 @@
package com.dfsek.terra.fabric;
import com.dfsek.terra.api.platform.modloader.Mod;
import net.fabricmc.loader.api.ModContainer;
public class FabricMod implements Mod {
private final ModContainer mod;
public FabricMod(ModContainer mod) {
this.mod = mod;
}
@Override
public String getID() {
return mod.getMetadata().getId();
}
@Override
public String getVersion() {
return mod.getMetadata().getVersion().getFriendlyString();
}
@Override
public String getName() {
return mod.getMetadata().getName();
}
}
@@ -1,5 +1,9 @@
package com.dfsek.terra.fabric;
import com.dfsek.tectonic.config.Configuration;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeRegistry;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.addons.TerraAddon;
@@ -8,142 +12,135 @@ import com.dfsek.terra.api.addons.annotations.Author;
import com.dfsek.terra.api.addons.annotations.Version;
import com.dfsek.terra.api.command.CommandManager;
import com.dfsek.terra.api.command.TerraCommandManager;
import com.dfsek.terra.api.command.exception.CommandException;
import com.dfsek.terra.api.command.exception.MalformedCommandException;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.EventManager;
import com.dfsek.terra.api.event.TerraEventManager;
import com.dfsek.terra.api.event.annotations.Global;
import com.dfsek.terra.api.event.annotations.Priority;
import com.dfsek.terra.api.event.events.config.ConfigPackPostLoadEvent;
import com.dfsek.terra.api.event.events.config.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.handle.ItemHandle;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.modloader.Mod;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.LockedRegistry;
import com.dfsek.terra.api.transform.NotNullValidator;
import com.dfsek.terra.api.transform.Transformer;
import com.dfsek.terra.api.transform.Validator;
import com.dfsek.terra.api.util.generic.pair.Pair;
import com.dfsek.terra.api.util.logging.DebugLogger;
import com.dfsek.terra.api.util.logging.Logger;
import com.dfsek.terra.commands.CommandUtil;
import com.dfsek.terra.config.GenericLoaders;
import com.dfsek.terra.config.PluginConfig;
import com.dfsek.terra.config.builder.BiomeBuilder;
import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.config.lang.Language;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.fabric.inventory.FabricItemHandle;
import com.dfsek.terra.fabric.mixin.GeneratorTypeAccessor;
import com.dfsek.terra.fabric.world.FabricAdapter;
import com.dfsek.terra.fabric.world.FabricBiome;
import com.dfsek.terra.fabric.world.FabricTree;
import com.dfsek.terra.fabric.world.FabricWorldHandle;
import com.dfsek.terra.fabric.world.TerraBiomeSource;
import com.dfsek.terra.fabric.world.features.PopulatorFeature;
import com.dfsek.terra.fabric.world.generator.FabricChunkGenerator;
import com.dfsek.terra.fabric.world.generator.FabricChunkGeneratorWrapper;
import com.dfsek.terra.fabric.config.PostLoadCompatibilityOptions;
import com.dfsek.terra.fabric.config.PreLoadCompatibilityOptions;
import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper;
import com.dfsek.terra.fabric.generation.PopulatorFeature;
import com.dfsek.terra.fabric.generation.TerraBiomeSource;
import com.dfsek.terra.fabric.handle.FabricItemHandle;
import com.dfsek.terra.fabric.handle.FabricWorldHandle;
import com.dfsek.terra.fabric.util.FabricUtil;
import com.dfsek.terra.profiler.Profiler;
import com.dfsek.terra.profiler.ProfilerImpl;
import com.dfsek.terra.registry.exception.DuplicateEntryException;
import com.dfsek.terra.registry.master.AddonRegistry;
import com.dfsek.terra.registry.master.ConfigRegistry;
import com.dfsek.terra.world.TerraWorld;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.block.Blocks;
import net.minecraft.client.world.GeneratorType;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.LiteralText;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeEffects;
import net.minecraft.world.biome.GenerationSettings;
import net.minecraft.world.biome.SpawnSettings;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.gen.chunk.ChunkGeneratorSettings;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.decorator.Decorator;
import net.minecraft.world.gen.decorator.NopeDecoratorConfig;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.ConfiguredFeatures;
import net.minecraft.world.gen.feature.DefaultBiomeFeatures;
import net.minecraft.world.gen.feature.DefaultFeatureConfig;
import net.minecraft.world.gen.feature.FeatureConfig;
import net.minecraft.world.gen.surfacebuilder.SurfaceBuilder;
import net.minecraft.world.gen.surfacebuilder.TernarySurfaceConfig;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;
import java.util.Set;
import java.util.stream.Collectors;
public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
private final org.apache.logging.log4j.Logger log4jLogger = LogManager.getLogger();
public static final PopulatorFeature POPULATOR_FEATURE = new PopulatorFeature(DefaultFeatureConfig.CODEC);
public static final ConfiguredFeature<?, ?> POPULATOR_CONFIGURED_FEATURE = POPULATOR_FEATURE.configure(FeatureConfig.DEFAULT).decorate(Decorator.NOPE.configure(NopeDecoratorConfig.INSTANCE));
private static TerraFabricPlugin instance;
private final Map<Long, TerraWorld> worldMap = new HashMap<>();
private final Map<DimensionType, Pair<ServerWorld, TerraWorld>> worldMap = new HashMap<>();
public Map<DimensionType, Pair<ServerWorld, TerraWorld>> getWorldMap() {
return worldMap;
}
private final EventManager eventManager = new TerraEventManager(this);
private final GenericLoaders genericLoaders = new GenericLoaders(this);
private final Logger logger = new Logger() {
private final org.apache.logging.log4j.Logger logger = LogManager.getLogger();
private final Profiler profiler = new ProfilerImpl();
private final Logger logger = new Logger() {
@Override
public void info(String message) {
logger.info(message);
log4jLogger.info(message);
}
@Override
public void warning(String message) {
logger.warn(message);
log4jLogger.warn(message);
}
@Override
public void severe(String message) {
logger.error(message);
log4jLogger.error(message);
}
};
private final DebugLogger debugLogger = new DebugLogger(logger);
private final ItemHandle itemHandle = new FabricItemHandle();
private final WorldHandle worldHandle = new FabricWorldHandle();
private final ConfigRegistry registry = new ConfigRegistry();
private final CheckedRegistry<ConfigPack> checkedRegistry = new CheckedRegistry<>(registry);
private final AddonRegistry addonRegistry = new AddonRegistry(new FabricAddon(this), this);
private final FabricAddon fabricAddon = new FabricAddon(this);
private final AddonRegistry addonRegistry = new AddonRegistry(fabricAddon, this);
private final LockedRegistry<TerraAddon> addonLockedRegistry = new LockedRegistry<>(addonRegistry);
private final PluginConfig config = new PluginConfig();
private final Transformer<String, Biome> biomeFixer = new Transformer.Builder<String, Biome>()
.addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse(id)), new NotNullValidator<>())
.addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse("minecraft:" + id.toLowerCase())), new NotNullValidator<>()).build();
.addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse(id)), Validator.notNull())
.addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse("minecraft:" + id.toLowerCase())), Validator.notNull()).build();
private File dataFolder;
private final CommandManager manager = new TerraCommandManager(this);
public CommandManager getManager() {
return manager;
}
public static TerraFabricPlugin getInstance() {
return instance;
}
public static String createBiomeID(ConfigPack pack, String biomeID) {
return pack.getTemplate().getID().toLowerCase() + "/" + biomeID.toLowerCase(Locale.ROOT);
}
@Override
public WorldHandle getWorldHandle() {
return worldHandle;
@@ -151,10 +148,13 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
@Override
public TerraWorld getWorld(World world) {
return worldMap.computeIfAbsent(world.getSeed(), w -> {
logger.info("Loading world " + w);
return new TerraWorld(world, ((FabricChunkGeneratorWrapper) ((FabricChunkGenerator) world.getGenerator()).getHandle()).getPack(), this);
});
return getWorld(((WorldAccess) world).getDimension());
}
public TerraWorld getWorld(DimensionType type) {
TerraWorld world = worldMap.get(type).getRight();
if(world == null) throw new IllegalArgumentException("No world exists with dimension type " + type);
return world;
}
@Override
@@ -174,7 +174,7 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
@Override
public boolean isDebug() {
return true;
return config.isDebug();
}
@Override
@@ -197,14 +197,11 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
config.load(this);
LangUtil.load(config.getLanguage(), this); // Load language.
boolean succeed = registry.loadAll(this);
Map<Long, TerraWorld> newMap = new HashMap<>();
worldMap.forEach((seed, tw) -> {
tw.getConfig().getSamplerCache().clear();
String packID = tw.getConfig().getTemplate().getID();
newMap.put(seed, new TerraWorld(tw.getWorld(), registry.get(packID), this));
worldMap.forEach((seed, pair) -> {
pair.getRight().getConfig().getSamplerCache().clear();
String packID = pair.getRight().getConfig().getTemplate().getID();
pair.setRight(new TerraWorld(pair.getRight().getWorld(), registry.get(packID), this));
});
worldMap.clear();
worldMap.putAll(newMap);
return succeed;
}
@@ -238,54 +235,21 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
genericLoaders.register(registry);
registry
.registerLoader(BlockData.class, (t, o, l) -> worldHandle.createBlockData((String) o))
.registerLoader(com.dfsek.terra.api.platform.world.Biome.class, (t, o, l) -> new FabricBiome(biomeFixer.translate((String) o)));
.registerLoader(com.dfsek.terra.api.platform.world.Biome.class, (t, o, l) -> biomeFixer.translate((String) o))
.registerLoader(Identifier.class, (t, o, l) -> {
Identifier identifier = Identifier.tryParse((String) o);
if(identifier == null) throw new LoadException("Invalid identifier: " + o);
return identifier;
});
}
private Biome createBiome(BiomeBuilder biome) {
SpawnSettings.Builder spawnSettings = new SpawnSettings.Builder();
DefaultBiomeFeatures.addFarmAnimals(spawnSettings);
DefaultBiomeFeatures.addMonsters(spawnSettings, 95, 5, 100);
public void packInit() {
logger.info("Loading config packs...");
registry.loadAll(this);
BiomeTemplate template = biome.getTemplate();
Map<String, Integer> colors = template.getColors();
registry.forEach(pack -> pack.getBiomeRegistry().forEach((id, biome) -> Registry.register(BuiltinRegistries.BIOME, new Identifier("terra", FabricUtil.createBiomeID(pack, id)), FabricUtil.createBiome(fabricAddon, biome, pack)))); // Register all Terra biomes.
Biome vanilla = ((FabricBiome) new ArrayList<>(biome.getVanillaBiomes().getContents()).get(0)).getHandle();
GenerationSettings.Builder generationSettings = new GenerationSettings.Builder();
generationSettings.surfaceBuilder(SurfaceBuilder.DEFAULT.withConfig(new TernarySurfaceConfig(Blocks.GRASS_BLOCK.getDefaultState(), Blocks.DIRT.getDefaultState(), Blocks.GRAVEL.getDefaultState()))); // It needs a surfacebuilder, even though we dont use it.
generationSettings.feature(GenerationStep.Feature.VEGETAL_DECORATION, POPULATOR_CONFIGURED_FEATURE);
BiomeEffects.Builder effects = new BiomeEffects.Builder()
.waterColor(colors.getOrDefault("water", vanilla.getEffects().waterColor))
.waterFogColor(colors.getOrDefault("water-fog", vanilla.getEffects().waterFogColor))
.fogColor(colors.getOrDefault("fog", vanilla.getEffects().fogColor))
.skyColor(colors.getOrDefault("sky", vanilla.getEffects().skyColor))
.grassColorModifier(vanilla.getEffects().grassColorModifier);
if(colors.containsKey("grass")) {
effects.grassColor(colors.get("grass"));
} else {
vanilla.getEffects().grassColor.ifPresent(effects::grassColor);
}
vanilla.getEffects().foliageColor.ifPresent(effects::foliageColor);
if(colors.containsKey("foliage")) {
effects.foliageColor(colors.get("foliage"));
} else {
vanilla.getEffects().foliageColor.ifPresent(effects::foliageColor);
}
return new Biome.Builder()
.precipitation(vanilla.getPrecipitation())
.category(vanilla.getCategory())
.depth(vanilla.getDepth())
.scale(vanilla.getScale())
.temperature(vanilla.getTemperature())
.downfall(vanilla.getDownfall())
.effects(effects.build())
.spawnSettings(spawnSettings.build())
.generationSettings(generationSettings.build())
.build();
logger.info("Loaded packs.");
}
@Override
@@ -295,6 +259,7 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
this.dataFolder = new File(FabricLoader.getInstance().getConfigDir().toFile(), "Terra");
saveDefaultConfig();
config.load(this);
debugLogger.setDebug(config.isDebug());
LangUtil.load(config.getLanguage(), this);
logger.info("Initializing Terra...");
@@ -303,84 +268,21 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
}
logger.info("Loaded addons.");
registry.loadAll(this);
logger.info("Loaded packs.");
Registry.register(Registry.FEATURE, new Identifier("terra", "flora_populator"), POPULATOR_FEATURE);
RegistryKey<ConfiguredFeature<?, ?>> floraKey = RegistryKey.of(Registry.CONFIGURED_FEATURE_WORLDGEN, new Identifier("terra", "flora_populator"));
Registry.register(Registry.FEATURE, new Identifier("terra", "populator"), POPULATOR_FEATURE);
RegistryKey<ConfiguredFeature<?, ?>> floraKey = RegistryKey.of(Registry.CONFIGURED_FEATURE_WORLDGEN, new Identifier("terra", "populator"));
Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, floraKey.getValue(), POPULATOR_CONFIGURED_FEATURE);
registry.forEach(pack -> pack.getBiomeRegistry().forEach((id, biome) -> Registry.register(BuiltinRegistries.BIOME, new Identifier("terra", createBiomeID(pack, id)), createBiome(biome)))); // Register all Terra biomes.
Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), FabricChunkGeneratorWrapper.CODEC);
Registry.register(Registry.BIOME_SOURCE, new Identifier("terra:terra"), TerraBiomeSource.CODEC);
if(FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
registry.forEach(pack -> {
final GeneratorType generatorType = new GeneratorType("terra." + pack.getTemplate().getID()) {
@Override
protected ChunkGenerator getChunkGenerator(Registry<Biome> biomeRegistry, Registry<ChunkGeneratorSettings> chunkGeneratorSettingsRegistry, long seed) {
return new FabricChunkGeneratorWrapper(new TerraBiomeSource(biomeRegistry, seed, pack), seed, pack);
}
};
//noinspection ConstantConditions
((GeneratorTypeAccessor) generatorType).setTranslationKey(new LiteralText("Terra:" + pack.getTemplate().getID()));
GeneratorTypeAccessor.getVALUES().add(generatorType);
});
}
CommandManager manager = new TerraCommandManager(this);
try {
CommandUtil.registerAll(manager);
} catch(MalformedCommandException e) {
e.printStackTrace(); // TODO do something here even though this should literally never happen
}
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> {
int max = manager.getMaxArgumentDepth();
RequiredArgumentBuilder<ServerCommandSource, String> arg = argument("arg" + (max - 1), StringArgumentType.word());
for(int i = 0; i < max; i++) {
RequiredArgumentBuilder<ServerCommandSource, String> next = argument("arg" + (max - i - 1), StringArgumentType.word());
arg = next.then(assemble(arg, manager));
}
dispatcher.register(literal("terra").executes(context -> 1).then(assemble(arg, manager)));
dispatcher.register(literal("te").executes(context -> 1).then(assemble(arg, manager)));
//dispatcher.register(literal("te").redirect(root));
}
);
}
private RequiredArgumentBuilder<ServerCommandSource, String> assemble(RequiredArgumentBuilder<ServerCommandSource, String> in, CommandManager manager) {
return in.suggests((context, builder) -> {
List<String> args = parseCommand(context.getInput());
CommandSender sender = FabricAdapter.adapt(context.getSource());
try {
manager.tabComplete(args.remove(0), sender, args).forEach(builder::suggest);
} catch(CommandException e) {
sender.sendMessage(e.getMessage());
}
return builder.buildFuture();
}).executes(context -> {
List<String> args = parseCommand(context.getInput());
try {
manager.execute(args.remove(0), FabricAdapter.adapt(context.getSource()), args);
} catch(CommandException e) {
context.getSource().sendError(new LiteralText(e.getMessage()));
}
return 1;
});
}
private List<String> parseCommand(String command) {
if(command.startsWith("/terra ")) command = command.substring("/terra ".length());
else if(command.startsWith("/te ")) command = command.substring("/te ".length());
List<String> c = new ArrayList<>(Arrays.asList(command.split(" ")));
if(command.endsWith(" ")) c.add("");
return c;
logger.info("Finished initialization.");
}
@@ -389,15 +291,32 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
return eventManager;
}
@Override
public Set<Mod> getMods() {
return FabricLoader.getInstance().getAllMods().stream().map(FabricMod::new).collect(Collectors.toSet());
}
@Override
public Profiler getProfiler() {
return profiler;
}
@Addon("Terra-Fabric")
@Author("Terra")
@Version("1.0.0")
private static final class FabricAddon extends TerraAddon implements EventListener {
public static final class FabricAddon extends TerraAddon implements EventListener {
private final TerraPlugin main;
private final Map<ConfigPack, Pair<PreLoadCompatibilityOptions, PostLoadCompatibilityOptions>> templates = new HashMap<>();
private final Map<ConfigPack, Configuration> compatConfigs = new HashMap<>();
private final ConfigLoader compatLoader = new ConfigLoader();
private FabricAddon(TerraPlugin main) {
this.main = main;
main.register(compatLoader);
}
@Override
@@ -428,14 +347,68 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
injectTree(treeRegistry, "MEGA_SPRUCE", ConfiguredFeatures.MEGA_SPRUCE);
injectTree(treeRegistry, "CRIMSON_FUNGUS", ConfiguredFeatures.CRIMSON_FUNGI);
injectTree(treeRegistry, "WARPED_FUNGUS", ConfiguredFeatures.WARPED_FUNGI);
Configuration compat;
try {
compat = new Configuration(event.getLoader().get("compat.yml"));
main.logger().info("Loading compatibility options from compat.yml.");
} catch(FileNotFoundException e) {
compat = new Configuration(new HashMap<>()); // blank config
main.logger().info("No compat.yml found, not loading compatibility options.");
} catch(IOException e) {
throw new RuntimeException("Failed to load compatibility config", e); // Something went wrong.
}
compatConfigs.put(event.getPack(), compat);
PreLoadCompatibilityOptions template = new PreLoadCompatibilityOptions();
try {
compatLoader.load(template, compat);
} catch(ConfigException e) {
e.printStackTrace();
}
if(template.doRegistryInjection()) {
BuiltinRegistries.CONFIGURED_FEATURE.getEntries().forEach(entry -> {
if(!template.getExcludedRegistryFeatures().contains(entry.getKey().getValue())) {
try {
event.getPack().getTreeRegistry().add(entry.getKey().getValue().toString(), (Tree) entry.getValue());
main.getDebugLogger().info("Injected ConfiguredFeature " + entry.getKey().getValue() + " as Tree.");
} catch(DuplicateEntryException ignored) {
}
}
});
}
templates.put(event.getPack(), Pair.of(template, null));
}
@Priority(Priority.HIGHEST)
@Global
public void createInjectionOptions(ConfigPackPostLoadEvent event) {
PostLoadCompatibilityOptions template = new PostLoadCompatibilityOptions();
try {
compatLoader.load(template, compatConfigs.get(event.getPack()));
} catch(ConfigException e) {
e.printStackTrace();
}
templates.get(event.getPack()).setRight(template);
}
private void injectTree(CheckedRegistry<Tree> registry, String id, ConfiguredFeature<?, ?> tree) {
try {
registry.add(id, new FabricTree(tree));
registry.add(id, (Tree) tree);
} catch(DuplicateEntryException ignore) {
}
}
public Map<ConfigPack, Pair<PreLoadCompatibilityOptions, PostLoadCompatibilityOptions>> getTemplates() {
return templates;
}
}
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.fabric.world.block;
package com.dfsek.terra.fabric.block;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.Block;
@@ -6,9 +6,9 @@ import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.BlockType;
import com.dfsek.terra.api.platform.block.state.BlockState;
import com.dfsek.terra.fabric.world.FabricAdapter;
import com.dfsek.terra.fabric.world.block.state.FabricBlockState;
import com.dfsek.terra.fabric.world.handles.world.FabricWorldAccess;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.fabric.util.FabricAdapter;
import net.minecraft.block.FluidBlock;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.WorldAccess;
@@ -21,7 +21,10 @@ public class FabricBlock implements Block {
@Override
public void setBlockData(BlockData data, boolean physics) {
delegate.worldAccess.setBlockState(delegate.position, ((FabricBlockData) data).getHandle(), physics ? 3 : 1042, 0);
delegate.worldAccess.setBlockState(delegate.position, ((FabricBlockData) data).getHandle(), physics ? 3 : 1042);
if(physics && ((FabricBlockData) data).getHandle().getBlock() instanceof FluidBlock) {
delegate.worldAccess.getFluidTickScheduler().schedule(delegate.position, ((FluidBlock) ((FabricBlockData) data).getHandle().getBlock()).getFluidState(((FabricBlockData) data).getHandle()).getFluid(), 0);
}
}
@Override
@@ -31,7 +34,7 @@ public class FabricBlock implements Block {
@Override
public BlockState getState() {
return FabricBlockState.newInstance(this);
return FabricAdapter.adapt(this);
}
@Override
@@ -47,7 +50,7 @@ public class FabricBlock implements Block {
@Override
public Location getLocation() {
return FabricAdapter.adapt(delegate.position).toLocation(new FabricWorldAccess(delegate.worldAccess));
return FabricAdapter.adapt(delegate.position).toLocation((World) delegate.worldAccess);
}
@Override
@@ -1,11 +1,10 @@
package com.dfsek.terra.fabric.world.block;
package com.dfsek.terra.fabric.block;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.BlockType;
import com.dfsek.terra.fabric.world.FabricAdapter;
import com.dfsek.terra.fabric.mixin.access.StateAccessor;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.state.State;
import net.minecraft.util.registry.Registry;
import java.util.stream.Collectors;
@@ -19,7 +18,7 @@ public class FabricBlockData implements BlockData {
@Override
public BlockType getBlockType() {
return FabricAdapter.adapt(delegate.getBlock());
return (BlockType) delegate.getBlock();
}
@Override
@@ -41,7 +40,7 @@ public class FabricBlockData implements BlockData {
StringBuilder data = new StringBuilder(Registry.BLOCK.getId(delegate.getBlock()).toString());
if(!delegate.getEntries().isEmpty()) {
data.append('[');
data.append(delegate.getEntries().entrySet().stream().map(State.PROPERTY_MAP_PRINTER).collect(Collectors.joining(",")));
data.append(delegate.getEntries().entrySet().stream().map(StateAccessor.getPropertyMapPrinter()).collect(Collectors.joining(",")));
data.append(']');
}
return data.toString();
@@ -1,7 +1,7 @@
package com.dfsek.terra.fabric.world.block.data;
package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.data.AnaloguePowerable;
import com.dfsek.terra.fabric.world.block.FabricBlockData;
import com.dfsek.terra.fabric.block.FabricBlockData;
import net.minecraft.block.BlockState;
/**
@@ -1,9 +1,9 @@
package com.dfsek.terra.fabric.world.block.data;
package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.Directional;
import com.dfsek.terra.fabric.world.FabricAdapter;
import com.dfsek.terra.fabric.world.block.FabricBlockData;
import com.dfsek.terra.fabric.block.FabricBlockData;
import com.dfsek.terra.fabric.util.FabricAdapter;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.DirectionProperty;
@@ -1,8 +1,8 @@
package com.dfsek.terra.fabric.world.block.data;
package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.MultipleFacing;
import com.dfsek.terra.fabric.world.block.FabricBlockData;
import com.dfsek.terra.fabric.block.FabricBlockData;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.Properties;
@@ -1,8 +1,9 @@
package com.dfsek.terra.fabric.world.block.data;
package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.Axis;
import com.dfsek.terra.api.platform.block.data.Orientable;
import com.dfsek.terra.fabric.world.block.FabricBlockData;
import com.dfsek.terra.fabric.block.FabricBlockData;
import com.dfsek.terra.fabric.util.FabricAdapter;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.EnumProperty;
import net.minecraft.util.math.Direction;
@@ -26,11 +27,11 @@ public class FabricOrientable extends FabricBlockData implements Orientable {
@Override
public Axis getAxis() {
return FabricEnumAdapter.adapt(getHandle().get(property));
return FabricAdapter.adapt(getHandle().get(property));
}
@Override
public void setAxis(Axis axis) {
delegate = delegate.with(property, FabricEnumAdapter.adapt(axis));
delegate = delegate.with(property, FabricAdapter.adapt(axis));
}
}

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