# Blocks and XP SYstem
# Made by DuckyAurora - Version 1.1
DD-MM-YYYY
# Requirements: Skript, skript-yaml, SkBee, skript-gui :P (Latest versions 22-05-
2025 15:38)
# How does the Skript work? well instead of using Variables, we are using .yaml to
save the information of the blocks, the file can
# be found at /plugins/Skript/scripts/adminxp/... here the files will be saved,
please don't touch them, erasing them can delete the
# Information of the levels and blocks that you have added, any suggestions please
dm "duckyhalowein" in the discord.
# Also, XP of player is saved on NBT "Stats;xp" exactly. to get it with skript do
(int tag "Stats;xp" of custom nbt of player)
# If you wan't to modificate things, the only current options are these below:
options:
prefix: &6[Block System] # You can change this, this is the prefix of the
messages
gain: &a+%{_xpGain}% XP &7(%{_newXP}%/%{_maxXP}%) &6Level %{_level}% # The
format of the XP message that shows up on Action Bar
# {_xpGain} = the XP obtained when broke the block
# {_newXP} = your total XP
# {_maxXP} = the max xp of the level
# {_level} = your actual level
# From now on, don't touch anything, they can be dangerous.
on load:
load yaml "plugins/Skript/scripts/adminxp/blocks.yml" as "blocks"
load yaml "plugins/Skript/scripts/adminxp/levels.yml" as "levels"
command /adminxp [<text>]:
permission: adminxp.admin
permission message: {@prefix} &cYou don't have permission to use this command!
trigger:
if arg-1 is not set:
openAdminXPGUI(player)
else if arg-1 is "setblock":
if {adminxp.setting_block::%player%} is true:
if player's tool is air:
send "{@prefix} &cYou must hold a block in your hand!" to
player
stop
set {adminxp.editing::%player%.block} to player's tool
delete {adminxp.setting_block::%player%}
send "{@prefix} &aBlock set to: %player's tool%" to player
wait 5 ticks
addEditBlock(player, {adminxp.editing::%player%.id})
else:
send "{@prefix} &cYou're not currently configuring a block." to
player
else if arg-1 is "reset":
send "{@prefix} &cThis will delete all your configured blocks and
levels!" to player
send "{@prefix} &cType &e/adminxp reset confirm &cto proceed." to
player
else if arg-1 is "reset confirm":
delete yaml "blocks"
load yaml "plugins/Skript/scripts/adminxp/blocks.yml" as "blocks"
save yaml "blocks"
delete yaml "levels"
load yaml "plugins/Skript/scripts/adminxp/levels.yml" as "levels"
set yaml value "levels.1" in "levels" to 150
set yaml value "levels.2" in "levels" to 300
set yaml value "levels.3" in "levels" to 750
save yaml "levels"
send "{@prefix} &aConfiguration files have been reset!" to player
function openAdminXPGUI(p: player):
create a gui with virtual chest inventory with 6 rows named "Admin XP
Configuration":
loop integers from 0 to 8:
make gui slot loop-value with black stained glass pane named " "
loop integers from 45 to 53:
make gui slot loop-value with black stained glass pane named " "
loop integers from 0 to 5:
make gui slot (loop-value * 9) with black stained glass pane named " "
make gui slot (loop-value * 9 + 8) with black stained glass pane named
" "
set {_nodes::*} to all yaml nodes of "blocks"
set {_slot} to 10
if size of {_nodes::*} > 0:
loop {_nodes::*}:
set {_blockId} to loop-value
if yaml path "%{_blockId}%.block_type" in "blocks" exists:
set {_blockTypeStr} to yaml value "%{_blockId}%.block_type" in
"blocks"
set {_block} to {_blockTypeStr} parsed as itemtype
set {_min} to yaml value "%{_blockId}%.min" in "blocks"
set {_max} to yaml value "%{_blockId}%.max" in "blocks"
make gui slot {_slot} with {_block} named "&e%{_blockTypeStr}%"
with lore "&7XP Range: &f%{_min}% - %{_max}%", "&7Click to edit", and "&cRight-
click to remove":
if gui click type is left mouse button:
addEditBlock({_p}, {_blockId})
else if gui click type is right mouse button:
load yaml "plugins/Skript/scripts/adminxp/blocks.yml"
as "blocks"
delete yaml value "%{_blockId}%" from "blocks"
save yaml "blocks"
send "{@prefix} &cRemoved XP block configuration: &e%
{_blockId}%" to {_p}
wait 5 ticks
openAdminXPGUI({_p})
add 1 to {_slot}
if mod({_slot} - 8, 9) is 0:
add 2 to {_slot}
if {_slot} >= 44:
exit loop
make gui slot 49 with emerald block named "&aAdd New XP Block" with lore
"&7Click to add a new block":
addEditBlock({_p})
make gui slot 46 with experience bottle named "&bConfigure Level
Requirements" with lore "&7Click to set XP needed for each level":
openLevelConfigGUI({_p})
open last gui to {_p}
function openLevelConfigGUI(p: player):
create a gui with virtual chest inventory with 6 rows named "Level Requirements
Configuration":
loop integers from 0 to 8:
make gui slot loop-value with black stained glass pane named " "
loop integers from 45 to 53:
make gui slot loop-value with black stained glass pane named " "
loop integers from 0 to 5:
make gui slot (loop-value * 9) with black stained glass pane named " "
make gui slot (loop-value * 9 + 8) with black stained glass pane named
" "
set {_nodes::*} to all yaml nodes of "levels"
make gui slot 49 with green dye named "&aAdd New Level" with lore "&7Click
to add a new level requirement":
close {_p}'s inventory
send "{@prefix} &aEnter the level number you want to add:" to {_p}
set {adminxp.adding_level::%{_p}%} to true
make gui slot 45 with arrow named "&cBack to Main Menu" with lore "&7Click
to go back":
openAdminXPGUI({_p})
set {_slot} to 10
if size of {_nodes::*} > 0:
loop {_nodes::*}:
if loop-value = "levels":
continue
set {_l::*} to loop-value split at "."
set {_level} to {_l::2} parsed as number
set {_xp} to yaml value "%loop-value%" in "levels"
make gui slot {_slot} with experience bottle named "&eLevel %
{_level}%" with lore "&7XP Required: &f%{_xp}%", and "&7Click to edit":
close {_p}'s inventory
send "{@prefix} &aEnter the XP required for Level %{_level}%
(current: %{_xp}%):" to {_p}
set {adminxp.editing_level::%{_p}%} to {_level}
add 1 to {_slot}
if mod({_slot} - 8, 9) is 0:
add 2 to {_slot}
if {_slot} >= 44:
exit loop
open last gui to {_p}
function addEditBlock(p: player, editId: text = ""):
set {_currentBlock} to {adminxp.editing::%{_p}%.block}
set {_currentMin} to {adminxp.editing::%{_p}%.min}
set {_currentMax} to {adminxp.editing::%{_p}%.max}
create a gui with virtual chest inventory with 3 rows named "Configure XP
Block":
loop integers from 0 to 8:
make gui slot loop-value with black stained glass pane named " "
loop integers from 18 to 26:
make gui slot loop-value with black stained glass pane named " "
loop integers from 0 to 2:
make gui slot (loop-value * 9) with black stained glass pane named " "
make gui slot (loop-value * 9 + 8) with black stained glass pane named
" "
if {_editId} is not "":
if yaml path "%{_editId}%.block_type" in "blocks" exists:
set {_blockTypeStr} to yaml value "%{_editId}%.block_type" in
"blocks"
set {_block} to {_blockTypeStr} parsed as itemtype
set {_min} to yaml value "%{_editId}%.min" in "blocks"
set {_max} to yaml value "%{_editId}%.max" in "blocks"
else:
if {_currentBlock} is set:
set {_block} to {_currentBlock}
set {_min} to {_currentMin} ? 25
set {_max} to {_currentMax} ? 50
else:
set {_block} to stone
set {_min} to 25
set {_max} to 50
else:
if {_currentBlock} is set:
set {_block} to {_currentBlock}
set {_min} to {_currentMin} ? 25
set {_max} to {_currentMax} ? 50
else:
set {_block} to stone
set {_min} to 25
set {_max} to 50
set {adminxp.editing::%{_p}%.id} to {_editId}
set {adminxp.editing::%{_p}%.block} to {_block}
set {adminxp.editing::%{_p}%.min} to {_min}
set {adminxp.editing::%{_p}%.max} to {_max}
if {_block} is not set:
set {_displayBlock} to barrier
else:
set {_displayBlock} to {_block}
make gui slot 11 with {_displayBlock} named "&eSelect Block Type" with lore
"&7Current: %{_displayBlock}%", and "&7Click to change":
close {_p}'s inventory
send "{@prefix} &aPlease hold the block you want to use and type
&e/adminxp setblock" to {_p}
set {adminxp.setting_block::%{_p}%} to true
make gui slot 13 with paper named "&eSet XP Range" with lore "&7Min: &f%
{_min}%", "&7Max: &f%{_max}%", and "&7Click to edit":
close {_p}'s inventory
send "{@prefix} &aEnter XP range (format: min-max):" to {_p}
set {adminxp.setting_range::%{_p}%} to true
make gui slot 15 with lime dye named "&aSave Configuration" with lore
"&7Click to save":
if {adminxp.editing::%{_p}%.block} is not set:
send "{@prefix} &cError: No block selected! Please select a block
first." to {_p}
stop
load yaml "plugins/Skript/scripts/adminxp/blocks.yml" as "blocks"
if {adminxp.editing::%{_p}%.id} is "":
set {_blockName} to "%{adminxp.editing::%{_p}%.block}%"
replace all " " with "_" in {_blockName}
set {_uuid} to random integer between 1000 and 9999
set {_newId} to "%{_blockName}%_%{_uuid}%"
else:
set {_newId} to {adminxp.editing::%{_p}%.id}
set {_blockType} to "%{adminxp.editing::%{_p}%.block}%"
set yaml value "%{_newId}%.block_type" in "blocks" to {_blockType}
set yaml value "%{_newId}%.min" in "blocks" to {adminxp.editing::%{_p}
%.min}
set yaml value "%{_newId}%.max" in "blocks" to {adminxp.editing::%{_p}
%.max}
save yaml "blocks"
delete {adminxp.editing::%{_p}%::*}
send "{@prefix} &aConfiguration saved!" to {_p}
wait 5 ticks
openAdminXPGUI({_p})
make gui slot 22 with arrow named "&cBack to Main Menu" with lore "&7Click
to go back without saving":
delete {adminxp.editing::%{_p}%::*}
openAdminXPGUI({_p})
open last gui to {_p}
function getPlayerLevel(xp: number) :: number:
set {_level} to 1
set {_nodes::*} to all yaml nodes of "levels"
loop {_nodes::*}:
if loop-value = "levels":
continue
set {_req} to yaml value "%loop-value%" from "levels"
set {_r::*} to loop-value split at "."
if {_xp} >= {_req}:
set {_level} to {_r::2} parsed as number
return {_level}
function getMaxXP(level: number) :: number:
set {_nextLevel} to {_level} + 1
set {_maxXP} to yaml value "levels.%{_nextLevel}%" in "levels"
if {_maxXP} isn't set:
return 0
return "%{_maxXP}%" parsed as number
function getMinXP(level: number) :: number:
if {_level} = 1:
return 0
set {_minXP} to yaml value "levels.%{_level}%" in "levels"
return "%{_minXP}%" parsed as number
function getProgressBar(current: number, max: number, length: number) :: string:
if {_max} <= 0:
set {_max} to 1
set {_percent} to {_current} / {_max}
if {_percent} > 1:
set {_percent} to 1
set {_completed} to floor({_percent} * {_length})
set {_bar} to ""
loop {_length} times:
if loop-number <= {_completed}:
set {_bar} to "%{_bar}%&a|"
else:
set {_bar} to "%{_bar}%&7|"
return {_bar}
on chat:
if {adminxp.adding_level::%player%} is true:
cancel event
set {_level} to message parsed as number
if {_level} is set:
if {_level} > 1:
delete {adminxp.adding_level::%player%}
send "{@prefix} &aEnter the XP required for Level %{_level}%:" to
player
set {adminxp.editing_level::%player%} to {_level}
else:
send "{@prefix} &cLevel must be greater than 1. Please try again."
to player
else:
send "{@prefix} &cInvalid number format. Please try again." to player
stop
if {adminxp.editing_level::%player%} is set:
cancel event
set {_level} to {adminxp.editing_level::%player%}
set {_xp} to message parsed as number
if {_xp} is set:
load yaml "plugins/Skript/scripts/adminxp/levels.yml" as "levels"
set yaml value "levels.%{_level}%" in "levels" to {_xp}
save yaml "levels"
send "{@prefix} &aLevel %{_level}% now requires %{_xp}% XP." to player
else:
send "{@prefix} &cInvalid number format. Please try again." to player
delete {adminxp.editing_level::%player%}
wait 5 ticks
openLevelConfigGUI(player)
stop
if {adminxp.setting_range::%player%} is true:
cancel event
set {_parts::*} to message split at "-"
if size of {_parts::*} = 2:
set {_min} to {_parts::1} parsed as number
set {_max} to {_parts::2} parsed as number
if {_min} is set:
if {_max} is set:
if {_min} < {_max}:
set {adminxp.editing::%player%.min} to {_min}
set {adminxp.editing::%player%.max} to {_max}
send "{@prefix} &aRange set to: %{_min}% - %{_max}%" to
player
else:
send "{@prefix} &cMinimum value must be less than maximum."
to player
else:
send "{@prefix} &cInvalid number format for maximum value.
Please try again." to player
else:
send "{@prefix} &cInvalid number format for minimum value. Please
try again." to player
else:
send "{@prefix} &cInvalid format. Please use format: min-max (e.g. 25-
50)" to player
delete {adminxp.setting_range::%player%}
wait 5 ticks
addEditBlock(player, {adminxp.editing::%player%.id})
stop
on break:
set {_nodes::*} to all yaml nodes of "blocks"
if size of {_nodes::*} = 0:
stop
loop {_nodes::*}:
set {_blockId} to loop-value
if yaml path "%{_blockId}%.block_type" in "blocks" exists:
set {_blockTypeStr} to yaml value "%{_blockId}%.block_type" in "blocks"
set {_blockType} to {_blockTypeStr} parsed as itemtype
if {_blockType} is not set:
continue
if event-block is {_blockType}:
set {_min} to 10
set {_max} to 50
if yaml path "%{_blockId}%.min" in "blocks" exists:
set {_minStr} to yaml value "%{_blockId}%.min" in "blocks"
set {_minTemp} to {_minStr} parsed as number
if {_minTemp} is set:
set {_min} to {_minTemp}
if yaml path "%{_blockId}%.max" in "blocks" exists:
set {_maxStr} to yaml value "%{_blockId}%.max" in "blocks"
set {_maxTemp} to {_maxStr} parsed as number
if {_maxTemp} is set:
set {_max} to {_maxTemp}
set {_xpGain} to random integer between {_min} and {_max}
set {_currentXP} to (int tag "Stats;xp" of custom nbt of player) ?
0
set {_newXP} to {_currentXP} + {_xpGain}
set int tag "Stats;xp" of custom nbt of player to {_newXP}
set {_level} to getPlayerLevel({_newXP})
set {_minXP} to getMinXP({_level})
set {_maxXP} to getMaxXP({_level})
send action bar "{@gain}" to player
exit loop