Skip to content

Commit dcc091e

Browse files
committed
Finish Forcefielding
1 parent 2fc2019 commit dcc091e

File tree

8 files changed

+106
-53
lines changed

8 files changed

+106
-53
lines changed

src/main/java/net/techcable/spawnshield/SpawnShield.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,7 @@ public int getValue() {
9292
case FORCEFIELD :
9393
Utils.warning("Force field mode is currently unsupported");
9494
this.forceFieldListener = new ForceFieldListener();
95-
registerListener(new ForceFieldListener());
96-
forceFieldUpdateTask = new ForceFieldUpdateTask();
97-
forceFieldUpdateTask.runTaskTimerAsynchronously(this, 0, 1); //Every single tick
95+
registerListener(forceFieldListener);
9896
break;
9997
case TELEPORT :
10098
teleportSafezoningTask = new TeleportSafezoningTask();

src/main/java/net/techcable/spawnshield/SpawnShieldPlayer.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ public SpawnShield getPlugin() {
7575
@Synchronized("forceFieldUpdateLock")
7676
public void updateForceField(ForceFieldUpdateRequest request) {
7777
if (updateRequest == null || updateRequest.isCompleted()) {
78-
updateRequest = null;
7978
updateRequest = request;
8079
}
8180
}

src/main/java/net/techcable/spawnshield/forcefield/BlockPos.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
@RequiredArgsConstructor
3636
@Getter
37-
@EqualsAndHashCode
37+
@EqualsAndHashCode(of = {"x", "y", "z", "world"})
3838
public class BlockPos {
3939

4040
public BlockPos(Location l) {
@@ -50,7 +50,7 @@ public Location toLocation() {
5050
}
5151

5252
public int distanceSquared(BlockPos other) {
53-
Preconditions.checkArgument(!other.getWorld().equals(getWorld()), "Can't compare the distances of different worlds");
53+
Preconditions.checkArgument(other.getWorld().equals(getWorld()), "Can't compare the distances of different worlds");
5454
return square(x - other.x) + square(y - other.y) + square(z - other.z);
5555
}
5656

src/main/java/net/techcable/spawnshield/forcefield/BorderFinder.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,19 @@ public static Collection<BlockPos> getBorderPoints(Region region) {
4343
getAlongX(point, region, result);
4444
getAlongZ(point, region, result);
4545
}
46+
getBottomOrTop(region.getMin(), region, result);
47+
getBottomOrTop(region.getMax(), region, result);
4648
return result;
4749
}
48-
50+
51+
private static void getBottomOrTop(BlockPos bottomOrTop, Region region, HashSet<BlockPos> result) {
52+
for (int x = bottomOrTop.getX(); region.contains(x, bottomOrTop.getY(), bottomOrTop.getZ()); x++) {
53+
for (int z = bottomOrTop.getZ(); region.contains(x, bottomOrTop.getY(), z); z++) {
54+
result.add(new BlockPos(x, bottomOrTop.getY(), z, region.getWorld()));
55+
}
56+
}
57+
}
58+
4959
private static void getAlongX(BlockPos start, Region region, HashSet<BlockPos> result) {
5060
if (region.contains(start.getX() + 1, start.getY(), start.getZ())) { //We are positive
5161
for (int x = start.getX(); region.contains(x, start.getY(), start.getZ()); x++) {

src/main/java/net/techcable/spawnshield/forcefield/ForceFieldListener.java

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@
2727
import com.google.common.base.Function;
2828
import com.google.common.collect.ImmutableSet;
2929
import com.google.common.collect.Maps;
30+
import com.google.common.collect.Sets;
31+
import com.google.common.util.concurrent.JdkFutureAdapters;
3032
import com.google.common.util.concurrent.ListenableFuture;
33+
import com.google.common.util.concurrent.MoreExecutors;
3134
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
3235
import net.techcable.spawnshield.CombatAPI;
3336
import net.techcable.spawnshield.SpawnShield;
3437
import net.techcable.spawnshield.SpawnShieldPlayer;
38+
import net.techcable.spawnshield.tasks.ForceFieldUpdateTask;
3539
import net.techcable.techutils.TechScheduler;
3640
import net.techcable.techutils.collect.Pair;
3741
import org.bukkit.Bukkit;
@@ -42,30 +46,69 @@
4246
import org.bukkit.event.EventHandler;
4347
import org.bukkit.event.EventPriority;
4448
import org.bukkit.event.Listener;
49+
import org.bukkit.event.player.PlayerKickEvent;
4550
import org.bukkit.event.player.PlayerMoveEvent;
51+
import org.bukkit.event.player.PlayerQuitEvent;
4652
import org.bukkit.scheduler.BukkitRunnable;
53+
import org.bukkit.scheduler.BukkitScheduler;
4754

4855
import javax.annotation.Nullable;
4956
import java.util.Collection;
5057
import java.util.HashSet;
5158
import java.util.Set;
59+
import java.util.UUID;
5260
import java.util.concurrent.ConcurrentMap;
5361

5462
public class ForceFieldListener implements Listener {
5563
public static final int DEFAULT_UPDATE_RADIUS = 20;
64+
private final Set<UUID> currentlyProcessing = Sets.newSetFromMap(Maps.<UUID, Boolean>newConcurrentMap());
5665
@EventHandler(priority = EventPriority.MONITOR)
5766
public void onMove(PlayerMoveEvent event) {
5867
if (event.getFrom().equals(event.getTo())) return; //Don't wanna fire if the player turned his head
59-
if (!CombatAPI.isTagged(event.getPlayer())) return;
60-
SpawnShieldPlayer player = SpawnShield.getInstance().getPlayer(event.getPlayer());
68+
if (currentlyProcessing.contains(event.getPlayer().getUniqueId())) return;
69+
final SpawnShieldPlayer player = SpawnShield.getInstance().getPlayer(event.getPlayer());
70+
if (!CombatAPI.isTagged(event.getPlayer())) {
71+
if (player.getLastShownBlocks() != null && !currentlyProcessing.contains(player.getId())) {
72+
currentlyProcessing.add(player.getId());
73+
new BukkitRunnable() {
74+
@Override
75+
public void run() {
76+
for (BlockPos lastShown : player.getLastShownBlocks()) {
77+
player.getEntity().sendBlockChange(lastShown.toLocation(), lastShown.getTypeAt(), lastShown.getDataAt());
78+
}
79+
player.setLastShownBlocks(null);
80+
currentlyProcessing.remove(player.getId());
81+
}
82+
}.runTaskAsynchronously(SpawnShield.getInstance());
83+
}
84+
return;
85+
}
86+
currentlyProcessing.add(player.getId());
6187
BlockPos pos = new BlockPos(player.getEntity().getLocation());
6288
Collection<Region> toUpdate = new HashSet<>();
6389
for (Pair<World, ProtectedRegion> wgRegion : SpawnShield.getInstance().getSettings().getRegionsToBlock()) {
64-
if (wgRegion.getFirst().equals(event.getPlayer().getWorld())) continue; //We dont need this one: Yay!
90+
if (!wgRegion.getFirst().equals(event.getPlayer().getWorld())) continue; //We dont need this one: Yay!
6591
ProtectedRegionRegion region = new ProtectedRegionRegion(wgRegion.getSecond(), wgRegion.getFirst());
6692
toUpdate.add(region);
6793
}
6894
ForceFieldUpdateRequest request = new ForceFieldUpdateRequest(pos, toUpdate, player, DEFAULT_UPDATE_RADIUS);
69-
player.updateForceField(request);
95+
final ForceFieldUpdateTask task = new ForceFieldUpdateTask(request);
96+
Bukkit.getScheduler().runTaskAsynchronously(SpawnShield.getInstance(), task);
97+
task.addListener(new Runnable() {
98+
@Override
99+
public void run() {
100+
currentlyProcessing.remove(player.getId());
101+
}
102+
}, MoreExecutors.sameThreadExecutor());;
103+
}
104+
105+
@EventHandler(priority = EventPriority.MONITOR)
106+
public void onLeave(PlayerQuitEvent e) {
107+
currentlyProcessing.remove(e.getPlayer().getUniqueId());
108+
}
109+
110+
@EventHandler(priority = EventPriority.MONITOR)
111+
public void onKick(PlayerKickEvent e) {
112+
currentlyProcessing.remove(e.getPlayer().getUniqueId());
70113
}
71114
}

src/main/java/net/techcable/spawnshield/forcefield/ProtectedRegionRegion.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
package net.techcable.spawnshield.forcefield;
2626

27+
import com.sk89q.worldedit.BlockVector;
2728
import com.sk89q.worldedit.BlockVector2D;
2829
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
2930
import lombok.Getter;
@@ -65,6 +66,19 @@ public Collection<BlockPos> getPoints() {
6566
return points;
6667
}
6768

69+
@Override
70+
public BlockPos getMin() {
71+
BlockVector min = handle.getMinimumPoint();
72+
return new BlockPos(min.getBlockX(), min.getBlockY(), min.getBlockZ(), getWorld());
73+
}
74+
75+
76+
@Override
77+
public BlockPos getMax() {
78+
BlockVector max = handle.getMaximumPoint();
79+
return new BlockPos(max.getBlockX(), max.getBlockY(), max.getBlockZ(), getWorld());
80+
}
81+
6882
@Override
6983
public int hashCode() {
7084
int prime = 31;

src/main/java/net/techcable/spawnshield/forcefield/Region.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,6 @@ public interface Region {
3333
public boolean contains(int x, int y, int z);
3434
public Collection<BlockPos> getPoints();
3535
public World getWorld();
36+
public BlockPos getMin();
37+
public BlockPos getMax();
3638
}

src/main/java/net/techcable/spawnshield/tasks/ForceFieldUpdateTask.java

Lines changed: 29 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@
2727
import com.google.common.base.Function;
2828
import com.google.common.base.Supplier;
2929
import com.google.common.collect.*;
30+
import com.google.common.util.concurrent.AbstractFuture;
31+
import com.google.common.util.concurrent.ListenableFuture;
32+
import com.google.common.util.concurrent.SettableFuture;
3033
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
3134
import lombok.RequiredArgsConstructor;
35+
import lombok.experimental.Delegate;
3236
import net.techcable.spawnshield.SpawnShield;
3337
import net.techcable.spawnshield.SpawnShieldPlayer;
3438
import net.techcable.spawnshield.Utils;
@@ -39,65 +43,48 @@
3943
import org.bukkit.World;
4044
import org.bukkit.entity.Player;
4145
import org.bukkit.scheduler.BukkitRunnable;
46+
import org.bukkit.scheduler.BukkitScheduler;
4247

4348
import java.util.Collection;
4449
import java.util.HashSet;
4550
import java.util.Map;
4651
import java.util.Set;
47-
import java.util.concurrent.ConcurrentHashMap;
48-
import java.util.concurrent.ConcurrentMap;
4952

5053
@RequiredArgsConstructor
51-
public class ForceFieldUpdateTask extends BukkitRunnable {
54+
public class ForceFieldUpdateTask extends AbstractFuture implements Runnable, ListenableFuture {
55+
56+
public static ListenableFuture<?> schedule(ForceFieldUpdateRequest request) {
57+
ForceFieldUpdateTask task = new ForceFieldUpdateTask(request);
58+
Bukkit.getScheduler().runTask(SpawnShield.getInstance(), task);
59+
return task;
60+
}
61+
private final ForceFieldUpdateRequest request;
5262
@Override
5363
public void run() {
54-
for (Player playerEntity : Bukkit.getOnlinePlayers()) {
55-
SpawnShieldPlayer player = SpawnShield.getInstance().getPlayer(playerEntity);
56-
ForceFieldUpdateRequest request = player.getUpdateRequest();
57-
if (request == null || request.isCompleted()) continue;
58-
processRequest(request);
59-
request.setCompleted();
60-
}
61-
}
62-
63-
private void processRequest(ForceFieldUpdateRequest request) {
64-
Set<BlockPos> nearbyBorderPoints = new HashSet<>();
64+
Set<BlockPos> shownBlocks = new HashSet<BlockPos>();
6565
for (Region region : request.getRegionsToUpdate()) {
66-
if (!region.getWorld().equals(request.getPosition().getWorld())) continue;
6766
for (BlockPos borderPoint : getBorders(region)) {
68-
int distance = borderPoint.distanceSquared(request.getPosition());
69-
if (distance <= request.getUpdateRadius()) {
70-
nearbyBorderPoints.add(borderPoint);
71-
Utils.debug("Near Distance " + distance);
72-
} else {
73-
Utils.debug("Far Distance " + distance);
67+
for (int y = region.getMin().getY(); y <= region.getMax().getY(); y++) {
68+
BlockPos toShow = borderPoint.withY(y);
69+
int distance = toShow.distanceSquared(request.getPosition());
70+
if (distance <= request.getUpdateRadius()) {
71+
shownBlocks.add(toShow);
72+
}
7473
}
7574
}
7675
}
77-
if (request.getPlayer().getLastShownBlocks() != null) {
78-
for (BlockPos lastShown : request.getPlayer().getLastShownBlocks()) {
79-
/* I'm not sure if minecraft's chunk loading code is thread safe
80-
* Plus, a player can't see unloaded chunks, so we don't have to refresh them
81-
*/
82-
if (!lastShown.getChunkPos().isLoaded()) continue;
83-
request.getPlayerEntity().sendBlockChange(lastShown.toLocation(), lastShown.getTypeAt(), lastShown.getDataAt());
84-
}
76+
Collection<BlockPos> lastShown = request.getPlayer().getLastShownBlocks();
77+
if (lastShown == null) lastShown = new HashSet<>();
78+
for (BlockPos noLongerShown : lastShown) {
79+
if (shownBlocks.contains(noLongerShown)) continue; //We will show
80+
request.getPlayerEntity().sendBlockChange(noLongerShown.toLocation(), noLongerShown.getTypeAt().getId(), noLongerShown.getDataAt());
8581
}
86-
Set<BlockPos> shownBlocks = new HashSet<BlockPos>();
87-
for (BlockPos borderPoint : nearbyBorderPoints) {
88-
/*
89-
* I'm not sure if minecraft's chunk loading code is thread safe
90-
* Plus no player will be near an unloaded chunk so we don't have to display then
91-
*/
92-
if (!borderPoint.getChunkPos().isLoaded()) continue;
93-
for (int y = 0; y < borderPoint.getWorld().getMaxHeight(); y++) {
94-
BlockPos pos = borderPoint.withY(y);
95-
if (pos.getTypeAt().isSolid()) continue; //Don't mess with solid blocks
96-
request.getPlayerEntity().sendBlockChange(pos.toLocation(), Material.STAINED_GLASS, (byte) 14);
97-
shownBlocks.add(pos);
98-
}
82+
for (BlockPos toShow : shownBlocks) {
83+
if (toShow.getTypeAt().isSolid()) continue;
84+
request.getPlayerEntity().sendBlockChange(toShow.toLocation(), Material.STAINED_GLASS, (byte)14);
9985
}
10086
request.getPlayer().setLastShownBlocks(shownBlocks);
87+
set(null);
10188
}
10289

10390
private final Map<Region, Collection<BlockPos>> borderCache = Maps.newHashMap(); //Will only be accessed by a single task, so no need for synchronization

0 commit comments

Comments
 (0)