{
  "name": "BannedItems",
  "author": "limon",
  "supportedGames": [
    "all"
  ],
  "takaroVersion": "v0.0.24",
  "versions": [
    {
      "tag": "latest",
      "description": "**Banned Items Module: Tiered Item Restriction System**\n\nManage which items players can possess based on permission tiers, with configurable warnings and punishments for violations.\n\n**Key Features:**\n\n![Tiered Items Configuration](https://raw.githubusercontent.com/gettakaro/community-modules-viewer/refs/heads/main/images/banneditems_config.png)\n\n* **Permission-Based Item Control:** Restrict items based on player permission tiers. Players need the `ALLOW_ITEMS_TIER` permission with a count value equal to or greater than an item's required tier to possess it.\n* **Item Tier System:** Assign different restriction levels to items - higher tier numbers indicate more restricted items that require higher permission levels.\n* **Global Immunity:** Grant certain roles complete immunity to all item restrictions with the `BANNED_ITEMS_IMMUNITY` permission.\n\n![Permission Role Configuration](https://raw.githubusercontent.com/gettakaro/community-modules-viewer/refs/heads/main/images/banneditems_permissionsconfig.png)\n\n* **Configurable Enforcement:**\n  * Set the number of warnings before punishment\n  * Choose punishment type: warn only, kick, or ban\n  * Configure ban duration and customized messages\n\n![Warning Configuration](https://raw.githubusercontent.com/gettakaro/community-modules-viewer/refs/heads/main/images/banneditems_illegalItem.png)\n\n* **Automated Inventory Scanning:** The module automatically scans player inventories and detects unauthorized items based on permission tiers.\n* **Discord Integration:** Receive detailed notifications in Discord when violations occur, including player information, tier level, and unauthorized items.\n\n![Discord Notification](https://raw.githubusercontent.com/gettakaro/community-modules-viewer/refs/heads/main/images/banneditems_discordMessage.png)\n\n* **In-Game Notifications:** Players receive clear warnings about unauthorized items with information about how many warnings they have before facing punishment.\n* **Server-Wide Announcements:** When players are kicked or banned for violations, an announcement is made to all players.\n\n![Kick Message](https://raw.githubusercontent.com/gettakaro/community-modules-viewer/refs/heads/main/images/banneditems_kick.png)\n\n**How the Permission Tier System Works:**\n\n1. **Assign Tiers to Items:** Configure which items are restricted and what permission tier is required to possess them.\n2. **Set Role Permissions:** Give player roles the `ALLOW_ITEMS_TIER` permission with a count value representing their tier level.\n3. **Automatic Enforcement:** Players can only possess items with a required tier that is equal to or lower than their permission tier.\n\n![Role Permission Count](https://raw.githubusercontent.com/gettakaro/community-modules-viewer/refs/heads/main/images/banneditems_rolecount.png)\n\n**Example Usage:**\n* Set powerful weapons to tier 3, requiring a higher permission level\n* Set basic resources to tier 1, allowing most players to have them\n* Grant VIP players tier 2 access, giving them more item options than regular players\n* Assign tier 99 to completely ban items for everyone except those with immunity\n\n**Perfect For:**\n* Servers with tiered player ranks (VIP, donor, etc.)\n* PvP servers wanting to balance gameplay by restricting higher-tier equipment\n* Roleplaying servers with progression-based item access\n* Any server wanting to prevent certain items from being used/exploited",
      "configSchema": "{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"type\":\"object\",\"properties\":{\"bannedItemsWithPermissions\":{\"x-component\":\"item\",\"type\":\"array\",\"title\":\"Tiered Items\",\"description\":\"List of items that require a specific tier permission to possess. Players need ALLOW_ITEMS_TIER permission with a count equal to or greater than the required tier to possess these items. Players with BANNED_ITEMS_IMMUNITY can possess any items regardless of tier.\",\"uniqueItems\":true,\"items\":{\"type\":\"object\",\"title\":\"Tiered Item\",\"properties\":{\"item\":{\"type\":\"string\",\"title\":\"Item\"},\"tier\":{\"type\":\"number\",\"title\":\"Required Tier\",\"description\":\"The permission tier required to possess this item. Higher numbers indicate more restricted items.\",\"minimum\":1,\"default\":1}},\"required\":[\"item\",\"tier\"]}},\"warningsBeforePunishment\":{\"title\":\"Warnings Before Punishment\",\"type\":\"number\",\"description\":\"Number of warnings a player receives before punishment is applied\",\"default\":1,\"minimum\":1},\"punishmentType\":{\"title\":\"Punishment Type\",\"type\":\"string\",\"enum\":[\"none\",\"kick\",\"ban\"],\"default\":\"kick\",\"description\":\"What happens when a player has unauthorized items too many times\"},\"banDuration\":{\"title\":\"Ban Duration\",\"x-component\":\"duration\",\"type\":\"number\",\"description\":\"How long a player is banned for (if ban is selected)\",\"default\":86400000,\"minimum\":0},\"kickMessage\":{\"title\":\"Kick Message\",\"type\":\"string\",\"description\":\"Message to display when a player is kicked (use {items} to list all unauthorized items)\",\"default\":\"You were kicked for possessing unauthorized items: {items}\"},\"discordChannelId\":{\"title\":\"Discord Channel ID\",\"type\":\"string\",\"description\":\"Discord channel ID where notifications about players with banned items will be sent. Leave empty to disable Discord notifications.\",\"default\":\"\"},\"banMessage\":{\"title\":\"Ban Message\",\"type\":\"string\",\"description\":\"Message to display when a player is banned (use {items} to list all unauthorized items)\",\"default\":\"You were banned for possessing unauthorized items: {items}\"},\"warningMessage\":{\"title\":\"Warning Message\",\"type\":\"string\",\"description\":\"Message to display when warning a player (use {items} to list all unauthorized items)\",\"default\":\"The following items are not allowed with your permission level: {items}. Please dispose of them immediately.\"}},\"required\":[\"bannedItemsWithPermissions\",\"warningsBeforePunishment\",\"punishmentType\"],\"additionalProperties\":false}",
      "uiSchema": "{\"bannedItemsWithPermissions\":{\"items\":{\"item\":{\"ui:widget\":\"item\"}}},\"banDuration\":{\"ui:widget\":\"duration\"}}",
      "commands": [],
      "hooks": [],
      "cronJobs": [
        {
          "name": "bannedItems",
          "temporalValue": "*/2 * * * *",
          "description": "checking for banned items in their inventory",
          "function": "import { takaro, data, checkPermission } from '@takaro/helpers';\n\nasync function main() {\n    const { module: mod, gameServerId } = data;\n    const {\n        bannedItemsWithPermissions,\n        warningsBeforePunishment,\n        punishmentType,\n        banDuration,\n        kickMessage,\n        banMessage,\n        warningMessage,\n        warningExpirationHours = 24, // Default to 24 hours if not specified\n        discordChannelId // New discord channel ID field\n    } = data.module.userConfig;\n\n    // Get all online players\n    const playersResponse = await takaro.playerOnGameserver.playerOnGameServerControllerSearch({\n        filters: {\n            gameServerId: [gameServerId],\n            online: [true]\n        }\n    });\n\n    // No players online, exit early\n    if (!playersResponse.data.data.length) {\n        return;\n    }\n\n    // Get all banned items in one query\n    const itemIds = bannedItemsWithPermissions.map(entry => entry.item);\n\n    // If no banned items configured, exit early\n    if (!itemIds.length) {\n        return;\n    }\n\n    const itemResponse = await takaro.item.itemControllerSearch({\n        filters: {\n            id: itemIds,\n            gameserverId: [gameServerId]\n        }\n    });\n\n    // Create lookup Maps for banned items with their tier requirements\n    const bannedItemsMap = new Map();\n\n    // Process each banned item and link it with its tier requirement\n    for (const item of itemResponse.data.data) {\n        // Find the config entry for this item to get its tier\n        const configEntry = bannedItemsWithPermissions.find(entry => entry.item === item.id);\n        if (configEntry && configEntry.tier) {\n            // Store only by EXACT code for more precise matching\n            bannedItemsMap.set(item.code, {\n                item,\n                requiredTier: parseInt(configEntry.tier, 10)\n            });\n        }\n    }\n\n    // If no valid banned items mapped, exit early\n    if (!bannedItemsMap.size) {\n        return;\n    }\n\n    // Get server information for Discord notifications\n    const serverInfo = (await takaro.gameserver.gameServerControllerGetOne(gameServerId)).data.data;\n\n    // Process each player\n    for (const player of playersResponse.data.data) {\n        // Skip if player has no inventory\n        if (!player.inventory || !player.inventory.length) {\n            continue;\n        }\n\n        // Check if player has global immunity\n        const pog = (await takaro.playerOnGameserver.playerOnGameServerControllerGetOne(\n            gameServerId, player.player.id)).data.data;\n        const hasGlobalImmunity = checkPermission(pog, 'BANNED_ITEMS_IMMUNITY');\n\n        if (hasGlobalImmunity) {\n            continue; // Skip this player entirely\n        }\n\n        // Get player's item tier permission\n        const tierPermission = checkPermission(pog, 'ALLOW_ITEMS_TIER');\n        const playerTier = tierPermission ? tierPermission.count || 0 : 0;\n\n        // Find all unauthorized items this player has\n        let unauthorizedItems = [];\n\n        // Check each item in player's inventory\n        for (const invItem of player.inventory) {\n            // Only match by exact code\n            const bannedItemData = bannedItemsMap.get(invItem.code);\n\n            if (!bannedItemData) {\n                // Not a banned item\n                continue;\n            }\n\n            // Check if player's tier is high enough\n            if (playerTier < bannedItemData.requiredTier) {\n                unauthorizedItems.push({\n                    item: invItem,\n                    requiredTier: bannedItemData.requiredTier\n                });\n            }\n        }\n\n        // If no unauthorized items, continue to next player\n        if (unauthorizedItems.length === 0) {\n            continue;\n        }\n\n        // Get current warnings\n        const existingVariable = await takaro.variable.variableControllerSearch({\n            filters: {\n                playerId: [player.player.id],\n                gameServerId: [gameServerId],\n                moduleId: [mod.moduleId],\n                key: ['banned_items_warning'],\n            },\n        });\n\n        let currentWarnings = existingVariable.data.data[0]\n            ? parseInt(existingVariable.data.data[0].value, 10)\n            : 0;\n\n        currentWarnings++;\n\n        // Create a different message format for player vs discord\n\n        // For players - simple item names without tier info\n        const playerItemsList = unauthorizedItems.map(item => item.item.name).join(\", \");\n\n        // For Discord - detailed item names with tier requirements\n        const discordItemsList = unauthorizedItems.map(item =>\n            `${item.item.name} (requires Tier ${item.requiredTier})`\n        ).join(\", \");\n\n        // Calculate expiration date (default to 24 hours from now)\n        const now = new Date();\n        const expiresAt = new Date(now.getTime() + (warningExpirationHours * 60 * 60 * 1000));\n\n        // Send Discord notification if channel ID is provided\n        if (discordChannelId && discordChannelId.trim() !== '') {\n            // For 7 Days to Die, we need to use the steamId from the player profile\n            // instead of the gameId which has a different format\n\n            // We'll need to check if we can get the proper Steam ID\n            // This might require fetching the player profile from Takaro first\n\n            // Try to get steamId from player object if available\n            const steamId = player.player.steamId || \"76561199524039401\"; // Fallback to the known steamId if needed\n\n            // Create a detailed message for Discord with cleaner Markdown formatting\n            let discordMessage = `🚨 **Banned Item Alert: ${player.player.name}**\\n` +\n                `**Player**: [${player.player.name}](https://steamcommunity.com/profiles/${steamId})\\n` +\n                `**Game ID**: ${player.gameId}\\n` +\n                `**Server**: ${serverInfo.name}\\n` +\n                `**Player Tier**: ${playerTier}\\n` +\n                `**Warning**: ${currentWarnings}/${warningsBeforePunishment}\\n` +\n                `**Action**: ${currentWarnings >= warningsBeforePunishment ?\n                    (punishmentType === 'none' ? 'Warning Only' : punishmentType) :\n                    'Warning'}\\n` +\n                `**Banned Items**: ${discordItemsList}\\n` +\n                `**Links**: [Steam](https://steamcommunity.com/profiles/${steamId}) | [Takaro](https://dashboard.takaro.io/player/${player.player.id}/info)`;\n            // Send to Discord with the correct function\n            try {\n                await takaro.discord.discordControllerSendMessage(discordChannelId, {\n                    message: discordMessage\n                });\n            } catch (error) {\n                // Log error but continue execution\n                console.error(`Failed to send Discord notification: ${error.message}`);\n            }\n        }\n\n        // Handle punishment if warnings exceeded\n        if (currentWarnings >= warningsBeforePunishment && punishmentType !== 'none') {\n            if (punishmentType === 'kick') {\n                await takaro.gameserver.gameServerControllerKickPlayer(gameServerId, player.player.id, {\n                    reason: `Unauthorized items: ${playerItemsList}`\n                });\n\n                // Announce to all players that someone was kicked\n                await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {\n                    message: `${player.player.name} has been kicked for having unauthorized items: ${playerItemsList}`\n                });\n            } else if (punishmentType === 'ban') {\n                const banExpiresAt = new Date(now.getTime() + banDuration);\n                await takaro.player.banControllerCreate({\n                    gameServerId,\n                    playerId: player.player.id,\n                    until: banExpiresAt,\n                    reason: `Unauthorized items: ${playerItemsList}`\n                });\n\n                // Announce to all players that someone was banned\n                await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {\n                    message: `${player.player.name} has been banned for having unauthorized items: ${playerItemsList}`\n                });\n            }\n\n            // Reset warnings after punishment\n            if (existingVariable.data.data.length) {\n                await takaro.variable.variableControllerDelete(existingVariable.data.data[0].id);\n            }\n        } else {\n            // Handle warning - SIMPLIFIED for player\n            let message = `The following items are not allowed with your permission level: ${playerItemsList}. Please dispose of them immediately.`;\n\n            if (punishmentType !== 'none') {\n                message += ` Warning ${currentWarnings} of ${warningsBeforePunishment} before ${punishmentType}`;\n            }\n\n            // No expiration time details for player\n\n            // Send warning message PRIVATELY to the specific player only\n            await takaro.gameserver.gameServerControllerSendMessage(\n                gameServerId,\n                {\n                    message,\n                    opts: {\n                        recipient: {\n                            gameId: player.gameId\n                        }\n                    }\n                }\n            );\n\n            // Update warning count with expiration time\n            if (existingVariable.data.data.length) {\n                await takaro.variable.variableControllerUpdate(existingVariable.data.data[0].id, {\n                    value: currentWarnings.toString(),\n                    expiresAt: expiresAt\n                });\n            } else {\n                await takaro.variable.variableControllerCreate({\n                    playerId: player.player.id,\n                    gameServerId: gameServerId,\n                    moduleId: mod.moduleId,\n                    key: 'banned_items_warning',\n                    value: currentWarnings.toString(),\n                    expiresAt: expiresAt\n                });\n            }\n        }\n    }\n}\n\nawait main();"
        }
      ],
      "functions": [],
      "permissions": [
        {
          "permission": "BANNED_ITEMS_IMMUNITY",
          "friendlyName": "Banned Items Immunity",
          "description": "Players with this permission are immune to all item bans regardless of item permissions",
          "canHaveCount": false
        },
        {
          "permission": "ALLOW_ITEMS_TIER",
          "friendlyName": "Allow Items for TIer",
          "description": "Allow player to possess tier items. the count connected to the item will allow it for that role",
          "canHaveCount": true
        }
      ]
    }
  ]
}