Skip to content
This repository was archived by the owner on Dec 7, 2022. It is now read-only.

Commit cb0f483

Browse files
committed
Implement renewables
1 parent 17d97ae commit cb0f483

File tree

5 files changed

+353
-2
lines changed

5 files changed

+353
-2
lines changed

src/main/java/in/twizmwaz/cardinal/module/ModuleFactory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import in.twizmwaz.cardinal.module.modules.rage.RageBuilder;
5858
import in.twizmwaz.cardinal.module.modules.rank.RankModuleBuilder;
5959
import in.twizmwaz.cardinal.module.modules.regions.RegionModuleBuilder;
60+
import in.twizmwaz.cardinal.module.modules.renewables.RenewablesBuilder;
6061
import in.twizmwaz.cardinal.module.modules.respawn.RespawnModuleBuilder;
6162
import in.twizmwaz.cardinal.module.modules.score.ScoreModuleBuilder;
6263
import in.twizmwaz.cardinal.module.modules.scoreboard.ScoreboardModuleBuilder;
@@ -185,7 +186,8 @@ private void addBuilders() {
185186
PostBuilder.class,
186187
FlagBuilder.class,
187188
NetBuilder.class,
188-
StatsBuilder.class
189+
StatsBuilder.class,
190+
RenewablesBuilder.class
189191
));
190192
}
191193

src/main/java/in/twizmwaz/cardinal/module/modules/filter/type/BlockFilter.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import in.twizmwaz.cardinal.module.modules.filter.parsers.BlockFilterParser;
66
import org.bukkit.Material;
77
import org.bukkit.block.Block;
8+
import org.bukkit.material.MaterialData;
89

