From 701790ccade4986c0aceb07146e19c00853b1285 Mon Sep 17 00:00:00 2001 From: Mateusz Zaremba <0.zaremate@gmail.com> Date: Wed, 9 Sep 2026 18:53:48 +0200 Subject: [PATCH] feat: made daylyquests script --- dailyquests.js | 1196 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1196 insertions(+) create mode 100644 dailyquests.js diff --git a/dailyquests.js b/dailyquests.js new file mode 100644 index 0000000..b84367f --- /dev/null +++ b/dailyquests.js @@ -0,0 +1,1196 @@ +/* + * Copyright (c) 2026 @ZareMate + * Original author: @ZareMate + * + * Licensed under the MIT License. + * + * If you modify this script, you may additionally identify yourself as: + * + * Modified by: @YourUsername + * + * The original author attribution and copyright notice must remain. + */ + +// Dependencies: LuckPerms + +var DAILY_QUESTS_FILE = "data/dailyquests/players.json"; +var DAILY_QUESTS_CONFIG = "config/dailyquests.json"; + +var data = null; +var config = null; +var lastResetCheckTick = 0; + +var LuckPermsApiProvider = Java.loadClass( + "net.luckperms.api.LuckPermsProvider", +); + +var luckPermsApi = null; + +function getDefaultConfig() { + return { + resetCheckInterval: 20, + questPermissionReroll: "dailyquests.command.reroll", + rewards: { + easy: { + item: "numismatics:bevel", + name: "Bevel", + amount: 1, + }, + medium: { + item: "numismatics:bevel", + name: "Bevel", + amount: 3, + }, + hard: { + item: "numismatics:cog", + name: "Cog", + amount: 1, + }, + }, + quests: { + easy: [ + { + id: "easy_iron", + name: "Iron Collector", + itemName: "Iron Ingots", + description: "Collect 10 Iron Ingots", + item: "minecraft:iron_ingot", + amount: 10, + reward: "easy", + }, + { + id: "easy_copper", + name: "Copper Collector", + itemName: "Copper Ingots", + description: "Collect 16 Copper Ingots", + item: "minecraft:copper_ingot", + amount: 16, + reward: "easy", + }, + { + id: "easy_coal", + name: "Coal Collector", + itemName: "Coal", + description: "Collect 20 Coal", + item: "minecraft:coal", + amount: 20, + reward: "easy", + }, + { + id: "easy_wheat", + name: "Farmer", + itemName: "Wheat", + description: "Collect 12 Wheat", + item: "minecraft:wheat", + amount: 12, + reward: "easy", + }, + { + id: "easy_redstone", + name: "Redstone Gatherer", + itemName: "Redstone Dust", + description: "Collect 8 Redstone Dust", + item: "minecraft:redstone", + amount: 8, + reward: "easy", + }, + { + id: "easy_oak", + name: "Lumberjack", + itemName: "Oak Logs", + description: "Collect 16 Oak Logs", + item: "minecraft:oak_log", + amount: 16, + reward: "easy", + }, + ], + medium: [ + { + id: "medium_iron", + name: "Iron Miner", + itemName: "Iron Ingots", + description: "Collect 32 Iron Ingots", + item: "minecraft:iron_ingot", + amount: 32, + reward: "medium", + }, + { + id: "medium_copper", + name: "Copper Miner", + itemName: "Copper Ingots", + description: "Collect 32 Copper Ingots", + item: "minecraft:copper_ingot", + amount: 32, + reward: "medium", + }, + { + id: "medium_gold", + name: "Gold Collector", + itemName: "Gold Ingots", + description: "Collect 16 Gold Ingots", + item: "minecraft:gold_ingot", + amount: 16, + reward: "medium", + }, + { + id: "medium_redstone", + name: "Redstone Engineer", + itemName: "Redstone Blocks", + description: "Collect 12 Redstone Blocks", + item: "minecraft:redstone_block", + amount: 12, + reward: "medium", + }, + { + id: "medium_bread", + name: "Baker", + itemName: "Bread", + description: "Collect 16 Bread", + item: "minecraft:bread", + amount: 16, + reward: "medium", + }, + { + id: "medium_diamond", + name: "Gem Hunter", + itemName: "Diamonds", + description: "Collect 8 Diamonds", + item: "minecraft:diamond", + amount: 8, + reward: "medium", + }, + ], + hard: [ + { + id: "hard_diamond", + name: "Diamond Hunter", + itemName: "Diamonds", + description: "Collect 8 Diamonds", + item: "minecraft:diamond", + amount: 8, + reward: "hard", + }, + { + id: "hard_gold", + name: "Gold Hoarder", + itemName: "Gold Ingots", + description: "Collect 16 Gold Ingots", + item: "minecraft:gold_ingot", + amount: 16, + reward: "hard", + }, + { + id: "hard_scrap", + name: "Netherite Scavenger", + itemName: "Netherite Scrap", + description: "Collect 4 Netherite Scrap", + item: "minecraft:netherite_scrap", + amount: 4, + reward: "hard", + }, + { + id: "hard_redstone", + name: "Redstone Builder", + itemName: "Redstone Blocks", + description: "Collect 32 Redstone Blocks", + item: "minecraft:redstone_block", + amount: 32, + reward: "hard", + }, + { + id: "hard_pearls", + name: "End Explorer", + itemName: "Ender Pearls", + description: "Collect 16 Ender Pearls", + item: "minecraft:ender_pearl", + amount: 16, + reward: "hard", + }, + { + id: "hard_star", + name: "Star Hunter", + itemName: "Nether Star", + description: "Collect 1 Nether Star", + item: "minecraft:nether_star", + amount: 1, + reward: "hard", + }, + ], + }, + }; +} + +function loadConfig() { + var defaults = getDefaultConfig(); + + try { + var loaded = JsonIO.read(DAILY_QUESTS_CONFIG); + + if (!loaded || typeof loaded !== "object") { + throw new Error("Invalid configuration"); + } + + config = loaded; + + if ( + typeof config.resetCheckInterval !== "number" || + config.resetCheckInterval < 1 + ) { + config.resetCheckInterval = defaults.resetCheckInterval; + } + + if ( + typeof config.questPermissionReroll !== "string" || + !config.questPermissionReroll + ) { + config.questPermissionReroll = defaults.questPermissionReroll; + } + + if (!config.rewards || typeof config.rewards !== "object") { + config.rewards = defaults.rewards; + } + + if (!config.rewards.easy) { + config.rewards.easy = defaults.rewards.easy; + } + + if (!config.rewards.medium) { + config.rewards.medium = defaults.rewards.medium; + } + + if (!config.rewards.hard) { + config.rewards.hard = defaults.rewards.hard; + } + + if (!config.quests || typeof config.quests !== "object") { + config.quests = defaults.quests; + } + + if ( + !Array.isArray(config.quests.easy) || + config.quests.easy.length === 0 + ) { + config.quests.easy = defaults.quests.easy; + } + + if ( + !Array.isArray(config.quests.medium) || + config.quests.medium.length === 0 + ) { + config.quests.medium = defaults.quests.medium; + } + + if ( + !Array.isArray(config.quests.hard) || + config.quests.hard.length === 0 + ) { + config.quests.hard = defaults.quests.hard; + } + + JsonIO.write(DAILY_QUESTS_CONFIG, config); + + console.log("[DailyQuests] Configuration loaded."); + } catch (error) { + config = defaults; + + try { + JsonIO.write(DAILY_QUESTS_CONFIG, config); + + console.log( + "[DailyQuests] Created default configuration: " + + DAILY_QUESTS_CONFIG, + ); + } catch (writeError) { + console.error( + "[DailyQuests] Failed to create configuration: " + + String(writeError), + ); + } + } +} + +function getLuckPerms() { + if (luckPermsApi) { + return luckPermsApi; + } + + try { + luckPermsApi = LuckPermsApiProvider.get(); + + return luckPermsApi; + } catch (error) { + console.error( + "[DailyQuests] Failed to load LuckPerms API: " + String(error), + ); + + return null; + } +} + +function hasPermission(player, permission) { + var api = getLuckPerms(); + + if (!api || !player) { + return false; + } + + try { + return api + .getUserManager() + .getUser(player.uuid) + .getCachedData() + .getPermissionData() + .checkPermission(permission) + .asBoolean(); + } catch (error) { + console.error( + "[DailyQuests] Permission check failed: " + String(error), + ); + + return false; + } +} + +function pad2(value) { + return String(value).padStart(2, "0"); +} + +function getToday() { + var now = new Date(); + + return ( + now.getFullYear() + + "-" + + pad2(now.getMonth() + 1) + + "-" + + pad2(now.getDate()) + ); +} + +function getResetCountdown() { + var now = new Date(); + var nextMidnight = new Date(now); + + nextMidnight.setHours(24, 0, 0, 0); + + var remaining = Math.max(0, nextMidnight.getTime() - now.getTime()); + + var totalSeconds = Math.floor(remaining / 1000); + + var hours = Math.floor(totalSeconds / 3600); + + totalSeconds %= 3600; + + var minutes = Math.floor(totalSeconds / 60); + + var seconds = totalSeconds % 60; + + if (hours > 0) { + return hours + "h " + pad2(minutes) + "m " + pad2(seconds) + "s"; + } + + if (minutes > 0) { + return minutes + "m " + pad2(seconds) + "s"; + } + + return seconds + "s"; +} + +function createEmptyData() { + return { + lastReset: getToday(), + players: {}, + }; +} + +function loadData() { + try { + var loaded = JsonIO.read(DAILY_QUESTS_FILE); + + if (!loaded || typeof loaded !== "object") { + data = createEmptyData(); + saveData(); + return; + } + + if (!loaded.players || typeof loaded.players !== "object") { + loaded.players = {}; + } + + if (typeof loaded.lastReset !== "string") { + loaded.lastReset = getToday(); + } + + data = loaded; + } catch (error) { + data = createEmptyData(); + saveData(); + } +} + +function saveData() { + if (!data) { + return; + } + + try { + JsonIO.write(DAILY_QUESTS_FILE, data); + } catch (error) { + console.error("[DailyQuests] Failed to save data: " + String(error)); + } +} + +function randomQuest(category) { + var pool = config.quests[category]; + + if (!Array.isArray(pool) || pool.length === 0) { + return null; + } + + return pool[Math.floor(Math.random() * pool.length)]; +} + +function getQuestById(id) { + if (!id) { + return null; + } + + var categories = ["easy", "medium", "hard"]; + + for (var i = 0; i < categories.length; i++) { + var pool = config.quests[categories[i]]; + + for (var j = 0; j < pool.length; j++) { + if (pool[j].id === id) { + return pool[j]; + } + } + } + + return null; +} + +function getQuestReward(quest) { + if (!quest) { + return null; + } + + if (quest.reward && typeof quest.reward === "object") { + return quest.reward; + } + + if (typeof quest.reward === "string") { + return config.rewards[quest.reward]; + } + + return null; +} + +function getPlayerUuid(player) { + return String(player.uuid); +} + +function createPlayerData(player) { + var easy = randomQuest("easy"); + var medium = randomQuest("medium"); + var hard = randomQuest("hard"); + + return { + name: String(player.username), + easyQuest: easy ? easy.id : null, + mediumQuest: medium ? medium.id : null, + hardQuest: hard ? hard.id : null, + easyClaimed: false, + mediumClaimed: false, + hardClaimed: false, + }; +} + +function createOfflinePlayerData(name) { + var easy = randomQuest("easy"); + var medium = randomQuest("medium"); + var hard = randomQuest("hard"); + + return { + name: String(name), + easyQuest: easy ? easy.id : null, + mediumQuest: medium ? medium.id : null, + hardQuest: hard ? hard.id : null, + easyClaimed: false, + mediumClaimed: false, + hardClaimed: false, + }; +} + +function repairPlayerData(player, playerData) { + var changed = false; + + if (!playerData.name) { + playerData.name = String(player.username); + changed = true; + } + + var categories = ["easy", "medium", "hard"]; + + for (var i = 0; i < categories.length; i++) { + var category = categories[i]; + + var questField = category + "Quest"; + + var claimedField = category + "Claimed"; + + if ( + typeof playerData[questField] !== "string" || + !getQuestById(playerData[questField]) + ) { + var quest = randomQuest(category); + + playerData[questField] = quest ? quest.id : null; + + playerData[claimedField] = false; + + changed = true; + } + + if (typeof playerData[claimedField] !== "boolean") { + playerData[claimedField] = false; + + changed = true; + } + } + + if (playerData.cogsEarned !== undefined) { + delete playerData.cogsEarned; + changed = true; + } + + return changed; +} + +function getPlayerData(player) { + var uuid = getPlayerUuid(player); + + if (!data.players[uuid]) { + data.players[uuid] = createPlayerData(player); + + saveData(); + + return data.players[uuid]; + } + + var playerData = data.players[uuid]; + + var changed = repairPlayerData(player, playerData); + + playerData.name = String(player.username); + + if (changed) { + saveData(); + } + + return playerData; +} + +function countItem(player, itemId) { + var total = 0; + + try { + var inventory = player.inventory; + + if (!inventory) { + return 0; + } + + var items = inventory.items; + + for (var i = 0; i < items.length; i++) { + var stack = items[i]; + + if (!stack || stack.empty) { + continue; + } + + if (stack.id !== itemId) { + continue; + } + + total += stack.count; + } + } catch (error) { + console.error("[DailyQuests] Inventory count error: " + String(error)); + + return 0; + } + + return total; +} + +function removeItems(player, itemId, amount) { + var remaining = amount; + + try { + var inventory = player.inventory; + + if (!inventory) { + return false; + } + + var items = inventory.items; + + for (var i = 0; i < items.length; i++) { + if (remaining <= 0) { + break; + } + + var stack = items[i]; + + if (!stack || stack.empty) { + continue; + } + + if (stack.id !== itemId) { + continue; + } + + var removeAmount = Math.min(remaining, stack.count); + + stack.shrink(removeAmount); + + remaining -= removeAmount; + } + } catch (error) { + console.error( + "[DailyQuests] Inventory removal error: " + String(error), + ); + + return false; + } + + return remaining <= 0; +} + +function giveReward(player, reward) { + if ( + !reward || + !reward.item || + typeof reward.amount !== "number" || + reward.amount <= 0 + ) { + return false; + } + + try { + player.give(Item.of(reward.item, reward.amount)); + + return true; + } catch (error) { + console.error("[DailyQuests] Reward error: " + String(error)); + + return false; + } +} + +function getProgress(player, quest) { + if (!quest) { + return 0; + } + + return Math.min(countItem(player, quest.item), quest.amount); +} + +function separator(player) { + player.tell(Text.of("───────────────────────────────────").gray()); +} + +function getCategoryColor(category) { + if (category === "medium") { + return "yellow"; + } + + if (category === "hard") { + return "red"; + } + + return "green"; +} + +function tellQuest(player, category, quest, claimed) { + if (!quest) { + player.tell(Text.of("Quest data is unavailable.").red()); + + return; + } + + var reward = getQuestReward(quest); + + var progress = getProgress(player, quest); + + var itemName = + quest.itemName || quest.description.replace(/^Collect\s+\d+\s+/i, ""); + + var rewardName = reward && reward.name ? reward.name : reward.item; + + player.tell( + Text.of(category.toUpperCase()) + .color(getCategoryColor(category)) + .bold(), + ); + + player.tell(Text.of(quest.name).white().bold()); + + player.tell( + Text.of("Collect: ") + .gray() + .append(Text.of(progress + " / " + quest.amount + " ").white()) + .append(Text.of(itemName).gray()), + ); + + player.tell( + Text.of("Reward: ") + .gray() + .append(Text.of(reward.amount + "x " + rewardName).gold()), + ); + + if (claimed) { + player.tell(Text.of("[ CLAIMED ]").darkGray()); + } else if (progress >= quest.amount) { + player.tell( + Text.of("[ CLAIM ]") + .green() + .bold() + .clickRunCommand("/dailyrewards claim " + category), + ); + } else { + player.tell(Text.of("[ NOT COMPLETE ]").red()); + } + + player.tell(""); +} + +function openDailyRewards(player) { + if (!player) { + return; + } + + checkDailyReset(player.server); + + var playerData = getPlayerData(player); + + var easyQuest = getQuestById(playerData.easyQuest); + + var mediumQuest = getQuestById(playerData.mediumQuest); + + var hardQuest = getQuestById(playerData.hardQuest); + + separator(player); + + player.tell(Text.of("DAILY QUESTS").gold().bold()); + + player.tell( + Text.of("Resets in: ") + .gray() + .append(Text.of(getResetCountdown()).aqua()), + ); + + player.tell(""); + + tellQuest(player, "easy", easyQuest, playerData.easyClaimed); + + tellQuest(player, "medium", mediumQuest, playerData.mediumClaimed); + + tellQuest(player, "hard", hardQuest, playerData.hardClaimed); + + player.tell(Text.of("[ REFRESH ]").aqua().clickRunCommand("/dailyrewards")); + + separator(player); +} + +function claimQuest(player, category) { + if (!player) { + return 0; + } + + if (category !== "easy" && category !== "medium" && category !== "hard") { + return 0; + } + + checkDailyReset(player.server); + + var playerData = getPlayerData(player); + + var questField = category + "Quest"; + + var claimedField = category + "Claimed"; + + var quest = getQuestById(playerData[questField]); + + if (!quest) { + player.tell( + Text.of( + "Your quest data was repaired. Run /dailyrewards again.", + ).yellow(), + ); + + repairPlayerData(player, playerData); + + saveData(); + + return 0; + } + + if (playerData[claimedField]) { + player.tell(Text.of("This quest has already been claimed.").red()); + + return 0; + } + + var reward = getQuestReward(quest); + + if (!reward) { + player.tell( + Text.of("This quest has an invalid reward configuration.").red(), + ); + + return 0; + } + + var currentAmount = countItem(player, quest.item); + + if (currentAmount < quest.amount) { + player.tell(Text.of("You do not have enough items.").red()); + + player.tell( + Text.of( + "Required: " + quest.amount + " | You have: " + currentAmount, + ).gray(), + ); + + return 0; + } + + if (countItem(player, quest.item) < quest.amount) { + player.tell( + Text.of("Your inventory changed. The claim was cancelled.").red(), + ); + + return 0; + } + + if (!removeItems(player, quest.item, quest.amount)) { + player.tell(Text.of("The quest items could not be removed.").red()); + + return 0; + } + + if (!giveReward(player, reward)) { + player.tell( + Text.of( + "The reward could not be given. Contact an administrator.", + ).red(), + ); + + return 0; + } + + playerData[claimedField] = true; + + saveData(); + + player.tell(Text.of("Quest claimed successfully!").green()); + + player.tell( + Text.of("Reward: ") + .gray() + .append( + Text.of( + reward.amount + "x " + (reward.name || reward.item), + ).gold(), + ), + ); + + player.tell(""); + + openDailyRewards(player); + + return 1; +} + +function findOnlinePlayer(server, name) { + var target = String(name).toLowerCase(); + + var players = server.players; + + for (var i = 0; i < players.length; i++) { + var player = players[i]; + + if (String(player.username).toLowerCase() === target) { + return player; + } + } + + return null; +} + +function findSavedPlayer(name) { + var target = String(name).toLowerCase(); + + for (var uuid in data.players) { + var playerData = data.players[uuid]; + + if (!playerData || !playerData.name) { + continue; + } + + if (String(playerData.name).toLowerCase() === target) { + return { + uuid: uuid, + name: String(playerData.name), + }; + } + } + + return null; +} + +function rerollPlayer(server, name) { + checkDailyReset(server); + + var onlinePlayer = findOnlinePlayer(server, name); + + if (onlinePlayer) { + var uuid = getPlayerUuid(onlinePlayer); + + data.players[uuid] = createPlayerData(onlinePlayer); + + saveData(); + + onlinePlayer.tell( + Text.of( + "Your daily quests have been rerolled by an administrator.", + ).yellow(), + ); + + openDailyRewards(onlinePlayer); + + return true; + } + + var savedPlayer = findSavedPlayer(name); + + if (!savedPlayer) { + return false; + } + + data.players[savedPlayer.uuid] = createOfflinePlayerData(savedPlayer.name); + + saveData(); + + return true; +} + +function resetDailyQuests(server) { + var today = getToday(); + + console.log("[DailyQuests] Resetting daily quests for " + today); + + data.players = {}; + data.lastReset = today; + + var players = server.players; + + for (var i = 0; i < players.length; i++) { + var player = players[i]; + + data.players[getPlayerUuid(player)] = createPlayerData(player); + } + + saveData(); + + for (var j = 0; j < players.length; j++) { + players[j].tell(Text.of("Daily quests have been reset!").green()); + + players[j].tell( + Text.of("Use /dailyrewards to view your new quests.").gray(), + ); + } + + console.log("[DailyQuests] Daily reset complete."); +} + +function checkDailyReset(server) { + if (!data) { + loadData(); + } + + var today = getToday(); + + if (data.lastReset !== today) { + resetDailyQuests(server); + } +} + +ServerEvents.commandRegistry(function (event) { + var Commands = event.commands; + + var Arguments = event.arguments; + + event.register( + Commands.literal("dailyrewards") + .executes(function (ctx) { + try { + var player = ctx.source.player; + + if (!player) { + ctx.source.sendFailure( + Text.of( + "This command can only be used by a player.", + ).red(), + ); + + return 0; + } + + openDailyRewards(player); + + return 1; + } catch (error) { + console.error( + "[DailyQuests] /dailyrewards error: " + String(error), + ); + + ctx.source.sendFailure( + Text.of( + "Daily Quests encountered an error. Check the server console.", + ).red(), + ); + + return 0; + } + }) + .then( + Commands.literal("claim") + .then( + Commands.literal("easy").executes(function (ctx) { + return claimQuest(ctx.source.player, "easy"); + }), + ) + .then( + Commands.literal("medium").executes(function (ctx) { + return claimQuest(ctx.source.player, "medium"); + }), + ) + .then( + Commands.literal("hard").executes(function (ctx) { + return claimQuest(ctx.source.player, "hard"); + }), + ), + ), + ); + + event.register( + Commands.literal("reroll") + .requires( + (source) => + source.isPlayer() && + (source.hasPermission(3) || + hasPermission( + source.player, + config.questPermissionReroll, + )), + ) + .then( + Commands.argument( + "player", + Arguments.PLAYER.create(event), + ).executes((ctx) => { + try { + var target = Arguments.PLAYER.getResult(ctx, "player"); + + if (!target) { + ctx.source.sendFailure( + Text.of("You must specify a player.").red(), + ); + + return 0; + } + + var name = String(target.username); + + var uuid = getPlayerUuid(target); + + checkDailyReset(ctx.source.server); + + data.players[uuid] = createPlayerData(target); + + saveData(); + + target.tell( + Text.of( + "Your daily quests have been rerolled by an administrator.", + ).yellow(), + ); + + openDailyRewards(target); + + ctx.source.sendSuccess( + Text.of( + "Daily quests rerolled for " + name + ".", + ).green(), + true, + ); + + return 1; + } catch (error) { + console.error( + "[DailyQuests] /reroll error: " + String(error), + ); + + ctx.source.sendFailure( + Text.of( + "Reroll failed. Check the server console.", + ).red(), + ); + + return 0; + } + }), + ), + ); +}); + +PlayerEvents.loggedIn(function (event) { + try { + checkDailyReset(event.server); + + getPlayerData(event.player); + } catch (error) { + console.error("[DailyQuests] Player join error: " + String(error)); + + event.player.tell( + Text.of( + "Daily Quests failed to load. Check the server console.", + ).red(), + ); + } +}); + +ServerEvents.tick(function (event) { + try { + var currentTick = event.server.tickCount; + + if (currentTick - lastResetCheckTick < config.resetCheckInterval) { + return; + } + + lastResetCheckTick = currentTick; + + checkDailyReset(event.server); + } catch (error) { + console.error("[DailyQuests] Tick error: " + String(error)); + } +}); + +loadConfig(); +loadData(); + +console.log("[DailyQuests] Loaded successfully.");