Skip to content

Commit

Permalink
Setting to use vanilla selection graphics
Browse files Browse the repository at this point in the history
Property to change
Add search bar to seer dialog
Cleanup BiasedLevenshtein functions
  • Loading branch information
buthed010203 committed Oct 16, 2023
1 parent 58e34cd commit a92818f
Show file tree
Hide file tree
Showing 16 changed files with 143 additions and 117 deletions.
4 changes: 3 additions & 1 deletion core/assets/bundles/bundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1458,6 +1458,8 @@ setting.drawwrecks.name = Draw Unit Wrecks
setting.drawallitems.name = Draw Items For All Units
setting.drawallitems.description = When turned off, only your unit's items will be drawn
setting.drawpath.name = Draw Paths When Pathing
setting.drawselectionvanilla.name = Vanilla Area Selection Graphics
setting.drawselectionvanilla.description = Draws an outline when selecting an area (schematics, rebuilding, breaking).
setting.drawcursors.name = Draw Player Cursors
setting.drawdisplayborder.name = Draw Display & Canvas Borders
setting.tracelogicunits.name = Trace logic controlled units
Expand All @@ -1484,7 +1486,7 @@ setting.cursednesslevel.description = EPILEPSY WARNING ANYTHING ABOVE OHNO
setting.showcutscenes.name = Show Cutscenes
setting.logiclinkorder.name = Free Logic Link Names Upon Link Removal
setting.powerinfo.name = Power Info
setting.powerinfo.description = Shows power info of the largest network in the top left pane.
setting.powerinfo.description = Shows power info of the largest network in the top left pane. Requires restart to take effect.
setting.activemodesdisplay.name = Active Modes Diplay
setting.activemodesdisplay.description = Shows information about whether things are enabled (such as showing turret ranges, hiding fog, hiding air units, navigating, etc) in the top left pane.

