[Feat] Persistent admin bypass mode across restarts and login/logout #71

Description

@derrickmehaffy

Scope

Allow the admin bypass toggle to persist across server restarts and player logout/login. Currently, bypass state is stored in-memory only and is lost whenever the server restarts or (by design) never cleared on logout — meaning bypass survives logout but not restart, which is inconsistent.

  1. Persist admin bypass state to player data storage (JSON)
  2. Restore bypass state on player login
  3. Restore bypass state on server restart (when admin next connects)
  4. Maintain current GUI toggle behavior on Admin Dashboard

Implementation Details

Current bypass storage (HyperFactions.java:128-129):

// Admin bypass state (per-player toggle for protection bypass)privatefinalMap<UUID, Boolean> adminBypassEnabled = newConcurrentHashMap<>();

Current toggle (HyperFactions.java:1089-1091):

publicbooleantoggleAdminBypass(@NotNullUUIDplayerUuid) {
returnadminBypassEnabled.compute(playerUuid, (k, v) -> v == null || !v);
}

GUI trigger:AdminDashboardPage.java (lines 119-179) — "Toggle Bypass" button on Admin Dashboard

Needed changes:

  1. Add field to PlayerData.java: private boolean adminBypassEnabled = false;

    • Serialize/deserialize alongside existing fields (power, kills, deaths, etc.)
    • PlayerData already persists to data/players/{uuid}.json via JsonPlayerStorage
  2. Load bypass state on player connect (PlayerConnectionHandler.java):

    • After loadPlayerData(uuid), check playerData.isAdminBypassEnabled()
    • If true AND player has hyperfactions.admin.use permission, restore to in-memory map
    • If player no longer has admin permission, clear the persisted flag
  3. Save bypass state on toggle (HyperFactions.toggleAdminBypass()):

    • After toggling in-memory map, also update PlayerData.adminBypassEnabled and trigger save
    • Can use existing async save pattern: playerStorage.savePlayerData(data)
  4. Include in auto-save cycle: Already covered — PeriodicTaskManager saves all player data periodically, and PlayerData fields are included automatically

Existing persistence pattern to follow (PlayerData.java):

  • Fields like powerLossDisabled (boolean) and claimDecayExempt (boolean) already follow this exact pattern
  • JSON serialization handled by JsonPlayerStorage which reads/writes all PlayerData fields

Protection check unchanged (ProtectionChecker.java:145-155):

  • Still reads from in-memory adminBypassEnabled map — no changes needed
  • The map is populated from persisted data on login, cleared on explicit toggle-off

Risks and Alternatives

  1. Risk: Admin who is demoted (loses hyperfactions.admin.use permission) could have a stale bypass flag persisted — mitigate by checking permission on login before restoring bypass
  2. Risk: If player data fails to load, bypass should default to OFF (fail-safe)
  3. Alternative: Separate bypass-players.json file instead of extending PlayerData — simpler but adds another file to manage
  4. Alternative: Config-based approach where bypass is listed in config.json — would survive restarts but is less elegant than per-player data

References and Media

