mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Ensure skull operations are done on the player thread
This commit is contained in:
parent
ab540b1951
commit
a1d167d5f1
3 changed files with 37 additions and 30 deletions
|
@ -34,7 +34,6 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
|||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
|
@ -43,17 +42,16 @@ import org.geysermc.connector.network.session.GeyserSession;
|
|||
* custom player skulls in Bedrock.
|
||||
*/
|
||||
public class SkullPlayerEntity extends PlayerEntity {
|
||||
|
||||
/**
|
||||
* Stores the block state that the skull is associated with. Used to determine if the block in the skull's position
|
||||
* has changed
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private int blockState;
|
||||
private final int blockState;
|
||||
|
||||
public SkullPlayerEntity(GameProfile gameProfile, long geyserId, Vector3f position, Vector3f rotation) {
|
||||
public SkullPlayerEntity(GameProfile gameProfile, long geyserId, Vector3f position, Vector3f rotation, int blockState) {
|
||||
super(gameProfile, 0, geyserId, position, Vector3f.ZERO, rotation);
|
||||
this.blockState = blockState;
|
||||
setPlayerList(false);
|
||||
|
||||
//Set bounding box to almost nothing so the skull is able to be broken and not cause entity to cast a shadow
|
||||
|
|
|
@ -883,7 +883,7 @@ public class GeyserSession implements CommandSender {
|
|||
try {
|
||||
runnable.run();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
connector.getLogger().error("Error thrown in " + getName() + "'s event loop!", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -896,7 +896,7 @@ public class GeyserSession implements CommandSender {
|
|||
try {
|
||||
runnable.run();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
connector.getLogger().error("Error thrown in " + getName() + "'s event loop!", e);
|
||||
}
|
||||
}, duration, timeUnit);
|
||||
}
|
||||
|
|
|
@ -123,36 +123,45 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
|
|||
Vector3i blockPosition = Vector3i.from(posX, posY, posZ);
|
||||
Vector3f entityPosition = Vector3f.from(x, y, z);
|
||||
Vector3f entityRotation = Vector3f.from(rotation, 0, rotation);
|
||||
long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet();
|
||||
|
||||
getProfile(tag).whenComplete((gameProfile, throwable) -> {
|
||||
if (gameProfile == null) {
|
||||
session.getConnector().getLogger().debug("Custom skull with invalid SkullOwner tag: " + blockPosition.toString() + " " + tag.toString());
|
||||
session.getConnector().getLogger().debug("Custom skull with invalid SkullOwner tag: " + blockPosition + " " + tag);
|
||||
return;
|
||||
}
|
||||
|
||||
SkullPlayerEntity existingSkull = session.getSkullCache().get(blockPosition);
|
||||
if (existingSkull != null) {
|
||||
// Ensure that two skulls can't spawn on the same point
|
||||
existingSkull.despawnEntity(session, blockPosition);
|
||||
}
|
||||
|
||||
SkullPlayerEntity player = new SkullPlayerEntity(gameProfile, geyserId, entityPosition, entityRotation);
|
||||
player.setBlockState(blockState);
|
||||
|
||||
// Cache entity
|
||||
session.getSkullCache().put(blockPosition, player);
|
||||
|
||||
// Only send to session if we are initialized, otherwise it will happen then.
|
||||
if (session.getUpstream().isInitialized()) {
|
||||
player.spawnEntity(session);
|
||||
|
||||
SkullSkinManager.requestAndHandleSkin(player, session, (skin -> session.scheduleInEventLoop(() -> {
|
||||
// Delay to minimize split-second "player" pop-in
|
||||
player.getMetadata().getFlags().setFlag(EntityFlag.INVISIBLE, false);
|
||||
player.updateBedrockMetadata(session);
|
||||
}, 250, TimeUnit.MILLISECONDS)));
|
||||
if (session.getEventLoop().inEventLoop()) {
|
||||
spawnPlayer(session, gameProfile, blockPosition, entityPosition, entityRotation, blockState);
|
||||
} else {
|
||||
session.executeInEventLoop(() -> spawnPlayer(session, gameProfile, blockPosition, entityPosition, entityRotation, blockState));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void spawnPlayer(GeyserSession session, GameProfile profile, Vector3i blockPosition,
|
||||
Vector3f entityPosition, Vector3f entityRotation, int blockState) {
|
||||
long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet();
|
||||
|
||||
SkullPlayerEntity existingSkull = session.getSkullCache().get(blockPosition);
|
||||
if (existingSkull != null) {
|
||||
// Ensure that two skulls can't spawn on the same point
|
||||
existingSkull.despawnEntity(session, blockPosition);
|
||||
}
|
||||
|
||||
SkullPlayerEntity player = new SkullPlayerEntity(profile, geyserId, entityPosition, entityRotation, blockState);
|
||||
|
||||
// Cache entity
|
||||
session.getSkullCache().put(blockPosition, player);
|
||||
|
||||
// Only send to session if we are initialized, otherwise it will happen then.
|
||||
if (session.getUpstream().isInitialized()) {
|
||||
player.spawnEntity(session);
|
||||
|
||||
SkullSkinManager.requestAndHandleSkin(player, session, (skin -> session.scheduleInEventLoop(() -> {
|
||||
// Delay to minimize split-second "player" pop-in
|
||||
player.getMetadata().getFlags().setFlag(EntityFlag.INVISIBLE, false);
|
||||
player.updateBedrockMetadata(session);
|
||||
}, 250, TimeUnit.MILLISECONDS)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue