port to MC 1.8
This commit is contained in:
223
src/main/kotlin/mods/octarinecore/common/Geometry.kt
Normal file
223
src/main/kotlin/mods/octarinecore/common/Geometry.kt
Normal file
@@ -0,0 +1,223 @@
|
||||
package mods.octarinecore.common
|
||||
|
||||
import mods.octarinecore.cross
|
||||
import net.minecraft.util.BlockPos
|
||||
import net.minecraft.util.EnumFacing
|
||||
import net.minecraft.util.EnumFacing.*
|
||||
import net.minecraft.util.EnumFacing.Axis.*
|
||||
import net.minecraft.util.EnumFacing.AxisDirection.*
|
||||
|
||||
// ================================
|
||||
// Axes and directions
|
||||
// ================================
|
||||
val axes = listOf(X, Y, Z)
|
||||
val axisDirs = listOf(POSITIVE, NEGATIVE)
|
||||
val EnumFacing.dir: AxisDirection get() = axisDirection
|
||||
val AxisDirection.sign: String get() = when(this) { POSITIVE -> "+"; NEGATIVE -> "-" }
|
||||
val forgeDirs = EnumFacing.values()
|
||||
val forgeDirOffsets = forgeDirs.map { Int3(it) }
|
||||
val Pair<Axis, AxisDirection>.face: EnumFacing get() = when(this) {
|
||||
X to POSITIVE -> EAST; X to NEGATIVE -> WEST;
|
||||
Y to POSITIVE -> UP; Y to NEGATIVE -> DOWN;
|
||||
Z to POSITIVE -> SOUTH; else -> NORTH;
|
||||
}
|
||||
val EnumFacing.perpendiculars: List<EnumFacing> get() =
|
||||
axes.filter { it != this.axis }.cross(axisDirs).map { it.face }
|
||||
val EnumFacing.offset: Int3 get() = forgeDirOffsets[ordinal]
|
||||
|
||||
/** Old ForgeDirection rotation matrix yanked from 1.7.10 */
|
||||
val ROTATION_MATRIX: Array<IntArray> get() = arrayOf(
|
||||
intArrayOf(0, 1, 4, 5, 3, 2, 6),
|
||||
intArrayOf(0, 1, 5, 4, 2, 3, 6),
|
||||
intArrayOf(5, 4, 2, 3, 0, 1, 6),
|
||||
intArrayOf(4, 5, 2, 3, 1, 0, 6),
|
||||
intArrayOf(2, 3, 1, 0, 4, 5, 6),
|
||||
intArrayOf(3, 2, 0, 1, 4, 5, 6)
|
||||
)
|
||||
|
||||
// ================================
|
||||
// Vectors
|
||||
// ================================
|
||||
operator fun EnumFacing.times(scale: Double) =
|
||||
Double3(directionVec.x.toDouble() * scale, directionVec.y.toDouble() * scale, directionVec.z.toDouble() * scale)
|
||||
val EnumFacing.vec: Double3 get() = Double3(directionVec.x.toDouble(), directionVec.y.toDouble(), directionVec.z.toDouble())
|
||||
operator fun BlockPos.plus(other: Int3) = BlockPos(x + other.x, y + other.y, z + other.z)
|
||||
|
||||
/** 3D vector of [Double]s. Offers both mutable operations, and immutable operations in operator notation. */
|
||||
data class Double3(var x: Double, var y: Double, var z: Double) {
|
||||
constructor(x: Float, y: Float, z: Float) : this(x.toDouble(), y.toDouble(), z.toDouble())
|
||||
constructor(dir: EnumFacing) : this(dir.directionVec.x.toDouble(), dir.directionVec.y.toDouble(), dir.directionVec.z.toDouble())
|
||||
companion object {
|
||||
val zero: Double3 get() = Double3(0.0, 0.0, 0.0)
|
||||
fun weight(v1: Double3, weight1: Double, v2: Double3, weight2: Double) =
|
||||
Double3(v1.x * weight1 + v2.x * weight2, v1.y * weight1 + v2.y * weight2, v1.z * weight1 + v2.z * weight2)
|
||||
}
|
||||
|
||||
// immutable operations
|
||||
operator fun plus(other: Double3) = Double3(x + other.x, y + other.y, z + other.z)
|
||||
operator fun unaryMinus() = Double3(-x, -y, -z)
|
||||
operator fun minus(other: Double3) = Double3(x - other.x, y - other.y, z - other.z)
|
||||
operator fun times(scale: Double) = Double3(x * scale, y * scale, z * scale)
|
||||
operator fun times(other: Double3) = Double3(x * other.x, y * other.y, z * other.z)
|
||||
|
||||
/** Rotate this vector, and return coordinates in the unrotated frame */
|
||||
fun rotate(rot: Rotation) = Double3(
|
||||
rot.rotatedComponent(EAST, x, y, z),
|
||||
rot.rotatedComponent(UP, x, y, z),
|
||||
rot.rotatedComponent(SOUTH, x, y, z)
|
||||
)
|
||||
|
||||
// mutable operations
|
||||
fun setTo(other: Double3): Double3 { x = other.x; y = other.y; z = other.z; return this }
|
||||
fun setTo(x: Double, y: Double, z: Double): Double3 { this.x = x; this.y = y; this.z = z; return this }
|
||||
fun setTo(x: Float, y: Float, z: Float) = setTo(x.toDouble(), y.toDouble(), z.toDouble())
|
||||
fun add(other: Double3): Double3 { x += other.x; y += other.y; z += other.z; return this }
|
||||
fun add(x: Double, y: Double, z: Double): Double3 { this.x += x; this.y += y; this.z += z; return this }
|
||||
fun sub(other: Double3): Double3 { x -= other.x; y -= other.y; z -= other.z; return this }
|
||||
fun sub(x: Double, y: Double, z: Double): Double3 { this.x -= x; this.y -= y; this.z -= z; return this }
|
||||
fun invert(): Double3 { x = -x; y = -y; z = -z; return this }
|
||||
fun mul(scale: Double): Double3 { x *= scale; y *= scale; z *= scale; return this }
|
||||
fun mul(other: Double3): Double3 { x *= other.x; y *= other.y; z *= other.z; return this }
|
||||
fun rotateMut(rot: Rotation): Double3 {
|
||||
val rotX = rot.rotatedComponent(EAST, x, y, z)
|
||||
val rotY = rot.rotatedComponent(UP, x, y, z)
|
||||
val rotZ = rot.rotatedComponent(SOUTH, x, y, z)
|
||||
return setTo(rotX, rotY, rotZ)
|
||||
}
|
||||
|
||||
// misc operations
|
||||
infix fun dot(other: Double3) = x * other.x + y * other.y + z * other.z
|
||||
infix fun cross(o: Double3) = Double3(y * o.z - z * o.y, z * o.x - x * o.z, x * o.y - y * o.x)
|
||||
val length: Double get() = Math.sqrt(x * x + y * y + z * z)
|
||||
val normalize: Double3 get() = (1.0 / length).let { Double3(x * it, y * it, z * it) }
|
||||
val nearestCardinal: EnumFacing get() = nearestAngle(this, forgeDirs.asIterable()) { it.vec }.first
|
||||
}
|
||||
|
||||
/** 3D vector of [Int]s. Offers both mutable operations, and immutable operations in operator notation. */
|
||||
data class Int3(var x: Int, var y: Int, var z: Int) {
|
||||
constructor(dir: EnumFacing) : this(dir.directionVec.x, dir.directionVec.y, dir.directionVec.z)
|
||||
constructor(offset: Pair<Int, EnumFacing>) : this(
|
||||
offset.first * offset.second.directionVec.x,
|
||||
offset.first * offset.second.directionVec.y,
|
||||
offset.first * offset.second.directionVec.z
|
||||
)
|
||||
companion object {
|
||||
val zero = Int3(0, 0, 0)
|
||||
}
|
||||
|
||||
// immutable operations
|
||||
operator fun plus(other: Int3) = Int3(x + other.x, y + other.y, z + other.z)
|
||||
operator fun plus(other: Pair<Int, EnumFacing>) = Int3(
|
||||
x + other.first * other.second.directionVec.x,
|
||||
y + other.first * other.second.directionVec.y,
|
||||
z + other.first * other.second.directionVec.z
|
||||
)
|
||||
operator fun unaryMinus() = Int3(-x, -y, -z)
|
||||
operator fun minus(other: Int3) = Int3(x - other.x, y - other.y, z - other.z)
|
||||
operator fun times(scale: Int) = Int3(x * scale, y * scale, z * scale)
|
||||
operator fun times(other: Int3) = Int3(x * other.x, y * other.y, z * other.z)
|
||||
|
||||
/** Rotate this vector, and return coordinates in the unrotated frame */
|
||||
fun rotate(rot: Rotation) = Int3(
|
||||
rot.rotatedComponent(EAST, x, y, z),
|
||||
rot.rotatedComponent(UP, x, y, z),
|
||||
rot.rotatedComponent(SOUTH, x, y, z)
|
||||
)
|
||||
|
||||
// mutable operations
|
||||
fun setTo(other: Int3): Int3 { x = other.x; y = other.y; z = other.z; return this }
|
||||
fun setTo(x: Int, y: Int, z: Int): Int3 { this.x = x; this.y = y; this.z = z; return this }
|
||||
fun add(other: Int3): Int3 { x += other.x; y += other.y; z += other.z; return this }
|
||||
fun sub(other: Int3): Int3 { x -= other.x; y -= other.y; z -= other.z; return this }
|
||||
fun invert(): Int3 { x = -x; y = -y; z = -z; return this }
|
||||
fun mul(scale: Int): Int3 { x *= scale; y *= scale; z *= scale; return this }
|
||||
fun mul(other: Int3): Int3 { x *= other.x; y *= other.y; z *= other.z; return this }
|
||||
fun rotateMut(rot: Rotation): Int3 {
|
||||
val rotX = rot.rotatedComponent(EAST, x, y, z)
|
||||
val rotY = rot.rotatedComponent(UP, x, y, z)
|
||||
val rotZ = rot.rotatedComponent(SOUTH, x, y, z)
|
||||
return setTo(rotX, rotY, rotZ)
|
||||
}
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Rotation
|
||||
// ================================
|
||||
val EnumFacing.rotations: Array<EnumFacing> get() =
|
||||
Array(6) { idx -> EnumFacing.values()[ROTATION_MATRIX[ordinal][idx]] }
|
||||
fun EnumFacing.rotate(rot: Rotation) = rot.forward[ordinal]
|
||||
fun rot(axis: EnumFacing) = Rotation.rot90[axis.ordinal]
|
||||
|
||||
/**
|
||||
* Class representing an arbitrary rotation (or combination of rotations) around cardinal axes by 90 degrees.
|
||||
* In effect, a permutation of [ForgeDirection]s.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
class Rotation(val forward: Array<EnumFacing>, val reverse: Array<EnumFacing>) {
|
||||
operator fun plus(other: Rotation) = Rotation(
|
||||
Array(6) { idx -> forward[other.forward[idx].ordinal] },
|
||||
Array(6) { idx -> other.reverse[reverse[idx].ordinal] }
|
||||
)
|
||||
operator fun unaryMinus() = Rotation(reverse, forward)
|
||||
operator fun times(num: Int) = when(num % 4) { 1 -> this; 2 -> this + this; 3 -> -this; else -> identity }
|
||||
|
||||
inline fun rotatedComponent(dir: EnumFacing, x: Int, y: Int, z: Int) =
|
||||
when(reverse[dir.ordinal]) { EAST -> x; WEST -> -x; UP -> y; DOWN -> -y; SOUTH -> z; NORTH -> -z; else -> 0 }
|
||||
inline fun rotatedComponent(dir: EnumFacing, x: Double, y: Double, z: Double) =
|
||||
when(reverse[dir.ordinal]) { EAST -> x; WEST -> -x; UP -> y; DOWN -> -y; SOUTH -> z; NORTH -> -z; else -> 0.0 }
|
||||
|
||||
companion object {
|
||||
// Forge rotation matrix is left-hand
|
||||
val rot90 = Array(6) { idx -> Rotation(forgeDirs[idx].opposite.rotations, forgeDirs[idx].rotations) }
|
||||
val identity = Rotation(forgeDirs, forgeDirs)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Miscellaneous
|
||||
// ================================
|
||||
/** List of all 12 box edges, represented as a [Pair] of [ForgeDirection]s */
|
||||
val boxEdges = forgeDirs.flatMap { face1 -> forgeDirs.filter { it.axis > face1.axis }.map { face1 to it } }
|
||||
|
||||
/**
|
||||
* Get the closest object to the specified point from a list of objects.
|
||||
*
|
||||
* @param[vertex] the reference point
|
||||
* @param[objs] list of geomertric objects
|
||||
* @param[objPos] lambda to calculate the position of an object
|
||||
* @return [Pair] of (object, distance)
|
||||
*/
|
||||
fun <T> nearestPosition(vertex: Double3, objs: Iterable<T>, objPos: (T)-> Double3): Pair<T, Double> =
|
||||
objs.map { it to (objPos(it) - vertex).length }.minBy { it.second }!!
|
||||
|
||||
/**
|
||||
* Get the object closest in orientation to the specified vector from a list of objects.
|
||||
*
|
||||
* @param[vector] the reference vector (direction)
|
||||
* @param[objs] list of geomertric objects
|
||||
* @param[objAngle] lambda to calculate the orientation of an object
|
||||
* @return [Pair] of (object, normalized dot product)
|
||||
*/
|
||||
fun <T> nearestAngle(vector: Double3, objs: Iterable<T>, objAngle: (T)-> Double3): Pair<T, Double> =
|
||||
objs.map { it to objAngle(it).dot(vector) }.maxBy { it.second }!!
|
||||
|
||||
data class FaceCorners(val topLeft: Pair<EnumFacing, EnumFacing>,
|
||||
val topRight: Pair<EnumFacing, EnumFacing>,
|
||||
val bottomLeft: Pair<EnumFacing, EnumFacing>,
|
||||
val bottomRight: Pair<EnumFacing, EnumFacing>) {
|
||||
constructor(top: EnumFacing, left: EnumFacing) :
|
||||
this(top to left, top to left.opposite, top.opposite to left, top.opposite to left.opposite)
|
||||
|
||||
val asArray = arrayOf(topLeft, topRight, bottomLeft, bottomRight)
|
||||
val asList = listOf(topLeft, topRight, bottomLeft, bottomRight)
|
||||
}
|
||||
|
||||
val faceCorners = forgeDirs.map { when(it) {
|
||||
DOWN -> FaceCorners(SOUTH, WEST)
|
||||
UP -> FaceCorners(SOUTH, EAST)
|
||||
NORTH -> FaceCorners(WEST, UP)
|
||||
SOUTH -> FaceCorners(UP, WEST)
|
||||
WEST -> FaceCorners(SOUTH, UP)
|
||||
EAST -> FaceCorners(SOUTH, DOWN)
|
||||
}}
|
||||
@@ -0,0 +1,232 @@
|
||||
package mods.octarinecore.common.config
|
||||
|
||||
import com.google.common.collect.LinkedListMultimap
|
||||
import mods.octarinecore.metaprog.reflectField
|
||||
import mods.octarinecore.metaprog.reflectFieldsOfType
|
||||
import mods.octarinecore.metaprog.reflectNestedObjects
|
||||
import net.minecraftforge.common.config.ConfigElement
|
||||
import net.minecraftforge.common.config.Configuration
|
||||
import net.minecraftforge.common.config.Property
|
||||
import net.minecraftforge.fml.client.config.GuiConfigEntries
|
||||
import net.minecraftforge.fml.client.config.IConfigElement
|
||||
import net.minecraftforge.fml.client.event.ConfigChangedEvent
|
||||
import net.minecraftforge.fml.common.FMLCommonHandler
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
// ============================
|
||||
// Configuration object base
|
||||
// ============================
|
||||
/**
|
||||
* Base class for declarative configuration handling.
|
||||
*
|
||||
* Subclasses should be singleton objects, containing one layer of further singleton objects representing
|
||||
* config categories (nesting is not supported).
|
||||
*
|
||||
* Both the root object (maps to the category _global_) and category objects can contain [ConfigPropertyBase]
|
||||
* instances (either directly or as a delegate), which handle the Forge [Configuration] itself.
|
||||
*
|
||||
* Config properties map to language keys by their field names.
|
||||
*
|
||||
* @param[modId] mod ID this configuration is linked to
|
||||
* @param[langPrefix] prefix to use for language keys
|
||||
*/
|
||||
abstract class DelegatingConfig(val modId: String, val langPrefix: String) {
|
||||
|
||||
init { FMLCommonHandler.instance().bus().register(this) }
|
||||
|
||||
/** The [Configuration] backing this config object. */
|
||||
var config: Configuration? = null
|
||||
val rootGuiElements = linkedListOf<IConfigElement>()
|
||||
|
||||
/** Attach this config object to the given [Configuration] and update all properties. */
|
||||
fun attach(config: Configuration) {
|
||||
this.config = config
|
||||
val subProperties = LinkedListMultimap.create<String, String>()
|
||||
rootGuiElements.clear()
|
||||
|
||||
forEachProperty { category, name, property ->
|
||||
property.lang = property.lang ?: "$category.$name"
|
||||
property.attach(config, langPrefix, category, name)
|
||||
property.guiProperties.forEach { guiProperty ->
|
||||
property.guiClass?.let { guiProperty.setConfigEntryClass(it) }
|
||||
if (category == "global") rootGuiElements.add(ConfigElement(guiProperty))
|
||||
else subProperties.put(category, guiProperty.name)
|
||||
}
|
||||
}
|
||||
for (category in subProperties.keySet()) {
|
||||
val configCategory = config.getCategory(category)
|
||||
configCategory.setLanguageKey("$langPrefix.$category")
|
||||
configCategory.setPropertyOrder(subProperties[category])
|
||||
rootGuiElements.add(ConfigElement(configCategory))
|
||||
}
|
||||
save()
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given lambda for all config properties.
|
||||
* Lambda params: (category name, property name, property instance)
|
||||
*/
|
||||
inline fun forEachProperty(init: (String, String, ConfigPropertyBase)->Unit) {
|
||||
reflectFieldsOfType(ConfigPropertyBase::class.java).forEach { property ->
|
||||
init("global", property.first.split("$")[0], property.second as ConfigPropertyBase)
|
||||
}
|
||||
for (category in reflectNestedObjects) {
|
||||
category.second.reflectFieldsOfType(ConfigPropertyBase::class.java).forEach { property ->
|
||||
init(category.first, property.first.split("$")[0], property.second as ConfigPropertyBase)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Save changes to the [Configuration]. */
|
||||
fun save() { if (config?.hasChanged() ?: false) config!!.save() }
|
||||
|
||||
/**
|
||||
* Returns true if any of the given configuration elements have changed.
|
||||
* Supports both categories and
|
||||
*/
|
||||
fun hasChanged(vararg elements: Any?): Boolean {
|
||||
reflectNestedObjects.forEach { category ->
|
||||
if (category.second in elements && config?.getCategory(category.first)?.hasChanged() ?: false) return true
|
||||
}
|
||||
forEachProperty { category, name, property ->
|
||||
if (property in elements && property.hasChanged) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/** Called when the configuration for the mod changes. */
|
||||
open fun onChange(event: ConfigChangedEvent.OnConfigChangedEvent) {
|
||||
save()
|
||||
forEachProperty { c, n, prop -> prop.read() }
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
fun handleConfigChange(event: ConfigChangedEvent.OnConfigChangedEvent) { if (event.modID == modId) onChange(event) }
|
||||
|
||||
/** Extension to get the underlying delegate of a field */
|
||||
operator fun Any.get(name: String) = this.reflectField<ConfigPropertyBase>("$name\$delegate")
|
||||
}
|
||||
|
||||
// ============================
|
||||
// Property delegates
|
||||
// ============================
|
||||
|
||||
/** Base class for config property delegates. */
|
||||
abstract class ConfigPropertyBase {
|
||||
/** Language key of the property. */
|
||||
var lang: String? = null
|
||||
|
||||
/** GUI class to use. */
|
||||
var guiClass: Class<out GuiConfigEntries.IConfigEntry>? = null
|
||||
|
||||
/** @return true if the property has changed. */
|
||||
abstract val hasChanged: Boolean
|
||||
|
||||
/** Attach this delegate to a Forge [Configuration]. */
|
||||
abstract fun attach(target: Configuration, langPrefix: String, categoryName: String, propertyName: String)
|
||||
|
||||
/** List of [Property] instances backing this delegate. */
|
||||
abstract val guiProperties: List<Property>
|
||||
|
||||
/** Re-read the property value from the [Configuration]. */
|
||||
open fun read() {}
|
||||
}
|
||||
|
||||
/** Delegate for a property backed by a single [Property] instance. */
|
||||
abstract class ConfigPropertyDelegate<T>() : ConfigPropertyBase() {
|
||||
/** Cached value of the property. */
|
||||
var cached: T? = null
|
||||
/** The [Property] backing this delegate. */
|
||||
var property: Property? = null
|
||||
|
||||
override val guiProperties: List<Property> get() = listOf(property!!)
|
||||
override val hasChanged: Boolean get() = property?.hasChanged() ?: false
|
||||
|
||||
/** Chained setter for the language key. */
|
||||
fun lang(lang: String) = apply { this.lang = lang }
|
||||
|
||||
/** Read the backing [Property] instance. */
|
||||
abstract fun Property.read(): T
|
||||
|
||||
/** Write the backing [Property] instance. */
|
||||
abstract fun Property.write(value: T)
|
||||
|
||||
/** Get the backing [Property] instance. */
|
||||
abstract fun resolve(target: Configuration, category: String, name: String): Property
|
||||
|
||||
/** Kotlin deleagation implementation. */
|
||||
operator fun getValue(thisRef: Any, delegator: KProperty<*>): T {
|
||||
if (cached != null) return cached!!
|
||||
cached = property!!.read()
|
||||
return cached!!
|
||||
}
|
||||
|
||||
/** Kotlin deleagation implementation. */
|
||||
operator fun setValue(thisRef: Any, delegator: KProperty<*>, value: T) {
|
||||
cached = value
|
||||
property!!.write(value)
|
||||
}
|
||||
|
||||
override fun read() { cached = null }
|
||||
|
||||
override fun attach(target: Configuration, langPrefix: String, categoryName: String, propertyName: String) {
|
||||
cached = null
|
||||
property = resolve(target, categoryName, propertyName)
|
||||
property!!.setLanguageKey("$langPrefix.$lang")
|
||||
}
|
||||
}
|
||||
|
||||
/** [Double]-typed property delegate. */
|
||||
class ConfigPropertyDouble(val min: Double, val max: Double, val default: Double) :
|
||||
ConfigPropertyDelegate<Double>() {
|
||||
override fun resolve(target: Configuration, category: String, name: String) =
|
||||
target.get(category, name, default, null).apply { setMinValue(min); setMaxValue(max) }
|
||||
override fun Property.read() = property!!.double
|
||||
override fun Property.write(value: Double) = property!!.set(value)
|
||||
}
|
||||
|
||||
/** [Float]-typed property delegate. */
|
||||
class ConfigPropertyFloat(val min: Double, val max: Double, val default: Double) :
|
||||
ConfigPropertyDelegate<Float>() {
|
||||
override fun resolve(target: Configuration, category: String, name: String) =
|
||||
target.get(category, name, default, null).apply { setMinValue(min); setMaxValue(max) }
|
||||
override fun Property.read() = property!!.double.toFloat()
|
||||
override fun Property.write(value: Float) = property!!.set(value.toDouble())
|
||||
}
|
||||
|
||||
/** [Int]-typed property delegate. */
|
||||
class ConfigPropertyInt(val min: Int, val max: Int, val default: Int) :
|
||||
ConfigPropertyDelegate<Int>() {
|
||||
override fun resolve(target: Configuration, category: String, name: String) =
|
||||
target.get(category, name, default, null).apply { setMinValue(min); setMaxValue(max) }
|
||||
override fun Property.read() = property!!.int
|
||||
override fun Property.write(value: Int) = property!!.set(value)
|
||||
}
|
||||
|
||||
/** [Boolean]-typed property delegate. */
|
||||
class ConfigPropertyBoolean(val default: Boolean) :
|
||||
ConfigPropertyDelegate<Boolean>() {
|
||||
override fun resolve(target: Configuration, category: String, name: String) =
|
||||
target.get(category, name, default, null)
|
||||
override fun Property.read() = property!!.boolean
|
||||
override fun Property.write(value: Boolean) = property!!.set(value)
|
||||
}
|
||||
|
||||
/** [Int] array typed property delegate. */
|
||||
class ConfigPropertyIntList(val defaults: ()->Array<Int>) :
|
||||
ConfigPropertyDelegate<Array<Int>>() {
|
||||
override fun resolve(target: Configuration, category: String, name: String) =
|
||||
target.get(category, name, defaults().toIntArray(), null)
|
||||
override fun Property.read() = property!!.intList.toTypedArray()
|
||||
override fun Property.write(value: Array<Int>) = property!!.set(value.toIntArray())
|
||||
}
|
||||
|
||||
// ============================
|
||||
// Delegate factory methods
|
||||
// ============================
|
||||
fun double(min: Double = 0.0, max: Double = 1.0, default: Double) = ConfigPropertyDouble(min, max, default)
|
||||
fun float(min: Double = 0.0, max: Double = 1.0, default: Double) = ConfigPropertyFloat(min, max, default)
|
||||
fun int(min: Int = 0, max: Int, default: Int) = ConfigPropertyInt(min, max, default)
|
||||
fun intList(defaults: ()->Array<Int>) = ConfigPropertyIntList(defaults)
|
||||
fun boolean(default: Boolean) = ConfigPropertyBoolean(default)
|
||||
Reference in New Issue
Block a user