├── .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