!MirrorUtils.sk

Created by Unknown

Just so you know, we don't know the file format for every file. If it's just a bunch of random characters, it's probably a .zip or .jar.

# 
#
#   ███╗   ███╗██╗██████╗ ██████╗  ██████╗ ██████╗   ██╗   ██╗████████╗██╗██╗     ███████╗
#   ████╗ ████║██║██╔══██╗██╔══██╗██╔═══██╗██╔══██╗  ██║   ██║╚══██╔══╝██║██║     ██╔════╝
#   ██╔████╔██║██║██████╔╝██████╔╝██║   ██║██████╔╝  ██║   ██║   ██║   ██║██║     ███████╗
#   ██║╚██╔╝██║██║██╔══██╗██╔══██╗██║   ██║██╔══██╗  ██║   ██║   ██║   ██║██║     ╚════██║
#   ██║ ╚═╝ ██║██║██║  ██║██║  ██║╚██████╔╝██║  ██║  ╚██████╔╝   ██║   ██║███████╗███████║
#   ╚═╝     ╚═╝╚═╝╚═╝  ╚═╝╚═╝  ╚═╝ ╚═════╝ ╚═╝  ╚═╝   ╚═════╝    ╚═╝   ╚═╝╚══════╝╚══════╝
#   by EWS (Trademark)
#
#   ABOUT
#     This API has many functions that may help you with scripts of
#     various types, like RegEx, number formatting, easy replace,
#     random string, blocks between and some APIs.
#
#   NOTES
#     MirrorUtils is a free resource made for the Skript community. Use and
#     redistribute it freely, but please keep the credits.
#
#   CONTACT
#     For issues (not questions) or script requests, please contact me by:
#     + Discord: EWS#5810
#     + Email: [email protected]
# 
#

import:
	
	# Java
	java.util.HashMap
	java.util.LinkedHashMap
	java.util.Map$Entry
	java.util.TreeMap
	java.util.stream.Collectors
	java.util.regex.Pattern
	java.util.regex.Matcher
	
	java.util.ArrayList
	java.util.Arrays
	
	java.util.Collections
	
	java.lang.System
	java.lang.String
	
	java.text.DecimalFormat
	java.text.DecimalFormatSymbols
	java.util.Locale
	
	# Apache
	org.apache.commons.lang.time.DurationFormatUtils
	org.apache.commons.lang3.RandomStringUtils
	
	# Bukkit
	org.bukkit.inventory.ItemFlag
	org.bukkit.inventory.ItemStack
	org.bukkit.enchantments.Enchantment
	org.bukkit.inventory.meta.ItemMeta
	
	# Skript
	ch.njol.skript.variables.Variables
		
#     ______      _             
#    / __/ /_____(_)__  ___ ____
#   _\ \/ __/ __/ / _ \/ _ `(_-<
#  /___/\__/_/ /_/_//_/\_, /___/
#                     /___/

#
# NEW LINE
# The OG new line from skQuery.
#
# + newline
# > [separator]
#
expression (newline|nl|cr):
	return type: object
	parse:	
		set {_r} to last character of System.getProperty("line.separator")
		continue
	get:
		return {_r}

#
# REGEX MATCHES
# Checks if a string matches a regular expression.
#
# + "123" matches "[^A-Z0-9]"
# > [boolean] false
#
condition %texts% [regex] matches %text%:
	check:
		set {_pattern} to Pattern.compile(expr-2)
		loop exprs-1:
			{_pattern}.matcher(loop-value).find() = false
			stop
		continue
		
#
# REGEX REPLACE
# Replaces a regular expression in a string with another string.
#
# + regex replace "( )+" with " " in "a     retard    used    2 many   spaces" 
# > [list] "a retard used 2 many spaces"
#		
expression regex replace %text% with %text% in %texts%:
	return type: texts
	get:
		loop exprs-3:
			add 1 to {_n}
			set {_r::%{_n}%} to loop-value.replaceAll(expr-1, expr-2)
		return {_r::*}
		
