Uploaded image for project: 'Spigot'
  1. Spigot
  2. SPIGOT-3663

Key parameter to player.hidePlayer/showPlayer

XMLWordPrintable

    • Icon: New Feature New Feature
    • Resolution: Fixed
    • Icon: Minor Minor
    • None
    • None
    • None

      If multiple unrelated plugins use the Player.hidePlayer/showPlayer methods, then there currently isn't a safe way for them to coordinate to avoid stomping over each other's changes.

      To use a specific example: I've made a plugin NonEuclid that among other things, causes anyone who enters a location to become invisible to players in certain other locations and then become visible again when they leave. However, if this is used with a classic invisibility plugin (say an admin switches to invisible mode when moderating, etc), then the admin will suddenly become visible to nearby players if they walk through one of the NonEuclid pathways. (For now, I've resorted to adding a config option that lets people opt out of NonEuclid's invisibility-handling, at cost of some broken illusions.)

      (One might think this is solvable by making a plugin check player.canSee between a pair of players before hiding a player and then restoring that later, but even if both plugins do that, that fails to work if two plugins activate invisibility between a pair of players and later the first plugin to activate invisibility cancels the invisibility while the second plugin still wants invisibility.)

      Some brainstorming to help explain my idea for a solution: This reminds me a lot of a small issue I occasionally run into in web development. Say there's a form with a button in it, and the button should be hidden if either one of two conditions are true. A naive solution is to set button.style.visibility='hidden' when a condition becomes true, and set it to 'visible' when a condition becomes false. Which has the issue that if you go from both conditions true to one of them being false, the button becomes visible when it shouldn't. It's an easy real situation to find yourself in if both of the conditions are added at different times and you don't think about the combination of them. Once identified, a trivial solution is to make two CSS class names, "condition1" and "condition2" which both set the visibility:hidden; rule. Condition one just toggles the condition1 class name on the button, and condition two just toggles the condition2 class name on the button. Following this strategy, neither of the conditions' code has to know about the other, they just have to use two different class names, and the browser handles storing the class names on the button and whether the button should be visible when either of the class names are added or removed.

      So back to spigot: the conflicts between multiple plugins setting invisibility between players would be solvable if player.hidePlayer/showPlayer both had a second optional "key" parameter. (Or "tag" if that's nicer. The example-inspired "ClassName" name would probably be a bad name for it in Java-land.) The key parameter could be of type Object. Then plugins could use any object, such as its own JavaPlugin instance, as a key. Plugins that want to use multiple keys (because they have multiple reasons for hiding players) could use arbitrary objects. The value `null` would be a legal value; the existing one-parameter versions of hidePlayer/showPlayer would be equivalent to passing null as the key parameter.

      The Set<UUID> hiddenPlayers field on CraftPlayer would become Map<UUID, Set<Object>>. The implementation of Player.canSee(Player) would stay about the same, checking that the Map doesn't contain an entry for the other player's UUID. The implementation of Player.hidePlayer(player, key) would create a HashSet if one wasn't already in the hiddenPlayers Map, and then add the key into it. Player.showPlayer(player, key) would check to see if there's a Set for the player's UUID in the Map, it would try to remove key from that Set, and then it would remove the Set from the Map entirely if the Set was now empty.

      Optionally, there could also be a new method like `Set<Object> Player.getHiddenPlayerKeys(Player)` for viewing the set. This would only be intended for diagnostic purposes. The returned Set could be wrapped with Collections.unmodifiableSet() to prevent plugins from poking it directly instead of using hidePlayer/showPlayer.

      If the design sounds okay, I'm willing to give making a pull request for it a shot!

            Unassigned Unassigned
            macil Chris Cowan
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: