Android switchable features, android night vision
Achieved with cry engine two™️
This commit is contained in:
parent
ca70916331
commit
71f3ad133e
@ -18,6 +18,7 @@ import ru.dbotthepony.mc.otm.block.entity.blackhole.ExplosionQueue;
|
|||||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||||
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability;
|
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability;
|
||||||
import ru.dbotthepony.mc.otm.capability.drive.DrivePool;
|
import ru.dbotthepony.mc.otm.capability.drive.DrivePool;
|
||||||
|
import ru.dbotthepony.mc.otm.client.AndroidMenuKeyMapping;
|
||||||
import ru.dbotthepony.mc.otm.client.ClientEventHandlerKt;
|
import ru.dbotthepony.mc.otm.client.ClientEventHandlerKt;
|
||||||
import ru.dbotthepony.mc.otm.client.MatteryGUI;
|
import ru.dbotthepony.mc.otm.client.MatteryGUI;
|
||||||
import ru.dbotthepony.mc.otm.client.model.GravitationStabilizerModel;
|
import ru.dbotthepony.mc.otm.client.model.GravitationStabilizerModel;
|
||||||
@ -105,6 +106,7 @@ public final class OverdriveThatMatters {
|
|||||||
EVENT_BUS.addListener(EventPriority.LOWEST, GlobalEventHandlerKt::onServerTick);
|
EVENT_BUS.addListener(EventPriority.LOWEST, GlobalEventHandlerKt::onServerTick);
|
||||||
|
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onPlayerTick);
|
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onPlayerTick);
|
||||||
|
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::isMobEffectApplicable);
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onHurtEvent);
|
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onHurtEvent);
|
||||||
EVENT_BUS.addGenericListener(Entity.class, EventPriority.NORMAL, MatteryPlayerCapability.Companion::onAttachCapabilityEvent);
|
EVENT_BUS.addGenericListener(Entity.class, EventPriority.NORMAL, MatteryPlayerCapability.Companion::onAttachCapabilityEvent);
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onPlayerChangeDimensionEvent);
|
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onPlayerChangeDimensionEvent);
|
||||||
@ -162,6 +164,9 @@ public final class OverdriveThatMatters {
|
|||||||
EVENT_BUS.addListener(EventPriority.NORMAL, TooltipsKt::tooltipEvent);
|
EVENT_BUS.addListener(EventPriority.NORMAL, TooltipsKt::tooltipEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FMLJavaModLoadingContext.get().getModEventBus().addListener(EventPriority.NORMAL, AndroidMenuKeyMapping.INSTANCE::register);
|
||||||
|
EVENT_BUS.addListener(EventPriority.NORMAL, AndroidMenuKeyMapping.INSTANCE::onRenderGuiEvent);
|
||||||
|
|
||||||
event.enqueueWork(GlobalEventHandlerKt::recordClientThread);
|
event.enqueueWork(GlobalEventHandlerKt::recordClientThread);
|
||||||
|
|
||||||
TritaniumArmorModel.register();
|
TritaniumArmorModel.register();
|
||||||
|
@ -82,7 +82,7 @@ object ServerConfig {
|
|||||||
init {
|
init {
|
||||||
specBuilder.comment("Serverside config, holds shared values that are required to be read by both client and server.").push("server")
|
specBuilder.comment("Serverside config, holds shared values that are required to be read by both client and server.").push("server")
|
||||||
|
|
||||||
specBuilder.comment("Energy batteries balance values").push("energy_batteries")
|
specBuilder.comment("Energy batteries balance values").push("energyBatteries")
|
||||||
}
|
}
|
||||||
|
|
||||||
val BATTERY_CRUDE = batteryValues(MNames.BATTERY_CRUDE, ImpreciseFraction(100_000), ImpreciseFraction(160), ImpreciseFraction(40), ImpreciseFraction(80_000))
|
val BATTERY_CRUDE = batteryValues(MNames.BATTERY_CRUDE, ImpreciseFraction(100_000), ImpreciseFraction(160), ImpreciseFraction(40), ImpreciseFraction(80_000))
|
||||||
@ -99,7 +99,7 @@ object ServerConfig {
|
|||||||
init {
|
init {
|
||||||
specBuilder.pop()
|
specBuilder.pop()
|
||||||
|
|
||||||
specBuilder.comment("Matter capacitors and pattern drives balance values").push("matter_capacitors_and_drives")
|
specBuilder.comment("Matter capacitors and pattern drives balance values").push("matterCapacitorsAndDrives")
|
||||||
}
|
}
|
||||||
|
|
||||||
val MATTER_CAPACITOR_BASIC by specBuilder.defineImpreciseFraction(MNames.MATTER_CAPACITOR_BASIC, ImpreciseFraction(2), minimum = ImpreciseFraction.ONE_TENTH)
|
val MATTER_CAPACITOR_BASIC by specBuilder.defineImpreciseFraction(MNames.MATTER_CAPACITOR_BASIC, ImpreciseFraction(2), minimum = ImpreciseFraction.ONE_TENTH)
|
||||||
@ -131,16 +131,18 @@ object ServerConfig {
|
|||||||
init {
|
init {
|
||||||
specBuilder.pop()
|
specBuilder.pop()
|
||||||
|
|
||||||
specBuilder.comment("Tweaking of android players").push("android_player")
|
specBuilder.comment("Tweaking of android players").push("androidPlayer")
|
||||||
}
|
}
|
||||||
|
|
||||||
val ANDROID_ENERGY_PER_HUNGER_POINT by specBuilder.defineImpreciseFraction("energy_per_hunger", ImpreciseFraction(1000), ImpreciseFraction.ZERO)
|
val ANDROID_ENERGY_PER_HUNGER_POINT by specBuilder.defineImpreciseFraction("energyPerHunger", ImpreciseFraction(1000), ImpreciseFraction.ZERO)
|
||||||
val ANDROID_MAX_ENERGY by specBuilder.comment("Internal battery of every android has this much storage").defineImpreciseFraction("capacity", ImpreciseFraction(80_000), ImpreciseFraction.ZERO)
|
val ANDROID_MAX_ENERGY by specBuilder.comment("Internal battery of every android has this much storage").defineImpreciseFraction("capacity", ImpreciseFraction(80_000), ImpreciseFraction.ZERO)
|
||||||
|
|
||||||
|
val NIGHT_VISION_POWER_DRAW by specBuilder.defineImpreciseFraction("nightVisionPowerDraw", ImpreciseFraction(8), ImpreciseFraction.ZERO)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
specBuilder.pop()
|
specBuilder.pop()
|
||||||
|
|
||||||
specBuilder.comment("Tweaking of exosuits").push("exosuit_player")
|
specBuilder.comment("Tweaking of exosuits").push("exosuitPlayer")
|
||||||
}
|
}
|
||||||
|
|
||||||
val INFINITE_EXOSUIT_UPGRADES: Boolean by specBuilder.comment("Allows to apply the same upgrade over and over again.", "Obviously completely breaks balance.").define("infinite_upgrades", false)
|
val INFINITE_EXOSUIT_UPGRADES: Boolean by specBuilder.comment("Allows to apply the same upgrade over and over again.", "Obviously completely breaks balance.").define("infinite_upgrades", false)
|
||||||
|
@ -18,6 +18,11 @@ typealias ResearchCallback = ((research: AndroidResearch, feature: AndroidFeatur
|
|||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
class AndroidResearchBuilder(
|
class AndroidResearchBuilder(
|
||||||
var experience: Int = 0,
|
var experience: Int = 0,
|
||||||
|
var name: Component? = null,
|
||||||
|
var customDescription: MutableList<Component>? = null,
|
||||||
|
var hasDescription: Boolean = false,
|
||||||
|
var skinIcon: SkinElement? = null,
|
||||||
|
var iconText: Component? = null,
|
||||||
) {
|
) {
|
||||||
private val items = ArrayList<ItemStack>()
|
private val items = ArrayList<ItemStack>()
|
||||||
private val prerequisites = ArrayList<Pair<() -> ResourceLocation, Boolean>>()
|
private val prerequisites = ArrayList<Pair<() -> ResourceLocation, Boolean>>()
|
||||||
@ -38,12 +43,6 @@ class AndroidResearchBuilder(
|
|||||||
val callbackResearched: ResearchCallback?
|
val callbackResearched: ResearchCallback?
|
||||||
)
|
)
|
||||||
|
|
||||||
var name: Component? = null
|
|
||||||
var description: MutableList<Component>? = null
|
|
||||||
var hasDescription = false
|
|
||||||
var skinIcon: SkinElement? = null
|
|
||||||
var iconText: Component? = null
|
|
||||||
|
|
||||||
fun withIconText(icon: Component?): AndroidResearchBuilder {
|
fun withIconText(icon: Component?): AndroidResearchBuilder {
|
||||||
this.iconText = icon
|
this.iconText = icon
|
||||||
return this
|
return this
|
||||||
@ -58,7 +57,7 @@ class AndroidResearchBuilder(
|
|||||||
|
|
||||||
fun withDescription(): AndroidResearchBuilder {
|
fun withDescription(): AndroidResearchBuilder {
|
||||||
this.hasDescription = true
|
this.hasDescription = true
|
||||||
this.description = null
|
this.customDescription = null
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,12 +67,12 @@ class AndroidResearchBuilder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun withDescription(vararg description: Component): AndroidResearchBuilder {
|
fun withDescription(vararg description: Component): AndroidResearchBuilder {
|
||||||
this.description = description.toMutableList()
|
this.customDescription = description.toMutableList()
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun withDescription(description: List<Component>): AndroidResearchBuilder {
|
fun withDescription(description: List<Component>): AndroidResearchBuilder {
|
||||||
this.description = ArrayList<Component>(description.size).also { it.addAll(description) }
|
this.customDescription = ArrayList<Component>(description.size).also { it.addAll(description) }
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +154,7 @@ class AndroidResearchBuilder(
|
|||||||
val experience = this.experience
|
val experience = this.experience
|
||||||
|
|
||||||
val name = name?.copy()
|
val name = name?.copy()
|
||||||
val description = description?.let {
|
val description = customDescription?.let {
|
||||||
val builder = ImmutableList.builder<Component>()
|
val builder = ImmutableList.builder<Component>()
|
||||||
|
|
||||||
for (component in it) {
|
for (component in it) {
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.android
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
|
||||||
|
import ru.dbotthepony.mc.otm.core.set
|
||||||
|
|
||||||
|
abstract class AndroidSwitchableFeature(type: AndroidFeatureType<*>, android: MatteryPlayerCapability) : AndroidFeature(type, android) {
|
||||||
|
var isActive by synchronizer.bool(setter = setter@{ value, access, setByRemote ->
|
||||||
|
if (value != access.read()) {
|
||||||
|
access.write(value)
|
||||||
|
|
||||||
|
if (!setByRemote) {
|
||||||
|
if (value) {
|
||||||
|
applyModifiers()
|
||||||
|
} else {
|
||||||
|
removeModifiers()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
open val allowToSwitchByPlayer: Boolean get() = true
|
||||||
|
|
||||||
|
abstract fun renderIcon(stack: PoseStack, x: Float, y: Float, width: Float, height: Float)
|
||||||
|
|
||||||
|
override fun serializeNBT(): CompoundTag {
|
||||||
|
return super.serializeNBT().also {
|
||||||
|
it["isActive"] = isActive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserializeNBT(nbt: CompoundTag) {
|
||||||
|
super.deserializeNBT(nbt)
|
||||||
|
isActive = nbt.getBoolean("isActive")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.android.feature
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance
|
||||||
|
import net.minecraft.world.effect.MobEffects
|
||||||
|
import ru.dbotthepony.mc.otm.ServerConfig
|
||||||
|
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.registry.AndroidFeatures
|
||||||
|
import ru.dbotthepony.mc.otm.registry.AndroidResearch
|
||||||
|
|
||||||
|
class NightVisionFeature(android: MatteryPlayerCapability) : AndroidSwitchableFeature(AndroidFeatures.NIGHT_VISION, android) {
|
||||||
|
override fun tickServer() {
|
||||||
|
if (isActive) {
|
||||||
|
val effect = android.ply.activeEffectsMap[MobEffects.NIGHT_VISION]
|
||||||
|
|
||||||
|
if ((effect == null || effect.duration < 220) && android.androidEnergy.extractEnergyInnerExact(ServerConfig.NIGHT_VISION_POWER_DRAW, true).isPositive) {
|
||||||
|
android.ply.addEffect(MobEffectInstance(MobEffects.NIGHT_VISION, 220))
|
||||||
|
android.androidEnergy.extractEnergyInner(ServerConfig.NIGHT_VISION_POWER_DRAW, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeModifiers() {
|
||||||
|
val effect = android.ply.activeEffectsMap[MobEffects.NIGHT_VISION]
|
||||||
|
|
||||||
|
if (effect != null && effect.duration <= 222) {
|
||||||
|
android.ply.removeEffect(MobEffects.NIGHT_VISION)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun renderIcon(stack: PoseStack, x: Float, y: Float, width: Float, height: Float) {
|
||||||
|
AndroidResearch.ICON_NIGHT_VISION.render(stack, x, y, width, height)
|
||||||
|
}
|
||||||
|
}
|
@ -31,6 +31,7 @@ import net.minecraftforge.event.entity.living.LivingDeathEvent
|
|||||||
import net.minecraftforge.event.entity.living.LivingDropsEvent
|
import net.minecraftforge.event.entity.living.LivingDropsEvent
|
||||||
import net.minecraftforge.event.entity.living.LivingHurtEvent
|
import net.minecraftforge.event.entity.living.LivingHurtEvent
|
||||||
import net.minecraftforge.event.entity.living.LivingSpawnEvent
|
import net.minecraftforge.event.entity.living.LivingSpawnEvent
|
||||||
|
import net.minecraftforge.event.entity.living.MobEffectEvent
|
||||||
import net.minecraftforge.event.entity.player.EntityItemPickupEvent
|
import net.minecraftforge.event.entity.player.EntityItemPickupEvent
|
||||||
import net.minecraftforge.event.entity.player.PlayerEvent
|
import net.minecraftforge.event.entity.player.PlayerEvent
|
||||||
import net.minecraftforge.eventbus.api.Event
|
import net.minecraftforge.eventbus.api.Event
|
||||||
@ -49,6 +50,7 @@ import ru.dbotthepony.mc.otm.network.*
|
|||||||
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
||||||
import ru.dbotthepony.mc.otm.registry.MRegistry
|
import ru.dbotthepony.mc.otm.registry.MRegistry
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.stream.Stream
|
||||||
import kotlin.collections.ArrayDeque
|
import kotlin.collections.ArrayDeque
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
@ -170,7 +172,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
|
|
||||||
private val deathLog = ArrayDeque<Pair<Int, Component>>()
|
private val deathLog = ArrayDeque<Pair<Int, Component>>()
|
||||||
|
|
||||||
private val features = IdentityHashMap<AndroidFeatureType<*>, AndroidFeature>()
|
private val featureMap = IdentityHashMap<AndroidFeatureType<*>, AndroidFeature>()
|
||||||
private val networkQueue = ArrayList<Any>()
|
private val networkQueue = ArrayList<Any>()
|
||||||
private val queuedTicks = ArrayList<Runnable>()
|
private val queuedTicks = ArrayList<Runnable>()
|
||||||
private var tickedOnce = false
|
private var tickedOnce = false
|
||||||
@ -252,7 +254,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val copy = ArrayList<AndroidFeature>(features.values.size).also { it.addAll(features.values) }
|
val copy = ArrayList<AndroidFeature>(featureMap.values.size).also { it.addAll(featureMap.values) }
|
||||||
|
|
||||||
for (feature in copy) {
|
for (feature in copy) {
|
||||||
removeFeature(feature.type)
|
removeFeature(feature.type)
|
||||||
@ -268,9 +270,11 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
} as T
|
} as T
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val features: Stream<out AndroidFeature> get() = featureMap.values.stream()
|
||||||
|
|
||||||
private fun addFeature(feature: AndroidFeature): Boolean {
|
private fun addFeature(feature: AndroidFeature): Boolean {
|
||||||
if (features.containsKey(feature.type)) return false
|
if (featureMap.containsKey(feature.type)) return false
|
||||||
features[feature.type] = feature
|
featureMap[feature.type] = feature
|
||||||
|
|
||||||
if (!ply.level.isClientSide) {
|
if (!ply.level.isClientSide) {
|
||||||
queuedTicks.add(feature::applyModifiers)
|
queuedTicks.add(feature::applyModifiers)
|
||||||
@ -290,12 +294,12 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
|
|
||||||
@Suppress("unchecked_cast")
|
@Suppress("unchecked_cast")
|
||||||
fun <T : AndroidFeature> addFeature(feature: AndroidFeatureType<T>): T {
|
fun <T : AndroidFeature> addFeature(feature: AndroidFeatureType<T>): T {
|
||||||
val get = features[feature]
|
val get = featureMap[feature]
|
||||||
if (get != null) return get as T
|
if (get != null) return get as T
|
||||||
|
|
||||||
val factory = feature.create(this)
|
val factory = feature.create(this)
|
||||||
|
|
||||||
features[feature] = factory
|
featureMap[feature] = factory
|
||||||
|
|
||||||
if (!ply.level.isClientSide) {
|
if (!ply.level.isClientSide) {
|
||||||
queuedTicks.add(factory::applyModifiers)
|
queuedTicks.add(factory::applyModifiers)
|
||||||
@ -314,7 +318,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun removeFeature(feature: AndroidFeatureType<*>): Boolean {
|
fun removeFeature(feature: AndroidFeatureType<*>): Boolean {
|
||||||
val removed = features.remove(feature)
|
val removed = featureMap.remove(feature)
|
||||||
|
|
||||||
if (removed != null) {
|
if (removed != null) {
|
||||||
if (!ply.level.isClientSide) {
|
if (!ply.level.isClientSide) {
|
||||||
@ -332,21 +336,21 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun hasFeature(feature: AndroidFeatureType<*>): Boolean {
|
fun hasFeature(feature: AndroidFeatureType<*>): Boolean {
|
||||||
return features.containsKey(feature)
|
return featureMap.containsKey(feature)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasFeatureLevel(feature: AndroidFeatureType<*>, level: Int): Boolean {
|
fun hasFeatureLevel(feature: AndroidFeatureType<*>, level: Int): Boolean {
|
||||||
val get = features[feature] ?: return false
|
val get = featureMap[feature] ?: return false
|
||||||
return get.level >= level
|
return get.level >= level
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unchecked_cast")
|
@Suppress("unchecked_cast")
|
||||||
fun <T : AndroidFeature> getFeature(feature: AndroidFeatureType<T>): T? {
|
fun <T : AndroidFeature> getFeature(feature: AndroidFeatureType<T>): T? {
|
||||||
return features[feature] as T?
|
return featureMap[feature] as T?
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onHurt(event: LivingHurtEvent) {
|
fun onHurt(event: LivingHurtEvent) {
|
||||||
for (feature in features.values) {
|
for (feature in featureMap.values) {
|
||||||
feature.onHurt(event)
|
feature.onHurt(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -401,7 +405,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
val featureList = ListTag()
|
val featureList = ListTag()
|
||||||
val researchList = ListTag()
|
val researchList = ListTag()
|
||||||
|
|
||||||
for (feature in features.values) {
|
for (feature in featureMap.values) {
|
||||||
featureList.add(feature.serializeNBT().also {
|
featureList.add(feature.serializeNBT().also {
|
||||||
it["id"] = feature.type.registryName!!.toString()
|
it["id"] = feature.type.registryName!!.toString()
|
||||||
})
|
})
|
||||||
@ -449,7 +453,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
|
|
||||||
tag.map("androidEnergy", androidEnergy::deserializeNBT)
|
tag.map("androidEnergy", androidEnergy::deserializeNBT)
|
||||||
|
|
||||||
features.clear()
|
featureMap.clear()
|
||||||
research.clear()
|
research.clear()
|
||||||
|
|
||||||
for (featureTag in tag.getCompoundList("features")) {
|
for (featureTag in tag.getCompoundList("features")) {
|
||||||
@ -512,7 +516,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isAndroid) {
|
if (isAndroid) {
|
||||||
for (feature in features.values) {
|
for (feature in featureMap.values) {
|
||||||
feature.tickClient()
|
feature.tickClient()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -582,7 +586,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
stats.setExhaustion(stats.exhaustionLevel - (extracted / ServerConfig.ANDROID_ENERGY_PER_HUNGER_POINT).toFloat() * 4f)
|
stats.setExhaustion(stats.exhaustionLevel - (extracted / ServerConfig.ANDROID_ENERGY_PER_HUNGER_POINT).toFloat() * 4f)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (feature in features.values) {
|
for (feature in featureMap.values) {
|
||||||
feature.tickServer()
|
feature.tickServer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -600,7 +604,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
instance.invalidateNetwork()
|
instance.invalidateNetwork()
|
||||||
}
|
}
|
||||||
|
|
||||||
for (feature in features.values) {
|
for (feature in featureMap.values) {
|
||||||
feature.invalidateNetwork()
|
feature.invalidateNetwork()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -629,7 +633,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (instance in features.values) {
|
for (instance in featureMap.values) {
|
||||||
val featurePayload = instance.collectNetworkPayload()
|
val featurePayload = instance.collectNetworkPayload()
|
||||||
|
|
||||||
if (featurePayload != null) {
|
if (featurePayload != null) {
|
||||||
@ -683,6 +687,14 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isMobEffectApplicable(event: MobEffectEvent.Applicable) {
|
||||||
|
event.entity.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK {
|
||||||
|
if (it.isAndroid && ForgeRegistries.MOB_EFFECTS.tags()?.getTag(ANDROID_IMMUNE_EFFECTS)?.stream()?.anyMatch { it == event.effectInstance.effect } == true) {
|
||||||
|
event.result = Event.Result.DENY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onHurtEvent(event: LivingHurtEvent) {
|
fun onHurtEvent(event: LivingHurtEvent) {
|
||||||
if (event.isCanceled) {
|
if (event.isCanceled) {
|
||||||
return
|
return
|
||||||
|
@ -0,0 +1,161 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.client
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.InputConstants
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem
|
||||||
|
import net.minecraft.client.KeyMapping
|
||||||
|
import net.minecraftforge.client.event.RegisterKeyMappingsEvent
|
||||||
|
import net.minecraftforge.client.event.RenderGuiEvent
|
||||||
|
import net.minecraftforge.client.settings.KeyConflictContext
|
||||||
|
import org.lwjgl.glfw.GLFW.GLFW_CURSOR_DISABLED
|
||||||
|
import org.lwjgl.glfw.GLFW.GLFW_CURSOR_NORMAL
|
||||||
|
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||||
|
import ru.dbotthepony.mc.otm.android.AndroidFeatureType
|
||||||
|
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
|
||||||
|
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.drawArc
|
||||||
|
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
|
||||||
|
import ru.dbotthepony.mc.otm.network.SwitchAndroidFeaturePacket
|
||||||
|
import java.util.stream.Collectors
|
||||||
|
import kotlin.math.PI
|
||||||
|
import kotlin.math.acos
|
||||||
|
import kotlin.math.cos
|
||||||
|
import kotlin.math.pow
|
||||||
|
import kotlin.math.sin
|
||||||
|
|
||||||
|
// TODO: forge's KeyMapping patch (ALL and MAP maps) is not thread safe... should we be worried?
|
||||||
|
object AndroidMenuKeyMapping : KeyMapping("key.otm.android_menu", KeyConflictContext.IN_GAME, InputConstants.Type.KEYSYM.getOrCreate(InputConstants.KEY_F), OverdriveThatMatters.MOD_ID) {
|
||||||
|
private var grabbedInput = false
|
||||||
|
private var selectedFeature: AndroidSwitchableFeature? = null
|
||||||
|
|
||||||
|
override fun setDown(isDown: Boolean) {
|
||||||
|
val old = this.isDown
|
||||||
|
super.setDown(isDown)
|
||||||
|
|
||||||
|
if (old != isDown) {
|
||||||
|
if (
|
||||||
|
minecraft.screen == null &&
|
||||||
|
isDown &&
|
||||||
|
minecraft.player?.matteryPlayer?.isAndroid == true &&
|
||||||
|
minecraft.player?.matteryPlayer?.features?.anyMatch { it is AndroidSwitchableFeature && it.allowToSwitchByPlayer } == true
|
||||||
|
) {
|
||||||
|
grabbedInput = true
|
||||||
|
minecraft.mouseHandler.releaseMouse()
|
||||||
|
} else if (!isDown && grabbedInput) {
|
||||||
|
grabbedInput = false
|
||||||
|
|
||||||
|
if (minecraft.screen == null) {
|
||||||
|
minecraft.mouseHandler.grabMouse()
|
||||||
|
|
||||||
|
val selectedFeature = selectedFeature
|
||||||
|
if (selectedFeature != null) {
|
||||||
|
MatteryPlayerNetworkChannel.sendToServer(SwitchAndroidFeaturePacket(selectedFeature.type, !selectedFeature.isActive))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedFeature = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onRenderGuiEvent(event: RenderGuiEvent.Post) {
|
||||||
|
if (!grabbedInput) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val features = minecraft.player?.matteryPlayer?.features?.filter { it is AndroidSwitchableFeature && it.allowToSwitchByPlayer }?.collect(Collectors.toList()) as MutableList<AndroidSwitchableFeature>? ?: return
|
||||||
|
|
||||||
|
if (features.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderSystem.setShaderColor(0f, 0f, 0f, 0.75f)
|
||||||
|
|
||||||
|
val size = minecraft.window.guiScaledHeight.coerceAtMost(minecraft.window.guiScaledWidth).toFloat() * 0.35f
|
||||||
|
|
||||||
|
drawArc(
|
||||||
|
event.poseStack,
|
||||||
|
minecraft.window.guiScaledWidth / 2f,
|
||||||
|
minecraft.window.guiScaledHeight / 2f,
|
||||||
|
size,
|
||||||
|
size * 0.3f
|
||||||
|
)
|
||||||
|
|
||||||
|
RenderSystem.setShaderColor(85 / 255f, 197 / 255f, 255 / 255f, 0.5f)
|
||||||
|
|
||||||
|
val degreePerSlice = PI * 2.0 / features.size
|
||||||
|
|
||||||
|
var (mouseX, mouseY) = mousePos
|
||||||
|
|
||||||
|
mouseX -= minecraft.window.width / 2.0
|
||||||
|
mouseY -= minecraft.window.height / 2.0
|
||||||
|
|
||||||
|
//font.drawAligned(event.poseStack, mouseX.toString(), TextAlign.CENTER_CENTER, 100f, 40f, RGBAColor.WHITE)
|
||||||
|
//font.drawAligned(event.poseStack, mouseY.toString(), TextAlign.CENTER_CENTER, 100f, 60f, RGBAColor.WHITE)
|
||||||
|
|
||||||
|
val length = (mouseX * mouseX + mouseY * mouseY).pow(0.5)
|
||||||
|
|
||||||
|
if ((length / minecraft.window.guiScale) in (size * 0.3f) .. size) {
|
||||||
|
var deg = acos(mouseX / length)
|
||||||
|
|
||||||
|
// opengl
|
||||||
|
// lower values are at bottom of screen
|
||||||
|
if (mouseY > 0.0) {
|
||||||
|
deg = -deg
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deg < 0.0) {
|
||||||
|
deg += PI * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
//font.drawAligned(event.poseStack, deg.toString(), TextAlign.CENTER_CENTER, 100f, 20f, RGBAColor.WHITE)
|
||||||
|
|
||||||
|
val index = (deg / degreePerSlice).toInt()
|
||||||
|
selectedFeature = features[index]
|
||||||
|
|
||||||
|
//font.drawAligned(event.poseStack, index.toString(), TextAlign.CENTER_CENTER, 100f, 80f, RGBAColor.WHITE)
|
||||||
|
|
||||||
|
RenderSystem.setShaderColor(85 / 255f, 197 / 255f, 255 / 255f, 0.3f)
|
||||||
|
|
||||||
|
drawArc(
|
||||||
|
event.poseStack,
|
||||||
|
minecraft.window.guiScaledWidth / 2f,
|
||||||
|
minecraft.window.guiScaledHeight / 2f,
|
||||||
|
size * 1.2f,
|
||||||
|
size * 0.4f,
|
||||||
|
|
||||||
|
startDegree = index * degreePerSlice,
|
||||||
|
endDegree = (index + 1) * degreePerSlice
|
||||||
|
)
|
||||||
|
|
||||||
|
//font.drawAligned(event.poseStack, (index * degreePerSlice).toString(), TextAlign.CENTER_CENTER, 100f, 100f, RGBAColor.WHITE)
|
||||||
|
} else {
|
||||||
|
selectedFeature = null
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
|
||||||
|
|
||||||
|
val iconSize = size * 0.25f
|
||||||
|
|
||||||
|
event.poseStack.pushPose()
|
||||||
|
event.poseStack.translate(minecraft.window.guiScaledWidth.toDouble() / 2f, minecraft.window.guiScaledHeight.toDouble() / 2f, 0.0)
|
||||||
|
|
||||||
|
if (features.size == 1) {
|
||||||
|
val feature = features.first()
|
||||||
|
|
||||||
|
feature.renderIcon(event.poseStack, -iconSize / 2f, -size * 0.7f - iconSize / 2f, iconSize, iconSize)
|
||||||
|
} else {
|
||||||
|
for ((index, feature) in features.withIndex()) {
|
||||||
|
val sin = sin((index + 0.5) * degreePerSlice).toFloat()
|
||||||
|
val cos = cos((index + 0.5) * degreePerSlice).toFloat()
|
||||||
|
|
||||||
|
feature.renderIcon(event.poseStack, -iconSize / 2f + size * 0.7f * cos, -size * 0.7f * sin - iconSize / 2f, iconSize, iconSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.poseStack.popPose()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun register(event: RegisterKeyMappingsEvent) {
|
||||||
|
event.register(this)
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import net.minecraft.client.gui.Font
|
|||||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||||
import net.minecraft.sounds.SoundEvents
|
import net.minecraft.sounds.SoundEvents
|
||||||
import org.lwjgl.glfw.GLFW
|
import org.lwjgl.glfw.GLFW
|
||||||
|
import org.lwjgl.glfw.GLFW.GLFW_CURSOR
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.nio.ByteOrder
|
import java.nio.ByteOrder
|
||||||
import java.nio.DoubleBuffer
|
import java.nio.DoubleBuffer
|
||||||
@ -35,6 +36,28 @@ fun setMousePosScaled(x: Float, y: Float) {
|
|||||||
private val cursorXPosBuf = ByteBuffer.allocateDirect(8).also { it.order(ByteOrder.LITTLE_ENDIAN) }.asDoubleBuffer()
|
private val cursorXPosBuf = ByteBuffer.allocateDirect(8).also { it.order(ByteOrder.LITTLE_ENDIAN) }.asDoubleBuffer()
|
||||||
private val cursorYPosBuf = ByteBuffer.allocateDirect(8).also { it.order(ByteOrder.LITTLE_ENDIAN) }.asDoubleBuffer()
|
private val cursorYPosBuf = ByteBuffer.allocateDirect(8).also { it.order(ByteOrder.LITTLE_ENDIAN) }.asDoubleBuffer()
|
||||||
|
|
||||||
|
data class ScaledMousePos(val x: Double, val y: Double) {
|
||||||
|
fun set() {
|
||||||
|
setMousePos(x * minecraft.window.guiScale, y * minecraft.window.guiScale)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun move(x: Double = 0.0, y: Double = 0.0) {
|
||||||
|
GLFW.glfwSetCursorPos(minecraft.window.window, this.x * minecraft.window.guiScale + x, this.y * minecraft.window.guiScale + y)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun move(x: Float = 0.0f, y: Float = 0.0f) {
|
||||||
|
GLFW.glfwSetCursorPos(minecraft.window.window, this.x * minecraft.window.guiScale + x, this.y * minecraft.window.guiScale + y)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun moveScaled(x: Double = 0.0, y: Double = 0.0) {
|
||||||
|
GLFW.glfwSetCursorPos(minecraft.window.window, this.x * minecraft.window.guiScale + x * minecraft.window.guiScale, this.y * minecraft.window.guiScale + y * minecraft.window.guiScale)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun moveScaled(x: Float = 0.0f, y: Float = 0.0f) {
|
||||||
|
GLFW.glfwSetCursorPos(minecraft.window.window, this.x * minecraft.window.guiScale + x * minecraft.window.guiScale, this.y * minecraft.window.guiScale + y * minecraft.window.guiScale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data class MousePos(val x: Double, val y: Double) {
|
data class MousePos(val x: Double, val y: Double) {
|
||||||
fun set() {
|
fun set() {
|
||||||
setMousePos(x, y)
|
setMousePos(x, y)
|
||||||
@ -69,6 +92,18 @@ val mousePos: MousePos get() {
|
|||||||
return MousePos(cursorXPosBuf.get(), cursorYPosBuf.get())
|
return MousePos(cursorXPosBuf.get(), cursorYPosBuf.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val scaledMousePos: ScaledMousePos get() {
|
||||||
|
cursorXPosBuf.position(0)
|
||||||
|
cursorYPosBuf.position(0)
|
||||||
|
|
||||||
|
GLFW.glfwGetCursorPos(minecraft.window.window, cursorXPosBuf, cursorYPosBuf)
|
||||||
|
|
||||||
|
cursorXPosBuf.position(0)
|
||||||
|
cursorYPosBuf.position(0)
|
||||||
|
|
||||||
|
return ScaledMousePos(cursorXPosBuf.get() / minecraft.window.guiScale, cursorYPosBuf.get() / minecraft.window.guiScale)
|
||||||
|
}
|
||||||
|
|
||||||
fun moveMousePos(x: Double = 0.0, y: Double = 0.0) {
|
fun moveMousePos(x: Double = 0.0, y: Double = 0.0) {
|
||||||
val (currentX, currentY) = mousePos
|
val (currentX, currentY) = mousePos
|
||||||
GLFW.glfwSetCursorPos(minecraft.window.window, currentX + x, currentY + y)
|
GLFW.glfwSetCursorPos(minecraft.window.window, currentX + x, currentY + y)
|
||||||
@ -88,3 +123,7 @@ fun moveMousePosScaled(x: Float = 0.0f, y: Float = 0.0f) {
|
|||||||
val (currentX, currentY) = mousePos
|
val (currentX, currentY) = mousePos
|
||||||
GLFW.glfwSetCursorPos(minecraft.window.window, currentX + x * minecraft.window.guiScale, currentY + y * minecraft.window.guiScale)
|
GLFW.glfwSetCursorPos(minecraft.window.window, currentX + x * minecraft.window.guiScale, currentY + y * minecraft.window.guiScale)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mouseInputMode: Int
|
||||||
|
get() = GLFW.glfwGetInputMode(minecraft.window.window, GLFW_CURSOR)
|
||||||
|
set(value) { GLFW.glfwSetInputMode(minecraft.window.window, GLFW_CURSOR, value) }
|
||||||
|
@ -97,7 +97,7 @@ object MatteryGUI {
|
|||||||
|
|
||||||
val deathLog = ArrayList<Pair<Int, Component>>()
|
val deathLog = ArrayList<Pair<Int, Component>>()
|
||||||
|
|
||||||
fun showIteration(event: RenderGuiEvent.Post) {
|
private fun showIteration(event: RenderGuiEvent.Post) {
|
||||||
if (minecraft.player?.matteryPlayer?.isAndroid != true) {
|
if (minecraft.player?.matteryPlayer?.isAndroid != true) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import org.lwjgl.opengl.GL11.GL_ALWAYS
|
|||||||
import org.lwjgl.opengl.GL11.GL_LESS
|
import org.lwjgl.opengl.GL11.GL_LESS
|
||||||
import ru.dbotthepony.mc.otm.client.minecraft
|
import ru.dbotthepony.mc.otm.client.minecraft
|
||||||
import ru.dbotthepony.mc.otm.core.RGBAColor
|
import ru.dbotthepony.mc.otm.core.RGBAColor
|
||||||
|
import kotlin.math.PI
|
||||||
import kotlin.math.acos
|
import kotlin.math.acos
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
@ -563,3 +564,93 @@ fun clearDepth(stack: PoseStack, x: Float, y: Float, width: Float, height: Float
|
|||||||
RenderSystem.setShader { oldShader }
|
RenderSystem.setShader { oldShader }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun drawArc(
|
||||||
|
stack: PoseStack,
|
||||||
|
x: Float,
|
||||||
|
y: Float,
|
||||||
|
outerRadius: Float,
|
||||||
|
innerRadius: Float = 0f,
|
||||||
|
startDegree: Double = 0.0,
|
||||||
|
endDegree: Double = PI * 2.0,
|
||||||
|
steps: Int = (outerRadius / 8.0 * (endDegree - startDegree)).roundToInt().coerceAtLeast(12),
|
||||||
|
alignAtCenter: Boolean = true
|
||||||
|
) = drawArc(stack.last().pose(), x, y, outerRadius, innerRadius, startDegree, endDegree, steps, alignAtCenter)
|
||||||
|
|
||||||
|
fun drawArc(
|
||||||
|
matrix: Matrix4f,
|
||||||
|
x: Float,
|
||||||
|
y: Float,
|
||||||
|
outerRadius: Float,
|
||||||
|
innerRadius: Float = 0f,
|
||||||
|
startDegree: Double = 0.0,
|
||||||
|
endDegree: Double = PI * 2.0,
|
||||||
|
steps: Int = (outerRadius / 8.0 * (endDegree - startDegree)).roundToInt().coerceAtLeast(12),
|
||||||
|
alignAtCenter: Boolean = true
|
||||||
|
) {
|
||||||
|
require(startDegree < endDegree) { "Invalid arc degree range: $startDegree - $endDegree" }
|
||||||
|
require(steps >= 0) { "Invalid amount of arc steps: $steps" }
|
||||||
|
require(innerRadius >= 0f) { "Invalid inner radius of arc: $innerRadius" }
|
||||||
|
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionShader)
|
||||||
|
RenderSystem.enableBlend()
|
||||||
|
RenderSystem.defaultBlendFunc()
|
||||||
|
RenderSystem.depthFunc(GL_ALWAYS)
|
||||||
|
|
||||||
|
@Suppress("name_shadowing")
|
||||||
|
var x = x
|
||||||
|
|
||||||
|
@Suppress("name_shadowing")
|
||||||
|
var y = y
|
||||||
|
|
||||||
|
@Suppress("name_shadowing")
|
||||||
|
val startDegree = startDegree + PI / 2.0
|
||||||
|
|
||||||
|
@Suppress("name_shadowing")
|
||||||
|
val endDegree = endDegree + PI / 2.0
|
||||||
|
|
||||||
|
if (!alignAtCenter) {
|
||||||
|
x += outerRadius
|
||||||
|
y += outerRadius
|
||||||
|
}
|
||||||
|
|
||||||
|
val builder = tesselator.builder
|
||||||
|
|
||||||
|
if (innerRadius == 0f) {
|
||||||
|
if (steps >= 1) {
|
||||||
|
val singleStep = (endDegree - startDegree) / steps
|
||||||
|
|
||||||
|
builder.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION)
|
||||||
|
|
||||||
|
builder.vertex(matrix, x, y, zLevel).endVertex()
|
||||||
|
|
||||||
|
for (i in 0 .. steps) {
|
||||||
|
val sin = sin(startDegree + i * singleStep).toFloat()
|
||||||
|
val cos = cos(startDegree + i * singleStep).toFloat()
|
||||||
|
|
||||||
|
builder.vertex(matrix, x + outerRadius * sin, y + cos * outerRadius, zLevel).endVertex()
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferUploader.drawWithShader(builder.end())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val singleStep = (endDegree - startDegree) / (steps + 1)
|
||||||
|
|
||||||
|
builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION)
|
||||||
|
|
||||||
|
for (i in 0 .. steps) {
|
||||||
|
val sin = sin(startDegree + i * singleStep).toFloat()
|
||||||
|
val cos = cos(startDegree + i * singleStep).toFloat()
|
||||||
|
|
||||||
|
val sin2 = sin(startDegree + (i + 1) * singleStep).toFloat()
|
||||||
|
val cos2 = cos(startDegree + (i + 1) * singleStep).toFloat()
|
||||||
|
|
||||||
|
builder.vertex(matrix, x + outerRadius * sin, y + cos * outerRadius, zLevel).endVertex()
|
||||||
|
builder.vertex(matrix, x + outerRadius * sin2, y + cos2 * outerRadius, zLevel).endVertex()
|
||||||
|
builder.vertex(matrix, x + innerRadius * sin2, y + cos2 * innerRadius, zLevel).endVertex()
|
||||||
|
builder.vertex(matrix, x + innerRadius * sin, y + cos * innerRadius, zLevel).endVertex()
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferUploader.drawWithShader(builder.end())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -72,6 +72,10 @@ abstract class MatteryNetworkChannel(val version: String, val name: String) {
|
|||||||
handler: BiConsumer<T, Supplier<NetworkEvent.Context>>,
|
handler: BiConsumer<T, Supplier<NetworkEvent.Context>>,
|
||||||
direction: NetworkDirection? = null
|
direction: NetworkDirection? = null
|
||||||
) {
|
) {
|
||||||
|
if (nextNetworkPacketID >= 256) {
|
||||||
|
throw IndexOutOfBoundsException("Network message ID overflow!")
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("INACCESSIBLE_TYPE")
|
@Suppress("INACCESSIBLE_TYPE")
|
||||||
channel.registerMessage(nextNetworkPacketID++, packetClass, writer, reader, handler, if (direction == null) Optional.empty() else Optional.of(direction))
|
channel.registerMessage(nextNetworkPacketID++, packetClass, writer, reader, handler, if (direction == null) Optional.empty() else Optional.of(direction))
|
||||||
}
|
}
|
||||||
|
@ -12,10 +12,12 @@ import ru.dbotthepony.mc.otm.android.AndroidFeature
|
|||||||
import ru.dbotthepony.mc.otm.android.AndroidFeatureType
|
import ru.dbotthepony.mc.otm.android.AndroidFeatureType
|
||||||
import ru.dbotthepony.mc.otm.android.AndroidResearch
|
import ru.dbotthepony.mc.otm.android.AndroidResearch
|
||||||
import ru.dbotthepony.mc.otm.android.AndroidResearchType
|
import ru.dbotthepony.mc.otm.android.AndroidResearchType
|
||||||
|
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
|
||||||
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
||||||
import ru.dbotthepony.mc.otm.client.MatteryGUI
|
import ru.dbotthepony.mc.otm.client.MatteryGUI
|
||||||
import ru.dbotthepony.mc.otm.client.minecraft
|
import ru.dbotthepony.mc.otm.client.minecraft
|
||||||
import ru.dbotthepony.mc.otm.menu.AndroidStationMenu
|
import ru.dbotthepony.mc.otm.menu.AndroidStationMenu
|
||||||
|
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
||||||
import ru.dbotthepony.mc.otm.registry.MRegistry
|
import ru.dbotthepony.mc.otm.registry.MRegistry
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
@ -320,6 +322,37 @@ object ExoSuitMenuClose : MatteryPacket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SwitchAndroidFeaturePacket(val type: AndroidFeatureType<*>, val newState: Boolean) : MatteryPacket {
|
||||||
|
override fun write(buff: FriendlyByteBuf) {
|
||||||
|
buff.writeInt(MRegistry.ANDROID_FEATURES.getID(type))
|
||||||
|
buff.writeBoolean(newState)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun play(context: Supplier<NetworkEvent.Context>) {
|
||||||
|
context.packetHandled = true
|
||||||
|
|
||||||
|
context.enqueueWork {
|
||||||
|
val matteryPlayer = context.sender?.matteryPlayer ?: return@enqueueWork
|
||||||
|
|
||||||
|
if (!matteryPlayer.isAndroid) {
|
||||||
|
return@enqueueWork
|
||||||
|
}
|
||||||
|
|
||||||
|
val feature = matteryPlayer.getFeature(type) ?: return@enqueueWork
|
||||||
|
|
||||||
|
if (feature is AndroidSwitchableFeature && feature.allowToSwitchByPlayer) {
|
||||||
|
feature.isActive = newState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun read(buff: FriendlyByteBuf): SwitchAndroidFeaturePacket {
|
||||||
|
return SwitchAndroidFeaturePacket(MRegistry.ANDROID_FEATURES.getValue(buff.readInt()) ?: AndroidFeatures.AIR_BAGS, buff.readBoolean())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
|
object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
|
||||||
version = "1",
|
version = "1",
|
||||||
name = "player"
|
name = "player"
|
||||||
@ -337,7 +370,10 @@ object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
|
|||||||
add(ExoSuitCarriedPacket::class, ExoSuitCarriedPacket.Companion::read, PLAY_TO_CLIENT)
|
add(ExoSuitCarriedPacket::class, ExoSuitCarriedPacket.Companion::read, PLAY_TO_CLIENT)
|
||||||
add(ExoSuitSlotPacket::class, ExoSuitSlotPacket.Companion::read, PLAY_TO_CLIENT)
|
add(ExoSuitSlotPacket::class, ExoSuitSlotPacket.Companion::read, PLAY_TO_CLIENT)
|
||||||
add(ExoSuitMenuInitPacket::class, ExoSuitMenuInitPacket.Companion::read, PLAY_TO_CLIENT)
|
add(ExoSuitMenuInitPacket::class, ExoSuitMenuInitPacket.Companion::read, PLAY_TO_CLIENT)
|
||||||
|
|
||||||
add(ExoSuitMenuOpen::class, { ExoSuitMenuOpen }, PLAY_TO_SERVER)
|
add(ExoSuitMenuOpen::class, { ExoSuitMenuOpen }, PLAY_TO_SERVER)
|
||||||
add(ExoSuitMenuClose::class, { ExoSuitMenuClose }, PLAY_TO_SERVER)
|
add(ExoSuitMenuClose::class, { ExoSuitMenuClose }, PLAY_TO_SERVER)
|
||||||
|
|
||||||
|
add(SwitchAndroidFeaturePacket::class, SwitchAndroidFeaturePacket.Companion::read, PLAY_TO_SERVER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ object AndroidFeatures {
|
|||||||
val NANOBOTS_REGENERATION: AndroidFeatureType<*> by registry.register(MNames.NANOBOTS_REGENERATION) { AndroidFeatureType(::NanobotsRegeneration) }
|
val NANOBOTS_REGENERATION: AndroidFeatureType<*> by registry.register(MNames.NANOBOTS_REGENERATION) { AndroidFeatureType(::NanobotsRegeneration) }
|
||||||
val NANOBOTS_ARMOR: AndroidFeatureType<*> by registry.register(MNames.NANOBOTS_ARMOR) { AndroidFeatureType(::NanobotsArmor) }
|
val NANOBOTS_ARMOR: AndroidFeatureType<*> by registry.register(MNames.NANOBOTS_ARMOR) { AndroidFeatureType(::NanobotsArmor) }
|
||||||
val EXTENDED_REACH: AndroidFeatureType<*> by registry.register(MNames.EXTENDED_REACH) { AndroidFeatureType(::ExtendedReach) }
|
val EXTENDED_REACH: AndroidFeatureType<*> by registry.register(MNames.EXTENDED_REACH) { AndroidFeatureType(::ExtendedReach) }
|
||||||
|
val NIGHT_VISION: AndroidFeatureType<*> by registry.register(MNames.NIGHT_VISION) { AndroidFeatureType(::NightVisionFeature) }
|
||||||
|
|
||||||
internal fun register(bus: IEventBus) {
|
internal fun register(bus: IEventBus) {
|
||||||
registry.register(bus)
|
registry.register(bus)
|
||||||
|
@ -118,6 +118,15 @@ object AndroidResearch {
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val NIGHT_VISION: AndroidResearchType<*> by registry.register(MNames.NIGHT_VISION) {
|
||||||
|
AndroidResearchBuilder()
|
||||||
|
.withExperience(40)
|
||||||
|
.withDescription()
|
||||||
|
.withIcon(ICON_NIGHT_VISION)
|
||||||
|
.addFeatureResult(AndroidFeatures.NIGHT_VISION)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
val NANOBOTS: AndroidResearchType<*> by registry.register(MNames.NANOBOTS) {
|
val NANOBOTS: AndroidResearchType<*> by registry.register(MNames.NANOBOTS) {
|
||||||
AndroidResearchBuilder()
|
AndroidResearchBuilder()
|
||||||
.withExperience(15)
|
.withExperience(15)
|
||||||
|
@ -207,6 +207,7 @@ object MNames {
|
|||||||
const val HYDRAULICS_OVERLOAD_3 = "hydraulics_overload_3"
|
const val HYDRAULICS_OVERLOAD_3 = "hydraulics_overload_3"
|
||||||
|
|
||||||
const val EXTENDED_REACH = "extended_reach"
|
const val EXTENDED_REACH = "extended_reach"
|
||||||
|
const val NIGHT_VISION = "night_vision"
|
||||||
const val IMPROVED_LIMBS = "improved_limbs"
|
const val IMPROVED_LIMBS = "improved_limbs"
|
||||||
|
|
||||||
// stats
|
// stats
|
||||||
|
Loading…
Reference in New Issue
Block a user