Skip to content

Commit

Permalink
Integrate UI synchronization, new sounds, translations
Browse files Browse the repository at this point in the history
  • Loading branch information
bibi-reden committed Jul 27, 2024
1 parent 16bced1 commit c898000
Show file tree
Hide file tree
Showing 21 changed files with 178 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.bibireden.playerex.mixin;

import com.bibireden.playerex.ui.PlayerEXScreen;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(ClientPlayerEntity.class)
abstract class ClientPlayerEntityMixin {
@Shadow @Final protected MinecraftClient client;

@Inject(method = "setExperience", at = @At("TAIL"))
private void setExperience(CallbackInfo ci) {
if (client.currentScreen instanceof PlayerEXScreen screen) screen.onExperienceUpdated();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.bibireden.playerex.mixin;

import com.bibireden.data_attributes.api.attribute.IEntityAttribute;
import com.bibireden.data_attributes.api.item.ItemFields;
import com.bibireden.playerex.PlayerEX;
import com.bibireden.playerex.config.PlayerEXConfigModel;
Expand Down
14 changes: 9 additions & 5 deletions src/client/kotlin/com/bibireden/playerex/PlayerEXClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ import org.lwjgl.glfw.GLFW
object PlayerEXClient : ClientModInitializer {
val MAIN_UI_SCREEN_ID = PlayerEX.id("main_ui_model")

private val KEYBINDING_MAIN_SCREEN: KeyBinding = KeyBindingHelper.registerKeyBinding(KeyBinding("${PlayerEX.MOD_ID}.key.main_screen", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_MINUS, "key.categories.${PlayerEX.MOD_ID}"))
val KEYBINDING_MAIN_SCREEN: KeyBinding = KeyBindingHelper.registerKeyBinding(KeyBinding("${PlayerEX.MOD_ID}.key.main_screen", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_MINUS, "key.categories.${PlayerEX.MOD_ID}"))

override fun onInitializeClient() {
NetworkingChannels.NOTIFICATIONS.registerClientbound(NetworkingPackets.Notify::class) { (type), ctx ->
val soundSettings = PlayerEX.CONFIG.soundSettings
when (type) {
NotificationType.LevelUpAvailable -> ctx.player().playSound(PlayerEXSoundEvents.LEVEL_UP_SOUND, SoundCategory.NEUTRAL, PlayerEX.CONFIG.levelUpVolume.toFloat(), 1F)
NotificationType.Spent -> ctx.player().playSound(PlayerEXSoundEvents.SPEND_SOUND, SoundCategory.NEUTRAL, PlayerEX.CONFIG.skillUpVolume.toFloat(), 1F)
NotificationType.LevelUpAvailable -> ctx.player().playSound(PlayerEXSoundEvents.LEVEL_UP_SOUND, SoundCategory.NEUTRAL, soundSettings.levelUpVolume.toFloat(), 1F)
NotificationType.Spent -> ctx.player().playSound(PlayerEXSoundEvents.SPEND_SOUND, SoundCategory.NEUTRAL, soundSettings.skillUpVolume.toFloat(), 1F)
NotificationType.Refunded -> ctx.player().playSound(PlayerEXSoundEvents.REFUND_SOUND, SoundCategory.NEUTRAL, soundSettings.refundVolume.toFloat(), 0.7F)
}
}

Expand All @@ -55,9 +57,11 @@ object PlayerEXClient : ClientModInitializer {
AttributesMenuRegistry.register(AttributesMenu::class.java)

ClientTickEvents.END_CLIENT_TICK.register { client ->
if (PlayerEX.CONFIG.disableAttributesGui) return@register
if (PlayerEX.CONFIG.disableUI) return@register
while (KEYBINDING_MAIN_SCREEN.wasPressed()) {
if (client.currentScreen == null) client.setScreen(PlayerEXScreen())
if (client.currentScreen == null) {
client.setScreen(PlayerEXScreen())
}
}
}
}
Expand Down
46 changes: 32 additions & 14 deletions src/client/kotlin/com/bibireden/playerex/ui/PlayerEXScreen.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.bibireden.playerex.ui

import com.bibireden.playerex.PlayerEX
import com.bibireden.playerex.PlayerEXClient
import com.bibireden.playerex.components.PlayerEXComponents
import com.bibireden.playerex.components.player.IPlayerDataComponent
import com.bibireden.playerex.ext.canLevelUp
import com.bibireden.playerex.ext.data
import com.bibireden.playerex.ext.level
import com.bibireden.playerex.networking.NetworkingChannels
Expand All @@ -25,6 +27,7 @@ import io.wispforest.owo.util.EventSource
import net.minecraft.entity.attribute.EntityAttribute
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.text.Text
import net.minecraft.util.math.MathHelper
import kotlin.reflect.KClass

// Transformers
Expand All @@ -41,6 +44,8 @@ class PlayerEXScreen : BaseUIModelScreen<FlowLayout>(FlowLayout::class.java, Dat
private val content by lazy { uiAdapter.rootComponent.childById(FlowLayout::class, "content")!! }
private val footer by lazy { uiAdapter.rootComponent.childById(FlowLayout::class, "footer")!! }

private val levelAmount by lazy { uiAdapter.rootComponent.childById(TextBoxComponent::class, "level:amount")!! }

private val onLevelUpdatedEvents = OnLevelUpdated.stream
private val onLevelUpdated: EventSource<OnLevelUpdated> = onLevelUpdatedEvents.source()

Expand All @@ -55,8 +60,8 @@ class PlayerEXScreen : BaseUIModelScreen<FlowLayout>(FlowLayout::class.java, Dat
}

updatePointsAvailable()
updateLevelUpButton(player, root.childById(TextBoxComponent::class, "level:amount")!!.text)
updateProgressBar(player)
updateLevelUpButton()
updateProgressBar()

this.uiAdapter.rootComponent.forEachDescendant { descendant ->
if (descendant is MenuComponent) descendant.onLevelUpdatedEvents.sink().onLevelUpdated(level)
Expand Down Expand Up @@ -95,18 +100,20 @@ class PlayerEXScreen : BaseUIModelScreen<FlowLayout>(FlowLayout::class.java, Dat
content.child(pages[currentPage])
}

private fun updateLevelUpButton(player: PlayerEntity, text: String) {
val amount = text.toIntOrNull() ?: return
private fun updateLevelUpButton() {
val amount = levelAmount.text.toIntOrNull() ?: return
val result = player.level + amount

this.uiAdapter.rootComponent.childById(ButtonComponent::class, "level:button")
?.tooltip(Text.translatable("playerex.ui.level_button", PlayerEXUtil.getRequiredXpForLevel(player, result), amount, player.experienceLevel))
this.uiAdapter.rootComponent.childById(ButtonComponent::class, "level:button")!!
.active(player.canLevelUp())
.tooltip(Text.translatable("playerex.ui.level_button", PlayerEXUtil.getRequiredXpForLevel(player, result), amount, player.experienceLevel))
}

private fun updateProgressBar(player: PlayerEntity) {
private fun updateProgressBar() {
var result = 0.0
if (player.experienceLevel > 0) {
result = (player.experienceLevel.toDouble() / PlayerEXUtil.getRequiredXpForNextLevel(player)) * 100
val required = PlayerEXUtil.getRequiredXpForNextLevel(player)
result = MathHelper.clamp((player.experienceLevel.toDouble() / required) * 100, 0.0, 100.0)
}
footer.childById(BoxComponent::class, "progress")!!
.horizontalSizing().animate(1000, Easing.CUBIC, Sizing.fill(result.toInt())).forwards()
Expand All @@ -115,11 +122,10 @@ class PlayerEXScreen : BaseUIModelScreen<FlowLayout>(FlowLayout::class.java, Dat
override fun build(rootComponent: FlowLayout) {
val player = client?.player ?: return

val levelAmount = rootComponent.childById(TextBoxComponent::class, "level:amount")!!
val levelUpButton = rootComponent.childById(ButtonComponent::class, "level:button")!!

updateLevelUpButton(player, levelAmount.text)
levelAmount.onChanged().subscribe { updateLevelUpButton(player, it) }
updateLevelUpButton()
levelAmount.onChanged().subscribe { updateLevelUpButton() }

val previousPage = rootComponent.childById(ButtonComponent::class, "previous")!!
val pageCounter = rootComponent.childById(LabelComponent::class, "counter")!!
Expand Down Expand Up @@ -157,13 +163,25 @@ class PlayerEXScreen : BaseUIModelScreen<FlowLayout>(FlowLayout::class.java, Dat
levelAmount.text.toIntOrNull()?.let { NetworkingChannels.MODIFY.clientHandle().send(NetworkingPackets.Level(it)) }
}

onLevelUpdated.subscribe {
this.updateLevelUpButton(player, rootComponent.childById(TextBoxComponent::class, "level:amount")!!.text)
}
onLevelUpdated.subscribe { this.updateLevelUpButton() }

exit.onPress { this.close() }
}

/** Whenever the player's experience is changed, refreshing the current status of experience-tied ui elements. */
fun onExperienceUpdated() {
updateLevelUpButton()
updateProgressBar()
}

override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
if (PlayerEXClient.KEYBINDING_MAIN_SCREEN.matchesKey(keyCode, scanCode)) {
this.close()
return true
}
return super.keyPressed(keyCode, scanCode, modifiers)
}

enum class AttributeButtonComponentType {
Add,
Remove;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import net.minecraft.entity.attribute.EntityAttribute
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.text.Text

class AttributeButtonComponent(private val attribute: EntityAttribute, private val player: PlayerEntity, private val component: IPlayerDataComponent, private val type: PlayerEXScreen.AttributeButtonComponentType) : ButtonComponent(
class AttributeButtonComponent(val attribute: EntityAttribute, private val player: PlayerEntity, private val component: IPlayerDataComponent, val type: PlayerEXScreen.AttributeButtonComponentType) : ButtonComponent(
Text.literal(type.symbol),
{
// reference text-box to get needed value to send to server
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
package com.bibireden.playerex.ui.menus

import com.bibireden.data_attributes.api.DataAttributesAPI
import com.bibireden.data_attributes.api.attribute.IEntityAttribute
import com.bibireden.playerex.api.attribute.PlayerEXAttributes
import com.bibireden.playerex.components.player.IPlayerDataComponent
import com.bibireden.playerex.ext.level
import com.bibireden.playerex.ui.PlayerEXScreen
import com.bibireden.playerex.ui.childById
import com.bibireden.playerex.ui.components.MenuComponent
import com.bibireden.playerex.ui.components.AttributeComponent
import com.bibireden.playerex.ui.components.buttons.AttributeButtonComponent
import com.bibireden.playerex.ui.components.labels.AttributeLabelComponent
import com.bibireden.playerex.util.PlayerEXUtil
import io.wispforest.owo.ui.component.Components
import io.wispforest.owo.ui.component.TextBoxComponent
import io.wispforest.owo.ui.container.Containers
import io.wispforest.owo.ui.container.FlowLayout
import io.wispforest.owo.ui.core.Insets
import io.wispforest.owo.ui.core.OwoUIAdapter
import io.wispforest.owo.ui.core.Positioning
import io.wispforest.owo.ui.core.Sizing
import net.minecraft.client.network.ClientPlayerEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.registry.Registries
import net.minecraft.text.Text

// todo: cache buttons/certain UI elements

class AttributesMenu : MenuComponent(Sizing.fill(100), Sizing.fill(100), Algorithm.VERTICAL) {
private fun onLevelUpdate(level: Int) {}

Expand All @@ -36,13 +45,31 @@ class AttributesMenu : MenuComponent(Sizing.fill(100), Sizing.fill(100), Algorit
}
}

private fun onInputFieldUpdated(player: PlayerEntity, component: IPlayerDataComponent) {
this.childById(FlowLayout::class, "attributes")?.childById(TextBoxComponent::class, "input")?.also {
val result = it.text.toDoubleOrNull() ?: return@also
this.forEachDescendant { descendant ->
if (descendant is AttributeButtonComponent) {
val max = (descendant.attribute as IEntityAttribute).`data_attributes$max`()
val current = DataAttributesAPI.getValue(descendant.attribute, player).orElse(0.0)
when (descendant.type) {
PlayerEXScreen.AttributeButtonComponentType.Add -> descendant.active(component.skillPoints >= result && (current + result) < max)
PlayerEXScreen.AttributeButtonComponentType.Remove -> descendant.active(component.refundablePoints >= 0 && (current - result > 0))
}
}
}
}

}

override fun build(player: ClientPlayerEntity, adapter: OwoUIAdapter<FlowLayout>, component: IPlayerDataComponent) {
child(Containers.verticalFlow(Sizing.fill(35), Sizing.fill(100)).apply {
child(Components.label(Text.translatable("playerex.ui.category.primary_attributes")))
child(
Components.textBox(Sizing.fixed(27))
.also {
it.setMaxLength(4)
it.onChanged().subscribe { onInputFieldUpdated(player, component) }
}
.text("1")
.verticalSizing(Sizing.fixed(10))
Expand All @@ -52,16 +79,15 @@ class AttributesMenu : MenuComponent(Sizing.fill(100), Sizing.fill(100), Algorit
child(Components.box(Sizing.fill(100), Sizing.fixed(2)))
gap(5)
children(PlayerEXAttributes.PRIMARY_ATTRIBUTE_IDS.mapNotNull(Registries.ATTRIBUTE::get).map { AttributeComponent(it, player, component) })
})
}.id("attributes"))

padding(Insets.both(12, 12))

onLevelUpdate(player.level.toInt())
onAttributeUpdate()
onInputFieldUpdated(player, component)


this.onLevelUpdate(player.level.toInt())
this.onAttributeUpdate()

this.onLevelUpdated.subscribe(::onLevelUpdate)
this.onAttributeUpdated.subscribe { _, _ -> onAttributeUpdate() }
onLevelUpdated.subscribe(::onLevelUpdate)
onAttributeUpdated.subscribe { _, _ -> onAttributeUpdate() }
}
}
8 changes: 3 additions & 5 deletions src/client/resources/assets/playerex/owo_ui/main_ui_model.xml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
<box>
<sizing><horizontal method="fill">100</horizontal><vertical method="fixed">2</vertical></sizing>
<fill>true</fill>
<positioning type="relative">0,15</positioning>
<positioning type="relative">0,10</positioning>
</box>

<box id="progress">
Expand All @@ -112,7 +112,7 @@
<start-color>gold</start-color>
<end-color>red</end-color>

<positioning type="relative">0,15</positioning>
<positioning type="relative">0,10</positioning>
<z-index>1</z-index>
</box>

Expand All @@ -135,13 +135,11 @@
<button id="level:button">
<text>+</text>

<renderer><flat color="black" hovered-color="black" disabled-color="dark-red"/></renderer>

<sizing><vertical method="fixed">12</vertical><horizontal method="fixed">12</horizontal></sizing>
</button>
</children>

<sizing><vertical method="fill">60</vertical><horizontal method="fill">100</horizontal></sizing>
<sizing><vertical method="fill">65</vertical><horizontal method="fill">100</horizontal></sizing>
<vertical-alignment>bottom</vertical-alignment>

<gap>2</gap>
Expand Down
1 change: 1 addition & 0 deletions src/client/resources/playerex.client.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"package": "com.bibireden.playerex.mixin",
"compatibilityLevel": "JAVA_17",
"client": [
"ClientPlayerEntityMixin",
"EntityRendererMixin"
],
"injectors": {
Expand Down
1 change: 1 addition & 0 deletions src/main/kotlin/com/bibireden/playerex/PlayerEX.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ object PlayerEX : ModInitializer {

Registry.register(Registries.SOUND_EVENT, PlayerEXSoundEvents.LEVEL_UP_SOUND.id, PlayerEXSoundEvents.LEVEL_UP_SOUND)
Registry.register(Registries.SOUND_EVENT, PlayerEXSoundEvents.SPEND_SOUND.id, PlayerEXSoundEvents.SPEND_SOUND)
Registry.register(Registries.SOUND_EVENT, PlayerEXSoundEvents.REFUND_SOUND.id, PlayerEXSoundEvents.REFUND_SOUND)

DefaultAttributeFactory.registerEntityTypes(DefaultAttributeImpl.ENTITY_TYPES)
DefaultAttributeFactory.registerFunctions(DefaultAttributeImpl.FUNCTIONS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ import net.minecraft.sound.SoundEvent
object PlayerEXSoundEvents {
val LEVEL_UP_SOUND = SoundEvent.of(PlayerEX.id("level_up"))
val SPEND_SOUND = SoundEvent.of(PlayerEX.id("spend"))
val REFUND_SOUND = SoundEvent.of(PlayerEX.id("refund"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,9 @@ class PlayerDataComponent(
this.addRefundablePoints(-amount)
this.addSkillPoints(amount)
this.set(skill, (value - amount).toInt())

ServerNetworkingFactory.notify(player, NotificationType.Refunded)

true
}.orElse(false)
}
Expand Down
Loading

0 comments on commit c898000

Please sign in to comment.