#
# REGEX SPLITS
# Splits a string using a regular expression.
#
# + regex split "something, stuff and other things" at "(, | and )"
# > [list] 1: something, 2: stuff, 3: other things
#
expression regex split %texts% at %text%:
	return type: texts
	get:
		loop exprs-1:
			loop ...loop-value.split(expr-2):
				add 1 to {_n}
				set {_r::%{_n}%} to loop-value-2
		return {_r::*}
		
#
# MATCHER OF STRING
# Gets the regular expression matcher in a string.
# Use it combined with regex groups.
#
# + match "item\((.+?)\)" in "item(diamond_sword) name(some name)"
# > [matcher]
#
expression match[er] %text% (to|in|of|with) %text%:
	return type: object
	get:
		return Pattern.compile(expr-1).matcher(expr-2)
		
#
# REGEX GROUPS OF MATCHER
# Gets the regular expression groups from a matcher.
# A matcher is obtained from the expression above.
#
# + set {_matcher} to match "item\((.+?)\)" in "item(diamond_sword) name(some name)"
# + groups 1 of {_matcher}
# > [list] "diamond_sword"
#
plural expression [regex] group[s] %integer% of [matcher] %object%:
	return type: texts
	get:
		if expr-2 is instance of Matcher:
			expr-2.reset()
			while expr-2.find() = true:
				add 1 to {_n}
				set {_groups::%{_n}%} to expr-2.group(expr-1)
			return {_groups::*}
		else:
			return
		
#
# SUBTEXT
# Gets the subtext of a string. Exactly like Skript's, but for a single argument
#
# + subtext of "abcdefghijk" from 2
# > [text] "bcdefghijk"
#
expression sub(text|string) of %text% (from|char[racter][s]) %integer%:
	return type: text
	get:
		return expr-1.substring(expr-2)
		
# 
# EXACTLY EQUALS
# Checks if a string is equal to another.
# Case sentitive (only reason for it to be here).
#
# + "ABC" equals "abc"
# > [boolean] false
#
expression %text% exactly equals [to] %text%:
	return type: boolean
	get:
		return expr-1.equals(expr-2)

#		
# ARGUMENT AT
# Gets the nth element of texts separated by spaces.
# Useful for on command events.
#
# + argument at 3 of "I am amazing"
# > [text] amazing
#
expression argument [at] %integer% of %text%:
	return type: text
	get:
		return expr-1th element of (regex split expr-2 at "( )+")
		
#
# REPLACER
# Allows you to replace multiple values at once in a string.
# Most useful expression around.
#
# + replacer "<money>" and "<player>" with "%player's balance%" and "%player%" in "Player <player> has <money>!"
# > [text] Player TrademarkTM has $1000.00!
#
expression (multi[ple] replace|replacer) [(elements|values)] %texts% with %objects% in %text%:
	return type: text
	get:
		set {_text} to expr-3
		loop exprs-1:
			add 1 to {_n}
			replace all "%loop-value%" with "%{_n}th element of exprs-2%" in {_text}
		return {_text}
		
#
# RANDOM STRING
# Generates a random string with the length specified.
#
# + random alphanumeric size 20
# > UkGYCR4J04nApGrh8CUQ
#
# + random ascii size 20
# > ?e:e*SmY7&LjIS#7cy#t
#
expression random (1¦alphanumeric|2¦alphabetic|3¦numeric|4¦ascii|5¦graph) [(text|string)] [with] (size|length) %integer%:
	return type: text
	get:
		if parse mark = 1:
			return RandomStringUtils.randomAlphanumeric(expr-1)
		else if parse mark = 2:
			return RandomStringUtils.randomAlphabetic(expr-1)
		else if parse mark = 3:
			return RandomStringUtils.randomNumeric(expr-1)
		else if parse mark = 4:
			return RandomStringUtils.randomAscii(expr-1)
		else:
			return RandomStringUtils.randomGraph(expr-1)

	
#    _  __           __             
#   / |/ /_ ____ _  / /  ___ _______
#  /    / // /  ' \/ _ \/ -_) __(_-<
# /_/|_/\_,_/_/_/_/_.__/\__/_/ /___/
#

#
# SPACED NUMBER
# Returns a string with formatted number.
#
# + spaced 1442361.13 and 1237123.111
# > [list] 1,442,361.13, 1,237,123.11
#
expression spaced %numbers%:
	return type: numbers
	get:
		set {_format} to new DecimalFormat("##,######.####")
		loop exprs-1:
			add 1 to {_n}
			set {_r::%{_n}%} to {_format}.format(loop-value)
		return {_r::*}
		
