#Make different entities for different players
1 messages · Page 1 of 1 (latest)
so im gonna explain what I am doing just to clear up any confusion
the moment you first log on, you will spawn on a set of islands and on those islands there may be different mobs and stuff. I want the players to only share entities and stuff once they reach the end which is like a "home base"
its a little complicated
So you want entities only visible to certain players?
i want my entities to almost be seperate for certain players
with their own pathfinding and health
they attack the player who is playing, and not a another player who happens to be also doing the beginning
What version is this for so I can look for specific classes?
1.19.2
kk ty
I guess this is kind of impossible because you would need to create a fake entity and basically rewrite the code as similar to Minecraft’s one
I mean not really impossible
Just really hard
not really
Just figuring out the code for it right now
It this is possible it would be really cool stuff
We should probably make a Library on this
I was thinking maybe hide the entites for one player sort of like how u can hide players from players and then assign each entity a different tag that tells them to only go for a certain player
You may be able to do something like this @rigid torrent
final Zombie zombie = new Zombie(EntityType.ZOMBIE, /* World goes here */);
zombie.targetSelector.removeAllGoals();
zombie.targetSelector.addGoal(0, new NearestAttackableTargetGoal<Player>(zombie, Player.class, true, (livingEntity) -> {
if (!(livingEntity instanceof Player target)) {
return false;
}
return target.getUUID().equals(/* Put the target players UUID in here*/);
}));```
That's the code with mojang mappings
With spigot mappings it's this:
EntityZombie zombie = new EntityZombie(EntityTypes.bj, /* World goes here */);
zombie.bT.a();
zombie.bT.a(0, new PathfinderGoalNearestAttackableTarget(zombie, EntityHuman.class, true, livingEntity -> {
if (!(livingEntity instanceof EntityHuman)) {
return false;
}
EntityHuman target = (EntityHuman)((Object)livingEntity);
return target.co().equals(/* Put the target players UUID in here*/);
}));```
So what does that do
Basically
like brief explenation
this allows the entity to ONLY attack the target player
Will it also pathfind to only the target player
Mojang Mappings: ClientboundRemoveEntitiesPacket
Spigot Mappings: PacketPlayOutEntityDestroy
Like this -
I should probably ask how i would implement something like this
Ive never dealt with packets before
Do i call the above after a player joins?
ClientboundRemoveEntitiesPacket removeEntityPacket = new ClientboundRemoveEntitiesPacket(/* Put the entities id's that you want to hide here*/);
for (final Player nonViewingPlayer : /* Provide the other players that aren't meant to see the enemy here */) {
((CraftPlayer) nonViewingPlayer).getHandle().connection.connection.send(removeEntityPacket);
}```
That's for when the entities spawn in
how do i get an entities id?
what do u mean by that
Does either - ClientboundRemoveEntitiesPacket exist or PacketPlayOutEntityDestroy
If neither, then you have to run buildtools to get NMS code
when i type them in normally just into intellij nothing comes up to autocomplete
Alright
The home of Spigot a high performance, no lag customized CraftBukkit Minecraft server API, and BungeeCord, the cloud server proxy.
Download that, put it in a folder
does build tools work if im using paper
Yeah it should still work
Because paper is built off of spigot
as long as paper hasn't changed anything major, then yeah
after i put it in a folder what do i do
should i just double click to run
java -jar BuildTools.jar --rev 1.19.2 --remapped```
can i just double click
no
It say build success?
oh wait
nvm
it said finished and then started decompiling everything
i see it all
it says Build Success now?
not that but it said Everything completed successfully
yes
Add this dependency and plugin
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.19.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
<classifier>remapped-mojang</classifier>
</dependency>```
<plugin>
<groupId>net.md-5</groupId>
<artifactId>specialsource-maven-plugin</artifactId>
<version>1.2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>remap</goal>
</goals>
<id>remap-obf</id>
<configuration>
<srgIn>org.spigotmc:minecraft-server:1.19.2-R0.1-SNAPSHOT:txt:maps-mojang</srgIn>
<reverse>true</reverse>
<remappedDependencies>org.spigotmc:spigot:1.19.2-R0.1-SNAPSHOT:jar:remapped-mojang
</remappedDependencies>
<remappedArtifactAttached>true</remappedArtifactAttached>
<remappedClassifierName>remapped-obf</remappedClassifierName>
</configuration>
</execution>
<execution>
<phase>package</phase>
<goals>
<goal>remap</goal>
</goals>
<id>remap-spigot</id>
<configuration>
<inputFile>
${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar
</inputFile>
<srgIn>org.spigotmc:minecraft-server:1.19.2-R0.1-SNAPSHOT:csrg:maps-spigot</srgIn>
<remappedDependencies>org.spigotmc:spigot:1.19.2-R0.1-SNAPSHOT:jar:remapped-obf
</remappedDependencies>
</configuration>
</execution>
</executions>
</plugin>```
should have probably put that in a paste
what file do i add it too
in order?
just put the dependency inside of the dependencies section
and put the plugin inside of
<plugins>
</plugins>
</build>```
What is the error?
ah
you clicked this then it appeared? if not, try click the button anyway
okay
Yo
i cant find this exact button
this?
yes
try click this
thats what i did
anywhere on your main drive (I think it has to be on main, not sure tho)
yup
Well, that's weird then lol
try change the version to 1.2.4
and then click this -
it fixed the error
nope!
Awesome
Now we can continue with this
so test if what works again
Check if "ClientboundRemoveEntitiesPacket" exists
found it
pog
it does
this one specifically
yep
i got it
i have an issue tho
not anything code based or anything
just that my test server isnt port forwarded and i have no idea how to test this
?
because like my normal client is still connected
its the same account twice on a server
nah just launch up a cracked account
can i just use a forge build
i dont have a launcher for that
wait nvm
i can just ask a friend to help out with it
ill just put it on a minehut server or something
so where do I put the code blocks u sent
still struggling to understand trhat
You're going to have to implement it yourself. I'm not going to really spoonfeed all the code. But, I will still help to tell you where to put it.
Basically
When a player joins, you may want to create the zombie
right
this one here
mhm
And to actually place it in the world -
level.addFreshEntity(zombie, CreatureSpawnEvent.SpawnReason.CUSTOM);```
Now, that would make it show for every player, but this is just for testing for now
Making sure that the entity actually spawns in
Oh one sec
there, that's the method
which zombie do i import
net.minecraft
same with EntityType?
You may also want to set the zombies position by doing -
zombie.setPos(new Vec3(x, y, z));```
Yep
ok
getting errors when trying to put the world in
final Level level = ((CraftWorld) world).getHandle();
final Zombie zombie = new Zombie(EntityType.ZOMBIE, level);```
basically, what that does, is gets the world in NMS
alright
zombie.targetSelector.addGoal(0, new NearestAttackableTargetGoal<Player>(zombie, Player.class, true, (livingEntity) getting an error with <Player>
saying I should implement LivingEntity instead
now that mobs can attack eachother
zombie.targetSelector.addGoal(0, new NearestAttackableTargetGoal<>(zombie, net.minecraft.world.entity.player.Player.class, true, (livingEntity) -> {```
Since this is NMS code, it required NMS objects
instead of bukkit
bukkit is just an abstracted api on top of NMS
zombie.targetSelector.addGoal(0, new NearestAttackableTargetGoal<net.minecraft.world.entity.player.Player>(zombie, Player.class, true, (livingEntity) ->
this is what i have
change the 2nd player to net.minecraft too
also, you don't need the one inside of the generics
so this will work
alright i did it
Can you send a snippet of your code just to make sure everything is gucci
still getting errors so probably not gucci atm
@EventHandler
public void onJoin(PlayerJoinEvent e){
Player p = e.getPlayer();
final Level level = ((CraftWorld) p.getWorld()).getHandle();
final Zombie zombie = new Zombie(EntityType.ZOMBIE, level);
zombie.targetSelector.removeAllGoals();
zombie.targetSelector.addGoal(0, new NearestAttackableTargetGoal<>(zombie, net.minecraft.world.entity.player.Player.class, true, (livingEntity) ->
{
if (!(livingEntity instanceof Player target)) {
return false;
}
return target.getUUID().equals(/* Put the target players UUID in here*/);
}
));
}
}```
public class OnJoin implements Listener {
@EventHandler
public void onJoin(PlayerJoinEvent event) {
final Player player = event.getPlayer();
final Level level = ((CraftWorld) player.getWorld()).getHandle();
final Zombie zombie = new Zombie(EntityType.ZOMBIE, level);
zombie.targetSelector.removeAllGoals();
zombie.targetSelector.addGoal(0, new NearestAttackableTargetGoal<>(zombie, net.minecraft.world.entity.player.Player.class, true, (livingEntity) ->
{
if (!(livingEntity instanceof net.minecraft.world.entity.player.Player target)) {
return false;
}
return target.getUUID().equals(player.getUUID());
}
));
}
}```
Try that @rigid torrent
oh wait
1 sec
One suggestion to help your code be better for people to read or if you ever join the industry. @rigid torrent - don't use single letter variable names
oh i just like using p because its quick and i use it a lot
i know its not practical but its whatever
do u want me to try the code
or are u doing something
Before you try the code. Make sure you do all this too -
.
.
public void onJoin(PlayerJoinEvent e){
Player p = e.getPlayer();
final Level level = ((CraftWorld) p.getWorld()).getHandle();
final Zombie zombie = new Zombie(EntityType.ZOMBIE, level);
zombie.targetSelector.removeAllGoals();
zombie.setPos(p.getLocation().getX(),p.getLocation().getY(),p.getLocation().getZ());
zombie.targetSelector.addGoal(0, new NearestAttackableTargetGoal<>(zombie, net.minecraft.world.entity.player.Player.class, true, (livingEntity) ->
{
if (!(livingEntity instanceof Player target)) {
return false;
}
return target.getUUID().equals(/* Put the target players UUID in here*/);
}
));
level.addFreshEntity(zombie, CreatureSpawnEvent.SpawnReason.CUSTOM);
}
Do level.addFreshEntity after you do "addGoal"
does that work?
wait im getting errors with getUUID
oh
im dumb
still an error
Patterns in 'instanceof' are not supported at language level '8'
pls dont tell me i gotta update by java version
wait why would u name that there
?
the target
Oh nah
dw
its causing errors somewhere else though
@EventHandler
public void onJoin(PlayerJoinEvent e){
Player p = e.getPlayer();
final Level level = ((CraftWorld) p.getWorld()).getHandle();
final Zombie zombie = new Zombie(EntityType.ZOMBIE, level);
zombie.targetSelector.removeAllGoals();
zombie.setPos(p.getLocation().getX(),p.getLocation().getY(),p.getLocation().getZ());
zombie.targetSelector.addGoal(0, new NearestAttackableTargetGoal<>(zombie, net.minecraft.world.entity.player.Player.class, true, (livingEntity) ->
{
if (!(livingEntity instanceof net.minecraft.world.entity.player.Player target)) {
return false;
}
return ((net.minecraft.world.entity.player.Player) target).getUUID().equals(/* Put the target players UUID in here*/);
}
));
level.addFreshEntity(zombie, CreatureSpawnEvent.SpawnReason.CUSTOM);
}```
i just updated to 16
fairs
no more errors
sickk
and less outdated
so just build and test right
not getting any zombie spawning in
nothign else in my plugin is working either
none of the commands anyway
Drag the -remapped jar from the folder in instead
drag it where
In your server instead
which jar would that be
i cant find it
is it in build tools?
When you build the plugin, what is in the target folder?
the plugin
Wait where are you looking?
the plugins folder
oh
no
the "target" folder
of the plugin you built
there should be a "...-remapped.jar"
where will it build to
to a folder named "target"
in the project?
yea
.
yeah
that one
drag it into plugins and delete old one?
yeah
zombie spawned 😄
immidiantly
Awesome!!
and everything else works
this one?
Yep 😄
so i put that in the join event aswell right
yeah
i need to get the entities that i want to hide though
so when i spawn the entities in
can i give them a tag with the players uuid or something
and then any mob without it loses it
?
because i need to identify who caused the mob to spawn right
to then hide any mob without it
You could probably store the entities in a map or smtn
i dont think a hashmap would be worth if they get immidiantly killed imo
i think ill do the tag thing
i just dont know how to add custom tags to mobs
Thing is, with the map, you can then hide the entities from other players that join the server
how do u get the entities id
.getId()
ok
will try
ill post results here
btw is there a packet to send to the player to make their hearts hardcore hearts
@tacit glade should i save the hashmap to a file?
ig so you know who's entities are who's
wait hold on
for (final Player nonViewingPlayer : /* Provide the other players that aren't meant to see the enemy here */) {
((CraftPlayer) nonViewingPlayer).getHandle().connection.connection.send(removeEntityPacket);
}```
thats what i have so far
i just cant figure out what to do at the bottom
at the bottom?
do you mean "/* Provide the other players that aren't meant to see the enemy here */"? @rigid torrent
yes
List<Player> players = new ArrayList<>(Bukkit.getWorld(/*world name*/).getPlayers());
players.remove(player);
why not amirite
@rigid torrent
?
likie if it were the players in the world, after i joined, the code would have already ran and then they would be able to see my zombie
what
im calling it on an on join event
so think about this
i join the server
my zombie gets hidden for all other players on the server
then if someone else joins
they are not a part of the list
oh yeah
was gonna explain that
basically by storing all the entities in the map, you can then send the packet for removing the zombies
like this:
when im finished with this i am making an api for this because this is complicated
final Map<UUID, Integer> enemiesIds = new HashMap<>();
join event ->
final Player player = event.getPlayer();
final ClientboundRemoveEntitiesPacket clientboundRemoveEntitiesPacket = new ClientboundRemoveEntitiesPacket(this.enemiesIds.values().stream().mapToInt(Integer::intValue).toArray());
((CraftPlayer) player).getHandle().connection.connection.send(clientboundRemoveEntitiesPacket);
something like that @rigid torrent
yea
alright imma try it out
so what exactly does the code do
just brief explenation
because i have no idea how to read that
final ClientboundRemoveEntitiesPacket clientboundRemoveEntitiesPacket = new ClientboundRemoveEntitiesPacket(this.enemiesIds.values().stream().mapToInt(Integer::intValue).toArray());
that just creates the packet
and converts the "Integer" from the map into an array of int's
the Integer in the map refers to the entities id's
that you want to hide from the players
where do i put the players or the zombies
or does it already do that
do i add the zombie to the enemiesIds after spawning it
yea
actually I've got a better idea
final Set<Integer> enemiesIds = new HashSet<>();
join event ->
final Player player = event.getPlayer();
final ClientboundRemoveEntitiesPacket clientboundRemoveEntitiesPacket = new ClientboundRemoveEntitiesPacket(this.enemiesIds.stream().mapToInt(Integer::intValue).toArray());
((CraftPlayer) player).getHandle().connection.connection.send(clientboundRemoveEntitiesPacket);```
@rigid torrent
how is this any different
you don't need a key
less memory usage
and Set's have a smaller memory footprint than lists
enemiesIds.add(zombie.getId()); this would go after it spawns
yep
but i still dont understand how that fixes this
because when a player joins, it will send the remove packet to them - for all the zombies that are going to be hidden
and for existing players?
no need to worry about that, the code below the spawn code should do that
if you kept the ClientboundRemoveEntitiesPacket there
where is there
oh
i still dont have that one
i dont know what to put in the bottom one remember
@rigid torrent
yeah but that would still be current players
?
like wouldnt that still only apply to current players
it will hide it for everyone in the world except the player that joined
can you send me your current code?
yeah but i have not added the ClientboundRemoveEntitiesPacket
final Set<Integer> enemiesIds = new HashSet<>();
@EventHandler
public void onJoin(PlayerJoinEvent e){
Player p = e.getPlayer();
if(p.hasPlayedBefore() == false){
Server.joinedPlayers[Server.joinedPlayers.length + 1] = p;
}
final Level level = ((CraftWorld) p.getWorld()).getHandle();
final Zombie zombie = new Zombie(EntityType.ZOMBIE, level);
zombie.targetSelector.removeAllGoals();
zombie.setPos(p.getLocation().getX(),p.getLocation().getY(),p.getLocation().getZ());
zombie.targetSelector.addGoal(0, new NearestAttackableTargetGoal<>(zombie, net.minecraft.world.entity.player.Player.class, true, (livingEntity) ->
{
if (!(livingEntity instanceof net.minecraft.world.entity.player.Player target)) {
return false;
}
return ((net.minecraft.world.entity.player.Player) target).getUUID().equals(p.getUniqueId());
}
));
level.addFreshEntity(zombie, CreatureSpawnEvent.SpawnReason.CUSTOM);
enemiesIds.add(zombie.getId());
final ClientboundRemoveEntitiesPacket clientboundRemoveEntitiesPacket = new ClientboundRemoveEntitiesPacket(this.enemiesIds.stream().mapToInt(Integer::intValue).toArray());
((CraftPlayer) p).getHandle().connection.connection.send(clientboundRemoveEntitiesPacket);
}
}```
public class OnJoin implements Listener {
private final Set<Integer> enemiesIds = new HashSet<>();
@EventHandler
public void hideAllEntities(PlayerJoinEvent e) {
final Player player = e.getPlayer();
final ClientboundRemoveEntitiesPacket clientboundRemoveEntitiesPacket = new ClientboundRemoveEntitiesPacket(this.enemiesIds.stream().mapToInt(Integer::intValue).toArray());
((CraftPlayer) player).getHandle().connection.connection.send(clientboundRemoveEntitiesPacket);
}
@EventHandler
public void onJoin(PlayerJoinEvent e){
Player p = e.getPlayer();
if(p.hasPlayedBefore() == false){
Server.joinedPlayers[Server.joinedPlayers.length + 1] = p;
}
final Level level = ((CraftWorld) p.getWorld()).getHandle();
final Zombie zombie = new Zombie(EntityType.ZOMBIE, level);
zombie.setPos(p.getLocation().getX(),p.getLocation().getY(),p.getLocation().getZ());
zombie.collides = false;
zombie.targetSelector.removeAllGoals();
zombie.targetSelector.addGoal(0, new NearestAttackableTargetGoal<>(zombie, net.minecraft.world.entity.player.Player.class, true, (livingEntity) -> {
if (!(livingEntity instanceof net.minecraft.world.entity.player.Player target)) {
return false;
}
return ((net.minecraft.world.entity.player.Player) target).getUUID().equals(p.getUniqueId());
}));
level.addFreshEntity(zombie, CreatureSpawnEvent.SpawnReason.CUSTOM);
enemiesIds.add(zombie.getId());
this.hideToOnlinePlayers(p, zombie);
}
private void hideToOnlinePlayers(Player owner, Zombie zombie) {
final ClientboundRemoveEntitiesPacket removeEntityPacket = new ClientboundRemoveEntitiesPacket(zombie.getId());
final List<Player> players = new ArrayList<>(p.getWorld().getPlayers());
players.remove(owner);
for (final Player online : players) {
((CraftPlayer) online).getHandle().connection.connection.send(removeEntityPacket);
}
}
}```
@rigid torrent
do u jut want me to replace that?
when you say p and player in the bottom function what player are u talking about because there is no variable
Fixed @rigid torrent
alright ill try it
Try change "max-entity-collisions" in the spigot.yml and something else to 0 @rigid torrent
Yeah but i would like to have mobs later on collide
question, did you copy all my code that I sent or only add the things you saw
Copy
i havent ran it yet i just thought about it
oh
i wasnt at my pc at the time
ohh ok
😉
@tacit glade i cant test it today but i will definitely let you know when i can and if it works
this needs to become an api sometime in the future
super useful
yet complicated
mob sounds :/
also when a zombie spawns in, the other person, yes, cannot see it
but then if they relog they can see it
how do u delay those
using a bukkit scheduler
do i do it to both or just hideAllEntities
just that one
you want me to put it in a bukkit runnable?
Bukkit.getScheduler().runTaskLater(() -> {
/* Code goes here */
}, 2);
oh alright
the only way i knew how to do it was runnables
Cannot resolve method 'runTaskLater(<lambda expression>, int)'
public void hideAllEntities(PlayerJoinEvent e) {
Bukkit.getScheduler().runTaskLater(() ->{
final Player player = e.getPlayer();
final ClientboundRemoveEntitiesPacket clientboundRemoveEntitiesPacket = new ClientboundRemoveEntitiesPacket(this.enemiesIds.stream().mapToInt(Integer::intValue).toArray());
((CraftPlayer) player).getHandle().connection.connection.send(clientboundRemoveEntitiesPacket);
},2);
}```
oh yeah
the plugin instance
@EventHandler
public void hideAllEntities(PlayerJoinEvent e) {
Bukkit.getScheduler().runTaskLater(plugin, () ->{
final Player player = e.getPlayer();
final ClientboundRemoveEntitiesPacket clientboundRemoveEntitiesPacket = new ClientboundRemoveEntitiesPacket(this.enemiesIds.stream().mapToInt(Integer::intValue).toArray());
((CraftPlayer) player).getHandle().connection.connection.send(clientboundRemoveEntitiesPacket);
},2);
}```
ohh
forgot to add the plugin
let me test
still need a fix for mob sounds
everything else is working great
You fine with the entity being completely silent?
yeah sure its only like 2 zombies and a spider at the very beginning of the game so i dont mind
.setSilent(true)
Yeah
?
ah
do u know
pretty sure you can just do "player.teleport(new Location(/* The world */, x, y, z))"
how would u get the world
Bukkit.getWorld("world name")
alright
is it possible to make somebody see hardcore hearts on their screen using packets
Yeah
how would that work
lemme find it
u dont have to write the code but u can link me to a javadoc or something
Probably going to have to intercept the "ClientboundLoginPacket" @rigid torrent
That contains all the information about the server when the player first joins
and hardcore hearts are through the server.properties so that make sense i guess
yea