├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── changelog.txt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src ├── api └── java │ ├── baubles │ └── api │ │ ├── BaubleType.java │ │ ├── BaublesApi.java │ │ ├── IBauble.java │ │ ├── cap │ │ ├── BaublesCapabilities.java │ │ ├── BaublesContainer.java │ │ ├── BaublesContainerProvider.java │ │ └── IBaublesItemHandler.java │ │ ├── inv │ │ └── BaublesInventoryWrapper.java │ │ ├── package-info.java │ │ └── render │ │ └── IRenderBauble.java │ └── mcjty │ └── enigma │ └── api │ └── IEnigmaScript.java └── main ├── java └── mcjty │ └── incontrol │ ├── ErrorHandler.java │ ├── ForgeEventHandlers.java │ ├── InControl.java │ ├── commands │ ├── CmdClearStats.java │ ├── CmdDays.java │ ├── CmdDebug.java │ ├── CmdInfo.java │ ├── CmdKillMobs.java │ ├── CmdList.java │ ├── CmdPhases.java │ ├── CmdReload.java │ ├── CmdShowMobs.java │ ├── CmdShowStats.java │ ├── Counter.java │ └── ModCommands.java │ ├── compat │ ├── BaublesSupport.java │ ├── EnigmaSupport.java │ ├── GameStageSupport.java │ ├── LostCitySupport.java │ ├── ModRuleCompatibilityLayer.java │ └── SereneSeasonsSupport.java │ ├── data │ ├── DataStorage.java │ ├── PhaseTools.java │ └── Statistics.java │ ├── rules │ ├── ExperienceRule.java │ ├── LootRule.java │ ├── PhaseRule.java │ ├── PotentialSpawnRule.java │ ├── RuleCache.java │ ├── RulesManager.java │ ├── SpawnRule.java │ ├── SummonAidRule.java │ ├── SummonEventGetter.java │ └── support │ │ ├── GenericRuleEvaluator.java │ │ └── RuleKeys.java │ ├── setup │ └── ModSetup.java │ ├── spawner │ ├── SpawnerConditions.java │ ├── SpawnerParser.java │ ├── SpawnerRule.java │ └── SpawnerSystem.java │ └── tools │ ├── cache │ ├── StructureCache.java │ └── StructureCacheEntry.java │ ├── rules │ ├── CommonRuleEvaluator.java │ ├── CommonRuleKeys.java │ ├── IEventQuery.java │ ├── IModRuleCompatibilityLayer.java │ └── RuleBase.java │ ├── typed │ ├── Attribute.java │ ├── AttributeMap.java │ ├── GenericAttributeMapFactory.java │ ├── Key.java │ └── Type.java │ └── varia │ ├── Box.java │ ├── DummyCommandSender.java │ ├── JSonTools.java │ ├── LookAtTools.java │ └── Tools.java └── resources ├── META-INF └── mods.toml └── pack.mcmeta /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | .gradle 26 | /build/ 27 | 28 | # Ignore Gradle GUI config 29 | gradle-app.setting 30 | 31 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 32 | !gradle-wrapper.jar 33 | 34 | # Cache of project 35 | .gradletasknamecache 36 | 37 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 38 | # gradle/wrapper/gradle-wrapper.properties -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # InControl 2 | Be In Control of Mob Spawns and others 3 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | 2 | // For those who want the bleeding edge 3 | buildscript { 4 | repositories { 5 | maven { url = 'https://files.minecraftforge.net/maven' } 6 | maven { url 'https://plugins.gradle.org/m2/' } 7 | jcenter() 8 | mavenCentral() 9 | } 10 | dependencies { 11 | classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true 12 | classpath 'gradle.plugin.com.matthewprenger:CurseGradle:1.4.0' 13 | } 14 | } 15 | 16 | apply plugin: 'net.minecraftforge.gradle' 17 | apply plugin: 'eclipse' 18 | apply plugin: 'com.matthewprenger.cursegradle' 19 | apply plugin: 'maven-publish' 20 | 21 | //configurations { 22 | // // configuration that holds jars to embed inside the jar 23 | // embed 24 | //} 25 | 26 | repositories { 27 | maven { // JEI 28 | url "http://dvs1.progwml6.com/files/maven" 29 | } 30 | maven { // Patchouli 31 | url "https://maven.blamejared.com" 32 | } 33 | maven { 34 | name 'OC Repo' 35 | url "http://maven.cil.li/" 36 | } 37 | maven { // TOP 38 | name 'tterrag maven' 39 | url "http://maven.tterrag.com/" 40 | } 41 | maven { // McJtyLib 42 | url "http://maven.k-4u.nl" 43 | } 44 | maven { 45 | name = "sonatype" 46 | url = "https://oss.sonatype.org/content/repositories/snapshots/" 47 | } 48 | maven { 49 | name = "CoFH Maven" 50 | url = "http://maven.covers1624.net" 51 | } 52 | } 53 | 54 | 55 | group= "com.github.mcjty" 56 | archivesBaseName = "incontrol" 57 | 58 | sourceCompatibility = 1.8 59 | targetCompatibility = 1.8 60 | 61 | minecraft { 62 | mappings channel: 'official', version: "1.16.5" 63 | accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') 64 | 65 | runs { 66 | client = { 67 | // recommended logging data for a userdev environment 68 | properties 'forge.logging.markers': 'SCAN,REGISTRIES,REGISTRYDUMP' 69 | // recommended logging level for the console 70 | properties 'forge.logging.console.level': 'debug' 71 | workingDirectory project.file('run').canonicalPath 72 | source sourceSets.main 73 | } 74 | server = { 75 | // recommended logging data for a userdev environment 76 | properties 'forge.logging.markers': 'SCAN,REGISTRIES,REGISTRYDUMP' 77 | // recommended logging level for the console 78 | properties 'forge.logging.console.level': 'debug' 79 | workingDirectory project.file('run').canonicalPath 80 | source sourceSets.main 81 | } 82 | data = { 83 | workingDirectory project.file('run').canonicalPath 84 | property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' 85 | property 'forge.logging.console.level', 'debug' 86 | args '--mod', 'incontrol', '--all', '--output', file('src/generated/resources/'), '--existing', sourceSets.main.resources.srcDirs[0] 87 | source sourceSets.main 88 | } 89 | } 90 | } 91 | 92 | jar { 93 | manifest { 94 | attributes 'FMLAT': 'accesstransformer.cfg', 95 | "Specification-Title": "incontrol", 96 | "Specification-Vendor": "McJty", 97 | "Specification-Version": "1", 98 | "Implementation-Title": project.name, 99 | "Implementation-Version": "${version}", 100 | "Implementation-Vendor" :"McJty", 101 | "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") 102 | } 103 | } 104 | 105 | 106 | dependencies { 107 | minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" 108 | compileOnly fg.deobf("mezz.jei:jei-${jei_version}:api") 109 | runtimeOnly fg.deobf("mezz.jei:jei-${jei_version}") 110 | if (findProject(':TheOneProbe') != null) { 111 | compile project(':TheOneProbe') 112 | } else { 113 | compile fg.deobf(project.dependencies.create("mcjty.theoneprobe:TheOneProbe-${top_version}") { 114 | transitive = false 115 | }) 116 | } 117 | // if (findProject(':McJtyTools') != null) { 118 | // compile project(':McJtyTools') 119 | // } else { 120 | // compile fg.deobf (project.dependencies.create("com.github.mcjty:mcjtytools:${mcjtytools_version}") { 121 | // transitive = false 122 | // }) 123 | // embed "com.github.mcjty:mcjtytools:${mcjtytools_version}" 124 | // } 125 | 126 | compile fg.deobf("net.darkhax.bookshelf:Bookshelf-1.16.4:9.3.18") 127 | compile fg.deobf("net.darkhax.gamestages:GameStages-1.16.4:6.0.1") 128 | compile fg.deobf (project.dependencies.create("com.github.mcjty:lostcities:${lostcities_version}") { 129 | transitive = false 130 | }) 131 | //compile "serene-seasons:SereneSeasons-1.12.2:1.2.15:universal" 132 | } 133 | 134 | String getChangelogText() { 135 | def changelogFile = file('changelog.txt') 136 | String str = '' 137 | int lineCount = 0 138 | boolean done = false 139 | changelogFile.eachLine { 140 | if (done || it == null) { 141 | return 142 | } 143 | if (it.size() > 1) { 144 | def temp = it 145 | if (lineCount == 0) { 146 | temp = "${modname} ${version}" 147 | temp = "

$temp

" 148 | } else if (it.startsWith('-')) { 149 | temp = "   $temp" 150 | temp = temp.replaceAll("(\\S+\\/\\S+)#([0-9]+)\\b", "\$0"); 151 | temp = temp.replaceAll("#([0-9]+)\\b(?!<\\/a>)", "\$0"); 152 | } else { 153 | temp = "

$temp

