// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 using System; using OpenTK; using ClassicalSharp.Events; using ClassicalSharp.GraphicsAPI; using ClassicalSharp.Physics; namespace ClassicalSharp.Entities { public enum NameMode { NoNames, HoveredOnly, All, AllAndHovered, } public enum EntityShadow { None, SnapToBlock, Circle, CircleAll, } public sealed class EntityList : IDisposable { public const int MaxCount = 256; public const byte SelfID = 255; public Entity[] Entities = new Entity[MaxCount]; public Game game; public EntityShadow ShadowMode = EntityShadow.None; byte closestId; /// Mode of how names of hovered entities are rendered (with or without depth testing), /// and how other entity names are rendered. public NameMode NamesMode = NameMode.AllAndHovered; public EntityList(Game game) { this.game = game; game.Graphics.ContextLost += ContextLost; game.Graphics.ContextRecreated += ContextRecreated; game.Events.ChatFontChanged += ChatFontChanged; game.Events.TextureChanged += TextureChanged; NamesMode = Options.GetEnum(OptionsKey.NamesMode, NameMode.HoveredOnly); if (game.ClassicMode) NamesMode = NameMode.HoveredOnly; ShadowMode = Options.GetEnum(OptionsKey.EntityShadow, EntityShadow.None); if (game.ClassicMode) ShadowMode = EntityShadow.None; } /// Performs a tick call for all player entities contained in this list. public void Tick(ScheduledTask task) { for (int i = 0; i < Entities.Length; i++) { if (Entities[i] == null) continue; Entities[i].Tick(task.Interval); } } /// Renders the models of all player entities contained in this list. public void RenderModels(IGraphicsApi gfx, double delta, float t) { gfx.Texturing = true; gfx.AlphaTest = true; for (int i = 0; i < Entities.Length; i++) { if (Entities[i] == null) continue; Entities[i].RenderModel(delta, t); } gfx.Texturing = false; gfx.AlphaTest = false; } /// Renders the names of all player entities contained in this list.
/// If ShowHoveredNames is false, this method only renders names of entities that are /// not currently being looked at by the user.
public void RenderNames(IGraphicsApi gfx, double delta) { if (NamesMode == NameMode.NoNames) return; gfx.Texturing = true; gfx.AlphaTest = true; LocalPlayer localP = game.LocalPlayer; Vector3 eyePos = localP.EyePosition; closestId = SelfID; if (NamesMode != NameMode.All) closestId = GetClosetPlayer(game.LocalPlayer); if (NamesMode == NameMode.HoveredOnly || !game.LocalPlayer.Hacks.CanSeeAllNames) { gfx.Texturing = false; gfx.AlphaTest = false; return; } for (int i = 0; i < Entities.Length; i++) { if (Entities[i] == null) continue; if (i != closestId || i == SelfID) Entities[i].RenderName(); } gfx.Texturing = false; gfx.AlphaTest = false; } public void RenderHoveredNames(IGraphicsApi gfx, double delta) { if (NamesMode == NameMode.NoNames || NamesMode == NameMode.All) return; gfx.Texturing = true; gfx.AlphaTest = true; gfx.DepthTest = false; for (int i = 0; i < Entities.Length; i++) { if (Entities[i] != null && i == closestId && i != SelfID) Entities[i].RenderName(); } gfx.Texturing = false; gfx.AlphaTest = false; gfx.DepthTest = true; } void ContextLost() { for (int i = 0; i < Entities.Length; i++) { if (Entities[i] == null) continue; Entities[i].ContextLost(); } } void ContextRecreated() { for (int i = 0; i < Entities.Length; i++) { if (Entities[i] == null) continue; Entities[i].ContextRecreated(); } } void TextureChanged(object sender, TextureEventArgs e) { if (e.Name != "char.png") return; for (int i = 0; i < Entities.Length; i++) { if (Entities[i] == null || Entities[i].TextureId != -1) continue; Entities[i].SkinType = game.DefaultPlayerSkinType; } } void ChatFontChanged(object sender, EventArgs e) { for (int i = 0; i < Entities.Length; i++) { if (Entities[i] == null) continue; Player p = Entities[i] as Player; if (p != null) p.UpdateName(); } } /// Disposes of all player entities contained in this list. public void Dispose() { for (int i = 0; i < Entities.Length; i++) { if (Entities[i] == null) continue; Entities[i].Despawn(); } game.Graphics.ContextLost -= ContextLost; game.Graphics.ContextRecreated -= ContextRecreated; game.Events.ChatFontChanged -= ChatFontChanged; game.Events.TextureChanged -= TextureChanged; if (ShadowComponent.shadowTex > 0) game.Graphics.DeleteTexture(ref ShadowComponent.shadowTex); } public byte GetClosetPlayer(Player src) { Vector3 eyePos = src.EyePosition; Vector3 dir = Utils.GetDirVector(src.HeadYRadians, src.HeadXRadians); float closestDist = float.PositiveInfinity; byte targetId = SelfID; for (int i = 0; i < Entities.Length - 1; i++) { // -1 because we don't want to pick against local player Entity p = Entities[i]; if (p == null) continue; float t0, t1; if (Intersection.RayIntersectsRotatedBox(eyePos, dir, p, out t0, out t1) && t0 < closestDist) { closestDist = t0; targetId = (byte)i; } } return targetId; } /// Gets or sets the player entity for the specified id. public Entity this[int id] { get { return Entities[id]; } set { Entities[id] = value; if (value != null) value.ID = (byte)id; } } public void DrawShadows() { if (ShadowMode == EntityShadow.None) return; ShadowComponent.boundShadowTex = false; IGraphicsApi gfx = game.Graphics; gfx.AlphaArgBlend = true; gfx.DepthWrite = false; gfx.AlphaBlending = true; gfx.Texturing = true; gfx.SetBatchFormat(VertexFormat.P3fT2fC4b); ((Player)Entities[SelfID]).shadow.Draw(); if (ShadowMode == EntityShadow.CircleAll) DrawOtherShadows(); gfx.AlphaArgBlend = false; gfx.DepthWrite = true; gfx.AlphaBlending = false; gfx.Texturing = false; } void DrawOtherShadows() { for (int i = 0; i < SelfID; i++) { if (Entities[i] == null) continue; Player p = Entities[i] as Player; if (p != null) p.shadow.Draw(); } } } }