wip: different heights for jump arrows

Note that this is very incomplete, for two different reasons:
- it's O(n^2) or potentially worse
- it makes the GC work hard (it invokes `new` in
  `LCanvas.DragLayout.layout()`)

For the second reason this does not clearly fit the criteria of
CONTRIBUTING.md, but I have yet to figure out ways to work around this
(or make the algorithm more efficient).
This commit is contained in:
code-explorer786
2024-06-26 10:37:20 +07:00
parent b8c9a05963
commit b58a6bb8d6
4 changed files with 94 additions and 4 deletions

View File

@@ -1225,6 +1225,7 @@ setting.bridgeopacity.name = Bridge Opacity
setting.playerchat.name = Display Player Bubble Chat setting.playerchat.name = Display Player Bubble Chat
setting.showweather.name = Show Weather Graphics setting.showweather.name = Show Weather Graphics
setting.hidedisplays.name = Hide Logic Displays setting.hidedisplays.name = Hide Logic Displays
setting.dynamicjumpheights.name = Dynamic Jump Heights
setting.macnotch.name = Adapt interface to display notch setting.macnotch.name = Adapt interface to display notch
setting.macnotch.description = Restart required to apply changes setting.macnotch.description = Restart required to apply changes
steam.friendsonly = Friends Only steam.friendsonly = Friends Only

View File