#
# ORDINAL NUMBER
# Gives you the number with proper formatting (1st, 2nd, 3rd... 22nd, 24th)
#
# + ordinal of 25
# > 25th
#
expression ordinal [of] %integer%:
	return type: text
	parse:
		set {_ordinals::*} to "th", "st", "nd", "rd", "th", "th", "th", "th", "th" and "th"
		continue
	get:
		set {_n} to mod(expr-1, 100)
		if {_n} = 11, 12 or 13:
			return "%expr-1%th"
		else:
			return "%expr-1%%{_ordinals::%{_n}%}%"
	
local effect set variable %object% to %object% in %event%:
	trigger:
		set {_name} to expr-1.getName().toString(expr-3)
		Variables.setVariable({_name}, expr-2, expr-3, expr-1.isLocal())
		
effect %object%(1¦++|2¦--)[%-number%]:
	trigger:
		set {_o} to expr-1
		set {_n} to expr-2 ? 1
		if parse mark = 1:
			set variable (raw expr-1) to ({_o} + {_n}) in event
		else:
			set variable (raw expr-1) to ({_o} - {_n}) in event

#
# SUM PREVIOUS
# Sums all the integers smaller than a number N.
# Useful for shops that increase the price and allow multiple items bought at once.
#
# + sum prev of 5
# > [number] 15 (from 5 + 4 + 3 + 2 + 1)
#
expression sum prev[ious] [numbers] of %integer%:
	return type: integer
	get:
		return expr-1^2 * expr-1/2
		
#
# ROUND TO
# Rounds a number to N decimal places.
#
# + round 341.1298376 to 3 places
# > [number] 341.129
#
expression round %number% to %number% [decimal] [places]:
	return type: numbers
	get:
		return floor((expr-1 * 10^expr-2) + 0.5) / 10^expr-2
		
#
# TOP ELEMENTS
# Sorts a variable directly and returns a list of texts with the format used.
# Considerably more efficient than any other methods of sorting available in Skript.
#
# + top 10 elements of {coins::*} as "<pos>. <index> has <value>" coins
# > [list] "1. player1 has 1000 coins", "2. player2 has 998.2 coins"
#
local expression variable %objects% in %event%:
	return type: object
	get:
		set {_name} to expr-1.getName().toString(expr-2)
		return Variables.getVariable({_name}, expr-2, expr-1.isLocal())

plural expression (1¦(top|first)|2¦(last)) %integer% (values|elements) of %objects% [formatted] as %text%:
	return type: texts
	get:
		set {_map} to variable raw exprs-2 in event
			
		set {_list} to new ArrayList({_map}.entrySet())
		{_list}.sort(Entry.comparingByValue())
		
		if parse mark = 1:
			Collections.reverse({_list})
		
		loop ...{_list}:
			add 1 to {_n}
			set {_r::%{_n}%} to replacer "<pos>", "<index>" and "<value>" with "%{_n}%", "%loop-value.getKey()%" and "%loop-value.getValue()%" in expr-3
			{_n} = expr-1
			stop loop

		return {_r::*}
		
#
# NUMBER TO ROMAN NUMERAL
# Converts a number to a roman numeral.
#
# + 999 to roman numeral
# [text] CMXCIX
#
expression %number% (to|in) roman [numeral]:
	return type: text
	parse:
		set {_roman::*} to "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" 
		continue
	get:
		set {_n} to expr-1
		
		loop 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4 and 1:
			add 1 to {_index}
			while {_n} >= loop-value:
				add 1 to {_next}
				remove loop-value from {_n}
				set {_result::%{_next}%} to {_roman::%{_index}%}
			
		return (join {_result::*} by "") ? "0"
		
