55import org .bukkit .Location ;
66import org .bukkit .Material ;
77import org .bukkit .block .Block ;
8+ import org .bukkit .block .data .Rail ;
9+ import org .bukkit .entity .Minecart ;
10+ import org .bukkit .entity .Vehicle ;
811import org .jetbrains .annotations .NotNull ;
912import org .jetbrains .annotations .Nullable ;
1013import org .jvnet .hk2 .annotations .Service ;
14+ import org .mvplugins .multiverse .core .api .LocationManipulation ;
1115
16+ /**
17+ *
18+ */
1219@ Service
1320public class AdvancedBlockSafety {
1421
1522 // This will search a maximum of 7 * 6 * 7 = 294 blocks
1623 public static final int DEFAULT_HORIZONTAL_RANGE = 3 ;
1724 public static final int DEFAULT_VERTICAL_RANGE = 2 ;
1825
26+ private final LocationManipulation locationManipulation ;
27+
1928 @ Inject
20- private AdvancedBlockSafety () {
29+ AdvancedBlockSafety (@ NotNull LocationManipulation locationManipulation ) {
30+ this .locationManipulation = locationManipulation ;
2131 }
2232
2333 public boolean playerCanSpawnSafelyAt (@ NotNull Location location ) {
2434 return playerCanSpawnSafelyAt (location .getBlock ());
2535 }
2636
2737 public boolean playerCanSpawnSafelyAt (@ NotNull Block block ) {
38+ Logging .finest ("Checking spawn safety for location: %s, %s, %s" , block .getX (), block .getY (), block .getZ ());
2839 if (isUnsafeSpawnBody (block )) {
2940 // Player body will be stuck in solid
3041 Logging .finest ("Unsafe location for player's body." );
@@ -42,6 +53,7 @@ public boolean playerCanSpawnSafelyAt(@NotNull Block block) {
4253 Logging .finest ("Unsafe location due to invalid platform." );
4354 return false ;
4455 }
56+ Logging .finest ("Location is safe." );
4557 return true ;
4658 }
4759
@@ -79,47 +91,88 @@ private boolean isDeepWater(@NotNull Block block) {
7991 return block .getRelative (0 , -1 , 0 ).getType () == Material .WATER ;
8092 }
8193
94+ /**
95+ *
96+ *
97+ * @param location
98+ * @return The safe location, or null
99+ */
82100 @ Nullable
83101 public Location adjustSafeSpawnLocation (@ NotNull Location location ) {
84102 return adjustSafeSpawnLocation (location , DEFAULT_HORIZONTAL_RANGE , DEFAULT_VERTICAL_RANGE );
85103 }
86104
105+ /**
106+ *
107+ * @param location
108+ * @param horizontalRange
109+ * @param verticalRange
110+ * @return The safe location, or null
111+ */
87112 @ Nullable
88113 public Location adjustSafeSpawnLocation (@ NotNull Location location , int horizontalRange , int verticalRange ) {
89114 Block safeBlock = adjustSafeSpawnBlock (location .getBlock (), horizontalRange , verticalRange );
90115 if (safeBlock == null ) {
91116 return null ;
92117 }
93- Location safeLocation = safeBlock .getLocation ();
94- // Adjust to center of block
95- safeLocation .add (0.5 , 0 , 0.5 );
96- return safeLocation ;
118+ return new Location (
119+ location .getWorld (),
120+ safeBlock .getX () + 0.5 ,
121+ safeBlock .getY (),
122+ safeBlock .getZ () + 0.5 ,
123+ location .getYaw (),
124+ location .getPitch ());
97125 }
98126
127+ /**
128+ *
129+ * @param block
130+ * @return The safe block, or null
131+ */
99132 @ Nullable
100133 public Block adjustSafeSpawnBlock (@ NotNull Block block ) {
101134 return adjustSafeSpawnBlock (block , DEFAULT_HORIZONTAL_RANGE , DEFAULT_VERTICAL_RANGE );
102135 }
103136
137+ /**
138+ *
139+ * @param block
140+ * @param horizontalRange
141+ * @param verticalRange
142+ * @return The safe block, or null
143+ */
104144 @ Nullable
105145 public Block adjustSafeSpawnBlock (@ NotNull Block block , int horizontalRange , int verticalRange ) {
106146 Block searchResult = searchAroundXZ (block , horizontalRange );
107147 if (searchResult != null ) {
108148 return searchResult ;
109149 }
150+ int maxHeight = block .getWorld ().getMaxHeight ();
151+ int minHeight = block .getWorld ().getMinHeight ();
110152 for (int i = 1 ; i <= verticalRange ; i ++) {
111- searchResult = searchAroundXZ (block .getRelative (0 , i , 0 ), horizontalRange );
112- if (searchResult != null ) {
113- return searchResult ;
153+ if (block .getY () + i < maxHeight ) {
154+ searchResult = searchAroundXZ (block .getRelative (0 , i , 0 ), horizontalRange );
155+ if (searchResult != null ) {
156+ return searchResult ;
157+ }
114158 }
115- searchResult = searchAroundXZ (block .getRelative (0 , -i , 0 ), horizontalRange );
116- if (searchResult != null ) {
117- return searchResult ;
159+ if (block .getY () - i >= minHeight ) {
160+ searchResult = searchAroundXZ (block .getRelative (0 , -i , 0 ), horizontalRange );
161+ if (searchResult != null ) {
162+ return searchResult ;
163+ }
118164 }
119165 }
120166 return null ;
121167 }
122168
169+ /**
170+ * Search a square from n - radius to n + radius for both x and z
171+ *
172+ * @param block
173+ * @param radius
174+ * @return The safe block, or null
175+ */
123176 @ Nullable
124177 private Block searchAroundXZ (Block block , int radius ) {
125178 if (playerCanSpawnSafelyAt (block )) {
@@ -147,28 +200,72 @@ private Block searchAroundXZ(Block block, int radius) {
147200 return null ;
148201 }
149202
203+ /**
204+ * Search 4 relative blocks with the following offsets: (-x, -z) (-x, z) (x, -z) (x, z)
205+ *
206+ * @param block The block to be relative to
207+ * @param x Amount to offset for the x axis
208+ * @param z Amount to offset for the z axis
209+ * @return The safe block, or null
210+ */
150211 @ Nullable
151212 private Block searchPlusMinusPermutation (Block block , int x , int z ) {
152- Block relative = block .getRelative (-x , 0 , z );
213+ Block relative = block .getRelative (-x , 0 , - z );
153214 if (playerCanSpawnSafelyAt (relative )) {
154215 return relative ;
155216 }
156- if (x != 0 ) {
157- relative = block .getRelative (-x , 0 , - z );
217+ if (z != 0 ) {
218+ relative = block .getRelative (-x , 0 , z );
158219 if (playerCanSpawnSafelyAt (relative )) {
159220 return relative ;
160221 }
161222 }
162- relative = block .getRelative (x , 0 , z );
163- if (playerCanSpawnSafelyAt (relative )) {
164- return relative ;
165- }
166- if (z != 0 ) {
223+ if (x != 0 ) {
167224 relative = block .getRelative (x , 0 , -z );
168225 if (playerCanSpawnSafelyAt (relative )) {
169226 return relative ;
170227 }
228+ if (z != 0 ) {
229+ relative = block .getRelative (x , 0 , z );
230+ if (playerCanSpawnSafelyAt (relative )) {
231+ return relative ;
232+ }
233+ }
171234 }
172235 return null ;
173236 }
237+
238+ public boolean isBlockAboveAir (Location location ) {
239+ return location .getBlock ().getRelative (0 , -1 , 0 ).getType ().isAir ();
240+ }
241+
242+ /**
243+ *
244+ * @param location
245+ * @return
246+ */
247+ public boolean isEntityOnTrack (Location location ) {
248+ return location .getBlock ().getBlockData () instanceof Rail ;
249+ }
250+
251+ /**
252+ *
253+ * @param cart
254+ * @return
255+ */
256+ public boolean canSpawnCartSafely (Minecart cart ) {
257+ if (isBlockAboveAir (cart .getLocation ())) {
258+ return true ;
259+ }
260+ return isEntityOnTrack (locationManipulation .getNextBlock (cart ));
261+ }
262+
263+ /**
264+ *
265+ * @param vehicle
266+ * @return
267+ */
268+ public boolean canSpawnVehicleSafely (Vehicle vehicle ) {
269+ return isBlockAboveAir (vehicle .getLocation ());
270+ }
174271}
0 commit comments