[solved]How to get a coordinates within a certain distance from a player?

Ok So What I’m trying to do here is grab a set of coordinates from TeleportHelper.getSafeLocation now. Here’s what I have for that so far

public class SpawnTesting {
public void getSpace(final Player player){
	if (!(player == null)){
		Location<World> location = player.getLocation();
		Optional<Location<World>> newSpawn = Sponge.getGame().getTeleportHelper().getSafeLocation(location, 10, 30);
		
		Sponge.getGame().getServer().getBroadcastChannel().send(Text.of(TextColors.AQUA, newSpawn));
	    }
    }
}

And so far it works…except it gives me the location of the player…not a set of random coordinates within that SafeLocation…help please?

newSpawn is an Optional, you need to check if it contains any reference, and if it does, get this reference before using it:

Optional<Location<World>> newSpawn = Sponge.getGame().getTeleportHelper().getSafeLocation(location, 10, 30);
if(!newSpawn.isPresent) {
  //no safe locations exists, you need to do something in that case
}
Location<World> safeNewSpawn = newSpawn.get();

To get the coordinates of a Location you can simply call Location.getPosition().

1 Like

Ok…but here’s the thing…i’m trying to grab random positions withing that 30block radius if they’re safe to spawn entities. Not my location…I’m only using my location as a focus point.
for example how would i set everything at a 5 block distance to be a new spawn point?

Edit: Perhaps my title was to broad of a question. I’ve updated the title to hopefully solve any confusion.

  1. Create a random vector with with a maximum length of 30
  2. Create a new location by adding this vector to the existing vector position of the player.
  3. Ask the teleport helper if the location is safe. If not, go to 1.
  4. If it doesn’t manage to find a location in n tries, something is wrong (the player is underground for example), fail gracefully.

Ok…that somewhat explains somethings. So I’d have to code for my players vector right.

Then the new vector would be like this:

Vector newVector = new Vector (30);
// code for getting players vector
Vector playerVector = new Vector(x, y, z);

playerVector.add(newVector);

//code for checking if it’s safe or not. …

Am I understandin this right?

And I’d use the teleporthelper to check playerVector then. Right?

AFAIK there is no constructor or convenience method to create a random vector in Sponge. Here is how I prefer to do it. Start with a base unit vector. Rotate it by some random amounts. The expand it by the maximum length.

Also remember that you can get a vector from a Location.

Here is roughly how I would do it with my own vectors. Don’t go looking for these methods on the Sponge vectors. You most likely won’t find them. Here is a link to my own Vector3. It’s written in Scala, but then again it’s mostly just math so it shouldn’t matter too much. https://github.com/Katrix-/DanmakuCore/blob/master/src/main/scala/net/katsstuff/danmakucore/data/vec3.scala (Please excuse the mess in there. It’s been some time since I cleanup up that class.)

playerVec.offset(Vector3.randomVector(), Math.random() * 30D)

K…well here’s what i came up with that is still only getting my player’s location… I’m probably using the wrong method within Vector3d…so how would i set the max?