#
# IMPROVED BETWEEN
# Checks if a number is between two others.
# Allows < and <=.
#
# + if 1 <= 5 < 10
# > [boolean] true
#
condition %number% (1¦\<|2¦\<=) %number% (3¦\<|4¦\<=) %number%:
	check:
		if parse mark = 2:
			expr-1 < expr-2
			expr-2 < expr-3
			continue
		else if parse mark = 5:
			expr-1 < expr-2
			expr-2 <= expr-3
			continue
		else if parse mark = 1: 
			expr-1 <= expr-2
			expr-2 < expr-3
			continue
		else if parse mark = 6:
			expr-1 <= expr-2
			expr-2 <= expr-3
			continue
			
# 
# NUMBER TO WORDS
# Converts a number into words.
#
# + number 123456 to words
# > [text] one hundred and twenty three thousand, four hundred and fifty six.
#
expression number %number% (to|in) words:
	return type: number
	parse:
		loop 27, 24, 21, 18, 15, 12, 9 and 6:
			add 1 to {_next}
			set {_numbers::%{_next}%} to 10^loop-value
		loop split "1000,100,90,80,70,60,50,40,30,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1" at ",":
			add 1 to {_next}
			set {_numbers::%{_next}%} to loop-value parsed as number
		clear {_next}
		set {_words::*} to split "octillion,septillion,sextillion,quintillion,quadrillion,trillion,billion,million,thousand,hundred,ninety,eighty,seventy,sixty,fifty,fourty,thirty,twenty,nineteen,eighteen,seventeen,sixteen,fifteen,fourteen,thirteen,twelve,eleven,ten,nine,eight,seven,six,five,four,three,two,one" at ","
		continue
	get:
		set {_n} to expr-1
		set {_r} to ""
		loop {_numbers::*}:
			while {_n} >= loop-value:
				add 1 to {_unit}
				remove loop-value from {_n}
			{_unit} is set
			add 1 to {_index}
			
			if {_unit} = 1:
				if loop-value < 100:
					set {_r::%{_index}%} to "%{_words::%loop-index%}%"
				else:
					set {_r::%{_index}%} to "one %{_words::%loop-index%}%,"
			else:
				set {_r::%{_index}%} to "%number {_unit} to words% %{_words::%loop-index%}%,"

			clear {_unit}
		return regex replace "(,)([^,]*)$" with " and$2" in join {_r::*} by " "
		
#
# FORMATTED NUMBER
# Formats a number using symbols to indicate base 10 exponents (k, M, B).
#
# + formatted 12345 rounded to 2
# > [text] 12.34k
#
expression formatted %number% [round[ed] to %-number%]:
	return type: text
	parse:
		loop 18, 15, 12, 9, 6 and 3:
			add 1 to {_n}
			set {_numbers::%{_n}%} to 10^loop-value
		set {_names::*} to "QT", "Q", "T", "B", "M" and "k"
		continue
	get:
		set {_value} to expr-1
		set {_round} to expr-2 ? 1
		loop {_numbers::*}:
			expr-1 >= loop-value
			return "%round ({_value} / loop-value) to {_round}%%{_names::%loop-index%}%"
		return expr-1
		
#
# PI
# pi
#
# > pi
# > [number] pi (the value)
#
expression pi:
	return type: number
	get:
		return 3.14592653589
		
#   _______          
#  /_  __(_)_ _  ___ 
#   / / / /  ' \/ -_)
#  /_/ /_/_/_/_/\__/
#  

#
# TIME SINCE
# Returns the time (seconds) since a unix timestamp.
#
# + time since unix timestamp of now
# > [number] 0
#
expression time since %number%:
	return type: number
	get:
		return unix timestamp of now - expr-1
		
#
# TEXT TO SECONDS
# Parses timespans like 1d10h10s.
# Incredibly useful for temporary bans/mutes...
#
# + text "9d4h10m" in seconds
# > [number] 792000
#
expression %text% (to|in) seconds:
	return type: number
	get:
		set {_matcher} to match "([0-9]{1,})([^0-9])+" in expr-1
		set {_times::*} to groups 2 of {_matcher}
		
		loop groups 1 of {_matcher}:
			add 1 to {_n}
			set {_value} to "%loop-value%" parsed as number
			if {_times::%{_n}%} = "year" or "y":
				add (31104000 * {_value}) to {_r}
			else if {_times::%{_n}%} = "month" or "m":
				add (2592000 * {_value}) to {_r}
			else if {_times::%{_n}%} = "week" or "w":
				add (604800 * {_value}) to {_r}
			else if {_times::%{_n}%} = "day" or "d":
				add (86400 * {_value}) to {_r}
			else if {_times::%{_n}%} = "hour" or "h":
				add (3600 * {_value}) to {_r}
			else if {_times::%{_n}%} = "min" or "m":
				add (60 * {_value}) to {_r}
			else if {_times::%{_n}%} = "sec" or "s":
				add {_value} to {_r}
		return {_r} ? 0
		