" 154 | } 155 | str += "$temp
" 156 | lineCount++ 157 | return 158 | } else { 159 | done = true 160 | } 161 | } 162 | return str 163 | } 164 | 165 | tasks.curseforge.enabled = project.hasProperty('curseforge_key') 166 | 167 | curseforge { 168 | if (project.hasProperty('curseforge_key')) { 169 | apiKey = project.curseforge_key 170 | } 171 | 172 | project { 173 | id = project.projectId 174 | changelog = System.getenv('CHANGELOG') == null || System.getenv('CHANGELOG').equals('none') ? getChangelogText() : System.getenv('CHANGELOG') 175 | changelogType = 'html' 176 | releaseType = project.curse_type 177 | addGameVersion '1.16.4' 178 | addGameVersion '1.16.5' 179 | mainArtifact(jar) { 180 | displayName = "${modname} - ${version}" 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | 1.16-5.2.12: 2 | - Fixed a potential incompatibility with fake worlds 3 | 4 | 1.16-5.2.11: 5 | - Fixed a bug with nbt matching (comparing any given tag with 'value'). It would only work for numeric values. Now strings and boolean values are also supported 6 | 7 | 1.16-5.2.10: 8 | - Fixed minlight/maxlight 9 | 10 | 1.16-5.2.9: 11 | - Added support for babies (new 'baby' keyword) 12 | 13 | 1.16-5.2.8: 14 | - New feature where you can specify 'all': true in a counting rule (similar to hostile/passive) 15 | 16 | 1.16-5.2.7: 17 | - Fixed the 'continue' keyword in spawn.json 18 | 19 | 1.16-5.2.6: 20 | - Made InControl compatible with FxControl again 21 | - Fixed the 'phase' keyword for spawn rules 22 | 23 | 1.16-5.2.5: 24 | - Bugfix with onjoin 25 | 26 | 1.16-5.2.4: 27 | - Added checks everywhere to see if invalid keywords are being used. When a keyword is not recognized you will get a warning 28 | - Added new 'daycount' condition for phases and normal rules. This condition will evaluate true every 'N'th day. For example, "daycount": 10 will be true on day 0, day 10, day 20, and so on 29 | 30 | 1.16-5.2.3: 31 | - Added new 'healthset', 'damageset', and 'speedset' keywords to specifically hard-set these attributes instead of modifying them 32 | - Added protection to spawner so it doesn't try forever to find a suitable place to spawn a mob in case the box has a weird shape 33 | - New statistics for spawn.json and spawner.json. These can help with debugging. Use the commands /incontrol showstats or /incontrol clearstats 34 | - Fixed a problem where setting the current day (using /incontrol days) didn't get persisted correctly 35 | 36 | 1.16-5.2.2: 37 | - Attempt two to fix the spawner deadlock 38 | 39 | 1.16-5.2.1: 40 | - Fixed a problem with the spawner where it was possible to get a deadlock situation with a rule that never managed to succeed 41 | 42 | 1.16-5.2.0: 43 | - InControl now keeps track of the day counter. Using the '/incontrol days' command you can see what the current day is and also change it. The day counter progresses whenever the time goes from night to day 44 | - New 'mindaycount' and 'maxdaycount' tags for spawn.json, potentialspawn.json, summonaid.json, and also the new spawner.json. 45 | - New phases.json rule file. There you can define phase rules for a limited set of global conditions. These phases can then be used in spawner, spawn, potentialspawn, ... for a more optimal way to check for rules 46 | - New '/incontrol phases' command to check the current active phases 47 | - New '/incontrol list' command to list all current mobs in the current world 48 | - New 'weight' system for spawner so that you can now have relative weights for the different mobs spawned by a single rule 49 | - The 'difficulty' test was broken 50 | - Changed the 'inwater' option for spawner to only work for actual water and not for other fluids 51 | - Added new 'inliquid' option which works for any liquid (as 'inwater' used to do) 52 | - Added new 'inlava' option which works for lava 53 | - Added the ability for spawner.json to spawn mobs that belong to the given biome. The new tag 'mobsfrombiome' can be used for that (instead of the normal 'mob' list). Possible values for this tag are: monster, creature, ambient, water_creature, water_ambient, and misc 54 | 55 | 1.16-5.1.9: 56 | - 'angry' tag should work better now 57 | - The spawner system will no longer at@Dtempt to spawn hostile mobs in peaceful mode 58 | - Fixed a serious problem with spawn rules using 'onjoin' and the 'block' test. It was possible that this rule would cause a deadlock (a non responsive Minecraft basically) 59 | - The spawner system will no longer try to spawn mobs in unloaded chunks 60 | - Much better error reporting and no longer crashing the game when there are json errors 61 | 62 | 1.16-5.1.8: 63 | - Fixed mintime and maxtime 64 | 65 | 1.16-5.1.7: 66 | - Fixed structure testing for good hopefully 67 | - Fixed a serious problem with 'onjoin': true. It would also work for players and by doing that you could prevent players from joining the world which unfortunatelly doesn't work too well. Changed so that players are no longer affected 68 | 69 | 1.16-5.1.6: 70 | - Fixed a few tests to work properly on new chunks 71 | 72 | 1.16-5.1.5: 73 | - Structure testing works again 74 | - Added new 'dimensionmod' feature so that you can have a rule match for all dimensions of a given mod (like for example 'rftoolsdim') 75 | 76 | 1.16-5.1.4: 77 | - Fixed a crash with the new spawner when the player moves outside world boundaries 78 | 79 | 1.16-5.1.3: 80 | - LostCity support is working again 81 | - Made counting slightly safer in rare circumstances 82 | 83 | 1.16-5.1.2: 84 | - Gamestage support is working again 85 | 86 | 1.16-5.1.1: 87 | - Small bugfix 88 | 89 | 1.16-5.1.0: 90 | - Big new spawner system (spawner.json) which implements a custom spawner with very little restrictions 91 | - New 'incontrol' tag for spawn.json to allow to test for a mob spawned by this new system 92 | 93 | 1.16-5.0.4: 94 | - Fixed a big bug with the 'block' test which could cause worlgen to hang in some situations 95 | 96 | 1.16-5.0.3: 97 | - Fixed a bug causing mob condition with multiple mobs to fail (one mob was fine) 98 | 99 | 1.16-5.0.2: 100 | - The 'biome' test would crash on biomes that were created using json 101 | - New 'continue' flag for spawn rules. If this is true then when this rule fires it will not prevent processing for subsequent rules. This can be used (for example) to give armor to mobs under certain circumstances but still do other processing later 102 | 103 | 1.16-5.0.1: 104 | - The mob counter now ignores the nodespawn flag. This should make it more compatible with modded mobs 105 | 106 | 5.0.0: 107 | - Biome registry name is now preferred for biome checks 108 | - 'tempcategory' is removed and replaced with a more generic 'category' for biomes. It's also a list now. The list of current categories is: taiga, extreme_hills, jungle, mesa, plains, savanna, icy, the_end, beach, forest, ocean, desert, river, swamp, mushroom and nether 109 | - 'biometype' has changed. It now only works for the following values: desert, desert_legacy, warm, cool, and icy 110 | - Numerical dimension ID's no longer work (like 0 for the overworld. Use 'minecraft:overworld' instead) 111 | 112 | 4.0.4: 113 | - Fixed a bug with the health, damage, and speed actions. They often fired multiple times making the mobs too OP 114 | 115 | 4.0.3: 116 | - 'perchunk' is implemented again 117 | - Avoid server-side crashes in combination with debug command 118 | 119 | 4.0.2: 120 | - Darkere improved performance when removing large amounts of mobs in potential spawn 121 | 122 | 4.0.1: 123 | - Fixed a problem where the config files where generated in the root 124 | 125 | 3.9.16: 126 | - Fixed a problem where 'onjoin' rules were also firing on the client which could cause issues with some of the conditions that don't properly work on the client 127 | 128 | 3.9.15: 129 | - Worked around a problem caused in the previous version. The issue was that there was both a condition called 'helditem' as well as an action called 'helditem'. For spawns the condition has been renamed to 'playerhelditem'. It is recommended to use this in other places as well (when used as a condition) 130 | 131 | 3.9.14: 132 | - Implemented a much requested feature with the spawn rules. That is support for gamestages. In Control will use the closest player (with a configurable maximum distance of 100). In addition keywords like helditem, helmet, trinker, ... are now also supported for spawn rules 133 | 134 | 3.9.13: 135 | - Fixed a problem with the mincount/maxcount always using a hostile counter 136 | 137 | 3.9.12: 138 | - Fixed a compatibility problem with old maxcount/mincount syntax 139 | 140 | 3.9.11: 141 | - Fixed a problem that 'onJoin' rules would also affect entities like item drops and non-living entities 142 | - Much more powerful 'mincount' and 'maxcount' syntax. The old syntax is still supported but you can now use a JSON object to specify one or more entities to count on, count entities for a given mod, and count scaled per player or per loaded chunk 143 | - Fixed a problem with Minecraft mods being reported as 'forge' instead of 'minecraft' 144 | 145 | 3.9.10: 146 | - Removed some debug code 147 | 148 | 3.9.9: 149 | - Allow 'count' for itemstacks with 'give' and related commands 150 | - Big optimisation in how 'maxcount' and 'mincount' are handled 151 | 152 | 3.9.8: 153 | - If a spawn rule has no explicit result given (as opposed to result default, deny, or allow) then InControl will no longer set any result but just leave the result in the event as it already is 154 | - Added new 'customname' action for spawn rules that you can use to set customnames on mobs when they spawn (turns out this is not possible to do with NBT) 155 | - The 'mintime' and 'maxtime' tests will now correctly work beyond the first day 156 | 157 | 3.9.7: 158 | - Various cleanups from SM9 159 | - Subscribe to events with lowest priority to potentially catch more mods which have the same subscriber (from SM9) 160 | - Fixed 'remove' in potential spawn. It was broken 161 | 162 | 3.9.6: 163 | - Update to be compatible with Fx Control 164 | 165 | 3.9.5: 166 | - Update to be compatible with Fx Control 167 | 168 | 3.9.4: 169 | - Loot control will now also support the more advanced itemstack syntax for removal. Note that this is a potentially compatibility breaking change as specifying something like 'minecraft:stone_sword' (without meta) will now match all stone swords while before it would only match stone_sword with meta 0 170 | 171 | 3.9.3: 172 | - Fixed a bug with the 'empty' keyword for items 173 | - Postponed loading of the rule files so that blocks/items from other mods can be found better 174 | 175 | 3.9.2: 176 | - New 'mod' attribute for 'block' test so that you can test for modded blocks: 'block': { 'mod': 'rftools' } 177 | - New 'mod' attribute for 'helditem' (and similar) test so that you can test for modded blocks 178 | - New 'empty' attribute for 'helditem' (and similar) tests so that you can test for an empty item: 'helditem': { 'empty': true } 179 | - New 'count' attribute for 'helditem' (and similar) tests so that you can add expresssions to test for amounts. For example 'helditem': { 'item': 'minecraft:coal', 'count': '>=10' } 180 | - New 'ore' attribute for 'helditem' (and similar) tests to do ore dictionary tests 181 | - New 'energy' attribute for 'helditem' (and similar) tests to that you can test for forge energy in an item. This supports expressions 182 | - New 'energy' attribute for 'block' test to that you can test for forge energy in a block. There is also a new 'energyside' attribute which allows you to specify from which side the energy will be examined. If not given it will use null 183 | 184 | 3.9.1: 185 | - Much more powerful item description system with expressions on damage and nbt 186 | - Giving items (armor, helditem, give command) is now also much more general and supports the new system 187 | - Removed 'blockup' command and instead add a more general 'blockoffset' command that works together with the 'block' command 188 | - Added support for EnigmaScript though 'state' and 'pstate' tests 189 | 190 | 3.9.0: 191 | - Added support for Serene Seasons with new 'winter', 'summer', 'spring', and 'autumn' boolean keywords 192 | - Added support for baubles: new 'amulet', 'ring', 'belt', 'trinket', 'charm', 'body', 'and 'head' keywords 193 | - New 'blockup' test for various rules which will test the condition of the block above the current position 194 | - New 'message' action to print a status message on screen for the nearest player (for 'spawn') 195 | 196 | 3.8.3: 197 | - New 'offhanditem' and 'bothhandsitem' tags that are equivalent to 'helditem' but also work on the offhand (or both) 198 | 199 | 3.8.2: 200 | - Updated to 2.0 API of GameStages. This means that InControl is no longer compatible with the older GameStages 201 | 202 | 3.8.1: 203 | - Added a rule to check for spawns by mob spawners 204 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | modname=InControl 2 | version=1.16-5.2.12 3 | curse_type=release 4 | projectId=257356 5 | github_project=McJtyMods/InControl 6 | 7 | minecraft_version=1.16.5 8 | forge_version=36.1.13 9 | 10 | jei_version=1.16.2:7.1.1.15 11 | waila_version=1.8.23-B38_1.12 12 | top_version=1.16:1.16-3.0.3-beta-6 13 | lostcities_version=1.16-4.0.5-alpha-3 14 | mcjtytools_version=1.16-1.0.0 15 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McJtyMods/InControl/235498f73827e0fcc256b0546f43ddbdd599e24f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jan 06 19:01:39 CET 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /src/api/java/baubles/api/BaubleType.java: -------------------------------------------------------------------------------- 1 | package baubles.api; 2 | 3 | public enum BaubleType { 4 | AMULET(0), 5 | RING(1,2), 6 | BELT(3), 7 | TRINKET(0,1,2,3,4,5,6), 8 | HEAD(4), 9 | BODY(5), 10 | CHARM(6); 11 | 12 | int[] validSlots; 13 | 14 | private BaubleType(int ... validSlots) { 15 | this.validSlots = validSlots; 16 | } 17 | 18 | public boolean hasSlot(int slot) { 19 | for (int s:validSlots) { 20 | if (s == slot) return true; 21 | } 22 | return false; 23 | } 24 | 25 | public int[] getValidSlots() { 26 | return validSlots; 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/api/java/baubles/api/BaublesApi.java: -------------------------------------------------------------------------------- 1 | package baubles.api; 2 | 3 | import baubles.api.cap.BaublesCapabilities; 4 | import baubles.api.cap.IBaublesItemHandler; 5 | import baubles.api.inv.BaublesInventoryWrapper; 6 | import net.minecraft.entity.player.PlayerEntity; 7 | import net.minecraft.inventory.IInventory; 8 | 9 | /** 10 | * @author Azanor 11 | */ 12 | public class BaublesApi 13 | { 14 | /** 15 | * Retrieves the baubles inventory capability handler for the supplied player 16 | */ 17 | public static IBaublesItemHandler getBaublesHandler(PlayerEntity player) 18 | { 19 | return player.getCapability(BaublesCapabilities.CAPABILITY_BAUBLES, null); 20 | } 21 | 22 | /** 23 | * Retrieves the baubles capability handler wrapped as a IInventory for the supplied player 24 | */ 25 | @Deprecated 26 | public static IInventory getBaubles(PlayerEntity player) 27 | { 28 | return new BaublesInventoryWrapper(player.getCapability(BaublesCapabilities.CAPABILITY_BAUBLES, null)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/api/java/baubles/api/IBauble.java: -------------------------------------------------------------------------------- 1 | package baubles.api; 2 | 3 | import net.minecraft.entity.LivingEntity; 4 | import net.minecraft.item.ItemStack; 5 | 6 | /** 7 | * 8 | * This interface should be extended by items that can be worn in bauble slots 9 | * 10 | * @author Azanor 11 | */ 12 | 13 | public interface IBauble { 14 | 15 | /** 16 | * This method return the type of bauble this is. 17 | * Type is used to determine the slots it can go into. 18 | */ 19 | public BaubleType getBaubleType(ItemStack itemstack); 20 | 21 | /** 22 | * This method is called once per tick if the bauble is being worn by a player 23 | */ 24 | public default void onWornTick(ItemStack itemstack, LivingEntity player) { 25 | } 26 | 27 | /** 28 | * This method is called when the bauble is equipped by a player 29 | */ 30 | public default void onEquipped(ItemStack itemstack, LivingEntity player) { 31 | } 32 | 33 | /** 34 | * This method is called when the bauble is unequipped by a player 35 | */ 36 | public default void onUnequipped(ItemStack itemstack, LivingEntity player) { 37 | } 38 | 39 | /** 40 | * can this bauble be placed in a bauble slot 41 | */ 42 | public default boolean canEquip(ItemStack itemstack, LivingEntity player) { 43 | return true; 44 | } 45 | 46 | /** 47 | * Can this bauble be removed from a bauble slot 48 | */ 49 | public default boolean canUnequip(ItemStack itemstack, LivingEntity player) { 50 | return true; 51 | } 52 | 53 | /** 54 | * Will bauble automatically sync to client if a change is detected in its NBT or damage values? 55 | * Default is off, so override and set to true if you want to auto sync. 56 | * This sync is not instant, but occurs every 10 ticks (.5 seconds). 57 | */ 58 | public default boolean willAutoSync(ItemStack itemstack, LivingEntity player) { 59 | return false; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/api/java/baubles/api/cap/BaublesCapabilities.java: -------------------------------------------------------------------------------- 1 | package baubles.api.cap; 2 | 3 | import net.minecraft.nbt.NBTBase; 4 | import net.minecraft.util.EnumFacing; 5 | import net.minecraftforge.common.capabilities.Capability; 6 | import net.minecraftforge.common.capabilities.Capability.IStorage; 7 | import net.minecraftforge.common.capabilities.CapabilityInject; 8 | 9 | public class BaublesCapabilities { 10 | 11 | /** 12 | * Access to the baubles capability. 13 | */ 14 | @CapabilityInject(IBaublesItemHandler.class) 15 | public static final Capability CAPABILITY_BAUBLES = null; 16 | 17 | public static class CapabilityBaubles implements IStorage { 18 | 19 | @Override 20 | public NBTBase writeNBT (Capability capability, IBaublesItemHandler instance, EnumFacing side) { 21 | 22 | return null; 23 | } 24 | 25 | @Override 26 | public void readNBT (Capability capability, IBaublesItemHandler instance, EnumFacing side, NBTBase nbt) { 27 | 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/api/java/baubles/api/cap/BaublesContainer.java: -------------------------------------------------------------------------------- 1 | package baubles.api.cap; 2 | 3 | import baubles.api.IBauble; 4 | import net.minecraft.entity.LivingEntity; 5 | import net.minecraft.item.ItemStack; 6 | import net.minecraftforge.items.ItemStackHandler; 7 | 8 | import java.util.Arrays; 9 | 10 | public class BaublesContainer extends ItemStackHandler implements IBaublesItemHandler { 11 | 12 | private final static int BAUBLE_SLOTS = 7; 13 | 14 | public BaublesContainer() 15 | { 16 | super(BAUBLE_SLOTS); 17 | } 18 | 19 | @Override 20 | public void setSize(int size) 21 | { 22 | if (size, ICapabilityProvider { 10 | 11 | private final BaublesContainer container; 12 | 13 | public BaublesContainerProvider(BaublesContainer container) { 14 | this.container = container; 15 | } 16 | 17 | @Override 18 | public boolean hasCapability (Capability capability, EnumFacing facing) { 19 | return capability == BaublesCapabilities.CAPABILITY_BAUBLES; 20 | } 21 | 22 | @Override 23 | @SuppressWarnings("unchecked") 24 | public T getCapability (Capability capability, EnumFacing facing) { 25 | if (capability == BaublesCapabilities.CAPABILITY_BAUBLES) return (T) this.container; 26 | return null; 27 | } 28 | 29 | @Override 30 | public CompoundNBT serializeNBT () { 31 | return this.container.serializeNBT(); 32 | } 33 | 34 | @Override 35 | public void deserializeNBT (CompoundNBT nbt) { 36 | this.container.deserializeNBT(nbt); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/api/java/baubles/api/cap/IBaublesItemHandler.java: -------------------------------------------------------------------------------- 1 | package baubles.api.cap; 2 | 3 | import net.minecraft.entity.LivingEntity; 4 | import net.minecraft.item.ItemStack; 5 | import net.minecraftforge.items.IItemHandlerModifiable; 6 | 7 | public interface IBaublesItemHandler extends IItemHandlerModifiable { 8 | 9 | public boolean isItemValidForSlot(int slot, ItemStack stack, LivingEntity player); 10 | 11 | /** 12 | * Used internally to prevent equip/unequip events from triggering when they shouldn't 13 | * @return 14 | */ 15 | public boolean isEventBlocked(); 16 | public void setEventBlock(boolean blockEvents); 17 | 18 | /** 19 | * Used internally for syncing. Indicates if the inventory has changed since last sync 20 | * @return 21 | */ 22 | boolean isChanged(int slot); 23 | void setChanged(int slot, boolean changed); 24 | } 25 | -------------------------------------------------------------------------------- /src/api/java/baubles/api/inv/BaublesInventoryWrapper.java: -------------------------------------------------------------------------------- 1 | package baubles.api.inv; 2 | 3 | import baubles.api.cap.IBaublesItemHandler; 4 | import net.minecraft.entity.player.PlayerEntity; 5 | import net.minecraft.inventory.IInventory; 6 | import net.minecraft.item.ItemStack; 7 | import net.minecraft.util.text.ITextComponent; 8 | import net.minecraft.util.text.StringTextComponent; 9 | 10 | public class BaublesInventoryWrapper implements IInventory { 11 | 12 | final IBaublesItemHandler handler; 13 | 14 | public BaublesInventoryWrapper(IBaublesItemHandler handler) { 15 | super(); 16 | this.handler = handler; 17 | } 18 | 19 | @Override 20 | public String getName() { 21 | return "BaublesInventory"; 22 | } 23 | 24 | @Override 25 | public boolean hasCustomName() { 26 | return false; 27 | } 28 | 29 | @Override 30 | public ITextComponent getDisplayName() { 31 | return new StringTextComponent(this.getName()); 32 | } 33 | 34 | @Override 35 | public int getSizeInventory() { 36 | return handler.getSlots(); 37 | } 38 | 39 | @Override 40 | public ItemStack getStackInSlot(int index) { 41 | return handler.getStackInSlot(index); 42 | } 43 | 44 | @Override 45 | public ItemStack decrStackSize(int index, int count) { 46 | return handler.extractItem(index, count, false); 47 | } 48 | 49 | @Override 50 | public ItemStack removeStackFromSlot(int index) { 51 | ItemStack out = this.getStackInSlot(index); 52 | handler.setStackInSlot(index, null); 53 | return out; 54 | } 55 | 56 | @Override 57 | public void setInventorySlotContents(int index, ItemStack stack) { 58 | handler.setStackInSlot(index, stack); 59 | } 60 | 61 | @Override 62 | public int getInventoryStackLimit() { 63 | return 64; 64 | } 65 | 66 | @Override 67 | public void markDirty() { } 68 | 69 | @Override 70 | public boolean isEmpty() { 71 | return false; 72 | } 73 | 74 | @Override 75 | public boolean isUsableByPlayer(PlayerEntity player) { 76 | return true; 77 | } 78 | 79 | @Override 80 | public void openInventory(PlayerEntity player) { } 81 | 82 | @Override 83 | public void closeInventory(PlayerEntity player) { } 84 | 85 | @Override 86 | public boolean isItemValidForSlot(int index, ItemStack stack) { 87 | return handler.isItemValidForSlot(index, stack, null); 88 | } 89 | 90 | @Override 91 | public int getField(int id) { 92 | return 0; 93 | } 94 | 95 | @Override 96 | public void setField(int id, int value) {} 97 | 98 | @Override 99 | public int getFieldCount() { 100 | return 0; 101 | } 102 | 103 | @Override 104 | public void clear() { 105 | for (int i = 0; i < this.getSizeInventory(); ++i) 106 | { 107 | this.setInventorySlotContents(i, null); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/api/java/baubles/api/package-info.java: -------------------------------------------------------------------------------- 1 | @API(owner = "Baubles", apiVersion = "1.3.1.0", provides = "Baubles|API") 2 | package baubles.api; 3 | 4 | -------------------------------------------------------------------------------- /src/api/java/baubles/api/render/IRenderBauble.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This class was created by . It's distributed as 3 | * part of the Botania Mod. Get the Source Code in github: 4 | * https://github.com/Vazkii/Botania 5 | * 6 | * Botania is Open Source and distributed under the 7 | * Botania License: http://botaniamod.net/license.php 8 | * 9 | * File Created @ [Aug 27, 2014, 8:55:00 PM (GMT)] 10 | */ 11 | 12 | package baubles.api.render; 13 | 14 | import net.minecraft.client.renderer.GlStateManager; 15 | import net.minecraft.entity.player.PlayerEntity; 16 | import net.minecraft.item.ItemStack; 17 | import net.minecraft.util.math.MathHelper; 18 | 19 | /** 20 | * A Bauble Item that implements this will be have hooks to render something on 21 | * the player while its equipped. 22 | * This class doesn't extend IBauble to make the API not depend on the Baubles 23 | * API, but the item in question still needs to implement IBauble. 24 | */ 25 | public interface IRenderBauble { 26 | 27 | /** 28 | * Called for the rendering of the bauble on the player. The player instance can be 29 | * acquired through the event parameter. Transformations are already applied for 30 | * the RenderType passed in. Make sure to check against the type parameter for 31 | * rendering. 32 | */ 33 | public void onPlayerBaubleRender(ItemStack stack, PlayerEntity player, RenderType type, float partialTicks); 34 | 35 | /** 36 | * A few helper methods for the render. 37 | */ 38 | final class Helper { 39 | 40 | /** 41 | * Rotates the render for a bauble correctly if the player is sneaking. 42 | * Use for renders under {@link RenderType#BODY}. 43 | */ 44 | public static void rotateIfSneaking(PlayerEntity player) { 45 | if(player.isSneaking()) 46 | applySneakingRotation(); 47 | } 48 | 49 | /** 50 | * Rotates the render for a bauble correctly for a sneaking player. 51 | * Use for renders under {@link RenderType#BODY}. 52 | */ 53 | public static void applySneakingRotation() { 54 | GlStateManager.translate(0F, 0.2F, 0F); 55 | GlStateManager.rotate(90F / (float) Math.PI, 1.0F, 0.0F, 0.0F); 56 | } 57 | 58 | /** 59 | * Shifts the render for a bauble correctly to the head, including sneaking rotation. 60 | * Use for renders under {@link RenderType#HEAD}. 61 | */ 62 | public static void translateToHeadLevel(PlayerEntity player) { 63 | GlStateManager.translate(0, -player.getDefaultEyeHeight(), 0); 64 | if (player.isSneaking()) 65 | GlStateManager.translate(0.25F * MathHelper.sin(player.rotationPitch * (float) Math.PI / 180), 0.25F * MathHelper.cos(player.rotationPitch * (float) Math.PI / 180), 0F); 66 | } 67 | 68 | /** 69 | * Shifts the render for a bauble correctly to the face. 70 | * Use for renders under {@link RenderType#HEAD}, and usually after calling {@link Helper#translateToHeadLevel(PlayerEntity)}. 71 | */ 72 | public static void translateToFace() { 73 | GlStateManager.rotate(90F, 0F, 1F, 0F); 74 | GlStateManager.rotate(180F, 1F, 0F, 0F); 75 | GlStateManager.translate(0f, -4.35f, -1.27f); 76 | } 77 | 78 | /** 79 | * Scales down the render to a correct size. 80 | * Use for any render. 81 | */ 82 | public static void defaultTransforms() { 83 | GlStateManager.translate(0.0, 3.0, 1.0); 84 | GlStateManager.scale(0.55, 0.55, 0.55); 85 | } 86 | 87 | /** 88 | * Shifts the render for a bauble correctly to the chest. 89 | * Use for renders under {@link RenderType#BODY}, and usually after calling {@link Helper#rotateIfSneaking(PlayerEntity)}. 90 | */ 91 | public static void translateToChest() { 92 | GlStateManager.rotate(180F, 1F, 0F, 0F); 93 | GlStateManager.translate(0F, -3.2F, -0.85F); 94 | } 95 | 96 | } 97 | 98 | public enum RenderType { 99 | /** 100 | * Render Type for the player's body, translations apply on the player's rotation. 101 | * Sneaking is not handled and should be done during the render. 102 | * @see IBaubleRender.Helper 103 | */ 104 | BODY, 105 | 106 | /** 107 | * Render Type for the player's body, translations apply on the player's head rotations. 108 | * Sneaking is not handled and should be done during the render. 109 | * @see IBaubleRender.Helper 110 | */ 111 | HEAD; 112 | } 113 | 114 | } -------------------------------------------------------------------------------- /src/api/java/mcjty/enigma/api/IEnigmaScript.java: -------------------------------------------------------------------------------- 1 | package mcjty.enigma.api; 2 | 3 | import net.minecraft.entity.player.PlayerEntity; 4 | import net.minecraft.world.World; 5 | 6 | public interface IEnigmaScript { 7 | 8 | void setPlayerState(PlayerEntity player, String statename, String statevalue); 9 | 10 | String getPlayerState(PlayerEntity player, String statename); 11 | 12 | void setState(World world, String statename, String statevalue); 13 | 14 | String getState(World world, String statename); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol; 2 | 3 | import net.minecraft.entity.player.ServerPlayerEntity; 4 | import net.minecraft.server.MinecraftServer; 5 | import net.minecraft.util.Util; 6 | import net.minecraft.util.text.StringTextComponent; 7 | import net.minecraft.util.text.TextFormatting; 8 | import net.minecraftforge.event.entity.player.PlayerEvent; 9 | import net.minecraftforge.fml.server.ServerLifecycleHooks; 10 | 11 | import java.util.HashSet; 12 | import java.util.Set; 13 | 14 | public class ErrorHandler { 15 | 16 | private static Set errors = new HashSet<>(); 17 | 18 | public static void clearErrors() { 19 | errors.clear(); 20 | } 21 | 22 | // Publish an error and notify all players of that error 23 | public static void error(String message) { 24 | errors.add(message); 25 | InControl.setup.getLogger().error(message); 26 | // Notify all logged in players 27 | MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); 28 | if (server != null) { 29 | for (ServerPlayerEntity player : server.getPlayerList().getPlayers()) { 30 | player.sendMessage(new StringTextComponent(TextFormatting.RED + "InControl Error: " + TextFormatting.GOLD + message), Util.NIL_UUID); 31 | } 32 | } 33 | } 34 | 35 | public static void onPlayerJoinWorld(PlayerEvent.PlayerLoggedInEvent event) { 36 | for (String error : errors) { 37 | event.getPlayer().sendMessage(new StringTextComponent(TextFormatting.RED + "InControl Error: " + TextFormatting.GOLD + error), Util.NIL_UUID); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/ForgeEventHandlers.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol; 2 | 3 | import mcjty.incontrol.commands.ModCommands; 4 | import mcjty.incontrol.data.DataStorage; 5 | import mcjty.incontrol.data.Statistics; 6 | import mcjty.incontrol.rules.*; 7 | import mcjty.incontrol.spawner.SpawnerSystem; 8 | import net.minecraft.entity.LivingEntity; 9 | import net.minecraft.entity.item.ItemEntity; 10 | import net.minecraft.entity.player.PlayerEntity; 11 | import net.minecraft.item.ItemStack; 12 | import net.minecraft.util.math.BlockPos; 13 | import net.minecraft.world.World; 14 | import net.minecraft.world.biome.MobSpawnInfo; 15 | import net.minecraftforge.event.RegisterCommandsEvent; 16 | import net.minecraftforge.event.TickEvent; 17 | import net.minecraftforge.event.entity.EntityJoinWorldEvent; 18 | import net.minecraftforge.event.entity.living.LivingDropsEvent; 19 | import net.minecraftforge.event.entity.living.LivingExperienceDropEvent; 20 | import net.minecraftforge.event.entity.living.LivingSpawnEvent; 21 | import net.minecraftforge.event.entity.living.ZombieEvent; 22 | import net.minecraftforge.event.world.BiomeLoadingEvent; 23 | import net.minecraftforge.event.world.WorldEvent; 24 | import net.minecraftforge.eventbus.api.Event; 25 | import net.minecraftforge.eventbus.api.EventPriority; 26 | import net.minecraftforge.eventbus.api.SubscribeEvent; 27 | import org.apache.commons.lang3.tuple.Pair; 28 | import org.apache.logging.log4j.Level; 29 | 30 | import java.util.ArrayList; 31 | import java.util.Collection; 32 | import java.util.List; 33 | import java.util.function.Function; 34 | import java.util.function.Predicate; 35 | 36 | public class ForgeEventHandlers { 37 | 38 | public static boolean debug = false; 39 | 40 | @SubscribeEvent 41 | public void registerCommands(RegisterCommandsEvent event) { 42 | ModCommands.register(event.getDispatcher()); 43 | } 44 | 45 | @SubscribeEvent(priority = EventPriority.LOWEST) 46 | public void onEntityJoinWorld(EntityJoinWorldEvent event) { 47 | int i = 0; 48 | if (!(event.getEntity() instanceof LivingEntity)) { 49 | return; 50 | } 51 | if (event.getEntity() instanceof PlayerEntity) { 52 | return; 53 | } 54 | if (event.getWorld().isClientSide) { 55 | return; 56 | } 57 | for (SpawnRule rule : RulesManager.getFilteredRules(event.getWorld())) { 58 | if (rule.isOnJoin() && rule.match(event)) { 59 | Event.Result result = rule.getResult(); 60 | if (debug) { 61 | InControl.setup.getLogger().log(Level.INFO, "Join Rule " + i + ": " + result 62 | + " entity: " + event.getEntity().getName() 63 | + " y: " + event.getEntity().blockPosition().getY()); 64 | } 65 | if (result != Event.Result.DENY) { 66 | Statistics.addSpawnStat(i, false); 67 | rule.action(event); 68 | } else { 69 | Statistics.addSpawnStat(i, true); 70 | event.setCanceled(true); 71 | } 72 | if (!rule.isDoContinue()) { 73 | return; 74 | } 75 | } 76 | i++; 77 | } 78 | } 79 | 80 | @SubscribeEvent(priority = EventPriority.HIGHEST) 81 | public void onEntityJoinWorldLast(EntityJoinWorldEvent event) { 82 | // We register spawns in a high priority event so that we take things that other mods 83 | // do into account 84 | if (!event.getWorld().isClientSide() && event.getEntity() instanceof LivingEntity) { 85 | if (!(event.getEntity() instanceof PlayerEntity)) { 86 | InControl.setup.cache.registerSpawn(event.getWorld(), event.getEntity().getType()); 87 | } 88 | } 89 | } 90 | 91 | @SubscribeEvent 92 | public void onWorldTick(TickEvent.WorldTickEvent event) { 93 | if (event.phase == TickEvent.Phase.START && !event.world.isClientSide) { 94 | // For every world tick we reset the cache 95 | InControl.setup.cache.reset(event.world); 96 | 97 | if (!event.world.players().isEmpty()) { 98 | // If a world has players we do mob spawning in it 99 | SpawnerSystem.checkRules(event); 100 | } 101 | 102 | if (event.world.dimension().equals(World.OVERWORLD)) { 103 | DataStorage.getData(event.world).tick(event.world); 104 | } 105 | } 106 | } 107 | 108 | 109 | @SubscribeEvent(priority = EventPriority.LOWEST) 110 | public void onEntitySpawnEvent(LivingSpawnEvent.CheckSpawn event) { 111 | int i = 0; 112 | for (SpawnRule rule : RulesManager.getFilteredRules(event.getEntity().getCommandSenderWorld())) { 113 | if (rule.match(event)) { 114 | Event.Result result = rule.getResult(); 115 | if (debug) { 116 | InControl.setup.getLogger().log(Level.INFO, "Rule " + i + ": " + result 117 | + " entity: " + event.getEntity().getName() 118 | + " y: " + event.getY() 119 | + " biome: " + event.getWorld().getBiome(new BlockPos(event.getX(), event.getY(), event.getZ())).getRegistryName()); 120 | } 121 | if (result != null) { 122 | event.setResult(result); 123 | } 124 | if (result != Event.Result.DENY) { 125 | Statistics.addSpawnStat(i, false); 126 | rule.action(event); 127 | } else { 128 | Statistics.addSpawnStat(i, true); 129 | } 130 | if (!rule.isDoContinue()) { 131 | return; 132 | } 133 | } 134 | i++; 135 | } 136 | } 137 | 138 | @SubscribeEvent(priority = EventPriority.LOWEST) 139 | public void onSummonAidEvent(ZombieEvent.SummonAidEvent event) { 140 | int i = 0; 141 | for (SummonAidRule rule : RulesManager.getFilteredSummonAidRules(event.getWorld())) { 142 | if (rule.match(event)) { 143 | Event.Result result = rule.getResult(); 144 | if (debug) { 145 | InControl.setup.getLogger().log(Level.INFO, "SummonAid " + i + ": " + result 146 | + " entity: " + event.getEntity().getName() 147 | + " y: " + event.getY() 148 | + " biome: " + event.getWorld().getBiome(new BlockPos(event.getX(), event.getY(), event.getZ())).getRegistryName()); 149 | } 150 | event.setResult(result); 151 | if (result != Event.Result.DENY) { 152 | rule.action(event); 153 | } 154 | return; 155 | } 156 | i++; 157 | } 158 | 159 | } 160 | 161 | @SubscribeEvent(priority = EventPriority.HIGH) 162 | public void onBiomeLoadingEvent(BiomeLoadingEvent event) { 163 | // On 1.16.3 potentialspawn alone can't add spawns that are not supported by the biome. So we need to add all 164 | // possible potential spawns to all possible biomes 165 | for (PotentialSpawnRule rule : RulesManager.potentialSpawnRules) { 166 | List spawnEntries = rule.getSpawnEntries(); 167 | for (MobSpawnInfo.Spawners entry : spawnEntries) { 168 | event.getSpawns().addSpawn(entry.type.getCategory(), entry); 169 | } 170 | } 171 | } 172 | 173 | @SubscribeEvent(priority = EventPriority.LOWEST) 174 | public void onPotentialSpawns(WorldEvent.PotentialSpawns event) { 175 | int i = 0; 176 | for (PotentialSpawnRule rule : RulesManager.potentialSpawnRules) { 177 | if (rule.match(event)) { 178 | 179 | // First remove mob entries if needed 180 | for (int idx = event.getList().size() - 1; idx >= 0; idx--) { 181 | if (rule.getToRemoveMobs().contains(event.getList().get(idx).type)) { 182 | event.getList().remove(idx); 183 | } 184 | } 185 | 186 | List spawnEntries = rule.getSpawnEntries(); 187 | for (MobSpawnInfo.Spawners entry : spawnEntries) { 188 | if (debug) { 189 | InControl.setup.getLogger().log(Level.INFO, "Potential " + i + ": " + entry.type.getRegistryName().toString()); 190 | } 191 | event.getList().add(entry); 192 | } 193 | } 194 | i++; 195 | } 196 | } 197 | 198 | @SubscribeEvent(priority = EventPriority.LOWEST) 199 | public void onLivingExperienceDrop(LivingExperienceDropEvent event) { 200 | int i = 0; 201 | for (ExperienceRule rule : RulesManager.getFilteredExperienceRuiles(event.getEntity().level)) { 202 | if (rule.match(event)) { 203 | Event.Result result = rule.getResult(); 204 | if (debug) { 205 | InControl.setup.getLogger().log(Level.INFO, "Experience Rule " + i + ": " + result 206 | + " entity: " + event.getEntity().getName() 207 | + " y: " + event.getEntity().blockPosition().getY()); 208 | } 209 | if (result != Event.Result.DENY) { 210 | int newxp = rule.modifyXp(event.getDroppedExperience()); 211 | event.setDroppedExperience(newxp); 212 | } else { 213 | event.setCanceled(true); 214 | } 215 | return; 216 | } 217 | i++; 218 | } 219 | } 220 | 221 | @SubscribeEvent(priority = EventPriority.LOWEST) 222 | public void onLivingDrops(LivingDropsEvent event) { 223 | World world = event.getEntity().getCommandSenderWorld(); 224 | int i = 0; 225 | for (LootRule rule : RulesManager.getFilteredLootRules(world)) { 226 | if (rule.match(event)) { 227 | if (debug) { 228 | InControl.setup.getLogger().log(Level.INFO, "Loot " + i + ": " 229 | + " entity: " + event.getEntity().getName()); 230 | } 231 | 232 | if (rule.isRemoveAll()) { 233 | event.getDrops().clear(); 234 | } else { 235 | List toRemove = null; 236 | for (Predicate stackTest : rule.getToRemoveItems()) { 237 | Collection drops = event.getDrops(); 238 | for (ItemEntity drop : drops) { 239 | ItemStack stack = drop.getItem(); 240 | if (stackTest.test(stack)) { 241 | if (toRemove == null) { 242 | toRemove = new ArrayList<>(); 243 | }; 244 | toRemove.add(drop); 245 | } 246 | } 247 | } 248 | if (toRemove != null) { 249 | Collection drops = event.getDrops(); 250 | for (ItemEntity entity : toRemove) { 251 | drops.remove(entity); 252 | } 253 | 254 | } 255 | } 256 | 257 | for (Pair> pair : rule.getToAddItems()) { 258 | ItemStack item = pair.getLeft(); 259 | int fortune = event.getLootingLevel(); 260 | int amount = pair.getValue().apply(fortune); 261 | BlockPos pos = event.getEntity().blockPosition(); 262 | while (amount > item.getMaxStackSize()) { 263 | ItemStack copy = item.copy(); 264 | copy.setCount(item.getMaxStackSize()); 265 | amount -= item.getMaxStackSize(); 266 | event.getDrops().add(new ItemEntity(world, pos.getX(), pos.getY(), pos.getZ(), 267 | copy)); 268 | } 269 | if (amount > 0) { 270 | ItemStack copy = item.copy(); 271 | copy.setCount(amount); 272 | event.getDrops().add(new ItemEntity(world, pos.getX(), pos.getY(), pos.getZ(), 273 | copy)); 274 | } 275 | } 276 | } 277 | i++; 278 | } 279 | } 280 | 281 | } 282 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/InControl.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol; 2 | 3 | 4 | import mcjty.incontrol.setup.ModSetup; 5 | import mcjty.incontrol.tools.cache.StructureCache; 6 | import net.minecraftforge.common.MinecraftForge; 7 | import net.minecraftforge.fml.common.Mod; 8 | import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; 9 | import net.minecraftforge.fml.event.server.FMLServerStoppedEvent; 10 | import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; 11 | 12 | @Mod(InControl.MODID) 13 | public class InControl { 14 | 15 | public static final String MODID = "incontrol"; 16 | 17 | public static ModSetup setup = new ModSetup(); 18 | 19 | public InControl() { 20 | FMLJavaModLoadingContext.get().getModEventBus().addListener((FMLCommonSetupEvent event) -> setup.init()); 21 | MinecraftForge.EVENT_BUS.addListener((FMLServerStoppedEvent event) -> StructureCache.CACHE.clean()); 22 | MinecraftForge.EVENT_BUS.addListener(ErrorHandler::onPlayerJoinWorld); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/commands/CmdClearStats.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.commands; 2 | 3 | import com.mojang.brigadier.Command; 4 | import com.mojang.brigadier.CommandDispatcher; 5 | import com.mojang.brigadier.builder.ArgumentBuilder; 6 | import com.mojang.brigadier.context.CommandContext; 7 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 8 | import mcjty.incontrol.data.Statistics; 9 | import net.minecraft.command.CommandSource; 10 | import net.minecraft.command.Commands; 11 | 12 | public class CmdClearStats implements Command { 13 | 14 | private static final CmdClearStats CMD = new CmdClearStats(); 15 | 16 | public static ArgumentBuilder register(CommandDispatcher dispatcher) { 17 | return Commands.literal("clearstats") 18 | .requires(cs -> cs.hasPermission(0)) 19 | .executes(CMD); 20 | } 21 | 22 | @Override 23 | public int run(CommandContext context) throws CommandSyntaxException { 24 | Statistics.clear(); 25 | return 0; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/commands/CmdDays.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.commands; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import com.mojang.brigadier.arguments.IntegerArgumentType; 5 | import com.mojang.brigadier.builder.ArgumentBuilder; 6 | import com.mojang.brigadier.context.CommandContext; 7 | import mcjty.incontrol.data.DataStorage; 8 | import net.minecraft.command.CommandSource; 9 | import net.minecraft.command.Commands; 10 | import net.minecraft.util.text.StringTextComponent; 11 | 12 | public class CmdDays { 13 | 14 | public static ArgumentBuilder register(CommandDispatcher dispatcher) { 15 | return Commands.literal("days") 16 | .requires(cs -> cs.hasPermission(2)) 17 | .then(Commands.argument("number", IntegerArgumentType.integer()).executes(CmdDays::setDays)) 18 | .executes(CmdDays::showDays); 19 | } 20 | 21 | private static int showDays(CommandContext context) { 22 | DataStorage data = DataStorage.getData(context.getSource().getLevel()); 23 | context.getSource().sendSuccess(new StringTextComponent("Current day is " + data.getDaycounter()), false); 24 | return 0; 25 | } 26 | 27 | private static int setDays(CommandContext context) { 28 | DataStorage data = DataStorage.getData(context.getSource().getLevel()); 29 | Integer number = context.getArgument("number", Integer.class); 30 | data.setDaycounter(number); 31 | return 0; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/commands/CmdDebug.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.commands; 2 | 3 | import com.mojang.brigadier.Command; 4 | import com.mojang.brigadier.CommandDispatcher; 5 | import com.mojang.brigadier.builder.ArgumentBuilder; 6 | import com.mojang.brigadier.context.CommandContext; 7 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 8 | import mcjty.incontrol.ForgeEventHandlers; 9 | import net.minecraft.command.CommandSource; 10 | import net.minecraft.command.Commands; 11 | import net.minecraft.entity.player.ServerPlayerEntity; 12 | import net.minecraft.util.Util; 13 | import net.minecraft.util.text.StringTextComponent; 14 | 15 | public class CmdDebug implements Command { 16 | 17 | private static final CmdDebug CMD = new CmdDebug(); 18 | 19 | public static ArgumentBuilder register(CommandDispatcher dispatcher) { 20 | return Commands.literal("debug") 21 | .requires(cs -> cs.hasPermission(0)) 22 | .executes(CMD); 23 | } 24 | 25 | @Override 26 | public int run(CommandContext context) throws CommandSyntaxException { 27 | ServerPlayerEntity player = context.getSource().getPlayerOrException(); 28 | if (player != null) { 29 | ForgeEventHandlers.debug = !ForgeEventHandlers.debug; 30 | if (ForgeEventHandlers.debug) { 31 | player.sendMessage(new StringTextComponent("Enabled InControl debug mode"), Util.NIL_UUID); 32 | } else { 33 | player.sendMessage(new StringTextComponent("Disabled InControl debug mode"), Util.NIL_UUID); 34 | } 35 | } 36 | return 0; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/commands/CmdInfo.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.commands; 2 | 3 | import com.mojang.brigadier.Command; 4 | import com.mojang.brigadier.CommandDispatcher; 5 | import com.mojang.brigadier.builder.ArgumentBuilder; 6 | import com.mojang.brigadier.context.CommandContext; 7 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 8 | import it.unimi.dsi.fastutil.longs.LongSet; 9 | import mcjty.incontrol.tools.varia.Tools; 10 | import net.minecraft.command.CommandSource; 11 | import net.minecraft.command.Commands; 12 | import net.minecraft.entity.player.ServerPlayerEntity; 13 | import net.minecraft.util.Util; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraft.util.text.StringTextComponent; 16 | import net.minecraft.world.chunk.ChunkStatus; 17 | import net.minecraft.world.chunk.IChunk; 18 | import net.minecraft.world.gen.feature.structure.Structure; 19 | import net.minecraft.world.server.ServerWorld; 20 | 21 | import java.util.Map; 22 | 23 | public class CmdInfo implements Command { 24 | 25 | private static final CmdInfo CMD = new CmdInfo(); 26 | 27 | public static ArgumentBuilder register(CommandDispatcher dispatcher) { 28 | return Commands.literal("info") 29 | .requires(cs -> cs.hasPermission(0)) 30 | .executes(CMD); 31 | } 32 | 33 | @Override 34 | public int run(CommandContext context) throws CommandSyntaxException { 35 | ServerPlayerEntity player = context.getSource().getPlayerOrException(); 36 | if (player != null) { 37 | BlockPos pos = player.blockPosition(); 38 | ServerWorld sw = Tools.getServerWorld(player.level); 39 | IChunk chunk = sw.getChunk(pos.getX() >> 4, pos.getZ() >> 4, ChunkStatus.STRUCTURE_REFERENCES, false); 40 | if (chunk != null) { 41 | Map, LongSet> references = chunk.getAllReferences(); 42 | for (Structure s : references.keySet()) { 43 | LongSet longs = references.get(s); 44 | player.sendMessage(new StringTextComponent(s.getRegistryName().toString() + ": " + longs.size()), Util.NIL_UUID); 45 | } 46 | } 47 | } 48 | return 0; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/commands/CmdKillMobs.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.commands; 2 | 3 | import com.mojang.brigadier.Command; 4 | import com.mojang.brigadier.CommandDispatcher; 5 | import com.mojang.brigadier.arguments.StringArgumentType; 6 | import com.mojang.brigadier.builder.ArgumentBuilder; 7 | import com.mojang.brigadier.context.CommandContext; 8 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 9 | import mcjty.incontrol.InControl; 10 | import net.minecraft.command.CommandSource; 11 | import net.minecraft.command.Commands; 12 | import net.minecraft.entity.Entity; 13 | import net.minecraft.entity.monster.IMob; 14 | import net.minecraft.entity.passive.AnimalEntity; 15 | import net.minecraft.entity.player.PlayerEntity; 16 | import net.minecraft.entity.player.ServerPlayerEntity; 17 | import net.minecraft.util.RegistryKey; 18 | import net.minecraft.util.Util; 19 | import net.minecraft.util.text.StringTextComponent; 20 | import net.minecraft.util.text.TextFormatting; 21 | import net.minecraft.world.World; 22 | import net.minecraft.world.server.ServerWorld; 23 | 24 | import java.util.List; 25 | 26 | public class CmdKillMobs implements Command { 27 | 28 | private static final CmdKillMobs CMD = new CmdKillMobs(); 29 | 30 | public static ArgumentBuilder register(CommandDispatcher dispatcher) { 31 | return Commands.literal("kill") 32 | .requires(cs -> cs.hasPermission(2)) 33 | .then(Commands.argument("type", StringArgumentType.word()) 34 | .executes(CMD)); 35 | } 36 | 37 | @Override 38 | public int run(CommandContext context) throws CommandSyntaxException { 39 | ServerPlayerEntity player = context.getSource().getPlayerOrException(); 40 | if (player != null) { 41 | String type = context.getArgument("type", String.class); 42 | if (type == null || type.trim().isEmpty()) { 43 | player.sendMessage(new StringTextComponent(TextFormatting.RED + "Use 'all', 'passive', 'hostile' or name of the mob followed by optional dimension id"), Util.NIL_UUID); 44 | InControl.setup.getLogger().error("Use 'all', 'passive', 'hostile', 'entity' or name of the mob followed by optional dimension id"); 45 | return 0; 46 | } 47 | RegistryKey dimension = player.getCommandSenderWorld().dimension(); 48 | // if (args.length > 1) { 49 | // dimension = Integer.parseInt(args[1]); 50 | // } 51 | boolean all = "all".equals(type); 52 | boolean passive = "passive".equals(type); 53 | boolean hostile = "hostile".equals(type); 54 | boolean entity = "entity".equals(type); 55 | 56 | ServerWorld worldServer = player.getCommandSenderWorld().getServer().getLevel(dimension); 57 | List entities = worldServer.getEntities(null, input -> { 58 | if (all) { 59 | return !(input instanceof PlayerEntity); 60 | } else if (passive) { 61 | return input instanceof AnimalEntity && !(input instanceof IMob); 62 | } else if (hostile) { 63 | return input instanceof IMob; 64 | } else if (entity) { 65 | return !(input instanceof AnimalEntity) && !(input instanceof PlayerEntity); 66 | } else { 67 | String id = input.getType().getRegistryName().toString(); 68 | return type.equals(id); 69 | } 70 | }); 71 | for (Entity e : entities) { 72 | worldServer.despawn(e); 73 | } 74 | player.sendMessage(new StringTextComponent(TextFormatting.YELLOW + "Removed " + entities.size() + " entities!"), Util.NIL_UUID); 75 | } 76 | return 0; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/commands/CmdList.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.commands; 2 | 3 | import com.mojang.brigadier.Command; 4 | import com.mojang.brigadier.CommandDispatcher; 5 | import com.mojang.brigadier.builder.ArgumentBuilder; 6 | import com.mojang.brigadier.context.CommandContext; 7 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 8 | import net.minecraft.command.CommandSource; 9 | import net.minecraft.command.Commands; 10 | import net.minecraft.entity.MobEntity; 11 | import net.minecraft.entity.player.ServerPlayerEntity; 12 | import net.minecraft.util.RegistryKey; 13 | import net.minecraft.util.ResourceLocation; 14 | import net.minecraft.util.Util; 15 | import net.minecraft.util.text.StringTextComponent; 16 | import net.minecraft.util.text.TextFormatting; 17 | import net.minecraft.world.World; 18 | import net.minecraft.world.server.ServerWorld; 19 | 20 | import java.util.Map; 21 | 22 | public class CmdList implements Command { 23 | 24 | private static final CmdList CMD = new CmdList(); 25 | 26 | public static ArgumentBuilder register(CommandDispatcher dispatcher) { 27 | return Commands.literal("list") 28 | .requires(cs -> cs.hasPermission(2)) 29 | .executes(CMD); 30 | } 31 | 32 | @Override 33 | public int run(CommandContext context) throws CommandSyntaxException { 34 | ServerPlayerEntity player = context.getSource().getPlayerOrException(); 35 | if (player != null) { 36 | RegistryKey dimension = player.getCommandSenderWorld().dimension(); 37 | 38 | ServerWorld worldServer = player.getCommandSenderWorld().getServer().getLevel(dimension); 39 | Counter counter = new Counter<>(); 40 | worldServer.getEntities(null, e -> e instanceof MobEntity).forEach(input -> { 41 | counter.add(input.getType().getRegistryName()); 42 | }); 43 | for (Map.Entry entry : counter.getMap().entrySet()) { 44 | player.sendMessage(new StringTextComponent(TextFormatting.YELLOW + "Mob " + entry.getKey().toString() + ": " + entry.getValue()), Util.NIL_UUID); 45 | } 46 | } 47 | return 0; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/commands/CmdPhases.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.commands; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import com.mojang.brigadier.builder.ArgumentBuilder; 5 | import com.mojang.brigadier.context.CommandContext; 6 | import mcjty.incontrol.data.DataStorage; 7 | import net.minecraft.command.CommandSource; 8 | import net.minecraft.command.Commands; 9 | import net.minecraft.util.text.StringTextComponent; 10 | 11 | public class CmdPhases { 12 | 13 | public static ArgumentBuilder register(CommandDispatcher dispatcher) { 14 | return Commands.literal("phases") 15 | .requires(cs -> cs.hasPermission(2)) 16 | .executes(CmdPhases::showPhases); 17 | } 18 | 19 | private static int showPhases(CommandContext context) { 20 | DataStorage data = DataStorage.getData(context.getSource().getLevel()); 21 | String phases = ""; 22 | for (String phase : data.getPhases()) { 23 | phases += phase + " "; 24 | } 25 | context.getSource().sendSuccess(new StringTextComponent("Current phases: " + phases), false); 26 | return 0; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/commands/CmdReload.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.commands; 2 | 3 | import com.mojang.brigadier.Command; 4 | import com.mojang.brigadier.CommandDispatcher; 5 | import com.mojang.brigadier.builder.ArgumentBuilder; 6 | import com.mojang.brigadier.context.CommandContext; 7 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 8 | import mcjty.incontrol.ErrorHandler; 9 | import mcjty.incontrol.InControl; 10 | import mcjty.incontrol.rules.RulesManager; 11 | import mcjty.incontrol.spawner.SpawnerSystem; 12 | import net.minecraft.command.CommandSource; 13 | import net.minecraft.command.Commands; 14 | import net.minecraft.entity.player.ServerPlayerEntity; 15 | import net.minecraft.util.Util; 16 | import net.minecraft.util.text.StringTextComponent; 17 | import net.minecraft.util.text.TextFormatting; 18 | 19 | public class CmdReload implements Command { 20 | 21 | private static final CmdReload CMD = new CmdReload(); 22 | 23 | public static ArgumentBuilder register(CommandDispatcher dispatcher) { 24 | return Commands.literal("reload") 25 | .requires(cs -> cs.hasPermission(1)) 26 | .executes(CMD); 27 | } 28 | 29 | @Override 30 | public int run(CommandContext context) throws CommandSyntaxException { 31 | ServerPlayerEntity player = context.getSource().getPlayerOrException(); 32 | ErrorHandler.clearErrors(); 33 | if (player != null) { 34 | player.sendMessage(new StringTextComponent("Reloaded InControl rules"), Util.NIL_UUID); 35 | try { 36 | RulesManager.reloadRules(); 37 | SpawnerSystem.reloadRules(); 38 | } catch (Exception e) { 39 | InControl.setup.getLogger().error("Error reloading rules!", e); 40 | player.sendMessage(new StringTextComponent(TextFormatting.RED + "Error: " + e.getLocalizedMessage()), Util.NIL_UUID); 41 | } 42 | } 43 | return 0; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/commands/CmdShowMobs.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.commands; 2 | 3 | import com.mojang.brigadier.Command; 4 | import com.mojang.brigadier.CommandDispatcher; 5 | import com.mojang.brigadier.builder.ArgumentBuilder; 6 | import com.mojang.brigadier.context.CommandContext; 7 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 8 | import mcjty.incontrol.InControl; 9 | import net.minecraft.command.CommandSource; 10 | import net.minecraft.command.Commands; 11 | import net.minecraft.entity.player.ServerPlayerEntity; 12 | import net.minecraft.util.ResourceLocation; 13 | import net.minecraftforge.registries.ForgeRegistries; 14 | 15 | import java.util.Set; 16 | 17 | public class CmdShowMobs implements Command { 18 | 19 | private static final CmdShowMobs CMD = new CmdShowMobs(); 20 | 21 | public static ArgumentBuilder register(CommandDispatcher dispatcher) { 22 | return Commands.literal("showmobs") 23 | .requires(cs -> cs.hasPermission(0)) 24 | .executes(CMD); 25 | } 26 | 27 | @Override 28 | public int run(CommandContext context) throws CommandSyntaxException { 29 | ServerPlayerEntity player = context.getSource().getPlayerOrException(); 30 | if (player != null) { 31 | Set keys = ForgeRegistries.ENTITIES.getKeys(); 32 | keys.forEach(s -> InControl.setup.getLogger().info(("Mob:" + s))); 33 | } 34 | return 0; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/commands/CmdShowStats.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.commands; 2 | 3 | import com.mojang.brigadier.Command; 4 | import com.mojang.brigadier.CommandDispatcher; 5 | import com.mojang.brigadier.builder.ArgumentBuilder; 6 | import com.mojang.brigadier.context.CommandContext; 7 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 8 | import mcjty.incontrol.data.Statistics; 9 | import net.minecraft.command.CommandSource; 10 | import net.minecraft.command.Commands; 11 | 12 | public class CmdShowStats implements Command { 13 | 14 | private static final CmdShowStats CMD = new CmdShowStats(); 15 | 16 | public static ArgumentBuilder register(CommandDispatcher dispatcher) { 17 | return Commands.literal("showstats") 18 | .requires(cs -> cs.hasPermission(0)) 19 | .executes(CMD); 20 | } 21 | 22 | @Override 23 | public int run(CommandContext context) throws CommandSyntaxException { 24 | Statistics.dump(); 25 | return 0; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/commands/Counter.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.commands; 2 | 3 | import java.util.HashMap; 4 | import java.util.Iterator; 5 | import java.util.Map; 6 | 7 | public class Counter { 8 | private Map internalMap = new HashMap(); 9 | 10 | public Counter() { 11 | } 12 | 13 | public void add(T key) { 14 | if (!this.internalMap.containsKey(key)) { 15 | this.internalMap.put(key, 0); 16 | } 17 | 18 | this.internalMap.put(key, (Integer)this.internalMap.get(key) + 1); 19 | } 20 | 21 | public Map getMap() { 22 | return this.internalMap; 23 | } 24 | 25 | public int get(T key) { 26 | return this.internalMap.containsKey(key) ? (Integer)this.internalMap.get(key) : 0; 27 | } 28 | 29 | public T getMostOccuring() { 30 | T max = null; 31 | int maxCount = -1; 32 | Iterator var3 = this.internalMap.entrySet().iterator(); 33 | 34 | while(var3.hasNext()) { 35 | Map.Entry entry = (Map.Entry)var3.next(); 36 | if ((Integer)entry.getValue() > maxCount) { 37 | maxCount = (Integer)entry.getValue(); 38 | max = entry.getKey(); 39 | } 40 | } 41 | 42 | return max; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/commands/ModCommands.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.commands; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import com.mojang.brigadier.tree.LiteralCommandNode; 5 | import mcjty.incontrol.InControl; 6 | import net.minecraft.command.CommandSource; 7 | import net.minecraft.command.Commands; 8 | 9 | public class ModCommands { 10 | 11 | public static void register(CommandDispatcher dispatcher) { 12 | LiteralCommandNode commands = dispatcher.register( 13 | Commands.literal(InControl.MODID) 14 | .then(CmdDebug.register(dispatcher)) 15 | .then(CmdKillMobs.register(dispatcher)) 16 | .then(CmdReload.register(dispatcher)) 17 | .then(CmdShowMobs.register(dispatcher)) 18 | .then(CmdShowStats.register(dispatcher)) 19 | .then(CmdClearStats.register(dispatcher)) 20 | .then(CmdList.register(dispatcher)) 21 | .then(CmdInfo.register(dispatcher)) 22 | .then(CmdDays.register(dispatcher)) 23 | .then(CmdPhases.register(dispatcher)) 24 | ); 25 | 26 | dispatcher.register(Commands.literal("ctrl").redirect(commands)); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/compat/BaublesSupport.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.compat; 2 | 3 | import net.minecraft.entity.player.PlayerEntity; 4 | import net.minecraft.item.ItemStack; 5 | 6 | public class BaublesSupport { 7 | 8 | private static final int[] EMPTY = new int[0]; 9 | 10 | // @todo 1.15 11 | public static int[] getAmuletSlots() { 12 | // return BaubleType.AMULET.getValidSlots(); 13 | return EMPTY; 14 | } 15 | // 16 | public static int[] getBeltSlots() { 17 | // return BaubleType.BELT.getValidSlots(); 18 | return EMPTY; 19 | } 20 | // 21 | public static int[] getBodySlots() { 22 | // return BaubleType.BODY.getValidSlots(); 23 | return EMPTY; 24 | } 25 | // 26 | public static int[] getCharmSlots() { 27 | // return BaubleType.CHARM.getValidSlots(); 28 | return EMPTY; 29 | } 30 | // 31 | public static int[] getHeadSlots() { 32 | // return BaubleType.HEAD.getValidSlots(); 33 | return EMPTY; 34 | } 35 | // 36 | public static int[] getRingSlots() { 37 | // return BaubleType.RING.getValidSlots(); 38 | return EMPTY; 39 | } 40 | // 41 | public static int[] getTrinketSlots() { 42 | // return BaubleType.TRINKET.getValidSlots(); 43 | return EMPTY; 44 | } 45 | // 46 | public static ItemStack getStack(PlayerEntity player, int slot) { 47 | // IBaublesItemHandler handler = BaublesApi.getBaublesHandler(player); 48 | // if (handler == null) { 49 | // return ItemStack.EMPTY; 50 | // } 51 | // return handler.getStackInSlot(slot); 52 | return ItemStack.EMPTY; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/compat/EnigmaSupport.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.compat; 2 | 3 | public class EnigmaSupport { 4 | 5 | // @todo 1.15 6 | // private static IEnigmaScript enigmaScript; 7 | // 8 | public static void register() { 9 | // FMLInterModComms.sendFunctionMessage("enigma", "getEnigmaScript", "mcjty.fxcontrol.compat.EnigmaSupport$GetEnigmaScript"); 10 | } 11 | // 12 | // public static void setPlayerState(PlayerEntity player, String statename, String statevalue) { 13 | // enigmaScript.setPlayerState(player, statename, statevalue); 14 | // } 15 | // 16 | // public static void setState(World world, String statename, String statevalue) { 17 | // enigmaScript.setState(world, statename, statevalue); 18 | // } 19 | // 20 | // public static String getPlayerState(PlayerEntity player, String statename) { 21 | // return enigmaScript.getPlayerState(player, statename); 22 | // } 23 | // 24 | // public static String getState(World world, String statename) { 25 | // return enigmaScript.getState(world, statename); 26 | // } 27 | // 28 | // public static class GetEnigmaScript implements Function { 29 | // @Nullable 30 | // @Override 31 | // public Void apply(IEnigmaScript lc) { 32 | // enigmaScript = lc; 33 | // return null; 34 | // } 35 | // } 36 | // 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/compat/GameStageSupport.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.compat; 2 | 3 | import net.darkhax.gamestages.GameStageHelper; 4 | import net.darkhax.gamestages.data.IStageData; 5 | import net.minecraft.entity.player.PlayerEntity; 6 | 7 | public class GameStageSupport { 8 | 9 | public static boolean hasGameStage(PlayerEntity player, String stage) { 10 | if (player != null) { 11 | IStageData stageData = GameStageHelper.getPlayerData(player); 12 | return stageData.hasStage(stage); 13 | } else { 14 | return false; 15 | } 16 | } 17 | 18 | public static void addGameStage(PlayerEntity player, String stage) { 19 | if (player != null) { 20 | IStageData stageData = GameStageHelper.getPlayerData(player); 21 | stageData.addStage(stage); 22 | } 23 | } 24 | 25 | public static void removeGameStage(PlayerEntity player, String stage) { 26 | if (player != null) { 27 | IStageData stageData = GameStageHelper.getPlayerData(player); 28 | stageData.addStage(stage); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/compat/LostCitySupport.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.compat; 2 | 3 | import mcjty.incontrol.InControl; 4 | import mcjty.lostcities.api.ILostChunkInfo; 5 | import mcjty.lostcities.api.ILostCities; 6 | import mcjty.lostcities.api.ILostCityInformation; 7 | import mcjty.incontrol.tools.rules.IEventQuery; 8 | import net.minecraft.util.math.BlockPos; 9 | import net.minecraft.world.IServerWorld; 10 | import net.minecraft.world.IWorld; 11 | import net.minecraft.world.World; 12 | import net.minecraftforge.fml.InterModComms; 13 | import net.minecraftforge.fml.ModList; 14 | 15 | import java.util.function.Function; 16 | 17 | public class LostCitySupport { 18 | 19 | private static boolean registered = false; 20 | private static ILostCities lostCities; 21 | 22 | public static void register() { 23 | if (ModList.get().isLoaded("lostcities")) { 24 | registerInternal(); 25 | } 26 | } 27 | 28 | private static void registerInternal() { 29 | if (registered) { 30 | return; 31 | } 32 | registered = true; 33 | InterModComms.sendTo("lostcities", "getLostCities", GetLostCities::new); 34 | InControl.setup.getLogger().info("Enabling support for Lost Cities"); 35 | } 36 | 37 | private static World getWorld(IEventQuery query, T event) { 38 | IWorld world = query.getWorld(event); 39 | if (world.isClientSide()) { 40 | return null; 41 | } 42 | World w; 43 | if (world instanceof World) { 44 | w = (World) world; 45 | } else if (world instanceof IServerWorld) { 46 | w = ((IServerWorld) world).getLevel(); 47 | } else { 48 | throw new IllegalStateException("Bad world!"); 49 | } 50 | return w; 51 | } 52 | 53 | 54 | public static boolean isCity(IEventQuery query, T event) { 55 | World w = getWorld(query, event); 56 | if (w == null) { 57 | return false; // This test don't work client side 58 | } 59 | ILostCityInformation info = lostCities.getLostInfo(w); 60 | if (info != null) { 61 | BlockPos pos = query.getPos(event); 62 | ILostChunkInfo chunkInfo = info.getChunkInfo(pos.getX() >> 4, pos.getZ() >> 4); 63 | return chunkInfo.isCity(); 64 | } 65 | return false; 66 | } 67 | 68 | public static boolean isStreet(IEventQuery query, T event) { 69 | World w = getWorld(query, event); 70 | if (w == null) { 71 | return false; // This test don't work client side 72 | } 73 | ILostCityInformation info = lostCities.getLostInfo(w); 74 | if (info != null) { 75 | BlockPos pos = query.getPos(event); 76 | ILostChunkInfo chunkInfo = info.getChunkInfo(pos.getX() >> 4, pos.getZ() >> 4); 77 | return chunkInfo.isCity() && chunkInfo.getBuildingType() == null; 78 | } 79 | return false; 80 | } 81 | 82 | public static boolean inSphere(IEventQuery query, T event) { 83 | World w = getWorld(query, event); 84 | if (w == null) { 85 | return false; // This test don't work client side 86 | } 87 | ILostCityInformation info = lostCities.getLostInfo(w); 88 | if (info != null) { 89 | BlockPos pos = query.getPos(event); 90 | ILostChunkInfo chunkInfo = info.getChunkInfo(pos.getX() >> 4, pos.getZ() >> 4); 91 | return chunkInfo.getSphere() != null; 92 | } 93 | return false; 94 | } 95 | 96 | public static boolean isBuilding(IEventQuery query, T event) { 97 | World w = getWorld(query, event); 98 | if (w == null) { 99 | return false; // This test don't work client side 100 | } 101 | ILostCityInformation info = lostCities.getLostInfo(w); 102 | if (info != null) { 103 | BlockPos pos = query.getPos(event); 104 | ILostChunkInfo chunkInfo = info.getChunkInfo(pos.getX() >> 4, pos.getZ() >> 4); 105 | return chunkInfo.isCity() && chunkInfo.getBuildingType() != null; 106 | } 107 | return false; 108 | } 109 | 110 | public static class GetLostCities implements Function { 111 | 112 | @Override 113 | public Void apply(ILostCities lc) { 114 | lostCities = lc; 115 | return null; 116 | } 117 | } 118 | 119 | } 120 | 121 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/compat/ModRuleCompatibilityLayer.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.compat; 2 | 3 | import mcjty.incontrol.setup.ModSetup; 4 | import mcjty.incontrol.tools.rules.IEventQuery; 5 | import mcjty.incontrol.tools.rules.IModRuleCompatibilityLayer; 6 | import net.minecraft.entity.player.PlayerEntity; 7 | import net.minecraft.item.ItemStack; 8 | import net.minecraft.util.ResourceLocation; 9 | import net.minecraft.util.text.TranslationTextComponent; 10 | import net.minecraft.world.IWorld; 11 | import net.minecraft.world.biome.Biome; 12 | 13 | public class ModRuleCompatibilityLayer implements IModRuleCompatibilityLayer { 14 | 15 | @Override 16 | public boolean hasBaubles() { 17 | return ModSetup.baubles; 18 | } 19 | 20 | @Override 21 | public int[] getAmuletSlots() { 22 | return BaublesSupport.getAmuletSlots(); 23 | } 24 | 25 | @Override 26 | public int[] getBeltSlots() { 27 | return BaublesSupport.getBeltSlots(); 28 | } 29 | 30 | @Override 31 | public int[] getBodySlots() { 32 | return BaublesSupport.getBodySlots(); 33 | } 34 | 35 | @Override 36 | public int[] getCharmSlots() { 37 | return BaublesSupport.getCharmSlots(); 38 | } 39 | 40 | @Override 41 | public int[] getHeadSlots() { 42 | return BaublesSupport.getHeadSlots(); 43 | } 44 | 45 | @Override 46 | public int[] getRingSlots() { 47 | return BaublesSupport.getRingSlots(); 48 | } 49 | 50 | @Override 51 | public int[] getTrinketSlots() { 52 | return BaublesSupport.getTrinketSlots(); 53 | } 54 | 55 | @Override 56 | public ItemStack getBaubleStack(PlayerEntity player, int slot) { 57 | return BaublesSupport.getStack(player, slot); 58 | } 59 | 60 | @Override 61 | public boolean hasGameStages() { 62 | return ModSetup.gamestages; 63 | } 64 | 65 | @Override 66 | public boolean hasGameStage(PlayerEntity player, String stage) { 67 | return GameStageSupport.hasGameStage(player, stage); 68 | } 69 | 70 | @Override 71 | public void addGameStage(PlayerEntity player, String stage) { 72 | GameStageSupport.addGameStage(player, stage); 73 | } 74 | 75 | @Override 76 | public void removeGameStage(PlayerEntity player, String stage) { 77 | GameStageSupport.removeGameStage(player, stage); 78 | } 79 | 80 | @Override 81 | public boolean hasLostCities() { 82 | return ModSetup.lostcities; 83 | } 84 | 85 | @Override 86 | public boolean isCity(IEventQuery query, T event) { 87 | return LostCitySupport.isCity(query, event); 88 | } 89 | 90 | @Override 91 | public boolean isStreet(IEventQuery query, T event) { 92 | return LostCitySupport.isStreet(query, event); 93 | } 94 | 95 | @Override 96 | public boolean inSphere(IEventQuery query, T event) { 97 | return LostCitySupport.inSphere(query, event); 98 | } 99 | 100 | @Override 101 | public boolean isBuilding(IEventQuery query, T event) { 102 | return LostCitySupport.isBuilding(query, event); 103 | } 104 | 105 | @Override 106 | public boolean hasSereneSeasons() { 107 | return ModSetup.sereneSeasons; 108 | } 109 | 110 | @Override 111 | public boolean isSpring(IWorld world) { 112 | return SereneSeasonsSupport.isSpring(world); 113 | } 114 | 115 | @Override 116 | public boolean isSummer(IWorld world) { 117 | return SereneSeasonsSupport.isSummer(world); 118 | } 119 | 120 | @Override 121 | public boolean isWinter(IWorld world) { 122 | return SereneSeasonsSupport.isWinter(world); 123 | } 124 | 125 | @Override 126 | public boolean isAutumn(IWorld world) { 127 | return SereneSeasonsSupport.isAutumn(world); 128 | } 129 | 130 | @Override 131 | public boolean hasEnigmaScript() { 132 | return false; 133 | } 134 | 135 | @Override 136 | public String getPlayerState(PlayerEntity player, String statename) { 137 | return null; 138 | } 139 | 140 | @Override 141 | public String getState(IWorld world, String statename) { 142 | return null; 143 | } 144 | 145 | @Override 146 | public void setPlayerState(PlayerEntity player, String statename, String statevalue) { 147 | // Not supported by In Control 148 | } 149 | 150 | @Override 151 | public void setState(IWorld world, String statename, String statevalue) { 152 | // Not supported by In Control 153 | } 154 | 155 | @Override 156 | public String getBiomeName(Biome biome) { 157 | ResourceLocation resourceLocation = biome.getRegistryName(); 158 | String s = "biome." + resourceLocation.getNamespace() + "." + resourceLocation.getPath(); 159 | return new TranslationTextComponent(s).getString(); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/compat/SereneSeasonsSupport.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.compat; 2 | 3 | import net.minecraft.world.IWorld; 4 | 5 | public class SereneSeasonsSupport { 6 | 7 | public static boolean isSpring(IWorld world) { 8 | // @todo 1.15 9 | return false; 10 | // ISeasonState seasonState = SeasonHelper.getSeasonState(world); 11 | // return Season.SPRING.equals(seasonState.getSeason()); 12 | } 13 | 14 | public static boolean isSummer(IWorld world) { 15 | // @todo 1.15 16 | return false; 17 | // ISeasonState seasonState = SeasonHelper.getSeasonState(world); 18 | // return Season.SUMMER.equals(seasonState.getSeason()); 19 | } 20 | 21 | public static boolean isWinter(IWorld world) { 22 | // @todo 1.15 23 | return false; 24 | // ISeasonState seasonState = SeasonHelper.getSeasonState(world); 25 | // return Season.WINTER.equals(seasonState.getSeason()); 26 | } 27 | 28 | public static boolean isAutumn(IWorld world) { 29 | // @todo 1.15 30 | return false; 31 | // ISeasonState seasonState = SeasonHelper.getSeasonState(world); 32 | // return Season.AUTUMN.equals(seasonState.getSeason()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/data/DataStorage.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.data; 2 | 3 | import mcjty.incontrol.rules.PhaseRule; 4 | import mcjty.incontrol.rules.RulesManager; 5 | import net.minecraft.nbt.CompoundNBT; 6 | import net.minecraft.server.MinecraftServer; 7 | import net.minecraft.world.World; 8 | import net.minecraft.world.server.ServerWorld; 9 | import net.minecraft.world.storage.DimensionSavedDataManager; 10 | import net.minecraft.world.storage.WorldSavedData; 11 | 12 | import javax.annotation.Nonnull; 13 | import java.util.HashSet; 14 | import java.util.Set; 15 | 16 | public class DataStorage extends WorldSavedData { 17 | 18 | private static final String NAME = "InControlData"; 19 | 20 | private Boolean isDay = null; 21 | private int daycounter = 0; 22 | private final Set phases = new HashSet<>(); 23 | 24 | private int checkCounter = 0; // We only check every X ticks for efficiency 25 | 26 | public DataStorage() { 27 | super(NAME); 28 | } 29 | 30 | @Nonnull 31 | public static DataStorage getData(World world) { 32 | if (world.isClientSide()) { 33 | throw new RuntimeException("Don't access this client-side!"); 34 | } 35 | MinecraftServer server = world.getServer(); 36 | ServerWorld overworld = server.getLevel(World.OVERWORLD); 37 | 38 | DimensionSavedDataManager storage = overworld.getDataStorage(); 39 | return storage.computeIfAbsent(DataStorage::new, NAME); 40 | } 41 | 42 | public int getDaycounter() { 43 | return daycounter; 44 | } 45 | 46 | public void setDaycounter(int daycounter) { 47 | this.daycounter = daycounter; 48 | setDirty(); 49 | } 50 | 51 | public Boolean getDay() { 52 | return isDay; 53 | } 54 | 55 | public void setDay(Boolean day) { 56 | isDay = day; 57 | } 58 | 59 | public Set getPhases() { 60 | return phases; 61 | } 62 | 63 | public void tick(World world) { 64 | tickTime(world); 65 | 66 | checkCounter--; 67 | if (checkCounter <= 0) { 68 | checkCounter = 10; 69 | tickPhases(world); 70 | } 71 | } 72 | 73 | private void tickTime(World world) { 74 | long time = world.getDayTime() % 24000; 75 | boolean day = time >= 0 && time < 12000; 76 | if (isDay == null) { 77 | isDay = day; 78 | setDirty(); 79 | } else { 80 | if (day != isDay) { 81 | if (day) { // New day 82 | daycounter++; 83 | } 84 | isDay = day; 85 | setDirty(); 86 | } 87 | } 88 | } 89 | 90 | private void tickPhases(World world) { 91 | boolean dirty = false; 92 | for (PhaseRule rule : RulesManager.phaseRules) { 93 | if (rule.match(world)) { 94 | if (phases.add(rule.getName())) { 95 | dirty = true; 96 | } 97 | } else { 98 | if (phases.remove(rule.getName())) { 99 | dirty = true; 100 | } 101 | } 102 | } 103 | if (dirty) { 104 | // We need to reevaluate the rules 105 | RulesManager.onPhaseChange(); 106 | } 107 | } 108 | 109 | @Override 110 | public void load(CompoundNBT tag) { 111 | daycounter = tag.getInt("daycounter"); 112 | if (tag.contains("isday")) { 113 | isDay = tag.getBoolean("isday"); 114 | } else { 115 | isDay = null; 116 | } 117 | } 118 | 119 | @Override 120 | public CompoundNBT save(CompoundNBT tag) { 121 | tag.putInt("daycounter", daycounter); 122 | if (isDay != null) { 123 | tag.putBoolean("isday", isDay); 124 | } 125 | return tag; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/data/PhaseTools.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.data; 2 | 3 | import com.google.gson.JsonArray; 4 | import com.google.gson.JsonElement; 5 | 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | public class PhaseTools { 10 | 11 | public static Set getPhases(JsonElement element) { 12 | Set phases = new HashSet<>(); 13 | if (element.getAsJsonObject().has("phase")) { 14 | JsonElement phaseElement = element.getAsJsonObject().get("phase"); 15 | if (phaseElement.isJsonArray()) { 16 | JsonArray phasesArray = phaseElement.getAsJsonArray(); 17 | phasesArray.forEach(e -> phases.add(e.getAsString())); 18 | } else { 19 | phases.add(phaseElement.getAsString()); 20 | } 21 | } 22 | return phases; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/data/Statistics.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.data; 2 | 3 | import mcjty.incontrol.InControl; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class Statistics { 9 | 10 | private static final List SPAWN_STATS = new ArrayList<>(); 11 | private static final List SPAWNER_STATS = new ArrayList<>(); 12 | 13 | public static void addSpawnerStat(int rule) { 14 | while (rule >= SPAWNER_STATS.size()) { 15 | SPAWNER_STATS.add(new SpawnerStat()); 16 | } 17 | SpawnerStat stat = SPAWNER_STATS.get(rule); 18 | stat.counter++; 19 | } 20 | 21 | public static void addSpawnStat(int rule, boolean deny) { 22 | while (rule >= SPAWN_STATS.size()) { 23 | SPAWN_STATS.add(new SpawnStat()); 24 | } 25 | SpawnStat stat = SPAWN_STATS.get(rule); 26 | stat.counter++; 27 | stat.deny = deny; 28 | } 29 | 30 | public static void clear() { 31 | SPAWN_STATS.clear(); 32 | SPAWNER_STATS.clear(); 33 | } 34 | 35 | public static void dump() { 36 | InControl.setup.getLogger().info("### Spawner ###"); 37 | for (int i = 0 ; i < SPAWNER_STATS.size() ; i++) { 38 | SpawnerStat stat = SPAWNER_STATS.get(i); 39 | InControl.setup.getLogger().info("Rule " + i + " spawned " + stat.counter + " mobs"); 40 | } 41 | InControl.setup.getLogger().info("### Spawn ###"); 42 | for (int i = 0; i < SPAWN_STATS.size() ; i++) { 43 | SpawnStat stat = SPAWN_STATS.get(i); 44 | InControl.setup.getLogger().info("Rule " + i + " fired " + stat.counter + " times (" + (stat.deny ? "deny)": "allow)")); 45 | } 46 | } 47 | 48 | private static class SpawnStat { 49 | private int counter; 50 | private boolean deny; 51 | } 52 | 53 | private static class SpawnerStat { 54 | private int counter; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/rules/ExperienceRule.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.rules; 2 | 3 | import com.google.gson.JsonElement; 4 | import mcjty.incontrol.ErrorHandler; 5 | import mcjty.incontrol.InControl; 6 | import mcjty.incontrol.compat.ModRuleCompatibilityLayer; 7 | import mcjty.incontrol.data.PhaseTools; 8 | import mcjty.incontrol.rules.support.GenericRuleEvaluator; 9 | import mcjty.incontrol.tools.rules.IEventQuery; 10 | import mcjty.incontrol.tools.rules.IModRuleCompatibilityLayer; 11 | import mcjty.incontrol.tools.rules.RuleBase; 12 | import mcjty.incontrol.tools.typed.Attribute; 13 | import mcjty.incontrol.tools.typed.AttributeMap; 14 | import mcjty.incontrol.tools.typed.GenericAttributeMapFactory; 15 | import net.minecraft.entity.Entity; 16 | import net.minecraft.entity.player.PlayerEntity; 17 | import net.minecraft.item.ItemStack; 18 | import net.minecraft.util.DamageSource; 19 | import net.minecraft.util.math.BlockPos; 20 | import net.minecraft.world.World; 21 | import net.minecraftforge.event.entity.living.LivingExperienceDropEvent; 22 | import net.minecraftforge.eventbus.api.Event; 23 | 24 | import java.util.Set; 25 | 26 | import static mcjty.incontrol.rules.support.RuleKeys.*; 27 | 28 | public class ExperienceRule extends RuleBase { 29 | 30 | public static final IEventQuery EVENT_QUERY = new IEventQuery() { 31 | @Override 32 | public World getWorld(LivingExperienceDropEvent o) { 33 | return o.getEntity().getCommandSenderWorld(); 34 | } 35 | 36 | @Override 37 | public BlockPos getPos(LivingExperienceDropEvent o) { 38 | return o.getEntity().blockPosition(); 39 | } 40 | 41 | @Override 42 | public BlockPos getValidBlockPos(LivingExperienceDropEvent o) { 43 | return o.getEntity().blockPosition().below(); 44 | } 45 | 46 | @Override 47 | public int getY(LivingExperienceDropEvent o) { 48 | return o.getEntity().blockPosition().getY(); 49 | } 50 | 51 | @Override 52 | public Entity getEntity(LivingExperienceDropEvent o) { 53 | return o.getEntity(); 54 | } 55 | 56 | @Override 57 | public DamageSource getSource(LivingExperienceDropEvent o) { 58 | return null; 59 | } 60 | 61 | @Override 62 | public Entity getAttacker(LivingExperienceDropEvent o) { 63 | return o.getAttackingPlayer(); 64 | } 65 | 66 | @Override 67 | public PlayerEntity getPlayer(LivingExperienceDropEvent o) { 68 | return o.getAttackingPlayer(); 69 | } 70 | 71 | @Override 72 | public ItemStack getItem(LivingExperienceDropEvent o) { 73 | return ItemStack.EMPTY; 74 | } 75 | }; 76 | private static final GenericAttributeMapFactory FACTORY = new GenericAttributeMapFactory(); 77 | 78 | static { 79 | FACTORY 80 | .attribute(Attribute.create(MINTIME)) 81 | .attribute(Attribute.create(MAXTIME)) 82 | .attribute(Attribute.create(MINLIGHT)) 83 | .attribute(Attribute.create(MAXLIGHT)) 84 | .attribute(Attribute.create(MINHEIGHT)) 85 | .attribute(Attribute.create(MAXHEIGHT)) 86 | .attribute(Attribute.create(MINDIFFICULTY)) 87 | .attribute(Attribute.create(MAXDIFFICULTY)) 88 | .attribute(Attribute.create(MINSPAWNDIST)) 89 | .attribute(Attribute.create(MAXSPAWNDIST)) 90 | .attribute(Attribute.create(RANDOM)) 91 | .attribute(Attribute.create(INBUILDING)) 92 | .attribute(Attribute.create(INCITY)) 93 | .attribute(Attribute.create(INSTREET)) 94 | .attribute(Attribute.create(INSPHERE)) 95 | .attribute(Attribute.create(PASSIVE)) 96 | .attribute(Attribute.create(HOSTILE)) 97 | .attribute(Attribute.create(BABY)) 98 | .attribute(Attribute.create(SEESKY)) 99 | .attribute(Attribute.create(WEATHER)) 100 | .attribute(Attribute.createMulti(CATEGORY)) 101 | .attribute(Attribute.create(DIFFICULTY)) 102 | .attribute(Attribute.create(STRUCTURE)) 103 | .attribute(Attribute.create(PLAYER)) 104 | .attribute(Attribute.create(REALPLAYER)) 105 | .attribute(Attribute.create(FAKEPLAYER)) 106 | .attribute(Attribute.create(WINTER)) 107 | .attribute(Attribute.create(SUMMER)) 108 | .attribute(Attribute.create(SPRING)) 109 | .attribute(Attribute.create(AUTUMN)) 110 | .attribute(Attribute.create(STATE)) 111 | .attribute(Attribute.create(PSTATE)) 112 | .attribute(Attribute.createMulti(MOB)) 113 | .attribute(Attribute.createMulti(MOD)) 114 | .attribute(Attribute.createMulti(BLOCK)) 115 | .attribute(Attribute.create(BLOCKOFFSET)) 116 | .attribute(Attribute.createMulti(BIOME)) 117 | .attribute(Attribute.createMulti(BIOMETYPE)) 118 | .attribute(Attribute.createMulti(DIMENSION)) 119 | .attribute(Attribute.createMulti(DIMENSION_MOD)) 120 | .attribute(Attribute.createMulti(HELDITEM)) 121 | .attribute(Attribute.createMulti(PLAYER_HELDITEM)) 122 | .attribute(Attribute.createMulti(OFFHANDITEM)) 123 | .attribute(Attribute.createMulti(BOTHHANDSITEM)) 124 | 125 | .attribute(Attribute.create(ACTION_RESULT)) 126 | .attribute(Attribute.create(ACTION_SETXP)) 127 | .attribute(Attribute.create(ACTION_ADDXP)) 128 | .attribute(Attribute.create(ACTION_MULTXP)) 129 | ; 130 | } 131 | 132 | private final GenericRuleEvaluator ruleEvaluator; 133 | private final Set phases; 134 | private Event.Result result; 135 | private Integer xp = null; 136 | private float multxp = 1.0f; 137 | private float addxp = 0.0f; 138 | 139 | private ExperienceRule(AttributeMap map, Set phases) { 140 | super(InControl.setup.getLogger()); 141 | this.phases = phases; 142 | ruleEvaluator = new GenericRuleEvaluator(map); 143 | addActions(map, new ModRuleCompatibilityLayer()); 144 | } 145 | 146 | public Set getPhases() { 147 | return phases; 148 | } 149 | 150 | public static ExperienceRule parse(JsonElement element) { 151 | if (element == null) { 152 | return null; 153 | } else { 154 | AttributeMap map = FACTORY.parse(element, "experience.json"); 155 | return new ExperienceRule(map, PhaseTools.getPhases(element)); 156 | } 157 | } 158 | 159 | public int modifyXp(int xpIn) { 160 | if (xp != null) { 161 | xpIn = xp; 162 | } 163 | return (int) (xpIn * multxp + addxp); 164 | } 165 | 166 | @Override 167 | protected void addActions(AttributeMap map, IModRuleCompatibilityLayer layer) { 168 | super.addActions(map, layer); 169 | 170 | map.consumeOrElse(ACTION_RESULT, br -> { 171 | if ("default".equals(br) || br.startsWith("def")) { 172 | this.result = Event.Result.DEFAULT; 173 | } else if ("allow".equals(br) || "true".equals(br)) { 174 | this.result = Event.Result.ALLOW; 175 | } else { 176 | this.result = Event.Result.DENY; 177 | } 178 | }, () -> { 179 | this.result = Event.Result.DEFAULT; 180 | }); 181 | 182 | map.consume(ACTION_SETXP, v -> xp = v); 183 | map.consume(ACTION_ADDXP, v -> addxp = v); 184 | map.consume(ACTION_MULTXP, v -> multxp = v); 185 | 186 | if (!map.isEmpty()) { 187 | StringBuffer buffer = new StringBuffer(); 188 | map.getKeys().forEach(k -> buffer.append(k).append(' ')); 189 | ErrorHandler.error("Invalid keywords in experience rule: " + buffer); 190 | } 191 | } 192 | 193 | public boolean match(LivingExperienceDropEvent event) { 194 | return ruleEvaluator.match(event, EVENT_QUERY); 195 | } 196 | 197 | public Event.Result getResult() { 198 | return result; 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/rules/PhaseRule.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.rules; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonObject; 5 | import mcjty.incontrol.rules.support.GenericRuleEvaluator; 6 | import mcjty.incontrol.tools.rules.IEventQuery; 7 | import mcjty.incontrol.tools.typed.Attribute; 8 | import mcjty.incontrol.tools.typed.AttributeMap; 9 | import mcjty.incontrol.tools.typed.GenericAttributeMapFactory; 10 | import net.minecraft.entity.Entity; 11 | import net.minecraft.entity.player.PlayerEntity; 12 | import net.minecraft.item.ItemStack; 13 | import net.minecraft.util.DamageSource; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraft.world.IWorld; 16 | 17 | import static mcjty.incontrol.rules.support.RuleKeys.*; 18 | 19 | public class PhaseRule { 20 | 21 | private final String name; 22 | private final GenericRuleEvaluator ruleEvaluator; 23 | 24 | 25 | public static final IEventQuery EVENT_QUERY = new IEventQuery() { 26 | @Override 27 | public IWorld getWorld(IWorld o) { 28 | return o; 29 | } 30 | 31 | @Override 32 | public BlockPos getPos(IWorld o) { 33 | return null; 34 | } 35 | 36 | @Override 37 | public BlockPos getValidBlockPos(IWorld o) { 38 | return null; 39 | } 40 | 41 | @Override 42 | public int getY(IWorld o) { 43 | return 0; 44 | } 45 | 46 | @Override 47 | public Entity getEntity(IWorld o) { 48 | return null; 49 | } 50 | 51 | @Override 52 | public DamageSource getSource(IWorld o) { 53 | return null; 54 | } 55 | 56 | @Override 57 | public Entity getAttacker(IWorld o) { 58 | return null; 59 | } 60 | 61 | @Override 62 | public PlayerEntity getPlayer(IWorld o) { 63 | return null; 64 | } 65 | 66 | @Override 67 | public ItemStack getItem(IWorld o) { 68 | return null; 69 | } 70 | }; 71 | 72 | private static final GenericAttributeMapFactory FACTORY = new GenericAttributeMapFactory(); 73 | static { 74 | FACTORY 75 | .attribute(Attribute.create(MINTIME)) 76 | .attribute(Attribute.create(MAXTIME)) 77 | .attribute(Attribute.create(DAYCOUNT)) 78 | .attribute(Attribute.create(MINDAYCOUNT)) 79 | .attribute(Attribute.create(MAXDAYCOUNT)) 80 | .attribute(Attribute.create(WEATHER)) 81 | .attribute(Attribute.create(WINTER)) 82 | .attribute(Attribute.create(SUMMER)) 83 | .attribute(Attribute.create(SPRING)) 84 | .attribute(Attribute.create(AUTUMN)) 85 | .attribute(Attribute.create(STATE)) 86 | ; 87 | } 88 | 89 | private PhaseRule(String name, AttributeMap map) { 90 | this.name = name; 91 | ruleEvaluator = new GenericRuleEvaluator(map); 92 | } 93 | 94 | public String getName() { 95 | return name; 96 | } 97 | 98 | public boolean match(IWorld world) { 99 | return ruleEvaluator.match(world, EVENT_QUERY); 100 | } 101 | 102 | 103 | public static PhaseRule parse(JsonElement element) { 104 | if (element == null) { 105 | return null; 106 | } 107 | JsonObject object = element.getAsJsonObject(); 108 | JsonElement conditions = object.get("conditions"); 109 | AttributeMap map = FACTORY.parse(conditions, "phases.json"); 110 | 111 | return new PhaseRule(object.get("name").getAsString(), map); 112 | } 113 | 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/rules/PotentialSpawnRule.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.rules; 2 | 3 | import com.google.gson.JsonArray; 4 | import com.google.gson.JsonElement; 5 | import com.google.gson.JsonObject; 6 | import mcjty.incontrol.InControl; 7 | import mcjty.incontrol.rules.support.GenericRuleEvaluator; 8 | import mcjty.incontrol.tools.rules.IEventQuery; 9 | import mcjty.incontrol.tools.rules.RuleBase; 10 | import mcjty.incontrol.tools.typed.Attribute; 11 | import mcjty.incontrol.tools.typed.AttributeMap; 12 | import mcjty.incontrol.tools.typed.GenericAttributeMapFactory; 13 | import net.minecraft.entity.Entity; 14 | import net.minecraft.entity.EntityType; 15 | import net.minecraft.entity.player.PlayerEntity; 16 | import net.minecraft.item.ItemStack; 17 | import net.minecraft.util.DamageSource; 18 | import net.minecraft.util.ResourceLocation; 19 | import net.minecraft.util.math.BlockPos; 20 | import net.minecraft.world.IWorld; 21 | import net.minecraft.world.biome.MobSpawnInfo; 22 | import net.minecraftforge.event.world.WorldEvent; 23 | import net.minecraftforge.registries.ForgeRegistries; 24 | import org.apache.logging.log4j.Level; 25 | 26 | import java.util.ArrayList; 27 | import java.util.HashSet; 28 | import java.util.List; 29 | import java.util.Set; 30 | 31 | import static mcjty.incontrol.rules.support.RuleKeys.*; 32 | 33 | public class PotentialSpawnRule extends RuleBase { 34 | 35 | public static final IEventQuery EVENT_QUERY = new IEventQuery() { 36 | @Override 37 | public IWorld getWorld(WorldEvent.PotentialSpawns o) { 38 | return o.getWorld(); 39 | } 40 | 41 | @Override 42 | public BlockPos getPos(WorldEvent.PotentialSpawns o) { 43 | return o.getPos(); 44 | } 45 | 46 | @Override 47 | public BlockPos getValidBlockPos(WorldEvent.PotentialSpawns o) { 48 | return o.getPos().below(); 49 | } 50 | 51 | @Override 52 | public int getY(WorldEvent.PotentialSpawns o) { 53 | return o.getPos().getY(); 54 | } 55 | 56 | @Override 57 | public Entity getEntity(WorldEvent.PotentialSpawns o) { 58 | return null; 59 | } 60 | 61 | @Override 62 | public DamageSource getSource(WorldEvent.PotentialSpawns o) { 63 | return null; 64 | } 65 | 66 | @Override 67 | public Entity getAttacker(WorldEvent.PotentialSpawns o) { 68 | return null; 69 | } 70 | 71 | @Override 72 | public PlayerEntity getPlayer(WorldEvent.PotentialSpawns o) { 73 | return null; 74 | } 75 | 76 | @Override 77 | public ItemStack getItem(WorldEvent.PotentialSpawns o) { 78 | return ItemStack.EMPTY; 79 | } 80 | }; 81 | private static final GenericAttributeMapFactory FACTORY = new GenericAttributeMapFactory(); 82 | private static final GenericAttributeMapFactory MOB_FACTORY = new GenericAttributeMapFactory(); 83 | 84 | static { 85 | FACTORY 86 | .attribute(Attribute.create(MINCOUNT)) 87 | .attribute(Attribute.create(MAXCOUNT)) 88 | .attribute(Attribute.create(MINDAYCOUNT)) 89 | .attribute(Attribute.create(MAXDAYCOUNT)) 90 | .attribute(Attribute.create(MINTIME)) 91 | .attribute(Attribute.create(MAXTIME)) 92 | .attribute(Attribute.create(MINLIGHT)) 93 | .attribute(Attribute.create(MAXLIGHT)) 94 | .attribute(Attribute.create(MINHEIGHT)) 95 | .attribute(Attribute.create(MAXHEIGHT)) 96 | .attribute(Attribute.create(MINDIFFICULTY)) 97 | .attribute(Attribute.create(MAXDIFFICULTY)) 98 | .attribute(Attribute.create(MINSPAWNDIST)) 99 | .attribute(Attribute.create(MAXSPAWNDIST)) 100 | .attribute(Attribute.create(RANDOM)) 101 | .attribute(Attribute.create(SEESKY)) 102 | .attribute(Attribute.create(WEATHER)) 103 | .attribute(Attribute.createMulti(CATEGORY)) 104 | .attribute(Attribute.create(DIFFICULTY)) 105 | .attribute(Attribute.create(STRUCTURE)) 106 | .attribute(Attribute.create(WINTER)) 107 | .attribute(Attribute.create(SUMMER)) 108 | .attribute(Attribute.create(SPRING)) 109 | .attribute(Attribute.create(AUTUMN)) 110 | .attribute(Attribute.create(STATE)) 111 | .attribute(Attribute.createMulti(BLOCK)) 112 | .attribute(Attribute.create(BLOCKOFFSET)) 113 | .attribute(Attribute.createMulti(BIOME)) 114 | .attribute(Attribute.createMulti(BIOMETYPE)) 115 | .attribute(Attribute.createMulti(DIMENSION)) 116 | .attribute(Attribute.createMulti(DIMENSION_MOD)) 117 | 118 | .attribute(Attribute.createMulti(ACTION_REMOVE_MOBS)) 119 | ; 120 | 121 | MOB_FACTORY 122 | .attribute(Attribute.create(MOB_NAME)) 123 | .attribute(Attribute.create(MOB_WEIGHT)) 124 | .attribute(Attribute.create(MOB_GROUPCOUNTMIN)) 125 | .attribute(Attribute.create(MOB_GROUPCOUNTMAX)) 126 | ; 127 | } 128 | 129 | private final GenericRuleEvaluator ruleEvaluator; 130 | private List spawnEntries = new ArrayList<>(); 131 | private Set toRemoveMobs = new HashSet<>(); 132 | 133 | private PotentialSpawnRule(AttributeMap map) { 134 | super(InControl.setup.getLogger()); 135 | 136 | ruleEvaluator = new GenericRuleEvaluator(map); 137 | 138 | if ((!map.has(ACTION_MOBS)) && (!map.has(ACTION_REMOVE_MOBS))) { 139 | InControl.setup.getLogger().log(Level.ERROR, "No 'mobs' or 'remove' specified!"); 140 | return; 141 | } 142 | makeSpawnEntries(map); 143 | if (map.has(ACTION_REMOVE_MOBS)) { 144 | addToRemoveAction(map); 145 | } 146 | } 147 | 148 | public static PotentialSpawnRule parse(JsonElement element) { 149 | if (element == null) { 150 | return null; 151 | } else { 152 | JsonObject jsonObject = element.getAsJsonObject(); 153 | if ((!jsonObject.has("mobs")) && (!jsonObject.has("remove"))) { 154 | return null; 155 | } 156 | 157 | AttributeMap map = FACTORY.parse(element, "potentialspawn.json"); 158 | 159 | if (jsonObject.has("mobs")) { 160 | JsonArray mobs = jsonObject.get("mobs").getAsJsonArray(); 161 | for (JsonElement mob : mobs) { 162 | AttributeMap mobMap = MOB_FACTORY.parse(mob, "potentialspawn.json (mob)"); 163 | map.addList(ACTION_MOBS, mobMap); 164 | } 165 | } 166 | return new PotentialSpawnRule(map); 167 | } 168 | } 169 | 170 | private void addToRemoveAction(AttributeMap map) { 171 | List toremove = map.getList(ACTION_REMOVE_MOBS); 172 | for (String s : toremove) { 173 | EntityType type = ForgeRegistries.ENTITIES.getValue(new ResourceLocation(s)); 174 | if (type == null) { 175 | InControl.setup.getLogger().log(Level.ERROR, "Cannot find mob '" + s + "'!"); 176 | return; 177 | } 178 | toRemoveMobs.add(type); 179 | } 180 | } 181 | 182 | private void makeSpawnEntries(AttributeMap map) { 183 | for (AttributeMap mobMap : map.getList(ACTION_MOBS)) { 184 | String id = mobMap.get(MOB_NAME); 185 | EntityType type = ForgeRegistries.ENTITIES.getValue(new ResourceLocation(id)); 186 | if (type == null) { 187 | InControl.setup.getLogger().log(Level.ERROR, "Cannot find mob '" + mobMap.get(MOB_NAME) + "'!"); 188 | return; 189 | } 190 | 191 | Integer weight = mobMap.get(MOB_WEIGHT); 192 | if (weight == null) { 193 | weight = 1; 194 | } 195 | Integer groupCountMin = mobMap.get(MOB_GROUPCOUNTMIN); 196 | if (groupCountMin == null) { 197 | groupCountMin = 1; 198 | } 199 | Integer groupCountMax = mobMap.get(MOB_GROUPCOUNTMAX); 200 | if (groupCountMax == null) { 201 | groupCountMax = Math.max(groupCountMin, 1); 202 | } 203 | MobSpawnInfo.Spawners entry = new MobSpawnInfo.Spawners(type, weight, groupCountMin, groupCountMax); 204 | spawnEntries.add(entry); 205 | } 206 | } 207 | 208 | public List getSpawnEntries() { 209 | return spawnEntries; 210 | } 211 | 212 | public boolean match(WorldEvent.PotentialSpawns event) { 213 | return ruleEvaluator.match(event, EVENT_QUERY); 214 | } 215 | 216 | public Set getToRemoveMobs() { 217 | return toRemoveMobs; 218 | } 219 | } 220 | 221 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/rules/RuleCache.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.rules; 2 | 3 | import mcjty.incontrol.tools.varia.Tools; 4 | import net.minecraft.entity.EntityType; 5 | import net.minecraft.entity.MobEntity; 6 | import net.minecraft.entity.monster.IMob; 7 | import net.minecraft.entity.passive.AnimalEntity; 8 | import net.minecraft.entity.player.PlayerEntity; 9 | import net.minecraft.util.RegistryKey; 10 | import net.minecraft.world.IWorld; 11 | import net.minecraft.world.World; 12 | import net.minecraft.world.server.ServerWorld; 13 | 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | public class RuleCache { 18 | 19 | private Map, CachePerWorld> caches = new HashMap<>(); 20 | 21 | public void reset(IWorld world) { 22 | RegistryKey key = Tools.getDimensionKey(world); 23 | CachePerWorld cache = caches.get(key); 24 | if (cache != null) { 25 | cache.reset(); 26 | } 27 | } 28 | 29 | public int getValidSpawnChunks(IWorld world) { 30 | CachePerWorld cache = getOrCreateCache(world); 31 | return cache.getValidSpawnChunks(world); 32 | } 33 | 34 | public int getValidPlayers(IWorld world) { 35 | CachePerWorld cache = getOrCreateCache(world); 36 | return cache.getValidPlayers(world); 37 | } 38 | 39 | public int getCountAll(IWorld world) { 40 | CachePerWorld cache = getOrCreateCache(world); 41 | return cache.getCountAll(world); 42 | } 43 | 44 | public int getCountPassive(IWorld world) { 45 | CachePerWorld cache = getOrCreateCache(world); 46 | return cache.getCountPassive(world); 47 | } 48 | 49 | public int getCountHostile(IWorld world) { 50 | CachePerWorld cache = getOrCreateCache(world); 51 | return cache.getCountHostile(world); 52 | } 53 | 54 | public int getCountNeutral(IWorld world) { 55 | CachePerWorld cache = getOrCreateCache(world); 56 | return cache.getCountNeutral(world); 57 | } 58 | 59 | 60 | public int getCount(IWorld world, EntityType entityType) { 61 | CachePerWorld cache = getOrCreateCache(world); 62 | int count = cache.getCount(world, entityType); 63 | return count; 64 | } 65 | 66 | public int getCountPerMod(IWorld world, String mod) { 67 | CachePerWorld cache = getOrCreateCache(world); 68 | CountPerMod countPerMod = cache.getCountPerMod(world, mod); 69 | return countPerMod == null ? 0 : countPerMod.total; 70 | } 71 | 72 | public int getCountPerModHostile(IWorld world, String mod) { 73 | CachePerWorld cache = getOrCreateCache(world); 74 | CountPerMod countPerMod = cache.getCountPerMod(world, mod); 75 | return countPerMod == null ? 0 : countPerMod.hostile; 76 | } 77 | 78 | public int getCountPerModPassive(IWorld world, String mod) { 79 | CachePerWorld cache = getOrCreateCache(world); 80 | CountPerMod countPerMod = cache.getCountPerMod(world, mod); 81 | return countPerMod == null ? 0 : countPerMod.passive; 82 | } 83 | 84 | public int getCountPerModAll(IWorld world, String mod) { 85 | CachePerWorld cache = getOrCreateCache(world); 86 | CountPerMod countPerMod = cache.getCountPerMod(world, mod); 87 | return countPerMod == null ? 0 : countPerMod.total; 88 | } 89 | 90 | public void registerSpawn(IWorld world, EntityType entityType) { 91 | CachePerWorld cache = getOrCreateCache(world); 92 | cache.registerSpawn(world, entityType); 93 | } 94 | 95 | public void registerDespawn(IWorld world, EntityType entityType) { 96 | CachePerWorld cache = getOrCreateCache(world); 97 | cache.registerDespawn(world, entityType); 98 | } 99 | 100 | private CachePerWorld getOrCreateCache(IWorld world) { 101 | RegistryKey key = Tools.getDimensionKey(world); 102 | CachePerWorld cache = caches.get(key); 103 | if (cache == null) { 104 | cache = new CachePerWorld(); 105 | caches.put(key, cache); 106 | } 107 | return cache; 108 | } 109 | 110 | 111 | private static class CountPerMod { 112 | private int hostile; 113 | private int passive; 114 | private int neutral; 115 | private int total; 116 | } 117 | 118 | private class CachePerWorld { 119 | 120 | private Map cachedCounters = new HashMap<>(); 121 | private Map countPerMod = new HashMap<>(); 122 | private int countPassive = -1; 123 | private int countHostile = -1; 124 | private int countNeutral = -1; 125 | private int validSpawnChunks = -1; 126 | private int validPlayers = -1; 127 | private boolean countDone = false; 128 | 129 | public void reset() { 130 | cachedCounters.clear(); 131 | countPerMod.clear(); 132 | countPassive = -1; 133 | countHostile = -1; 134 | countNeutral = -1; 135 | validSpawnChunks = -1; 136 | validPlayers = -1; 137 | countDone = false; 138 | } 139 | 140 | public int getValidSpawnChunks(IWorld world) { 141 | if (validSpawnChunks == -1) { 142 | validSpawnChunks = countValidSpawnChunks(world); 143 | } 144 | return validSpawnChunks; 145 | } 146 | 147 | public int getValidPlayers(IWorld world) { 148 | if (validPlayers == -1) { 149 | validPlayers = countValidPlayers(world); 150 | } 151 | return validPlayers; 152 | } 153 | 154 | private int countValidPlayers(IWorld world) { 155 | int cnt = 0; 156 | for (PlayerEntity entityplayer : world.players()) { 157 | if (!entityplayer.isSpectator()) { 158 | cnt++; 159 | } 160 | } 161 | return cnt; 162 | } 163 | 164 | private int countValidSpawnChunks(IWorld world) { 165 | ServerWorld sw = Tools.getServerWorld(world); 166 | return sw.getChunkSource().chunkMap.size(); 167 | } 168 | 169 | public int getCountAll(IWorld world) { 170 | count(world); 171 | return countHostile + countPassive + countNeutral; 172 | } 173 | 174 | public int getCountPassive(IWorld world) { 175 | count(world); 176 | return countPassive; 177 | } 178 | 179 | public int getCountHostile(IWorld world) { 180 | count(world); 181 | return countHostile; 182 | } 183 | 184 | public int getCountNeutral(IWorld world) { 185 | count(world); 186 | return countNeutral; 187 | } 188 | 189 | private void count(IWorld world) { 190 | if (countDone) { 191 | return; 192 | } 193 | countDone = true; 194 | cachedCounters.clear(); 195 | countPerMod.clear(); 196 | countPassive = 0; 197 | countHostile = 0; 198 | countNeutral = 0; 199 | 200 | ServerWorld sw = Tools.getServerWorld(world); 201 | 202 | sw.getEntities().forEach(entity -> { 203 | if (entity instanceof MobEntity) { 204 | int cnt = cachedCounters.getOrDefault(entity.getType(), 0)+1; 205 | cachedCounters.put(entity.getType(), cnt); 206 | 207 | String mod = entity.getType().getRegistryName().getNamespace(); 208 | CountPerMod count = countPerMod.computeIfAbsent(mod, s -> new CountPerMod()); 209 | count.total++; 210 | 211 | if (entity instanceof IMob) { 212 | count.hostile++; 213 | countHostile++; 214 | } else if (entity instanceof AnimalEntity) { 215 | count.passive++; 216 | countPassive++; 217 | } else { 218 | count.neutral++; 219 | countNeutral++; 220 | } 221 | } 222 | }); 223 | } 224 | 225 | public int getCount(IWorld world, EntityType entityType) { 226 | count(world); 227 | return cachedCounters.getOrDefault(entityType, 0); 228 | } 229 | 230 | public CountPerMod getCountPerMod(IWorld world, String mod) { 231 | count(world); 232 | return countPerMod.get(mod); 233 | } 234 | 235 | public void registerSpawn(IWorld world, EntityType entityType) { 236 | count(world); 237 | cachedCounters.put(entityType, cachedCounters.getOrDefault(entityType, 0) + 1); 238 | } 239 | 240 | public void registerDespawn(IWorld world, EntityType entityType) { 241 | count(world); 242 | Integer cnt = cachedCounters.getOrDefault(entityType, 0); 243 | if (cnt > 0) { 244 | cachedCounters.put(entityType, cnt-1); 245 | } 246 | } 247 | } 248 | 249 | } 250 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/rules/RulesManager.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.rules; 2 | 3 | import com.google.gson.JsonElement; 4 | import mcjty.incontrol.ErrorHandler; 5 | import mcjty.incontrol.InControl; 6 | import mcjty.incontrol.data.DataStorage; 7 | import mcjty.incontrol.tools.varia.JSonTools; 8 | import net.minecraft.world.World; 9 | import org.apache.logging.log4j.Level; 10 | 11 | import java.io.File; 12 | import java.nio.file.Path; 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.Set; 16 | import java.util.function.Function; 17 | import java.util.stream.Collectors; 18 | 19 | public class RulesManager { 20 | 21 | private static List rules = new ArrayList<>(); 22 | private static List filteredRules = null; 23 | 24 | private static List summonAidRules = new ArrayList<>(); 25 | private static List filteredSummonAidRules = null; 26 | 27 | private static List lootRules = new ArrayList<>(); 28 | private static List filteredLootRules = null; 29 | 30 | private static List experienceRules = new ArrayList<>(); 31 | private static List filteredExperienceRuiles = null; 32 | 33 | public static List potentialSpawnRules = new ArrayList<>(); 34 | public static List phaseRules = new ArrayList<>(); 35 | private static String path; 36 | 37 | public static void reloadRules() { 38 | rules.clear(); 39 | summonAidRules.clear(); 40 | potentialSpawnRules.clear(); 41 | lootRules.clear(); 42 | experienceRules.clear(); 43 | phaseRules.clear(); 44 | onPhaseChange(); 45 | readAllRules(); 46 | } 47 | 48 | public static void setRulePath(Path path) { 49 | RulesManager.path = path.toString(); 50 | } 51 | 52 | public static void readRules() { 53 | readAllRules(); 54 | } 55 | 56 | public static void onPhaseChange() { 57 | filteredRules = null; 58 | filteredSummonAidRules = null; 59 | filteredLootRules = null; 60 | filteredExperienceRuiles = null; 61 | } 62 | 63 | public static List getFilteredRules(World world) { 64 | if (filteredRules == null) { 65 | Set phases = DataStorage.getData(world).getPhases(); 66 | filteredRules = rules.stream().filter(r -> phases.containsAll(r.getPhases())).collect(Collectors.toList()); 67 | } 68 | return filteredRules; 69 | } 70 | 71 | public static List getFilteredSummonAidRules(World world) { 72 | if (filteredSummonAidRules == null) { 73 | Set phases = DataStorage.getData(world).getPhases(); 74 | filteredSummonAidRules = summonAidRules.stream().filter(r -> phases.containsAll(r.getPhases())).collect(Collectors.toList()); 75 | } 76 | return filteredSummonAidRules; 77 | } 78 | 79 | public static List getFilteredLootRules(World world) { 80 | if (filteredLootRules == null) { 81 | Set phases = DataStorage.getData(world).getPhases(); 82 | filteredLootRules = lootRules.stream().filter(r -> phases.containsAll(r.getPhases())).collect(Collectors.toList()); 83 | } 84 | return filteredLootRules; 85 | } 86 | 87 | public static List getFilteredExperienceRuiles(World world) { 88 | if (filteredExperienceRuiles == null) { 89 | Set phases = DataStorage.getData(world).getPhases(); 90 | filteredExperienceRuiles = experienceRules.stream().filter(r -> phases.containsAll(r.getPhases())).collect(Collectors.toList()); 91 | } 92 | return filteredExperienceRuiles; 93 | } 94 | 95 | private static boolean exists(String file) { 96 | File f = new File(file); 97 | return f.exists() && !f.isDirectory(); 98 | } 99 | 100 | public static boolean readCustomSpawn(String file) { 101 | System.out.println("file = " + file); 102 | if (!exists(file)) { 103 | return false; 104 | } 105 | rules.clear(); 106 | readRules(null, file, SpawnRule::parse, rules); 107 | return true; 108 | } 109 | 110 | public static boolean readCustomSummonAid(String file) { 111 | if (!exists(file)) { 112 | return false; 113 | } 114 | summonAidRules.clear(); 115 | readRules(null, file, SummonAidRule::parse, summonAidRules); 116 | return true; 117 | } 118 | 119 | public static boolean readCustomPotentialSpawn(String file) { 120 | if (!exists(file)) { 121 | return false; 122 | } 123 | potentialSpawnRules.clear(); 124 | readRules(null, file, PotentialSpawnRule::parse, potentialSpawnRules); 125 | return true; 126 | } 127 | 128 | public static boolean readCustomLoot(String file) { 129 | if (!exists(file)) { 130 | return false; 131 | } 132 | lootRules.clear(); 133 | readRules(null, file, LootRule::parse, lootRules); 134 | return true; 135 | } 136 | 137 | private static void readAllRules() { 138 | File directory = new File(path + File.separator + "incontrol"); 139 | if (!directory.exists()) { 140 | directory.mkdir(); 141 | } 142 | 143 | safeCall("spawn.json", () -> readRules(path, "spawn.json", SpawnRule::parse, rules)); 144 | safeCall("summonaid.json", () -> readRules(path, "summonaid.json", SummonAidRule::parse, summonAidRules)); 145 | safeCall("potentialspawn.json", () -> readRules(path, "potentialspawn.json", PotentialSpawnRule::parse, potentialSpawnRules)); 146 | safeCall("loot.json", () -> readRules(path, "loot.json", LootRule::parse, lootRules)); 147 | safeCall("experience.json", () -> readRules(path, "experience.json", ExperienceRule::parse, experienceRules)); 148 | safeCall("phases.json", () -> readRules(path, "phases.json", PhaseRule::parse, phaseRules)); 149 | } 150 | 151 | private static void safeCall(String name, Runnable code) { 152 | try { 153 | code.run(); 154 | } catch (Exception e) { 155 | ErrorHandler.error("JSON error in '" + name + "': check log for details (" + e.getMessage() + ")"); 156 | InControl.setup.getLogger().log(Level.ERROR, "Error parsing '" + name + "'", e); 157 | } 158 | } 159 | 160 | private static void readRules(String path, String filename, Function parser, List rules) { 161 | JsonElement element = getRootElement(path, filename); 162 | if (element == null) { 163 | return; 164 | } 165 | int i = 0; 166 | for (JsonElement entry : element.getAsJsonArray()) { 167 | T rule = parser.apply(entry); 168 | if (rule != null) { 169 | rules.add(rule); 170 | } else { 171 | InControl.setup.getLogger().log(Level.ERROR, "Rule " + i + " in " + filename + " is invalid, skipping!"); 172 | } 173 | i++; 174 | } 175 | } 176 | 177 | private static JsonElement getRootElement(String path, String filename) { 178 | return JSonTools.getRootElement(path, filename, InControl.setup.getLogger()); 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/rules/SummonEventGetter.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.rules; 2 | 3 | import mcjty.incontrol.tools.rules.RuleBase; 4 | import net.minecraft.entity.monster.ZombieEntity; 5 | 6 | public interface SummonEventGetter extends RuleBase.EventGetter { 7 | ZombieEntity getZombieHelper(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/rules/support/RuleKeys.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.rules.support; 2 | 3 | import mcjty.incontrol.tools.rules.CommonRuleKeys; 4 | import mcjty.incontrol.tools.typed.AttributeMap; 5 | import mcjty.incontrol.tools.typed.Key; 6 | import mcjty.incontrol.tools.typed.Type; 7 | 8 | public interface RuleKeys extends CommonRuleKeys { 9 | 10 | // Inputs 11 | Key MINCOUNT = Key.create(Type.JSON, "mincount"); 12 | Key MAXCOUNT = Key.create(Type.JSON, "maxcount"); 13 | Key DAYCOUNT = Key.create(Type.INTEGER, "daycount"); 14 | Key MINDAYCOUNT = Key.create(Type.INTEGER, "mindaycount"); 15 | Key MAXDAYCOUNT = Key.create(Type.INTEGER, "maxdaycount"); 16 | Key CANSPAWNHERE = Key.create(Type.BOOLEAN, "canspawnhere"); 17 | Key NOTCOLLIDING = Key.create(Type.BOOLEAN, "notcolliding"); 18 | Key PASSIVE = Key.create(Type.BOOLEAN, "passive"); 19 | Key HOSTILE = Key.create(Type.BOOLEAN, "hostile"); 20 | Key BABY = Key.create(Type.BOOLEAN, "baby"); 21 | Key MOB = Key.create(Type.STRING, "mob"); 22 | Key MOD = Key.create(Type.STRING, "mod"); 23 | 24 | Key SPAWNER = Key.create(Type.BOOLEAN, "spawner"); 25 | Key INCONTROL = Key.create(Type.BOOLEAN, "incontrol"); 26 | 27 | // Foor loot rules 28 | Key SOURCE = Key.create(Type.STRING, "source"); 29 | Key PLAYER = Key.create(Type.BOOLEAN, "player"); 30 | Key REALPLAYER = Key.create(Type.BOOLEAN, "realplayer"); 31 | Key FAKEPLAYER = Key.create(Type.BOOLEAN, "fakeplayer"); 32 | Key PROJECTILE = Key.create(Type.BOOLEAN, "projectile"); 33 | Key EXPLOSION = Key.create(Type.BOOLEAN, "explosion"); 34 | Key FIRE = Key.create(Type.BOOLEAN, "fire"); 35 | Key MAGIC = Key.create(Type.BOOLEAN, "magic"); 36 | 37 | Key ACTION_ITEMNBT = Key.create(Type.JSON, "nbt"); 38 | Key ACTION_ITEM = Key.create(Type.STRING, "item"); 39 | Key ACTION_ITEMCOUNT = Key.create(Type.STRING, "itemcount"); 40 | Key ACTION_REMOVEALL = Key.create(Type.BOOLEAN, "removeall"); 41 | 42 | Key ACTION_SETXP = Key.create(Type.INTEGER, "setxp"); 43 | Key ACTION_MULTXP = Key.create(Type.FLOAT, "multxp"); 44 | Key ACTION_ADDXP = Key.create(Type.FLOAT, "addxp"); 45 | 46 | // Mob spawn entry 47 | Key ACTION_MOBS = Key.create(Type.MAP, "mobs"); 48 | Key ACTION_REMOVE = Key.create(Type.JSON, "remove"); 49 | Key ACTION_REMOVE_MOBS = Key.create(Type.STRING, "remove"); 50 | Key MOB_NAME = Key.create(Type.STRING, "mob"); 51 | Key MOB_WEIGHT = Key.create(Type.INTEGER, "weight"); 52 | Key MOB_GROUPCOUNTMIN = Key.create(Type.INTEGER, "groupcountmin"); 53 | Key MOB_GROUPCOUNTMAX = Key.create(Type.INTEGER, "groupcountmax"); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/setup/ModSetup.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.setup; 2 | 3 | import mcjty.incontrol.ForgeEventHandlers; 4 | import mcjty.incontrol.InControl; 5 | import mcjty.incontrol.compat.EnigmaSupport; 6 | import mcjty.incontrol.compat.LostCitySupport; 7 | import mcjty.incontrol.rules.RuleCache; 8 | import mcjty.incontrol.rules.RulesManager; 9 | import mcjty.incontrol.spawner.SpawnerParser; 10 | import net.minecraftforge.common.MinecraftForge; 11 | import net.minecraftforge.fml.ModList; 12 | import net.minecraftforge.fml.loading.FMLPaths; 13 | import org.apache.logging.log4j.Level; 14 | import org.apache.logging.log4j.LogManager; 15 | import org.apache.logging.log4j.Logger; 16 | 17 | public class ModSetup { 18 | 19 | public static boolean lostcities = false; 20 | public static boolean gamestages = false; 21 | public static boolean sereneSeasons = false; 22 | public static boolean baubles = false; 23 | public static boolean enigma = false; 24 | 25 | private Logger logger; 26 | public RuleCache cache = new RuleCache(); 27 | 28 | public void init() { 29 | logger = LogManager.getLogger(InControl.MODID); 30 | setupModCompat(); 31 | 32 | MinecraftForge.EVENT_BUS.register(new ForgeEventHandlers()); 33 | RulesManager.setRulePath(FMLPaths.CONFIGDIR.get()); 34 | RulesManager.readRules(); 35 | SpawnerParser.setRulePath(FMLPaths.CONFIGDIR.get()); 36 | SpawnerParser.readRules("spawner.json"); 37 | } 38 | 39 | public Logger getLogger() { 40 | return logger; 41 | } 42 | 43 | private void setupModCompat() { 44 | lostcities = ModList.get().isLoaded("lostcities"); 45 | gamestages = ModList.get().isLoaded("gamestages"); 46 | sereneSeasons = ModList.get().isLoaded("sereneseasons"); 47 | baubles = ModList.get().isLoaded("baubles"); 48 | enigma = ModList.get().isLoaded("enigma"); 49 | 50 | if (ModSetup.lostcities) { 51 | LostCitySupport.register(); 52 | logger.log(Level.INFO, "Enabling support for Lost Cities"); 53 | } 54 | if (ModSetup.gamestages) { 55 | logger.log(Level.INFO, "Enabling support for Game Stages"); 56 | } 57 | if (ModSetup.sereneSeasons) { 58 | logger.log(Level.INFO, "Enabling support for Serene Seasons"); 59 | } 60 | if (ModSetup.baubles) { 61 | logger.log(Level.INFO, "Enabling support for Baubles"); 62 | } 63 | if (ModSetup.enigma) { 64 | EnigmaSupport.register(); 65 | logger.log(Level.INFO, "Enabling support for EnigmaScript"); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/spawner/SpawnerConditions.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.spawner; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonObject; 5 | import mcjty.incontrol.ErrorHandler; 6 | import net.minecraft.util.RegistryKey; 7 | import net.minecraft.util.ResourceLocation; 8 | import net.minecraft.util.registry.Registry; 9 | import net.minecraft.world.World; 10 | 11 | import java.util.*; 12 | 13 | public class SpawnerConditions { 14 | 15 | private final Set> dimensions; 16 | private final int mindist; 17 | private final int maxdist; 18 | private final int minheight; 19 | private final int maxheight; 20 | private final int mindaycount; 21 | private final int maxdaycount; 22 | private final boolean inLiquid; 23 | private final boolean inWater; 24 | private final boolean inLava; 25 | private final boolean inAir; 26 | private final boolean noRestrictions; 27 | private final int maxthis; 28 | private final int maxlocal; 29 | private final int maxtotal; 30 | private final int maxhostile; 31 | private final int maxpeaceful; 32 | private final int maxneutral; 33 | 34 | public static final SpawnerConditions DEFAULT = SpawnerConditions.create().build(); 35 | 36 | enum Cmd { 37 | DIMENSION, 38 | MINDIST, 39 | MAXDIST, 40 | MINDAYCOUNT, 41 | MAXDAYCOUNT, 42 | MINHEIGHT, 43 | MAXHEIGHT, 44 | INWATER, 45 | INLAVA, 46 | INLIQUID, 47 | INAIR, 48 | NORESTRICTIONS, 49 | MAXTHIS, 50 | MAXLOCAL, 51 | MAXTOTAL, 52 | MAXHOSTILE, 53 | MAXPEACEFUL, 54 | MAXNEUTRAL 55 | } 56 | 57 | private static final Map CONDITIONS = new HashMap<>(); 58 | static { 59 | for (Cmd cmd : Cmd.values()) { 60 | CONDITIONS.put(cmd.name().toLowerCase(), cmd); 61 | } 62 | } 63 | 64 | 65 | private SpawnerConditions(Builder builder) { 66 | dimensions = new HashSet<>(builder.dimensions); 67 | mindist = builder.mindist; 68 | maxdist = builder.maxdist; 69 | minheight = builder.minheight; 70 | maxheight = builder.maxheight; 71 | mindaycount = builder.mindaycount; 72 | maxdaycount = builder.maxdaycount; 73 | inLiquid = builder.inLiquid; 74 | inWater = builder.inWater; 75 | inLava = builder.inLava; 76 | inAir = builder.inAir; 77 | maxthis = builder.maxthis; 78 | maxlocal = builder.maxlocal; 79 | maxtotal = builder.maxtotal; 80 | maxhostile = builder.maxhostile; 81 | maxpeaceful = builder.maxpeaceful; 82 | maxneutral = builder.maxneutral; 83 | noRestrictions = builder.noRestrictions; 84 | 85 | validate(); 86 | } 87 | 88 | private void validate() { 89 | if (mindaycount < 0) { 90 | throw new IllegalStateException("Invalid negative minimum daycount!"); 91 | } 92 | if (maxdaycount < 0) { 93 | throw new IllegalStateException("Invalid negative maximum daycount!"); 94 | } 95 | if (mindist < 0) { 96 | throw new IllegalStateException("Invalid negative minimum distance!"); 97 | } 98 | if (maxdist < 0) { 99 | throw new IllegalStateException("Invalid negative maximum distance!"); 100 | } 101 | if (minheight < 0) { 102 | throw new IllegalStateException("Invalid negative minimum height!"); 103 | } 104 | if (maxheight < 0) { 105 | throw new IllegalStateException("Invalid negative maximum height!"); 106 | } 107 | if (mindist >= maxdist) { 108 | throw new IllegalStateException("Minimum distance must be smaller then maximum!"); 109 | } 110 | if (minheight >= maxheight) { 111 | throw new IllegalStateException("Minimum height must be smaller then maximum!"); 112 | } 113 | } 114 | 115 | public Set> getDimensions() { 116 | return dimensions; 117 | } 118 | 119 | public int getMindaycount() { 120 | return mindaycount; 121 | } 122 | 123 | public int getMaxdaycount() { 124 | return maxdaycount; 125 | } 126 | 127 | public int getMindist() { 128 | return mindist; 129 | } 130 | 131 | public int getMaxdist() { 132 | return maxdist; 133 | } 134 | 135 | public int getMinheight() { 136 | return minheight; 137 | } 138 | 139 | public int getMaxheight() { 140 | return maxheight; 141 | } 142 | 143 | public boolean isInLiquid() { 144 | return inLiquid; 145 | } 146 | 147 | public boolean isInWater() { 148 | return inWater; 149 | } 150 | 151 | public boolean isInLava() { 152 | return inLava; 153 | } 154 | 155 | public boolean isInAir() { 156 | return inAir; 157 | } 158 | 159 | public boolean isNoRestrictions() { 160 | return noRestrictions; 161 | } 162 | 163 | public int getMaxthis() { 164 | return maxthis; 165 | } 166 | 167 | public int getMaxlocal() { 168 | return maxlocal; 169 | } 170 | 171 | public int getMaxtotal() { 172 | return maxtotal; 173 | } 174 | 175 | public int getMaxhostile() { 176 | return maxhostile; 177 | } 178 | 179 | public int getMaxpeaceful() { 180 | return maxpeaceful; 181 | } 182 | 183 | public int getMaxneutral() { 184 | return maxneutral; 185 | } 186 | 187 | public static Builder create() { 188 | return new Builder(); 189 | } 190 | 191 | public static void parse(JsonObject object, Builder builder) { 192 | for (Map.Entry entry : object.entrySet()) { 193 | String attr = entry.getKey(); 194 | Cmd cmd = CONDITIONS.get(attr); 195 | if (cmd == null) { 196 | ErrorHandler.error("Invalid condition '" + attr + "' for spawner rule!"); 197 | return; 198 | } 199 | 200 | switch (cmd) { 201 | case DIMENSION: { 202 | JsonElement value = object.get(attr); 203 | if (value.isJsonArray()) { 204 | for (JsonElement element : value.getAsJsonArray()) { 205 | RegistryKey key = RegistryKey.create(Registry.DIMENSION_REGISTRY, new ResourceLocation(element.getAsString())); 206 | builder.dimensions(key); 207 | } 208 | } else { 209 | RegistryKey key = RegistryKey.create(Registry.DIMENSION_REGISTRY, new ResourceLocation(value.getAsString())); 210 | builder.dimensions(key); 211 | } 212 | break; 213 | } 214 | case MINDIST: { 215 | builder.distance(object.getAsJsonPrimitive("mindist").getAsInt(), builder.maxdist); 216 | break; 217 | } 218 | case MAXDIST: { 219 | builder.distance(builder.mindist, object.getAsJsonPrimitive("maxdist").getAsInt()); 220 | break; 221 | } 222 | case MINDAYCOUNT: { 223 | builder.daycount(object.getAsJsonPrimitive("mindaycount").getAsInt(), builder.maxdaycount); 224 | break; 225 | } 226 | case MAXDAYCOUNT: { 227 | builder.daycount(builder.mindaycount, object.getAsJsonPrimitive("maxdaycount").getAsInt()); 228 | break; 229 | } 230 | case MINHEIGHT: { 231 | builder.height(object.getAsJsonPrimitive("minheight").getAsInt(), builder.maxheight); 232 | break; 233 | } 234 | case MAXHEIGHT: { 235 | builder.height(builder.minheight, object.getAsJsonPrimitive("maxheight").getAsInt()); 236 | break; 237 | } 238 | case INWATER: { 239 | builder.inWater(object.getAsJsonPrimitive("inwater").getAsBoolean()); 240 | break; 241 | } 242 | case INLAVA: { 243 | builder.inLava(object.getAsJsonPrimitive("inlava").getAsBoolean()); 244 | break; 245 | } 246 | case INLIQUID: { 247 | builder.inLiquid(object.getAsJsonPrimitive("inliquid").getAsBoolean()); 248 | break; 249 | } 250 | case INAIR: { 251 | builder.inAir(object.getAsJsonPrimitive("inair").getAsBoolean()); 252 | break; 253 | } 254 | case NORESTRICTIONS: { 255 | builder.noRestrictions(object.getAsJsonPrimitive("norestrictions").getAsBoolean()); 256 | break; 257 | } 258 | case MAXTHIS: { 259 | builder.maxThis(object.getAsJsonPrimitive("maxthis").getAsInt()); 260 | break; 261 | } 262 | case MAXLOCAL: { 263 | builder.maxLocal(object.getAsJsonPrimitive("maxlocal").getAsInt()); 264 | break; 265 | } 266 | case MAXTOTAL: { 267 | builder.maxTotal(object.getAsJsonPrimitive("maxtotal").getAsInt()); 268 | break; 269 | } 270 | case MAXHOSTILE: { 271 | builder.maxHostile(object.getAsJsonPrimitive("maxhostile").getAsInt()); 272 | break; 273 | } 274 | case MAXPEACEFUL: { 275 | builder.maxPeaceful(object.getAsJsonPrimitive("maxpeaceful").getAsInt()); 276 | break; 277 | } 278 | case MAXNEUTRAL: { 279 | builder.maxNeutral(object.getAsJsonPrimitive("maxneutral").getAsInt()); 280 | break; 281 | } 282 | } 283 | } 284 | } 285 | 286 | public static class Builder { 287 | private final Set> dimensions = new HashSet<>(); 288 | 289 | private int mindist = 24; 290 | private int maxdist = 120; 291 | private int mindaycount = 0; 292 | private int maxdaycount = Integer.MAX_VALUE; 293 | private int minheight = 1; 294 | private int maxheight = 256; 295 | private boolean inLiquid = false; 296 | private boolean inWater = false; 297 | private boolean inLava = false; 298 | private boolean inAir = false; 299 | private boolean noRestrictions = false; 300 | 301 | private int maxthis = -1; 302 | private int maxlocal = -1; 303 | private int maxtotal = -1; 304 | private int maxhostile = -1; 305 | private int maxpeaceful = -1; 306 | private int maxneutral = -1; 307 | 308 | public Builder dimensions(RegistryKey... dimensions) { 309 | Collections.addAll(this.dimensions, dimensions); 310 | return this; 311 | } 312 | 313 | public Builder noRestrictions(boolean noRestrictions) { 314 | this.noRestrictions = noRestrictions; 315 | return this; 316 | } 317 | 318 | public Builder daycount(int min, int max) { 319 | this.mindaycount = min; 320 | this.maxdaycount = max; 321 | return this; 322 | } 323 | 324 | public Builder distance(int min, int max) { 325 | this.mindist = min; 326 | this.maxdist = max; 327 | return this; 328 | } 329 | 330 | public Builder height(int min, int max) { 331 | this.minheight = min; 332 | this.maxheight = max; 333 | return this; 334 | } 335 | 336 | public Builder inLiquid(boolean inLiquid) { 337 | this.inLiquid = inLiquid; 338 | return this; 339 | } 340 | 341 | public Builder inWater(boolean inWater) { 342 | this.inWater = inWater; 343 | return this; 344 | } 345 | 346 | public Builder inLava(boolean inLava) { 347 | this.inLava = inLava; 348 | return this; 349 | } 350 | 351 | public Builder inAir(boolean inAir) { 352 | this.inAir = inAir; 353 | return this; 354 | } 355 | 356 | public Builder maxThis(int maxThis) { 357 | this.maxthis = maxThis; 358 | return this; 359 | } 360 | 361 | public Builder maxLocal(int maxLocal) { 362 | this.maxlocal = maxLocal; 363 | return this; 364 | } 365 | 366 | public Builder maxTotal(int maxTotal) { 367 | this.maxtotal = maxTotal; 368 | return this; 369 | } 370 | 371 | public Builder maxHostile(int maxHostile) { 372 | this.maxhostile = maxHostile; 373 | return this; 374 | } 375 | 376 | public Builder maxPeaceful(int maxPeaceful) { 377 | this.maxpeaceful = maxPeaceful; 378 | return this; 379 | } 380 | 381 | public Builder maxNeutral(int maxNeutral) { 382 | this.maxneutral = maxNeutral; 383 | return this; 384 | } 385 | 386 | public SpawnerConditions build() { 387 | return new SpawnerConditions(this); 388 | } 389 | } 390 | } 391 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/spawner/SpawnerParser.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.spawner; 2 | 3 | import com.google.gson.JsonElement; 4 | import mcjty.incontrol.ErrorHandler; 5 | import mcjty.incontrol.InControl; 6 | import mcjty.incontrol.tools.varia.JSonTools; 7 | import org.apache.logging.log4j.Level; 8 | 9 | import java.nio.file.Path; 10 | 11 | public class SpawnerParser { 12 | 13 | private static String path; 14 | 15 | public static void readRules(String filename) { 16 | JsonElement element = JSonTools.getRootElement(path, filename, InControl.setup.getLogger()); 17 | if (element == null) { 18 | return; 19 | } 20 | for (JsonElement entry : element.getAsJsonArray()) { 21 | SpawnerRule.Builder builder = SpawnerRule.create(); 22 | try { 23 | SpawnerRule.parse(entry.getAsJsonObject(), builder); 24 | SpawnerSystem.addRule(builder.build()); 25 | } catch (Exception e) { 26 | ErrorHandler.error("JSON error in 'spawner.json': check log for details (" + e.getMessage() + ")"); 27 | InControl.setup.getLogger().log(Level.ERROR, "Error parsing 'spawner.json'", e); 28 | } 29 | } 30 | } 31 | 32 | public static void setRulePath(Path path) { 33 | SpawnerParser.path = path.toString(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/spawner/SpawnerRule.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.spawner; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonObject; 5 | import mcjty.incontrol.ErrorHandler; 6 | import mcjty.incontrol.InControl; 7 | import net.minecraft.entity.EntityClassification; 8 | import net.minecraft.entity.EntityType; 9 | import net.minecraft.util.ResourceLocation; 10 | import net.minecraftforge.registries.ForgeRegistries; 11 | 12 | import java.util.*; 13 | 14 | public class SpawnerRule { 15 | 16 | private final List> mobs = new ArrayList<>(); 17 | private final List weights = new ArrayList<>(); 18 | private final EntityClassification mobsFromBiome; 19 | 20 | private final float maxWeight; 21 | private final float persecond; 22 | private final int attempts; 23 | private final int minSpawn; 24 | private final int maxSpawn; 25 | private final Set phases; 26 | private final SpawnerConditions conditions; 27 | 28 | enum Cmd { 29 | MOB, 30 | WEIGHTS, 31 | MOBSFROMBIOME, 32 | PHASE, 33 | PERSECOND, 34 | ATTEMPTS, 35 | AMOUNT, 36 | CONDITIONS 37 | } 38 | 39 | private static final Map COMMANDS = new HashMap<>(); 40 | static { 41 | for (Cmd cmd : Cmd.values()) { 42 | COMMANDS.put(cmd.name().toLowerCase(), cmd); 43 | } 44 | } 45 | 46 | private SpawnerRule(Builder builder) { 47 | mobs.addAll(builder.mobs); 48 | weights.addAll(builder.weights); 49 | mobsFromBiome = builder.mobsFromBiome; 50 | 51 | phases = builder.phases; 52 | persecond = builder.persecond; 53 | attempts = builder.attempts; 54 | conditions = builder.conditions; 55 | minSpawn = builder.minSpawn; 56 | maxSpawn = builder.maxSpawn; 57 | float w = 0; 58 | for (Float weight : weights) { 59 | w += weight; 60 | } 61 | if (w <= 0) { 62 | w = mobs.size(); 63 | } 64 | maxWeight = w; 65 | 66 | } 67 | 68 | public List> getMobs() { 69 | return mobs; 70 | } 71 | 72 | public List getWeights() { 73 | return weights; 74 | } 75 | 76 | public EntityClassification getMobsFromBiome() { 77 | return mobsFromBiome; 78 | } 79 | 80 | public float getMaxWeight() { 81 | return maxWeight; 82 | } 83 | 84 | public Set getPhases() { 85 | return phases; 86 | } 87 | 88 | public float getPersecond() { 89 | return persecond; 90 | } 91 | 92 | public int getAttempts() { 93 | return attempts; 94 | } 95 | 96 | public int getMinSpawn() { 97 | return minSpawn; 98 | } 99 | 100 | public int getMaxSpawn() { 101 | return maxSpawn; 102 | } 103 | 104 | public SpawnerConditions getConditions() { 105 | return conditions; 106 | } 107 | 108 | public static Builder create() { 109 | return new Builder(); 110 | } 111 | 112 | public static void parse(JsonObject object, Builder builder) { 113 | for (Map.Entry pair : object.entrySet()) { 114 | String attr = pair.getKey(); 115 | Cmd cmd = COMMANDS.get(attr); 116 | if (cmd == null) { 117 | ErrorHandler.error("Invalid command '" + attr + "' for spawner rule!"); 118 | return; 119 | } 120 | 121 | switch (cmd) { 122 | case MOB: { 123 | JsonElement mob = object.get("mob"); 124 | if (mob.isJsonArray()) { 125 | for (JsonElement element : mob.getAsJsonArray()) { 126 | addMob(builder, element); 127 | } 128 | } else { 129 | addMob(builder, mob); 130 | } 131 | break; 132 | } 133 | case WEIGHTS: { 134 | JsonElement weights = object.get("weights"); 135 | if (weights.isJsonArray()) { 136 | for (JsonElement element : weights.getAsJsonArray()) { 137 | builder.weights(element.getAsFloat()); 138 | } 139 | } else { 140 | builder.weights(weights.getAsFloat()); 141 | } 142 | break; 143 | } 144 | case MOBSFROMBIOME: { 145 | if (!builder.mobs.isEmpty()) { 146 | InControl.setup.getLogger().error("'mobsfrombiome' cannot be combined with manual mobs!"); 147 | throw new RuntimeException("'mobsfrombiome' cannot be combined with manual mobs!"); 148 | } 149 | String name = object.get("mobsfrombiome").getAsString().toLowerCase(); 150 | EntityClassification classification = EntityClassification.byName(name); 151 | if (classification == null) { 152 | InControl.setup.getLogger().error("Unknown classification " + name + "!"); 153 | throw new RuntimeException("Unknown classification " + name + "!"); 154 | } 155 | builder.mobsFromBiome(classification); 156 | break; 157 | } 158 | case PHASE: { 159 | JsonElement phaseElement = object.get("phase"); 160 | if (phaseElement.isJsonArray()) { 161 | for (JsonElement element : phaseElement.getAsJsonArray()) { 162 | builder.phases(element.getAsString()); 163 | } 164 | } else { 165 | builder.phases(phaseElement.getAsString()); 166 | } 167 | break; 168 | } 169 | case PERSECOND: { 170 | builder.perSecond(object.getAsJsonPrimitive("persecond").getAsFloat()); 171 | break; 172 | } 173 | case ATTEMPTS: { 174 | builder.attempts(object.getAsJsonPrimitive("attempts").getAsInt()); 175 | break; 176 | } 177 | case AMOUNT: { 178 | JsonObject amount = object.getAsJsonObject("amount"); 179 | if (amount.has("minimum")) { 180 | builder.minSpawn(amount.getAsJsonPrimitive("minimum").getAsInt()); 181 | } 182 | if (amount.has("maximum")) { 183 | builder.maxSpawn(amount.getAsJsonPrimitive("maximum").getAsInt()); 184 | } 185 | break; 186 | } 187 | case CONDITIONS: { 188 | JsonObject conditions = object.getAsJsonObject("conditions"); 189 | SpawnerConditions.Builder conditionsBuilder = SpawnerConditions.create(); 190 | SpawnerConditions.parse(conditions, conditionsBuilder); 191 | builder.conditions(conditionsBuilder.build()); 192 | break; 193 | } 194 | } 195 | } 196 | } 197 | 198 | private static void addMob(Builder builder, JsonElement element) { 199 | EntityType value = ForgeRegistries.ENTITIES.getValue(new ResourceLocation(element.getAsString())); 200 | if (value == null) { 201 | InControl.setup.getLogger().error("Error finding entity " + element.getAsString() + "!"); 202 | throw new RuntimeException("Error finding entity " + element.getAsString() + "!"); 203 | } 204 | builder.mobs(value); 205 | } 206 | 207 | public static class Builder { 208 | private final List> mobs = new ArrayList<>(); 209 | private final List weights = new ArrayList<>(); 210 | private EntityClassification mobsFromBiome = null; 211 | 212 | private final Set phases = new HashSet<>(); 213 | private float persecond = 1.0f; 214 | private int attempts = 1; 215 | private int minSpawn = 1; 216 | private int maxSpawn = 1; 217 | private SpawnerConditions conditions = SpawnerConditions.DEFAULT; 218 | 219 | public Builder mobs(EntityType... mobs) { 220 | Collections.addAll(this.mobs, mobs); 221 | return this; 222 | } 223 | 224 | public Builder weights(Float... weights) { 225 | Collections.addAll(this.weights, weights); 226 | return this; 227 | } 228 | 229 | public Builder mobsFromBiome(EntityClassification mobsFromBiome) { 230 | this.mobsFromBiome = mobsFromBiome; 231 | return this; 232 | } 233 | 234 | public Builder phases(String... phases) { 235 | Collections.addAll(this.phases, phases); 236 | return this; 237 | } 238 | 239 | public Builder perSecond(float persecond) { 240 | this.persecond = persecond; 241 | return this; 242 | } 243 | 244 | public Builder attempts(int attempts) { 245 | this.attempts = attempts; 246 | return this; 247 | } 248 | 249 | public Builder minSpawn(int minSpawn) { 250 | this.minSpawn = minSpawn; 251 | return this; 252 | } 253 | 254 | public Builder maxSpawn(int maxSpawn) { 255 | this.maxSpawn = maxSpawn; 256 | return this; 257 | } 258 | 259 | public Builder conditions(SpawnerConditions conditions) { 260 | this.conditions = conditions; 261 | return this; 262 | } 263 | 264 | public SpawnerRule build() { 265 | return new SpawnerRule(this); 266 | } 267 | } 268 | 269 | } 270 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/cache/StructureCache.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.cache; 2 | 3 | import it.unimi.dsi.fastutil.longs.LongSet; 4 | import mcjty.incontrol.tools.varia.Tools; 5 | import net.minecraft.util.RegistryKey; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.util.math.ChunkPos; 8 | import net.minecraft.world.IWorld; 9 | import net.minecraft.world.World; 10 | import net.minecraft.world.chunk.ChunkStatus; 11 | import net.minecraft.world.chunk.IChunk; 12 | import net.minecraft.world.gen.feature.structure.Structure; 13 | import net.minecraft.world.server.ServerWorld; 14 | 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | /** 19 | * Remember where structures are 20 | */ 21 | public class StructureCache { 22 | 23 | public static final StructureCache CACHE = new StructureCache(); 24 | 25 | private final Map structureCache = new HashMap<>(); 26 | 27 | public void clean() { 28 | structureCache.clear(); 29 | } 30 | 31 | public boolean isInStructure(IWorld world, String structure, BlockPos pos) { 32 | RegistryKey dimension = Tools.getDimensionKey(world); 33 | ChunkPos cp = new ChunkPos(pos); 34 | long cplong = ChunkPos.asLong(cp.x, cp.z); 35 | StructureCacheEntry entry = new StructureCacheEntry(structure, dimension, cplong); 36 | if (structureCache.containsKey(entry)) { 37 | return structureCache.get(entry); 38 | } 39 | 40 | ServerWorld sw = Tools.getServerWorld(world); 41 | IChunk chunk = sw.getChunk(pos.getX() >> 4, pos.getZ() >> 4, ChunkStatus.STRUCTURE_REFERENCES, false); 42 | if (chunk == null) { 43 | return false; 44 | } 45 | Map, LongSet> references = chunk.getAllReferences(); 46 | for (Map.Entry, LongSet> e : references.entrySet()) { 47 | LongSet longs = e.getValue(); 48 | if (!longs.isEmpty()) { 49 | structureCache.put(new StructureCacheEntry(e.getKey().getRegistryName().toString(), dimension, cplong), true); 50 | } 51 | } 52 | 53 | if (structureCache.containsKey(entry)) { 54 | return true; 55 | } else { 56 | structureCache.put(entry, false); 57 | return false; 58 | } 59 | } 60 | 61 | // private static Set parseStructureData(MapGenStructureData data) { 62 | // Set chunks = new HashSet<>(); 63 | // CompoundNBT nbttagcompound = data.getTagCompound(); 64 | // 65 | // for (String s : nbttagcompound.getKeySet()) { 66 | // NBTBase nbtbase = nbttagcompound.getTag(s); 67 | // 68 | // if (nbtbase.getId() == 10) { 69 | // CompoundNBT nbttagcompound1 = (CompoundNBT) nbtbase; 70 | // 71 | // if (nbttagcompound1.hasKey("ChunkX") && nbttagcompound1.hasKey("ChunkZ")) { 72 | // int i = nbttagcompound1.getInteger("ChunkX"); 73 | // int j = nbttagcompound1.getInteger("ChunkZ"); 74 | // chunks.add(ChunkPos.asLong(i, j)); 75 | // } 76 | // } 77 | // } 78 | // return chunks; 79 | // } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/cache/StructureCacheEntry.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.cache; 2 | 3 | import net.minecraft.util.RegistryKey; 4 | import net.minecraft.world.World; 5 | 6 | import javax.annotation.Nonnull; 7 | 8 | public class StructureCacheEntry { 9 | @Nonnull private final String structure; 10 | private final RegistryKey dimension; 11 | private final long chunkpos; 12 | 13 | public StructureCacheEntry(@Nonnull String structure, RegistryKey dimension, long chunkpos) { 14 | this.structure = structure; 15 | this.dimension = dimension; 16 | this.chunkpos = chunkpos; 17 | } 18 | 19 | @Nonnull 20 | public String getStructure() { 21 | return structure; 22 | } 23 | 24 | public RegistryKey getDimension() { 25 | return dimension; 26 | } 27 | 28 | public long getChunkpos() { 29 | return chunkpos; 30 | } 31 | 32 | @Override 33 | public boolean equals(Object o) { 34 | if (this == o) return true; 35 | if (o == null || getClass() != o.getClass()) return false; 36 | 37 | StructureCacheEntry that = (StructureCacheEntry) o; 38 | 39 | if (dimension != that.dimension) return false; 40 | if (chunkpos != that.chunkpos) return false; 41 | if (!structure.equals(that.structure)) return false; 42 | 43 | return true; 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | int result = structure.hashCode(); 49 | result = 31 * result + dimension.hashCode(); 50 | result = 31 * result + (int) (chunkpos ^ (chunkpos >>> 32)); 51 | return result; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/rules/CommonRuleKeys.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.rules; 2 | 3 | import mcjty.incontrol.tools.typed.Key; 4 | import mcjty.incontrol.tools.typed.Type; 5 | import net.minecraft.util.RegistryKey; 6 | import net.minecraft.world.World; 7 | 8 | public interface CommonRuleKeys { 9 | 10 | Key ONJOIN = Key.create(Type.BOOLEAN, "onjoin"); 11 | Key PHASE = Key.create(Type.STRING, "phase"); 12 | 13 | // Inputs 14 | Key MINTIME = Key.create(Type.INTEGER, "mintime"); 15 | Key MAXTIME = Key.create(Type.INTEGER, "maxtime"); 16 | Key MINLIGHT = Key.create(Type.INTEGER, "minlight"); 17 | Key MAXLIGHT = Key.create(Type.INTEGER, "maxlight"); 18 | Key MINHEIGHT = Key.create(Type.INTEGER, "minheight"); 19 | Key MAXHEIGHT = Key.create(Type.INTEGER, "maxheight"); 20 | Key MINDIFFICULTY = Key.create(Type.FLOAT, "mindifficulty"); 21 | Key MAXDIFFICULTY = Key.create(Type.FLOAT, "maxdifficulty"); 22 | Key MINSPAWNDIST = Key.create(Type.FLOAT, "minspawndist"); 23 | Key MAXSPAWNDIST = Key.create(Type.FLOAT, "maxspawndist"); 24 | Key RANDOM = Key.create(Type.FLOAT, "random"); 25 | Key SEESKY = Key.create(Type.BOOLEAN, "seesky"); 26 | Key WEATHER = Key.create(Type.STRING, "weather"); 27 | Key CATEGORY = Key.create(Type.STRING, "category"); 28 | Key DIFFICULTY = Key.create(Type.STRING, "difficulty"); 29 | Key BLOCK = Key.create(Type.JSON, "block"); 30 | Key BLOCKOFFSET = Key.create(Type.JSON, "blockoffset"); 31 | Key BIOME = Key.create(Type.STRING, "biome"); 32 | Key BIOMETYPE = Key.create(Type.STRING, "biometype"); 33 | Key STRUCTURE = Key.create(Type.STRING, "structure"); 34 | Key> DIMENSION = Key.create(Type.DIMENSION_TYPE, "dimension"); 35 | Key DIMENSION_MOD = Key.create(Type.STRING, "dimensionmod"); 36 | 37 | Key HELMET = Key.create(Type.JSON, "helmet"); 38 | Key CHESTPLATE = Key.create(Type.JSON, "chestplate"); 39 | Key LEGGINGS = Key.create(Type.JSON, "leggings"); 40 | Key BOOTS = Key.create(Type.JSON, "boots"); 41 | Key HELDITEM = Key.create(Type.JSON, "helditem"); 42 | Key PLAYER_HELDITEM = Key.create(Type.JSON, "playerhelditem"); 43 | Key OFFHANDITEM = Key.create(Type.JSON, "offhanditem"); 44 | Key BOTHHANDSITEM = Key.create(Type.JSON, "bothhandsitem"); 45 | 46 | Key INCITY = Key.create(Type.BOOLEAN, "incity"); 47 | Key INBUILDING = Key.create(Type.BOOLEAN, "inbuilding"); 48 | Key INSTREET = Key.create(Type.BOOLEAN, "instreet"); 49 | Key INSPHERE = Key.create(Type.BOOLEAN, "insphere"); 50 | 51 | Key GAMESTAGE = Key.create(Type.STRING, "gamestage"); 52 | 53 | Key SUMMER = Key.create(Type.BOOLEAN, "summer"); 54 | Key WINTER = Key.create(Type.BOOLEAN, "winter"); 55 | Key SPRING = Key.create(Type.BOOLEAN, "spring"); 56 | Key AUTUMN = Key.create(Type.BOOLEAN, "autumn"); 57 | 58 | Key AMULET = Key.create(Type.JSON, "amulet"); 59 | Key RING = Key.create(Type.JSON, "ring"); 60 | Key BELT = Key.create(Type.JSON, "belt"); 61 | Key TRINKET = Key.create(Type.JSON, "trinket"); 62 | Key HEAD = Key.create(Type.JSON, "head"); 63 | Key BODY = Key.create(Type.JSON, "body"); 64 | Key CHARM = Key.create(Type.JSON, "charm"); 65 | 66 | Key STATE = Key.create(Type.STRING, "state"); 67 | Key PSTATE = Key.create(Type.STRING, "pstate"); 68 | 69 | // Outputs 70 | 71 | Key ACTION_COMMAND = Key.create(Type.STRING, "command"); 72 | Key ACTION_ADDSTAGE = Key.create(Type.STRING, "addstage"); 73 | Key ACTION_REMOVESTAGE = Key.create(Type.STRING, "removestage"); 74 | Key ACTION_RESULT = Key.create(Type.STRING, "result"); 75 | Key ACTION_CONTINUE = Key.create(Type.BOOLEAN, "continue"); 76 | 77 | Key ACTION_HEALTHSET = Key.create(Type.FLOAT, "healthset"); 78 | Key ACTION_HEALTHMULTIPLY = Key.create(Type.FLOAT, "healthmultiply"); 79 | Key ACTION_HEALTHADD = Key.create(Type.FLOAT, "healthadd"); 80 | Key ACTION_SPEEDSET = Key.create(Type.FLOAT, "speedset"); 81 | Key ACTION_SPEEDMULTIPLY = Key.create(Type.FLOAT, "speedmultiply"); 82 | Key ACTION_SPEEDADD = Key.create(Type.FLOAT, "speedadd"); 83 | Key ACTION_DAMAGESET = Key.create(Type.FLOAT, "damageset"); 84 | Key ACTION_DAMAGEMULTIPLY = Key.create(Type.FLOAT, "damagemultiply"); 85 | Key ACTION_DAMAGEADD = Key.create(Type.FLOAT, "damageadd"); 86 | Key ACTION_SIZEMULTIPLY = Key.create(Type.FLOAT, "sizemultiply"); 87 | Key ACTION_SIZEADD = Key.create(Type.FLOAT, "sizeadd"); 88 | 89 | Key ACTION_POTION = Key.create(Type.STRING, "potion"); 90 | Key ACTION_HELDITEM = Key.create(Type.JSON, "helditem"); 91 | Key ACTION_ARMORCHEST = Key.create(Type.JSON, "armorchest"); 92 | Key ACTION_ARMORHELMET = Key.create(Type.JSON, "armorhelmet"); 93 | Key ACTION_ARMORLEGS = Key.create(Type.JSON, "armorlegs"); 94 | Key ACTION_ARMORBOOTS = Key.create(Type.JSON, "armorboots"); 95 | Key ACTION_MOBNBT = Key.create(Type.JSON, "nbt"); 96 | Key ACTION_CUSTOMNAME = Key.create(Type.STRING, "customname"); 97 | Key ACTION_ANGRY = Key.create(Type.BOOLEAN, "angry"); 98 | Key ACTION_MESSAGE = Key.create(Type.STRING, "message"); 99 | Key ACTION_GIVE = Key.create(Type.JSON, "give"); 100 | Key ACTION_DROP = Key.create(Type.JSON, "drop"); 101 | Key ACTION_SETBLOCK = Key.create(Type.JSON, "setblock"); 102 | Key ACTION_SETHELDITEM = Key.create(Type.JSON, "sethelditem"); 103 | Key ACTION_SETHELDAMOUNT = Key.create(Type.STRING, "setheldamount"); 104 | Key ACTION_SETSTATE = Key.create(Type.STRING, "setstate"); 105 | Key ACTION_SETPSTATE = Key.create(Type.STRING, "setpstate"); 106 | 107 | Key ACTION_EXPLOSION = Key.create(Type.STRING, "explosion"); 108 | Key ACTION_FIRE = Key.create(Type.INTEGER, "fire"); 109 | Key ACTION_CLEAR = Key.create(Type.BOOLEAN, "clear"); 110 | Key ACTION_DAMAGE = Key.create(Type.STRING, "damage"); 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/rules/IEventQuery.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.rules; 2 | 3 | import net.minecraft.entity.Entity; 4 | import net.minecraft.entity.player.PlayerEntity; 5 | import net.minecraft.item.ItemStack; 6 | import net.minecraft.util.DamageSource; 7 | import net.minecraft.util.math.BlockPos; 8 | import net.minecraft.world.IWorld; 9 | 10 | public interface IEventQuery { 11 | 12 | IWorld getWorld(T o); 13 | 14 | /// Get the position directly from the event 15 | BlockPos getPos(T o); 16 | /// Get the position from the event corrected to correspond to a position more likely containing a valid block 17 | BlockPos getValidBlockPos(T o); 18 | 19 | int getY(T o); 20 | 21 | Entity getEntity(T o); 22 | 23 | DamageSource getSource(T o); 24 | 25 | Entity getAttacker(T o); 26 | 27 | PlayerEntity getPlayer(T o); 28 | 29 | /// Get the item that is being placed 30 | ItemStack getItem(T o); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/rules/IModRuleCompatibilityLayer.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.rules; 2 | 3 | import net.minecraft.entity.player.PlayerEntity; 4 | import net.minecraft.item.ItemStack; 5 | import net.minecraft.world.IWorld; 6 | import net.minecraft.world.biome.Biome; 7 | 8 | public interface IModRuleCompatibilityLayer { 9 | 10 | // -------------------- 11 | // Baubles 12 | // -------------------- 13 | boolean hasBaubles(); 14 | 15 | int[] getAmuletSlots(); 16 | 17 | int[] getBeltSlots(); 18 | 19 | int[] getBodySlots(); 20 | 21 | int[] getCharmSlots(); 22 | 23 | int[] getHeadSlots(); 24 | 25 | int[] getRingSlots(); 26 | 27 | int[] getTrinketSlots(); 28 | 29 | ItemStack getBaubleStack(PlayerEntity player, int slot); 30 | 31 | 32 | // -------------------- 33 | // Game Stages 34 | // -------------------- 35 | 36 | boolean hasGameStages(); 37 | 38 | boolean hasGameStage(PlayerEntity player, String stage); 39 | 40 | void addGameStage(PlayerEntity player, String stage); 41 | 42 | void removeGameStage(PlayerEntity player, String stage); 43 | 44 | // -------------------- 45 | // Lost Cities 46 | // -------------------- 47 | 48 | boolean hasLostCities(); 49 | 50 | boolean isCity(IEventQuery query, T event); 51 | 52 | boolean isStreet(IEventQuery query, T event); 53 | 54 | boolean inSphere(IEventQuery query, T event); 55 | 56 | boolean isBuilding(IEventQuery query, T event); 57 | 58 | // -------------------- 59 | // Serene Seasons 60 | // -------------------- 61 | 62 | boolean hasSereneSeasons(); 63 | 64 | boolean isSpring(IWorld world); 65 | 66 | boolean isSummer(IWorld world); 67 | 68 | boolean isWinter(IWorld world); 69 | 70 | boolean isAutumn(IWorld world); 71 | 72 | // -------------------- 73 | // EnigmaScript 74 | // -------------------- 75 | 76 | boolean hasEnigmaScript(); 77 | 78 | void setPlayerState(PlayerEntity player, String statename, String statevalue); 79 | 80 | String getPlayerState(PlayerEntity player, String statename); 81 | 82 | void setState(IWorld world, String statename, String statevalue); 83 | 84 | String getState(IWorld world, String statename); 85 | 86 | // -------------------- 87 | // Specific methods to avoid AT issues in McJtyTools 88 | // -------------------- 89 | String getBiomeName(Biome biome); 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/typed/Attribute.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.typed; 2 | 3 | public class Attribute { 4 | 5 | private final Key key; 6 | private final boolean multi; 7 | 8 | private Attribute(Key key, boolean multi) { 9 | this.key = key; 10 | this.multi = multi; 11 | } 12 | 13 | public static Attribute create(Key key) { 14 | return new Attribute(key, false); 15 | } 16 | 17 | public static Attribute createMulti(Key key) { 18 | return new Attribute(key, true); 19 | } 20 | 21 | public Key getKey() { 22 | return key; 23 | } 24 | 25 | public boolean isMulti() { 26 | return multi; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/typed/AttributeMap.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.typed; 2 | 3 | import javax.annotation.Nonnull; 4 | import javax.annotation.Nullable; 5 | import java.util.*; 6 | import java.util.function.BiConsumer; 7 | import java.util.function.Consumer; 8 | 9 | public class AttributeMap { 10 | 11 | private final Map, Object> values = new HashMap<>(); 12 | 13 | public boolean has(@Nonnull Key key) { 14 | return values.containsKey(key); 15 | } 16 | 17 | public void set(@Nonnull Key key, A value) { 18 | values.put(key, value); 19 | } 20 | 21 | public boolean isEmpty() { 22 | return values.isEmpty(); 23 | } 24 | 25 | public Set> getKeys() { 26 | return values.keySet(); 27 | } 28 | 29 | public void setNonnull(@Nonnull Key key, A value) { 30 | if (value != null) { 31 | values.put(key, value); 32 | } 33 | } 34 | 35 | public void consume(@Nonnull Key key, Consumer consumer) { 36 | if (has(key)) { 37 | consumer.accept(get(key)); 38 | values.remove(key); 39 | } 40 | } 41 | 42 | @Nullable 43 | public A consumeAndFetch(@Nonnull Key key) { 44 | return consumeAndFetch(key, null); 45 | } 46 | 47 | @Nullable 48 | public A consumeAndFetch(@Nonnull Key key, A def) { 49 | if (has(key)) { 50 | A value = get(key); 51 | values.remove(key); 52 | return value; 53 | } 54 | return def; 55 | } 56 | 57 | public void consumeAsList(@Nonnull Key key, Consumer> consumer) { 58 | if (has(key)) { 59 | consumer.accept(getList(key)); 60 | values.remove(key); 61 | } 62 | } 63 | 64 | public void consume2(@Nonnull Key key1, @Nonnull Key key2, BiConsumer consumer) { 65 | if (has(key1) || has(key2)) { 66 | consumer.accept(get(key1), get(key2)); 67 | values.remove(key1); 68 | values.remove(key2); 69 | } 70 | } 71 | 72 | public void consumeOrElse(@Nonnull Key key, Consumer consumer, Runnable elseRun) { 73 | if (has(key)) { 74 | consumer.accept(get(key)); 75 | values.remove(key); 76 | } else { 77 | elseRun.run(); 78 | } 79 | } 80 | 81 | public A get(@Nonnull Key key) { 82 | //noinspection unchecked 83 | return (A) values.get(key); 84 | } 85 | 86 | public Optional getOptional(@Nonnull Key key) { 87 | //noinspection unchecked 88 | return Optional.ofNullable((A) values.get(key)); 89 | } 90 | 91 | public void addList(@Nonnull Key key, A value) { 92 | if (!values.containsKey(key)) { 93 | values.put(key, new ArrayList<>()); 94 | } 95 | //noinspection unchecked 96 | List l = (List) values.get(key); 97 | l.add(value); 98 | } 99 | 100 | public void addListNonnull(@Nonnull Key key, A value) { 101 | if (value == null) { 102 | return; 103 | } 104 | if (!values.containsKey(key)) { 105 | values.put(key, new ArrayList<>()); 106 | } 107 | //noinspection unchecked 108 | List l = (List) values.get(key); 109 | l.add(value); 110 | } 111 | 112 | public List getList(@Nonnull Key key) { 113 | if (!values.containsKey(key)) { 114 | return Collections.emptyList(); 115 | } 116 | //noinspection unchecked 117 | return (List) values.get(key); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/typed/GenericAttributeMapFactory.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.typed; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonObject; 5 | import com.google.gson.JsonPrimitive; 6 | import mcjty.incontrol.ErrorHandler; 7 | import mcjty.incontrol.tools.varia.JSonTools; 8 | import net.minecraft.server.MinecraftServer; 9 | import net.minecraft.util.RegistryKey; 10 | import net.minecraft.util.ResourceLocation; 11 | import net.minecraft.util.registry.Registry; 12 | import net.minecraft.world.World; 13 | import net.minecraftforge.fml.server.ServerLifecycleHooks; 14 | import org.apache.commons.lang3.StringUtils; 15 | 16 | import javax.annotation.Nonnull; 17 | import java.util.ArrayList; 18 | import java.util.HashSet; 19 | import java.util.List; 20 | import java.util.Set; 21 | import java.util.function.Function; 22 | import java.util.stream.Collectors; 23 | 24 | public class GenericAttributeMapFactory { 25 | 26 | private final List attributes = new ArrayList<>(); 27 | 28 | public GenericAttributeMapFactory attribute(@Nonnull Attribute a) { 29 | attributes.add(a); 30 | return this; 31 | } 32 | 33 | private boolean validate(JsonObject object, String file) { 34 | Set validKeys = attributes.stream().map(a -> a.getKey().getName()).collect(Collectors.toSet()); 35 | Set errors = new HashSet<>(); 36 | object.entrySet().forEach(entry -> { 37 | String attr = entry.getKey(); 38 | if (!validKeys.contains(attr)) { 39 | errors.add(attr); 40 | } 41 | }); 42 | if (!errors.isEmpty()) { 43 | ErrorHandler.error("Invalid keywords for " + file + ": " + StringUtils.join(errors, ' ')); 44 | return false; 45 | } 46 | return true; 47 | } 48 | 49 | @Nonnull 50 | public AttributeMap parse(@Nonnull JsonElement element, String file) { 51 | JsonObject jsonObject = element.getAsJsonObject(); 52 | AttributeMap map = new AttributeMap(); 53 | 54 | if (!validate(jsonObject, file)) { 55 | return map; 56 | } 57 | 58 | for (Attribute attribute : attributes) { 59 | Key key = attribute.getKey(); 60 | Type type = key.getType(); 61 | 62 | if (attribute.isMulti()) { 63 | Function transformer; 64 | if (type == Type.INTEGER) { 65 | transformer = JsonElement::getAsInt; 66 | } else if (type == Type.FLOAT) { 67 | transformer = JsonElement::getAsFloat; 68 | } else if (type == Type.BOOLEAN) { 69 | transformer = JsonElement::getAsBoolean; 70 | } else if (type == Type.STRING) { 71 | transformer = JsonElement::getAsString; 72 | } else if (type == Type.JSON) { 73 | transformer = JsonElement::toString; 74 | } else if (type == Type.DIMENSION_TYPE) { 75 | transformer = jsonElement -> { 76 | RegistryKey worldkey = RegistryKey.create(Registry.DIMENSION_REGISTRY, new ResourceLocation(jsonElement.getAsString())); 77 | MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); 78 | if (server != null) { 79 | if (!server.levelKeys().contains(worldkey)) { 80 | ErrorHandler.error("Dimension '" + jsonElement.getAsString() + "' not found!"); 81 | } 82 | } 83 | return worldkey; 84 | }; 85 | } else { 86 | transformer = e -> "INVALID"; 87 | } 88 | 89 | JSonTools.getElement(jsonObject, key.getName()) 90 | .ifPresent(e -> { 91 | JSonTools.asArrayOrSingle(e) 92 | .map(transformer) 93 | .forEach(s -> { 94 | map.addListNonnull(key, s); 95 | }); 96 | }); 97 | } else { 98 | if (type == Type.INTEGER) { 99 | map.setNonnull(key, JSonTools.parseInt(jsonObject, key.getName())); 100 | } else if (type == Type.FLOAT) { 101 | map.setNonnull(key, JSonTools.parseFloat(jsonObject, key.getName())); 102 | } else if (type == Type.BOOLEAN) { 103 | map.setNonnull(key, JSonTools.parseBool(jsonObject, key.getName())); 104 | } else if (type == Type.STRING) { 105 | if (jsonObject.has(key.getName())) { 106 | map.setNonnull(key, jsonObject.get(key.getName()).getAsString()); 107 | } 108 | } else if (type == Type.DIMENSION_TYPE) { 109 | if (jsonObject.has(key.getName())) { 110 | JsonElement jsonElement = jsonObject.get(key.getName()); 111 | map.setNonnull(key, RegistryKey.create(Registry.DIMENSION_REGISTRY, new ResourceLocation(jsonElement.getAsString()))); 112 | } 113 | } else if (type == Type.JSON) { 114 | if (jsonObject.has(key.getName())) { 115 | JsonElement el = jsonObject.get(key.getName()); 116 | if (el.isJsonObject()) { 117 | JsonObject obj = el.getAsJsonObject(); 118 | map.setNonnull(key, obj.toString()); 119 | } else { 120 | if (el.isJsonPrimitive()) { 121 | JsonPrimitive prim = el.getAsJsonPrimitive(); 122 | if (prim.isString()) { 123 | map.setNonnull(key, prim.getAsString()); 124 | } else if (prim.isNumber()) { 125 | map.setNonnull(key, "" + prim.getAsInt()); 126 | } else { 127 | throw new RuntimeException("Bad type for key '" + key.getName() + "'!"); 128 | } 129 | } 130 | } 131 | } 132 | } 133 | } 134 | } 135 | 136 | return map; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/typed/Key.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.typed; 2 | 3 | 4 | import javax.annotation.Nonnull; 5 | 6 | public class Key { 7 | 8 | @Nonnull private final Type type; 9 | @Nonnull private final String name; 10 | 11 | Key(@Nonnull final Type type, @Nonnull final String name) { 12 | this.type = type; 13 | this.name = name; 14 | } 15 | 16 | @Nonnull 17 | public static Key create(@Nonnull final Type type, 18 | @Nonnull final String code) { 19 | return new Key(type, code); 20 | } 21 | 22 | @Nonnull 23 | public Type getType() { 24 | return type; 25 | } 26 | 27 | @Nonnull 28 | public String getName() { 29 | return name; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return "Key(" + name + ')'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/typed/Type.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.typed; 2 | 3 | 4 | import net.minecraft.util.RegistryKey; 5 | import net.minecraft.world.World; 6 | 7 | import javax.annotation.Nonnull; 8 | import java.util.List; 9 | 10 | /** 11 | * A Type object represents a given type. 12 | */ 13 | public final class Type { 14 | 15 | // Root 16 | public static final Type OBJECT = new Type(Object.class); 17 | 18 | // Basic 19 | public static final Type INTEGER = create(Integer.class); 20 | public static final Type DOUBLE = create(Double.class); 21 | public static final Type FLOAT = create(Float.class); 22 | public static final Type LONG = create(Long.class); 23 | public static final Type STRING = create(String.class); 24 | public static final Type BOOLEAN = create(Boolean.class); 25 | public static final Type JSON = create(String.class); 26 | public static final Type> DIMENSION_TYPE = create(RegistryKey.class); 27 | 28 | // Map 29 | public static final Type MAP = create(AttributeMap.class); 30 | 31 | @Nonnull private final Class type; 32 | 33 | private Type(@Nonnull final Class type) { 34 | this.type = type; 35 | } 36 | 37 | @Nonnull 38 | public static Type create(@Nonnull final Class type) { 39 | return new Type((Class) type); 40 | } 41 | 42 | @Nonnull 43 | public Class getType() { 44 | return type; 45 | } 46 | 47 | @Nonnull 48 | public List convert(@Nonnull List list) { 49 | return (List) list; 50 | } 51 | 52 | public V convert(Object o) { 53 | return (V) o; 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return "Type(" + getType().getSimpleName() + ')'; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/varia/Box.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.varia; 2 | 3 | import net.minecraft.util.math.BlockPos; 4 | 5 | import java.util.Random; 6 | 7 | public class Box { 8 | 9 | private final int minX; 10 | private final int minY; 11 | private final int minZ; 12 | private final int maxX; 13 | private final int maxY; 14 | private final int maxZ; 15 | 16 | private Box(Builder builder) { 17 | this.minX = builder.minX; 18 | this.minY = builder.minY; 19 | this.minZ = builder.minZ; 20 | this.maxX = builder.maxX; 21 | this.maxY = builder.maxY; 22 | this.maxZ = builder.maxZ; 23 | } 24 | 25 | public int getMinX() { 26 | return minX; 27 | } 28 | 29 | public int getMinY() { 30 | return minY; 31 | } 32 | 33 | public int getMinZ() { 34 | return minZ; 35 | } 36 | 37 | public int getMaxX() { 38 | return maxX; 39 | } 40 | 41 | public int getMaxY() { 42 | return maxY; 43 | } 44 | 45 | public int getMaxZ() { 46 | return maxZ; 47 | } 48 | 49 | public boolean isValid() { 50 | if (minX >= maxX) { 51 | return false; 52 | } 53 | if (minY >= maxY) { 54 | return false; 55 | } 56 | if (minZ >= maxZ) { 57 | return false; 58 | } 59 | return true; 60 | } 61 | 62 | public boolean in(BlockPos pos) { 63 | if (pos.getX() < minX || pos.getX() > maxX) { 64 | return false; 65 | } 66 | if (pos.getY() < minY || pos.getY() > maxY) { 67 | return false; 68 | } 69 | if (pos.getZ() < minZ || pos.getZ() > maxZ) { 70 | return false; 71 | } 72 | return true; 73 | } 74 | 75 | public BlockPos randomPos(Random random) { 76 | return new BlockPos( 77 | minX + random.nextInt(maxX - minX+1), 78 | minY + random.nextInt(maxY - minY+1), 79 | minZ + random.nextInt(maxZ - minZ+1)); 80 | } 81 | 82 | public static Builder create() { 83 | return new Builder(); 84 | } 85 | 86 | public static class Builder { 87 | 88 | private int minX; 89 | private int minY; 90 | private int minZ; 91 | private int maxX; 92 | private int maxY; 93 | private int maxZ; 94 | 95 | public Builder minimum(BlockPos pos) { 96 | minX = pos.getX(); 97 | minY = pos.getY(); 98 | minZ = pos.getZ(); 99 | return this; 100 | } 101 | 102 | public Builder maximum(BlockPos pos) { 103 | maxX = pos.getX(); 104 | maxY = pos.getY(); 105 | maxZ = pos.getZ(); 106 | return this; 107 | } 108 | 109 | public Builder center(BlockPos center, int radiusX, int radiusY, int radiusZ) { 110 | minX = center.getX() - radiusX; 111 | minY = center.getY() - radiusY; 112 | minZ = center.getZ() - radiusZ; 113 | maxX = center.getX() + radiusX; 114 | maxY = center.getY() + radiusY; 115 | maxZ = center.getZ() + radiusZ; 116 | return this; 117 | } 118 | 119 | public Builder clampY(int minimumY, int maximumY) { 120 | minY = Math.max(minY, minimumY); 121 | maxY = Math.min(maxY, maximumY); 122 | return this; 123 | } 124 | 125 | public Box build() { 126 | return new Box(this); 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/varia/DummyCommandSender.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.varia; 2 | 3 | public class DummyCommandSender {} /* @todo 1.15 implements ICommandSender { 4 | 5 | private final World world; 6 | private final PlayerEntity player; 7 | 8 | public DummyCommandSender(World world, PlayerEntity player) { 9 | this.world = world; 10 | this.player = player; 11 | } 12 | 13 | @Override 14 | public String getName() { 15 | return "dummy"; 16 | } 17 | 18 | @Override 19 | public ITextComponent getDisplayName() { 20 | return new StringTextComponent("dummy"); 21 | } 22 | 23 | @Override 24 | public void sendMessage(ITextComponent component) { 25 | System.out.println(component.getFormattedText()); 26 | } 27 | 28 | @Override 29 | public boolean canUseCommand(int permLevel, String commandName) { 30 | return true; 31 | } 32 | 33 | @Override 34 | public BlockPos getPosition() { 35 | return new BlockPos(0, 0, 0); 36 | } 37 | 38 | @Override 39 | public Vec3d getPositionVector() { 40 | return new Vec3d(0, 0, 0); 41 | } 42 | 43 | @Override 44 | public World getEntityWorld() { 45 | return world; 46 | } 47 | 48 | @Nullable 49 | @Override 50 | public Entity getCommandSenderEntity() { 51 | return player; 52 | } 53 | 54 | @Override 55 | public boolean sendCommandFeedback() { 56 | return false; 57 | } 58 | 59 | @Override 60 | public void setCommandStat(CommandResultStats.Type type, int amount) { 61 | 62 | } 63 | 64 | @Nullable 65 | @Override 66 | public MinecraftServer getServer() { 67 | return world.getMinecraftServer(); 68 | } 69 | } 70 | */ -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/varia/JSonTools.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.varia; 2 | 3 | import com.google.gson.*; 4 | import org.apache.commons.lang3.tuple.Pair; 5 | import org.apache.logging.log4j.Level; 6 | import org.apache.logging.log4j.Logger; 7 | 8 | import javax.annotation.Nullable; 9 | import java.io.*; 10 | import java.util.Collection; 11 | import java.util.Map; 12 | import java.util.Optional; 13 | import java.util.stream.Stream; 14 | 15 | public class JSonTools { 16 | 17 | public static JsonElement getRootElement(String path, String filename, Logger logger) { 18 | File file; 19 | if (path == null) { 20 | file = new File(filename); 21 | } else { 22 | file = new File(path + File.separator + "incontrol", filename); 23 | } 24 | if (!file.exists()) { 25 | // Create an empty rule file 26 | makeEmptyRuleFile(file, logger); 27 | return null; 28 | } 29 | 30 | logger.log(Level.INFO, "Reading rules from " + filename); 31 | InputStream inputstream = null; 32 | try { 33 | inputstream = new FileInputStream(file); 34 | } catch (FileNotFoundException e) { 35 | logger.log(Level.ERROR, "Error reading " + filename + "!"); 36 | return null; 37 | } 38 | 39 | BufferedReader br; 40 | try { 41 | br = new BufferedReader(new InputStreamReader(inputstream, "UTF-8")); 42 | } catch (UnsupportedEncodingException e) { 43 | logger.log(Level.ERROR, "Error reading " + filename + "!"); 44 | return null; 45 | } 46 | 47 | JsonParser parser = new JsonParser(); 48 | JsonElement element = parser.parse(br); 49 | 50 | return element; 51 | } 52 | 53 | private static void makeEmptyRuleFile(File file, Logger logger) { 54 | PrintWriter writer; 55 | try { 56 | writer = new PrintWriter(file); 57 | } catch (FileNotFoundException e) { 58 | logger.log(Level.ERROR, "Error writing " + file.getName() + "!"); 59 | return; 60 | } 61 | JsonArray array = new JsonArray(); 62 | Gson gson = new GsonBuilder().setPrettyPrinting().create(); 63 | writer.print(gson.toJson(array)); 64 | writer.close(); 65 | } 66 | 67 | 68 | public static Optional getElement(JsonObject element, String name) { 69 | JsonElement el = element.get(name); 70 | if (el != null) { 71 | return Optional.of(el); 72 | } else { 73 | return Optional.empty(); 74 | } 75 | } 76 | 77 | @Nullable 78 | public static Float parseFloat(JsonObject jsonObject, String name) { 79 | if (jsonObject.has(name)) { 80 | return jsonObject.get(name).getAsFloat(); 81 | } else { 82 | return null; 83 | } 84 | } 85 | 86 | @Nullable 87 | public static Integer parseInt(JsonObject jsonObject, String name) { 88 | if (jsonObject.has(name)) { 89 | return jsonObject.get(name).getAsInt(); 90 | } else { 91 | return null; 92 | } 93 | } 94 | 95 | @Nullable 96 | public static Boolean parseBool(JsonObject jsonObject, String name) { 97 | if (jsonObject.has(name)) { 98 | return jsonObject.get(name).getAsBoolean(); 99 | } else { 100 | return null; 101 | } 102 | } 103 | 104 | public static Stream> asPairs(JsonElement element) { 105 | Stream.Builder> builder = Stream.builder(); 106 | for (Map.Entry entry : element.getAsJsonObject().entrySet()) { 107 | builder.add(Pair.of(entry.getKey(), entry.getValue().getAsString())); 108 | } 109 | return builder.build(); 110 | } 111 | 112 | public static Stream asArrayOrSingle(JsonElement element) { 113 | if (element.isJsonArray()) { 114 | Stream.Builder builder = Stream.builder(); 115 | for (JsonElement el : element.getAsJsonArray()) { 116 | builder.add(el); 117 | } 118 | return builder.build(); 119 | } else { 120 | return Stream.of(element); 121 | } 122 | } 123 | 124 | public static void addPairs(JsonObject parent, String name, Map pairs) { 125 | if (pairs != null) { 126 | JsonObject object = new JsonObject(); 127 | for (Map.Entry entry : pairs.entrySet()) { 128 | object.add(entry.getKey(), new JsonPrimitive(entry.getValue())); 129 | } 130 | parent.add(name, object); 131 | } 132 | } 133 | 134 | public static void addArrayOrSingle(JsonObject parent, String name, Collection strings) { 135 | if (strings != null) { 136 | if (strings.size() == 1) { 137 | parent.add(name, new JsonPrimitive(strings.iterator().next())); 138 | } else { 139 | JsonArray array = new JsonArray(); 140 | for (String value : strings) { 141 | array.add(new JsonPrimitive(value)); 142 | } 143 | parent.add(name, array); 144 | } 145 | } 146 | } 147 | 148 | public static void addIntArrayOrSingle(JsonObject parent, String name, Collection integers) { 149 | if (integers != null) { 150 | if (integers.size() == 1) { 151 | parent.add(name, new JsonPrimitive(integers.iterator().next())); 152 | } else { 153 | JsonArray array = new JsonArray(); 154 | for (Integer value : integers) { 155 | array.add(new JsonPrimitive(value)); 156 | } 157 | parent.add(name, array); 158 | } 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/varia/LookAtTools.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.varia; 2 | 3 | import net.minecraft.entity.player.PlayerEntity; 4 | import net.minecraft.entity.player.ServerPlayerEntity; 5 | import net.minecraft.util.math.MathHelper; 6 | import net.minecraft.util.math.RayTraceContext; 7 | import net.minecraft.util.math.RayTraceResult; 8 | import net.minecraft.util.math.vector.Vector3d; 9 | import net.minecraft.world.IWorld; 10 | 11 | public class LookAtTools { 12 | 13 | public static RayTraceResult getMovingObjectPositionFromPlayer(IWorld worldIn, PlayerEntity playerIn, boolean useLiquids) { 14 | float pitch = playerIn.xRot; 15 | float yaw = playerIn.yRot; 16 | Vector3d vec3 = getPlayerEyes(playerIn); 17 | float f2 = MathHelper.cos(-yaw * 0.017453292F - (float) Math.PI); 18 | float f3 = MathHelper.sin(-yaw * 0.017453292F - (float)Math.PI); 19 | float f4 = -MathHelper.cos(-pitch * 0.017453292F); 20 | float f5 = MathHelper.sin(-pitch * 0.017453292F); 21 | float f6 = f3 * f4; 22 | float f7 = f2 * f4; 23 | double reach = 5.0D; 24 | if (playerIn instanceof ServerPlayerEntity) { 25 | // @todo 1.15? Where is reach? 26 | // reach = ((ServerPlayerEntity)playerIn).interactionManager.getBlockReachDistance(); 27 | } 28 | Vector3d vec31 = vec3.add(f6 * reach, f5 * reach, f7 * reach); 29 | RayTraceContext context = new RayTraceContext(vec3, vec31, RayTraceContext.BlockMode.COLLIDER, useLiquids ? RayTraceContext.FluidMode.ANY : RayTraceContext.FluidMode.NONE, playerIn); 30 | return worldIn.clip(context); 31 | } 32 | 33 | private static Vector3d getPlayerEyes(PlayerEntity playerIn) { 34 | double x = playerIn.getX(); 35 | double y = playerIn.getY() + playerIn.getEyeHeight(); 36 | double z = playerIn.getZ(); 37 | return new Vector3d(x, y, z); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/mcjty/incontrol/tools/varia/Tools.java: -------------------------------------------------------------------------------- 1 | package mcjty.incontrol.tools.varia; 2 | 3 | import com.google.gson.JsonObject; 4 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 5 | import mcjty.incontrol.ErrorHandler; 6 | import net.minecraft.item.Item; 7 | import net.minecraft.item.ItemStack; 8 | import net.minecraft.nbt.CompoundNBT; 9 | import net.minecraft.nbt.JsonToNBT; 10 | import net.minecraft.util.RegistryKey; 11 | import net.minecraft.util.ResourceLocation; 12 | import net.minecraft.util.registry.DynamicRegistries; 13 | import net.minecraft.util.registry.MutableRegistry; 14 | import net.minecraft.util.registry.Registry; 15 | import net.minecraft.world.IServerWorld; 16 | import net.minecraft.world.IWorld; 17 | import net.minecraft.world.World; 18 | import net.minecraft.world.biome.Biome; 19 | import net.minecraft.world.gen.WorldGenRegion; 20 | import net.minecraft.world.server.ServerWorld; 21 | import net.minecraftforge.registries.ForgeRegistries; 22 | import org.apache.commons.lang3.StringUtils; 23 | import org.apache.commons.lang3.tuple.Pair; 24 | import org.apache.logging.log4j.Logger; 25 | 26 | import javax.annotation.Nonnull; 27 | import javax.annotation.Nullable; 28 | import java.util.Optional; 29 | 30 | public class Tools { 31 | 32 | public static RegistryKey getDimensionKey(IWorld world) { 33 | if (world instanceof World) { 34 | return ((World) world).dimension(); 35 | } else if (world instanceof IServerWorld) { 36 | return ((IServerWorld) world).getLevel().dimension(); 37 | } else { 38 | throw new IllegalStateException("Not possible to get a dimension key here!"); 39 | } 40 | } 41 | 42 | /// Returns empty string on invalid biomes 43 | @Nonnull 44 | public static String getBiomeId(Biome biome) { 45 | if (biome.getRegistryName() == null) { 46 | Optional> biomeRegistry = DynamicRegistries.builtin().registry(Registry.BIOME_REGISTRY); 47 | return biomeRegistry.map(r -> r.getResourceKey(biome).map(key -> key.location().toString()).orElse("")).orElse(""); 48 | } else { 49 | return biome.getRegistryName().toString(); 50 | } 51 | } 52 | 53 | public static Pair parseStackWithFactor(String name, Logger logger) { 54 | int i = 0; 55 | while (i < name.length() && (Character.isDigit(name.charAt(i)) || name.charAt(i) == '.')) { 56 | i++; 57 | } 58 | if (i < name.length() && name.charAt(i) == '=') { 59 | String f = name.substring(0, i); 60 | float v; 61 | try { 62 | v = Float.parseFloat(f); 63 | } catch (NumberFormatException e) { 64 | v = 1.0f; 65 | } 66 | return Pair.of(v, parseStack(name.substring(i+1), logger)); 67 | } 68 | 69 | return Pair.of(1.0f, parseStack(name, logger)); 70 | } 71 | 72 | public static Pair parseStackWithFactor(JsonObject obj, Logger logger) { 73 | float factor = 1.0f; 74 | if (obj.has("factor")) { 75 | factor = obj.get("factor").getAsFloat(); 76 | } 77 | ItemStack stack = parseStack(obj, logger); 78 | if (stack == null) { 79 | return null; 80 | } 81 | return Pair.of(factor, stack); 82 | } 83 | 84 | @Nonnull 85 | public static ItemStack parseStack(String name, Logger logger) { 86 | if (name.contains("/")) { 87 | String[] split = StringUtils.split(name, "/"); 88 | ItemStack stack = parseStackNoNBT(split[0], logger); 89 | if (stack.isEmpty()) { 90 | return stack; 91 | } 92 | CompoundNBT nbt; 93 | try { 94 | nbt = JsonToNBT.parseTag(split[1]); 95 | } catch (CommandSyntaxException e) { 96 | ErrorHandler.error("Error parsing NBT in '" + name + "'!"); 97 | return ItemStack.EMPTY; 98 | } 99 | stack.setTag(nbt); 100 | return stack; 101 | } else { 102 | return parseStackNoNBT(name, logger); 103 | } 104 | } 105 | 106 | @Nullable 107 | public static ItemStack parseStack(JsonObject obj, Logger logger) { 108 | if (obj.has("empty")) { 109 | return ItemStack.EMPTY; 110 | } 111 | String name = obj.get("item").getAsString(); 112 | Item item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(name)); 113 | if (item == null) { 114 | ErrorHandler.error("Unknown item '" + name + "'!"); 115 | return null; 116 | } 117 | ItemStack stack = new ItemStack(item); 118 | if (obj.has("damage")) { 119 | stack.setDamageValue(obj.get("damage").getAsInt()); 120 | } 121 | if (obj.has("count")) { 122 | stack.setCount(obj.get("count").getAsInt()); 123 | } 124 | if (obj.has("nbt")) { 125 | String nbt = obj.get("nbt").toString(); 126 | CompoundNBT tag = null; 127 | try { 128 | tag = JsonToNBT.parseTag(nbt); 129 | } catch (CommandSyntaxException e) { 130 | ErrorHandler.error("Error parsing json '" + nbt + "'!"); 131 | return ItemStack.EMPTY; 132 | } 133 | stack.setTag(tag); 134 | } 135 | return stack; 136 | } 137 | 138 | private static ItemStack parseStackNoNBT(String name, Logger logger) { 139 | if (name.contains("@")) { 140 | String[] split = StringUtils.split(name, "@"); 141 | Item item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(split[0])); 142 | if (item == null) { 143 | return ItemStack.EMPTY; 144 | } 145 | int meta = 0; 146 | try { 147 | meta = Integer.parseInt(split[1]); 148 | } catch (NumberFormatException e) { 149 | ErrorHandler.error("Unknown item '" + name + "'!"); 150 | return ItemStack.EMPTY; 151 | } 152 | // @todo 1.15 Meta? Support properties? 153 | return new ItemStack(item, 1); 154 | } else { 155 | Item item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(name)); 156 | if (item == null) { 157 | return ItemStack.EMPTY; 158 | } 159 | return new ItemStack(item); 160 | } 161 | } 162 | 163 | 164 | public static ServerWorld getServerWorld(IWorld world) { 165 | ServerWorld sw; 166 | if (world instanceof ServerWorld) { 167 | sw = (ServerWorld) world; 168 | } else if (world instanceof IServerWorld) { 169 | sw = ((IServerWorld) world).getLevel(); 170 | } else { 171 | throw new IllegalStateException("No world found!"); 172 | } 173 | return sw; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | modLoader="javafml" 2 | loaderVersion="[33,)" 3 | license="MIT License https://github.com/McJtyMods/FXControl/blob/1.16/LICENCE" 4 | issueTrackerURL="http://github.com/McJtyMods/InControl/issues" 5 | displayURL="http://github.com/McJtyMods/InControl/" 6 | #logoFile="examplemod.png" #optional 7 | #credits="Thanks for this example mod goes to Java" #optional 8 | authors="McJty" 9 | 10 | [[mods]] 11 | modId="incontrol" 12 | version="${file.jarVersion}" 13 | displayName="InControl" 14 | #updateJSONURL="http://myurl.me/" #optional 15 | description=''' 16 | Be in control of spawns 17 | ''' 18 | [[dependencies.incontrol]] 19 | modId="forge" 20 | mandatory=true 21 | versionRange="[33,)" 22 | ordering="NONE" 23 | side="BOTH" 24 | -------------------------------------------------------------------------------- /src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "pack_format": 4, 4 | "description": "Resources used for InControl" 5 | } 6 | } 7 | --------------------------------------------------------------------------------