12:58:22,542 ERROR [LegacyApplication] Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.StackOverflowError
at java.util.HashMap.hash(HashMap.java:338) ~[?:1.8.0_111]
at java.util.HashMap.remove(HashMap.java:798) ~[?:1.8.0_111]
at java.util.HashSet.remove(HashSet.java:235) ~[?:1.8.0_111]
at com.simsilica.lemur.input.InputMapper.deactivate(InputMapper.java:423) ~[lemur-1.9.1.jar:?]
at com.simsilica.lemur.input.InputMapper$StateGroupIndex.refresh(InputMapper.java:757) ~[lemur-1.9.1.jar:?]
at com.simsilica.lemur.input.InputMapper$StateGroupIndex.refresh(InputMapper.java:764) ~[lemur-1.9.1.jar:?]
at com.simsilica.lemur.input.InputMapper$StateGroupIndex.refresh(InputMapper.java:764) ~[lemur-1.9.1.jar:?]
at com.simsilica.lemur.input.InputMapper$StateGroupIndex.refresh(InputMapper.java:764) ~[lemur-1.9.1.jar:?]
at com.simsilica.lemur.input.InputMapper$StateGroupIndex.refresh(InputMapper.java:764) ~[lemur-1.9.1.jar:?]
at com.simsilica.lemur.input.InputMapper$StateGroupIndex.refresh(InputMapper.java:764) ~[lemur-1.9.1.jar:?]
at com.simsilica.lemur.input.InputMapper$StateGroupIndex.refresh(InputMapper.java:764) ~[lemur-1.9.1.jar:?]
When I press the TAB key, to shoot my bombs. The stacktrace continues like that for 100s of lines.
Suspected cause: Having both a binding for TAB, and one for SHIFT+TAB, like so:
public class PlayerMovementFunctions {
public static final String G_MOVEMENT = "Movement";
public static final FunctionId F_BOMB = new FunctionId(G_MOVEMENT, "Bomb");
public static final FunctionId F_MINE = new FunctionId(G_MOVEMENT, "Mine");
public static void initializeDefaultMappings(InputMapper inputMapper) {
if (!inputMapper.hasMappings(F_BOMB)) {
inputMapper.map(F_BOMB, KeyInput.KEY_TAB);
}
if (!inputMapper.hasMappings(F_MINE)) {
inputMapper.map(F_MINE, KeyInput.KEY_LSHIFT, KeyInput.KEY_TAB);
}
}
}
Tests: I’ve tried removing the binding from the addStateListener and removeStateListener:
Thanks. It doesn’t throw the error now, but I think my StateFunctionListener may be wrong - since I check on value == InputState.Positive it triggers an action as soon as one of the buttons is pressed down - which doesn’t work for combos, since one key is perhaps pressed before the other.
@Override
public void valueChanged(FunctionId func, InputState value, double tpf) {
if (value == InputState.Positive) {
if (func == PlayerMovementFunctions.F_SHOOT) {
session.attack(ProjectileTypes.BULLET);
} else if (func == PlayerMovementFunctions.F_BOMB) {
session.attack(ProjectileTypes.BOMB);
} else if (func == PlayerMovementFunctions.F_GRAVBOMB) {
session.attack(ProjectileTypes.GRAVITYBOMB);
} else if (func == PlayerMovementFunctions.F_REPEL) {
session.attack(ProjectileTypes.REPEL);
} else if (func == PlayerMovementFunctions.F_MINE) {
session.attack(ProjectileTypes.MINE);
}
}
}
I’ll work on this and see if I can come up with a sensible solution
Yeah, I think that’s true. If you activate something on the down then you’ll end up with both activated. At least, I don’t think I automatically deactivate the other one.
I dont really understand the order of the mappings/bindings, because I have other bindings depending on the other key (3+ bindings that overlap so to speak with both key combos and single keys).
It depends on the order the keys are passed to the mapping call for sure. That much I know 100%. I just can’t remember off the top of my head which is the proper order. I thought it was shared keys must go first… but that could be backwards.
It’s definitely consistent, whichever way it is. And when I get it wrong, I just never see the events. I don’t get that weird error you got.
Yea, but I could have scenarios where both keys in a key combo is shared with other key combos. But I guess that doesn’t really matter as long as I put the shared keys first.
I tried with InputState.Off, to make it fire when I release the keys. Now it seems to map to one binding alone, but the wrong one. I try with SHIFT+TAB, but it maps to just SHIFT.
These are my mappings:
// Default key mappings
if (!inputMapper.hasMappings(F_TURN)) {
inputMapper.map(F_TURN, KeyInput.KEY_A);
inputMapper.map(F_TURN, InputState.Negative, KeyInput.KEY_D);
}
if (!inputMapper.hasMappings(F_THRUST)) {
inputMapper.map(F_THRUST, KeyInput.KEY_W);
inputMapper.map(F_THRUST, InputState.Negative, KeyInput.KEY_S);
}
if (!inputMapper.hasMappings(F_SHOOT)) {
inputMapper.map(F_SHOOT, KeyInput.KEY_LCONTROL);
}
if (!inputMapper.hasMappings(F_BOMB)) {
inputMapper.map(F_BOMB, KeyInput.KEY_TAB);
}
if (!inputMapper.hasMappings(F_STOP)) {
inputMapper.map(F_STOP, KeyInput.KEY_SPACE);
}
if (!inputMapper.hasMappings(F_MOUSELEFTCLICK)) {
inputMapper.map(F_MOUSELEFTCLICK, Button.MOUSE_BUTTON1);
}
if (!inputMapper.hasMappings(F_MOUSERIGHTCLICK)) {
inputMapper.map(F_MOUSERIGHTCLICK, Button.MOUSE_BUTTON2);
}
if (!inputMapper.hasMappings(F_GRAVBOMB)) {
inputMapper.map(F_GRAVBOMB, KeyInput.KEY_LSHIFT);
}
if (!inputMapper.hasMappings(F_REPEL)) {
inputMapper.map(F_REPEL, KeyInput.KEY_LSHIFT, KeyInput.KEY_LCONTROL);
}
if (!inputMapper.hasMappings(F_MINE)) {
inputMapper.map(F_MINE, KeyInput.KEY_TAB, KeyInput.KEY_LSHIFT);
}
As I said, I could have it backwards and it’s supposed to be shared key last. Unfortunately, I don’t have time to look at my own mappings at the moment… but I do this in a few places in my own code.