#
# FORMAT SECONDS
# Uses an util to change seconds into any format you want.
# Check https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/time/DurationFormatUtils.html.
#
# + format 10000 into "y 'years', M 'months', d 'days', H 'hours', m 'minutes', s 'seconds', S 'milliseconds'"
# > 0 years, 0 months, 0 days, 2 hours, 46 minutes, 40 seconds
#
expression format %number% (into|as) %text%:
	return type: text
	get:
		return DurationFormatUtils.formatDuration((expr-1 * 1000), expr-2)
		
#
# CURRENT MILLISECONDS
# Returns the current time, in milliseconds.
#
# + current ms
# > [number] 1543940812663
# 
expression [current] m[illi]s[econds]:
	get:
		return System.currentTimeMillis()
		
#    __                 __  _         
#   / /  ___  _______ _/ /_(_)__  ___ 
#  / /__/ _ \/ __/ _ `/ __/ / _ \/ _ \
# /____/\___/\__/\_,_/\__/_/\___/_//_/
# 		

#
# DIRECTION NAME
# Returns the first letter of the direction of a location. (N, S, E, W)
# Use "with cardinals" to include SW, NW, NE and SE.
#
# + direction name of player's location with cardinals
# [text] NW
#
expression direction name of %location% [(1¦with cardinals)]:
	return type: text
	get:
		set {_yaw} to yaw of expr-1
		if parse mark = 1:
			set {_directions::*} to "S", "SW", "W", "NW", "N", "NE", "E" and "SE" 
			set {_values::*} to 30, 60, 120, 150, 210, 240, 300 and 330
		else:
			set {_directions::*} to "S", "W", "N", "E"
			set {_values::*} to 45, 135, 225 and 315
		loop {_values::*}:
			{_yaw} < loop-value
			return {_directions::%loop-index%}
		return "S"
		
#
# BLOCKS FROM A TO B
# Gets the blocks between two locations.
#
# + blocks from player's location to player's targeted block
# [blocks] (loopable list)
#
# + set blocks from {pos1} to {pos2} to diamond block
# [sets the blocks]
#
plural expression blocks from %location% (to|and) %location%:
	loop of: block
	return type: blocks
	get:
	
		set {_1} to expr-1
		set {_2} to expr-2
		
		set {_x} to 1
		set {_y} to 1
		set {_z} to 1
		
		if x coord of {_1} > x coord of {_2}:
			set {_x} to -1
		if y coord of {_1} > y coord of {_2}:
			set {_y} to -1
		if z coord of {_1} > z coord of {_2}:
			set {_z} to -1
		
		set {_base1} to {_1}
		loop abs(x coord of {_1} - x coord of {_2}) + 1 times:
			loop abs(z coord of {_1} - z coord of {_2}) + 1 times:
				loop abs(y coord of {_1} - y coord of {_2}) + 1 times:
		
					add 1 to {_next}
					set {_b::%{_next}%} to block at {_1}
				
					add {_y} to y coord of {_1}
			
				add {_z} to z coord of {_1}
				set y coord of {_1} to y coord of {_base1}
		
			add {_x} to x coord of {_1}
			set z coord of {_1} to z coord of {_base1}
		return {_b::*}
		
	set:
		loop blocks from expr-1 and expr-2:
			set block at loop-value to change value
			
#    ______              
#   /  _/ /____ __ _  ___
#  _/ // __/ -_)  ' \(_-<
# /___/\__/\__/_/_/_/___/
#

