Item Magnet for androids
This commit is contained in:
parent
c7dad0a48c
commit
b89d59358c
@ -2,7 +2,9 @@ package ru.dbotthepony.mc.otm.datagen
|
||||
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearchType
|
||||
import ru.dbotthepony.mc.otm.android.feature.ItemMagnetFeature
|
||||
import ru.dbotthepony.mc.otm.android.feature.NanobotsArmorFeature
|
||||
import ru.dbotthepony.mc.otm.android.feature.ShockwaveFeature
|
||||
import ru.dbotthepony.mc.otm.client.render.ResearchIcons
|
||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
@ -221,12 +223,24 @@ fun addResearchData(serializer: Consumer<AndroidResearchType>, lang: MatteryLang
|
||||
AndroidResearchType.Builder(modLocation(MNames.SHOCKWAVE))
|
||||
.withExperience(40)
|
||||
.withDescription()
|
||||
.appendDescription(ShockwaveFeature.POWER_COST_DESCRIPTION)
|
||||
.withIcon(ResearchIcons.ICON_SHOCKWAVE)
|
||||
.addFeatureResult(AndroidFeatures.SHOCKWAVE)
|
||||
.addPrerequisite(attackBoostList[2])
|
||||
.build()
|
||||
|
||||
val ITEM_MAGNET =
|
||||
AndroidResearchType.Builder(modLocation(MNames.ITEM_MAGNET))
|
||||
.withExperience(28)
|
||||
.withDescription(0 .. 1)
|
||||
.appendDescription(ItemMagnetFeature.POWER_COST_DESCRIPTION)
|
||||
.withIcon(ResearchIcons.ICON_ITEM_MAGNET)
|
||||
.addFeatureResult(AndroidFeatures.ITEM_MAGNET)
|
||||
.addPrerequisite(STEP_ASSIST)
|
||||
.build()
|
||||
|
||||
serializer.accept(SHOCKWAVE)
|
||||
serializer.accept(ITEM_MAGNET)
|
||||
|
||||
with(lang.english) {
|
||||
add(limbList[0], "Limb Overclocking %s")
|
||||
@ -259,6 +273,13 @@ fun addResearchData(serializer: Consumer<AndroidResearchType>, lang: MatteryLang
|
||||
add(STEP_ASSIST, "Step Assist")
|
||||
add(STEP_ASSIST, "description", "Allows unit to step up whole blocks")
|
||||
|
||||
add(ITEM_MAGNET, "Item Magnet")
|
||||
add(ITEM_MAGNET, "description0", "Pulls nearby items to you while active")
|
||||
add(ITEM_MAGNET, "description1", "Drains energy for each item stack it pulls")
|
||||
|
||||
add(SHOCKWAVE, "Shockwave Pulsator")
|
||||
add(SHOCKWAVE, "description", "Releases a shockwave around you, damaging everything in small radius, as you quickly land on ground")
|
||||
|
||||
add(attackBoostList[0], "Attack Boost %s")
|
||||
add(attackBoostList[0], "description", "Increases total melee attack strength by %s%%")
|
||||
}
|
||||
|
@ -51,6 +51,9 @@ private fun sounds(provider: MatteryLanguageProvider) {
|
||||
|
||||
private fun misc(provider: MatteryLanguageProvider) {
|
||||
with(provider.english) {
|
||||
gui("power_cost_per_use", "Power cost per use: %s")
|
||||
gui("power_cost_per_tick", "Power cost per tick: %s")
|
||||
|
||||
gui("cancel", "Cancel")
|
||||
gui("confirm", "Confirm")
|
||||
|
||||
@ -464,6 +467,7 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
|
||||
add(AndroidFeatures.SHOCKWAVE, "Shockwave")
|
||||
add(AndroidFeatures.NIGHT_VISION, "Night Vision")
|
||||
add(AndroidFeatures.NANOBOTS_ARMOR, "Nanobots Armor")
|
||||
add(AndroidFeatures.ITEM_MAGNET, "Item Magnet")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,8 +100,6 @@ public final class OverdriveThatMatters {
|
||||
|
||||
ClientConfig.INSTANCE.register();
|
||||
ServerConfig.INSTANCE.register();
|
||||
|
||||
NanobotsArmorFeature.Companion.register();
|
||||
}
|
||||
|
||||
private void setup(final FMLCommonSetupEvent event) {
|
||||
|
@ -141,6 +141,20 @@ object ServerConfig {
|
||||
|
||||
val NIGHT_VISION_POWER_DRAW by specBuilder.defineImpreciseFraction("nightVisionPowerDraw", ImpreciseFraction(8), ImpreciseFraction.ZERO)
|
||||
|
||||
object AndroidItemMagnet {
|
||||
init {
|
||||
specBuilder.comment("Item magnet ability").push("item_magnet")
|
||||
}
|
||||
|
||||
val POWER_DRAW by specBuilder.comment("Per tick per stack").defineImpreciseFraction("powerDraw", ImpreciseFraction(8), ImpreciseFraction.ZERO)
|
||||
val RADIUS_HORIZONTAL: Double by specBuilder.defineInRange("radiusHorizontal", 6.0, 0.0, Double.MAX_VALUE / 4.0)
|
||||
val RADIUS_VERTICAL: Double by specBuilder.defineInRange("radiusVertical", 3.0, 0.0, Double.MAX_VALUE / 4.0)
|
||||
|
||||
init {
|
||||
specBuilder.pop()
|
||||
}
|
||||
}
|
||||
|
||||
object Shockwave {
|
||||
init {
|
||||
specBuilder.comment("Shockwave ability").push("shockwave")
|
||||
@ -162,6 +176,7 @@ object ServerConfig {
|
||||
|
||||
init {
|
||||
// access shockwave class so spec is built
|
||||
AndroidItemMagnet
|
||||
Shockwave
|
||||
|
||||
specBuilder.pop()
|
||||
|
@ -65,7 +65,7 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay
|
||||
get.level = level.level
|
||||
|
||||
for (transformer in type.features.first { it.id == feature.feature.registryName }.transformersDown) {
|
||||
transformer.accept(this to get)
|
||||
transformer.apply(this to get)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,7 +94,7 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay
|
||||
}
|
||||
|
||||
for (transformer in type.features.first { it.id == feature.feature.registryName }.transformersUp) {
|
||||
transformer.accept(this to get)
|
||||
transformer.apply(this to get)
|
||||
}
|
||||
}
|
||||
} catch(err: Throwable) {
|
||||
|
@ -32,6 +32,8 @@ open class AndroidResearchDataProvider(protected val dataGenerator: DataGenerato
|
||||
}
|
||||
|
||||
final override fun run(output: CachedOutput) {
|
||||
AndroidResearchManager.fireRegistrationEvent()
|
||||
|
||||
val set = ObjectArraySet<ResourceLocation>()
|
||||
val added = LinkedList<AndroidResearchType>()
|
||||
|
||||
|
@ -6,21 +6,24 @@ import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.client.server.IntegratedServer
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.packs.resources.ResourceManager
|
||||
import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener
|
||||
import net.minecraft.util.profiling.ProfilerFiller
|
||||
import net.minecraftforge.common.MinecraftForge
|
||||
import net.minecraftforge.event.AddReloadListenerEvent
|
||||
import net.minecraftforge.event.OnDatapackSyncEvent
|
||||
import net.minecraftforge.eventbus.api.Event
|
||||
import net.minecraftforge.network.NetworkEvent
|
||||
import net.minecraftforge.network.PacketDistributor
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.mc.otm.MINECRAFT_SERVER
|
||||
import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE
|
||||
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.data.SerializedFunctionRegistry
|
||||
import ru.dbotthepony.mc.otm.network.MatteryPacket
|
||||
import ru.dbotthepony.mc.otm.network.RegistryNetworkChannel
|
||||
@ -30,6 +33,9 @@ import ru.dbotthepony.mc.otm.onceServer
|
||||
import java.util.LinkedList
|
||||
import java.util.function.Supplier
|
||||
|
||||
typealias AndroidResultTransformer = SerializedFunctionRegistry.BoundFunction<Pair<AndroidResearch, AndroidFeature>, Unit>
|
||||
typealias ComponentSupplier = SerializedFunctionRegistry.BoundFunction<Unit, Component>
|
||||
|
||||
object AndroidResearchManager : SimpleJsonResourceReloadListener(GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(), "otm_android_research"), Iterable<AndroidResearchType> {
|
||||
/**
|
||||
* Feel free to register functions inside this thing from anywhere in your code
|
||||
@ -37,7 +43,36 @@ object AndroidResearchManager : SimpleJsonResourceReloadListener(GsonBuilder().s
|
||||
*
|
||||
* Just make sure client and server has the same set of functions defined.
|
||||
*/
|
||||
val featureResultTransformers = SerializedFunctionRegistry<Pair<AndroidResearch, AndroidFeature>>()
|
||||
val featureResultTransformers = SerializedFunctionRegistry<Pair<AndroidResearch, AndroidFeature>, Unit>()
|
||||
|
||||
/**
|
||||
* Feel free to register functions inside this thing from anywhere in your code
|
||||
* (registration and querying is completely thread safe).
|
||||
*
|
||||
* Just make sure client and server has the same set of functions defined.
|
||||
*/
|
||||
val descriptionFuncs = SerializedFunctionRegistry<Unit, Component>()
|
||||
|
||||
fun descriptionFunc(name: ResourceLocation, base: String, vararg argument: Supplier<Any>): ComponentSupplier {
|
||||
return descriptionFuncs.register(name) {->
|
||||
return@register TranslatableComponent(base, *argument.map { it.get() }.toTypedArray())
|
||||
}.bind()
|
||||
}
|
||||
|
||||
private var firedRegistrationEvent = false
|
||||
|
||||
/**
|
||||
* Event-style registration of serializable functions, for those who prefer/need it
|
||||
*
|
||||
* Fired *once* on [MinecraftForge.EVENT_BUS] before loading android research
|
||||
*/
|
||||
object RegisterFuncsEvent : Event() {
|
||||
val manager get() = AndroidResearchManager
|
||||
val featureResults by ::featureResultTransformers
|
||||
val descriptionFunctions by ::descriptionFuncs
|
||||
|
||||
fun descriptionFunc(name: ResourceLocation, base: String, vararg argument: Supplier<Any>): ComponentSupplier = AndroidResearchManager.descriptionFunc(name, base, *argument)
|
||||
}
|
||||
|
||||
const val DIRECTORY = "otm_android_research"
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
@ -62,11 +97,23 @@ object AndroidResearchManager : SimpleJsonResourceReloadListener(GsonBuilder().s
|
||||
var researchMap: Map<ResourceLocation, AndroidResearchType> = mapOf()
|
||||
private set
|
||||
|
||||
internal fun fireRegistrationEvent() {
|
||||
if (!firedRegistrationEvent) {
|
||||
try {
|
||||
MinecraftForge.EVENT_BUS.post(RegisterFuncsEvent)
|
||||
} finally {
|
||||
firedRegistrationEvent = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun apply(
|
||||
jsonElementMap: Map<ResourceLocation, JsonElement>,
|
||||
manager: ResourceManager,
|
||||
profiler: ProfilerFiller
|
||||
) {
|
||||
fireRegistrationEvent()
|
||||
|
||||
val builder = ImmutableMap.builder<ResourceLocation, AndroidResearchType>()
|
||||
|
||||
for ((k, v) in jsonElementMap) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package ru.dbotthepony.mc.otm.android
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.Streams
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
@ -21,15 +22,13 @@ import ru.dbotthepony.mc.otm.core.ListSet
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.core.registryName
|
||||
import ru.dbotthepony.mc.otm.core.set
|
||||
import ru.dbotthepony.mc.otm.core.stream
|
||||
import ru.dbotthepony.mc.otm.core.toImmutableList
|
||||
import ru.dbotthepony.mc.otm.data.ItemStackCodec
|
||||
import ru.dbotthepony.mc.otm.data.SerializedFunctionRegistry
|
||||
import ru.dbotthepony.mc.otm.data.stream
|
||||
import ru.dbotthepony.mc.otm.registry.MRegistry
|
||||
import java.util.ArrayList
|
||||
import java.util.LinkedList
|
||||
import java.util.stream.Stream
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashSet
|
||||
|
||||
private fun findPrerequisites(
|
||||
@ -81,6 +80,7 @@ class AndroidResearchType(
|
||||
features: Collection<FeatureReference>,
|
||||
|
||||
descriptionLines: Collection<Component>,
|
||||
descriptionSuppliers: Collection<ComponentSupplier> = listOf(),
|
||||
|
||||
val experienceLevels: Int = 0,
|
||||
private val customName: Component? = null,
|
||||
@ -137,8 +137,8 @@ class AndroidResearchType(
|
||||
val id: ResourceLocation,
|
||||
val level: Int = 0,
|
||||
val isRigid: Boolean,
|
||||
val transformersUp: Collection<SerializedFunctionRegistry.BoundFunction<Pair<AndroidResearch, AndroidFeature>>> = listOf(),
|
||||
val transformersDown: Collection<SerializedFunctionRegistry.BoundFunction<Pair<AndroidResearch, AndroidFeature>>> = listOf(),
|
||||
val transformersUp: Collection<AndroidResultTransformer> = listOf(),
|
||||
val transformersDown: Collection<AndroidResultTransformer> = listOf(),
|
||||
) {
|
||||
fun toJson(): JsonObject {
|
||||
return JsonObject().also {
|
||||
@ -186,8 +186,8 @@ class AndroidResearchType(
|
||||
ResourceLocation((value["id"] as? JsonPrimitive ?: throw JsonSyntaxException("Invalid `id` value")).asString),
|
||||
(value["level"] as JsonPrimitive?)?.asInt ?: 0,
|
||||
(value["is_rigid"] as JsonPrimitive?)?.asBoolean ?: true,
|
||||
(value["functions_up"] as JsonArray? ?: JsonArray()).stream().map { AndroidResearchManager.featureResultTransformers.fromJson(it) }.filter { it != null }.collect(ImmutableList.toImmutableList<SerializedFunctionRegistry.BoundFunction<Pair<AndroidResearch, AndroidFeature>>>()),
|
||||
(value["functions_down"] as JsonArray? ?: JsonArray()).stream().map { AndroidResearchManager.featureResultTransformers.fromJson(it) }.filter { it != null }.collect(ImmutableList.toImmutableList<SerializedFunctionRegistry.BoundFunction<Pair<AndroidResearch, AndroidFeature>>>()),
|
||||
(value["functions_up"] as JsonArray? ?: JsonArray()).stream().map { AndroidResearchManager.featureResultTransformers.fromJson(it) }.filter { it != null }.collect(ImmutableList.toImmutableList<AndroidResultTransformer>()),
|
||||
(value["functions_down"] as JsonArray? ?: JsonArray()).stream().map { AndroidResearchManager.featureResultTransformers.fromJson(it) }.filter { it != null }.collect(ImmutableList.toImmutableList<AndroidResultTransformer>()),
|
||||
)
|
||||
} else {
|
||||
throw JsonSyntaxException("Unknown element type ${value::class.qualifiedName}")
|
||||
@ -258,10 +258,12 @@ class AndroidResearchType(
|
||||
|
||||
private val descriptionLines: List<MutableComponent> = ImmutableList.copyOf(descriptionLines.map { it.copy() })
|
||||
|
||||
private val descriptionSuppliers: List<ComponentSupplier> = ImmutableList.copyOf(descriptionSuppliers)
|
||||
|
||||
/**
|
||||
* Stream containing copies of original [Component]s in list
|
||||
*/
|
||||
val description: Stream<out Component> get() = descriptionLines.stream().map { it.copy() }
|
||||
val description: Stream<out Component> get() = Streams.concat(descriptionLines.stream().map { it.copy() }, descriptionSuppliers.stream().map { it.apply(Unit) })
|
||||
|
||||
/**
|
||||
* Flat list of research preceding this research.
|
||||
@ -465,6 +467,7 @@ class AndroidResearchType(
|
||||
it["required_items"] = JsonArray().also { for (item in itemCollection) it.add(ItemStackCodec.serialize(item)) }
|
||||
it["feature_result"] = JsonArray().also { for (feature in features) it.add(feature.toJson()) }
|
||||
it["description"] = JsonArray().also { for (line in descriptionLines) it.add(Component.Serializer.toJsonTree(line)) }
|
||||
it["description_funcs"] = JsonArray().also { for (line in descriptionSuppliers) it.add(line.toJson()) }
|
||||
it["experience"] = JsonPrimitive(experienceLevels)
|
||||
|
||||
if (skinIcon != null) {
|
||||
@ -498,6 +501,7 @@ class AndroidResearchType(
|
||||
buff.writeCollection(itemCollection) { a, b -> a.writeItem(b) }
|
||||
buff.writeCollection(features) { a, b -> b.toNetwork(a) }
|
||||
buff.writeCollection(descriptionLines) { a, b -> a.writeComponent(b) }
|
||||
buff.writeCollection(descriptionSuppliers) { a, b -> b.toNetwork(a) }
|
||||
buff.writeVarInt(experienceLevels)
|
||||
|
||||
buff.writeBoolean(customName != null)
|
||||
@ -521,6 +525,7 @@ class AndroidResearchType(
|
||||
val items = buff.readCollection({ LinkedList() }, FriendlyByteBuf::readItem)
|
||||
val features = buff.readCollection({ LinkedList() }, FeatureReference::fromNetwork)
|
||||
val descriptionLines = buff.readCollection({ LinkedList() }, FriendlyByteBuf::readComponent)
|
||||
val descriptionSuppliers = buff.readCollection({ LinkedList() }, { AndroidResearchManager.descriptionFuncs.fromNetwork(it) })
|
||||
val experienceLevels = buff.readVarInt()
|
||||
|
||||
val customName = if (buff.readBoolean()) {
|
||||
@ -554,6 +559,7 @@ class AndroidResearchType(
|
||||
items = items,
|
||||
features = features,
|
||||
descriptionLines = descriptionLines,
|
||||
descriptionSuppliers = descriptionSuppliers.filterNotNull(),
|
||||
experienceLevels = experienceLevels,
|
||||
customName = customName,
|
||||
iconText = iconTextValue,
|
||||
@ -572,6 +578,7 @@ class AndroidResearchType(
|
||||
val items = value["required_items"] as JsonArray? ?: JsonArray()
|
||||
val features = value["feature_result"] as JsonArray? ?: JsonArray()
|
||||
val description = value["description"] as JsonArray? ?: JsonArray()
|
||||
val description_funcs = value["description_funcs"] as JsonArray? ?: JsonArray()
|
||||
val experience = value["experience"]?.asInt ?: 0
|
||||
val customName = value["custom_name"]?.let(Component.Serializer::fromJson)
|
||||
val iconText = value["icon_text"]?.let(Component.Serializer::fromJson)
|
||||
@ -585,6 +592,7 @@ class AndroidResearchType(
|
||||
features = features.stream().map { FeatureReference.fromJson(it) }.toList(),
|
||||
items = items.stream().map { ItemStackCodec.deserialize(it) }.filter { !it.isEmpty }.toList(),
|
||||
descriptionLines = description.stream().map { Component.Serializer.fromJson(it) }.toList() as List<MutableComponent>,
|
||||
descriptionSuppliers = description_funcs.stream().map { AndroidResearchManager.descriptionFuncs.fromJson(it) }.toList() as List<ComponentSupplier>,
|
||||
experienceLevels = experience,
|
||||
customName = customName,
|
||||
iconText = iconText,
|
||||
@ -600,6 +608,7 @@ class AndroidResearchType(
|
||||
var experience: Int = 0,
|
||||
var customName: Component? = null,
|
||||
var description: MutableList<Component>? = null,
|
||||
var descriptionSuppliers: MutableList<ComponentSupplier>? = null,
|
||||
var itemIcon: Item? = null,
|
||||
var skinIcon: SkinElement? = null,
|
||||
var iconText: Component? = null,
|
||||
@ -643,6 +652,17 @@ class AndroidResearchType(
|
||||
return this
|
||||
}
|
||||
|
||||
fun withDescription(range: IntRange): Builder {
|
||||
val result = ArrayList<Component>()
|
||||
|
||||
for (i in range) {
|
||||
result.add(TranslatableComponent("android_research.${id.namespace}.${id.path}.description$i"))
|
||||
}
|
||||
|
||||
this.description = result
|
||||
return this
|
||||
}
|
||||
|
||||
fun withExperience(experience: Int): Builder {
|
||||
this.experience = experience
|
||||
return this
|
||||
@ -653,11 +673,72 @@ class AndroidResearchType(
|
||||
return this
|
||||
}
|
||||
|
||||
fun withDescription(description: List<Component>): Builder {
|
||||
fun withDescription(description: Collection<Component>): Builder {
|
||||
this.description = ArrayList<Component>(description.size).also { it.addAll(description) }
|
||||
return this
|
||||
}
|
||||
|
||||
fun appendDescription(range: IntRange): Builder {
|
||||
val result = this.description ?: ArrayList()
|
||||
|
||||
for (i in range) {
|
||||
result.add(TranslatableComponent("android_research.${id.namespace}.${id.path}.description$i"))
|
||||
}
|
||||
|
||||
this.description = result
|
||||
return this
|
||||
}
|
||||
|
||||
fun appendDescription(description: Component): Builder {
|
||||
this.description = (this.description ?: mutableListOf()).also { it.add(description) }
|
||||
return this
|
||||
}
|
||||
|
||||
fun appendDescription(vararg description: Component): Builder {
|
||||
this.description = (this.description ?: mutableListOf()).also { it.addAll(description) }
|
||||
return this
|
||||
}
|
||||
|
||||
fun appendDescription(description: Collection<Component>): Builder {
|
||||
this.description = (this.description ?: mutableListOf()).also { it.addAll(description) }
|
||||
return this
|
||||
}
|
||||
|
||||
fun withDescription(vararg description: ComponentSupplier): Builder {
|
||||
this.descriptionSuppliers = description.toMutableList()
|
||||
return this
|
||||
}
|
||||
|
||||
fun withDescriptionSupplier(description: Collection<ComponentSupplier>): Builder {
|
||||
this.descriptionSuppliers = ArrayList<ComponentSupplier>(description.size).also { it.addAll(description) }
|
||||
return this
|
||||
}
|
||||
|
||||
fun appendDescription(description: ComponentSupplier): Builder {
|
||||
this.descriptionSuppliers = (this.descriptionSuppliers ?: mutableListOf()).also { it.add(description) }
|
||||
return this
|
||||
}
|
||||
|
||||
fun appendDescriptionSupplier(description: ComponentSupplier): Builder {
|
||||
this.descriptionSuppliers = (this.descriptionSuppliers ?: mutableListOf()).also { it.add(description) }
|
||||
return this
|
||||
}
|
||||
|
||||
fun appendDescription(vararg description: ComponentSupplier): Builder {
|
||||
this.descriptionSuppliers = (this.descriptionSuppliers ?: mutableListOf()).also { it.addAll(description) }
|
||||
return this
|
||||
}
|
||||
|
||||
fun appendDescriptionSupplier(vararg description: ComponentSupplier): Builder {
|
||||
this.descriptionSuppliers = (this.descriptionSuppliers ?: mutableListOf()).also { it.addAll(description) }
|
||||
return this
|
||||
}
|
||||
|
||||
fun appendDescriptionSupplier(description: Collection<ComponentSupplier>): Builder {
|
||||
this.descriptionSuppliers = (this.descriptionSuppliers ?: mutableListOf()).also { it.addAll(description) }
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Please avoid having multiple prerequisites as case with more than 1 prerequisite does not have proper
|
||||
* research tree render logic (yet).
|
||||
@ -686,8 +767,8 @@ class AndroidResearchType(
|
||||
id: ResourceLocation,
|
||||
level: Int = 0,
|
||||
rigid: Boolean = false,
|
||||
transformersUp: Collection<SerializedFunctionRegistry.BoundFunction<Pair<AndroidResearch, AndroidFeature>>> = listOf(),
|
||||
transformersDown: Collection<SerializedFunctionRegistry.BoundFunction<Pair<AndroidResearch, AndroidFeature>>> = listOf(),
|
||||
transformersUp: Collection<AndroidResultTransformer> = listOf(),
|
||||
transformersDown: Collection<AndroidResultTransformer> = listOf(),
|
||||
): Builder {
|
||||
features.add(FeatureReference(id, level, rigid, transformersUp, transformersDown))
|
||||
return this
|
||||
@ -698,8 +779,8 @@ class AndroidResearchType(
|
||||
feature: AndroidFeatureType<*>,
|
||||
level: Int = 0,
|
||||
rigid: Boolean = true,
|
||||
transformersUp: Collection<SerializedFunctionRegistry.BoundFunction<Pair<AndroidResearch, AndroidFeature>>> = listOf(),
|
||||
transformersDown: Collection<SerializedFunctionRegistry.BoundFunction<Pair<AndroidResearch, AndroidFeature>>> = listOf(),
|
||||
transformersUp: Collection<AndroidResultTransformer> = listOf(),
|
||||
transformersDown: Collection<AndroidResultTransformer> = listOf(),
|
||||
): Builder {
|
||||
features.add(FeatureReference(feature.registryName ?: throw NullPointerException("Feature $feature does not have registry name"), level, rigid, transformersUp, transformersDown))
|
||||
return this
|
||||
@ -708,8 +789,8 @@ class AndroidResearchType(
|
||||
fun addFeatureResult(
|
||||
id: ResourceLocation,
|
||||
rigid: Boolean = false,
|
||||
transformersUp: Collection<SerializedFunctionRegistry.BoundFunction<Pair<AndroidResearch, AndroidFeature>>> = listOf(),
|
||||
transformersDown: Collection<SerializedFunctionRegistry.BoundFunction<Pair<AndroidResearch, AndroidFeature>>> = listOf(),
|
||||
transformersUp: Collection<AndroidResultTransformer> = listOf(),
|
||||
transformersDown: Collection<AndroidResultTransformer> = listOf(),
|
||||
): Builder {
|
||||
features.add(FeatureReference(id, 0, rigid, transformersUp, transformersDown))
|
||||
return this
|
||||
@ -733,6 +814,7 @@ class AndroidResearchType(
|
||||
items = items,
|
||||
features = features,
|
||||
descriptionLines = description ?: listOf(),
|
||||
descriptionSuppliers = descriptionSuppliers ?: listOf(),
|
||||
experienceLevels = experience,
|
||||
customName = customName,
|
||||
skinIcon = skinIcon,
|
||||
|
@ -0,0 +1,147 @@
|
||||
package ru.dbotthepony.mc.otm.android.feature
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.client.multiplayer.ClientLevel
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraftforge.event.ForgeEventFactory
|
||||
import net.minecraftforge.network.NetworkEvent
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import ru.dbotthepony.mc.otm.ServerConfig
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearchManager
|
||||
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
|
||||
import ru.dbotthepony.mc.otm.capability.extractEnergyInner
|
||||
import ru.dbotthepony.mc.otm.capability.extractEnergyInnerExact
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.client.render.ResearchIcons
|
||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||
import ru.dbotthepony.mc.otm.core.Vector
|
||||
import ru.dbotthepony.mc.otm.core.formatPower
|
||||
import ru.dbotthepony.mc.otm.core.formatSi
|
||||
import ru.dbotthepony.mc.otm.core.getEntitiesInEllipsoid
|
||||
import ru.dbotthepony.mc.otm.core.minus
|
||||
import ru.dbotthepony.mc.otm.core.plus
|
||||
import ru.dbotthepony.mc.otm.core.position
|
||||
import ru.dbotthepony.mc.otm.core.times
|
||||
import ru.dbotthepony.mc.otm.network.MatteryPacket
|
||||
import ru.dbotthepony.mc.otm.network.WorldNetworkChannel
|
||||
import ru.dbotthepony.mc.otm.network.packetHandled
|
||||
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
||||
import ru.dbotthepony.mc.otm.registry.MNames
|
||||
import java.util.UUID
|
||||
import java.util.WeakHashMap
|
||||
import java.util.function.Predicate
|
||||
import java.util.function.Supplier
|
||||
|
||||
private data class SharedItemEntityData(val owner: UUID? = null, val age: Int = 0, val lifespan: Int = 0, val hasPickupDelay: Boolean = true) {
|
||||
companion object {
|
||||
val EMPTY = SharedItemEntityData()
|
||||
}
|
||||
}
|
||||
|
||||
private val datatable = WeakHashMap<ItemEntity, SharedItemEntityData>()
|
||||
|
||||
class ItemEntityDataPacket(val itemUUID: Int, val owner: UUID? = null, val age: Int = 0, val lifespan: Int = 0, val hasPickupDelay: Boolean = true) : MatteryPacket {
|
||||
override fun write(buff: FriendlyByteBuf) {
|
||||
buff.writeVarInt(itemUUID)
|
||||
buff.writeBoolean(owner != null)
|
||||
if (owner != null) buff.writeUUID(owner)
|
||||
buff.writeVarInt(age)
|
||||
buff.writeVarInt(lifespan)
|
||||
buff.writeBoolean(hasPickupDelay)
|
||||
}
|
||||
|
||||
override fun play(context: Supplier<NetworkEvent.Context>) {
|
||||
context.packetHandled = true
|
||||
val level = minecraft.player?.level as ClientLevel? ?: return
|
||||
val entity = level.getEntity(itemUUID) as ItemEntity? ?: return
|
||||
datatable[entity] = SharedItemEntityData(owner, age, lifespan, hasPickupDelay)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun read(buff: FriendlyByteBuf): ItemEntityDataPacket {
|
||||
return ItemEntityDataPacket(buff.readVarInt(), if (buff.readBoolean()) buff.readUUID() else null, buff.readVarInt(), buff.readVarInt(), buff.readBoolean())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ItemMagnetFeature(capability: MatteryPlayerCapability) : AndroidSwitchableFeature(AndroidFeatures.ITEM_MAGNET, capability) {
|
||||
private data class ItemPos(var position: Vector, var ticksSinceActivity: Int)
|
||||
private val rememberPositions = WeakHashMap<ItemEntity, ItemPos>()
|
||||
|
||||
private val serverPredicate = Predicate<Entity> { it is ItemEntity && !it.hasPickUpDelay() && (it.owner == null || it.owner != ply.uuid || it.lifespan - it.age <= 200) }
|
||||
private val clientPredicate = Predicate<Entity> { it is ItemEntity && (datatable[it] ?: SharedItemEntityData.EMPTY).let { !it.hasPickupDelay && (it.owner == null || it.owner != ply.uuid || it.lifespan - it.age <= 200) } }
|
||||
|
||||
private fun doTick(server: Boolean) {
|
||||
if (server && !android.androidEnergy.extractEnergyInnerExact(ServerConfig.AndroidItemMagnet.POWER_DRAW, true).isPositive) {
|
||||
return
|
||||
}
|
||||
|
||||
val entities = ply.level.getEntitiesInEllipsoid(
|
||||
ply.position,
|
||||
Vector(ServerConfig.AndroidItemMagnet.RADIUS_HORIZONTAL, ServerConfig.AndroidItemMagnet.RADIUS_VERTICAL, ServerConfig.AndroidItemMagnet.RADIUS_HORIZONTAL),
|
||||
if (server) Predicate<Entity> { it is ItemEntity } else clientPredicate
|
||||
)
|
||||
|
||||
for ((ent, distance) in entities) {
|
||||
ent as ItemEntity
|
||||
|
||||
if (server) {
|
||||
WorldNetworkChannel.send(ply, ItemEntityDataPacket(ent.id, ent.owner, ent.age, ent.lifespan, ent.hasPickUpDelay()))
|
||||
|
||||
if (!serverPredicate.test(ent)) {
|
||||
continue
|
||||
}
|
||||
|
||||
val data = rememberPositions.computeIfAbsent(ent) { ItemPos(it.position, 0) }
|
||||
|
||||
if (data.position.distanceToSqr(ent.position) < 1.0) {
|
||||
data.ticksSinceActivity++
|
||||
} else {
|
||||
if (!android.androidEnergy.extractEnergyInnerExact(ServerConfig.AndroidItemMagnet.POWER_DRAW, false).isPositive) {
|
||||
return
|
||||
}
|
||||
|
||||
data.position = ent.position
|
||||
data.ticksSinceActivity = 0
|
||||
}
|
||||
}
|
||||
|
||||
ent.deltaMovement += (ply.position - ent.position).normalize() * ((1.0 - distance) * 0.2)
|
||||
}
|
||||
}
|
||||
|
||||
override fun tickClient() {
|
||||
super.tickClient()
|
||||
|
||||
if (isActive && android.androidEnergy.extractEnergyInnerExact(ServerConfig.AndroidItemMagnet.POWER_DRAW, true).isPositive) {
|
||||
doTick(false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun tickServer() {
|
||||
super.tickServer()
|
||||
|
||||
if (isActive) {
|
||||
doTick(true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun renderIcon(stack: PoseStack, x: Float, y: Float, width: Float, height: Float) {
|
||||
ResearchIcons.ICON_ITEM_MAGNET.render(stack, x, y, width, height)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val POWER_COST_DESCRIPTION =
|
||||
AndroidResearchManager.descriptionFunc(ResourceLocation(
|
||||
OverdriveThatMatters.MOD_ID, MNames.ITEM_MAGNET),
|
||||
"otm.gui.power_cost_per_tick",
|
||||
{ ServerConfig.AndroidItemMagnet.POWER_DRAW.formatPower().copy().withStyle(ChatFormatting.YELLOW) })
|
||||
}
|
||||
}
|
@ -117,12 +117,5 @@ class NanobotsArmorFeature(android: MatteryPlayerCapability) : AndroidFeature(An
|
||||
(second as NanobotsArmorFeature).speed = level - 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy method just for static initializer to execute
|
||||
*/
|
||||
fun register() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,16 +2,24 @@ package ru.dbotthepony.mc.otm.android.feature
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.phys.AABB
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import ru.dbotthepony.mc.otm.ServerConfig
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearchManager
|
||||
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
|
||||
import ru.dbotthepony.mc.otm.capability.extractEnergyInnerExact
|
||||
import ru.dbotthepony.mc.otm.client.render.ResearchIcons
|
||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||
import ru.dbotthepony.mc.otm.core.Vector
|
||||
import ru.dbotthepony.mc.otm.core.formatPower
|
||||
import ru.dbotthepony.mc.otm.core.formatSi
|
||||
import ru.dbotthepony.mc.otm.core.getEllipsoidBlockPositions
|
||||
import ru.dbotthepony.mc.otm.core.getEntitiesInEllipsoid
|
||||
import ru.dbotthepony.mc.otm.core.getExplosionResistance
|
||||
import ru.dbotthepony.mc.otm.core.minus
|
||||
import ru.dbotthepony.mc.otm.core.plus
|
||||
@ -21,6 +29,7 @@ import ru.dbotthepony.mc.otm.core.times
|
||||
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
|
||||
import ru.dbotthepony.mc.otm.network.TriggerShockwavePacket
|
||||
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
||||
import ru.dbotthepony.mc.otm.registry.MNames
|
||||
import ru.dbotthepony.mc.otm.registry.ShockwaveDamageSource
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
@ -49,45 +58,21 @@ class ShockwaveFeature(capability: MatteryPlayerCapability) : AndroidSwitchableF
|
||||
cooldown = ServerConfig.Shockwave.COOLDOWN
|
||||
|
||||
// TODO: raycasting
|
||||
val entities = ply.level.getEntities(ply, AABB(
|
||||
ply.position.x - ServerConfig.Shockwave.RADIUS_HORIZONTAL,
|
||||
ply.position.y - ServerConfig.Shockwave.RADIUS_VERTICAL,
|
||||
ply.position.z - ServerConfig.Shockwave.RADIUS_HORIZONTAL,
|
||||
|
||||
ply.position.x + ServerConfig.Shockwave.RADIUS_HORIZONTAL,
|
||||
ply.position.y + ServerConfig.Shockwave.RADIUS_VERTICAL,
|
||||
ply.position.z + ServerConfig.Shockwave.RADIUS_HORIZONTAL,
|
||||
)) { (it !is LivingEntity || !it.isSpectator && it.isAlive) && ((it.position - ply.position).let { vec ->
|
||||
vec.x.pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0) +
|
||||
vec.y.pow(2.0) / ServerConfig.Shockwave.RADIUS_VERTICAL.pow(2.0) +
|
||||
vec.z.pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0) <= 1.0
|
||||
}) || it.boundingBox.center.let { vec ->
|
||||
(vec.x - ply.position.x).pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0) +
|
||||
(vec.y - ply.position.y).pow(2.0) / ServerConfig.Shockwave.RADIUS_VERTICAL.pow(2.0) +
|
||||
(vec.z - ply.position.z).pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0) <= 1.0
|
||||
} }
|
||||
|
||||
for (entity in entities) {
|
||||
val diff = entity.position - ply.position
|
||||
|
||||
val distanceMultiplier = diff.let {
|
||||
it.x.pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0) +
|
||||
it.y.pow(2.0) / ServerConfig.Shockwave.RADIUS_VERTICAL.pow(2.0) +
|
||||
it.z.pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0)
|
||||
}.coerceAtMost(entity.boundingBox.center.let { vec ->
|
||||
(vec.x - ply.position.x).pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0) +
|
||||
(vec.y - ply.position.y).pow(2.0) / ServerConfig.Shockwave.RADIUS_VERTICAL.pow(2.0) +
|
||||
(vec.z - ply.position.z).pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0)
|
||||
})
|
||||
val entities = ply.level.getEntitiesInEllipsoid(
|
||||
ply.position,
|
||||
Vector(ServerConfig.Shockwave.RADIUS_HORIZONTAL, ServerConfig.Shockwave.RADIUS_VERTICAL, ServerConfig.Shockwave.RADIUS_HORIZONTAL),
|
||||
except = ply,
|
||||
) { (it !is LivingEntity || !it.isSpectator && it.isAlive) }
|
||||
|
||||
for ((entity, distanceMultiplier) in entities) {
|
||||
val multiplier = (1.0 - distanceMultiplier).pow(1.25)
|
||||
|
||||
// don't hurt items, arrows, etc etc
|
||||
if (entity is LivingEntity) {
|
||||
entity.hurt(ShockwaveDamageSource(ply), multiplier.toFloat() * ServerConfig.Shockwave.DAMAGE.toFloat())
|
||||
entity.deltaMovement += diff.normalize() * (multiplier * 3.0)
|
||||
entity.deltaMovement += (entity.position - ply.position).normalize() * (multiplier * 3.0)
|
||||
} else {
|
||||
entity.deltaMovement += diff.normalize() * (multiplier * 6.0)
|
||||
entity.deltaMovement += (entity.position - ply.position).normalize() * (multiplier * 6.0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,4 +150,12 @@ class ShockwaveFeature(capability: MatteryPlayerCapability) : AndroidSwitchableF
|
||||
RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val POWER_COST_DESCRIPTION =
|
||||
AndroidResearchManager.descriptionFunc(
|
||||
ResourceLocation(OverdriveThatMatters.MOD_ID, MNames.SHOCKWAVE),
|
||||
"otm.gui.power_cost_per_use",
|
||||
{ ServerConfig.Shockwave.ENERGY_COST.formatPower().copy().withStyle(ChatFormatting.YELLOW) })
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ object ResearchIcons {
|
||||
val ICON_JUMP_BOOST: SkinElement
|
||||
|
||||
val ICON_FEATHER_FALLING: SkinElement
|
||||
val ICON_ARC: SkinElement
|
||||
val ICON_ITEM_MAGNET: SkinElement
|
||||
val ICON_ARROW: SkinElement
|
||||
val ICON_ARMOR: SkinElement
|
||||
val ICON_NANOBOTS: SkinElement
|
||||
@ -43,7 +43,7 @@ object ResearchIcons {
|
||||
ICON_JUMP_BOOST = grid.next()
|
||||
|
||||
ICON_FEATHER_FALLING = grid.next()
|
||||
ICON_ARC = grid.next()
|
||||
ICON_ITEM_MAGNET = grid.next()
|
||||
ICON_ARROW = grid.next()
|
||||
ICON_ARMOR = grid.next()
|
||||
ICON_NANOBOTS = grid.next()
|
||||
|
67
src/main/kotlin/ru/dbotthepony/mc/otm/core/LevelExt.kt
Normal file
67
src/main/kotlin/ru/dbotthepony/mc/otm/core/LevelExt.kt
Normal file
@ -0,0 +1,67 @@
|
||||
package ru.dbotthepony.mc.otm.core
|
||||
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.phys.AABB
|
||||
import java.util.function.Predicate
|
||||
import kotlin.math.pow
|
||||
|
||||
/**
|
||||
* Pair of entity and distance fraction to center of ellipsoid
|
||||
*/
|
||||
fun Level.getEntitiesInEllipsoid(pos: Vector, dimensions: Vector, except: Entity?, predicate: Predicate<in Entity>): List<Pair<Entity, Double>> {
|
||||
val entities = getEntities(except, AABB(
|
||||
pos.x - dimensions.x,
|
||||
pos.y - dimensions.y,
|
||||
pos.z - dimensions.z,
|
||||
|
||||
pos.x + dimensions.x,
|
||||
pos.y + dimensions.y,
|
||||
pos.z + dimensions.z,
|
||||
), predicate)
|
||||
|
||||
val result = ArrayList<Pair<Entity, Double>>()
|
||||
|
||||
for (it in entities) {
|
||||
val a = (it.position - pos).let { vec ->
|
||||
vec.x.pow(2.0) / dimensions.x.pow(2.0) +
|
||||
vec.y.pow(2.0) / dimensions.y.pow(2.0) +
|
||||
vec.z.pow(2.0) / dimensions.z.pow(2.0)
|
||||
}
|
||||
|
||||
val b = it.boundingBox.center.let { vec ->
|
||||
(vec.x - pos.x).pow(2.0) / dimensions.x.pow(2.0) +
|
||||
(vec.y - pos.y).pow(2.0) / dimensions.y.pow(2.0) +
|
||||
(vec.z - pos.z).pow(2.0) / dimensions.z.pow(2.0)
|
||||
}
|
||||
|
||||
val min = a.coerceAtMost(b)
|
||||
|
||||
if (min <= 1.0) {
|
||||
result.add(it to min)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Pair of entity and distance fraction to center of ellipsoid
|
||||
*/
|
||||
fun Level.getEntitiesInEllipsoid(pos: Vector, dimensions: Vector, predicate: Predicate<in Entity>): List<Pair<Entity, Double>> {
|
||||
return getEntitiesInEllipsoid(pos, dimensions, null, predicate)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pair of entity and distance fraction to center of ellipsoid
|
||||
*/
|
||||
fun Level.getEntitiesInSphere(pos: Vector, radius: Double, except: Entity?, predicate: Predicate<in Entity>): List<Pair<Entity, Double>> {
|
||||
return getEntitiesInEllipsoid(pos, Vector(radius, radius, radius), except, predicate)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pair of entity and distance fraction to center of ellipsoid
|
||||
*/
|
||||
fun Level.getEntitiesInSphere(pos: Vector, radius: Double, predicate: Predicate<in Entity>): List<Pair<Entity, Double>> {
|
||||
return getEntitiesInEllipsoid(pos, Vector(radius, radius, radius), null, predicate)
|
||||
}
|
@ -32,15 +32,15 @@ import java.util.Collections
|
||||
import java.util.LinkedList
|
||||
import java.util.function.Consumer
|
||||
|
||||
class SerializedFunctionRegistry<R>(val gson: Gson = Gson()) : JsonSerializer<SerializedFunctionRegistry.BoundFunction<R>>, JsonDeserializer<SerializedFunctionRegistry.BoundFunction<R>>, TypeAdapter<SerializedFunctionRegistry.BoundFunction<R>>() {
|
||||
fun interface AnonymousFunction<R> {
|
||||
fun invoke(receiver: R, arguments: List<Any?>)
|
||||
class SerializedFunctionRegistry<R, T>(val gson: Gson = Gson()) : JsonSerializer<SerializedFunctionRegistry.BoundFunction<R, T>>, JsonDeserializer<SerializedFunctionRegistry.BoundFunction<R, T>>, TypeAdapter<SerializedFunctionRegistry.BoundFunction<R, T>>() {
|
||||
fun interface AnonymousFunction<R, T> {
|
||||
fun invoke(receiver: R, arguments: List<Any?>): T
|
||||
}
|
||||
|
||||
data class BoundFunction<R>(
|
||||
val function: Function<R>,
|
||||
data class BoundFunction<R, T>(
|
||||
val function: Function<R, T>,
|
||||
val arguments: List<Any?>
|
||||
) : Consumer<R> {
|
||||
) : java.util.function.Function<R, T> {
|
||||
fun toJson(): JsonElement {
|
||||
return JsonObject().also {
|
||||
it["function"] = function.toJson()
|
||||
@ -67,22 +67,22 @@ class SerializedFunctionRegistry<R>(val gson: Gson = Gson()) : JsonSerializer<Se
|
||||
}
|
||||
}
|
||||
|
||||
override fun accept(t: R) {
|
||||
function.body.invoke(t, arguments)
|
||||
override fun apply(t: R): T {
|
||||
return function.body.invoke(t, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
data class Function<R>(
|
||||
data class Function<R, T>(
|
||||
val id: ResourceLocation,
|
||||
val body: AnonymousFunction<R>,
|
||||
val registry: SerializedFunctionRegistry<R>
|
||||
val body: AnonymousFunction<R, T>,
|
||||
val registry: SerializedFunctionRegistry<R, T>
|
||||
) {
|
||||
fun bind(vararg arguments: Any?): BoundFunction<R> {
|
||||
fun bind(vararg arguments: Any?): BoundFunction<R, T> {
|
||||
validate(arguments.iterator().withIndex())
|
||||
return BoundFunction(this, Collections.unmodifiableList(LinkedList<Any?>().also { it.addAll(arguments) }))
|
||||
}
|
||||
|
||||
fun bind(arguments: List<Any?>): BoundFunction<R> {
|
||||
fun bind(arguments: List<Any?>): BoundFunction<R, T> {
|
||||
validate(arguments.iterator().withIndex())
|
||||
return BoundFunction(this, Collections.unmodifiableList(LinkedList<Any?>().also { it.addAll(arguments) }))
|
||||
}
|
||||
@ -114,15 +114,22 @@ class SerializedFunctionRegistry<R>(val gson: Gson = Gson()) : JsonSerializer<Se
|
||||
}
|
||||
}
|
||||
|
||||
private val map = HashMap<ResourceLocation, Function<R>>()
|
||||
private val map = HashMap<ResourceLocation, Function<R, T>>()
|
||||
|
||||
fun register(id: ResourceLocation, function: AnonymousFunction<R>): Function<R> {
|
||||
fun register(id: ResourceLocation, function: AnonymousFunction<R, T>): Function<R, T> {
|
||||
synchronized(map) {
|
||||
return map.computeIfAbsent(id) { Function(id, function, this) }
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified A : Any> register(id: ResourceLocation, noinline function: R.(A) -> Unit): Function<R> {
|
||||
fun register(id: ResourceLocation, function: R.() -> T): Function<R, T> {
|
||||
return register(id, AnonymousFunction { r, args ->
|
||||
check(args.isEmpty()) { "Invalid amount of arguments. No arguments are required" }
|
||||
function.invoke(r)
|
||||
})
|
||||
}
|
||||
|
||||
inline fun <reified A : Any> register(id: ResourceLocation, noinline function: R.(A) -> T): Function<R, T> {
|
||||
return register(id, AnonymousFunction { r, args ->
|
||||
check(args.size == 1) { "Invalid amount of arguments. 1 is required" }
|
||||
function.invoke(
|
||||
@ -132,7 +139,7 @@ class SerializedFunctionRegistry<R>(val gson: Gson = Gson()) : JsonSerializer<Se
|
||||
})
|
||||
}
|
||||
|
||||
inline fun <reified A : Any, reified B : Any> register(id: ResourceLocation, noinline function: R.(A, B) -> Unit): Function<R> {
|
||||
inline fun <reified A : Any, reified B : Any> register(id: ResourceLocation, noinline function: R.(A, B) -> T): Function<R, T> {
|
||||
return register(id, AnonymousFunction { r, args ->
|
||||
check(args.size == 2) { "Invalid amount of arguments. 2 is required" }
|
||||
|
||||
@ -144,7 +151,7 @@ class SerializedFunctionRegistry<R>(val gson: Gson = Gson()) : JsonSerializer<Se
|
||||
})
|
||||
}
|
||||
|
||||
inline fun <reified A : Any, reified B : Any, reified C : Any> register(id: ResourceLocation, noinline function: R.(A, B, C) -> Unit): Function<R> {
|
||||
inline fun <reified A : Any, reified B : Any, reified C : Any> register(id: ResourceLocation, noinline function: R.(A, B, C) -> T): Function<R, T> {
|
||||
return register(id, AnonymousFunction { r, args ->
|
||||
check(args.size == 3) { "Invalid amount of arguments. 3 is required" }
|
||||
|
||||
@ -157,13 +164,13 @@ class SerializedFunctionRegistry<R>(val gson: Gson = Gson()) : JsonSerializer<Se
|
||||
})
|
||||
}
|
||||
|
||||
fun get(id: ResourceLocation): Function<R>? {
|
||||
fun get(id: ResourceLocation): Function<R, T>? {
|
||||
synchronized(map) {
|
||||
return map[id]
|
||||
}
|
||||
}
|
||||
|
||||
fun fromNetwork(buff: FriendlyByteBuf): BoundFunction<R>? {
|
||||
fun fromNetwork(buff: FriendlyByteBuf): BoundFunction<R, T>? {
|
||||
val id = ResourceLocation(buff.readUtf())
|
||||
val stream = DataInputStream(ByteBufInputStream(buff))
|
||||
|
||||
@ -176,7 +183,7 @@ class SerializedFunctionRegistry<R>(val gson: Gson = Gson()) : JsonSerializer<Se
|
||||
return map[id]?.bind(arguments)
|
||||
}
|
||||
|
||||
fun fromJson(value: JsonElement): BoundFunction<R>? {
|
||||
fun fromJson(value: JsonElement): BoundFunction<R, T>? {
|
||||
if (value !is JsonObject) {
|
||||
return null
|
||||
}
|
||||
@ -193,7 +200,7 @@ class SerializedFunctionRegistry<R>(val gson: Gson = Gson()) : JsonSerializer<Se
|
||||
return map[ResourceLocation(id)]?.bind(arguments)
|
||||
}
|
||||
|
||||
override fun serialize(src: BoundFunction<R>, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
|
||||
override fun serialize(src: BoundFunction<R, T>, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
|
||||
return src.toJson()
|
||||
}
|
||||
|
||||
@ -201,15 +208,15 @@ class SerializedFunctionRegistry<R>(val gson: Gson = Gson()) : JsonSerializer<Se
|
||||
json: JsonElement,
|
||||
typeOfT: Type,
|
||||
context: JsonDeserializationContext
|
||||
): BoundFunction<R> {
|
||||
): BoundFunction<R, T> {
|
||||
return fromJson(json) ?: throw JsonSyntaxException("Function is invalid")
|
||||
}
|
||||
|
||||
override fun write(out: JsonWriter, value: BoundFunction<R>) {
|
||||
override fun write(out: JsonWriter, value: BoundFunction<R, T>) {
|
||||
TypeAdapters.JSON_ELEMENT.write(out, value.toJson())
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): BoundFunction<R> {
|
||||
override fun read(`in`: JsonReader): BoundFunction<R, T> {
|
||||
return fromJson(TypeAdapters.JSON_ELEMENT.read(`in`)) ?: throw JsonSyntaxException("Function is invalid")
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package ru.dbotthepony.mc.otm.network
|
||||
|
||||
import net.minecraftforge.network.NetworkDirection
|
||||
import ru.dbotthepony.mc.otm.android.feature.ItemEntityDataPacket
|
||||
import ru.dbotthepony.mc.otm.block.entity.EnergyCounterPacket
|
||||
|
||||
object WorldNetworkChannel : MatteryNetworkChannel(
|
||||
@ -9,5 +10,6 @@ object WorldNetworkChannel : MatteryNetworkChannel(
|
||||
) {
|
||||
fun register() {
|
||||
add(EnergyCounterPacket::class.java, EnergyCounterPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT)
|
||||
add(ItemEntityDataPacket::class.java, ItemEntityDataPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT)
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ object AndroidFeatures {
|
||||
val EXTENDED_REACH: AndroidFeatureType<*> by registry.register(MNames.EXTENDED_REACH) { AndroidFeatureType(::ExtendedReachFeature) }
|
||||
val NIGHT_VISION: AndroidFeatureType<*> by registry.register(MNames.NIGHT_VISION) { AndroidFeatureType(::NightVisionFeature) }
|
||||
val SHOCKWAVE: AndroidFeatureType<*> by registry.register(MNames.SHOCKWAVE) { AndroidFeatureType(::ShockwaveFeature) }
|
||||
val ITEM_MAGNET: AndroidFeatureType<*> by registry.register(MNames.ITEM_MAGNET) { AndroidFeatureType(::ItemMagnetFeature) }
|
||||
|
||||
internal fun register(bus: IEventBus) {
|
||||
registry.register(bus)
|
||||
|
@ -209,6 +209,7 @@ object MNames {
|
||||
const val EXTENDED_REACH = "extended_reach"
|
||||
const val NIGHT_VISION = "night_vision"
|
||||
const val SHOCKWAVE = "shockwave"
|
||||
const val ITEM_MAGNET = "item_magnet"
|
||||
const val IMPROVED_LIMBS = "improved_limbs"
|
||||
|
||||
// stats
|
||||
|
@ -24,6 +24,9 @@ import net.minecraftforge.registries.RegistryBuilder
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import ru.dbotthepony.mc.otm.android.AndroidFeatureType
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearchType
|
||||
import ru.dbotthepony.mc.otm.android.feature.ItemMagnetFeature
|
||||
import ru.dbotthepony.mc.otm.android.feature.NanobotsArmorFeature
|
||||
import ru.dbotthepony.mc.otm.android.feature.ShockwaveFeature
|
||||
import ru.dbotthepony.mc.otm.block.CargoCrateBlock
|
||||
import ru.dbotthepony.mc.otm.registry.objects.ColoredDecorativeBlock
|
||||
import ru.dbotthepony.mc.otm.registry.objects.CrateProperties
|
||||
@ -230,5 +233,10 @@ object MRegistry {
|
||||
LootModifiers.register(bus)
|
||||
|
||||
MRecipes.register(bus)
|
||||
|
||||
// call static constructors
|
||||
NanobotsArmorFeature.Companion
|
||||
ShockwaveFeature.Companion
|
||||
ItemMagnetFeature.Companion
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user