/*
* Skytils - Hypixel Skyblock Quality of Life Mod
* Copyright (C) 2021 Skytils
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package skytils.skytilsmod.gui
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import gg.essential.api.EssentialAPI
import gg.essential.elementa.WindowScreen
import gg.essential.elementa.components.ScrollComponent
import gg.essential.elementa.components.UIContainer
import gg.essential.elementa.components.UIText
import gg.essential.elementa.constraints.CenterConstraint
import gg.essential.elementa.constraints.ChildBasedSizeConstraint
import gg.essential.elementa.constraints.RelativeConstraint
import gg.essential.elementa.constraints.SiblingConstraint
import gg.essential.elementa.dsl.*
import gg.essential.elementa.effects.OutlineEffect
import gg.essential.vigilance.gui.settings.CheckboxComponent
import gg.essential.vigilance.gui.settings.DropDown
import gg.essential.vigilance.utils.onLeftClick
import net.minecraft.util.BlockPos
import org.apache.commons.codec.binary.Base64
import skytils.skytilsmod.Skytils
import skytils.skytilsmod.core.PersistentSave
import skytils.skytilsmod.features.impl.handlers.Waypoint
import skytils.skytilsmod.features.impl.handlers.Waypoints
import skytils.skytilsmod.gui.components.SimpleButton
import skytils.skytilsmod.utils.SBInfo
import skytils.skytilsmod.utils.SkyblockIsland
import skytils.skytilsmod.utils.setState
import java.awt.Color
class WaypointShareGui : WindowScreen(newGuiScale = 2) {
companion object {
private val gson: Gson = GsonBuilder().create()
}
private val scrollComponent: ScrollComponent
private val islandDropdown: DropDown
private val entries = HashMap()
init {
scrollComponent = ScrollComponent(
innerPadding = 4f,
).childOf(window).constrain {
x = CenterConstraint()
y = 15.percent()
width = 90.percent()
height = 70.percent() + 2.pixels()
}
islandDropdown = DropDown(SkyblockIsland.values().indexOfFirst {
SBInfo.mode == it.mode
}.run { if (this == -1) 0 else this }, SkyblockIsland.values().map { it.formattedName }).childOf(window)
.constrain {
x = basicXConstraint { it.parent.getRight() - it.getWidth() - 5f }
y = 5.percent()
}.also {
it.onValueChange { s ->
loadWaypointsForSelection(s)
}
}
UIText("Waypoints").childOf(window).constrain {
x = CenterConstraint()
y = RelativeConstraint(0.075f)
height = 14.pixels()
}
val bottomButtons = UIContainer().childOf(window).constrain {
x = CenterConstraint()
y = 90.percent()
width = ChildBasedSizeConstraint()
height = ChildBasedSizeConstraint()
}
SimpleButton("Back").childOf(bottomButtons).constrain {
x = 0.pixels()
y = 0.pixels()
}.onLeftClick {
mc.displayGuiScreen(null)
}
SimpleButton("Import from Clipboard").childOf(bottomButtons).constrain {
x = SiblingConstraint(5f)
y = 0.pixels()
}.onLeftClick {
importFromClipboard()
}
SimpleButton("Export Selected to Clipboard").childOf(bottomButtons).constrain {
x = SiblingConstraint(5f)
y = 0.pixels()
}.onLeftClick {
exportSelectedWaypoints()
}
SimpleButton("Select All").childOf(window).constrain {
x = 5.pixels()
y = 5.pixels(alignOpposite = true)
}.onLeftClick {
if (entries.values.all {
it.selected.checked
}) {
entries.values.forEach {
it.selected.setState(false)
}
} else {
entries.values.forEach {
it.selected.setState(true)
}
}
}
loadWaypointsForSelection(islandDropdown.getValue())
}
private fun importFromClipboard() {
runCatching {
val decoded = Base64.decodeBase64(getClipboardString()).toString(Charsets.UTF_8)
val arr = gson.fromJson(decoded, JsonArray::class.java)
val results = arr.mapNotNull { e ->
return@mapNotNull runCatching {
e as JsonObject
return@runCatching Waypoint(
e["name"].asString,
BlockPos(
e["x"].asInt,
e["y"].asInt,
e["z"].asInt
),
SkyblockIsland.values().find {
it.mode == e["island"].asString
} ?: return@mapNotNull null,
e["enabled"].asBoolean,
e["color"]?.let{Color(it.asInt)} ?: Color.RED
)
}.onFailure {
it.printStackTrace()
}.getOrNull()
}
Waypoints.waypoints.addAll(results)
PersistentSave.markDirty()
loadWaypointsForSelection(islandDropdown.getValue())
EssentialAPI.getNotifications()
.push("Waypoints Imported", "Successfully imported ${results.size} waypoints!", 2.5f)
}.onFailure {
it.printStackTrace()
EssentialAPI.getNotifications()
.push("Error", "Failed to import waypoints, reason: ${it::class.simpleName}: ${it.message}")
}
}
private fun exportSelectedWaypoints() {
val island = SkyblockIsland.values()[islandDropdown.getValue()]
val arr = JsonArray()
entries.values.filter {
it.selected.checked
}.forEach {
runCatching {
arr.add(JsonObject().apply {
addProperty("name", it.name.getText())
addProperty("x", it.x.getText().toInt())
addProperty("y", it.y.getText().toInt())
addProperty("z", it.z.getText().toInt())
addProperty("island", island.mode)
addProperty("enabled", true)
addProperty("color", Color.RED.rgb)
})
}.onFailure {
it.printStackTrace()
}
}
setClipboardString(Base64.encodeBase64String(gson.toJson(arr).encodeToByteArray()))
EssentialAPI.getNotifications()
.push(
"Waypoints Exported",
"${arr.size()} ${island.formattedName} waypoints were copied to your clipboard!",
2.5f
)
}
private fun loadWaypointsForSelection(selection: Int) {
entries.clear()
scrollComponent.clearChildren()
val island = SkyblockIsland.values()[selection]
Waypoints.waypoints.filter {
it.island == island
}.sortedBy { "${it.name} ${it.pos} ${it.enabled}" }.forEach {
addNewWaypoint(it.name, it.pos, it.enabled)
}
}
private fun addNewWaypoint(name: String = "", pos: BlockPos = mc.thePlayer.position, selected: Boolean = false) {
val container = UIContainer().childOf(scrollComponent).constrain {
x = CenterConstraint()
y = SiblingConstraint(5f)
width = 80.percent()
height = 9.5.percent()
}.effect(OutlineEffect(Color(0, 243, 255), 1f))
val selected = CheckboxComponent(selected).childOf(container).constrain {
x = 7.5.pixels()
y = CenterConstraint()
}
val nameComponent = UIText(name).childOf(container).constrain {
x = SiblingConstraint(5f)
y = CenterConstraint()
}
val xComponent = UIText(pos.x.toString()).childOf(container).constrain {
x = SiblingConstraint(5f)
y = CenterConstraint()
}
val yComponent = UIText(pos.y.toString()).childOf(container).constrain {
x = SiblingConstraint(5f)
y = CenterConstraint()
}
val zComponent = UIText(pos.z.toString()).childOf(container).constrain {
x = SiblingConstraint(5f)
y = CenterConstraint()
}
entries[container] = Entry(selected, nameComponent, xComponent, yComponent, zComponent)
}
override fun onScreenClose() {
super.onScreenClose()
Skytils.displayScreen = WaypointsGui()
}
private data class Entry(
val selected: CheckboxComponent,
val name: UIText,
val x: UIText,
val y: UIText,
val z: UIText
)
}