#
# ITEM WITH LORE
# Returns an item with the lore specified.
#
# + diamond sword with lore "ABC||DEF"
# > [item] diamond_sword
#
expression %item% with lore %text%:
	return type: item
	get:
		set {_i} to expr-1.clone()
		set {_meta} to {_i}.getItemMeta()
		{_meta}.setLore(Arrays.asList(split expr-2 at "||"))
		{_i}.setItemMeta({_meta})
		return {_i}
		
#
# HIDE FLAGS
# Hides flags of an item. Examples:
# When on body: +5 armor
# When in main hand: 1.6 attack speed
#
# Use "ALL" to hide all the flags.
#
# + diamond sword with hideflags "ATTRIBUTES", "DESTROYS", "ENCHANTS", "PLACED_ON", "POTION_EFFECTS" and "UNBREAKABLE"
# > [item] diamond_sword
#
expression %item% with [(item|hidden|hide)][ ]flags %texts%:
	return type: item
	get:
		if expr-1 = air:
			return
		else:
			set {_meta} to expr-1.getItemMeta()
			if 1st element of exprs-2 = "ALL":
				{_meta}.addItemFlags(ItemFlag.values())
			else:
				loop exprs-2:
					set {_flag} to try ItemFlag.valueOf("HIDE_%loop-value%" in upper case)
					{_flag} is set
					add 1 to {_n}
					set {_flags::%{_n}%} to {_flag}
				{_meta}.addItemFlags([{_flags::*} as ItemFlag])
			expr-1.setItemMeta({_meta})
			return expr-1
			
#
# ITEM OF ENCHANTMENTS
# Exactly like Skript's expression, but works for variables.
# 
# + player's tool of sharpness 5, unbreaking 3 and fire aspect 2
# > [item]
#
expression %item% of %enchantmenttypes%:
	return type: item
	get:
		set {_i} to expr-1.clone()
		loop exprs-2:
			set {_e} to loop-value
			enchant {_i} with {_e}
		return {_i}
			
#
# GLOWING ITEM
# Returns a glowing item (glows like it's enchanted, but doesn't show any).
#
# + glowing diamond sword
# > [item]
# 
expression glowing %items%:
	return type: items
	get:
		loop exprs-1:
			add 1 to {_n}
			set {_i} to loop-value
			set {_r::%{_n}%} to {_i} of lure 1 with hideflags "ENCHANTS"
		return {_r::*}
		
#
# ITEM'S META
# Returns the meta of an item.
#
# + meta of player's tool
# > [meta]
#
expression:
	patterns:
		meta of %item%
		%item%'s meta
	get:
		return expr-1.getItemMeta()
	set:
		change value is instance of ItemMeta
		expr-1.setItemMeta(change value)
		
#    ___  __                 
#   / _ \/ /__ ___ _____ ____
#  / ___/ / _ `/ // / -_) __/
# /_/  /_/\_,_/\_, /\__/_/   
#             /___/
		
#
# ENTITY HAS POTIONS
# Continues if the entity has those enchants in their respective levels.
#
# + player has speed and strength levels 1 and 2
# > [condition] passes
#
condition %livingentity% has [potion] [effect[s]] %potiontypes% [level[s]] [%-integers%]:
	check:
		set {_s} to size of {_effects::*}
		
		loop exprs-2:
			add 1 to {_n}
			loop ...expr-1.getActivePotionEffects():
				loop-value-2.getType() = loop-value-1
				if exprs-3 is not set:
					add 1 to {_has}
				else:
					loop-value-2.getAmplifier() + 1 = {_n}th element of exprs-3
					add 1 to {_has}
			{_s} + {_has} != {_s} + {_n}
			stop
		{_has} = {_s}
		continue
		
#
# DURATION OF POTION
# Returns the duration (in seconds) of that potion in an entity.
#
# > duration of speed of player
# + [number] 120
# 
expression duration of [potion] [effect] %potiontype% (on|of) %livingentity%:
	return type: number
	get:
		return (expr-2.getPotionEffect(expr-1).getDuration() ? 0) / 20
		
#
# TIER OF POTION
# Returns the level of the potion applied to an entity.
#
# > tier of strength on player's targeted entity
# + [number] 2
#
expression tier of [potion] [effect] %potiontype% (on|of) %livingentity%:
	return type: number
	get:
		return (expr-2.getPotionEffect(expr-1) ? -1) + 1