How do I get the block under the player? - java

I want to know which block is under the Player .And if the BLock is identical to another block (selected before), do something.
i tried something like this: (But I know it doesn't work at all). Thank you!
BlockPos PlayerIsStandingOn = player.getPosition().down();
Block PlayerIsStandingOnBlock = worldIn.getBlockState(PlayerIsStandingOn);
if (PlayerIsStandingOn == randomBlock) { }

You're close but getBlockState returns IBlockState not Block. You could do it like this:
BlockPos posBelow = player.getPosition().down();
IBlockState blockStateBelow = player.world.getBlockState(posBelow);
then you can either check if the block is a specific material like so, I think this is likely what you're after; this will return if the Material is not GROUND (dirt):
if(blockStateBelow.getMaterial() != Material.GROUND)
return;
//your logic here
Or you can do a comparison to check if two blocks are the same:
if(!Block.isEqualTo(blockStateBelow.getBlock(), <your other block>))
return;
//your logic here
And so on...
Edit
This answer was originally written for 1.12.2, it seems a few things have changed in 1.15.2
BlockPos posBelow = player.getPosition().down();
BlockState blockStateBelow = player.world.getBlockState(posBelow);
Block below = blockStateBelow.getBlock();
if(!below.equals(<your other block>))
return;

Related

How to choose the block that the item can be placed on?

I would like to know how to choose the block that my TNT be placed on. Here is my code.
ItemStack tnt = new ItemStack(Material.TNT, 1);
As in give #p tnt 1 0 {PlaceOn:emerald_block}.
I am using Spigot for Minecraft 1.12 and Eclipse.
There is no way to do that via the Spigot API natively, you need to use NMS and NBT:
net.minecraft.server.v1_12_R1.ItemStack stack = CraftItemStack.asNMSCopy(tnt);
NBTTagList tags = (NBTTagList) stack.getTag().get("CanPlaceOn");
if (tags == null)
tags = new NBTTagList();
tags.add(new NBTTagString("minecraft:emerald_block"));
stack.getTag().set("CanPlaceOn", tags);
ItemStack toUse = CraftItemStack.asCraftMirror(stack);
Generally speaking if you can avoid using NMS you should, and there is a pretty easy way to do this. Whenever a block is placed by a player, a BlockPlaceEvent is called by the server. If you are unsure how they work, look here: http://bukkit.gamepedia.com/Event_API_Reference.
An example of how to handle this behavior is below:
public void onBlockPlace(BlockPlaceEvent e) {
if (e.getBlockPlaced().getType() == Material.TNT) {
Material belowType = e.getBlockPlaced().getRelative(BlockFace.DOWN).getType();
// your code here...
}
}
This code allows you to check if the block that is placed is TNT, then it retrieves the type of the block directly below it.
Hope this helps!!

a nicer way for if (!true) {return;}

I have a big chuck of code witch looks like this
if(!Click(By.linkText("HR Development"))){return;}
if(!Click(By.linkText("ISTQB Agile Tester Extension ( 1/2)"))){return;}
The idea is that the Click function returns true if the click succeeds and false otherwise.
There are also other functions like this outside the click function
does someone know a nicer way to get the same result?
So why not just
return boolean_expression();
whatever that expression evaluates, gets returned.
e.g.
if (foo == bar) {
return true;
} else {
return false;
}
can simply be
return (foo == bar);
You could recast to the equivalent
if (
!Click(By.linkText("HR Development")) ||
!Click(By.linkText("ISTQB Agile Tester Extension ( 1/2)"))
){
return;
}
Note that evaluation of || stops once the result is known. (This is called short-circuitting.)
Littering your functions with many return; statements can make debugging difficult as it can become difficult to set reliable breakpoints.
I have a big chuck of code witch [sic] looks like this
That's your problem. It looks like you've written one click handling class for many events.
Another idea might be to create individual handlers for events and have custom behavior as needed. That would be a more object-oriented approach.
Just make boolean variables out your conditions, and test with a || (or) operator:
boolean foo = !Click(By.linkText("HR Development"));
boolean bar = !Click(By.linkText("ISTQB Agile Tester Extension ( 1/2)"));
if (foo || bar) {
return;
}
It's clean, and if needed, you can add as many variables as you want.

Should I avoid using "!" in if statement in Java?

Our team's Java Coding Guideline says:
Avoid using "!" in if statement as much as possible.
I have asked other colleagues, but no one gave me clear ideas why, because the guideline was created a long time ago and the author might have left our company.
Do you have any idea?
With the information provided, this calls for some speculation. One possible reason is that the intent was not for an if-statement by itself but for an if-else statement. In that case, I can see where you might say that you should reverse the cases so that you don't have the extra operation of the negation. Instead of
if (! boolVar) {
// Something
} else {
// Something else
}
you might prefer
if (boolVar) {
// Something else
} else {
// Something
}
Whether this is worth it or not is probably more a matter of taste and standardization than anything else.
The rule is likely an adaptation from Robert Martin's Clean Code, page 302:
Negatives are just a bit harder to understand than positives. So, when possible, conditionals should be expressed as positives. For example:
if(buffer.shouldCompact())
is preferable to
if(!buffer.shouldNotCompact())
As an example, suppose you're creating a validator that requires two things to be false for the entity to be valid:
The entity must not have been created within the last 12 hours, and
The entity's bank account total sum must not exceed $50,000.
Naturally the idea would be to write two methods for this:
boolean isCreatedWithinLastTwelveHours(BankAccount account)
boolean hasMoreThanTotalSumCap(BankAccount account)
...at which point, you then invoke these as:
boolean newAccount = isCreatedWithinTheLastTwelveHours(account);
boolean highEndAccount = hasMoreThanTotalSumCap(account);
if(!newAccount && !highEndAccount) { // ... other logic
// The more astute would use DeMorgan's law in an effort to make this more readable
if(!(newAccount || highEndAccount)) { // other logic
Well...wouldn't it be nicer if you just said what they weren't instead?
boolean isNotCreatedWithinLastTwelveHours(BankAccount account)
boolean hasLessThanTotalSumCap(BankAccount account)
That'd make the expression a bit more concise:
if(notNewAccount && notHighEndAccount) { // .. carry on!
Of course "!" can be used when you like. There is no "unless" in java and you have no other choices in some conditions.
Looks like yet-another-useless-rule. Generally speaking, there are no absolute terms in this scenario, true that if you are in a if-else clause then possibly it is better to write
if(myCondition) {
doThis()
} else {
doSomethingElse()
}
Instead of
if(!myCondition) {
doSomethingElse()
} else {
doThis()
}
However, that said, in some scenarios is actually quite ok to use the negation operator, particularly if no else clause is provided, example
if (!tokenDoesCompute()) {
throw InvalidTockenException("Whatever")
}
And actually in that scenario, using "!" makes quite a bit of sense for me.
Finally, if no one can really explain WHY the rule is there, maybe it is time to remove it, the only good reason I could find for it would be to provide consistency regarding the code style.
Okay, I answer my own question.
As other say, maybe this is written for the readability.
In The Art of Readable Code (p. 72) says:
Prefer dealing with the positive case first instead of the negative-e.g., if(debug) instead of if(!debug)
I found below post as well:
Readable Code - Remove Checking null
bool func(String name)
{
if ( (name != null) && (name.equals("true") ) {
//...
} else {
//...
}
}
bool func(String name)
{
if ( "true".equals(name) ) {
//...
} else {
//...
}
}
Ofcourse you can use the negation operator ! whenever you like.
However, if you have a situation where you have to write some actions in both if and else block then the following is more readable :
if(status){
//do something
}
else{
//do something else
}
than
if(!status){
//do something
}
else{
//do something else
}
But if you have situation where you only need to perform certain actions based on just one condition, i.e. if you have only an if block & no else block, then it is reasonably fine to use ! in if
I haven't seen anyone else suggest this, which is probably because they hate it as much as I do, but I'm showing it for completeness.
// Using not operator (preferred)
if (! someTest) { ... }
// Using compact not operator (kind of hides it)
if (!someTest) { ... }
// Comparing to false (ok, explicitly states what you want)
if (someTest == false) { ... }
// Comparing to true (a bit obscure)
if (someTest != true) { ... }
They all do the same, but please keep using !, just make sure you add a space after it, so it's easier to see.

Is this usage of a cache map safe in a multithreaded environment?

I'm implementing a LRU cache for photos of users, using Commons Collections LRUMap (which is basicly a LinkedHashMap with small modifications). The findPhoto method can be called several hundred times within a few seconds.
public class CacheHandler {
private static final int MAX_ENTRIES = 1000;
private static Map<Long, Photo> photoCache = Collections.synchronizedMap(new LRUMap(MAX_ENTRIES));
public static Map<Long, Photo> getPhotoCache() {
return photoCache;
}
}
Usage:
public Photo findPhoto(Long userId){
User user = userDAO.find(userId);
if (user != null) {
Map<Long, Photo> cache = CacheHandler.getPhotoCache();
Photo photo = cache.get(userId);
if(photo == null){
if (user.isFromAD()) {
try {
photo = LDAPService.getInstance().getPhoto(user.getLogin());
} catch (LDAPSearchException e) {
throw new EJBException(e);
}
} else {
log.debug("Fetching photo from DB for external user: " + user.getLogin());
UserFile file = userDAO.findUserFile(user.getPhotoId());
if (file != null) {
photo = new Photo(file.getFilename(), "image/png", file.getFileData());
}
}
cache.put(userId, photo);
}else{
log.debug("Fetching photo from cache, user: " + user.getLogin());
}
return photo;
}else{
return null;
}
}
As you can see I'm not using synchronization blocks. I'm assuming that the worst case scenario here is a race condition that causes two threads to run cache.put(userId, photo) for the same userId. But the data will be the same for two threads, so that is not an issue.
Is my reasoning here correct? If not, is there a way to use a synchronization block without getting a large performance hit? Having only 1 thread accessing the map at a time feels like overkill.
Assylias is right that what you've got will work fine.
However, if you want to avoid fetching images more than once, that is also possible, with a bit more work. The insight is that if a thread comes along, makes a cache miss, and starts loading an image, then if a second thread comes along wanting the same image before the first thread has finished loading it, then it should wait for the first thread, rather than going and loading it itself.
This is fairly easy to coordinate using some of Java's simpler concurrency classes.
Firstly, let me refactor your example to pull out the interesting bit. Here's what you wrote:
public Photo findPhoto(User user) {
Map<Long, Photo> cache = CacheHandler.getPhotoCache();
Photo photo = cache.get(user.getId());
if (photo == null) {
photo = loadPhoto(user);
cache.put(user.getId(), photo);
}
return photo;
}
Here, loadPhoto is a method which does the actual nitty-gritty of loading a photo, which isn't relevant here. I assume that the validation of the user is done in another method which calls this one. Other than that, this is your code.
What we do instead is this:
public Photo findPhoto(final User user) throws InterruptedException, ExecutionException {
Map<Long, Future<Photo>> cache = CacheHandler.getPhotoCache();
Future<Photo> photo;
FutureTask<Photo> task;
synchronized (cache) {
photo = cache.get(user.getId());
if (photo == null) {
task = new FutureTask<Photo>(new Callable<Photo>() {
#Override
public Photo call() throws Exception {
return loadPhoto(user);
}
});
photo = task;
cache.put(user.getId(), photo);
}
else {
task = null;
}
}
if (task != null) task.run();
return photo.get();
}
Note that you need to change the type of CacheHandler.photoCache to accommodate the wrapping FutureTasks. And since this code does explicit locking, you can remove the synchronizedMap from it. You could also use a ConcurrentMap for the cache, which would allow the use of putIfAbsent, a more concurrent alternative to the lock/get/check for null/put/unlock sequence.
Hopefully, what is happening here is fairly obvious. The basic pattern of getting something from the cache, checking to see if what you got was null, and if so putting something back in is still there. But instead of putting in a Photo, you put in a Future, which is essentially a placeholder for a Photo which may not (or may) be there right at that moment, but which will become available later. The get method on Future gets the thing that a place is being held for, blocking until it arrives if necessary.
This code uses FutureTask as an implementation of Future; this takes a Callable capable of producing a Photo as a constructor argument, and calls it when its run method is called. The call to run is guarded with a test that essentially recapitulates the if (photo == null) test from earlier, but outside the synchronized block (because as you realised, you really don't want to be loading photos while holding the cache lock).
This is a pattern i've seen or needed a few times. It's a shame it's not built into the standard library somewhere.
Yes you are right - if the photo creation is idempotent (always returns the same photo), the worst thing that can happen is that you will fetch it more than once and put it into the map more than once.

How do I throw and catch an IllegalArgumentException?

So basically I have a GridWorld Project that I'm doing right now in my AP Comp Sci class. I'm doing Pacman. Here is my code for the act method (for those unfamiliar with GridWorld, the act method is called every time an actor is expected to make a new move) :
public void act()
{
Location loc = getLocation();
if(direction==null) {
}
else if(direction.equals("NORTH")) {
Location next = loc.getAdjacentLocation(loc.NORTH);
if(getGrid().isValid(next) && (getGrid().get(next)==null || getGrid().get(next) instanceof Food)) {
if(getGrid().get(next) instanceof Food)
addFood();
moveTo(next);
direction = "NORTH";
}
}
else if(direction.equals("SOUTH")) {
Location next = loc.getAdjacentLocation(loc.SOUTH);
if(getGrid().isValid(next) && (getGrid().get(next)==null || getGrid().get(next) instanceof Food)) {
if(getGrid().get(next) instanceof Food)
addFood();
moveTo(getLocation().getAdjacentLocation(getLocation().SOUTH));
direction = "SOUTH";
}
}
else if(direction.equals("EAST")) {
Location next = loc.getAdjacentLocation(loc.EAST);
if(getGrid().isValid(next) && (getGrid().get(next)==null || getGrid().get(next) instanceof Food)) {
if(getGrid().get(next) instanceof Food)
addFood();
moveTo(getLocation().getAdjacentLocation(getLocation().EAST));
direction = "EAST";
}
else if(getLocation().getCol()==20 && getLocation().getRow()==9) {
moveTo(new Location(9,0));
direction = "EAST";
}
}
else if(direction.equals("WEST")) {
Location next = loc.getAdjacentLocation(loc.WEST);
if(getGrid().isValid(next) && (getGrid().get(next)==null || getGrid().get(next) instanceof Food)) {
moveTo(getLocation().getAdjacentLocation(getLocation().WEST));
direction = "WEST";
}
else if(getLocation().getCol()==0 && getLocation().getRow()==9) {
moveTo(new Location(9,20));
direction = "WEST";
}
}
}
The reason for the weird wording in the last two if statements is bc I want the Pacman to be able to teleport in the real game. Now when I run the game, about 90% of the time it works but in the other 10% I get an IllegalArgumentException bc it says I am trying to move to a place that is not on the board (eg. (9,-1) and (9,21)). I want to know how I can catch or throw or whatever I need to do to stop this from happening. I have never used catch or throw so also please try to explain your reasoning thanks!
To throw an exception, you use keyword throw. To catch, you use the try / catch construct. See this for more details:
http://docs.oracle.com/javase/tutorial/essential/exceptions/try.html
For your case, you'd do something like this - this is a test case:
try {
throw new IllegalArgumentException("Threw an IllegalArgumentException");
} catch(IllegalArgumentException e) {
System.out.println("Caught an IllegalArgumentException..." + e.getMessage());
}
You should, however, look into your code to see why IllegalArgumentException is being thrown anyway and fix that part. Using exceptions and try / catch is for unexpected events, not events that you expect to happen and that you can handle in a better way.
For example, FileNotFoundException gets thrown when a file could not be found. You generally try / catch that, so that you do something if the file was not found. However, if it's expected in a reasonable number of cases that the file might not be there, it would be better to first check if the file exists and then if it does actually do something with it.
You can catch IllegalArgumentException in the same way you catch a normal exception. Typically an IAE comes from a state that invalidates your program, so if you receive a negative index you will need to convert that to its equivalent valid value. In terms of how your program is intended to function, typically a negative index reference is not a good thing.
It seems you want to be able to catch your exceptions to keep your game running, and you are contented with parameters being wrong. So effectively you are using exceptions into the logic of the program, defeating their purpose.
An IllegalArgumentException is a runtime exception, you should not catch them and the program should just fail in some way. Simply make sure that the parameters passed are correct.
You can learn to catch and throw exceptions easily with one of the many tutorials found on Google.
However, and IllegalArgumentException means that some parameter you're sending to a third-party API is wrong. You should debug your application and see what code is causing the trouble, check the API documentation to see the requirements/constraints of the parameters you are breaking and fix it.
Of course, you can only add a catch (IllegalArgunentException e) and do nothing about it. Your program may run, but maybe it can crash later.

Categories