910
import static in.twizmwaz.cardinal.module.modules.filter.FilterState.ABSTAIN;
1011
import static in.twizmwaz.cardinal.module.modules.filter.FilterState.ALLOW;
@@ -23,7 +24,6 @@ public BlockFilter(final BlockFilterParser parser) {
2324

2425
@Override
2526
public FilterState evaluate(final Object... objects) {
26-
2727
for (Object object : objects) {
2828
if (object instanceof Block) {
2929
if (((Block) object).getType().equals(material) && (damageValue == -1 || (int) ((Block) object).getState().getData().getData() == damageValue))
@@ -33,6 +33,10 @@ public FilterState evaluate(final Object... objects) {
3333
if ((object).equals(material))
3434
return ALLOW;
3535
else return DENY;
36+
} else if (object instanceof MaterialData) {
37+
if (((MaterialData) object).getItemType().equals(material) && (damageValue == -1 || (int) ((MaterialData) object).getData() == damageValue))
38+
return ALLOW;
39+
else return DENY;
3640
}
3741
}
3842
return (getParent() == null ? ABSTAIN : getParent().evaluate(objects));
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
package in.twizmwaz.cardinal.module.modules.renewables;
2+
3+
import com.google.common.collect.Lists;
4+
import in.twizmwaz.cardinal.Cardinal;
5+
import in.twizmwaz.cardinal.GameHandler;
6+
import in.twizmwaz.cardinal.event.MatchEndEvent;
7+
import in.twizmwaz.cardinal.module.TaskedModule;
8+
import in.twizmwaz.cardinal.module.modules.filter.FilterModule;
9+
import in.twizmwaz.cardinal.module.modules.filter.FilterState;
10+
import in.twizmwaz.cardinal.module.modules.regions.RegionModule;
11+
import in.twizmwaz.cardinal.module.modules.team.TeamModule;
12+
import in.twizmwaz.cardinal.util.Teams;
13+
import net.minecraft.server.SoundCategory;
14+
import net.minecraft.server.SoundEffectType;
15+
import net.minecraft.server.World;
16+
import org.bukkit.Bukkit;
17+
import org.bukkit.Material;
18+
import org.bukkit.block.Block;
19+
import org.bukkit.block.BlockFace;
20+
import org.bukkit.craftbukkit.CraftWorld;
21+
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
22+
import org.bukkit.entity.Player;
23+
import org.bukkit.event.EventHandler;
24+
import org.bukkit.event.EventPriority;
25+
import org.bukkit.event.HandlerList;
26+
import org.bukkit.event.block.BlockBreakEvent;
27+
import org.bukkit.event.block.BlockPlaceEvent;
28+
import org.bukkit.event.entity.EntityExplodeEvent;
29+
import org.bukkit.event.player.PlayerBucketEmptyEvent;
30+
import org.bukkit.event.player.PlayerBucketFillEvent;
31+
import org.bukkit.material.MaterialData;
32+
import org.bukkit.util.BlockVector;
33+
import org.bukkit.util.Vector;
34+
35+
import java.util.HashMap;
36+
import java.util.List;
37+
import java.util.Map;
38+
import java.util.Random;
39+
40+
public class Renewable implements TaskedModule {
41+
42+
private RegionModule region;
43+
private FilterModule renewFilter;
44+
private FilterModule replaceFilter;
45+
private FilterModule shuffleFilter;
46+
private RenewMode mode;
47+
private double ratePerTick;
48+
private double intervalTicks;
49+
private boolean grow;
50+
private boolean particles;
51+
private boolean sound;
52+
private int avoidPlayers;
53+
54+
private Random random = new Random();
55+
private double renewals;
56+
57+
private Map<BlockVector, MaterialData> blocks = new HashMap<>();
58+
private List<BlockVector> toRenew = Lists.newArrayList();
59+
private List<Integer> tasks = Lists.newArrayList();
60+
61+
private static BlockFace[] faces = {BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST, BlockFace.UP, BlockFace.DOWN};
62+
63+
Renewable(RegionModule region,
64+
FilterModule renewFilter,
65+
FilterModule replaceFilter,
66+
FilterModule shuffleFilter,
67+
double rate,
68+
double interval,
69+
boolean grow,
70+
boolean particles,
71+
boolean sound,
72+
int avoidPlayers) {
73+
this.region = region;
74+
this.renewFilter = renewFilter;
75+
this.replaceFilter = replaceFilter;
76+
this.shuffleFilter = shuffleFilter;
77+
this.mode = interval < 0 ? RenewMode.RATE : RenewMode.INTERVAL;
78+
this.intervalTicks = (int) interval * 20;
79+
this.ratePerTick = rate / 20;
80+
this.grow = grow;
81+
this.particles = particles;
82+
this.sound = sound;
83+
this.avoidPlayers = avoidPlayers * avoidPlayers;
84+
}
85+
86+
@Override
87+
public void unload() {
88+
HandlerList.unregisterAll(this);
89+
}
90+
91+
@Override
92+
public void run() {
93+
if (GameHandler.getGameHandler().getMatch().isRunning() && mode.equals(RenewMode.RATE)) {
94+
renewals += ratePerTick;
95+
96+
int fails = 0, maxFails = 5 + (toRenew.size() / 4);
97+
98+
while(fails < maxFails && toRenew.size() > 0 && renewals > 1) {
99+
BlockVector loc = toRenew.get(random.nextInt(toRenew.size()));
100+
101+
Boolean renew = attemptRenew(loc);
102+
if (renew != null) {
103+
if (renew) renewals--;
104+
else fails++;
105+
}
106+
107+
}
108+
if (renewals > 1) renewals -= (int) renewals;
109+
}
110+
}
111+
112+
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
113+
public void onBlockBreak(BlockBreakEvent event) {
114+
editedBlock(event.getBlock().getLocation(), event.getBlock().getState().getMaterialData());
115+
}
116+
117+
118+
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
119+
public void onBlockPlace(BlockPlaceEvent event) {
120+
editedBlock(event.getBlock().getLocation(), event.getBlockReplacedState().getMaterialData());
121+
}
122+
123+
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
124+
public void onBucketFill(PlayerBucketFillEvent event) {
125+
editedBlock(event.getBlockClicked().getLocation(), event.getBlockClicked().getState().getMaterialData());
126+
}
127+
128+
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
129+
public void onBucketEmpty(PlayerBucketEmptyEvent event) {
130+
Block relative = event.getBlockClicked().getRelative(event.getBlockFace());
131+
editedBlock(relative.getLocation(), relative.getState().getMaterialData());
132+
}
133+
134+
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
135+
public void onBlockBlow(EntityExplodeEvent event) {
136+
for (Block block : event.blockList()) {
137+
editedBlock(block.getLocation(), block.getState().getMaterialData());
138+
}
139+
}
140+
141+
@EventHandler
142+
public void onMatchEnd(MatchEndEvent event) {
143+
for (int id : tasks) {
144+
Bukkit.getScheduler().cancelTask(id);
145+
}
146+
tasks.clear();
147+
}
148+
149+
public void stopTask(int id) {
150+
Bukkit.getScheduler().cancelTask(id);
151+
tasks.remove((Integer) id);
152+
}
153+
154+
private void editedBlock(Vector loc, MaterialData save) {
155+
if (isInRegion(loc)) {
156+
BlockVector block = loc.toBlockVector();
157+
if (!blocks.containsKey(block)) {
158+
blocks.put(block, save);
159+
}
160+
if (!toRenew.contains(block) && renewFilter.evaluate(save).equals(FilterState.ALLOW)) {
161+
toRenew.add(block);
162+
if (mode.equals(RenewMode.INTERVAL)) {
163+
RenewRunnable renewRunnable = new RenewRunnable(this, block);
164+
int taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(Cardinal.getInstance(), renewRunnable, (long) intervalTicks, (long) intervalTicks);
165+
renewRunnable.setTask(taskId);
166+
tasks.add(taskId);
167+
}
168+
}
169+
}
170+
}
171+
172+
public Boolean attemptRenew(BlockVector loc) {
173+
Block block = loc.toLocation(GameHandler.getGameHandler().getMatchWorld()).getBlock();
174+
175+
if (isRenewed(block)) {
176+
toRenew.remove(loc);
177+
return null;
178+
} else if (canRenew(block)) {
179+
resetBlock(block);
180+
toRenew.remove(loc);
181+
return true;
182+
} else {
183+
return false;
184+
}
185+
}
186+
187+
private void resetBlock(Block block) {
188+
MaterialData original = blocks.get(block.getLocation().toBlockVector());
189+
190+
block.setTypeIdAndData(original.getItemTypeId(), original.getData(), true);
191+
192+
World nmsWorld = ((CraftWorld) GameHandler.getGameHandler().getMatchWorld()).getHandle();
193+
if (sound) {
194+
SoundEffectType sound = CraftMagicNumbers.getBlock(original.getItemType()).getSoundEffects();
195+
nmsWorld.playSoundEffect(null, block.getX(), block.getY(), block.getZ(), sound.breakSound(), SoundCategory.BLOCKS, sound.b(), sound.a());
196+
}
197+
/*if (particles) {
198+
PacketPlayOutWorldParticles packet = new PacketPlayOutWorldParticles(EnumParticle.ITEM_CRACK, true, (float)block.getX(), (float)block.getY(), (float)block.getZ(), 0.15f, 24.0f, 0.15f, 0.0f, 40, 35, (int)color.getWoolData());
199+
PacketUtils.broadcastPacket(packet);
200+
}*/
201+
}
202+
203+
private boolean hasAdjacentBlocks(Block block) {
204+
for (BlockFace face : faces) {
205+
Block relative = block.getRelative(face);
206+
if (!relative.getType().equals(Material.AIR) && isRenewed(relative)) return true;
207+
}
208+
return false;
209+
}
210+
211+
private boolean isRenewed(Block block) {
212+
if (!isInRegion(block.getLocation())) return false;
213+
BlockVector loc = block.getLocation().toBlockVector();
214+
if (!blocks.containsKey(loc)) {
215+
return true;
216+
} else if (shuffleFilter.evaluate(blocks.get(loc)).equals(FilterState.ALLOW)) {
217+
return shuffleFilter.evaluate(block).equals(FilterState.ALLOW);
218+
} else {
219+
return blocks.get(loc).equals(block.getState().getMaterialData());
220+
}
221+
}
222+
223+
public boolean canRenew(Block block) {
224+
BlockVector pos = block.getLocation().toVector().toBlockVector();
225+
226+
if(isInRegion(pos) && blocks.containsKey(pos) && !blocks.get(pos).getItemType().equals(Material.AIR)
227+
&& replaceFilter.evaluate(block).equals(FilterState.ALLOW) && (!grow || hasAdjacentBlocks(block))) {
228+
if (avoidPlayers != 0) {
229+
for (TeamModule team : Teams.getTeams()) {
230+
if (team.isObserver()) continue;
231+
for (Player player : (List<Player>) team) {
232+
if (player.getLocation().plus(0, 0.5, 0).distanceSquared(block.getLocation().plus(0.5, 0.5, 0.5)) < avoidPlayers) {
233+
return false;
234+
}
235+
}
236+
}
237+
}
238+
return true;
239+
}
240+
return false;
241+
}
242+
243+
private boolean isInRegion(Vector pos) {
244+
Vector vec = new Vector(pos.getBlockX() + 0.5, pos.getBlockY() + 0.5, pos.getBlockZ() + 0.5);
245+
return region.contains(vec);
246+
}
247+
248+
enum RenewMode {
249+
RATE(),
250+
INTERVAL();
251+
}
252+
253+
private class RenewRunnable implements Runnable {
254+
255+
private Renewable renewable;
256+
private BlockVector toRenew;
257+
private int taskId;
258+
259+
public RenewRunnable(Renewable renewable, BlockVector block) {
260+
this.renewable = renewable;
261+
this.toRenew = block;
262+
}
263+
264+
public void setTask(int taskId) {
265+
this.taskId = taskId;
266+
}
267+
268+
@Override
269+
public void run() {
270+
Boolean renew = renewable.attemptRenew(toRenew);
271+
if (renew == null || renew) {
272+
renewable.stopTask(taskId);
273+
}
274+
}
275+
276+
}
277+
278+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package in.twizmwaz.cardinal.module.modules.renewables;
2+
3+
import in.twizmwaz.cardinal.match.Match;
4+
import in.twizmwaz.cardinal.module.ModuleBuilder;
5+
import in.twizmwaz.cardinal.module.ModuleCollection;
6+
import in.twizmwaz.cardinal.module.modules.filter.FilterModule;
7+
import in.twizmwaz.cardinal.module.modules.filter.FilterModuleBuilder;
8+
import in.twizmwaz.cardinal.module.modules.filter.parsers.BlockFilterParser;
9+
import in.twizmwaz.cardinal.module.modules.filter.type.BlockFilter;
10+
import in.twizmwaz.cardinal.module.modules.regions.RegionModule;
11+
import in.twizmwaz.cardinal.module.modules.regions.RegionModuleBuilder;
12+
import in.twizmwaz.cardinal.util.Numbers;
13+
import in.twizmwaz.cardinal.util.Parser;
14+
import in.twizmwaz.cardinal.util.Proto;
15+
import in.twizmwaz.cardinal.util.Strings;
16+
import org.jdom2.Element;
17+
18+
public class RenewablesBuilder implements ModuleBuilder {
19+
20+
@Override
21+
public ModuleCollection<Renewable> load(Match match) {
22+
ModuleCollection<Renewable> results = new ModuleCollection<>();
23+
for (Element renewables : match.getDocument().getRootElement().getChildren("renewables")) {
24+
for (Element renewable : renewables.getChildren("renewable")) {
25+
results.add(getRenewable(match.getProto(), renewable, renewables));
26+
}
27+
for (Element renewables2 : renewables.getChildren("renewables")) {
28+
for (Element renewable : renewables2.getChildren("renewable")) {
29+
results.add(getRenewable(match.getProto(), renewable, renewables2, renewable));
30+
}
31+
}
32+
}
33+
return results;
34+
}
35+
36+
private Renewable getRenewable(Proto proto, Element... elements) {
37+
RegionModule region = RegionModuleBuilder.getAttributeOrChild("region", elements);
38+
39+
FilterModule renewFilter, replaceFilter, shuffleFilter;
40+
41+
if (proto.greaterOrEqualTo(Proto.parseProto("1.4.0"))) {
42+
renewFilter = FilterModuleBuilder.getAttributeOrChild("renew-filter", "always", elements);
43+
replaceFilter = FilterModuleBuilder.getAttributeOrChild("replace-filter", "always", elements);
44+
shuffleFilter = FilterModuleBuilder.getAttributeOrChild("shuffle-filter", "never", elements);
45+
} else {
46+
renewFilter = new BlockFilter(new BlockFilterParser(elements[0].getChild("renew")));
47+
replaceFilter = new BlockFilter(new BlockFilterParser(elements[0].getChild("replace")));
48+
shuffleFilter = FilterModuleBuilder.getAttributeOrChild("shuffle", "never", elements);
49+
}
50+
51+
double rate = Numbers.parseDouble(Parser.getOrderedAttribute("rate", elements), 1);
52+
double interval = Strings.timeStringToExactSeconds(Strings.fallback(Parser.getOrderedAttribute("interval", elements), "-1s"));
53+
54+
boolean grow = Numbers.parseBoolean(Parser.getOrderedAttribute("grow", elements), true);
55+
boolean particles = Numbers.parseBoolean(Parser.getOrderedAttribute("particles", elements), true);
56+
boolean sound = Numbers.parseBoolean(Parser.getOrderedAttribute("sound", elements), true);
57+
int avoidPlayers = Numbers.parseInt(Parser.getOrderedAttribute("avoid-players", elements), 2);
58+
59+
return new Renewable(region, renewFilter, replaceFilter, shuffleFilter, rate, interval, grow, particles, sound, avoidPlayers);
60+
}
61+
62+
}

src/main/java/in/twizmwaz/cardinal/util/Strings.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,4 +162,9 @@ public static String getCurrentChatColor(String str, int index) {
162162
}
163163
return color;
164164
}
165+
166+
public static String fallback(String string, String fallback) {
167+
return string == null ? fallback : string;
168+
}
169+
165170
}

0 commit comments

Comments
 (0)