summaryrefslogtreecommitdiff
path: root/src/main/kotlin/io/dico/parcels2/Interactable.kt
blob: f1beac5a5d4473376d5ba36e97fe01449b4846aa (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
package io.dico.parcels2

import io.dico.parcels2.util.ext.findWoodKindPrefixedMaterials
import org.bukkit.Material
import java.util.EnumMap

class Interactables
private constructor(val id: Int,
                    val name: String,
                    val interactableByDefault: Boolean,
                    vararg val materials: Material) {

    companion object {
        val classesById: List<Interactables>
        val classesByName: Map<String, Interactables>
        val listedMaterials: Map<Material, Int>

        init {
            val array = getClassesArray()
            classesById = array.asList()
            classesByName = mapOf(*array.map { it.name to it }.toTypedArray())
            listedMaterials = EnumMap(mapOf(*array.flatMap { clazz -> clazz.materials.map { it to clazz.id } }.toTypedArray()))
        }

        private fun getClassesArray() = run {
            var id = 0
            @Suppress("UNUSED_CHANGED_VALUE")
            arrayOf(
                Interactables(id++, "button", true,
                    Material.STONE_BUTTON,
                    *findWoodKindPrefixedMaterials("BUTTON")
                ),

                Interactables(id++, "lever", true,
                    Material.LEVER),

                Interactables(id++, "pressure_plate", true,
                    Material.STONE_PRESSURE_PLATE,
                    *findWoodKindPrefixedMaterials("PRESSURE_PLATE"),
                    Material.HEAVY_WEIGHTED_PRESSURE_PLATE,
                    Material.LIGHT_WEIGHTED_PRESSURE_PLATE),

                Interactables(id++, "redstone_components", false,
                    Material.COMPARATOR,
                    Material.REPEATER),

                Interactables(id++, "containers", false,
                    Material.CHEST,
                    Material.TRAPPED_CHEST,
                    Material.DISPENSER,
                    Material.DROPPER,
                    Material.HOPPER,
                    Material.FURNACE)
            )
        }

    }

}

interface InteractableConfiguration {
    val interactableClasses: List<Interactables> get() = Interactables.classesById.filter { isInteractable(it) }
    fun isInteractable(material: Material): Boolean
    fun isInteractable(clazz: Interactables): Boolean
    fun setInteractable(clazz: Interactables, interactable: Boolean): Boolean
    fun clear(): Boolean
    fun copyFrom(other: InteractableConfiguration) {
        Interactables.classesById.forEach { setInteractable(it, other.isInteractable(it)) }
    }
}

class BitmaskInteractableConfiguration : InteractableConfiguration {
    val bitmaskArray = IntArray((Interactables.classesById.size + 31) / 32)

    private fun isBitSet(classId: Int): Boolean {
        val idx = classId.ushr(5)
        return idx < bitmaskArray.size && bitmaskArray[idx].and(0x1.shl(classId.and(0x1F))) != 0
    }

    override fun isInteractable(material: Material): Boolean {
        val classId = Interactables.listedMaterials[material] ?: return false
        return isBitSet(classId) != Interactables.classesById[classId].interactableByDefault
    }

    override fun isInteractable(clazz: Interactables): Boolean {
        return isBitSet(clazz.id) != clazz.interactableByDefault
    }

    override fun setInteractable(clazz: Interactables, interactable: Boolean): Boolean {
        val idx = clazz.id.ushr(5)
        if (idx >= bitmaskArray.size) return false
        val bit = 0x1.shl(clazz.id.and(0x1F))
        val oldBitmask = bitmaskArray[idx]
        bitmaskArray[idx] = if (interactable != clazz.interactableByDefault) oldBitmask.or(bit) else oldBitmask.and(bit.inv())
        return bitmaskArray[idx] != oldBitmask
    }

    override fun clear(): Boolean {
        var change = false
        for (i in bitmaskArray.indices) {
            change = change || bitmaskArray[i] != 0
            bitmaskArray[i] = 0
        }
        return change
    }

}