Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/main/kotlin/com/lambda/config/groups/BreakSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.lambda.interaction.managers.breaking.BreakConfig.BreakMode
import com.lambda.interaction.managers.breaking.BreakConfig.SwingMode
import com.lambda.util.NamedEnum
import net.minecraft.block.Block
import net.minecraft.registry.Registries
import java.awt.Color

open class BreakSettings(
Expand Down Expand Up @@ -77,7 +78,7 @@ open class BreakSettings(
override val breaksPerTick by c.setting("${prefix}Breaks Per Tick", 30, 1..30, 1, "Maximum instant block breaks per tick", visibility = visibility).group(*baseGroup, Group.General).index()

// Block
override val ignoredBlocks by c.setting("${prefix}Ignored Blocks", emptySet<Block>(), description = "Blocks that wont be broken", visibility = visibility).group(*baseGroup, Group.General).index()
override val blocks by c.setting("${prefix}Blocks", Registries.BLOCK.toList(), description = "Blocks that are allowed to be broken", visibility = visibility).group(*baseGroup, Group.General).index()
override val avoidFluids by c.setting("${prefix}Avoid Fluids", true, "Avoids breaking blocks that would cause fluids to spill", visibility = visibility).group(*baseGroup, Group.General).index()
override val avoidSupporting by c.setting("${prefix}Avoid Supporting", true, "Avoids breaking the block supporting the player", visibility = visibility).group(*baseGroup, Group.General).index()
override val fillFluids by c.setting("Fill Fluids", true, "Fills fluids in order to break blocks that would initially spill them") { visibility() && avoidFluids }.group(*baseGroup, Group.General).index()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ class BlockCollectionSetting(
serialize = true,
) {
context(setting: Setting<*, MutableCollection<Block>>)
override fun ImGuiBuilder.buildLayout() = buildComboBox("block") { BlockCodec.stringify(it) }
override fun ImGuiBuilder.buildLayout() = buildDualPane("block") { BlockCodec.stringify(it) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class ClassCollectionSetting<T : Any>(
serialize = false,
) {
context(setting: Setting<*, MutableCollection<T>>)
override fun ImGuiBuilder.buildLayout() = buildComboBox("item") { it.className }
override fun ImGuiBuilder.buildLayout() = buildDualPane("item") { it.className }

// When serializing the list to json we do not want to serialize the elements' classes, but their stringified representation.
// If we do serialize the classes we'll run into missing type adapters errors by Gson.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ import com.lambda.config.SettingEditorDsl
import com.lambda.config.SettingGroupEditor
import com.lambda.context.SafeContext
import com.lambda.gui.dsl.ImGuiBuilder
import com.lambda.imgui.ImGui
import com.lambda.imgui.ImGui.getContentRegionAvail
import com.lambda.threading.runSafe
import com.lambda.imgui.ImGuiListClipper
import com.lambda.imgui.callback.ImListClipperCallback
import com.lambda.imgui.flag.ImGuiChildFlags
import com.lambda.imgui.flag.ImGuiPopupFlags
import com.lambda.imgui.flag.ImGuiSelectableFlags.DontClosePopups
import java.lang.reflect.Type

Expand Down Expand Up @@ -66,47 +69,100 @@ open class CollectionSetting<R : Any>(
val deselectListeners = mutableListOf<SafeContext.(R) -> Unit>()

context(setting: Setting<*, MutableCollection<R>>)
override fun ImGuiBuilder.buildLayout() = buildComboBox("item") { it.toString() }
override fun ImGuiBuilder.buildLayout() = buildDualPane("item") { it.toString() }

context(setting: Setting<*, MutableCollection<R>>)
fun ImGuiBuilder.buildComboBox(itemName: String, toString: (R) -> String) {
fun ImGuiBuilder.buildDualPane(itemName: String, toString: (R) -> String) {
val text = if (value.size == 1) itemName else "${itemName}s"
val popupId = "##${setting.name}-collection-popup"

combo("##${setting.name}", "${setting.name}: ${value.size} $text") {
button("${setting.name}: ${value.size} $text") {
ImGui.openPopup(popupId)
}

ImGui.setNextWindowSizeConstraints(500f, 0f, Float.MAX_VALUE, io.displaySize.y * 0.5f)
popupContextItem(popupId, ImGuiPopupFlags.None) {
inputText("##${setting.name}-SearchBox", ::searchFilter)

child(
strId = "##${setting.name}-ComboOptionsChild",
childFlags = ImGuiChildFlags.AutoResizeY or ImGuiChildFlags.AlwaysAutoResize,
) {
val list = immutableCollection
.filter { item ->
val q = searchFilter.trim()
if (q.isEmpty()) true
else toString(item).contains(q, ignoreCase = true)
val q = searchFilter.trim()
val filteredDeselected = immutableCollection
.filter { item -> !value.contains(item) && (q.isEmpty() || toString(item).contains(q, ignoreCase = true)) }
val filteredSelected = immutableCollection
.filter { item -> value.contains(item) && (q.isEmpty() || toString(item).contains(q, ignoreCase = true)) }

val availableWidth = getContentRegionAvail().x
val swapButtonWidth = 30f
val paneWidth = (availableWidth - swapButtonWidth - style.itemSpacing.x * 2) / 2f
val paneHeight = 200f

group {
textDisabled("Deselected (${filteredDeselected.size})")
child(
strId = "##${setting.name}-Deselected",
width = paneWidth,
height = paneHeight,
childFlags = ImGuiChildFlags.Border or ImGuiChildFlags.ResizeX or ImGuiChildFlags.ResizeY,
) {
val deselectedCallback = object : ImListClipperCallback() {
override fun accept(index: Int) {
val v = filteredDeselected.getOrNull(index) ?: return
selectable(
label = toString(v),
flags = DontClosePopups
) {
value.add(v)
runSafe { selectListeners.forEach { listener -> listener(v) } }
}
}
}
ImGuiListClipper.forEach(filteredDeselected.size, deselectedCallback)
}
}

sameLine()

group {
cursorPosY += paneHeight / 2f
button("<>", swapButtonWidth) {
val currentlySelected = value.toList()
val allItems = immutableCollection.toList()
value.clear()
allItems.forEach { item ->
if (!currentlySelected.contains(item)) {
value.add(item)
}
}
runSafe {
currentlySelected.forEach { v -> deselectListeners.forEach { listener -> listener(v) } }
value.forEach { v -> selectListeners.forEach { listener -> listener(v) } }
}
}
}

val listClipperCallback = object : ImListClipperCallback() {
override fun accept(index: Int) {
val v = list.getOrNull(index) ?: return
val selected = value.contains(v)

selectable(
label = toString(v),
selected = selected,
flags = DontClosePopups
) {
if (selected) {
sameLine()

group {
textDisabled("Selected (${filteredSelected.size})")
child(
strId = "##${setting.name}-Selected",
width = paneWidth,
height = paneHeight,
childFlags = ImGuiChildFlags.Border or ImGuiChildFlags.ResizeX or ImGuiChildFlags.ResizeY,
) {
val selectedCallback = object : ImListClipperCallback() {
override fun accept(index: Int) {
val v = filteredSelected.getOrNull(index) ?: return
selectable(
label = toString(v),
flags = DontClosePopups
) {
value.remove(v)
runSafe { deselectListeners.forEach { listener -> listener(v) } }
} else {
value.add(v)
runSafe { selectListeners.forEach { listener -> listener(v) } }
}
}
}
ImGuiListClipper.forEach(filteredSelected.size, selectedCallback)
}
ImGuiListClipper.forEach(list.size, listClipperCallback)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ class ItemCollectionSetting(
serialize = true,
) {
context(setting: Setting<*, MutableCollection<Item>>)
override fun ImGuiBuilder.buildLayout() = buildComboBox("item") { ItemCodec.stringify(it) }
override fun ImGuiBuilder.buildLayout() = buildDualPane("item") { ItemCodec.stringify(it) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ object BasicChecker : Results<PreSimResult> {
}

// block should be ignored
if (state.block in breakConfig.ignoredBlocks && this@hasBasicRequirements is BreakSimInfo) {
if (this@hasBasicRequirements is BreakSimInfo && state.block !in breakConfig.blocks) {
result(GenericResult.Ignored(pos))
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ interface BreakConfig : ActionConfig, ISettingGroup {
val avoidFluids: Boolean
val fillFluids: Boolean
val avoidSupporting: Boolean
val ignoredBlocks: Collection<Block>
val blocks: Collection<Block>

val efficientOnly: Boolean
val suitableToolsOnly: Boolean
Expand Down