[Bug]: Water disappears when placed in own faction claim #95

Description

@derrickmehaffy

Plugin Version

0.11.1

Operating System

Linux (Debian/Ubuntu)

Bug Description

Water disappears immediately after being placed in a player's own faction claim. Reported by Discord user bonito: "Cant place water on own claim — Water just disappear when placed in claim."

The player is a member of the faction that owns the claim, so they should have full BUILD permission. The water block appears briefly then vanishes.

Code Analysis

There are two separate protection paths for fluid in claimed territory:

1. Placement path (HyperFactionsPlaceFluidInteraction.interactWithBlock())

  • Checks canInteract(playerUuid, world, x, z, InteractionType.BUILD)
  • For faction members in their own claim, this returns ALLOWED_OWN_CLAIM — placement is permitted
  • This path appears to work correctly (the water briefly appears)

2. Spread path (HyperProtect-Mixin FlameTickInterceptor.onSpread())

  • Intercepts FluidTicker.spread() via mixin redirect
  • Calls queryFluidVerdict()FluidSpreadHook.evaluateFluidSpread() (slot 25) → ProtectionChecker.shouldBlockFluidSpread()
  • shouldBlockFluidSpread() (line 1237-1239) blindly delegates to shouldBlockFireSpread()
  • For faction claims, shouldBlockFireSpread() (lines 1218-1222) returns !ConfigManager.get().isFireSpreadAllowed()
  • If fireSpreadAllowed is false in config, ALL fluid spread in claims is blocked — including water placed by the claim owner

Root cause:shouldBlockFluidSpread() reuses shouldBlockFireSpread() logic, which has no concept of WHO placed the fluid. When fireSpreadAllowed: false is set in factions.json, the mixin removes ALL spreading fluid in claims indiscriminately — even water the owner just placed. The fluid placement succeeds (source block appears), but the mixin immediately prevents it from spreading, causing the water to appear to "disappear."

Key files:

  • ProtectionChecker.java:1237-1239shouldBlockFluidSpread() delegates to shouldBlockFireSpread()
  • ProtectionChecker.java:1218-1222 — claim-level fire spread check uses global config toggle
  • FlameTickInterceptor.java:139-143 — mixin removes fluid when verdict is DENY
  • HyperProtectIntegration.java:1172-1187FluidSpreadHook at slot 25
  • FactionsConfig.java:102fireSpreadAllowed defaults to true

Steps to Reproduce

  1. Create a faction and claim territory
  2. Set fireSpreadAllowed: false in config/factions.json (or verify current config)
  3. Place a water bucket in your own faction claim
  4. Water source block appears briefly, then disappears as spread is blocked

Expected Behavior

Water placed by a faction member in their own claim should persist and spread normally. The fireSpreadAllowed config should only affect fire spread (and possibly fluid from OUTSIDE the claim spreading IN), not fluid placed by authorized members within their own territory.

Logs

No response

Code Snippets

// ProtectionChecker.java:1237-1239 — the problematic delegationpublicbooleanshouldBlockFluidSpread(@NotNullWorldworld, intx, inty, intz) {
returnshouldBlockFireSpread(world, x, y, z);
}
// ProtectionChecker.java:1218-1222 — claim-level check (no player context)FactionclaimOwner = chunkManager.getFactionAt(world, chunkX, chunkZ);
if (claimOwner != null) {
return !ConfigManager.get().isFireSpreadAllowed();
}

Media

No response

Additional information

Reported by: Discord user "bonito"

Possible fix approaches:

  1. Separate fluid spread from fire spread — give shouldBlockFluidSpread() its own logic that always allows fluid spread in claims (fire and fluid are fundamentally different concerns)
  2. Add a dedicated fluidSpreadAllowed config option — separate from fireSpreadAllowed, defaulting to true
  3. Track player-placed fluid sources — allow spread from player-placed source blocks while still blocking natural/external fluid spread (more complex, may not be necessary)

Option 1 or 2 is the simplest fix. The core issue is that fluid spread should not be governed by the fire spread config toggle.