Expand Down
8 changes: 1 addition & 7 deletions core/src/mindustry/Vars.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import mindustry.mod.*;
import mindustry.net.*;
import mindustry.service.*;
import mindustry.type.*;
import mindustry.ui.dialogs.*;
import mindustry.world.*;
import mindustry.world.meta.*;
Expand Down Expand Up @@ -296,7 +295,7 @@ public static void init(){
saveDirectory = dataDirectory.child("saves/");
tmpDirectory = dataDirectory.child("tmp/");
modDirectory = dataDirectory.child("mods/");
schematicDirectory = dataDirectory.child("schematics/");
schematicDirectory = OS.hasProp("schematicDir") ? Fi.get(OS.prop("schematicDir")) : dataDirectory.child("schematics/");
bebuildDirectory = dataDirectory.child("be_builds/");
emptyMap = new Map(new StringMap());

Expand Down Expand Up @@ -438,11 +437,6 @@ public static void loadSettings(){
keybinds.setDefaults(Binding.values());
settings.setAutosave(false);
settings.load();
Core.app.post(() -> { // Set settings vars FINISHME: Move this awfulness
UnitType.drawAllItems = settings.getBool("drawallitems");
UnitType.formationAlpha = settings.getInt("formationopacity") / 100f;
UnitType.hitboxAlpha = settings.getInt("hitboxopacity") / 100f;
});
if(Core.settings.getBool("debug") || OS.hasProp("debug")) Log.level = Log.LogLevel.debug;

//https://github.com/Anuken/Mindustry/issues/8483
Expand Down
6 changes: 5 additions & 1 deletion core/src/mindustry/client/ClientLogic.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import mindustry.client.navigation.*
import mindustry.client.navigation.Navigation.stopFollowing
import mindustry.client.ui.*
import mindustry.client.utils.*
import mindustry.client.utils.BiasedLevenshtein.biasedLevenshtein
import mindustry.core.*
import mindustry.game.EventType.*
import mindustry.gen.*
Expand Down Expand Up @@ -120,6 +121,9 @@ class ClientLogic {
if (settings.getBool("discordrpc")) platform.startDiscord()
if (settings.getBool("mobileui")) mobile = !mobile
if (settings.getBool("viruswarnings")) LExecutor.virusWarnings = true
UnitType.drawAllItems = settings.getBool("drawallitems")
UnitType.formationAlpha = settings.getInt("formationopacity") / 100f
UnitType.hitboxAlpha = settings.getInt("hitboxopacity") / 100f

Autocomplete.autocompleters.add(BlockEmotes(), PlayerCompletion(), CommandCompletion())

Expand All @@ -132,7 +136,7 @@ class ClientLogic {
if (isDeveloper()) {
register("update <name/id...>") { args, _ ->
val name = args.joinToString(" ")
val player = Groups.player.find { it.id == Strings.parseInt(name) } ?: Groups.player.minByOrNull { BiasedLevenshtein.biasedLevenshteinInsensitive(Strings.stripColors(it.name), name) }!!
val player = Groups.player.find { it.id == Strings.parseInt(name) } ?: Groups.player.minByOrNull { biasedLevenshtein(Strings.stripColors(it.name), name) }!!
Main.send(CommandTransmission(CommandTransmission.Commands.UPDATE, Main.keyStorage.cert() ?: return@register, player))
}
}
Expand Down
13 changes: 7 additions & 6 deletions core/src/mindustry/client/Commands.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ fun setupCommands() {
}

register("unit-old <unit-type>", Core.bundle.get("client.command.unit.description")) { args, _ ->
ui.unitPicker.pickUnit(content.units().min { b -> BiasedLevenshtein.biasedLevenshteinInsensitive(args[0], b.name) })
ui.unitPicker.pickUnit(content.units().min { b -> BiasedLevenshtein.biasedLevenshtein(args[0], b.name) })
}

register("unit <unit-type>", Core.bundle.get("client.command.unit.description")) { args, _ ->
Expand Down Expand Up @@ -437,7 +437,7 @@ fun setupCommands() {
})
}

register("binds <type>", Core.bundle.get("client.command.binds.description")) { args, player ->
register("binds <type>", Core.bundle.get("client.command.binds.description")) { args, player -> // FINISHME: Pagination
val type = findUnit(args[0])

player.team().data().unitCache(type)
Expand Down Expand Up @@ -699,7 +699,7 @@ fun setupCommands() {
register("mute <player>", Core.bundle.get("client.command.mute.description")) { args, player ->
val id = args[0].toIntOrNull()
val target = if (id != null && Groups.player.getByID(id) != null) Groups.player.getByID(id)
else Groups.player.minBy { p -> BiasedLevenshtein.biasedLevenshteinInsensitive(p.name, args[0]) }
else Groups.player.minBy { p -> BiasedLevenshtein.biasedLevenshtein(p.name, args[0]) }

player.sendMessage(Core.bundle.format("client.command.mute.success", target.coloredName(), target.id))
val previous = mutedPlayers.firstOrNull { pair -> pair.first.name == target.name || pair.second == target.id }
Expand All @@ -709,7 +709,7 @@ fun setupCommands() {

register("unmute <player>", Core.bundle.get("client.command.unmute.description")) { args, player ->
val id = args[0].toIntOrNull()
val target = Groups.player.minBy { p -> BiasedLevenshtein.biasedLevenshteinInsensitive(p.name, args[0]) }
val target = Groups.player.minBy { p -> BiasedLevenshtein.biasedLevenshtein(p.name, args[0]) }
val match = mutedPlayers.firstOrNull { p -> (id != null && p.second == id) || (p.first != null && p.first.name == target.name) }
if (match != null) {
if (target != null) player.sendMessage(Core.bundle.format("client.command.unmute.success", target.coloredName(), target.id))
Expand All @@ -724,8 +724,9 @@ fun setupCommands() {
mutedPlayers.clear()
}

register("ohno", "Runs the auto ohno procedure on fish servers") { _, _ -> // FINISHME: This is great and all but it would be nice to run this automatically every minute or so
register("ohno", "Runs the auto ohno procedure on fish servers") { _, player -> // FINISHME: This is great and all but it would be nice to run this automatically every minute or so
if (!Server.fish()) return@register
player.sendMessage("[accent]Running auto ohno") // FINISHME: Bundle
Server.ohnoTask?.cancel()
Server.ohnoTask = Timer.schedule({ Call.sendChatMessage("/ohno") }, 0f, 0.3f)
}
Expand Down Expand Up @@ -773,7 +774,7 @@ fun setupCommands() {

register("hh [h]", "!") { args, player ->
if (!net.client()) return@register
val u = if (args.any()) content.units().min { u -> BiasedLevenshtein.biasedLevenshteinInsensitive(args[0], u.name) } else player.unit().type
val u = if (args.any()) findUnit(args[0]) else player.unit().type
val current = ui.join.lastHost ?: return@register
if (current.group == null) current.group = ui.join.communityHosts.find { it == current } ?.group ?: return@register
switchTo = ui.join.communityHosts.filterTo(arrayListOf<Any>()) { it.group == current.group && it != current && (it.version == Version.build || Version.build == -1) }.apply { add(current); add(u) }
Expand Down
2 changes: 1 addition & 1 deletion core/src/mindustry/client/ui/FindDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ object FindDialog : BaseDialog("@client.find") {
private var guesses: MutableList<Block> = mutableListOf()

private fun updateGuesses() {
guesses = content.blocks().copy().toMutableList().apply { sortBy { BiasedLevenshtein.biasedLevenshteinInsensitive(it.localizedName, inputField.text) } }
guesses = content.blocks().copy().toMutableList().apply { sortBy { BiasedLevenshtein.biasedLevenshtein(it.localizedName, inputField.text) } }
}

private fun updateImages() {
Expand Down
62 changes: 38 additions & 24 deletions core/src/mindustry/client/ui/SeerDialog.kt
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
package mindustry.client.ui

import arc.Core
import mindustry.Vars
import mindustry.client.antigrief.Seer
import mindustry.client.utils.dialog
import mindustry.client.utils.label
import mindustry.client.utils.wrap
import mindustry.ui.dialogs.BaseDialog
import java.time.temporal.ChronoUnit

object SeerDialog : BaseDialog("Seer") {
import arc.*
import arc.scene.ui.*
import arc.scene.ui.layout.*
import mindustry.*
import mindustry.client.antigrief.*
import mindustry.client.utils.*
import mindustry.ui.dialogs.*
import java.time.temporal.*

object SeerDialog : BaseDialog("Seer") { // FINISHME: Bundle
init {
cont.button("Cached players") {
dialog("Seer cached players") {
cont.label("Click on player to copy their id").center().grow()
cont.row()
showCachedPlayers()
}.size(200f, 50f)

cont.button("Settings") {
// FINISHME: Separate UI
Vars.ui.settings.visible(3) // Activate client settings
}.size(200f, 50f)

addCloseButton()
}

cont.pane { t ->
for (data in Seer.players) {
private fun showCachedPlayers() {
dialog("Seer cached players") {
fun createPane(search: String = "") =
Table { t ->
for (data in Seer.players.select { search.isBlank() || BiasedLevenshtein.biasedLevenshtein(search, it.lastInstance.name) < 3 }) {
t.button(
"<${data.score}> ${data.lastInstance.name}[white] (${data.id}) [${data.firstJoined.truncatedTo(
ChronoUnit.MINUTES)}m]") {
Expand All @@ -26,16 +36,20 @@ object SeerDialog : BaseDialog("Seer") {
t.marginBottom(10f)
t.row()
}
}.grow()
addCloseButton()
}.show()
}.size(200f, 50f)
}

cont.button("Settings") {
// FINISHME: Separate UI
Vars.ui.settings.visible(3) // Activate client settings
}.size(200f, 50f)
val pane = ScrollPane(createPane())

addCloseButton()
var search = ""
cont.table { table ->
table.label("@search")
table.field(search) { search = it; pane.widget = createPane(search) }
}.center().row()

cont.label("Click on player to copy their id").center().row()
cont.add(pane)

addCloseButton()
}.show()
}
}
2 changes: 1 addition & 1 deletion core/src/mindustry/client/ui/UnitPicker.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ void build(){
labels.add(new Label(""));
}
TextField searchField = cont.field("", string -> {
sorted = sorted.sort((b) -> BiasedLevenshtein.biasedLevenshteinInsensitive(string, b.localizedName));
sorted = sorted.sort((b) -> BiasedLevenshtein.biasedLevenshtein(string, b.localizedName));
for (int i = 0; i < imgs.size; i++) {
Image region = new Image(sorted.get(i).uiIcon);
imgs.get(i).setDrawable(region.getDrawable());
Expand Down
119 changes: 62 additions & 57 deletions core/src/mindustry/client/utils/BiasedLevenshtein.kt
Original file line number Diff line number Diff line change
@@ -1,77 +1,82 @@
package mindustry.client.utils;
@file:Suppress("NAME_SHADOWING")

public class BiasedLevenshtein {
package mindustry.client.utils

public static float biasedLevenshtein(String x, String y) {
int[][] dp = new int[x.length() + 1][y.length() + 1];
import arc.math.*
import kotlin.math.*

for(int i = 0; i <= x.length(); i++){
for(int j = 0; j <= y.length(); j++){
if(i == 0){
dp[i][j] = j;
}else if(j == 0){
dp[i][j] = i;
}else{
dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1]
+ (x.charAt(i - 1) == y.charAt(j - 1) ? 0 : 1),
dp[i - 1][j] + 1),
dp[i][j - 1] + 1);
object BiasedLevenshtein {
@JvmOverloads @JvmStatic
fun biasedLevenshtein(x: String, y: String, caseSensitive: Boolean = false, lengthIndependent: Boolean = false): Float {
var x = x
var y = y
if (!caseSensitive) {
x = x.lowercase()
y = y.lowercase()
}
if (lengthIndependent) return biasedLevenshteinLengthIndependent(x, y)

val dp = Array(x.length + 1) { IntArray(y.length + 1) }
for (i in 0..x.length) {
for (j in 0..y.length) {
if (i == 0) {
dp[i][j] = j
} else if (j == 0) {
dp[i][j] = i
} else {
dp[i][j] = minOf(
(dp[i - 1][j - 1] + if (x[i - 1] == y[j - 1]) 0 else 1),
(dp[i - 1][j] + 1),
(dp[i][j - 1] + 1)
)
}
}
}

int output = dp[x.length()][y.length()];
val output = dp[x.length][y.length]
if (y.startsWith(x) || x.startsWith(y)) {
return output / 3f;
return output / 3f
}
if (y.contains(x) || x.contains(y)) {
return output / 1.5f;
}
return output;
}

public static float biasedLevenshteinInsensitive(String x, String y) {
return biasedLevenshtein(x.toLowerCase(), y.toLowerCase());
return if (y.contains(x) || x.contains(y)) {
output / 1.5f
} else output.toFloat()
}

public static float biasedLevenshteinLengthIndependent(String x, String y) {
if (x.length() > y.length()){
String temp = x;
x = y;
y = temp;
}
int xl = x.length(), yl = y.length();
int yw = yl + 1;
int[] dp = new int[2 * yw];
// FINISHME: This should be merged with the function above. I can't be bothered to figure out what the differences between the two are now though
private fun biasedLevenshteinLengthIndependent(x: String, y: String): Float {
var x = x
var y = y
if (x.length > y.length) x = y.apply { y = x } // Y will be the longer of the two

for(int j=0; j <= yl; ++j){
dp[j] = 0; // Insertions at the beginning are free
}
int prev = yw, curr = 0, temp;
for(int i = 1; i <= xl; i++){
temp = prev;
prev = curr;
curr = temp;
dp[curr] = i;
for(int j = 1; j <= yl; j++){
dp[curr + j] = Math.min(dp[prev + j - 1] + (x.charAt(i - 1) == y.charAt(j - 1) ? 0 : 1),
Math.min(dp[prev + j], dp[curr + j - 1]) + 1);
val xl = x.length
val yl = y.length
val yw = yl + 1
val dp = IntArray(2 * yw)
for (j in 0..yl) dp[j] = 0 // Insertions at the beginning are free
var prev = yw
var curr = 0
var temp: Int
for (i in 1..xl) {
temp = prev
prev = curr
curr = temp
dp[curr] = i
for (j in 1..yl) {
dp[curr + j] = minOf(
dp[prev + j - 1] + Mathf.num(x[i - 1] != y[j - 1]),
dp[prev + j] + 1,
dp[curr + j - 1] + 1,
)
}
}

// startsWith
if(dp[curr + xl] == 0) return 0f;
if (dp[curr + xl] == 0) return 0f
// Disregard insertions at the end - if it made it it made it
int output = xl;
for(int i = curr; i < curr + yl; ++i){
output = Math.min(output, dp[i]);
var output = xl
for (i in curr until curr + yl) {
output = min(output, dp[i])
}
// contains
if (output == 0) return 0.5f; // Prefer startsWith
return output;
}

public static float biasedLevenshteinLengthIndependentInsensitive(String x, String y) {
return biasedLevenshteinLengthIndependent(x.toLowerCase(), y.toLowerCase());
return if (output == 0) 0.5f else output.toFloat() // Prefer startsWith
}
}
2 changes: 1 addition & 1 deletion core/src/mindustry/client/utils/BlockEmotes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class BlockEmotes : Autocompleter {
matchCache = 0f
return 0f
}
var dst = BiasedLevenshtein.biasedLevenshteinInsensitive(input.substring(input.lastIndexOf(':') + 1), name)
var dst = BiasedLevenshtein.biasedLevenshtein(input.substring(input.lastIndexOf(':') + 1), name)
dst *= -1f
dst += name.length.toFloat()
dst /= name.length.toFloat()
Expand Down
8 changes: 4 additions & 4 deletions core/src/mindustry/client/utils/ClientUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -457,13 +457,13 @@ fun ChatMessage.findCoords(): ChatMessage = NetClient.findCoords(this)

fun ChatMessage.findLinks(start: Int = 0): ChatMessage = NetClient.findLinks(this, start)

fun findItem(arg: String): Item = content.items().min { b -> BiasedLevenshtein.biasedLevenshteinInsensitive(arg, b.localizedName) }
fun findItem(arg: String): Item = content.items().min { b -> BiasedLevenshtein.biasedLevenshtein(arg, b.localizedName) }

fun findUnit(arg: String): UnitType = content.units().min { b -> BiasedLevenshtein.biasedLevenshteinInsensitive(arg, b.localizedName) }
fun findUnit(arg: String): UnitType = content.units().min { b -> BiasedLevenshtein.biasedLevenshtein(arg, b.localizedName) }

fun findBlock(arg: String): Block = content.blocks().min { b -> BiasedLevenshtein.biasedLevenshteinInsensitive(arg, b.localizedName) }
fun findBlock(arg: String): Block = content.blocks().min { b -> BiasedLevenshtein.biasedLevenshtein(arg, b.localizedName) }

fun findTeam(arg: String): Team = if (arg.toIntOrNull() in 0 until Team.all.size) Team.all[arg.toInt()] else Team.all.minBy { t -> if (t.name == null) Float.MAX_VALUE else BiasedLevenshtein.biasedLevenshteinInsensitive(arg, t.localized()) }
fun findTeam(arg: String): Team = if (arg.toIntOrNull() in 0 until Team.all.size) Team.all[arg.toInt()] else Team.all.minBy { t -> if (t.name == null) Float.MAX_VALUE else BiasedLevenshtein.biasedLevenshtein(arg, t.localized()) }

fun parseBool(arg: String) = arg.lowercase().startsWith("y") || arg.lowercase().startsWith("t") // FINISHME: This should probably just spit out an error on non y/n input

Expand Down
Loading

0 comments on commit a92818f

Please sign in to comment.