Skip to content

Commit

Permalink
Version 1.3.5.2
Browse files Browse the repository at this point in the history
  • Loading branch information
EssentialGGBot committed Nov 11, 2024
1 parent d0cee53 commit d14a22a
Show file tree
Hide file tree
Showing 91 changed files with 1,167 additions and 692 deletions.
2 changes: 1 addition & 1 deletion build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ dependencies {
implementation("org.ow2.asm:asm-commons:9.3")
implementation ("com.google.guava:guava:30.1.1-jre")

implementation("gg.essential:essential-gradle-toolkit:0.6.3")
implementation("gg.essential:essential-gradle-toolkit:0.6.4")
}

gradlePlugin {
Expand Down
1 change: 1 addition & 0 deletions build-logic/src/main/kotlin/essential/universal.kt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ fun Project.universalLibs() {
compileOnly("org.lwjgl:lwjgl-opengl:3.3.1")
// Depending on 1.8.9 for all of these because that's the oldest version we support
compileOnly("com.google.code.gson:gson:2.2.4")
compileOnly("com.google.guava:guava:17.0")
compileOnly("commons-codec:commons-codec:1.9")
compileOnly("org.apache.httpcomponents:httpclient:4.3.3") // TODO ideally switch to one of the libs we bundle
// These versions are configured in gradle/libs.versions.toml
Expand Down
10 changes: 10 additions & 0 deletions changelog/release-1.3.5.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Title: Bug Patch
Summary: Minor bug fixes

## Wardrobe
- Added emote sound settings

## Bug Fixes
- Fixed crash when unbinding the zoom key in 1.21.2+
- Fixed emotes unlocked via bundles permanently playing on the player
- Fixed incorrect small purchase banner positioning
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ package gg.essential.gui.elementa.state.v2.collections

import gg.essential.elementa.state.v2.ReferenceHolder
import gg.essential.gui.elementa.state.v2.ListState
import gg.essential.gui.elementa.state.v2.effect

// FIXME this is assuming there are no duplicate keys (good enough for now)
fun <T, K, V> ListState<T>.asMap(owner: ReferenceHolder, block: (T) -> Pair<K, V>): Map<K, V> {
Expand Down Expand Up @@ -41,6 +42,35 @@ fun <T, K, V> ListState<T>.asMap(owner: ReferenceHolder, block: (T) -> Pair<K, V
return map
}

fun <T> ListState<T>.effectOnChange(
referenceHolder: ReferenceHolder,
onChange: (TrackedList.Change<T>) -> Unit,
) {
var oldList = trackedListOf<T>()
effect(referenceHolder) {
val newList = this@effectOnChange()
val changes = newList.getChangesSince(oldList).also { oldList = newList }
for (change in changes) {
onChange(change)
}
}
}

fun <T> ListState<T>.effectOnChange(
referenceHolder: ReferenceHolder,
add: (IndexedValue<T>) -> Unit,
remove: (IndexedValue<T>) -> Unit,
clear: (List<T>) -> Unit = { list -> list.forEach { remove(IndexedValue(0, it)) } },
) {
effectOnChange(referenceHolder) { change ->
when (change) {
is TrackedList.Add -> add(change.element)
is TrackedList.Remove -> remove(change.element)
is TrackedList.Clear -> clear(change.oldElements)
}
}
}

fun <T> trackedListOf(vararg elements: T) : TrackedList<T> = MutableTrackedList(elements.toMutableList())

fun <T> mutableTrackedListOf(vararg elements: T): MutableTrackedList<T> = MutableTrackedList(elements.toMutableList())
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ org.gradle.configureondemand=true
org.gradle.parallel.threads=128
org.gradle.jvmargs=-Xmx16G
minecraftVersion=11202
version=1.3.5.1
version=1.3.5.2
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,14 @@ object EssentialConfig : Vigilant2(), GuiEssentialPlatform.Config {
val disableEmotesState = property("Emotes.General.Disable Emotes", false)
var disableEmotes by disableEmotesState

enum class AllowEmoteSounds(val label: String) {
FROM_EVERYONE("From everyone"),
FROM_MYSELF_AND_FRIENDS("From myself & friends"),
FROM_MYSELF_ONLY("From myself only"),
FROM_NOBODY("From nobody")
}
val allowEmoteSounds = property("Emotes.General.Allow emote sounds", AllowEmoteSounds.FROM_EVERYONE)

val essentialScreenshotsState = property("Quality of Life.Screenshots.Essential Screenshots", true)
var essentialScreenshots: Boolean
get() = essentialEnabled && essentialScreenshotsState.get()
Expand Down Expand Up @@ -250,6 +258,8 @@ object EssentialConfig : Vigilant2(), GuiEssentialPlatform.Config {
enum class PreviouslyLaunchedWithContainer { Unknown, Yes, No }
val previouslyLaunchedWithContainer = property("Hidden.previously_launched_with_container", PreviouslyLaunchedWithContainer.Unknown)

val playEmoteSoundsInWardrobe = property("Hidden.play_emote_sounds_in_wardrobe", true)

override val migrations = listOf(
Migration { config ->
val overrideGuiScale = config.remove("general.general.gui_scale") as Boolean? ?: return@Migration
Expand Down Expand Up @@ -378,6 +388,12 @@ object EssentialConfig : Vigilant2(), GuiEssentialPlatform.Config {
description = "Show emote animations on yourself and other players."
}

selector(allowEmoteSounds) {
name = "Allow emote sounds"
description = "Select who you can hear emote sounds from."
options = AllowEmoteSounds.entries.map { it.label }
}

switch(thirdPersonEmotesState) {
name = "Play emotes in third person view"
description = "Emotes will be shown in third-person view. You can still toggle between front and back view."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import gg.essential.gui.common.LoadingIcon
import gg.essential.gui.common.shadow.ShadowEffect
import gg.essential.gui.common.shadow.ShadowIcon
import gg.essential.gui.elementa.state.v2.combinators.map
import gg.essential.gui.elementa.state.v2.combinators.zip
import java.awt.Color
import gg.essential.gui.elementa.state.v2.State as StateV2

Expand All @@ -38,6 +39,8 @@ fun Modifier.effect(effect: () -> Effect) = this then {

fun Modifier.outline(color: Color, width: Float, drawInsideChildren: Boolean = false) = effect { OutlineEffect(color, width, drawInsideChildren = drawInsideChildren) }
fun Modifier.outline(color: State<Color>, width: State<Float>, drawInsideChildren: Boolean = false) = effect { OutlineEffect(color, width, drawInsideChildren = drawInsideChildren) }
// TODO: Implement this properly with statev2
fun Modifier.outline(color: StateV2<Color>, width: StateV2<Float>, drawInsideChildren: Boolean = false) = then(color.zip(width).map { (color, width) -> outline(color, width, drawInsideChildren) })

fun Modifier.shadow(color: Color? = null) = this then {
when (this) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@
package gg.essential.gui.overlay

enum class LayerPriority {
/**
* Layer which is logically positioned below the currently active screen.
*
* Note that this does not yet have dedicated input events and will instead use the same events as
* [AboveScreenContent] (i.e. it will handle events before the screen and can cancel them). This is not intentional
* and will change in the future if someone has an actual need for it.
*/
BelowScreen,

/**
* Layer which is logically positioned below most of the content of the currently active screen.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ package gg.essential.gui.wardrobe

import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap
import gg.essential.Essential
import gg.essential.cosmetics.CosmeticBundleId
import gg.essential.cosmetics.CosmeticCategoryId
import gg.essential.cosmetics.CosmeticId
Expand All @@ -23,7 +22,6 @@ import gg.essential.cosmetics.FeaturedPageCollectionId
import gg.essential.cosmetics.diagnose
import gg.essential.cosmetics.events.AnimationEventType
import gg.essential.elementa.UIComponent
import gg.essential.elementa.events.UIClickEvent
import gg.essential.gui.common.onSetValueAndNow
import gg.essential.gui.elementa.state.v2.ListState
import gg.essential.gui.elementa.state.v2.MutableState
Expand All @@ -41,53 +39,56 @@ import gg.essential.gui.elementa.state.v2.onChange
import gg.essential.gui.elementa.state.v2.set
import gg.essential.gui.elementa.state.v2.setAll
import gg.essential.gui.elementa.state.v2.stateBy
import gg.essential.gui.elementa.state.v2.stateOf
import gg.essential.gui.elementa.state.v2.toListState
import gg.essential.gui.elementa.state.v2.zipWithEachElement
import gg.essential.gui.state.Sale
import gg.essential.gui.util.layoutSafePollingState
import gg.essential.gui.wardrobe.Item.Companion.toItem
import gg.essential.gui.wardrobe.components.handleBundleLeftClick
import gg.essential.gui.wardrobe.components.handleBundleRightClick
import gg.essential.gui.wardrobe.components.handleCosmeticOrEmoteLeftClick
import gg.essential.gui.wardrobe.components.handleCosmeticOrEmoteRightClick
import gg.essential.gui.wardrobe.components.handleOutfitLeftClick
import gg.essential.gui.wardrobe.components.displayOutfitOptions
import gg.essential.gui.wardrobe.components.handleSkinLeftClick
import gg.essential.gui.wardrobe.components.handleSkinRightClick
import gg.essential.gui.wardrobe.components.hasBundleOptionsButton
import gg.essential.gui.wardrobe.components.hasCosmeticOrEmoteOptionsButton
import gg.essential.handlers.EssentialSoundManager
import gg.essential.mod.cosmetics.CosmeticCategory
import gg.essential.mod.cosmetics.CosmeticSlot
import gg.essential.mod.cosmetics.featured.FeaturedPageCollection
import gg.essential.mod.cosmetics.settings.CosmeticSetting
import gg.essential.model.Side
import gg.essential.network.connectionmanager.coins.CoinsManager
import gg.essential.network.connectionmanager.cosmetics.AssetLoader
import gg.essential.network.connectionmanager.cosmetics.CosmeticsManager
import gg.essential.network.connectionmanager.skins.SkinsManager
import gg.essential.network.cosmetics.Cosmetic
import gg.essential.util.Multithreading
import gg.essential.gui.util.pollingStateV2
import gg.essential.mod.cosmetics.featured.FeaturedItem
import gg.essential.mod.cosmetics.settings.CosmeticSettings
import gg.essential.mod.cosmetics.settings.setting
import gg.essential.network.connectionmanager.cosmetics.EmoteWheelManager
import gg.essential.network.connectionmanager.cosmetics.ICosmeticsManager
import gg.essential.network.connectionmanager.cosmetics.ModelLoader
import gg.essential.network.connectionmanager.cosmetics.OutfitManager
import gg.essential.network.connectionmanager.cosmetics.WardrobeSettings
import gg.essential.universal.UResolution
import java.util.concurrent.TimeUnit
import gg.essential.util.Client
import gg.essential.util.EssentialSounds
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.slf4j.LoggerFactory
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds

class WardrobeState(
initialCategory: WardrobeCategory?,
val screenOpen: State<Boolean>,
component: UIComponent,
val cosmeticsManager: CosmeticsManager,
val cosmeticsManager: ICosmeticsManager,
val modelLoader: ModelLoader,
val settings: WardrobeSettings,
val outfitManager: OutfitManager,
val skinsManager: SkinsManager,
val emoteWheelManager: EmoteWheelManager,
val coinsManager: CoinsManager,
val saleState: ListState<Sale>,
private val guiScale: State<Int>,
) {
val outfitManager = Essential.getInstance().connectionManager.outfitManager

val diagnosticsEnabled = cosmeticsManager.localCosmeticsData != null

val inEmoteWheel = mutableStateOf(false)
Expand All @@ -105,6 +106,8 @@ class WardrobeState(
cosmeticsManager.unlockedCosmetics.onSetValue(component) { this.set(it) }
}

val cosmeticsData = cosmeticsManager.cosmeticsData

val rawTypes = cosmeticsManager.cosmeticsData.types

val rawCategories = cosmeticsManager.cosmeticsData.categories
Expand All @@ -124,7 +127,7 @@ class WardrobeState(

val cosmetics = if (diagnosticsEnabled) {
val cosmeticsWithDiagnostics = availableCosmetics.mapEach { cosmetic ->
val diagnosticsState = diagnose(cosmeticsManager.modelLoader, cosmetic)
val diagnosticsState = diagnose(modelLoader, cosmetic)
memo {
val diagnostics = diagnosticsState()
when {
Expand Down Expand Up @@ -247,10 +250,6 @@ class WardrobeState(

val visibleCosmetics = visibleCosmeticItems.mapEach { it.cosmetic }

val saleState = Essential.getInstance().connectionManager.noticesManager.saleNoticeManager.saleState.map {
it.filter { it.discountPercent > 0 } // Sales with 0% discount are used to display on the main menu and should be ignored here
}.toListState()

/**
* When set, the main view is scrolled to have the item, with the same itemId,
* in view and the item outline is highlighted for a moment.
Expand Down Expand Up @@ -477,6 +476,11 @@ class WardrobeState(
}.toMap())
}

fun getTotalCost(items: ListState<Item>): State<Int> {
val costs = items.map { it.toSet().toList() }.toListState().mapEach { it.getCost(this) }
return stateBy { costs().sumOf { it() ?: 0 } }
}

// Local cosmetics editing

val editingMenuOpen = mutableStateOf(false)
Expand Down Expand Up @@ -598,63 +602,40 @@ class WardrobeState(
}
}

fun hasOptionsButton(item: Item): State<Boolean> {
return when (item) {
is Item.CosmeticOrEmote -> {
hasCosmeticOrEmoteOptionsButton(item, this)
}
is Item.Bundle -> {
hasBundleOptionsButton(item, this)
}
else -> stateOf(true)
}
}

fun handleItemLeftClick(item: Item, category: WardrobeCategory, event: UIClickEvent) {
when (item) {
is Item.Bundle -> handleBundleLeftClick(item, category, this)
is Item.CosmeticOrEmote -> handleCosmeticOrEmoteLeftClick(item, category, this)
is Item.OutfitItem -> handleOutfitLeftClick(item, this, event)
is Item.SkinItem -> handleSkinLeftClick(item, this)
}
}

fun handleItemRightClick(item: Item, category: WardrobeCategory, event: UIClickEvent) {
when (item) {
is Item.Bundle -> handleBundleRightClick(item, this, event)
is Item.CosmeticOrEmote -> handleCosmeticOrEmoteRightClick(item, category, this, event)
is Item.OutfitItem -> displayOutfitOptions(item, this, event)
is Item.SkinItem -> handleSkinRightClick(item, this, event)
}
}

@OptIn(DelicateCoroutinesApi::class) // FIXME should use screen scope or something like that
fun triggerPurchaseAnimation() {
if (purchaseAnimationState.get()) {
return
}
val purchaseEmote = rawCosmetics.get().find { it.id == purchaseConfirmationEmoteId }
if (purchaseEmote == null) {
Essential.logger.warn("Unable to find purchase confirmation animation.")
LOGGER.warn("Unable to find purchase confirmation animation.")
return
}
// Find out animation time for purchase confirmation emote
val bedrockModel = cosmeticsManager.modelLoader.getModel(
val bedrockModel = modelLoader.getModel(
purchaseEmote, purchaseEmote.defaultVariantName, AssetLoader.Priority.Blocking
).join()
val emoteTime = ((bedrockModel.animationEvents
val emoteTime = bedrockModel.animationEvents
.filter { it.type == AnimationEventType.EMOTE }
.maxOfOrNull { it.getTotalTime(bedrockModel) }
?: 0f) * 1000).toLong()
?.toDouble()?.seconds
?: Duration.ZERO

// Delay purchase sound to go with the animation (animation is delayed by 0.3s)
Multithreading.scheduleOnMainThread({
EssentialSoundManager.playPurchaseConfirmationSound()
}, 300, TimeUnit.MILLISECONDS)
GlobalScope.launch(Dispatchers.Client) {
delay(300.milliseconds)
EssentialSounds.playPurchaseConfirmationSound()
}

purchaseAnimationState.set(true)
Multithreading.scheduleOnMainThread({
purchaseAnimationState.set(false)
}, emoteTime, TimeUnit.MILLISECONDS)
GlobalScope.launch(Dispatchers.Client) {
purchaseAnimationState.set(true)
try {
delay(emoteTime)
} finally {
purchaseAnimationState.set(false)
}
}
}

private fun getWardrobeGridColumnCount(): Int {
Expand Down Expand Up @@ -707,6 +688,8 @@ class WardrobeState(
data class CosmeticWithSortInfo(val cosmetic: Cosmetic, val owned: Boolean, val price: Int?, val collection: CosmeticCategory?)

companion object {
private val LOGGER = LoggerFactory.getLogger(WardrobeState::class.java)

private val sortByOrderInCollection: Comparator<CosmeticWithSortInfo> =
compareBy { it.cosmetic.categories[it.collection?.id] ?: 0 }
private val sortBySortWeight: Comparator<CosmeticWithSortInfo> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import gg.essential.gui.common.modal.Modal
import gg.essential.gui.layoutdsl.*
import gg.essential.gui.overlay.ModalManager
import gg.essential.gui.wardrobe.components.coinPackImage
import gg.essential.handlers.EssentialSoundManager.playCoinsSound
import gg.essential.network.connectionmanager.coins.CoinsManager
import gg.essential.util.EssentialSounds.playCoinsSound

class CoinsReceivedModal private constructor(
modalManager: ModalManager,
Expand Down
Loading

0 comments on commit d14a22a

Please sign in to comment.