Confirmation Checklist

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

    No labels
    No labels

    Type

    No type

    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
     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

    [Bug]: Water disappears when placed in own faction claim #95

    Description

    @derrickmehaffy

    Plugin Version

    0.11.1

    Operating System

    Linux (Debian/Ubuntu)

    Bug Description

    Water disappears immediately after being placed in a player's own faction claim. Reported by Discord user bonito: "Cant place water on own claim — Water just disappear when placed in claim."

    The player is a member of the faction that owns the claim, so they should have full BUILD permission. The water block appears briefly then vanishes.

    Code Analysis

    There are two separate protection paths for fluid in claimed territory:

    1. Placement path (HyperFactionsPlaceFluidInteraction.interactWithBlock())

    • Checks canInteract(playerUuid, world, x, z, InteractionType.BUILD)
    • For faction members in their own claim, this returns ALLOWED_OWN_CLAIM — placement is permitted
    • This path appears to work correctly (the water briefly appears)

    2. Spread path (HyperProtect-Mixin FlameTickInterceptor.onSpread())

    • Intercepts FluidTicker.spread() via mixin redirect
    • Calls queryFluidVerdict()FluidSpreadHook.evaluateFluidSpread() (slot 25) → ProtectionChecker.shouldBlockFluidSpread()
    • shouldBlockFluidSpread() (line 1237-1239) blindly delegates to shouldBlockFireSpread()
    • For faction claims, shouldBlockFireSpread() (lines 1218-1222) returns !ConfigManager.get().isFireSpreadAllowed()
    • If fireSpreadAllowed is false in config, ALL fluid spread in claims is blocked — including water placed by the claim owner

    Root cause:shouldBlockFluidSpread() reuses shouldBlockFireSpread() logic, which has no concept of WHO placed the fluid. When fireSpreadAllowed: false is set in factions.json, the mixin removes ALL spreading fluid in claims indiscriminately — even water the owner just placed. The fluid placement succeeds (source block appears), but the mixin immediately prevents it from spreading, causing the water to appear to "disappear."

    Key files:

    • ProtectionChecker.java:1237-1239shouldBlockFluidSpread() delegates to shouldBlockFireSpread()
    • ProtectionChecker.java:1218-1222 — claim-level fire spread check uses global config toggle
    • FlameTickInterceptor.java:139-143 — mixin removes fluid when verdict is DENY
    • HyperProtectIntegration.java:1172-1187FluidSpreadHook at slot 25
    • FactionsConfig.java:102fireSpreadAllowed defaults to true

    Steps to Reproduce

    1. Create a faction and claim territory
    2. Set fireSpreadAllowed: false in config/factions.json (or verify current config)
    3. Place a water bucket in your own faction claim
    4. Water source block appears briefly, then disappears as spread is blocked

    Expected Behavior

    Water placed by a faction member in their own claim should persist and spread normally. The fireSpreadAllowed config should only affect fire spread (and possibly fluid from OUTSIDE the claim spreading IN), not fluid placed by authorized members within their own territory.

    Logs

    No response

    Code Snippets

    // ProtectionChecker.java:1237-1239 — the problematic delegationpublicbooleanshouldBlockFluidSpread(@NotNullWorldworld, intx, inty, intz) {
    returnshouldBlockFireSpread(world, x, y, z);
    }
    // ProtectionChecker.java:1218-1222 — claim-level check (no player context)FactionclaimOwner = chunkManager.getFactionAt(world, chunkX, chunkZ);
    if (claimOwner != null) {
    return !ConfigManager.get().isFireSpreadAllowed();
    }

    Media

    No response

    Additional information

    Reported by: Discord user "bonito"

    Possible fix approaches:

    1. Separate fluid spread from fire spread — give shouldBlockFluidSpread() its own logic that always allows fluid spread in claims (fire and fluid are fundamentally different concerns)
    2. Add a dedicated fluidSpreadAllowed config option — separate from fireSpreadAllowed, defaulting to true
    3. Track player-placed fluid sources — allow spread from player-placed source blocks while still blocking natural/external fluid spread (more complex, may not be necessary)

    Option 1 or 2 is the simplest fix. The core issue is that fluid spread should not be governed by the fire spread config toggle.

    Confirmation Checklist

    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

      No labels
      No labels

      Type

      No type

      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

      [Bug]: Water disappears when placed in own faction claim #95

      Description

      @derrickmehaffy

      Plugin Version

      0.11.1

      Operating System

      Linux (Debian/Ubuntu)

      Bug Description

      Water disappears immediately after being placed in a player's own faction claim. Reported by Discord user bonito: "Cant place water on own claim — Water just disappear when placed in claim."

      The player is a member of the faction that owns the claim, so they should have full BUILD permission. The water block appears briefly then vanishes.

      Code Analysis

      There are two separate protection paths for fluid in claimed territory:

      1. Placement path (HyperFactionsPlaceFluidInteraction.interactWithBlock())

      • Checks canInteract(playerUuid, world, x, z, InteractionType.BUILD)
      • For faction members in their own claim, this returns ALLOWED_OWN_CLAIM — placement is permitted
      • This path appears to work correctly (the water briefly appears)

      2. Spread path (HyperProtect-Mixin FlameTickInterceptor.onSpread())

      • Intercepts FluidTicker.spread() via mixin redirect
      • Calls queryFluidVerdict()FluidSpreadHook.evaluateFluidSpread() (slot 25) → ProtectionChecker.shouldBlockFluidSpread()
      • shouldBlockFluidSpread() (line 1237-1239) blindly delegates to shouldBlockFireSpread()
      • For faction claims, shouldBlockFireSpread() (lines 1218-1222) returns !ConfigManager.get().isFireSpreadAllowed()
      • If fireSpreadAllowed is false in config, ALL fluid spread in claims is blocked — including water placed by the claim owner

      Root cause:shouldBlockFluidSpread() reuses shouldBlockFireSpread() logic, which has no concept of WHO placed the fluid. When fireSpreadAllowed: false is set in factions.json, the mixin removes ALL spreading fluid in claims indiscriminately — even water the owner just placed. The fluid placement succeeds (source block appears), but the mixin immediately prevents it from spreading, causing the water to appear to "disappear."

      Key files:

      • ProtectionChecker.java:1237-1239shouldBlockFluidSpread() delegates to shouldBlockFireSpread()
      • ProtectionChecker.java:1218-1222 — claim-level fire spread check uses global config toggle
      • FlameTickInterceptor.java:139-143 — mixin removes fluid when verdict is DENY
      • HyperProtectIntegration.java:1172-1187FluidSpreadHook at slot 25
      • FactionsConfig.java:102fireSpreadAllowed defaults to true

      Steps to Reproduce

      1. Create a faction and claim territory
      2. Set fireSpreadAllowed: false in config/factions.json (or verify current config)
      3. Place a water bucket in your own faction claim
      4. Water source block appears briefly, then disappears as spread is blocked

      Expected Behavior

      Water placed by a faction member in their own claim should persist and spread normally. The fireSpreadAllowed config should only affect fire spread (and possibly fluid from OUTSIDE the claim spreading IN), not fluid placed by authorized members within their own territory.

      Logs

      No response

      Code Snippets

      // ProtectionChecker.java:1237-1239 — the problematic delegationpublicbooleanshouldBlockFluidSpread(@NotNullWorldworld, intx, inty, intz) {
      returnshouldBlockFireSpread(world, x, y, z);
      }
      // ProtectionChecker.java:1218-1222 — claim-level check (no player context)FactionclaimOwner = chunkManager.getFactionAt(world, chunkX, chunkZ);
      if (claimOwner != null) {
      return !ConfigManager.get().isFireSpreadAllowed();
      }

      Media

      No response

      Additional information

      Reported by: Discord user "bonito"

      Possible fix approaches:

      1. Separate fluid spread from fire spread — give shouldBlockFluidSpread() its own logic that always allows fluid spread in claims (fire and fluid are fundamentally different concerns)
      2. Add a dedicated fluidSpreadAllowed config option — separate from fireSpreadAllowed, defaulting to true
      3. Track player-placed fluid sources — allow spread from player-placed source blocks while still blocking natural/external fluid spread (more complex, may not be necessary)

      Option 1 or 2 is the simplest fix. The core issue is that fluid spread should not be governed by the fire spread config toggle.

      Confirmation Checklist

      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

        No labels
        No labels

        Type

        No type

        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 > 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

        [Bug]: Water disappears when placed in own faction claim #95

        Description

        @derrickmehaffy

        Plugin Version

        0.11.1

        Operating System

        Linux (Debian/Ubuntu)

        Bug Description

        Water disappears immediately after being placed in a player's own faction claim. Reported by Discord user bonito: "Cant place water on own claim — Water just disappear when placed in claim."

        The player is a member of the faction that owns the claim, so they should have full BUILD permission. The water block appears briefly then vanishes.

        Code Analysis

        There are two separate protection paths for fluid in claimed territory:

        1. Placement path (HyperFactionsPlaceFluidInteraction.interactWithBlock())

        • Checks canInteract(playerUuid, world, x, z, InteractionType.BUILD)
        • For faction members in their own claim, this returns ALLOWED_OWN_CLAIM — placement is permitted
        • This path appears to work correctly (the water briefly appears)

        2. Spread path (HyperProtect-Mixin FlameTickInterceptor.onSpread())

        • Intercepts FluidTicker.spread() via mixin redirect
        • Calls queryFluidVerdict()FluidSpreadHook.evaluateFluidSpread() (slot 25) → ProtectionChecker.shouldBlockFluidSpread()
        • shouldBlockFluidSpread() (line 1237-1239) blindly delegates to shouldBlockFireSpread()
        • For faction claims, shouldBlockFireSpread() (lines 1218-1222) returns !ConfigManager.get().isFireSpreadAllowed()
        • If fireSpreadAllowed is false in config, ALL fluid spread in claims is blocked — including water placed by the claim owner

        Root cause:shouldBlockFluidSpread() reuses shouldBlockFireSpread() logic, which has no concept of WHO placed the fluid. When fireSpreadAllowed: false is set in factions.json, the mixin removes ALL spreading fluid in claims indiscriminately — even water the owner just placed. The fluid placement succeeds (source block appears), but the mixin immediately prevents it from spreading, causing the water to appear to "disappear."

        Key files:

        • ProtectionChecker.java:1237-1239shouldBlockFluidSpread() delegates to shouldBlockFireSpread()
        • ProtectionChecker.java:1218-1222 — claim-level fire spread check uses global config toggle
        • FlameTickInterceptor.java:139-143 — mixin removes fluid when verdict is DENY
        • HyperProtectIntegration.java:1172-1187FluidSpreadHook at slot 25
        • FactionsConfig.java:102fireSpreadAllowed defaults to true

        Steps to Reproduce

        1. Create a faction and claim territory
        2. Set fireSpreadAllowed: false in config/factions.json (or verify current config)
        3. Place a water bucket in your own faction claim
        4. Water source block appears briefly, then disappears as spread is blocked

        Expected Behavior

        Water placed by a faction member in their own claim should persist and spread normally. The fireSpreadAllowed config should only affect fire spread (and possibly fluid from OUTSIDE the claim spreading IN), not fluid placed by authorized members within their own territory.

        Logs

        No response

        Code Snippets

        // ProtectionChecker.java:1237-1239 — the problematic delegationpublicbooleanshouldBlockFluidSpread(@NotNullWorldworld, intx, inty, intz) {
        returnshouldBlockFireSpread(world, x, y, z);
        }
        // ProtectionChecker.java:1218-1222 — claim-level check (no player context)FactionclaimOwner = chunkManager.getFactionAt(world, chunkX, chunkZ);
        if (claimOwner != null) {
        return !ConfigManager.get().isFireSpreadAllowed();
        }

        Media

        No response

        Additional information

        Reported by: Discord user "bonito"

        Possible fix approaches:

        1. Separate fluid spread from fire spread — give shouldBlockFluidSpread() its own logic that always allows fluid spread in claims (fire and fluid are fundamentally different concerns)
        2. Add a dedicated fluidSpreadAllowed config option — separate from fireSpreadAllowed, defaulting to true
        3. Track player-placed fluid sources — allow spread from player-placed source blocks while still blocking natural/external fluid spread (more complex, may not be necessary)

        Option 1 or 2 is the simplest fix. The core issue is that fluid spread should not be governed by the fire spread config toggle.

        Confirmation Checklist

        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

          No labels
          No labels

          Type

          No type

          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

          [Bug]: Water disappears when placed in own faction claim #95

          Description

          @derrickmehaffy

          Plugin Version

          0.11.1

          Operating System

          Linux (Debian/Ubuntu)

          Bug Description

          Water disappears immediately after being placed in a player's own faction claim. Reported by Discord user bonito: "Cant place water on own claim — Water just disappear when placed in claim."

          The player is a member of the faction that owns the claim, so they should have full BUILD permission. The water block appears briefly then vanishes.

          Code Analysis

          There are two separate protection paths for fluid in claimed territory:

          1. Placement path (HyperFactionsPlaceFluidInteraction.interactWithBlock())

          • Checks canInteract(playerUuid, world, x, z, InteractionType.BUILD)
          • For faction members in their own claim, this returns ALLOWED_OWN_CLAIM — placement is permitted
          • This path appears to work correctly (the water briefly appears)

          2. Spread path (HyperProtect-Mixin FlameTickInterceptor.onSpread())

          • Intercepts FluidTicker.spread() via mixin redirect
          • Calls queryFluidVerdict()FluidSpreadHook.evaluateFluidSpread() (slot 25) → ProtectionChecker.shouldBlockFluidSpread()
          • shouldBlockFluidSpread() (line 1237-1239) blindly delegates to shouldBlockFireSpread()
          • For faction claims, shouldBlockFireSpread() (lines 1218-1222) returns !ConfigManager.get().isFireSpreadAllowed()
          • If fireSpreadAllowed is false in config, ALL fluid spread in claims is blocked — including water placed by the claim owner

          Root cause:shouldBlockFluidSpread() reuses shouldBlockFireSpread() logic, which has no concept of WHO placed the fluid. When fireSpreadAllowed: false is set in factions.json, the mixin removes ALL spreading fluid in claims indiscriminately — even water the owner just placed. The fluid placement succeeds (source block appears), but the mixin immediately prevents it from spreading, causing the water to appear to "disappear."

          Key files:

          • ProtectionChecker.java:1237-1239shouldBlockFluidSpread() delegates to shouldBlockFireSpread()
          • ProtectionChecker.java:1218-1222 — claim-level fire spread check uses global config toggle
          • FlameTickInterceptor.java:139-143 — mixin removes fluid when verdict is DENY
          • HyperProtectIntegration.java:1172-1187FluidSpreadHook at slot 25
          • FactionsConfig.java:102fireSpreadAllowed defaults to true

          Steps to Reproduce

          1. Create a faction and claim territory
          2. Set fireSpreadAllowed: false in config/factions.json (or verify current config)
          3. Place a water bucket in your own faction claim
          4. Water source block appears briefly, then disappears as spread is blocked

          Expected Behavior

          Water placed by a faction member in their own claim should persist and spread normally. The fireSpreadAllowed config should only affect fire spread (and possibly fluid from OUTSIDE the claim spreading IN), not fluid placed by authorized members within their own territory.

          Logs

          No response

          Code Snippets

          // ProtectionChecker.java:1237-1239 — the problematic delegationpublicbooleanshouldBlockFluidSpread(@NotNullWorldworld, intx, inty, intz) {
          returnshouldBlockFireSpread(world, x, y, z);
          }
          // ProtectionChecker.java:1218-1222 — claim-level check (no player context)FactionclaimOwner = chunkManager.getFactionAt(world, chunkX, chunkZ);
          if (claimOwner != null) {
          return !ConfigManager.get().isFireSpreadAllowed();
          }

          Media

          No response

          Additional information

          Reported by: Discord user "bonito"

          Possible fix approaches:

          1. Separate fluid spread from fire spread — give shouldBlockFluidSpread() its own logic that always allows fluid spread in claims (fire and fluid are fundamentally different concerns)
          2. Add a dedicated fluidSpreadAllowed config option — separate from fireSpreadAllowed, defaulting to true
          3. Track player-placed fluid sources — allow spread from player-placed source blocks while still blocking natural/external fluid spread (more complex, may not be necessary)

          Option 1 or 2 is the simplest fix. The core issue is that fluid spread should not be governed by the fire spread config toggle.

          Confirmation Checklist

          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

            No labels
            No labels

            Type

            No type

            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

            [Bug]: Water disappears when placed in own faction claim #95

            Description

            @derrickmehaffy

            Plugin Version

            0.11.1

            Operating System

            Linux (Debian/Ubuntu)

            Bug Description

            Water disappears immediately after being placed in a player's own faction claim. Reported by Discord user bonito: "Cant place water on own claim — Water just disappear when placed in claim."

            The player is a member of the faction that owns the claim, so they should have full BUILD permission. The water block appears briefly then vanishes.

            Code Analysis

            There are two separate protection paths for fluid in claimed territory:

            1. Placement path (HyperFactionsPlaceFluidInteraction.interactWithBlock())

            • Checks canInteract(playerUuid, world, x, z, InteractionType.BUILD)
            • For faction members in their own claim, this returns ALLOWED_OWN_CLAIM — placement is permitted
            • This path appears to work correctly (the water briefly appears)

            2. Spread path (HyperProtect-Mixin FlameTickInterceptor.onSpread())

            • Intercepts FluidTicker.spread() via mixin redirect
            • Calls queryFluidVerdict()FluidSpreadHook.evaluateFluidSpread() (slot 25) → ProtectionChecker.shouldBlockFluidSpread()
            • shouldBlockFluidSpread() (line 1237-1239) blindly delegates to shouldBlockFireSpread()
            • For faction claims, shouldBlockFireSpread() (lines 1218-1222) returns !ConfigManager.get().isFireSpreadAllowed()
            • If fireSpreadAllowed is false in config, ALL fluid spread in claims is blocked — including water placed by the claim owner

            Root cause:shouldBlockFluidSpread() reuses shouldBlockFireSpread() logic, which has no concept of WHO placed the fluid. When fireSpreadAllowed: false is set in factions.json, the mixin removes ALL spreading fluid in claims indiscriminately — even water the owner just placed. The fluid placement succeeds (source block appears), but the mixin immediately prevents it from spreading, causing the water to appear to "disappear."

            Key files:

            • ProtectionChecker.java:1237-1239shouldBlockFluidSpread() delegates to shouldBlockFireSpread()
            • ProtectionChecker.java:1218-1222 — claim-level fire spread check uses global config toggle
            • FlameTickInterceptor.java:139-143 — mixin removes fluid when verdict is DENY
            • HyperProtectIntegration.java:1172-1187FluidSpreadHook at slot 25
            • FactionsConfig.java:102fireSpreadAllowed defaults to true

            Steps to Reproduce

            1. Create a faction and claim territory
            2. Set fireSpreadAllowed: false in config/factions.json (or verify current config)
            3. Place a water bucket in your own faction claim
            4. Water source block appears briefly, then disappears as spread is blocked

            Expected Behavior

            Water placed by a faction member in their own claim should persist and spread normally. The fireSpreadAllowed config should only affect fire spread (and possibly fluid from OUTSIDE the claim spreading IN), not fluid placed by authorized members within their own territory.

            Logs

            No response

            Code Snippets

            // ProtectionChecker.java:1237-1239 — the problematic delegationpublicbooleanshouldBlockFluidSpread(@NotNullWorldworld, intx, inty, intz) {
            returnshouldBlockFireSpread(world, x, y, z);
            }
            // ProtectionChecker.java:1218-1222 — claim-level check (no player context)FactionclaimOwner = chunkManager.getFactionAt(world, chunkX, chunkZ);
            if (claimOwner != null) {
            return !ConfigManager.get().isFireSpreadAllowed();
            }

            Media

            No response

            Additional information

            Reported by: Discord user "bonito"

            Possible fix approaches:

            1. Separate fluid spread from fire spread — give shouldBlockFluidSpread() its own logic that always allows fluid spread in claims (fire and fluid are fundamentally different concerns)
            2. Add a dedicated fluidSpreadAllowed config option — separate from fireSpreadAllowed, defaulting to true
            3. Track player-placed fluid sources — allow spread from player-placed source blocks while still blocking natural/external fluid spread (more complex, may not be necessary)

            Option 1 or 2 is the simplest fix. The core issue is that fluid spread should not be governed by the fire spread config toggle.

            Confirmation Checklist

            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

              No labels
              No labels

              Type

              No type

              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

              [Bug]: Water disappears when placed in own faction claim #95

              Description

              @derrickmehaffy

              Plugin Version

              0.11.1

              Operating System

              Linux (Debian/Ubuntu)

              Bug Description

              Water disappears immediately after being placed in a player's own faction claim. Reported by Discord user bonito: "Cant place water on own claim — Water just disappear when placed in claim."

              The player is a member of the faction that owns the claim, so they should have full BUILD permission. The water block appears briefly then vanishes.

              Code Analysis

              There are two separate protection paths for fluid in claimed territory:

              1. Placement path (HyperFactionsPlaceFluidInteraction.interactWithBlock())

              • Checks canInteract(playerUuid, world, x, z, InteractionType.BUILD)
              • For faction members in their own claim, this returns ALLOWED_OWN_CLAIM — placement is permitted
              • This path appears to work correctly (the water briefly appears)

              2. Spread path (HyperProtect-Mixin FlameTickInterceptor.onSpread())

              • Intercepts FluidTicker.spread() via mixin redirect
              • Calls queryFluidVerdict()FluidSpreadHook.evaluateFluidSpread() (slot 25) → ProtectionChecker.shouldBlockFluidSpread()
              • shouldBlockFluidSpread() (line 1237-1239) blindly delegates to shouldBlockFireSpread()
              • For faction claims, shouldBlockFireSpread() (lines 1218-1222) returns !ConfigManager.get().isFireSpreadAllowed()
              • If fireSpreadAllowed is false in config, ALL fluid spread in claims is blocked — including water placed by the claim owner

              Root cause:shouldBlockFluidSpread() reuses shouldBlockFireSpread() logic, which has no concept of WHO placed the fluid. When fireSpreadAllowed: false is set in factions.json, the mixin removes ALL spreading fluid in claims indiscriminately — even water the owner just placed. The fluid placement succeeds (source block appears), but the mixin immediately prevents it from spreading, causing the water to appear to "disappear."

              Key files:

              • ProtectionChecker.java:1237-1239shouldBlockFluidSpread() delegates to shouldBlockFireSpread()
              • ProtectionChecker.java:1218-1222 — claim-level fire spread check uses global config toggle
              • FlameTickInterceptor.java:139-143 — mixin removes fluid when verdict is DENY
              • HyperProtectIntegration.java:1172-1187FluidSpreadHook at slot 25
              • FactionsConfig.java:102fireSpreadAllowed defaults to true

              Steps to Reproduce

              1. Create a faction and claim territory
              2. Set fireSpreadAllowed: false in config/factions.json (or verify current config)
              3. Place a water bucket in your own faction claim
              4. Water source block appears briefly, then disappears as spread is blocked

              Expected Behavior

              Water placed by a faction member in their own claim should persist and spread normally. The fireSpreadAllowed config should only affect fire spread (and possibly fluid from OUTSIDE the claim spreading IN), not fluid placed by authorized members within their own territory.

              Logs

              No response

              Code Snippets

              // ProtectionChecker.java:1237-1239 — the problematic delegationpublicbooleanshouldBlockFluidSpread(@NotNullWorldworld, intx, inty, intz) {
              returnshouldBlockFireSpread(world, x, y, z);
              }
              // ProtectionChecker.java:1218-1222 — claim-level check (no player context)FactionclaimOwner = chunkManager.getFactionAt(world, chunkX, chunkZ);
              if (claimOwner != null) {
              return !ConfigManager.get().isFireSpreadAllowed();
              }

              Media

              No response

              Additional information

              Reported by: Discord user "bonito"

              Possible fix approaches:

              1. Separate fluid spread from fire spread — give shouldBlockFluidSpread() its own logic that always allows fluid spread in claims (fire and fluid are fundamentally different concerns)
              2. Add a dedicated fluidSpreadAllowed config option — separate from fireSpreadAllowed, defaulting to true
              3. Track player-placed fluid sources — allow spread from player-placed source blocks while still blocking natural/external fluid spread (more complex, may not be necessary)

              Option 1 or 2 is the simplest fix. The core issue is that fluid spread should not be governed by the fire spread config toggle.

              Confirmation Checklist

              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

                No labels
                No labels

                Type

                No type

                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

                [Bug]: Water disappears when placed in own faction claim #95

                Description

                @derrickmehaffy

                Plugin Version

                0.11.1

                Operating System

                Linux (Debian/Ubuntu)

                Bug Description

                Water disappears immediately after being placed in a player's own faction claim. Reported by Discord user bonito: "Cant place water on own claim — Water just disappear when placed in claim."

                The player is a member of the faction that owns the claim, so they should have full BUILD permission. The water block appears briefly then vanishes.

                Code Analysis

                There are two separate protection paths for fluid in claimed territory:

                1. Placement path (HyperFactionsPlaceFluidInteraction.interactWithBlock())

                • Checks canInteract(playerUuid, world, x, z, InteractionType.BUILD)
                • For faction members in their own claim, this returns ALLOWED_OWN_CLAIM — placement is permitted
                • This path appears to work correctly (the water briefly appears)

                2. Spread path (HyperProtect-Mixin FlameTickInterceptor.onSpread())

                • Intercepts FluidTicker.spread() via mixin redirect
                • Calls queryFluidVerdict()FluidSpreadHook.evaluateFluidSpread() (slot 25) → ProtectionChecker.shouldBlockFluidSpread()
                • shouldBlockFluidSpread() (line 1237-1239) blindly delegates to shouldBlockFireSpread()
                • For faction claims, shouldBlockFireSpread() (lines 1218-1222) returns !ConfigManager.get().isFireSpreadAllowed()
                • If fireSpreadAllowed is false in config, ALL fluid spread in claims is blocked — including water placed by the claim owner

                Root cause:shouldBlockFluidSpread() reuses shouldBlockFireSpread() logic, which has no concept of WHO placed the fluid. When fireSpreadAllowed: false is set in factions.json, the mixin removes ALL spreading fluid in claims indiscriminately — even water the owner just placed. The fluid placement succeeds (source block appears), but the mixin immediately prevents it from spreading, causing the water to appear to "disappear."

                Key files:

                • ProtectionChecker.java:1237-1239shouldBlockFluidSpread() delegates to shouldBlockFireSpread()
                • ProtectionChecker.java:1218-1222 — claim-level fire spread check uses global config toggle
                • FlameTickInterceptor.java:139-143 — mixin removes fluid when verdict is DENY
                • HyperProtectIntegration.java:1172-1187FluidSpreadHook at slot 25
                • FactionsConfig.java:102fireSpreadAllowed defaults to true

                Steps to Reproduce

                1. Create a faction and claim territory
                2. Set fireSpreadAllowed: false in config/factions.json (or verify current config)
                3. Place a water bucket in your own faction claim
                4. Water source block appears briefly, then disappears as spread is blocked

                Expected Behavior

                Water placed by a faction member in their own claim should persist and spread normally. The fireSpreadAllowed config should only affect fire spread (and possibly fluid from OUTSIDE the claim spreading IN), not fluid placed by authorized members within their own territory.

                Logs

                No response

                Code Snippets

                // ProtectionChecker.java:1237-1239 — the problematic delegationpublicbooleanshouldBlockFluidSpread(@NotNullWorldworld, intx, inty, intz) {
                returnshouldBlockFireSpread(world, x, y, z);
                }
                // ProtectionChecker.java:1218-1222 — claim-level check (no player context)FactionclaimOwner = chunkManager.getFactionAt(world, chunkX, chunkZ);
                if (claimOwner != null) {
                return !ConfigManager.get().isFireSpreadAllowed();
                }

                Media

                No response

                Additional information

                Reported by: Discord user "bonito"

                Possible fix approaches:

                1. Separate fluid spread from fire spread — give shouldBlockFluidSpread() its own logic that always allows fluid spread in claims (fire and fluid are fundamentally different concerns)
                2. Add a dedicated fluidSpreadAllowed config option — separate from fireSpreadAllowed, defaulting to true
                3. Track player-placed fluid sources — allow spread from player-placed source blocks while still blocking natural/external fluid spread (more complex, may not be necessary)

                Option 1 or 2 is the simplest fix. The core issue is that fluid spread should not be governed by the fire spread config toggle.

                Confirmation Checklist

                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

                  No labels
                  No labels

                  Type

                  No type

                  Projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions