Skip to content

Commit

Permalink
[EXPERIMENTAL] Add fake_player custom entity type
Browse files Browse the repository at this point in the history
Currently, pretty much all they can do is stand there. But it's a start.
To give them a name, do "fake_player[name=Dinnerbone]" or the like
  • Loading branch information
Morphan1 committed Feb 21, 2015
1 parent d38a1ab commit 0115332
Show file tree
Hide file tree
Showing 11 changed files with 381 additions and 9 deletions.
2 changes: 2 additions & 0 deletions src/main/java/net/aufdemrand/denizen/Denizen.java
Expand Up @@ -25,6 +25,7 @@
import net.aufdemrand.denizen.tags.BukkitTagContext;
import net.aufdemrand.denizen.tags.core.*;
import net.aufdemrand.denizen.utilities.entity.CraftFakeArrow;
import net.aufdemrand.denizen.utilities.entity.CraftFakePlayer;
import net.aufdemrand.denizen.utilities.entity.CraftItemProjectile;
import net.aufdemrand.denizen.utilities.entity.DenizenEntityType;
import net.aufdemrand.denizencore.events.OldEventManager;
Expand Down Expand Up @@ -414,6 +415,7 @@ public void onEnable() {
// Register DenizenEntityTypes
DenizenEntityType.registerEntityType("ITEM_PROJECTILE", CraftItemProjectile.class);
DenizenEntityType.registerEntityType("FAKE_ARROW", CraftFakeArrow.class);
DenizenEntityType.registerEntityType("FAKE_PLAYER", CraftFakePlayer.class);

// Track all player names for quick dPlayer matching
for (OfflinePlayer player: Bukkit.getOfflinePlayers()) {
Expand Down
Expand Up @@ -3,6 +3,7 @@
import net.aufdemrand.denizen.utilities.DenizenAPI;
import net.aufdemrand.denizen.utilities.Utilities;
import net.aufdemrand.denizen.utilities.entity.CraftFakeArrow;
import net.aufdemrand.denizencore.objects.Mechanism;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;

Expand All @@ -16,6 +17,8 @@
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.vehicle.VehicleExitEvent;

import java.util.ArrayList;

public class SittingTrait extends Trait implements Listener {

@Persist("sitting")
Expand Down Expand Up @@ -69,7 +72,7 @@ public void sit() {
}

private void sitInternal() {
CraftFakeArrow.createArrow(npc.getEntity().getLocation()).setPassenger(npc.getEntity());
CraftFakeArrow.createArrow(npc.getEntity().getLocation(), new ArrayList<Mechanism>()).setPassenger(npc.getEntity());
//PlayerAnimation.SIT.play((Player)npc.getEntity());
//eh.getDataWatcher().watch(0, (byte) 0x04);
sitting = true;
Expand Down
11 changes: 7 additions & 4 deletions src/main/java/net/aufdemrand/denizen/objects/dEntity.java
Expand Up @@ -60,7 +60,7 @@ public static boolean isCitizensNPC(Entity entity) {
}

public static dNPC getNPCFrom(Entity entity) {
if (isNPC(entity))
if (isCitizensNPC(entity))
return dNPC.fromEntity(entity);
else
return null;
Expand Down Expand Up @@ -522,7 +522,7 @@ public dPlayer getDenizenPlayer() {
*/

public boolean isPlayer() {
return !isNPC() && entity instanceof Player;
return entity instanceof Player && !isNPC();
}

/**
Expand Down Expand Up @@ -735,7 +735,7 @@ public void spawnAt(Location location) {
}
// Else, use the entity_type specified/remembered
else
entity = entity_type.spawnNewEntity(location);
entity = entity_type.spawnNewEntity(location, mechanisms);

getLivingEntity().teleport(location);
getLivingEntity().getEquipment().setArmorContents(despawned_entity.equipment);
Expand Down Expand Up @@ -801,8 +801,11 @@ else if (entity_type.getName().equals("FALLING_BLOCK")) {
}
else {

ent = entity_type.spawnNewEntity(location);
ent = entity_type.spawnNewEntity(location, mechanisms);
entity = ent;
if (entity == null) {
return;
}
uuid = entity.getUniqueId();
if (entityScript != null)
EntityScriptHelper.setEntityScript(entity, entityScript);
Expand Down
@@ -1,6 +1,7 @@
package net.aufdemrand.denizen.utilities.entity;

import net.aufdemrand.denizen.utilities.debugging.dB;
import net.aufdemrand.denizencore.objects.Mechanism;
import net.minecraft.server.v1_8_R1.EntityArrow;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R1.CraftServer;
Expand All @@ -13,6 +14,7 @@
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;

import java.util.ArrayList;
import java.util.Set;

public class CraftFakeArrow extends CraftArrow implements DenizenCustomEntity, Vehicle {
Expand All @@ -33,7 +35,7 @@ public void remove() {
}

@CreateEntity
public static Arrow createArrow(Location location) {
public static Arrow createArrow(Location location, ArrayList<Mechanism> mechanisms) {
CraftWorld world = (CraftWorld) location.getWorld();
EntityArrow arrow = new FakeArrowEntity(world, location);
return (Arrow) arrow.getBukkitEntity();
Expand Down
@@ -0,0 +1,114 @@
package net.aufdemrand.denizen.utilities.entity;

import com.mojang.authlib.GameProfile;
import net.aufdemrand.denizen.objects.properties.item.ItemSkullskin;
import net.aufdemrand.denizen.utilities.DenizenAPI;
import net.aufdemrand.denizen.utilities.debugging.dB;
import net.aufdemrand.denizen.utilities.packets.PacketHelper;
import net.aufdemrand.denizencore.objects.Mechanism;
import net.minecraft.server.v1_8_R1.*;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R1.CraftServer;
import org.bukkit.craftbukkit.v1_8_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_8_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.metadata.MetadataValue;
import org.bukkit.plugin.Plugin;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class CraftFakePlayer extends CraftPlayer implements DenizenCustomEntity {

private static final Field gameProfileId;
private final CraftServer server;

static {
Field field = null;
try {
field = GameProfile.class.getDeclaredField("id");
field.setAccessible(true);
} catch (Exception e) {
dB.echoError(e);
}
gameProfileId = field;
}

public CraftFakePlayer(CraftServer server, EntityFakePlayer entity) {
super(server, entity);
this.server = server;
setMetadata("NPC", new FixedMetadataValue(DenizenAPI.getCurrentInstance(), true));
}

@CreateEntity
public static Player createFakePlayer(Location location, ArrayList<Mechanism> mechanisms) {
String name = null;
for (Mechanism mechanism : mechanisms) {
if (mechanism.matches("name"))
name = mechanism.getValue().asString();
}
if (name == null || name.length() == 0 || name.length() > 16) {
dB.echoError("You must specify a name with no more than 16 characters for FAKE_PLAYER entities!");
return null;
}
CraftWorld world = (CraftWorld) location.getWorld();
WorldServer worldServer = world.getHandle();
GameProfile gameProfile = new GameProfile(null, name);
gameProfile = ItemSkullskin.fillGameProfile(gameProfile);
UUID uuid = UUID.randomUUID();
if (uuid.version() == 4) {
long msb = uuid.getMostSignificantBits();
msb &= ~0x0000000000004000L;
msb |= 0x0000000000002000L;
uuid = new UUID(msb, uuid.getLeastSignificantBits());
}
setProfileId(gameProfile, uuid);

EntityFakePlayer fakePlayer = new EntityFakePlayer(worldServer.getMinecraftServer(), worldServer, gameProfile,
new PlayerInteractManager(worldServer));
fakePlayer.setPositionRotation(location.getX(), location.getY(), location.getZ(),
location.getYaw(), location.getPitch());
PacketPlayOutNamedEntitySpawn spawnPacket = new PacketPlayOutNamedEntitySpawn(fakePlayer);
for (Player player : Bukkit.getServer().getOnlinePlayers()) {
PacketHelper.sendPacket(player, spawnPacket);
}
return fakePlayer.getBukkitEntity();
}

private static void setProfileId(GameProfile gameProfile, UUID uuid) {
try {
gameProfileId.set(gameProfile, uuid);
} catch (Exception e) {
dB.echoError(e);
}
}

@Override
public void setMetadata(String metadataKey, MetadataValue newMetadataValue) {
this.server.getEntityMetadata().setMetadata(this, metadataKey, newMetadataValue);
}

@Override
public List<MetadataValue> getMetadata(String metadataKey) {
return this.server.getEntityMetadata().getMetadata(this, metadataKey);
}

@Override
public boolean hasMetadata(String metadataKey) {
return this.server.getEntityMetadata().hasMetadata(this, metadataKey);
}

@Override
public void removeMetadata(String metadataKey, Plugin owningPlugin) {
this.server.getEntityMetadata().removeMetadata(this, metadataKey, owningPlugin);
}

@Override
public String getEntityTypeName() {
return "FAKE_PLAYER";
}
}
@@ -1,5 +1,6 @@
package net.aufdemrand.denizen.utilities.entity;

import net.aufdemrand.denizencore.objects.Mechanism;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R1.CraftServer;
import org.bukkit.craftbukkit.v1_8_R1.CraftWorld;
Expand All @@ -9,6 +10,8 @@
import org.bukkit.entity.LivingEntity;
import org.bukkit.projectiles.ProjectileSource;

import java.util.ArrayList;

public class CraftItemProjectile extends CraftItem implements DenizenCustomEntity, ItemProjectile {

private boolean doesBounce;
Expand All @@ -18,7 +21,7 @@ public CraftItemProjectile(CraftServer server, EntityItemProjectile entity) {
}

@CreateEntity
public static ItemProjectile createItemProjectile(Location location) {
public static ItemProjectile createItemProjectile(Location location, ArrayList<Mechanism> mechanisms) {
CraftWorld world = (CraftWorld) location.getWorld();
EntityItemProjectile entity = new EntityItemProjectile(world, location);
return (ItemProjectile) entity.getBukkitEntity();
Expand Down
@@ -1,6 +1,7 @@
package net.aufdemrand.denizen.utilities.entity;

import net.aufdemrand.denizen.utilities.debugging.dB;
import net.aufdemrand.denizencore.objects.Mechanism;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_8_R1.entity.CraftEntity;
Expand All @@ -9,6 +10,7 @@
import org.bukkit.inventory.ItemStack;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -65,14 +67,14 @@ private DenizenEntityType(String name, Class<? extends DenizenCustomEntity> enti
this.createMethod = finalMethod;
}

public Entity spawnNewEntity(Location location) {
public Entity spawnNewEntity(Location location, ArrayList<Mechanism> mechanisms) {
try {
if (name.equals("DROPPED_ITEM"))
return location.getWorld().dropItem(location, new ItemStack(Material.STONE));
else if (!isCustom())
return location.getWorld().spawnEntity(location, bukkitEntityType);
else
return (Entity) createMethod.invoke(null, location);
return (Entity) createMethod.invoke(null, location, mechanisms);
} catch (Exception e) {
dB.echoError(e);
}
Expand Down
@@ -0,0 +1,109 @@
package net.aufdemrand.denizen.utilities.entity;

import com.mojang.authlib.GameProfile;
import net.aufdemrand.denizen.utilities.DenizenAPI;
import net.aufdemrand.denizen.utilities.debugging.dB;
import net.aufdemrand.denizen.utilities.entity.network.FakeNetworkManager;
import net.aufdemrand.denizen.utilities.entity.network.FakePlayerConnection;
import net.aufdemrand.denizen.utilities.packets.PacketHelper;
import net.minecraft.server.v1_8_R1.*;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_8_R1.CraftServer;
import org.bukkit.craftbukkit.v1_8_R1.entity.CraftPlayer;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.scheduler.BukkitRunnable;

import java.lang.reflect.Field;
import java.util.Set;

public class EntityFakePlayer extends EntityPlayer {

private static final Field entryFlag;
private static final Field trackerSet;

static {
Field entryFlagField = null;
Field trackerSetField = null;
try {
entryFlagField = EntityTrackerEntry.class.getDeclaredField("u");
entryFlagField.setAccessible(true);
trackerSetField = EntityTracker.class.getDeclaredField("c");
trackerSetField.setAccessible(true);
} catch (Exception e) {
dB.echoError(e);
}
entryFlag = entryFlagField;
trackerSet = trackerSetField;
}

public EntityFakePlayer(MinecraftServer minecraftserver, WorldServer worldserver, GameProfile gameprofile, PlayerInteractManager playerinteractmanager) {
super(minecraftserver, worldserver, gameprofile, playerinteractmanager);
playerinteractmanager.setGameMode(EnumGamemode.SURVIVAL);
NetworkManager networkManager = new FakeNetworkManager(EnumProtocolDirection.CLIENTBOUND);
playerConnection = new FakePlayerConnection(minecraftserver, networkManager, this);
networkManager.a(playerConnection);
datawatcher.watch(10, (byte) 127);
this.bukkitEntity = new CraftFakePlayer((CraftServer) Bukkit.getServer(), this);
worldserver.addEntity(this, CreatureSpawnEvent.SpawnReason.CUSTOM);
EntityTrackerEntry entry = (EntityTrackerEntry) worldserver.getTracker().trackedEntities.get(getId());
FakePlayerEntityTrackerEntry newEntry = new FakePlayerEntityTrackerEntry(entry);
worldserver.getTracker().trackedEntities.a(getId(), newEntry);
try {
Set set = (Set) trackerSet.get(worldserver.getTracker());
set.remove(entry);
set.add(newEntry);
} catch (Exception e) {
dB.echoError(e);
}
}

@Override
public CraftFakePlayer getBukkitEntity() {
return (CraftFakePlayer) bukkitEntity;
}

private static boolean getFlag(EntityTrackerEntry entry) {
try {
return entryFlag.getBoolean(entry);
} catch (Exception e) {
return false;
}
}

public class FakePlayerEntityTrackerEntry extends EntityTrackerEntry {

public FakePlayerEntityTrackerEntry(EntityTrackerEntry entry) {
super(entry.tracker, entry.b, entry.c, getFlag(entry));
}

@Override
public void updatePlayer(final EntityPlayer entityplayer) {
if(entityplayer != this.tracker) {
if (this.c(entityplayer)) {
if (!this.trackedPlayers.contains(entityplayer)
&& (entityplayer.u().getPlayerChunkMap().a(entityplayer, this.tracker.ae, this.tracker.ag)
|| this.tracker.attachedToPlayer)) {
if (this.tracker instanceof EntityPlayer) {
CraftPlayer player = ((EntityPlayer)this.tracker).getBukkitEntity();
if(!entityplayer.getBukkitEntity().canSee(player)) {
return;
}
final PacketPlayOutPlayerInfo[] playerListPacket = {new PacketPlayOutPlayerInfo(
EnumPlayerInfoAction.ADD_PLAYER, (EntityPlayer) this.tracker)};
PacketHelper.sendPacket(entityplayer.getBukkitEntity(), playerListPacket[0]);
new BukkitRunnable() {
@Override
public void run() {
playerListPacket[0] = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER,
(EntityPlayer) tracker);
PacketHelper.sendPacket(entityplayer.getBukkitEntity(), playerListPacket[0]);
}
}.runTaskLater(DenizenAPI.getCurrentInstance(), 2);
}
}
}
}
super.updatePlayer(entityplayer);
}
}
}

0 comments on commit 0115332

Please sign in to comment.