public class SpawnTesting {
	public void getSpace(final Player player){
	if (!(player == null)){
		Vector3d playersVector = player.getLocation().getPosition();
		playersVector.max(10, 10, 10);
		
		Sponge.getGame().getServer().getBroadcastChannel().send(Text.of(TextColors.AQUA, playersVector));

I’m trying to get a random coordinate within a specific radius of my player…not my players radius lol :’( this is the first time i’ve dealt with vectors to be honest. That’s why I’m a bit confused…I’ve set the ‘max’ method…but it’s still just giving me the players vector.

Edit: this is mainly because there doesn’t seem to be an offset option for vectors…

max for vector is roughly the same as the max you find in Math. Looked through the Vector3d class though and there does seem to be a method to get a random vector, so that shouldn’t be a problem. Once you have your random vector you can’t just add it to the player’s vector as it is. That only offsets the players vector by 1 block (most random vector methods gives you back a unit vector, that is a vector representing a direction with a length of 1). What you want is a vector with a length up to 30. An easy way to change the length of a unit vector to a given value is to scale that unit vector by the desired length (multiplication).

For a better understanding of vectors and what you can do with them I’d recommend you to read a bit over this page. Euclidean vector - Wikipedia

You don’t have to read it all, Vector algebra is the most important to just get the general gist of it. Basic properties can also be nice to read.

I’m sorry to ask this as I know you’re explaining it to me but could you give me an example of the way this would work in sponge?

Get a a random unit vector back from the method in Vector3d. Multiply it with the desired length (in this case a value up to 30). The add this value to the player’s position vector. You now have a vector for some random point within 30 blocks of the player.

1 Like

You are amazing! YoI’ve given me references and examples! And have been patient throughout this! Thank you. I will be trying the above once I’m at home tonight :slight_smile:

K so here’s the new code…

Though I’m not sure where to set the 30 quite… here

Edit: and it definetly doesn’t like that :’( Can you help out with this? You seem to understand it a lot and I just need an example that’ll work in order for me to understand it :frowning:

Nearly there. You need to scala the vector to your desired length. Here that is just a number up to 30. Just to something like angle.multiply(random.nextDouble() * 30D) (Can’t remember the exact method name to multiply with these vectors). Go and look for it yourself. Once you have that you can add it to the player vec like you are currently doing.

Ok… so no errors…however the server doesn’t say anything like it should…Here’s the new code thoughts?

Eh, a step backwards I’d say. The Sponge vectors are immutable, so if you do something to it you also have to assign it to a variable. If not it’s just dead code that won’t do anything. What you want to do is to use trial as the angle vector. As such you need to multiply trial by the desired length. Here’s the correct code to explain it better. Try to read the comments and understand what’s happening.

Vector3d playersVector = player.getLocation().getPosition(); //We get the players current position 
Vector3d angle = Vector3d.createRandomDirection(random); //We create a new random unit vector. This is done by creating a vector from a random pitch and yaw value.
double scale = random.nextDouble() * 30D; //We got some random double, and then multiply it by 30. This will make sure that it goes from 0 to 30 instead of 0 to 1. It's easier to explain if we multiply with 10. Let's say that we have our random double rand. If rand == 0, and we multiply it with 10, it will stay at 0. If rand == 0.1, and we multiply it with 10 it will be 0.1, and so it goes to all values. 
Vector3d scaledVector = angle.mul(scale); //Now that we have our scale, we multiply the angle with the scale. We have to assign it to a variable as Vector3d is immutable. While before angle had just a direction (and a length of 1), it now has both a direction, and the amount to go in that direction. 
Vector3d newVector = playersVector.add(scaledVector); //We add the scaled vector to our player vector, and thus offset the player vector with the scaledVector.
Sponge.getGame().getServer().getBroadcastChannel().send(Text.of(TextColors.AQUA, playersVector));

If you still have problems understanding it, let’s try to think of how it would look if everything was one dimensional instead of three dimensional.

double playersPos = player.getLocation().getPosition(); //If everything was one dimensional, the vectors would be just doubles
double direction = random.nextBoolean() ? 1D : -1D; //In one dimension there are just two ways to go, so a random boolean is enough.
double scale = random.nextDouble() * 30D; //We create our scala again.
double scaledDirection = direction * scale; //We then apply our scale to our direction
double newPos = playerPos + scaledDirection; //We offset the player's current position by our value.
Sponge.getGame().getServer().getBroadcastChannel().send(Text.of(TextColors.AQUA, newPos));
1 Like

…OMG!!! I WAS MAKING THIS in 1D? beats head against table sigh

No you weren’t it was to explain how it works.

OOOh Ok! Phew that was kind of scary lol

So any clue why it won’t send the message? for the location?

If you’re using the code above and it doesn’t send, no idea. Some exception maybe? You’d have to show the rest of your code to be able to help you there. This doesn’t have anything to do with a random position anymore.

1 Like