forked from DevotedMC/SimpleAdminHacks
-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathGameTuning.java
More file actions
487 lines (432 loc) · 15.9 KB
/
GameTuning.java
File metadata and controls
487 lines (432 loc) · 15.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
package com.programmerdan.minecraft.simpleadminhacks.hacks;
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
import com.programmerdan.minecraft.simpleadminhacks.configs.GameTuningConfig;
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
import com.programmerdan.minecraft.simpleadminhacks.framework.utilities.TeleportUtil;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World.Environment;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Skeleton;
import org.bukkit.entity.SkeletonHorse;
import org.bukkit.entity.minecart.HopperMinecart;
import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityPortalEvent;
import org.bukkit.event.entity.EntityPotionEffectEvent;
import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.inventory.InventoryMoveItemEvent;
import org.bukkit.event.player.PlayerBedEnterEvent;
import org.bukkit.event.player.PlayerBedEnterEvent.BedEnterResult;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.weather.WeatherChangeEvent;
import org.bukkit.event.world.PortalCreateEvent;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.meta.SpawnEggMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import vg.civcraft.mc.civmodcore.inventory.items.ItemUtils;
/**
* This is a grab-bag class to hold any _tuning_ related configurations that impact the
* game, server-wide.
*
* It's part of a series of focused hacks.
*
* {@link GameFixes} is focused on things that are broken or don't work, and attempts to fix them.
* {@link GameFeatures} focuses on enabling and disabling features, like elytra, various potion states.
* {@link GameTuning} neither fixes nor disables, but rather adjusts and reconfigures.
*
* Currently you can control the following:
* - BlockEntity limits per chunk
* - Setting bed during the day instead of just at night
*/
public class GameTuning extends SimpleHack<GameTuningConfig> implements Listener, CommandExecutor {
public static final String NAME = "GameTuning";
public GameTuning(SimpleAdminHacks plugin, GameTuningConfig config) {
super(plugin, config);
}
@Override
public void registerListeners() {
if (config != null && config.isEnabled()) {
plugin().log("Registering GameTuning listeners");
plugin().registerListener(this);
}
}
@Override
public void unregisterListeners() {
// Bukkit does this for us.
}
@Override
public void registerCommands() {
if (config.isEnabled()) {
plugin.registerCommand("chunklimits", this);
}
}
@Override
public void unregisterCommands() {
}
@Override
public void dataBootstrap() {
}
@Override
public void dataCleanup() {
// NO-OP
}
@Override
public String status() {
StringBuilder genStatus = new StringBuilder();
genStatus.append("GameTuning is ");
if (config != null && config.isEnabled()) {
genStatus.append("active\n");
if (config.areChunkLimitsEnabled()) {
genStatus.append(" Chunk Limits are enabled\n");
} else {
genStatus.append(" Chunk Limits are disabled\n");
}
if (config.areDaytimeBedsEnabled()) {
genStatus.append(" Daytime Beds are enabled\n");
} else {
genStatus.append(" Daytime Beds are disabled\n");
}
genStatus.append(" One To One Nether is ");
if (config.isOneToOneNether()) {
genStatus.append("enabled\n");
} else {
genStatus.append("disabled\n");
}
genStatus.append(" Stop trap horses is ");
if (config.stopTrapHorses()) {
genStatus.append("enabled\n");
} else {
genStatus.append("disabled\n");
}
genStatus.append(" Kill trap horses is ");
if (config.killTrapHorses()) {
genStatus.append("enabled\n");
} else {
genStatus.append("disabled\n");
}
genStatus.append(" Changing spawner type is ");
if (config.canChangeSpawnerType()) {
genStatus.append("enabled\n");
} else {
genStatus.append("disabled\n");
}
genStatus.append(" Villager trading is ");
if (config.allowVillagerTrading()) {
genStatus.append("enabled\n");
} else {
genStatus.append("disabled\n");
}
genStatus.append(" Ender grief is ");
if (config.isEnderGrief()) {
genStatus.append("enabled\n");
} else {
genStatus.append("disabled\n");
}
genStatus.append(" Wither grief is ");
if (config.isWitherGrief()) {
genStatus.append("enabled\n");
} else {
genStatus.append("disabled\n");
}
genStatus.append(" Dragon grief is ");
if (config.isDragonGrief()) {
genStatus.append("enabled\n");
} else {
genStatus.append("disabled\n");
}
genStatus.append(" Prevent falling through bedrock is ");
if (config.isPreventFallingThroughBedrock()) {
genStatus.append("enabled\n");
} else {
genStatus.append("disabled\n");
}
genStatus.append(" Bad Omen is ");
if (config.isBadOmenEnabled()) {
genStatus.append("enabled\n");
} else {
genStatus.append("disabled\n");
}
genStatus.append(" Rain reduction is ");
if (config.isRainReductionEnabled()) {
genStatus.append("enabled\n");
} else {
genStatus.append("disabled\n");
}
} else {
genStatus.append("inactive");
}
return genStatus.toString();
}
public static GameTuningConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
return new GameTuningConfig(plugin, config);
}
/* From here on, the actual meat of the hack. Above is basically boilerplate for micro-plugins.*/
/**
* Many thanks to BlackXNT for his work on this event in Humbug, which I have largely copied and expanded.
*
* This tracks block placements, and if a limit is configured and the block is a TileEntity w/ state,
* will reject the placement if otherwise it would exceed limits for the Chunk.
*
* @param event the Placement event.
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void chunkLimits(BlockPlaceEvent event) {
if (!config.isEnabled() || !config.areChunkLimitsEnabled()) return;
try {
Player player = event.getPlayer();
Block block = event.getBlock();
if (!config.applyChunkLimits(player.getUniqueId())) return;
Material mat = block.getType();
Integer limit = config.getChunkLimit(mat);
if (limit == null) return;
int current = 0;
for (BlockState state : block.getChunk().getTileEntities()) {
if (state != null && mat.equals(state.getType())) {
if (++current > limit) {
event.setCancelled(true);
player.sendMessage(config.getChunkLimitsExceededMessage()
.replaceAll("%Limit%",Integer.toString(limit))
.replaceAll("%Material%", ItemUtils.getItemName(mat))
);
return;
}
}
}
} catch (Exception e) {
plugin().log(Level.WARNING, "Failed to measure chunk limit", e);
}
}
// If any limit at all, cancel the piston event.
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void chunkLimitsExploitExtend(BlockPistonExtendEvent event) {
if (!config.isEnabled() || !config.areChunkLimitsEnabled()) return;
List<Block> blocks = event.getBlocks();
if (!blocks.isEmpty()) {
for (Block b : blocks) {
if (b != null && config.getChunkLimit(b.getType()) != null) {
event.setCancelled(true);
return; // TODO send message to nearby player warning of reason for stopping.
}
}
}
}
// Yes, this is identical ...
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void chunkLimitsExploitRetract(BlockPistonRetractEvent event) {
if (!config.isEnabled() || !config.areChunkLimitsEnabled()) return;
List<Block> blocks = event.getBlocks();
if (!blocks.isEmpty()) {
for (Block b : blocks) {
if (b != null && config.getChunkLimit(b.getType()) != null) {
event.setCancelled(true);
return; // TODO send message to nearby player warning of reason for stopping.
}
}
}
}
@EventHandler
public void enterBed(PlayerBedEnterEvent e) {
if (!config.isEnabled() || !config.areDaytimeBedsEnabled()) {
return;
}
if (BedEnterResult.NOT_POSSIBLE_NOW.equals(e.getBedEnterResult()) || BedEnterResult.NOT_SAFE.equals(e.getBedEnterResult())) {
e.getPlayer().setBedSpawnLocation(e.getBed().getLocation(), false);
e.getPlayer().sendTitle("", config.getDaytimeBedSpawnSetMessage());
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPortalTravel(EntityPortalEvent event) {
if (!config.isEnabled()) {
return;
}
if (!config.allowNetherTravel() && event.getTo() != null && event.getTo().getWorld().getEnvironment() == Environment.NETHER) {
event.setCancelled(true);
return;
}
if (config.isOneToOneNether()) {
Location newLoc = event.getFrom();
newLoc.setWorld(event.getTo().getWorld());
event.setTo(newLoc);
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerPortalTravel(PlayerPortalEvent event) {
if(config.isEnabled() && PlayerTeleportEvent.TeleportCause.NETHER_PORTAL == event.getCause()) {
if(!config.allowNetherTravel()) {
event.setCancelled(true);
} else if (config.isOneToOneNether()) {
Location newLoc = event.getFrom();
newLoc.setWorld(event.getTo().getWorld());
event.setTo(newLoc);
}
}
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPortalCreate(PortalCreateEvent event) {
if (config.isEnabled() && !config.isReturnNetherPortal()) {
if (PortalCreateEvent.CreateReason.FIRE.equals(event.getReason()) && Environment.NETHER.equals(event.getWorld().getEnvironment())) {
event.setCancelled(true);
}
}
}
//Trying to stop dupe bugs via minecart inventories
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onEntityRightClick(PlayerInteractEntityEvent event) {
if (!config.isEnabled()) return;
if (!config.isChestedMinecartInventories() || !config.isHopperMinecartInventories()) {
Entity target = event.getRightClicked();
if (target.getType().equals(EntityType.MINECART_CHEST) && !config.isChestedMinecartInventories()) {
event.setCancelled(true);
}
if (target.getType().equals(EntityType.MINECART_HOPPER) && !config.isHopperMinecartInventories()) {
event.setCancelled(true);
}
}
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onInventoryMoveItemEvent(InventoryMoveItemEvent event) {
if (!config.isEnabled()) return;
if (!config.isChestedMinecartInventories() || !config.isHopperMinecartInventories()) {
InventoryHolder holder = event.getDestination().getHolder();
if (holder instanceof StorageMinecart && !config.isChestedMinecartInventories()) {
event.setCancelled(true);
}
if (holder instanceof HopperMinecart && !config.isHopperMinecartInventories()) {
event.setCancelled(true);
}
}
}
@EventHandler
public void onEntityTarget(EntityTargetEvent event) {
if(config.isEnabled() && config.stopTrapHorses()) {
Entity entity = event.getEntity();
if(entity instanceof Skeleton && entity.isInsideVehicle() && entity.getVehicle() instanceof SkeletonHorse) {
if(config.killTrapHorses()) {
entity.getVehicle().remove();
}
entity.remove();
}
}
}
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
if(!config.isEnabled() || !Action.RIGHT_CLICK_BLOCK.equals(event.getAction())) {
return;
}
boolean cancel = !config.canChangeSpawnerType() && Material.SPAWNER.equals(event.getClickedBlock().getType())
&& event.getItem() != null && event.getItem().getItemMeta() instanceof SpawnEggMeta;
if (cancel) {
event.setCancelled(true);
}
}
@EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
if(config.isEnabled() && !config.canPlace(event.getBlock().getType())) {
event.setCancelled(true);
event.getPlayer().sendMessage(ChatColor.RED + "You're not allowed to place that!");
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if(config.isEnabled() && !config.allowVillagerTrading()) {
Entity npc = event.getRightClicked();
// consistency, preserving null check
if(npc != null && EntityType.VILLAGER.equals(npc.getType())) {
event.setCancelled(true);
}
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
if(config.isEnabled() &&
(!config.isEnderGrief() && EntityType.ENDERMAN.equals(event.getEntityType())) ||
(!config.isWitherGrief() && EntityType.WITHER.equals(event.getEntityType())) ||
(!config.isDragonGrief() && EntityType.ENDER_DRAGON.equals(event.getEntityType()))) {
event.setCancelled(true);
}
}
/**
* Speculative handler for dragon fireballs and exploding wither skulls
*
* Some examples online prefer event.getEntity() instanceof DragonFireball and WitherSkull, could try that
* if this does not work
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onEntityExplodeEvent(EntityExplodeEvent event) {
if (config.isEnabled() &&
(!config.isDragonGrief() && EntityType.DRAGON_FIREBALL.equals(event.getEntityType())) ||
(!config.isWitherGrief() && EntityType.WITHER_SKULL.equals(event.getEntityType()))) {
event.setCancelled(true);
// note this might not prevent block breaks, check on that (1.14)
}
}
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
if(config.isEnabled() && config.isPreventFallingThroughBedrock() && event.getTo().getY() < 1
&& GameMode.SURVIVAL.equals(event.getPlayer().getGameMode())) {
TeleportUtil.tryToTeleportVertically(event.getPlayer(), event.getTo(), "falling into the void");
}
}
@EventHandler
public void onBadOmenEffect(EntityPotionEffectEvent event) {
if (!config.isEnabled() || config.isBadOmenEnabled()) {
return;
}
PotionEffect effect = event.getNewEffect();
if (effect != null && effect.getType().equals(PotionEffectType.BAD_OMEN)) {
event.setCancelled(true);
}
}
@EventHandler
public void onRain(WeatherChangeEvent event) {
if (!config.isEnabled() || !config.isRainReductionEnabled()) {
return;
}
if (event.toWeatherState() && Math.random() >= config.getRainOccurrenceChance()) {
event.setCancelled(true);
plugin().getLogger().info("Rain event was cancelled");
}
}
@Override
public boolean onCommand(@Nonnull CommandSender commandSender, @Nonnull Command command, @Nonnull String s, @Nonnull String[] strings) {
Map<Material, Integer> blockLimits = config.getBlockEntityLimits();
StringBuilder stringB = new StringBuilder();
stringB.append(ChatColor.AQUA + "-- Chunk Limitations for the following blocks --\n");
stringB.append("\n");
for (Map.Entry<Material, Integer> entries: blockLimits.entrySet()) {
Material material = entries.getKey();
Integer blockLimit = entries.getValue();
stringB.append("" + ChatColor.WHITE + material + " : " + blockLimit+ "\n");
}
commandSender.sendMessage(stringB.toString());
return true;
}
}