Follows the existing PlayerData persistence pattern used for powerLossDisabled and claimDecayExempt flags. The auto-save system (PeriodicTaskManager) already handles periodic flushing of player data to disk.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
      Skip to content

      [Feat] Persistent admin bypass mode across restarts and login/logout #71

      Description

      @derrickmehaffy

      Scope

      Allow the admin bypass toggle to persist across server restarts and player logout/login. Currently, bypass state is stored in-memory only and is lost whenever the server restarts or (by design) never cleared on logout — meaning bypass survives logout but not restart, which is inconsistent.

      1. Persist admin bypass state to player data storage (JSON)
      2. Restore bypass state on player login
      3. Restore bypass state on server restart (when admin next connects)
      4. Maintain current GUI toggle behavior on Admin Dashboard

      Implementation Details

      Current bypass storage (HyperFactions.java:128-129):

      // Admin bypass state (per-player toggle for protection bypass)privatefinalMap<UUID, Boolean> adminBypassEnabled = newConcurrentHashMap<>();

      Current toggle (HyperFactions.java:1089-1091):

      publicbooleantoggleAdminBypass(@NotNullUUIDplayerUuid) {
      returnadminBypassEnabled.compute(playerUuid, (k, v) -> v == null || !v);
      }

      GUI trigger:AdminDashboardPage.java (lines 119-179) — "Toggle Bypass" button on Admin Dashboard

      Needed changes:

      1. Add field to PlayerData.java: private boolean adminBypassEnabled = false;

        • Serialize/deserialize alongside existing fields (power, kills, deaths, etc.)
        • PlayerData already persists to data/players/{uuid}.json via JsonPlayerStorage
      2. Load bypass state on player connect (PlayerConnectionHandler.java):

        • After loadPlayerData(uuid), check playerData.isAdminBypassEnabled()
        • If true AND player has hyperfactions.admin.use permission, restore to in-memory map
        • If player no longer has admin permission, clear the persisted flag
      3. Save bypass state on toggle (HyperFactions.toggleAdminBypass()):

        • After toggling in-memory map, also update PlayerData.adminBypassEnabled and trigger save
        • Can use existing async save pattern: playerStorage.savePlayerData(data)
      4. Include in auto-save cycle: Already covered — PeriodicTaskManager saves all player data periodically, and PlayerData fields are included automatically

      Existing persistence pattern to follow (PlayerData.java):

      • Fields like powerLossDisabled (boolean) and claimDecayExempt (boolean) already follow this exact pattern
      • JSON serialization handled by JsonPlayerStorage which reads/writes all PlayerData fields

      Protection check unchanged (ProtectionChecker.java:145-155):

      • Still reads from in-memory adminBypassEnabled map — no changes needed
      • The map is populated from persisted data on login, cleared on explicit toggle-off

      Risks and Alternatives

      1. Risk: Admin who is demoted (loses hyperfactions.admin.use permission) could have a stale bypass flag persisted — mitigate by checking permission on login before restoring bypass
      2. Risk: If player data fails to load, bypass should default to OFF (fail-safe)
      3. Alternative: Separate bypass-players.json file instead of extending PlayerData — simpler but adds another file to manage
      4. Alternative: Config-based approach where bypass is listed in config.json — would survive restarts but is less elegant than per-player data

      References and Media

      Follows the existing PlayerData persistence pattern used for powerLossDisabled and claimDecayExempt flags. The auto-save system (PeriodicTaskManager) already handles periodic flushing of player data to disk.

      Activity

      Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

      Metadata

      Metadata

      Assignees

      No one assigned

        Labels

        enhancementNew feature or request

        Type

        No type

        Projects

        No projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
          Skip to content

          [Feat] Persistent admin bypass mode across restarts and login/logout #71

          Description

          @derrickmehaffy

          Scope

          Allow the admin bypass toggle to persist across server restarts and player logout/login. Currently, bypass state is stored in-memory only and is lost whenever the server restarts or (by design) never cleared on logout — meaning bypass survives logout but not restart, which is inconsistent.

          1. Persist admin bypass state to player data storage (JSON)
          2. Restore bypass state on player login
          3. Restore bypass state on server restart (when admin next connects)
          4. Maintain current GUI toggle behavior on Admin Dashboard

          Implementation Details

          Current bypass storage (HyperFactions.java:128-129):

          // Admin bypass state (per-player toggle for protection bypass)privatefinalMap<UUID, Boolean> adminBypassEnabled = newConcurrentHashMap<>();

          Current toggle (HyperFactions.java:1089-1091):

          publicbooleantoggleAdminBypass(@NotNullUUIDplayerUuid) {
          returnadminBypassEnabled.compute(playerUuid, (k, v) -> v == null || !v);
          }

          GUI trigger:AdminDashboardPage.java (lines 119-179) — "Toggle Bypass" button on Admin Dashboard

          Needed changes:

          1. Add field to PlayerData.java: private boolean adminBypassEnabled = false;

            • Serialize/deserialize alongside existing fields (power, kills, deaths, etc.)
            • PlayerData already persists to data/players/{uuid}.json via JsonPlayerStorage
          2. Load bypass state on player connect (PlayerConnectionHandler.java):

            • After loadPlayerData(uuid), check playerData.isAdminBypassEnabled()
            • If true AND player has hyperfactions.admin.use permission, restore to in-memory map
            • If player no longer has admin permission, clear the persisted flag
          3. Save bypass state on toggle (HyperFactions.toggleAdminBypass()):

            • After toggling in-memory map, also update PlayerData.adminBypassEnabled and trigger save
            • Can use existing async save pattern: playerStorage.savePlayerData(data)
          4. Include in auto-save cycle: Already covered — PeriodicTaskManager saves all player data periodically, and PlayerData fields are included automatically

          Existing persistence pattern to follow (PlayerData.java):

          • Fields like powerLossDisabled (boolean) and claimDecayExempt (boolean) already follow this exact pattern
          • JSON serialization handled by JsonPlayerStorage which reads/writes all PlayerData fields

          Protection check unchanged (ProtectionChecker.java:145-155):

          • Still reads from in-memory adminBypassEnabled map — no changes needed
          • The map is populated from persisted data on login, cleared on explicit toggle-off

          Risks and Alternatives

          1. Risk: Admin who is demoted (loses hyperfactions.admin.use permission) could have a stale bypass flag persisted — mitigate by checking permission on login before restoring bypass
          2. Risk: If player data fails to load, bypass should default to OFF (fail-safe)
          3. Alternative: Separate bypass-players.json file instead of extending PlayerData — simpler but adds another file to manage
          4. Alternative: Config-based approach where bypass is listed in config.json — would survive restarts but is less elegant than per-player data

          References and Media

          Follows the existing PlayerData persistence pattern used for powerLossDisabled and claimDecayExempt flags. The auto-save system (PeriodicTaskManager) already handles periodic flushing of player data to disk.

          Activity

          Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

          Metadata

          Metadata

          Assignees

          No one assigned

            Labels

            enhancementNew feature or request

            Type

            No type

            Projects

            No projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
              Skip to content

              [Feat] Persistent admin bypass mode across restarts and login/logout #71

              Description

              @derrickmehaffy

              Scope

              Allow the admin bypass toggle to persist across server restarts and player logout/login. Currently, bypass state is stored in-memory only and is lost whenever the server restarts or (by design) never cleared on logout — meaning bypass survives logout but not restart, which is inconsistent.

              1. Persist admin bypass state to player data storage (JSON)
              2. Restore bypass state on player login
              3. Restore bypass state on server restart (when admin next connects)
              4. Maintain current GUI toggle behavior on Admin Dashboard

              Implementation Details

              Current bypass storage (HyperFactions.java:128-129):

              // Admin bypass state (per-player toggle for protection bypass)privatefinalMap<UUID, Boolean> adminBypassEnabled = newConcurrentHashMap<>();

              Current toggle (HyperFactions.java:1089-1091):

              publicbooleantoggleAdminBypass(@NotNullUUIDplayerUuid) {
              returnadminBypassEnabled.compute(playerUuid, (k, v) -> v == null || !v);
              }

              GUI trigger:AdminDashboardPage.java (lines 119-179) — "Toggle Bypass" button on Admin Dashboard

              Needed changes:

              1. Add field to PlayerData.java: private boolean adminBypassEnabled = false;

                • Serialize/deserialize alongside existing fields (power, kills, deaths, etc.)
                • PlayerData already persists to data/players/{uuid}.json via JsonPlayerStorage
              2. Load bypass state on player connect (PlayerConnectionHandler.java):

                • After loadPlayerData(uuid), check playerData.isAdminBypassEnabled()
                • If true AND player has hyperfactions.admin.use permission, restore to in-memory map
                • If player no longer has admin permission, clear the persisted flag
              3. Save bypass state on toggle (HyperFactions.toggleAdminBypass()):

                • After toggling in-memory map, also update PlayerData.adminBypassEnabled and trigger save
                • Can use existing async save pattern: playerStorage.savePlayerData(data)
              4. Include in auto-save cycle: Already covered — PeriodicTaskManager saves all player data periodically, and PlayerData fields are included automatically

              Existing persistence pattern to follow (PlayerData.java):

              • Fields like powerLossDisabled (boolean) and claimDecayExempt (boolean) already follow this exact pattern
              • JSON serialization handled by JsonPlayerStorage which reads/writes all PlayerData fields

              Protection check unchanged (ProtectionChecker.java:145-155):

              • Still reads from in-memory adminBypassEnabled map — no changes needed
              • The map is populated from persisted data on login, cleared on explicit toggle-off

              Risks and Alternatives

              1. Risk: Admin who is demoted (loses hyperfactions.admin.use permission) could have a stale bypass flag persisted — mitigate by checking permission on login before restoring bypass
              2. Risk: If player data fails to load, bypass should default to OFF (fail-safe)
              3. Alternative: Separate bypass-players.json file instead of extending PlayerData — simpler but adds another file to manage
              4. Alternative: Config-based approach where bypass is listed in config.json — would survive restarts but is less elegant than per-player data

              References and Media

              Follows the existing PlayerData persistence pattern used for powerLossDisabled and claimDecayExempt flags. The auto-save system (PeriodicTaskManager) already handles periodic flushing of player data to disk.

              Activity

              Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

              Metadata

              Metadata

              Assignees

              No one assigned

                Labels

                enhancementNew feature or request

                Type

                No type

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions

                  , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
                  Skip to content

                  [Feat] Persistent admin bypass mode across restarts and login/logout #71

                  Description

                  @derrickmehaffy

                  Scope

                  Allow the admin bypass toggle to persist across server restarts and player logout/login. Currently, bypass state is stored in-memory only and is lost whenever the server restarts or (by design) never cleared on logout — meaning bypass survives logout but not restart, which is inconsistent.

                  1. Persist admin bypass state to player data storage (JSON)
                  2. Restore bypass state on player login
                  3. Restore bypass state on server restart (when admin next connects)
                  4. Maintain current GUI toggle behavior on Admin Dashboard

                  Implementation Details

                  Current bypass storage (HyperFactions.java:128-129):

                  // Admin bypass state (per-player toggle for protection bypass)privatefinalMap<UUID, Boolean> adminBypassEnabled = newConcurrentHashMap<>();

                  Current toggle (HyperFactions.java:1089-1091):

                  publicbooleantoggleAdminBypass(@NotNullUUIDplayerUuid) {
                  returnadminBypassEnabled.compute(playerUuid, (k, v) -> v == null || !v);
                  }

                  GUI trigger:AdminDashboardPage.java (lines 119-179) — "Toggle Bypass" button on Admin Dashboard

                  Needed changes:

                  1. Add field to PlayerData.java: private boolean adminBypassEnabled = false;

                    • Serialize/deserialize alongside existing fields (power, kills, deaths, etc.)
                    • PlayerData already persists to data/players/{uuid}.json via JsonPlayerStorage
                  2. Load bypass state on player connect (PlayerConnectionHandler.java):

                    • After loadPlayerData(uuid), check playerData.isAdminBypassEnabled()
                    • If true AND player has hyperfactions.admin.use permission, restore to in-memory map
                    • If player no longer has admin permission, clear the persisted flag
                  3. Save bypass state on toggle (HyperFactions.toggleAdminBypass()):

                    • After toggling in-memory map, also update PlayerData.adminBypassEnabled and trigger save
                    • Can use existing async save pattern: playerStorage.savePlayerData(data)
                  4. Include in auto-save cycle: Already covered — PeriodicTaskManager saves all player data periodically, and PlayerData fields are included automatically

                  Existing persistence pattern to follow (PlayerData.java):

                  • Fields like powerLossDisabled (boolean) and claimDecayExempt (boolean) already follow this exact pattern
                  • JSON serialization handled by JsonPlayerStorage which reads/writes all PlayerData fields

                  Protection check unchanged (ProtectionChecker.java:145-155):

                  • Still reads from in-memory adminBypassEnabled map — no changes needed
                  • The map is populated from persisted data on login, cleared on explicit toggle-off

                  Risks and Alternatives

                  1. Risk: Admin who is demoted (loses hyperfactions.admin.use permission) could have a stale bypass flag persisted — mitigate by checking permission on login before restoring bypass
                  2. Risk: If player data fails to load, bypass should default to OFF (fail-safe)
                  3. Alternative: Separate bypass-players.json file instead of extending PlayerData — simpler but adds another file to manage
                  4. Alternative: Config-based approach where bypass is listed in config.json — would survive restarts but is less elegant than per-player data

                  References and Media

                  Follows the existing PlayerData persistence pattern used for powerLossDisabled and claimDecayExempt flags. The auto-save system (PeriodicTaskManager) already handles periodic flushing of player data to disk.

                  Activity

                  Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

                  Metadata

                  Metadata

                  Assignees

                  No one assigned

                    Labels

                    enhancementNew feature or request

                    Type

                    No type

                    Projects

                    No projects

                      Milestone

                      No milestone

                      Relationships

                      None yet

                      Development

                      No branches or pull requests

                      Issue actions

                      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                      Skip to content

                      [Feat] Persistent admin bypass mode across restarts and login/logout #71

                      Description

                      @derrickmehaffy

                      Scope

                      Allow the admin bypass toggle to persist across server restarts and player logout/login. Currently, bypass state is stored in-memory only and is lost whenever the server restarts or (by design) never cleared on logout — meaning bypass survives logout but not restart, which is inconsistent.

                      1. Persist admin bypass state to player data storage (JSON)
                      2. Restore bypass state on player login
                      3. Restore bypass state on server restart (when admin next connects)
                      4. Maintain current GUI toggle behavior on Admin Dashboard

                      Implementation Details

                      Current bypass storage (HyperFactions.java:128-129):

                      // Admin bypass state (per-player toggle for protection bypass)privatefinalMap<UUID, Boolean> adminBypassEnabled = newConcurrentHashMap<>();

                      Current toggle (HyperFactions.java:1089-1091):

                      publicbooleantoggleAdminBypass(@NotNullUUIDplayerUuid) {
                      returnadminBypassEnabled.compute(playerUuid, (k, v) -> v == null || !v);
                      }

                      GUI trigger:AdminDashboardPage.java (lines 119-179) — "Toggle Bypass" button on Admin Dashboard

                      Needed changes:

                      1. Add field to PlayerData.java: private boolean adminBypassEnabled = false;

                        • Serialize/deserialize alongside existing fields (power, kills, deaths, etc.)
                        • PlayerData already persists to data/players/{uuid}.json via JsonPlayerStorage
                      2. Load bypass state on player connect (PlayerConnectionHandler.java):

                        • After loadPlayerData(uuid), check playerData.isAdminBypassEnabled()
                        • If true AND player has hyperfactions.admin.use permission, restore to in-memory map
                        • If player no longer has admin permission, clear the persisted flag
                      3. Save bypass state on toggle (HyperFactions.toggleAdminBypass()):

                        • After toggling in-memory map, also update PlayerData.adminBypassEnabled and trigger save
                        • Can use existing async save pattern: playerStorage.savePlayerData(data)
                      4. Include in auto-save cycle: Already covered — PeriodicTaskManager saves all player data periodically, and PlayerData fields are included automatically

                      Existing persistence pattern to follow (PlayerData.java):

                      • Fields like powerLossDisabled (boolean) and claimDecayExempt (boolean) already follow this exact pattern
                      • JSON serialization handled by JsonPlayerStorage which reads/writes all PlayerData fields

                      Protection check unchanged (ProtectionChecker.java:145-155):

                      • Still reads from in-memory adminBypassEnabled map — no changes needed
                      • The map is populated from persisted data on login, cleared on explicit toggle-off

                      Risks and Alternatives

                      1. Risk: Admin who is demoted (loses hyperfactions.admin.use permission) could have a stale bypass flag persisted — mitigate by checking permission on login before restoring bypass
                      2. Risk: If player data fails to load, bypass should default to OFF (fail-safe)
                      3. Alternative: Separate bypass-players.json file instead of extending PlayerData — simpler but adds another file to manage
                      4. Alternative: Config-based approach where bypass is listed in config.json — would survive restarts but is less elegant than per-player data

                      References and Media

                      Follows the existing PlayerData persistence pattern used for powerLossDisabled and claimDecayExempt flags. The auto-save system (PeriodicTaskManager) already handles periodic flushing of player data to disk.

                      Activity

                      Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

                      Metadata

                      Metadata

                      Assignees

                      No one assigned

                        Labels

                        enhancementNew feature or request

                        Type

                        No type

                        Projects

                        No projects

                          Milestone

                          No milestone

                          Relationships

                          None yet

                          Development

                          No branches or pull requests

                          Issue actions

                          , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                          Skip to content

                          [Feat] Persistent admin bypass mode across restarts and login/logout #71

                          Description

                          @derrickmehaffy

                          Scope

                          Allow the admin bypass toggle to persist across server restarts and player logout/login. Currently, bypass state is stored in-memory only and is lost whenever the server restarts or (by design) never cleared on logout — meaning bypass survives logout but not restart, which is inconsistent.

                          1. Persist admin bypass state to player data storage (JSON)
                          2. Restore bypass state on player login
                          3. Restore bypass state on server restart (when admin next connects)
                          4. Maintain current GUI toggle behavior on Admin Dashboard

                          Implementation Details

                          Current bypass storage (HyperFactions.java:128-129):

                          // Admin bypass state (per-player toggle for protection bypass)privatefinalMap<UUID, Boolean> adminBypassEnabled = newConcurrentHashMap<>();

                          Current toggle (HyperFactions.java:1089-1091):

                          publicbooleantoggleAdminBypass(@NotNullUUIDplayerUuid) {
                          returnadminBypassEnabled.compute(playerUuid, (k, v) -> v == null || !v);
                          }

                          GUI trigger:AdminDashboardPage.java (lines 119-179) — "Toggle Bypass" button on Admin Dashboard

                          Needed changes:

                          1. Add field to PlayerData.java: private boolean adminBypassEnabled = false;

                            • Serialize/deserialize alongside existing fields (power, kills, deaths, etc.)
                            • PlayerData already persists to data/players/{uuid}.json via JsonPlayerStorage
                          2. Load bypass state on player connect (PlayerConnectionHandler.java):

                            • After loadPlayerData(uuid), check playerData.isAdminBypassEnabled()
                            • If true AND player has hyperfactions.admin.use permission, restore to in-memory map
                            • If player no longer has admin permission, clear the persisted flag
                          3. Save bypass state on toggle (HyperFactions.toggleAdminBypass()):

                            • After toggling in-memory map, also update PlayerData.adminBypassEnabled and trigger save
                            • Can use existing async save pattern: playerStorage.savePlayerData(data)
                          4. Include in auto-save cycle: Already covered — PeriodicTaskManager saves all player data periodically, and PlayerData fields are included automatically

                          Existing persistence pattern to follow (PlayerData.java):

                          • Fields like powerLossDisabled (boolean) and claimDecayExempt (boolean) already follow this exact pattern
                          • JSON serialization handled by JsonPlayerStorage which reads/writes all PlayerData fields

                          Protection check unchanged (ProtectionChecker.java:145-155):

                          • Still reads from in-memory adminBypassEnabled map — no changes needed
                          • The map is populated from persisted data on login, cleared on explicit toggle-off

                          Risks and Alternatives

                          1. Risk: Admin who is demoted (loses hyperfactions.admin.use permission) could have a stale bypass flag persisted — mitigate by checking permission on login before restoring bypass
                          2. Risk: If player data fails to load, bypass should default to OFF (fail-safe)
                          3. Alternative: Separate bypass-players.json file instead of extending PlayerData — simpler but adds another file to manage
                          4. Alternative: Config-based approach where bypass is listed in config.json — would survive restarts but is less elegant than per-player data

                          References and Media

                          Follows the existing PlayerData persistence pattern used for powerLossDisabled and claimDecayExempt flags. The auto-save system (PeriodicTaskManager) already handles periodic flushing of player data to disk.

                          Activity

                          Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

                          Metadata

                          Metadata

                          Assignees

                          No one assigned

                            Labels

                            enhancementNew feature or request

                            Type

                            No type

                            Projects

                            No projects

                              Milestone

                              No milestone

                              Relationships

                              None yet

                              Development

                              No branches or pull requests

                              Issue actions

                              , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
                              Skip to content

                              [Feat] Persistent admin bypass mode across restarts and login/logout #71

                              Description

                              @derrickmehaffy

                              Scope

                              Allow the admin bypass toggle to persist across server restarts and player logout/login. Currently, bypass state is stored in-memory only and is lost whenever the server restarts or (by design) never cleared on logout — meaning bypass survives logout but not restart, which is inconsistent.

                              1. Persist admin bypass state to player data storage (JSON)
                              2. Restore bypass state on player login
                              3. Restore bypass state on server restart (when admin next connects)
                              4. Maintain current GUI toggle behavior on Admin Dashboard

                              Implementation Details

                              Current bypass storage (HyperFactions.java:128-129):

                              // Admin bypass state (per-player toggle for protection bypass)privatefinalMap<UUID, Boolean> adminBypassEnabled = newConcurrentHashMap<>();

                              Current toggle (HyperFactions.java:1089-1091):

                              publicbooleantoggleAdminBypass(@NotNullUUIDplayerUuid) {
                              returnadminBypassEnabled.compute(playerUuid, (k, v) -> v == null || !v);
                              }

                              GUI trigger:AdminDashboardPage.java (lines 119-179) — "Toggle Bypass" button on Admin Dashboard

                              Needed changes:

                              1. Add field to PlayerData.java: private boolean adminBypassEnabled = false;

                                • Serialize/deserialize alongside existing fields (power, kills, deaths, etc.)
                                • PlayerData already persists to data/players/{uuid}.json via JsonPlayerStorage
                              2. Load bypass state on player connect (PlayerConnectionHandler.java):

                                • After loadPlayerData(uuid), check playerData.isAdminBypassEnabled()
                                • If true AND player has hyperfactions.admin.use permission, restore to in-memory map
                                • If player no longer has admin permission, clear the persisted flag
                              3. Save bypass state on toggle (HyperFactions.toggleAdminBypass()):

                                • After toggling in-memory map, also update PlayerData.adminBypassEnabled and trigger save
                                • Can use existing async save pattern: playerStorage.savePlayerData(data)
                              4. Include in auto-save cycle: Already covered — PeriodicTaskManager saves all player data periodically, and PlayerData fields are included automatically

                              Existing persistence pattern to follow (PlayerData.java):

                              • Fields like powerLossDisabled (boolean) and claimDecayExempt (boolean) already follow this exact pattern
                              • JSON serialization handled by JsonPlayerStorage which reads/writes all PlayerData fields

                              Protection check unchanged (ProtectionChecker.java:145-155):

                              • Still reads from in-memory adminBypassEnabled map — no changes needed
                              • The map is populated from persisted data on login, cleared on explicit toggle-off

                              Risks and Alternatives

                              1. Risk: Admin who is demoted (loses hyperfactions.admin.use permission) could have a stale bypass flag persisted — mitigate by checking permission on login before restoring bypass
                              2. Risk: If player data fails to load, bypass should default to OFF (fail-safe)
                              3. Alternative: Separate bypass-players.json file instead of extending PlayerData — simpler but adds another file to manage
                              4. Alternative: Config-based approach where bypass is listed in config.json — would survive restarts but is less elegant than per-player data

                              References and Media

                              Follows the existing PlayerData persistence pattern used for powerLossDisabled and claimDecayExempt flags. The auto-save system (PeriodicTaskManager) already handles periodic flushing of player data to disk.

                              Activity

                              Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

                              Metadata

                              Metadata

                              Assignees

                              No one assigned

                                Labels

                                enhancementNew feature or request

                                Type

                                No type

                                Projects

                                No projects

                                  Milestone

                                  No milestone

                                  Relationships

                                  None yet

                                  Development

                                  No branches or pull requests

                                  Issue actions