Why can't you make the same functionid twice?


#1

I’m curious as to why it’s forbidden to create identical functionid? I’m trying to support x player split screen (that is, as many controllers as you can plug in/sync) and the easiest way I thought would be to have the functionid’s created dynamically. Now I can make maps at runtime to prevent duplicate id creation but then I’m forced to plan out sharing that function map vs simply creating new functionid’s that are identical.

The function id’s over-ride .equals so having identical id’s seems like something that was planned for, but then the “existing” set prevents you from utilizing said function.

I understand that in the end this might make code more consistent, and slightly lower memory usage, but it forces alot of inter connectivity that I don’t think is necessary.


#2

The function ID defines some game function. Like “player 1 fly up”. It doesn’t make sense to have more than one “player 1 fly up”. I think you are mistaking what a function ID is.

It’s a logical connection to some control input… player 1 thrust, player 2 thrust, player 99 thrust… are all different function IDs.

Note: right now there is a limitation that Lemur only supports one gamepad/joystick at a time. I plan to fix that this weekend… but that is separate from your issue.


#3

Thanks for the quick reply. I’m not trying to register multiple identical id’s, rather I’m trying to make the id object multiple times relying on the fact that they are identical. That way I can have my playerinput object create it’s id’s such as “p1_flyup” and “p2_flyUP” with a function to register the id’s to the mapper, then down the line I can have an appstate that creates and identical functionid to register to the listener to receive the id’s events. Because both the playerinput, id’s AND the listeners are all created at runtime it’s a pain to share the same id object all the way down the line, but not impossible.
On another note I did not realize the input mapper had trouble with multiple joysticks.


#4

Then I don’t understand.

As far as InputMapper is concerned, new FunctionId(“foo”) is the same as any other new FunctionId(“foo”).

It’s user code that tends to do: func == MY_FUNCTION that will fail in this case.

The real question is why aren’t constants ok for you? There can only be so many players, only so many functions… why worry about passing them around when they could just be constants in a file somewhere?


#5

The idea was that there wouldn’t be a limit on the number of players. I’m sure there’s a technical or practical limit, but I also thought it would be fun to push that.


#6

Hmm… I wonder when the input library stops giving you access to game controllers over a certain count.

Anyway, there is nothing wrong with creating as many FunctionId(“foo”) as you want… as long as your handlers recognize that they need to use .equals() instead of ==.

== only works if you use constants.


#7

It throws a “this I’d already exists” exception when the constructor is xalled


#8

Oh… hahah. I forgot about that. Trying to protect users from themselves. I’m loathe to remove that just because the common use case would be to use constants… and then a duplicate ID is because of a typo.

You could get around this (and still be able to use == in your handlers) if you create a static registry/factory for your FunctionIds.

Off the top of my head:

public class FunctionIds {
    private static Map<String, FunctionId> registry = new HashMap<>();

    public static FunctionId id( String group, String id, String name ) {
        String key = group + id;
        FunctionId result = registry.get(key);
        if( result == null ) {
            result = new FunctionId(group, id, name);
            registry.put(key, result);
        }
        return result;
    }

    public static FunctionId id( String group, String id ) {
        return id(group, id, null);
    }

    public static FunctionId id( String id ) {
        return id(FunctionId.DEFAULT_GROUP, id, null);
    }
}

Then wherever you need a new id:
id = FunctionIds.id(“player 1 thrust”);
…or…
id = FunctionIds.id(“someGroup”, “player 1 thrust”);


#9

Yeah, that’s similar to the solution I’m gonna pursue. I was mostly curious as to why the exception exists


#10

For a somewhat contrived concrete example:

public class MyUiFunctions {
    public static final FunctionId UP = new FunctionId("UP");
    ....
}

public class MovementFunctions {
    public static final FunctionId UP = new FunctionId("UP");
    ....
}

class SomeUiInputHandler implements StateFunctionListener {
    public void valueChanged( FunctionId func, InputState value, double tpf ) {
        if( func == MyUiFunctions.UP ) {
            move up
        }
    }
}

Some user:

Hey, how come your stupid library won’t handle my input events?!?! I followed the examples exactly and here’s my code (includes only function IDs and handler that are erroring)

…20 page thread exploring problem that is nearly impossible to solve over forum threads.

Edit: I repeat that this did not actually happen but it’s easy to imagine.