@@ -21,8 +21,10 @@ import mindustry.ui.*;
public class LCanvas extends Table{ public class LCanvas extends Table{
public static final int maxJumpsDrawn = 100; public static final int maxJumpsDrawn = 100;
private static final int invalidJump = Integer.MAX_VALUE; // terrible hack
//ew static variables //ew static variables
static LCanvas canvas; static LCanvas canvas;
private static boolean dynamicJumpHeights = false;
public DragLayout statements; public DragLayout statements;
public ScrollPane pane; public ScrollPane pane;
@@ -108,6 +110,8 @@ public class LCanvas extends Table{
statements = new DragLayout(); statements = new DragLayout();
jumps = statements.jumps; jumps = statements.jumps;
dynamicJumpHeights = Core.settings.getBool("dynamicjumpheights", false);
pane = pane(t -> { pane = pane(t -> {
t.center(); t.center();
t.add(statements).pad(2f).center().width(targetWidth); t.add(statements).pad(2f).center().width(targetWidth);
@@ -196,6 +200,7 @@ public class LCanvas extends Table{
int insertPosition = 0; int insertPosition = 0;
boolean invalidated; boolean invalidated;
public Group jumps = new WidgetGroup(); public Group jumps = new WidgetGroup();
private Seq<JumpCurve> processedJumps = new Seq<JumpCurve>();
{ {
setTransform(true); setTransform(true);
@@ -251,13 +256,73 @@ public class LCanvas extends Table{
} }
} }
if(parent != null) parent.invalidateHierarchy(); if(dynamicJumpHeights) setJumpHeights();
if(parent != null) parent.invalidateHierarchy();//don't invalid self
if(parent != null && parent instanceof Table){ if(parent != null && parent instanceof Table){
setCullingArea(parent.getCullingArea()); setCullingArea(parent.getCullingArea());
} }
} }
private void setJumpHeights(){
SnapshotSeq<Element> jumpsChildren = jumps.getChildren();
processedJumps.clear();
jumpsChildren.each(e -> {
if(e instanceof JumpCurve e2){
e2.prepareHeight();
if(e2.jumpUIBegin != invalidJump){
processedJumps.add(e2);
}
}
});
processedJumps.sort((a,b) -> a.jumpUIBegin - b.jumpUIBegin);
Seq<JumpCurve> occupiers = new Seq<JumpCurve>();
Bits occupied = new Bits();
for(int i = 0; i < processedJumps.size; i++){
JumpCurve cur = processedJumps.get(i);
occupiers.retainAll(e -> {
if(e.jumpUIEnd > cur.jumpUIBegin) return true;
occupied.clear(e.predHeight);
return false;
});
int h = getJumpHeight(i, occupiers, occupied);
occupiers.add(cur);
occupied.set(h);
}
}
private int getJumpHeight(int index, Seq<JumpCurve> occupiers, Bits occupied){
JumpCurve jmp = processedJumps.get(index);
if(jmp.markedDone) return jmp.predHeight;
// TODO: optimize for LESS cloning
Seq<JumpCurve> tmpOccupiers = new Seq<JumpCurve>(occupiers);
Bits tmpOccupied = new Bits();
tmpOccupied.set(occupied);
int max = -1;
for(int i = index + 1; i < processedJumps.size; i++){
JumpCurve cur = processedJumps.get(i);
if(cur.jumpUIEnd > jmp.jumpUIEnd) continue;
tmpOccupiers.retainAll(e -> {
if(e.jumpUIEnd > cur.jumpUIBegin) return true;
tmpOccupied.clear(e.predHeight);
return false;
});
int h = getJumpHeight(i, tmpOccupiers, tmpOccupied);
tmpOccupiers.add(cur);
tmpOccupied.set(h);
max = Math.max(max, h);
}
jmp.predHeight = occupied.nextClearBit(max + 1);
jmp.markedDone = true;
return jmp.predHeight;
}
@Override @Override
public float getPrefWidth(){ public float getPrefWidth(){
return prefWidth; return prefWidth;
@@ -452,12 +517,14 @@ public class LCanvas extends Table{
ClickListener listener; ClickListener listener;
public JumpCurve curve; public JumpCurve curve;
public StatementElem elem;
public JumpButton(Prov<StatementElem> getter, Cons<StatementElem> setter){ public JumpButton(Prov<StatementElem> getter, Cons<StatementElem> setter, StatementElem elem){
super(Tex.logicNode, new ImageButtonStyle(){{ super(Tex.logicNode, new ImageButtonStyle(){{
imageUpColor = Color.white; imageUpColor = Color.white;
}}); }});
this.elem = elem;
to = getter; to = getter;
addListener(listener = new ClickListener()); addListener(listener = new ClickListener());
@@ -518,6 +585,11 @@ public class LCanvas extends Table{
public static class JumpCurve extends Element{ public static class JumpCurve extends Element{
public JumpButton button; public JumpButton button;
// for jump prediction; see DragLayout
public int predHeight = 0;
public boolean markedDone = false;
public int jumpUIBegin = 0, jumpUIEnd = 0;
public JumpCurve(JumpButton button){ public JumpCurve(JumpButton button){
this.button = button; this.button = button;
} }
@@ -575,7 +647,7 @@ public class LCanvas extends Table{
Lines.stroke(4f, button.color); Lines.stroke(4f, button.color);
Draw.alpha(parentAlpha); Draw.alpha(parentAlpha);
float dist = 100f; float dist = 100f + 100f * (float) predHeight;
//square jumps //square jumps
if(false){ if(false){
@@ -599,5 +671,20 @@ public class LCanvas extends Table{
x2, y2, x2, y2,
Math.max(18, (int)(Mathf.dst(x, y, x2, y2) / 6))); Math.max(18, (int)(Mathf.dst(x, y, x2, y2) / 6)));
} }
public void prepareHeight(){
if(this.button.to.get() == null){
this.markedDone = true;
this.predHeight = 0;
this.jumpUIBegin = this.jumpUIEnd = invalidJump;
} else {
this.markedDone = false;
int i = this.button.elem.index;
int j = this.button.to.get().index;
this.jumpUIBegin = Math.min(i,j);
this.jumpUIEnd = Math.max(i,j);
// height will be recalculated later
}
}
} }
} }

View File

@@ -870,7 +870,7 @@ public class LStatements{
table.table(this::rebuild); table.table(this::rebuild);
table.add().growX(); table.add().growX();
table.add(new JumpButton(() -> dest, s -> dest = s)).size(30).right().padLeft(-8); table.add(new JumpButton(() -> dest, s -> dest = s, this.elem)).size(30).right().padLeft(-8);
String name = name(); String name = name();

View File

@@ -502,6 +502,8 @@ public class SettingsMenuDialog extends BaseDialog{
if(!mobile){ if(!mobile){
Core.settings.put("swapdiagonal", false); Core.settings.put("swapdiagonal", false);
} }
graphics.checkPref("dynamicjumpheights", true);
} }
public void exportData(Fi file) throws IOException{ public void exportData(Fi file) throws IOException{