Skip to content

Instantly share code, notes, and snippets.

@aadnk
Created February 15, 2014 11:19
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aadnk/9017880 to your computer and use it in GitHub Desktop.
Save aadnk/9017880 to your computer and use it in GitHub Desktop.
A fake entity.
package com.comphenix.example;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitTask;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
public class FakeEntity {
/**
* Retrieve the entity counter field used to generate a unique entity ID.
*/
private static final FieldAccessor ENTITY_ID = Accessors.getFieldAccessor(
MinecraftReflection.getEntityClass(), "entityCount", true);
public List<Player> observers = Lists.newArrayList();
private Location clientLocation;
private Location serverLocation;
private int entityId;
private String name;
private String uuid;
private WrappedDataWatcher watcher;
private boolean changed;
// Update task
private BukkitTask task;
public FakeEntity(Plugin plugin, Location location, String name) {
this.clientLocation = Preconditions.checkNotNull(location, "location cannot be NULL");
this.serverLocation = clientLocation.clone();
this.name = Preconditions.checkNotNull(name, "name cannot be NULL");
this.uuid = UUID.randomUUID().toString();
this.entityId = (Integer) ENTITY_ID.get(null);
this.watcher = new WrappedDataWatcher();
this.watcher.setObject(0, (byte)0);
// Increment next entity ID
ENTITY_ID.set(null, entityId + 1);
// Background worker
Bukkit.getScheduler().runTaskTimer(plugin, new Runnable() {
@Override
public void run() {
updateEntity();
}
}, 1, 1);
}
public void addObserver(Player player) {
notifySpawnEntity(player);
observers.add(player);
}
public void removeObserver(Player player) {
WrapperPlayServerEntityDestroy destroy = new WrapperPlayServerEntityDestroy();
destroy.setEntities(new int[] { entityId });
destroy.sendPacket(player);
observers.remove(player);
}
private void updateEntity() {
// Detect changes
if (changed) {
for (Player player : observers) {
notifySpawnEntity(player);
}
changed = false;
// Update location
} else if (!serverLocation.equals(clientLocation)) {
broadcastMoveEntity();
clientLocation = serverLocation.clone();
}
}
private void notifySpawnEntity(Player player) {
WrapperPlayServerNamedEntitySpawn spawned = new WrapperPlayServerNamedEntitySpawn();
spawned.setEntityID(entityId);
spawned.setPosition(serverLocation.toVector());
spawned.setPlayerName(name);
spawned.setPlayerUUID(uuid);
spawned.setYaw(serverLocation.getYaw());
spawned.setPitch(serverLocation.getPitch());
spawned.setMetadata(watcher);
spawned.sendPacket(player);
}
private void broadcastMoveEntity() {
WrapperPlayServerEntityMoveLook move = new WrapperPlayServerEntityMoveLook();
move.setEntityID(entityId);
move.setDx(serverLocation.getX() - clientLocation.getX());
move.setDy(serverLocation.getY() - clientLocation.getY());
move.setDz(serverLocation.getZ() - clientLocation.getZ());
move.setYaw(serverLocation.getYaw());
move.setPitch(serverLocation.getPitch());
for (Player player : observers) {
move.sendPacket(player);
}
}
/**
* Destroy the current entity.
*/
public void destroy() {
task.cancel();
for (Player player : Lists.newArrayList(observers)) {
removeObserver(player);
}
}
public int getEntityId() {
return entityId;
}
/**
* Retrieve an immutable view of every player observing this entity.
* @return Every observer.
*/
public List<Player> getObservers() {
return Collections.unmodifiableList(observers);
}
public Location getLocation() {
return serverLocation;
}
public void setLocation(Location location) {
this.serverLocation = location;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
this.changed = true;
}
}
@blazedaf
Copy link

Why does this not work in 1.8 Spigot servers? It works fine 1.7.10 and below. Any help in solving this would be appreciated.

@meyerzinn
Copy link

@blazedaf It's becasue the Wrappers have changed.

@WASasquatch
Copy link

Is there any updates for the 3 wrappers used or the new names?

@pluttotv
Copy link

any chance to update it for 1.15.2? :P

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment