create class for all items, save tags

This commit is contained in:
Bixilon 2021-05-21 20:01:25 +02:00
parent 6bec745340
commit 44d01b5d89
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
19 changed files with 372 additions and 13 deletions

View File

@ -12,9 +12,6 @@
*/
package de.bixilon.minosoft.data
import de.bixilon.minosoft.data.mappings.ResourceLocation
data class Tag<T>(
val resourceLocation: ResourceLocation,
val ids: Set<T>,
)

View File

@ -33,7 +33,11 @@ import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import glm_.vec3.Vec3i
open class Block(final override val resourceLocation: ResourceLocation, mappings: VersionMapping, data: JsonObject) : RegistryItem {
open class Block(
final override val resourceLocation: ResourceLocation,
mappings: VersionMapping,
data: JsonObject,
) : RegistryItem {
open val explosionResistance: Float = data["explosion_resistance"]?.asFloat ?: 0.0f
open val tintColor: RGBColor? = data["tint_color"]?.asInt?.let { TintColorCalculator.getJsonColor(it) }
open val randomOffsetType: RandomOffsetTypes? = data["offset_type"]?.asString?.let { RandomOffsetTypes[it] }

View File

@ -20,8 +20,8 @@ import de.bixilon.minosoft.data.mappings.versions.VersionMapping
open class BlockItem(
resourceLocation: ResourceLocation,
data: JsonObject,
versionMapping: VersionMapping,
data: JsonObject,
) : Item(resourceLocation, versionMapping, data) {
val block: Block = versionMapping.blockRegistry[data["block"].asInt]
}

View File

@ -0,0 +1,27 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.mappings.items
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
open class BucketItem(
resourceLocation: ResourceLocation,
versionMapping: VersionMapping,
data: JsonObject,
) : Item(resourceLocation, versionMapping, data) {
val fluid = versionMapping.fluidRegistry[data["bucked_fluid_type"].asInt]
}

View File

@ -0,0 +1,26 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.mappings.items
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
open class DyeItem(
resourceLocation: ResourceLocation,
versionMapping: VersionMapping,
data: JsonObject,
) : Item(resourceLocation, versionMapping, data) {
val dyeColor = data["dye_color"]?.asString ?: "white"
}

View File

@ -17,6 +17,11 @@ import de.bixilon.minosoft.data.Rarities
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.inventory.CreativeModeTab
import de.bixilon.minosoft.data.mappings.items.armor.ArmorItem
import de.bixilon.minosoft.data.mappings.items.armor.HorseArmorItem
import de.bixilon.minosoft.data.mappings.items.tools.AxeItem
import de.bixilon.minosoft.data.mappings.items.tools.MiningToolItem
import de.bixilon.minosoft.data.mappings.items.tools.SwordItem
import de.bixilon.minosoft.data.mappings.items.tools.ToolItem
import de.bixilon.minosoft.data.mappings.registry.RegistryItem
import de.bixilon.minosoft.data.mappings.registry.ResourceLocationDeserializer
import de.bixilon.minosoft.data.mappings.registry.Translatable
@ -42,8 +47,17 @@ open class Item(
override fun deserialize(mappings: VersionMapping?, resourceLocation: ResourceLocation, data: JsonObject): Item {
check(mappings != null) { "VersionMapping is null!" }
return when (data["class"].asString) {
"BlockItem" -> BlockItem(resourceLocation, data, mappings)
"BlockItem" -> BlockItem(resourceLocation, mappings, data)
"ArmorItem" -> ArmorItem(resourceLocation, mappings, data)
"SwordItem" -> SwordItem(resourceLocation, mappings, data)
"ToolItem" -> ToolItem(resourceLocation, mappings, data)
"MiningToolItem" -> MiningToolItem(resourceLocation, mappings, data)
"AxeItem" -> AxeItem(resourceLocation, mappings, data)
"BucketItem" -> BucketItem(resourceLocation, mappings, data)
"DyeItem" -> DyeItem(resourceLocation, mappings, data)
"HorseArmorItem" -> HorseArmorItem(resourceLocation, mappings, data)
"SpawnEggItem" -> SpawnEggItem(resourceLocation, mappings, data)
"MusicDiscItem" -> MusicDiscItem(resourceLocation, mappings, data)
// "Item" -> Item(resourceLocation, data)
// else -> TODO("Can not find item class: ${data["class"].asString}")
else -> Item(resourceLocation, mappings, data)

View File

@ -0,0 +1,27 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.mappings.items
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
open class MusicDiscItem(
resourceLocation: ResourceLocation,
versionMapping: VersionMapping,
data: JsonObject,
) : Item(resourceLocation, versionMapping, data) {
val analogOutput = data["analog_output"]?.asInt ?: 0
val sound = data["sound"]?.asInt?.let { versionMapping.soundEventRegistry[it] }
}

View File

@ -0,0 +1,29 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.mappings.items
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
import de.bixilon.minosoft.data.text.RGBColor.Companion.asRGBColor
open class SpawnEggItem(
resourceLocation: ResourceLocation,
versionMapping: VersionMapping,
data: JsonObject,
) : Item(resourceLocation, versionMapping, data) {
val color1 = data["spawn_egg_color_1"]?.asInt?.asRGBColor()
val color2 = data["spawn_egg_color_2"]?.asInt?.asRGBColor()
val entityType = data["spawn_egg_entity_type"]?.asInt?.let { versionMapping.entityTypeRegistry[it] }
}

View File

@ -0,0 +1,28 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.mappings.items.armor
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.items.Item
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
open class HorseArmorItem(
resourceLocation: ResourceLocation,
versionMapping: VersionMapping,
data: JsonObject,
) : Item(resourceLocation, versionMapping, data) {
val horseProtection = data["horse_protection"]?.asInt ?: 0
val horseTexture = data["horse_texture"]?.asString
}

View File

@ -0,0 +1,34 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.mappings.items.tools
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.blocks.types.Block
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
open class AxeItem(
resourceLocation: ResourceLocation,
versionMapping: VersionMapping,
data: JsonObject,
) : MiningToolItem(resourceLocation, versionMapping, data) {
val strippableBlocks: List<Block>? = data["strippables_blocks"]?.asJsonArray?.let {
val strippableBlocks: MutableList<Block> = mutableListOf()
for (id in it) {
strippableBlocks += versionMapping.blockRegistry[id.asInt]
}
strippableBlocks.toList()
}
}

View File

@ -0,0 +1,34 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.mappings.items.tools
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.blocks.BlockState
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
open class HoeItem(
resourceLocation: ResourceLocation,
versionMapping: VersionMapping,
data: JsonObject,
) : MiningToolItem(resourceLocation, versionMapping, data) {
val tillableBlocKStates: List<BlockState>? = data["tillables_block_states"]?.asJsonArray?.let {
val diggableBlocks: MutableList<BlockState> = mutableListOf()
for (id in it) {
diggableBlocks += versionMapping.getBlockState(id.asInt)!!
}
diggableBlocks.toList()
}
}

View File

@ -0,0 +1,36 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.mappings.items.tools
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.blocks.types.Block
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
open class MiningToolItem(
resourceLocation: ResourceLocation,
versionMapping: VersionMapping,
data: JsonObject,
) : ToolItem(resourceLocation, versionMapping, data) {
val diggableBlocks: List<Block>? = data["diggable_blocks"]?.asJsonArray?.let {
val diggableBlocks: MutableList<Block> = mutableListOf()
for (id in it) {
diggableBlocks += versionMapping.blockRegistry[id.asInt]
}
diggableBlocks.toList()
}
override val attackDamage: Float = data["attack_damage"]?.asFloat ?: 1.0f
val miningSpeed: Float = data["mining_speed"]?.asFloat ?: 1.0f
}

View File

@ -0,0 +1,34 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.mappings.items.tools
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.blocks.BlockState
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
open class ShovelItem(
resourceLocation: ResourceLocation,
versionMapping: VersionMapping,
data: JsonObject,
) : MiningToolItem(resourceLocation, versionMapping, data) {
val flattenableBlockStates: List<BlockState>? = data["flattenables_block_states"]?.asJsonArray?.let {
val flattenableBlockStates: MutableList<BlockState> = mutableListOf()
for (id in it) {
flattenableBlockStates += versionMapping.getBlockState(id.asInt)!!
}
flattenableBlockStates.toList()
}
}

View File

@ -0,0 +1,27 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.mappings.items.tools
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
open class SwordItem(
resourceLocation: ResourceLocation,
versionMapping: VersionMapping,
data: JsonObject,
) : ToolItem(resourceLocation, versionMapping, data) {
override val attackDamage = data["attack_damage"]?.asFloat ?: -1.0f
}

View File

@ -0,0 +1,32 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.mappings.items.tools
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.items.Item
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
open class ToolItem(
resourceLocation: ResourceLocation,
versionMapping: VersionMapping,
data: JsonObject,
) : Item(resourceLocation, versionMapping, data) {
val durability = data["uses"]?.asInt ?: 1
val speed = data["speed"]?.asFloat ?: 1.0f
open val attackDamage = data["attack_damage_bonus"]?.asFloat ?: 1.0f
val miningLevel = data["mining_level"]?.asInt ?: 1
val enchantmentValue = data["enchantment_value"]?.asInt ?: 1
}

View File

@ -176,6 +176,8 @@ class VersionMapping {
blockEntityTypeRegistry.initialize(pixlyzerData["block_entities"]?.asJsonObject, this, BlockEntityType)
entityTypeRegistry.initialize(pixlyzerData["entities"]?.asJsonObject, this, EntityType)
soundEventRegistry.initialize(pixlyzerData["sound_events"]?.asJsonObject, this, SoundEvent)
particleTypeRegistry.initialize(pixlyzerData["particles"]?.asJsonObject, this, ParticleType)
materialRegistry.initialize(pixlyzerData["materials"]?.asJsonObject, this, Material)
@ -190,7 +192,6 @@ class VersionMapping {
villagerProfessionRegistry.initialize(pixlyzerData["villager_professions"]?.asJsonObject, this, VillagerProfession)
entityTypeRegistry.initialize(pixlyzerData["entities"]?.asJsonObject, this, EntityType)
blockEntityMetaDataTypeRegistry.initialize(pixlyzerData["block_entity_meta_data_types"]?.asJsonObject, this, BlockEntityMetaType, alternative = DefaultRegistries.BLOCK_ENTITY_META_TYPE_REGISTRY.forVersion(version))

View File

@ -15,10 +15,12 @@ package de.bixilon.minosoft.protocol.network.connection
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.config.StaticConfiguration
import de.bixilon.minosoft.data.Tag
import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.data.assets.MultiAssetsManager
import de.bixilon.minosoft.data.commands.CommandRootNode
import de.bixilon.minosoft.data.mappings.MappingsLoadingException
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.recipes.Recipes
import de.bixilon.minosoft.data.mappings.versions.Version
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
@ -39,6 +41,7 @@ import de.bixilon.minosoft.protocol.protocol.*
import de.bixilon.minosoft.terminal.CLI
import de.bixilon.minosoft.terminal.commands.commands.Command
import de.bixilon.minosoft.util.CountUpAndDownLatch
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
import de.bixilon.minosoft.util.ServerAddress
import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels
@ -60,6 +63,7 @@ class PlayConnection(
val sender = PacketSender(this)
lateinit var assetsManager: MultiAssetsManager
private set
val tags: MutableMap<ResourceLocation, Map<ResourceLocation, Tag<Any>>> = synchronizedMapOf()
var commandRootNode: CommandRootNode? = null

View File

@ -14,6 +14,7 @@ package de.bixilon.minosoft.protocol.packets.s2c.play
import de.bixilon.minosoft.data.Tag
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
@ -23,10 +24,10 @@ import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
class TagsS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
val tags: Map<ResourceLocation, List<Tag<Any>>>
val tags: Map<ResourceLocation, Map<ResourceLocation, Tag<Any>>>
init {
val tags: MutableMap<ResourceLocation, List<Tag<Any>>> = mutableMapOf()
val tags: MutableMap<ResourceLocation, Map<ResourceLocation, Tag<Any>>> = mutableMapOf()
if (buffer.versionId < ProtocolVersions.V_20W51A) {
tags[BLOCK_TAG_RESOURCE_LOCATION] = buffer.readTagArray { buffer.connection.mapping.getBlockState(it)!! }
tags[ITEM_TAG_RESOURCE_LOCATION] = buffer.readTagArray { buffer.connection.mapping.itemRegistry[it] }
@ -51,6 +52,10 @@ class TagsS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
this.tags = tags.toMap()
}
override fun handle(connection: PlayConnection) {
connection.tags.putAll(tags)
}
override fun log() {
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Tags (tags=$tags)" }
}

View File

@ -409,18 +409,18 @@ open class InByteBuffer {
return String(Base64.getEncoder().encode(readRest()))
}
fun <T> readTag(idResolver: (Int) -> T): Tag<T> {
fun <T> readTag(idResolver: (Int) -> T): Pair<ResourceLocation, Tag<T>> {
val resourceLocation = readResourceLocation()
val ids = readVarIntArray()
val items: MutableSet<T> = mutableSetOf()
for (id in ids) {
items += idResolver(id)
}
return Tag(resourceLocation, items.toSet())
return Pair(resourceLocation, Tag(items.toSet()))
}
fun <T> readTagArray(length: Int = readVarInt(), idResolver: (Int) -> T): List<Tag<T>> {
return (readArray(length) { readTag(idResolver) }).toList()
fun <T> readTagArray(length: Int = readVarInt(), idResolver: (Int) -> T): Map<ResourceLocation, Tag<T>> {
return mapOf(*(readArray(length) { readTag(idResolver) }))
}
fun <T> readOptional(reader: () -> T): T? {