aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/events/RenderEntityOutlineEvent.kt
blob: d061becf9b50eae389778d8b2d58b2fd2865eeea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package at.hannibal2.skyhanni.events

import net.minecraft.client.Minecraft
import net.minecraft.entity.Entity
import net.minecraft.entity.item.EntityArmorStand
import net.minecraft.entity.item.EntityItemFrame
import java.util.function.Consumer

class RenderEntityOutlineEvent(theType: Type?, potentialEntities: HashSet<Entity>?) :
    LorenzEvent() {

    /**
     * The phase of the event (see [Type]
     */
    var type: Type? = null

    /**
     * The entities to outline. This is progressively cumulated from [.entitiesToChooseFrom]
     */
    var entitiesToOutline: HashMap<Entity, Int>? = null

    /**
     * The entities we can outline. Note that this set and [.entitiesToOutline] are disjoint at all times.
     */
    var entitiesToChooseFrom: HashSet<Entity>? = null

    /**
     * Constructs the event, given the type and optional entities to outline.
     *
     *
     * This will modify {@param potentialEntities} internally, so make a copy before passing it if necessary.
     *
     * @param theType of the event (see [Type]
     */
    init {
        type = theType
        entitiesToChooseFrom = potentialEntities
        if (potentialEntities != null) {
            entitiesToOutline = HashMap(potentialEntities.size)
        }
    }

    /**
     * Conditionally queue entities around which to render entities
     * Selects from the pool of [.entitiesToChooseFrom] to speed up the predicate testing on subsequent calls.
     * Is more efficient (theoretically) than calling [.queueEntityToOutline] for each entity because lists are handled internally.
     *
     *
     * This function loops through all entities and so is not very efficient.
     * It's advisable to encapsulate calls to this function with global checks (those not dependent on an individual entity) for efficiency purposes.
     *
     * @param outlineColor a function to test
     */
    fun queueEntitiesToOutline(outlineColor: ((entity: Entity) -> Int?)? = null) {
        if (outlineColor == null) {
            return
        }
        if (entitiesToChooseFrom == null) {
            computeAndCacheEntitiesToChooseFrom()
        }
        val itr: MutableIterator<Entity> = entitiesToChooseFrom!!.iterator()
        while (itr.hasNext()) {
            val e: Entity = itr.next()
            val i: Int? = outlineColor(e)
            if (i != null) {
                entitiesToOutline!![e] = i
                itr.remove()
            }
        }
    }

    /**
     * Adds a single entity to the list of the entities to outline
     *
     * @param entity       the entity to add
     * @param outlineColor the color with which to outline
     */
    fun queueEntityToOutline(entity: Entity?, outlineColor: Int) {
        if (entity == null) {
            return
        }
        if (entitiesToChooseFrom == null) {
            computeAndCacheEntitiesToChooseFrom()
        }
        if (!entitiesToChooseFrom!!.contains(entity)) {
            return
        }
        entitiesToOutline!![entity] = outlineColor
        entitiesToChooseFrom!!.remove(entity)
    }

    /**
     * Used for on-the-fly generation of entities. Driven by event handlers in a decentralized fashion
     */
    private fun computeAndCacheEntitiesToChooseFrom() {
        val entities: List<Entity> = Minecraft.getMinecraft().theWorld.getLoadedEntityList()
        // Only render outlines around non-null entities within the camera frustum
        entitiesToChooseFrom = HashSet(entities.size)
        // Only consider entities that aren't invisible armorstands to increase FPS significantly
        entities.forEach(Consumer<Entity> { e: Entity? ->
            if (e != null && !(e is EntityArmorStand && e.isInvisible()) && e !is EntityItemFrame) {
                entitiesToChooseFrom!!.add(e)
            }
        })
        entitiesToOutline = HashMap(entitiesToChooseFrom!!.size)
    }

    /**
     * The phase of the event.
     * [.XRAY] means that this directly precedes entities whose outlines are rendered through walls (Vanilla 1.9+)
     * [.NO_XRAY] means that this directly precedes entities whose outlines are rendered only when visible to the client
     */
    enum class Type {

        XRAY,
        NO_XRAY
    }
}