Copying entities

OK what I’m doing here is creating a snapshot of an entity and storing it to use later. The plan is to use this snapshot to create multiple entities to spawn in the world. My issue is I’m receiving entity tracking errors.

So the gist is I have the an instance of an Entity so I create a snapshot

EntitySnapshot snapshot = entity.createSnapshot();

Cool no problems there. So now for the new Entity I set a new location on the snapshot.

EntitySnapshot newSnapshot = snapshot.withLocation(location);

Great now I restore the Entity and spawn it in the world

Optional<Entity> optionalEntity = snapshot.restore();

if(optionalEntity.isPresent()) {
    Entity entity = optionalEntity.get();

    location.getExtent().spawnEntity(entity, Cause.of(NamedCause.source(EntitySpawnCause.builder().entity(entity).type(SpawnTypes.PLUGIN).build())));
}

This is where the problem arises.

It seems to be a complete clone of the original Entity. On restart I also recieve these:

[15:28:26] [Server thread/WARN]: Keeping entity Skeleton that already exists with UUID a36dfcf6-0f56-4d96-9b61-a7ebd05a4168
[15:28:26] [Server thread/WARN]: Keeping entity Skeleton that already exists with UUID a36dfcf6-0f56-4d96-9b61-a7ebd05a4168
[15:28:26] [Server thread/WARN]: Keeping entity Skeleton that already exists with UUID a36dfcf6-0f56-4d96-9b61-a7ebd05a4168
[15:28:26] [Server thread/WARN]: Keeping entity Skeleton that already exists with UUID a36dfcf6-0f56-4d96-9b61-a7ebd05a4168
[15:28:26] [Server thread/WARN]: Keeping entity Skeleton that already exists with UUID a36dfcf6-0f56-4d96-9b61-a7ebd05a4168

I’ve tried EntitySnapshot#copy(), same result, tried using EntitySnapshot.builder().from(). Pretty much everything returns the same result so apparently I don’t know what I’m doing.

Basically the only data I care about is the EntityType and any DataManipulators attached so I can create new entities from it later. HELP!:tired_face:

EntitySnapshots are snapshots of entities, if you want to create multiple copies of the entity you need to change the UUID somehow.

I’m not sure if there is any methods for creating entities using snapshots as a base…

However the good news is that there is EntityArchetypes Which are likely a better fit for what you are trying to do.
Archetype

/**
 * A {@link DataHolder} which has no attachment to any particular world allowing
 * it to be used as a blueprint to create multiple copies of its containing
 * data.
 */

vs EntitySnapshot


/**
 * Represents a snapshot of an {@link Entity} and all of it's related data in
 * the form of {@link ImmutableDataManipulator}s and {@link ImmutableValue}s.
 * While an {@link Entity} is a live instance and therefor residing in a
 * {@link World}, an {@link EntitySnapshot} may be snapshotted of a
 * {@link World} that is not currently loaded, or may not exist any longer.
 *
 * <p>All data associated with the {@link EntitySnapshot} should be separated
 * from the {@link Game} instance such that external processing, building,
 * and manipulation can take place.</p>
 */
2 Likes

Exactly as mentioned, EntityArchetypes are what you’re looking for.

Perfect. I completely overlooked EntityArchetype. Thanks guys

What happened to the solution checkbox?

So I can’t seem to deserialize EntityArchetype. I can see it in nbtexplorer so its serializing fine but when I try to deserialize it I get no value present errors when I do getSerializable, followed by the data getting removed

@Override
protected Optional<EntityItemData> buildContent(DataView container) throws InvalidDataException {
	if (!container.contains(ENTITY.getQuery())) {
		return Optional.empty();
	}
	EntityArchetype entity = container.getSerializable(ENTITY.getQuery(), EntityArchetype.class).get();

	return Optional.of(new EntityItemData(entity));
}

Look at the bottom of the exception stack trace:

[13:11:57] [Netty Server IO #1/INFO] [STDERR]: [java.lang.Throwable:printStackTrace:643]: Caused by: java.util.NoSuchElementException: No value present
[13:11:57] [Netty Server IO #1/INFO] [STDERR]: [java.lang.Throwable:printStackTrace:643]:       at java.util.Optional.get(Optional.java:135)
[13:11:57] [Netty Server IO #1/INFO] [STDERR]: [java.lang.Throwable:printStackTrace:643]:       at com.gmail.trentech.mobspawners.data.entity.EntityItemDataManipulatorBuilder.buildContent(EntityItemDataManipulatorBuilder.java:26)
[13:11:57] [Netty Server IO #1/INFO] [STDERR]: [java.lang.Throwable:printStackTrace:643]:       at org.spongepowered.api.data.persistence.AbstractDataBuilder.build(AbstractDataBuilder.java:86)
[13:11:57] [Netty Server IO #1/INFO] [STDERR]: [java.lang.Throwable:printStackTrace:643]:       ... 28 more

Yeah I see that but the data does exist. I can physically see it. Also if that was truly the case then this:

if (!container.contains(ENTITY.getQuery())) {
    return Optional.empty();
}

should have been the stopping point however, line 26 is this

EntityArchetype entity = container.getSerializable(ENTITY.getQuery(), EntityArchetype.class).get();

Anybody? I’ve played around with this and it all comes down to EntityArchetype won’t deserialize. I have two data classes that store EntityArchetype and both fail at the point of deserializing EntityArchetype.

https://github.com/trentech/MobSpawners/blob/dev/src/main/java/com/gmail/trentech/mobspawners/data/spawner/Spawner.java#L358

and here

https://github.com/trentech/MobSpawners/blob/dev/src/main/java/com/gmail/trentech/mobspawners/data/entity/EntityData.java#L83

It’s clearly there as seen here but yet it always returns absent, which tells me the data is malformed or something considering checks show it does contain the DataQuery in question.

Still an issue.

I’ll get a chance tomorrow to review this. I have it bookmarked on my things to do.