forked from PaperMC/Paper-1.7
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
266 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
public interface Hologram { | ||
void delete(); | ||
|
||
String getMessage(); | ||
|
||
void setMessage(String paramString); | ||
|
||
Location getLocation(); | ||
|
||
void setMessageHandler(MessageHandler paramMessageHandler); | ||
|
||
Hologram addLineBelow(String text); | ||
|
||
public static interface MessageHandler { | ||
String getMessage(Player param1Player, String param1String); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
237 changes: 237 additions & 0 deletions
237
nPaper-Server/src/main/java/io/noks/cb/CraftHologram.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
package io.noks.cb; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.UUID; | ||
import java.util.WeakHashMap; | ||
|
||
import org.bukkit.Bukkit; | ||
import org.bukkit.Location; | ||
import org.bukkit.craftbukkit.CraftWorld; | ||
import org.bukkit.entity.Player; | ||
|
||
import com.avaje.ebean.validation.NotNull; | ||
|
||
import io.noks.Hologram; | ||
import net.minecraft.server.Chunk; | ||
import net.minecraft.server.DataWatcher; | ||
import net.minecraft.server.Entity; | ||
import net.minecraft.server.EntityPlayer; | ||
import net.minecraft.server.MathHelper; | ||
import net.minecraft.server.PacketPlayOutAttachEntity; | ||
import net.minecraft.server.PacketPlayOutEntityDestroy; | ||
import net.minecraft.server.PacketPlayOutEntityTeleport; | ||
import net.minecraft.server.PacketPlayOutSpawnEntity; | ||
import net.minecraft.server.PacketPlayOutSpawnEntityLiving; | ||
import net.minecraft.server.WorldServer; | ||
|
||
public class CraftHologram implements Hologram { | ||
private static final List<CraftHologram> holograms = new ArrayList<CraftHologram>(); | ||
private String text; | ||
private Location location; | ||
private final int entityId; | ||
private @NotNull final UUID uuid; | ||
private Set<EntityPlayer> viewers = Collections.newSetFromMap(new WeakHashMap<>()); | ||
private final int viewDistance = 32; | ||
private Hologram.MessageHandler messageHandler; | ||
private int playerSearchTick = 0; | ||
|
||
public CraftHologram(Location location, String text) { | ||
this.text = text; | ||
this.location = location; | ||
this.entityId = Entity.entityCount; | ||
Entity.entityCount += 2; | ||
this.uuid = UUID.randomUUID(); | ||
holograms.add(this); | ||
} | ||
|
||
public static void tickAll() { | ||
final Iterator<CraftHologram> iter = holograms.iterator(); | ||
while (iter.hasNext()) { | ||
CraftHologram hologram = iter.next(); | ||
if (hologram.location == null) { | ||
iter.remove(); | ||
continue; | ||
} | ||
hologram.tick(); | ||
} | ||
} | ||
|
||
private void tick() { | ||
if (--this.playerSearchTick < 0) { | ||
this.playerSearchTick = 10; | ||
final double viewDistanceSq = this.viewDistance * this.viewDistance; | ||
final Iterator<EntityPlayer> iter = this.viewers.iterator(); | ||
while (iter.hasNext()) { | ||
EntityPlayer player = iter.next(); | ||
if (shouldRemovePlayer(player, this.location, viewDistanceSq)) { | ||
iter.remove(); | ||
sendDestroyPacket(player); | ||
} | ||
} | ||
WorldServer world = ((CraftWorld) this.location.getWorld()).getHandle(); | ||
int chunkX = this.location.getBlockX() >> 4; | ||
int chunkZ = this.location.getBlockZ() >> 4; | ||
for (int x = chunkX - 1; x <= chunkX + 1; x++) { | ||
for (int z = chunkZ - 1; z <= chunkZ + 1; z++) { | ||
Chunk chunk = world.getChunkIfLoaded(x, z); | ||
if (chunk == null) continue; | ||
|
||
for (EntityPlayer player : chunk.playersInChunk) { | ||
if (!this.viewers.contains(player) && shouldAddPlayer(player, this.location, viewDistanceSq)) { | ||
this.viewers.add(player); | ||
sendSpawnPackets(player); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
private boolean shouldRemovePlayer(EntityPlayer player, Location hologramLocation, double viewDistanceSq) { | ||
return player.dead || player.world.getWorld() != hologramLocation.getWorld() || player.getBukkitEntity().getLocation().distanceSquared(hologramLocation) > viewDistanceSq; | ||
} | ||
|
||
private boolean shouldAddPlayer(EntityPlayer player, Location hologramLocation, double viewDistanceSq) { | ||
return player.getBukkitEntity().getLocation().distanceSquared(hologramLocation) < viewDistanceSq; | ||
} | ||
|
||
public void delete() { | ||
this.location = null; | ||
this.text = null; | ||
for (EntityPlayer player : this.viewers) { | ||
sendDestroyPacket(player); | ||
} | ||
this.viewers = null; | ||
} | ||
|
||
public String getMessage() { | ||
return this.text; | ||
} | ||
|
||
public void setMessage(String msg) { | ||
this.text = msg; | ||
for (EntityPlayer player : this.viewers) { | ||
sendMessagePacket(player); | ||
} | ||
} | ||
|
||
public Location getLocation() { | ||
return this.location; | ||
} | ||
|
||
public void setMessageHandler(Hologram.MessageHandler messageHandler) { | ||
this.messageHandler = messageHandler; | ||
} | ||
|
||
private void sendSpawnPackets(EntityPlayer player) { | ||
if (player.playerConnection.networkManager.getVersion() < 47) { | ||
final PacketPlayOutSpawnEntity skullPacket = new PacketPlayOutSpawnEntity(); | ||
skullPacket.a = this.entityId + 1; | ||
skullPacket.b = MathHelper.floor(this.location.getX() * 32.0D); | ||
skullPacket.c = MathHelper.floor((this.location.getY() + 54.55D) * 32.0D); | ||
skullPacket.d = MathHelper.floor(this.location.getZ() * 32.0D); | ||
skullPacket.j = 64; | ||
final PacketPlayOutAttachEntity attachEntityPacket = new PacketPlayOutAttachEntity(); | ||
attachEntityPacket.leash = 0; | ||
attachEntityPacket.entityId = this.entityId; | ||
attachEntityPacket.vehicleEntityId = this.entityId + 1; | ||
final PacketPlayOutSpawnEntityLiving horsePacket = new PacketPlayOutSpawnEntityLiving(); | ||
horsePacket.a = this.entityId; | ||
horsePacket.b = 100; | ||
horsePacket.c = MathHelper.floor(location.getX() * 32.0D); | ||
horsePacket.d = MathHelper.floor(location.getY() * 32.0D); | ||
horsePacket.e = MathHelper.floor(location.getZ() * 32.0D); | ||
horsePacket.l = new DataWatcher(null); | ||
|
||
horsePacket.l.a(10, getMessageForPlayer(player)); | ||
horsePacket.l.a(11, (byte) 1); | ||
horsePacket.l.a(12, -1700000); | ||
|
||
player.playerConnection.sendPacket(horsePacket); | ||
player.playerConnection.sendPacket(skullPacket); | ||
player.playerConnection.sendPacket(attachEntityPacket); | ||
return; | ||
} | ||
final PacketPlayOutEntityTeleport packetPlayOutEntityTeleport = new PacketPlayOutEntityTeleport(); | ||
packetPlayOutEntityTeleport.a = this.entityId; | ||
packetPlayOutEntityTeleport.b = MathHelper.floor(this.location.getX() * 32.0D); | ||
packetPlayOutEntityTeleport.c = MathHelper.floor((this.location.getY() - 0.25) * 32.0D); | ||
packetPlayOutEntityTeleport.d = MathHelper.floor(this.location.getZ() * 32.0D); | ||
packetPlayOutEntityTeleport.onGround = true; | ||
final PacketPlayOutSpawnEntityLiving armorStandPacket = new PacketPlayOutSpawnEntityLiving(); | ||
armorStandPacket.a = this.entityId; | ||
armorStandPacket.b = 30; | ||
armorStandPacket.c = packetPlayOutEntityTeleport.b; | ||
armorStandPacket.d = packetPlayOutEntityTeleport.c; | ||
armorStandPacket.e = packetPlayOutEntityTeleport.d; | ||
armorStandPacket.l = new DataWatcher(null); | ||
|
||
armorStandPacket.l.a(0, (byte) 0x20); | ||
armorStandPacket.l.a(2, getMessageForPlayer(player)); | ||
armorStandPacket.l.a(3, (byte) 1); | ||
armorStandPacket.l.a(10, (byte) 0x16); | ||
|
||
player.playerConnection.sendPacket(armorStandPacket); | ||
player.playerConnection.sendPacket(packetPlayOutEntityTeleport); | ||
} | ||
|
||
// TODO: ONLY REFRESH WHEN UNTRACKING AND TRACKING BACK WHEN USING THE NON RETRACK METHOD | ||
private void sendMessagePacket(EntityPlayer player) { | ||
this.retrack(player); | ||
/* | ||
final DataWatcher dataWatcher = new DataWatcher(null); | ||
dataWatcher.a((player.playerConnection.networkManager.getVersion() < 47 ? 10 : 2), getMessageForPlayer(player)); | ||
final PacketPlayOutEntityMetadata metadataPacket = new PacketPlayOutEntityMetadata(); | ||
metadataPacket.a = this.entityId; | ||
metadataPacket.b = dataWatcher.b(); | ||
player.playerConnection.sendPacket(metadataPacket);*/ | ||
|
||
} | ||
|
||
/*private void sendMessagePacket(EntityPlayer player) { | ||
PacketPlayOutEntityMetadata metadataPacket = new PacketPlayOutEntityMetadata(); | ||
metadataPacket.a = Entity.entityCount; | ||
metadataPacket.b = new DataWatcher(null).b(); // Initialize an empty DataWatcher and get list of WatchableObjects | ||
metadataPacket.b.add(new WatchableObject(10, 0, getMessageForPlayer(player))); // Add custom name for the hologram | ||
metadataPacket.b.add(new WatchableObject(11, 1, (byte) 1)); // Add flag for custom name | ||
player.playerConnection.sendPacket(metadataPacket); | ||
}*/ | ||
|
||
private void sendDestroyPacket(EntityPlayer player) { | ||
player.playerConnection.sendPacket(new PacketPlayOutEntityDestroy(new int[] { this.entityId, this.entityId + 1 })); | ||
} | ||
|
||
private String getMessageForPlayer(EntityPlayer player) { | ||
String message = this.text; | ||
if (message.contains("{player}")) | ||
message = message.replace("{player}", player.getName()); | ||
if (message.contains("{displayname}")) | ||
message = message.replace("{displayname}", player.getBukkitEntity().getDisplayName()); | ||
if (this.messageHandler != null) | ||
try { | ||
message = this.messageHandler.getMessage((Player) player.getBukkitEntity(), message); | ||
} catch (Exception ex) { | ||
Bukkit.getLogger().severe("Exception in CraftHologram.messageHandler:"); | ||
ex.printStackTrace(); | ||
} | ||
if (message.length() > 64) | ||
message = message.substring(0, 64); | ||
return message; | ||
} | ||
|
||
@Override | ||
public Hologram addLineBelow(String text) { | ||
final Hologram holow = new CraftHologram(location.clone().subtract(0, 0.25, 0), text); | ||
return holow; | ||
} | ||
|
||
// TEMP FIX | ||
private void retrack(EntityPlayer player) { | ||
this.sendDestroyPacket(player); | ||
this.sendSpawnPackets(player); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters