Other available versions. Ordered by newest to oldest versions:
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.
options:
enable: true
enable-recipebook: true
recipebook-register-delay: 1 tick
enable-suggestions: true
suggestions-permission: fancywb.suggestion
import:
java.util.HashMap
org.bukkit.Bukkit
org.bukkit.event.inventory.InventoryDragEvent
org.bukkit.inventory.Recipe
org.bukkit.inventory.ShapedRecipe
org.bukkit.inventory.ShapelessRecipe
org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack
net.minecraft.world.inventory.InventoryCrafting
net.minecraft.world.inventory.ContainerWorkbench
net.minecraft.world.entity.player.PlayerInventory
net.minecraft.world.item.crafting.Recipes
function initWorkbench(p: player):
set metadata tag "fancyTable" of {_p} to chest inventory with 8 rows named "Craft Item"
set slots (integers between 0 and 44) of metadata tag "fancyTable" of {_p} to black stained glass pane named "&0"
set slots (integers between 45 and 53) of metadata tag "fancyTable" of {_p} to red stained glass pane named "&0"
set slots (49 and (23 if {@enable-suggestions} is true, else 24)) of metadata tag "fancyTable" of {_p} to barrier named "&cClose" and getInvalidRecipeItem()
set slots (10, 11, 12, 19, 20, 21, 28, 29 and 30) of metadata tag "fancyTable" of {_p} to air
set slots (16, 25, 34) of metadata tag "fancyTable" of {_p} to getEmptySuggestionItem({_p}) if {@enable-suggestions} is true
set metadata tag "fancyContainer" of {_p} to new InventoryCrafting((new ContainerWorkbench(-1, new PlayerInventory(null))), 3, 3, null)
function resetWorkbench(p: player):
set slot (integers between 45 and 53) of metadata tag "fancyTable" of {_p} to red stained glass pane named "&0"
set slots (49 and (23 if {@enable-suggestions} is true, else 24)) of metadata tag "fancyTable" of {_p} to barrier named "&cClose" and getInvalidRecipeItem()
set slots (10, 11, 12, 19, 20, 21, 28, 29 and 30) of metadata tag "fancyTable" of {_p} to air
set slots (16, 25, 34) of metadata tag "fancyTable" of {_p} to getEmptySuggestionItem({_p}) if {@enable-suggestions} is true
function openWorkbench(p: player):
resetWorkbench({_p})
open (metadata tag "fancyTable" of {_p}) to {_p}
if {@enable-suggestions} is true:
delete (metadata tag "suggestions" of {_p})
displaySuggestions({_p}) if {_p} has permission "{@suggestions-permission}"
function getInvalidRecipeItem() :: item:
return (knowledge book if {@enable-recipebook} is true, else barrier) named "&cRecipe Required" with lore "&7Add the items for a valid recipe", "&7in the crafting grid to the", "&7left!" and (("", "&eClick to view Recipe Book!") if {@enable-recipebook} is true, else {_})
function getEmptySuggestionItem(p: player) :: item:
return (gray stained glass pane if {_p} has permission "{@suggestions-permission}", else red stained glass pane) named "&cQuick Crafting Slot" with lore "&7Quick crafting allows you to", "&7craft items without assembling", "&7the recipe." and ("" and "&cRequires &aVIP &cor higher!" if {_p} doesn't have permission "{@suggestions-permission}", else {_})
function updateWorkbench(p: player):
wait a tick
set {_ic} to metadata tag "fancyContainer" of {_p}
loop (10, 11, 12, 19, 20, 21, 28, 29 and 30):
add 1 to {_c}
{_ic}.a({_c} - 1, CraftItemStack.asNMSCopy(random item of (slot loop-value ? {_} of (metadata tag "fancyTable" of {_p}))))
set {_optional} to Bukkit.getServer().getHandle().b().aB.b().e().a(Recipes.a, {_ic}, null)
if {_optional}.isPresent():
set {_itemStack} to CraftItemStack.asBukkitCopy({_optional}.get().a({_ic}))
set lore of {_itemStack} to lore of {_itemStack}, "&8&l&m-----------------", "&7This is the item you are" and "&7crafting."
set slot (23 if {@enable-suggestions} is true, else 24) of (metadata tag "fancyTable" of {_p}) to {_itemStack}
set slot (integers between 45 and 53) of metadata tag "fancyTable" of {_p} to (light green stained glass pane named "&0")
set slot 49 of metadata tag "fancyTable" of {_p} to barrier named "&cClose"
else:
set slot (integers between 45 and 53) of metadata tag "fancyTable" of {_p} to red stained glass pane named "&0"
set slots (49 and (23 if {@enable-suggestions} is true, else 24)) of metadata tag "fancyTable" of {_p} to barrier named "&cClose" and getInvalidRecipeItem()
function craftWorkbench(p: player, click: click type):
set {_result} to slot (23 if {@enable-suggestions} is true, else 24) of metadata tag "fancyTable" of {_p}
loop integers between 0 and 2:
clear line ((size of lore of {_result}) - loop-value) of lore of {_result}
if "%{_click}%" is "left mouse button" or "right mouse button" or "double click using mouse":
((item amount of cursor slot of {_p}) + (item amount of {_result})) <= {_result}.getMaxStackSize()
if 1 of {_p}'s cursor slot is 1 of {_result}:
add (item amount of {_result}) to item amount of {_p}'s cursor slot
removeItems({_p}, 1)
else if type of {_p}'s cursor slot is air:
set cursor slot of {_p} to {_result}
removeItems({_p}, 1)
else if "%{_click}%" is "left mouse button with shift" or "right mouse button with shift":
loop (10, 11, 12, 19, 20, 21, 28, 29, 30):
slot loop-value ? {_} of metadata tag "fancyTable" of {_p} is not air
set {_amounts::%loop-value%} to item amount of slot loop-value ? {_} of metadata tag "fancyTable" of {_p}
set {_amount} to (item amount of {_result}) * min({_amounts::*})
while {_p} doesn't have enough space for {_amount} of {_result}:
subtract item amount of {_result} from {_amount}
give {_amount} of {_result} to {_p}
removeItems({_p}, {_amount} / (item amount of {_result}))
if {@enable-suggestions} is true:
displaySuggestions({_p}) if {_p} has permission "{@suggestions-permission}"
function removeItems(p: player, count: numbers) :: object:
loop (10, 11, 12, 19, 20, 21, 28, 29, 30):
add 1 to {_c}
set item amount of slot loop-value ? {_} of metadata tag "fancyTable" of {_p} to (item amount of slot loop-value ? {_} of metadata tag "fancyTable" of {_p}) - ({_count::%{_c}%} ? {_count::1})
function refreshRecipes():
set {recipeMap} to new HashMap()
set {recipeBook} to new HashMap()
set {suggestionMap} to new HashMap()
set {_recipeIterator} to Bukkit.recipeIterator()
create section stored in {_recipeRefresh}:
while {_recipeIterator}.hasNext():
set {_recipe} to {_recipeIterator}.next()
sum(1 if {_recipe} is instance of ShapedRecipe, else 0, 1 if {_recipe} is instance of ShapelessRecipe, else 0) > 0
add 1 to {_c}
{recipeMap}.put({_c}, {_recipe})
{@enable-suggestions} is true
set {_ingredients::*} to getRecipeItems({_recipe}) where [type of input is not air]
set {_sumStorage} to chest inventory with 1 row
add {_ingredients::*} to {_sumStorage}
set {_sumIngredients::*} to slots (integers between 0 and 8) of {_sumStorage} where [type of input is not air]
clear {_ingredientsKeys::*}
loop {_sumIngredients::*}:
set {_ingredientsKeys::%loop-value%} to name of loop-value ? raw name of loop-value
set {_suggestionMapWriter} to {suggestionMap}
loop (alphabetically sorted {_ingredientsKeys::*}):
{_suggestionMapWriter}.put(loop-value, new HashMap()) if {_suggestionMapWriter}.get(loop-value) is not set
set {_suggestionMapWriter} to {_suggestionMapWriter}.get(loop-value)
{_suggestionMapWriter}.put({_recipe}.hashCode(), {_recipe})
run section {_recipeRefresh} async and wait
function displaySuggestions(p: player):
create section with {_p} stored in {_displaySuggestions}:
set {_suggestions::*} to getSuggestedRecipes({_p})
set {_oldSuggestions::*} to ...(metadata tag "suggestions" of {_p})
loop {_oldSuggestions::*}:
add (1 if loop-value is {_suggestions::%loop-index%}, else -1) to {_c}
stop trigger if {_c} is size of {_suggestions::*}
set metadata tag "suggestions" of {_p} to [{_suggestions::*}]
set {_suggestionsSlots::*} to (16, 25, 34)
set slots {_suggestionsSlots::*} of metadata tag "fancyTable" of {_p} to getEmptySuggestionItem({_p})
loop {_suggestions::*}:
set {_itemStack} to loop-value.getResult()
set {_ingredients::*} to getRecipeItems(loop-value) where [type of input is not air]
set {_sumStorage} to chest inventory with 1 row
add {_ingredients::*} to {_sumStorage}
set {_sumIngredients::*} to slots (integers between 0 and 8) of {_sumStorage} where [type of input is not air]
add "&0", "&9Ingredients:" to lore of {_itemStack}
loop {_sumIngredients::*}:
add "&7%item amount of loop-value-2%x %name of loop-value-2 ? proper case (raw name of loop-value-2).replace("minecraft:", "").replace("_", " ")%" to lore of {_itemStack}
add "&0" and "&eClick to craft!" to lore of {_itemStack}
set slot {_suggestionsSlots::%loop-index%} of metadata tag "fancyTable" of {_p} to {_itemStack}
run section {_displaySuggestions} async with {_p}
function getSuggestedRecipes(p: player, count: number = 3) :: objects:
set {_tableContents::*} to slots (10, 11, 12, 19, 20, 21, 28, 29 and 30) of metadata tag "fancyTable" of {_p}
set {_playerItems::*} to ({_tableContents::*}, all items in {_p}'s inventory, cursor slot of {_p}) where [type of input is not air]
return {_} if size of {_playerItems::*} is 0
loop {_playerItems::*}:
set {_playerItemsKeys::%name of loop-value ? raw name of loop-value%} to name of loop-value ? raw name of loop-value
set {_sortedPlayerItemsKeys::*} to alphabetically sorted {_playerItemsKeys::*}
set {_c} to 0
set {_sumStorage} to chest inventory with 1 row
set {_playerInventoryCopy} to chest inventory with 1 row
add {_playerItems::*} to {_playerInventoryCopy}
set {_suggestionMapReader::%{_c}%} to {suggestionMap}
while true is true:
loop {_suggestionMapReader::*}:
set {_recipes::*} to ...(loop-value).values() where [input is instance of Recipe]
loop {_recipes::*}:
set slots (integers between 0 and 8) of {_sumStorage} to air
add getRecipeItems(loop-value-2) to {_sumStorage}
set {_sumIngredients::*} to slots (integers between 0 and 8) of {_sumStorage} where [type of input is not air]
set {_suggestions::%loop-value-2.hashCode()%} to loop-value-2 if {_playerInventoryCopy} has {_sumIngredients::*}
return {_suggestions::*} if size of {_suggestions::*} is {_count}
loop {_sortedPlayerItemsKeys::*}:
add 1 to {_c}
set {_suggestionMapReader::%{_c}%} to (loop-value-1).get(loop-value-2)
delete {_suggestionMapReader::%loop-index%}
exit this section if size of {_suggestionMapReader::*} is 0
return {_suggestions::*}
function openRecipeBook(p: player, page: number = 1):
set {_page} to round({_page})
if {recipeBook}.get({_page}) is not set:
set {_gui} to chest inventory with 8 rows named "Recipe Book (Page %{_page}%)"
set slots (integers between 0 and 44) of {_gui} to light gray stained glass pane named "&0"
set slots ((integers between 0 and 9), 18, 27, 36, 45, 17, 26, 35, (integers between 44 and 53)) of {_gui} to black stained glass pane named "&0"
set slots (45, 49 and 53) of {_gui} to (arrow named "&aPage %{_page} - 1%" if {_page} > 1, else black stained glass pane named "&0"), barrier named "&cClose" and (arrow named "&aPage %{_page} + 1%" if {recipeMap}.size() > {_page} * 28, else black stained glass pane named "&0")
{recipeBook}.put({_page}, {_gui})
create section with {_gui}, {_page} stored in {_loadRecipes}:
set {_offset} to ({_page} - 1) * 28
loop (integers between 10 and 16), (integers between 19 and 25), (integers between 28 and 34) and (integers between 37 and 43):
add 1 to {_c}
set {_itemStack} to {recipeMap}.get(({_offset} + {_c}).longValue()).getResult()
exit loop if {_itemStack} is not set
set lore of {_itemStack} to lore of {_itemStack}, "&8&l&m-----------------", "&7Click to veiw recipe" and "&7for &e%name of {_itemStack} ? proper case (raw name of {_itemStack}).replace("minecraft:", "").replace("_", " ")%"
set slot loop-number ? {_} of {_gui} to {_itemStack}
run section {_loadRecipes} async with {_gui} and {_page}
open {recipeBook}.get({_page}) to {_p}
function getRecipeItems(recipe: object) :: objects:
loop 9 times:
set {_items::%loop-value%} to air
if {_recipe} is instance of ShapedRecipe:
loop ...{_recipe}.getShape():
set {_recipeLine} to loop-value
while length of {_recipeLine} is not 3:
set {_recipeLine} to join {_recipeLine} and "-"
set {_recipeLines} to join {_recipeLines} and {_recipeLine}
set {_shape::*} to (split {_recipeLines} at "") where [length of input > 0]
loop 9 times:
set {_items::%loop-value%} to {_recipe}.getIngredientMap().get({_shape::%loop-value%}.charAt(0)) ? air
else if {_recipe} is instance of ShapelessRecipe:
set {_c} to 0
loop reversed ...{_recipe}.getIngredientList():
add 1 to {_c}
set {_items::%{_c}%} to loop-value
return {_items::*}
on InventoryDragEvent:
updateWorkbench(event.getWhoClicked()) if event.getWhoClicked()'s current inventory is (metadata tag "fancyTable" of event.getWhoClicked())
on inventory click:
updateWorkbench(player) if player's current inventory is (metadata tag "fancyTable" of player)
event-inventory is not inventory of player
if event-inventory is (metadata tag "fancyTable" of player):
cancel event if (10, 11, 12, 19, 20, 21, 28, 29, 30) doesn't contain index of event-slot
close player's inventory if index of event-slot is 49
if (index of event-slot) is (23 if {@enable-suggestions} is true, else 24):
if event-slot is not getInvalidRecipeItem():
craftWorkbench(player, click type)
else:
openRecipeBook(player) if {@enable-recipebook} is true
if (16, 25, 34) contains index of event-slot:
{@enable-suggestions} is true
set {_recipe} to (metadata tag "suggestions" of player)[mod(index of event-slot, 8)]
set {_sumStorage} to chest inventory with 1 row
add getRecipeItems({_recipe}) to {_sumStorage}
set {_sumIngredients::*} to slots (integers between 0 and 8) of {_sumStorage} where [type of input is not air]
player has {_sumIngredients::*}
set {_result} to {_recipe}.getResult()
if "%click type%" is "left mouse button" or "right mouse button" or "double click using mouse":
((item amount of cursor slot of player) + (item amount of {_result})) <= {_result}.getMaxStackSize()
if 1 of player's cursor slot is 1 of {_result}:
add (item amount of {_result}) to item amount of player's cursor slot
remove {_sumIngredients::*} from player
else if type of player's cursor slot is air:
set cursor slot of player to {_result}
remove {_sumIngredients::*} from player
displaySuggestions(player)
else if "%click type%" is "left mouse button with shift" or "right mouse button with shift":
while player has {_sumIngredients::*}:
exit this section if player doesn't have enough space for {_result}
remove {_sumIngredients::*} from player
give {_result} to player
displaySuggestions(player)
if name of event-inventory partially matches "Recipe Book \(Page [0-9]+\)":
cancel event
set {_recipeSlots::*} to (integers between 10 and 16), (integers between 19 and 25), (integers between 28 and 34) and (integers between 37 and 43)
openWorkbench(player) if index of event-slot is 49
if type of event-slot is arrow:
set {_page} to first element of ((name of event-slot parsed as "&aPage %number%") and 1)
openRecipeBook(player, {_page}) if index of event-slot is 45 or 53
if {_recipeSlots::*} contains index of event-slot:
set {_page} to first element of ((name of event-inventory parsed as "Recipe Book \(Page %number%\)") and 1)
event-slot is not light gray stained glass pane named "&0"
set metadata tag "lastPage" of player to {_page}
set {_gui} to chest inventory with 8 rows named "Preview recipe for: %name of event-slot ? proper case (raw name of event-slot).replace("minecraft:", "").replace("_", " ")%"
set slots (integers between 0 and 53) of {_gui} to black stained glass pane named "&0"
set slot 49 of {_gui} to barrier named "&cClose"
set {_offset} to ({_page} - 1) * 28
loop {_recipeSlots::*}:
add 1 to {_c}
exit loop if loop-value is index of event-slot
set {_recipe} to {recipeMap}.get(({_offset} + {_c}).longValue())
set {_recipeDisplaySlots::*} to (10, 11, 12, 19, 20, 21, 28, 29 and 30)
set slots {_recipeDisplaySlots::*} of {_gui} to light gray stained glass pane named "&0"
create section with {_recipe}, {_recipeDisplaySlots::*} stored in {_loadIngredients}:
set {_items::*} to getRecipeItems({_recipe})
loop {_recipeDisplaySlots::*}:
set slot loop-value of {_gui} to {_items::%loop-index%} if type of {_items::%loop-index%} is not air, else light gray stained glass pane named "&0"
run section {_loadIngredients} async with {_recipe} and {_recipeDisplaySlots::*}
set slot 24 of {_gui} to {_recipe}.getResult()
open {_gui} to player
if name of event-inventory partially matches "Preview recipe for: ":
cancel event
openRecipeBook(player, metadata tag "lastPage" of player) if index of event-slot is 49
on inventory close:
player's current inventory is (metadata tag "fancyTable" of player)
set {_v} to (vector from yaw player's yaw and pitch player's pitch) ** (vector(0.3, 0.3, 0.3))
loop (10, 11, 12, 19, 20, 21, 28, 29 and 30):
if player has enough space for (slot loop-value ? {_} of (metadata tag "fancyTable" of player)):
give (slot loop-value ? {_} of (metadata tag "fancyTable" of player)) to player
else:
drop (slot loop-value ? {_} of (metadata tag "fancyTable" of player)) 1 above player's location
set velocity of last dropped item to {_v}
on rightclick on crafting table:
stop trigger if {@enable} is false
stop trigger if player is sneaking
cancel event
openWorkbench(player)
on join:
initWorkbench(player)
on load:
stop trigger if {@enable} is false
loop all players:
initWorkbench(loop-player)
wait {@recipebook-register-delay}
refreshRecipes() if sum(1 if {@enable-recipebook} is true, else 0, 1 if {@enable-suggestions} is true, else 0) > 0
on unload:
loop all players:
close loop-player's inventory if loop-player's current inventory is (metadata tag "fancyTable" of loop-player)
close loop-player's inventory if name of (loop-player's current inventory) partially matches "Recipe Book \(Page [0-9]+\)"
close loop-player's inventory if name of (loop-player's current inventory) partially matches "Preview recipe for: "
delete {recipeMap}, {recipeBook} and {suggestionMap}