Closed plytki closed 2 years ago
GetEntity does not return the added entity. Instead it is a representation of the stored nbt data using the Entity interface. The actual entities are not accessible at this stage. Just query the chunk/world before and after loading a structure to get the added delta of entities.
I don't want to risk like that. Can't I just get the uuids of entities and then get them or add NBT data to the entity and then based on that identify them when getting entities from chunk? I want it to be stable.
The NMS implementation from mojang removes the UUID tag (and other not known tags) before spawning. There isn't really anything I can do except my previous suggestion because unfortunatly the entity spawning is quite closed.
Another "more stable" suggestion would be to disable spawning entities, collecting them in a list and spawning them yourself after the structure has been placed.
List<StructureEntity<Entity, Location>> structureEntities = new ArrayList<>();
List<Entity> entities = new ArrayList<>(); // Final list of the spawned entities you can fully control
Location targetLocation = ..;
structureBlockLibApi
.loadStructure(plugin)
.at(targetLocation)
.includeEntities(false)
.onProcessEntity(structureEntity -> {
structureEntities.add(structureEntity);
return false;
})
.loadFromPath(..)
.onResult(e -> {
for(StructureEntity<Entity, Location> entity : structureEntities){
Location entityLocation = // I am not sure about this calculation. You need to check it yourself.
targetLocation.clone().add(entity.getSourceLocation());
entity.spawnEntity(entityLocation).ifPresent(addedEntity -> {
entities.add(addedEntity);
});
}
});
The NMS implementation from mojang removes the UUID tag (and other not known tags) before spawning. There isn't really anything I can do except my previous suggestion because unfortunatly the entity spawning is quite closed.
Another "more stable" suggestion would be to disable spawning entities, collecting them in a list and spawning them yourself after the structure has been placed.
List<StructureEntity<Entity, Location>> structureEntities = new ArrayList<>(); List<Entity> entities = new ArrayList<>(); // Final list of the spawned entities you can fully control Location targetLocation = ..; structureBlockLibApi .loadStructure(plugin) .at(targetLocation) .includeEntities(false) .onProcessEntity(structureEntity -> { structureEntities.add(structureEntity); return false; }) .loadFromPath(..) .onResult(e -> { for(StructureEntity<Entity, Location> entity : structureEntities){ Location entityLocation = // I am not sure about this calculation. You need to check it yourself. targetLocation.clone().add(entity.getSourceLocation()); entity.spawnEntity(entityLocation).ifPresent(addedEntity -> { entities.add(addedEntity); }); } });
Does not work for me. I can't get entities to spawn.
There might be a exception swallowed by the completeable futures. Put a try catch around the code in onResult
I got this error, but when I try converting and adding as a vector I get this.
The proper one is on the left side but the pasted one is the right one.
I think I need the rotation processing with my list of entities.
The structureEntity.getEntity may contain the rotation data somewhere. (Maybe in getlocation, getYaw?). It should just be a wrapper around the nbt data.
I don't really know how the API works so It's going to be pain in the ass to solve that issue.
Also when I will base on my calculations I won't have access to rotation API system which is very important for me.
for (StructureEntity<Entity, Location> entity : entities) {
entity.getEntity().ifPresent(virtualEntity -> {
Location entityLocation = // I am not sure about this calculation. You need to check it yourself.
targetLocation.clone().add(entity.getSourceLocation().toVector());
Location l = virtualEntity.getLocation();
entityLocation.setYaw(l.getYaw());
entityLocation.setPitch(l.getPitch());
entity.spawnEntity( entityLocation);
});
}
Did you try it like that?
Yes
The only way I got it working is this but It's not the nicest way to do that. "/ If there is going be other way to do that please inform me.
System.out.println("trying to place furniture");
this.placing = true;
Set<Entity> beforePasting = new HashSet<>();
HashMap<Long, Chunk> chunks = new HashMap<>();
StructureBlockLibApi.INSTANCE
.loadStructure(plugin)
.at(targetLocation)
.includeEntities(true)
.onProcessEntity(e -> {
e.getEntity().ifPresent(entity -> {
Location entityLocation = targetLocation.clone().add(e.getSourceLocation().toVector());
Chunk chunk = entityLocation.getChunk();
if (!chunks.containsKey(chunk.getChunkKey())) {
chunks.put(chunk.getChunkKey(), chunk);
}
Chunk chunk2 = entity.getChunk();
if (!chunks.containsKey(chunk2.getChunkKey())) {
chunks.put(chunk2.getChunkKey(), chunk2);
}
});
return false;
})
.onProcessBlock(e -> false)
.rotation(rotation)
.loadFromPath(nbtFile.toPath())
.onException(e -> plugin.getLogger().log(Level.SEVERE, "Failed to load structure.", e))
.onResult(e -> {
this.usedChunks = new HashMap<>(chunks);
chunks.forEach((aLong, chunk) -> {
beforePasting.addAll(Arrays.asList(chunk.getEntities()));
});
StructureBlockLibApi.INSTANCE
.loadStructure(plugin)
.at(targetLocation)
.includeEntities(true)
.onProcessEntity(process -> true)
.onProcessBlock(process -> false)
.rotation(rotation)
.loadFromPath(nbtFile.toPath())
.onException(process -> plugin.getLogger().log(Level.SEVERE, "Failed to load structure.", process))
.onResult(process -> {
new BukkitRunnable() {
@Override
public void run() {
Set<Entity> allEntities = new HashSet<>();
usedChunks.forEach((aLong, chunk) -> {
System.out.println("checking chunk: " + aLong);
for (Entity entity : chunk.getEntities()) {
if (!(entity instanceof Player)) {
allEntities.add(entity);
}
}
});
plugin.getLogger().log(Level.INFO, ChatColor.GREEN + "Loaded structure '" + nbtFile.getName() + "'.");
allEntities.removeAll(beforePasting);
entities = allEntities;
System.out.println(entities.size());
placing = false;
}
}.runTaskLater(PartiEffects.getInstance(), 5);
});
});
Nice that you got it to work. This behaviour wasn't really the intention of the API (just basic loading/saving structures), so I guess this is the way to do it.
I'll paste my final code here in case anyone would need it too.
Set<Entity> beforePasting = new HashSet<>();
StructureBlockLibApi.INSTANCE
.loadStructure(plugin)
.at(targetLocation)
.includeEntities(true)
.onProcessEntity(e -> {
e.getEntity().ifPresent(entity -> {
Location entityLocation = targetLocation.clone().add(e.getSourceLocation().toVector());
Chunk chunk = entityLocation.getChunk();
if (!usedChunks.containsKey(chunk.getChunkKey())) {
usedChunks.put(chunk.getChunkKey(), chunk);
}
});
return false;
})
.onProcessBlock(e -> false)
.rotation(rotation)
.loadFromPath(nbtFile.toPath())
.onException(e -> plugin.getLogger().log(Level.SEVERE, "Failed to load structure.", e))
.onResult(e -> {
usedChunks.forEach((aLong, chunk) -> {
beforePasting.addAll(Arrays.asList(chunk.getEntities()));
});
StructureBlockLibApi.INSTANCE
.loadStructure(plugin)
.at(targetLocation)
.includeEntities(true)
.onProcessEntity(process -> true)
.onProcessBlock(process -> false)
.rotation(rotation)
.loadFromPath(nbtFile.toPath())
.onException(process -> plugin.getLogger().log(Level.SEVERE, "Failed to load structure.", process))
.onResult(process -> {
Set<Entity> allEntities = new HashSet<>();
usedChunks.forEach((aLong, chunk) -> {
//System.out.println("checking chunk: " + aLong);
for (Entity entity : chunk.getEntities()) {
if (!(entity instanceof Player)) {
allEntities.add(entity);
}
}
});
allEntities.removeAll(beforePasting);
entities = allEntities;
for (Entity entity : entities) {
assignData(entity);
}
//System.out.println(entities.size());
placing = false;
plugin.getLogger().log(Level.INFO, "Loaded structure '" + nbtFile.getName() + "'.");
});
});
Also you have to block from placing other entities in the chunks that are affected by the structurelib during pasting the structure.
I'm handling the entities and I'm adding them to list and I'm trying to remove them later. I store entities in a list. But when I try to remove them they are not removing.
What's wrong with that?