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
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
|
package com.earth2me.essentials;
import java.util.List;
import org.bukkit.block.Block;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
/**
* Original authors: toi & Raphfrk
*/
@Deprecated
public class TargetBlock
{
private transient final Location location;
private transient final double viewHeight;
private transient final int maxDistance;
private transient final int[] blockToIgnore;
private transient final double checkDistance;
private transient double curDistance;
private transient double targetPositionX;
private transient double targetPositionY;
private transient double targetPositionZ;
private transient int itargetPositionX;
private transient int itargetPositionY;
private transient int itargetPositionZ;
private transient int prevPositionX;
private transient int prevPositionY;
private transient int prevPositionZ;
private transient final double offsetX;
private transient final double offsetY;
private transient final double offsetZ;
/**
* Constructor requiring a player, uses default values
*
* @param player Player to work with
*/
public TargetBlock(final Player player)
{
this(player.getLocation(), 300, 1.65, 0.2, null);
}
/**
* Constructor requiring a location, uses default values
*
* @param loc Location to work with
*/
public TargetBlock(final Location loc)
{
this(loc, 300, 0, 0.2, null);
}
/**
* Constructor requiring a player, max distance and a checking distance
*
* @param player Player to work with
* @param maxDistance How far it checks for blocks
* @param checkDistance How often to check for blocks, the smaller the more precise
*/
public TargetBlock(final Player player, final int maxDistance, final double checkDistance)
{
this(player.getLocation(), maxDistance, 1.65, checkDistance, null);
}
/**
* Constructor requiring a location, max distance and a checking distance
*
* @param loc What location to work with
* @param maxDistance How far it checks for blocks
* @param checkDistance How often to check for blocks, the smaller the more precise
*/
public TargetBlock(final Location loc, final int maxDistance, final double checkDistance)
{
this(loc, maxDistance, 0, checkDistance, null);
}
/**
* Constructor requiring a player, max distance, checking distance and an array of blocks to ignore
*
* @param player What player to work with
* @param maxDistance How far it checks for blocks
* @param checkDistance How often to check for blocks, the smaller the more precise
* @param blocksToIgnore Integer array of what block ids to ignore while checking for viable targets
*/
public TargetBlock(final Player player, final int maxDistance, final double checkDistance, final int[] blocksToIgnore)
{
this(player.getLocation(), maxDistance, 1.65, checkDistance, blocksToIgnore);
}
/**
* Constructor requiring a location, max distance, checking distance and an array of blocks to ignore
*
* @param loc What location to work with
* @param maxDistance How far it checks for blocks
* @param checkDistance How often to check for blocks, the smaller the more precise
* @param blocksToIgnore Array of what block ids to ignore while checking for viable targets
*/
public TargetBlock(final Location loc, final int maxDistance, final double checkDistance, final int[] blocksToIgnore)
{
this(loc, maxDistance, 0, checkDistance, blocksToIgnore);
}
/**
* Constructor requiring a player, max distance, checking distance and an array of blocks to ignore
*
* @param player What player to work with
* @param maxDistance How far it checks for blocks
* @param checkDistance How often to check for blocks, the smaller the more precise
* @param blocksToIgnore String ArrayList of what block ids to ignore while checking for viable targets
*/
public TargetBlock(final Player player, final int maxDistance, final double checkDistance, final List<String> blocksToIgnore)
{
this(player.getLocation(), maxDistance, 1.65, checkDistance, TargetBlock.convertStringArraytoIntArray(blocksToIgnore));
}
/**
* Constructor requiring a location, max distance, checking distance and an array of blocks to ignore
*
* @param loc What location to work with
* @param maxDistance How far it checks for blocks
* @param checkDistance How often to check for blocks, the smaller the more precise
* @param blocksToIgnore String ArrayList of what block ids to ignore while checking for viable targets
*/
public TargetBlock(final Location loc, final int maxDistance, final double checkDistance, final List<String> blocksToIgnore)
{
this(loc, maxDistance, 0, checkDistance, TargetBlock.convertStringArraytoIntArray(blocksToIgnore));
}
/**
* Set the values, all constructors uses this function
*
* @param loc Location of the view
* @param maxDistance How far it checks for blocks
* @param viewPos Where the view is positioned in y-axis
* @param checkDistance How often to check for blocks, the smaller the more precise
* @param blocksToIgnore Ids of blocks to ignore while checking for viable targets
*/
private TargetBlock(final Location loc, final int maxDistance, final double viewHeight, final double checkDistance, final int[] blocksToIgnore)
{
this.location = loc;
this.maxDistance = maxDistance;
this.viewHeight = viewHeight;
this.checkDistance = checkDistance;
if (blocksToIgnore == null || blocksToIgnore.length == 0)
{
this.blockToIgnore = new int[0];
}
else
{
this.blockToIgnore = new int[blocksToIgnore.length];
System.arraycopy(blocksToIgnore, 0, this.blockToIgnore, 0, this.blockToIgnore.length);
}
final double xRotation = (loc.getYaw() + 90) % 360;
final double yRotation = loc.getPitch() * -1;
final double hypotenuse = (checkDistance * Math.cos(Math.toRadians(yRotation)));
offsetX = hypotenuse * Math.cos(Math.toRadians(xRotation));
offsetY = checkDistance * Math.sin(Math.toRadians(yRotation));
offsetZ = hypotenuse * Math.sin(Math.toRadians(xRotation));
reset();
}
/**
* Call this to reset checking position to allow you to check for a new target with the same TargetBlock instance.
*/
public final void reset()
{
targetPositionX = location.getX();
targetPositionY = location.getY() + viewHeight;
targetPositionZ = location.getZ();
itargetPositionX = (int)Math.floor(targetPositionX);
itargetPositionY = (int)Math.floor(targetPositionY);
itargetPositionZ = (int)Math.floor(targetPositionZ);
prevPositionX = itargetPositionX;
prevPositionY = itargetPositionY;
prevPositionZ = itargetPositionZ;
this.curDistance = 0;
}
/**
* Gets the distance to a block. Measures from the block underneath the player to the targetblock
* Should only be used when passing player as an constructor parameter
*
* @return double
*/
public double getDistanceToBlock()
{
final double blockUnderPlayerX = Math.floor(location.getX() + 0.5);
final double blockUnderPlayerY = Math.floor(location.getY() - 0.5);
final double blockUnderPlayerZ = Math.floor(location.getZ() + 0.5);
final Block block = getTargetBlock();
final double distX = block.getX() - blockUnderPlayerX;
final double distY = block.getY() - blockUnderPlayerY;
final double distZ = block.getZ() - blockUnderPlayerZ;
return Math.sqrt(distX*distX + distY*distY + distZ*distZ);
}
/**
* Gets the rounded distance to a block. Measures from the block underneath the player to the targetblock
* Should only be used when passing player as an constructor parameter
*
* @return int
*/
public int getDistanceToBlockRounded()
{
return (int)Math.round(getDistanceToBlock());
}
/**
* Gets the floored x distance to a block.
*
* @return int
*/
public int getXDistanceToBlock()
{
return (int)Math.floor(getTargetBlock().getX() - location.getBlockX() + 0.5);
}
/**
* Gets the floored y distance to a block
*
* @return int
*/
public int getYDistanceToBlock()
{
return (int)Math.floor(getTargetBlock().getY() - location.getBlockY() + viewHeight);
}
/**
* Gets the floored z distance to a block
*
* @return int
*/
public int getZDistanceToBlock()
{
return (int)Math.floor(getTargetBlock().getZ() - location.getBlockZ() + 0.5);
}
/**
* Returns the block at the sight. Returns null if out of range or if no viable target was found
*
* @return Block
*/
public Block getTargetBlock()
{
this.reset();
Block block;
do
{
block = getNextBlock();
}
while (block != null && ((block.getTypeId() == 0) || this.blockIsIgnored(block.getTypeId())));
return block;
}
/**
* Sets the type of the block at the sight. Returns false if the block wasn't set.
*
* @param typeID ID of type to set the block to
* @return boolean
*/
public boolean setTargetBlock(final int typeID)
{
return setTargetBlock(Material.getMaterial(typeID));
}
/**
* Sets the type of the block at the sight. Returns false if the block wasn't set.
*
* @param type Material to set the block to
* @return boolean
*/
@SuppressWarnings("empty-statement")
public boolean setTargetBlock(final Material type)
{
if (type == null)
{
return false;
}
final Block block = getTargetBlock();
if (block != null)
{
block.setType(type);
return true;
}
return false;
}
/**
* Sets the type of the block at the sight. Returns false if the block wasn't set.
* Observe! At the moment this function is using the built-in enumerator function .valueOf(String) but would preferably be changed to smarter function, when implemented
*
* @param type Name of type to set the block to
* @return boolean
*/
public boolean setTargetBlock(final String type)
{
return setTargetBlock(Material.valueOf(type));
}
/**
* Returns the block attached to the face at the sight. Returns null if out of range or if no viable target was found
*
* @return Block
*/
public Block getFaceBlock()
{
final Block block = getTargetBlock();
if (block == null)
{
return null;
}
return getPreviousBlock();
}
/**
* Sets the type of the block attached to the face at the sight. Returns false if the block wasn't set.
*
* @param typeID
* @return boolean
*/
public boolean setFaceBlock(final int typeID)
{
return setFaceBlock(Material.getMaterial(typeID));
}
/**
* Sets the type of the block attached to the face at the sight. Returns false if the block wasn't set.
*
* @param type
* @return boolean
*/
public boolean setFaceBlock(final Material type)
{
if (type == null)
{
return false;
}
if (getCurrentBlock() != null)
{
final Block blk = location.getWorld().getBlockAt(prevPositionX, prevPositionY, prevPositionZ);
blk.setType(type);
return true;
}
return false;
}
/**
* Sets the type of the block attached to the face at the sight. Returns false if the block wasn't set.
* Observe! At the moment this function is using the built-in enumerator function .valueOf(String) but would preferably be changed to smarter function, when implemented
*
* @param type
* @return boolean
*/
public boolean setFaceBlock(final String type)
{
return setFaceBlock(Material.valueOf(type));
}
/**
* Get next block
*
* @return Block
*/
public Block getNextBlock()
{
prevPositionX = itargetPositionX;
prevPositionY = itargetPositionY;
prevPositionZ = itargetPositionZ;
do
{
curDistance += checkDistance;
targetPositionX += offsetX;
targetPositionY += offsetY;
targetPositionZ += offsetZ;
itargetPositionX = (int)Math.floor(targetPositionX);
itargetPositionY = (int)Math.floor(targetPositionY);
itargetPositionZ = (int)Math.floor(targetPositionZ);
}
while (curDistance <= maxDistance && itargetPositionX == prevPositionX && itargetPositionY == prevPositionY && itargetPositionZ == prevPositionZ);
if (curDistance > maxDistance)
{
return null;
}
return this.location.getWorld().getBlockAt(itargetPositionX, itargetPositionY, itargetPositionZ);
}
/**
* Returns the current block along the line of vision
*
* @return Block
*/
public Block getCurrentBlock()
{
Block block;
if (curDistance <= maxDistance)
{
block = this.location.getWorld().getBlockAt(itargetPositionX, itargetPositionY, itargetPositionZ);
}
else
{
block = null;
}
return block;
}
/**
* Sets current block type. Returns false if the block wasn't set.
*
* @param typeID
*/
public boolean setCurrentBlock(final int typeID)
{
return setCurrentBlock(Material.getMaterial(typeID));
}
/**
* Sets current block type. Returns false if the block wasn't set.
*
* @param type
*/
public boolean setCurrentBlock(final Material type)
{
final Block blk = getCurrentBlock();
if (blk != null && type != null)
{
blk.setType(type);
return true;
}
return false;
}
/**
* Sets current block type. Returns false if the block wasn't set.
* Observe! At the moment this function is using the built-in enumerator function .valueOf(String) but would preferably be changed to smarter function, when implemented
*
* @param type
*/
public boolean setCurrentBlock(final String type)
{
return setCurrentBlock(Material.valueOf(type));
}
/**
* Returns the previous block in the aimed path
*
* @return Block
*/
public Block getPreviousBlock()
{
return this.location.getWorld().getBlockAt(prevPositionX, prevPositionY, prevPositionZ);
}
/**
* Sets previous block type id. Returns false if the block wasn't set.
*
* @param typeID
*/
public boolean setPreviousBlock(final int typeID)
{
return setPreviousBlock(Material.getMaterial(typeID));
}
/**
* Sets previous block type id. Returns false if the block wasn't set.
*
* @param type
*/
public boolean setPreviousBlock(final Material type)
{
final Block blk = getPreviousBlock();
if (blk != null && type != null)
{
blk.setType(type);
return true;
}
return false;
}
/**
* Sets previous block type id. Returns false if the block wasn't set.
* Observe! At the moment this function is using the built-in enumerator function .valueOf(String) but would preferably be changed to smarter function, when implemented
*
* @param type
*/
public boolean setPreviousBlock(final String type)
{
return setPreviousBlock(Material.valueOf(type));
}
private static int[] convertStringArraytoIntArray(final List<String> array)
{
final int intarray[] = new int[array == null ? 0 : array.size()];
for (int i = 0; i < intarray.length; i++)
{
try
{
intarray[i] = Integer.parseInt(array.get(i));
}
catch (NumberFormatException nfe)
{
}
}
return intarray;
}
private boolean blockIsIgnored(final int value)
{
for (int i : this.blockToIgnore)
{
if (i == value)
{
return true;
}
}
return false;
}
}
|