[{"data":1,"prerenderedAt":1207},["ShallowReactive",2],{"wiki-nav":3,"wiki-\u002Fwiki\u002Fdevelopers\u002Fapi":238,"wiki-surround-\u002Fwiki\u002Fdevelopers\u002Fapi":1136,"wiki-meta:\u002Fwiki\u002Fdevelopers\u002Fapi":1139,"wiki-sidebar":1141},[4],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"Wiki","i-lucide-book","\u002Fwiki","wiki",[10,13,40,84,88,110,114,155,159,197,212,234],{"title":11,"path":7,"stem":12},"Wiki home","wiki\u002Findex",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":39},"About","i-lucide-info","\u002Fwiki\u002Fabout","wiki\u002Fabout",[19,23,27,31,35],{"title":20,"path":21,"stem":22},"Credits","\u002Fwiki\u002Fabout\u002Fcredits","wiki\u002Fabout\u002Fcredits",{"title":24,"path":25,"stem":26},"External connections","\u002Fwiki\u002Fabout\u002Fexternal-connections","wiki\u002Fabout\u002Fexternal-connections",{"title":28,"path":29,"stem":30},"Locale and translations","\u002Fwiki\u002Fabout\u002Flocale","wiki\u002Fabout\u002Flocale",{"title":32,"path":33,"stem":34},"Placeholders","\u002Fwiki\u002Fabout\u002Fplaceholders","wiki\u002Fabout\u002Fplaceholders",{"title":36,"path":37,"stem":38},"Why LuckPerms?","\u002Fwiki\u002Fabout\u002Fwhy-luckperms","wiki\u002Fabout\u002Fwhy-luckperms",false,{"title":41,"icon":42,"path":43,"stem":44,"children":45},"Commands","i-lucide-terminal","\u002Fwiki\u002Fcommands","wiki\u002Fcommands\u002Findex",[46,48,52,56,60,64,68,72,76,80],{"title":47,"path":43,"stem":44},"Command usage",{"title":49,"path":50,"stem":51},"General commands","\u002Fwiki\u002Fcommands\u002Fgeneral","wiki\u002Fcommands\u002Fgeneral",{"title":53,"path":54,"stem":55},"Group commands","\u002Fwiki\u002Fcommands\u002Fgroup","wiki\u002Fcommands\u002Fgroup",{"title":57,"path":58,"stem":59},"Log commands","\u002Fwiki\u002Fcommands\u002Flog","wiki\u002Fcommands\u002Flog",{"title":61,"path":62,"stem":63},"Meta commands","\u002Fwiki\u002Fcommands\u002Fmeta","wiki\u002Fcommands\u002Fmeta",{"title":65,"path":66,"stem":67},"Parent commands","\u002Fwiki\u002Fcommands\u002Fparent","wiki\u002Fcommands\u002Fparent",{"title":69,"path":70,"stem":71},"Permission commands","\u002Fwiki\u002Fcommands\u002Fpermission","wiki\u002Fcommands\u002Fpermission",{"title":73,"path":74,"stem":75},"Permissions reference","\u002Fwiki\u002Fcommands\u002Fpermissions","wiki\u002Fcommands\u002Fpermissions",{"title":77,"path":78,"stem":79},"Track commands","\u002Fwiki\u002Fcommands\u002Ftrack","wiki\u002Fcommands\u002Ftrack",{"title":81,"path":82,"stem":83},"User commands","\u002Fwiki\u002Fcommands\u002Fuser","wiki\u002Fcommands\u002Fuser",{"title":85,"path":86,"stem":87},"Configuration","\u002Fwiki\u002Fconfiguration","wiki\u002Fconfiguration",{"title":89,"icon":90,"path":91,"stem":92,"children":93,"page":39},"Developers","i-lucide-code","\u002Fwiki\u002Fdevelopers","wiki\u002Fdevelopers",[94,98,102,106],{"title":95,"path":96,"stem":97},"Developer API","\u002Fwiki\u002Fdevelopers\u002Fapi","wiki\u002Fdevelopers\u002Fapi",{"title":99,"path":100,"stem":101},"API usage","\u002Fwiki\u002Fdevelopers\u002Fapi-usage","wiki\u002Fdevelopers\u002Fapi-usage",{"title":103,"path":104,"stem":105},"Contributing","\u002Fwiki\u002Fdevelopers\u002Fcontributing","wiki\u002Fdevelopers\u002Fcontributing",{"title":107,"path":108,"stem":109},"Standalone app and REST API","\u002Fwiki\u002Fdevelopers\u002Fstandalone-rest","wiki\u002Fdevelopers\u002Fstandalone-rest",{"title":111,"path":112,"stem":113},"FAQ","\u002Fwiki\u002Ffaq","wiki\u002Ffaq",{"title":115,"icon":116,"path":117,"stem":118,"children":119,"page":39},"Features","i-lucide-sparkles","\u002Fwiki\u002Ffeatures","wiki\u002Ffeatures",[120,124,128,132,136,140,151],{"title":121,"path":122,"stem":123},"Context","\u002Fwiki\u002Ffeatures\u002Fcontext","wiki\u002Ffeatures\u002Fcontext",{"title":125,"path":126,"stem":127},"Default groups","\u002Fwiki\u002Ffeatures\u002Fdefault-groups","wiki\u002Ffeatures\u002Fdefault-groups",{"title":129,"path":130,"stem":131},"Prefixes, suffixes and meta","\u002Fwiki\u002Ffeatures\u002Fprefixes-suffixes-meta","wiki\u002Ffeatures\u002Fprefixes-suffixes-meta",{"title":133,"path":134,"stem":135},"Tracks","\u002Fwiki\u002Ffeatures\u002Ftracks","wiki\u002Ffeatures\u002Ftracks",{"title":137,"path":138,"stem":139},"Verbose","\u002Fwiki\u002Ffeatures\u002Fverbose","wiki\u002Ffeatures\u002Fverbose",{"title":141,"path":142,"stem":143,"children":144},"Web Editor","\u002Fwiki\u002Ffeatures\u002Fweb-editor","wiki\u002Ffeatures\u002Fweb-editor\u002Findex",[145,147],{"title":146,"path":142,"stem":143},"Web editor",{"title":148,"path":149,"stem":150},"Web editor technical details","\u002Fwiki\u002Ffeatures\u002Fweb-editor\u002Ftechnical","wiki\u002Ffeatures\u002Fweb-editor\u002Ftechnical",{"title":152,"path":153,"stem":154},"Weight","\u002Fwiki\u002Ffeatures\u002Fweight","wiki\u002Ffeatures\u002Fweight",{"title":156,"path":157,"stem":158},"Getting started","\u002Fwiki\u002Fgetting-started","wiki\u002Fgetting-started",{"title":160,"icon":161,"path":162,"stem":163,"children":164,"page":39},"Guides","i-lucide-map","\u002Fwiki\u002Fguides","wiki\u002Fguides",[165,169,173,177,181,185,189,193],{"title":166,"path":167,"stem":168},"Argument-based command permissions","\u002Fwiki\u002Fguides\u002Fargument-permissions","wiki\u002Fguides\u002Fargument-permissions",{"title":170,"path":171,"stem":172},"Bulk editing","\u002Fwiki\u002Fguides\u002Fbulk-editing","wiki\u002Fguides\u002Fbulk-editing",{"title":174,"path":175,"stem":176},"Extensions","\u002Fwiki\u002Fguides\u002Fextensions","wiki\u002Fguides\u002Fextensions",{"title":178,"path":179,"stem":180},"Migration","\u002Fwiki\u002Fguides\u002Fmigration","wiki\u002Fguides\u002Fmigration",{"title":182,"path":183,"stem":184},"Prefix and suffix stacking","\u002Fwiki\u002Fguides\u002Fprefix-stacking","wiki\u002Fguides\u002Fprefix-stacking",{"title":186,"path":187,"stem":188},"Storage system errors","\u002Fwiki\u002Fguides\u002Fstorage-errors","wiki\u002Fguides\u002Fstorage-errors",{"title":190,"path":191,"stem":192},"Switching storage types","\u002Fwiki\u002Fguides\u002Fswitching-storage","wiki\u002Fguides\u002Fswitching-storage",{"title":194,"path":195,"stem":196},"Syncing data between servers","\u002Fwiki\u002Fguides\u002Fsyncing","wiki\u002Fguides\u002Fsyncing",{"title":198,"icon":199,"path":200,"stem":201,"children":202},"Installation","i-lucide-download","\u002Fwiki\u002Finstall","wiki\u002Finstall\u002Findex",[203,204,208],{"title":198,"path":200,"stem":201},{"title":205,"path":206,"stem":207},"Hytale","\u002Fwiki\u002Finstall\u002Fhytale","wiki\u002Finstall\u002Fhytale",{"title":209,"path":210,"stem":211},"Network installation","\u002Fwiki\u002Finstall\u002Fnetwork","wiki\u002Finstall\u002Fnetwork",{"title":213,"icon":214,"path":215,"stem":216,"children":217,"page":39},"Reference","i-lucide-library","\u002Fwiki\u002Freference","wiki\u002Freference",[218,222,226,230],{"title":219,"path":220,"stem":221},"Migrating from GroupManager or PermissionsEx","\u002Fwiki\u002Freference\u002Fmigrating-gm-pex","wiki\u002Freference\u002Fmigrating-gm-pex",{"title":223,"path":224,"stem":225},"How permission calculation works","\u002Fwiki\u002Freference\u002Fpermission-calculation","wiki\u002Freference\u002Fpermission-calculation",{"title":227,"path":228,"stem":229},"Self-hosting the web interfaces","\u002Fwiki\u002Freference\u002Fself-hosting","wiki\u002Freference\u002Fself-hosting",{"title":231,"path":232,"stem":233},"Upgrading from v4 to v5","\u002Fwiki\u002Freference\u002Fupgrade-v4-v5","wiki\u002Freference\u002Fupgrade-v4-v5",{"title":235,"path":236,"stem":237},"Storage types","\u002Fwiki\u002Fstorage","wiki\u002Fstorage",{"id":239,"title":95,"body":240,"description":1130,"extension":1131,"meta":1132,"navigation":558,"path":96,"seo":1133,"stem":97,"updatedAt":1134,"__hash__":1135},"wiki_en\u002Fwiki\u002Fdevelopers\u002Fapi.md",{"type":241,"value":242,"toc":1105},"minimark",[243,248,252,256,267,275,299,304,341,345,437,440,443,452,456,463,522,525,528,533,574,578,612,615,618,639,641,644,651,654,657,663,694,697,702,730,734,743,754,763,765,768,774,777,785,788,796,799,821,824,838,845,854,871,874,980,991,994,1072,1075,1084,1087,1090,1098,1101],[244,245,247],"h2",{"id":246},"intro","Intro",[249,250,251],"p",{},"LuckPerms has a complete developer API, which allows other plugins on the server to read and modify LuckPerms data, and easily integrate LuckPerms deeply into existing plugins and systems.",[244,253,255],{"id":254},"versioning","Versioning",[249,257,258,259,266],{},"The API uses ",[260,261,265],"a",{"href":262,"rel":263},"https:\u002F\u002Fsemver.org\u002F",[264],"nofollow","Semantic Versioning",", meaning whenever a non-backwards compatible change is made, the major version will increment. You can rest assured knowing your integration will not break between versions, providing the major version remains the same.",[249,268,269,270,274],{},"The current API release is ",[271,272,273],"code",{},"5.5",".",[276,277,278,285],"ul",{},[279,280,281,282,274],"li",{},"The API package in LuckPerms is ",[271,283,284],{},"net.luckperms.api",[279,286,287,288,293,294,274],{},"JavaDocs are available either in ",[260,289,292],{"href":290,"rel":291},"https:\u002F\u002Fjavadoc.io\u002Fdoc\u002Fnet.luckperms\u002Fapi\u002Flatest\u002F",[264],"a standard JavaDoc layout",", or within the API ",[260,295,298],{"href":296,"rel":297},"https:\u002F\u002Fgithub.com\u002FLuckPerms\u002FLuckPerms\u002Ftree\u002Fmaster\u002Fapi\u002Fsrc\u002Fmain\u002Fjava\u002Fnet\u002Fluckperms\u002Fapi",[264],"source code",[300,301,303],"h3",{"id":302},"changelogs","Changelogs",[276,305,306,313,325,335],{},[279,307,308,309,312],{},"Version ",[271,310,311],{},"2.x"," represented the initial release of the API.",[279,314,308,315,318,319,324],{},[271,316,317],{},"3.x"," (19th Feb 17) introduced a number of backwards incompatible changes. [",[260,320,323],{"href":321,"rel":322},"https:\u002F\u002Fgist.github.com\u002Flucko\u002Ffdf6ae4b2d9e466d8103dd9c68e5db9e",[264],"changelog","]",[279,326,308,327,330,331,324],{},[271,328,329],{},"4.x"," (7th Nov 17) introduced a number of backwards incompatible changes. [",[260,332,323],{"href":333,"rel":334},"https:\u002F\u002Fgist.github.com\u002Flucko\u002F34c5c3c52ad80f8541395a096a937e91",[264],[279,336,308,337,340],{},[271,338,339],{},"5.x"," was a complete rewrite of the API. Bridging tools are provided to maintain compatibility with older versions.",[244,342,344],{"id":343},"quick-start-guide","Quick start guide",[276,346,347,373,399],{},[279,348,349,353],{},[260,350,352],{"href":351},"#adding-luckperms-to-your-project","Adding LuckPerms to your project",[276,354,355,361,367],{},[279,356,357],{},[260,358,360],{"href":359},"#maven","Maven",[279,362,363],{},[260,364,366],{"href":365},"#gradle","Gradle",[279,368,369],{},[260,370,372],{"href":371},"#manual","Manual",[279,374,375,379],{},[260,376,378],{"href":377},"#obtaining-an-instance-of-the-api","Obtaining an instance of the API",[276,380,381,387,393],{},[279,382,383],{},[260,384,386],{"href":385},"#using-the-bukkit-servicesmanager","Using the Bukkit ServicesManager",[279,388,389],{},[260,390,392],{"href":391},"#using-the-sponge-servicesmanager","Using the Sponge ServicesManager",[279,394,395],{},[260,396,398],{"href":397},"#using-the-singleton-static-access","Using the singleton",[279,400,401,405],{},[260,402,404],{"href":403},"#useful-information","Useful information",[276,406,407,413,419,425,431],{},[279,408,409],{},[260,410,412],{"href":411},"#thread-safety","Thread safety",[279,414,415],{},[260,416,418],{"href":417},"#immutability","Immutability",[279,420,421],{},[260,422,424],{"href":423},"#blocking-operations","Blocking operations",[279,426,427],{},[260,428,430],{"href":429},"#using-completablefutures","Using CompletableFutures",[279,432,433],{},[260,434,436],{"href":435},"#asynchronous-events--callbacks","Asynchronous events & callbacks",[438,439],"hr",{},[300,441,352],{"id":442},"adding-luckperms-to-your-project",[249,444,445,446,451],{},"The API artifact is published to the ",[260,447,450],{"href":448,"rel":449},"http:\u002F\u002Fcentral.sonatype.org\u002F",[264],"Maven Central"," repository.",[453,454,360],"h4",{"id":455},"maven",[249,457,458,459,462],{},"If you're using Maven, simply add this to the ",[271,460,461],{},"dependencies"," section of your POM.",[464,465,470],"pre",{"className":466,"code":467,"language":468,"meta":469,"style":469},"language-xml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cdependencies>\n    \u003Cdependency>\n        \u003CgroupId>net.luckperms\u003C\u002FgroupId>\n        \u003CartifactId>api\u003C\u002FartifactId>\n        \u003Cversion>5.5\u003C\u002Fversion>\n        \u003Cscope>provided\u003C\u002Fscope>\n    \u003C\u002Fdependency>\n\u003C\u002Fdependencies>\n","xml","",[271,471,472,480,486,492,498,504,510,516],{"__ignoreMap":469},[473,474,477],"span",{"class":475,"line":476},"line",1,[473,478,479],{},"\u003Cdependencies>\n",[473,481,483],{"class":475,"line":482},2,[473,484,485],{},"    \u003Cdependency>\n",[473,487,489],{"class":475,"line":488},3,[473,490,491],{},"        \u003CgroupId>net.luckperms\u003C\u002FgroupId>\n",[473,493,495],{"class":475,"line":494},4,[473,496,497],{},"        \u003CartifactId>api\u003C\u002FartifactId>\n",[473,499,501],{"class":475,"line":500},5,[473,502,503],{},"        \u003Cversion>5.5\u003C\u002Fversion>\n",[473,505,507],{"class":475,"line":506},6,[473,508,509],{},"        \u003Cscope>provided\u003C\u002Fscope>\n",[473,511,513],{"class":475,"line":512},7,[473,514,515],{},"    \u003C\u002Fdependency>\n",[473,517,519],{"class":475,"line":518},8,[473,520,521],{},"\u003C\u002Fdependencies>\n",[453,523,366],{"id":524},"gradle",[249,526,527],{},"If you're using Gradle, you need to add these lines to your build script.",[529,530,532],"h5",{"id":531},"groovy-dsl","Groovy DSL:",[464,534,537],{"className":535,"code":536,"language":524,"meta":469,"style":469},"language-gradle shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","repositories {\n    mavenCentral()\n}\n\ndependencies {\n    compileOnly 'net.luckperms:api:5.5'\n}\n",[271,538,539,544,549,554,560,565,570],{"__ignoreMap":469},[473,540,541],{"class":475,"line":476},[473,542,543],{},"repositories {\n",[473,545,546],{"class":475,"line":482},[473,547,548],{},"    mavenCentral()\n",[473,550,551],{"class":475,"line":488},[473,552,553],{},"}\n",[473,555,556],{"class":475,"line":494},[473,557,559],{"emptyLinePlaceholder":558},true,"\n",[473,561,562],{"class":475,"line":500},[473,563,564],{},"dependencies {\n",[473,566,567],{"class":475,"line":506},[473,568,569],{},"    compileOnly 'net.luckperms:api:5.5'\n",[473,571,572],{"class":475,"line":512},[473,573,553],{},[529,575,577],{"id":576},"kotlin-dsl","Kotlin DSL:",[464,579,581],{"className":535,"code":580,"language":524,"meta":469,"style":469},"repositories {\n    mavenCentral()\n}\n\ndependencies {\n    compileOnly(\"net.luckperms:api:5.5\")\n}\n",[271,582,583,587,591,595,599,603,608],{"__ignoreMap":469},[473,584,585],{"class":475,"line":476},[473,586,543],{},[473,588,589],{"class":475,"line":482},[473,590,548],{},[473,592,593],{"class":475,"line":488},[473,594,553],{},[473,596,597],{"class":475,"line":494},[473,598,559],{"emptyLinePlaceholder":558},[473,600,601],{"class":475,"line":500},[473,602,564],{},[473,604,605],{"class":475,"line":506},[473,606,607],{},"    compileOnly(\"net.luckperms:api:5.5\")\n",[473,609,610],{"class":475,"line":512},[473,611,553],{},[453,613,372],{"id":614},"manual",[249,616,617],{},"If you want to manually add the API dependency to your classpath, you can obtain the jar by:",[619,620,621,630,633],"ol",{},[279,622,623,624],{},"Navigating to ",[260,625,628],{"href":626,"rel":627},"https:\u002F\u002Frepo1.maven.org\u002Fmaven2\u002Fnet\u002Fluckperms\u002Fapi\u002F",[264],[271,629,626],{},[279,631,632],{},"Selecting the version you wish to use",[279,634,635,636],{},"Downloading the jar titled ",[271,637,638],{},"api-x.x.jar",[438,640],{},[300,642,378],{"id":643},"obtaining-an-instance-of-the-api",[249,645,646,647,650],{},"The root API interface is ",[271,648,649],{},"LuckPerms",". You need to obtain an instance of this interface in order to do anything.",[249,652,653],{},"It can be obtained in a number of ways.",[453,655,386],{"id":656},"using-the-bukkit-servicesmanager",[249,658,659,660,662],{},"When the plugin is enabled, an instance of ",[271,661,649],{}," will be provided in the Bukkit ServicesManager. (obviously you need to be writing your plugin for Bukkit!)",[464,664,668],{"className":665,"code":666,"language":667,"meta":469,"style":469},"language-java shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","RegisteredServiceProvider\u003CLuckPerms> provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class);\nif (provider != null) {\n    LuckPerms api = provider.getProvider();\n    \n}\n","java",[271,669,670,675,680,685,690],{"__ignoreMap":469},[473,671,672],{"class":475,"line":476},[473,673,674],{},"RegisteredServiceProvider\u003CLuckPerms> provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class);\n",[473,676,677],{"class":475,"line":482},[473,678,679],{},"if (provider != null) {\n",[473,681,682],{"class":475,"line":488},[473,683,684],{},"    LuckPerms api = provider.getProvider();\n",[473,686,687],{"class":475,"line":494},[473,688,689],{},"    \n",[473,691,692],{"class":475,"line":500},[473,693,553],{},[453,695,392],{"id":696},"using-the-sponge-servicesmanager",[249,698,659,699,701],{},[271,700,649],{}," will be provided in the Sponge ServicesManager. (obviously you need to be writing your plugin for Sponge!)",[464,703,705],{"className":665,"code":704,"language":667,"meta":469,"style":469},"Optional\u003CProviderRegistration\u003CLuckPerms>> provider = Sponge.getServiceManager().getRegistration(LuckPerms.class);\nif (provider.isPresent()) {\n    LuckPerms api = provider.get().getProvider();\n    \n}\n",[271,706,707,712,717,722,726],{"__ignoreMap":469},[473,708,709],{"class":475,"line":476},[473,710,711],{},"Optional\u003CProviderRegistration\u003CLuckPerms>> provider = Sponge.getServiceManager().getRegistration(LuckPerms.class);\n",[473,713,714],{"class":475,"line":482},[473,715,716],{},"if (provider.isPresent()) {\n",[473,718,719],{"class":475,"line":488},[473,720,721],{},"    LuckPerms api = provider.get().getProvider();\n",[473,723,724],{"class":475,"line":494},[473,725,689],{},[473,727,728],{"class":475,"line":500},[473,729,553],{},[453,731,733],{"id":732},"using-the-singleton-static-access","Using the singleton (static access)",[249,735,659,736,738,739,742],{},[271,737,649],{}," can be obtained statically from the ",[271,740,741],{},"LuckPermsProvider"," class. (this will work on all platforms)",[249,744,745,749,750,753],{},[746,747,748],"strong",{},"Note:"," this method will throw an ",[271,751,752],{},"IllegalStateException"," if the API is not loaded.",[464,755,757],{"className":665,"code":756,"language":667,"meta":469,"style":469},"LuckPerms api = LuckPermsProvider.get();\n",[271,758,759],{"__ignoreMap":469},[473,760,761],{"class":475,"line":476},[473,762,756],{},[438,764],{},[300,766,404],{"id":767},"useful-information",[249,769,770,771,773],{},"Now you've added the API classes to your project, and obtained an instance of the ",[271,772,649],{},", you're almost ready to start using the API. However, before you go any further, please make sure you read and understand the information below.",[453,775,412],{"id":776},"thread-safety",[276,778,779,782],{},[279,780,781],{},"All LuckPerms internals are thread-safe. You can safely interact with the API from async scheduler tasks (or just generally from other threads)",[279,783,784],{},"This also extends to the permission querying methods in Bukkit\u002FBungee\u002FSponge. These can be safely called async when LuckPerms is being used as the permissions plugin.",[453,786,418],{"id":787},"immutability",[276,789,790,793],{},[279,791,792],{},"In cases where methods return classes from the Java collections framework, assume that the returned methods are always immutable, unless indicated otherwise. (in the JavaDocs)",[279,794,795],{},"This means that you cannot make changes to any returned collections, and that the collections are only an accurate representation of the underlying data at the time of the method call.",[453,797,424],{"id":798},"blocking-operations",[276,800,801,804,807,815,818],{},[279,802,803],{},"Some methods are not \"main thread friendly\", meaning that if they are called from the main Minecraft Server thread, the server will lag.",[279,805,806],{},"This is because many methods conduct I\u002FO with either the file system or the network.",[279,808,809,810,274],{},"In most cases, these methods return ",[260,811,814],{"href":812,"rel":813},"https:\u002F\u002Fdocs.oracle.com\u002Fjavase\u002F8\u002Fdocs\u002Fapi\u002Fjava\u002Futil\u002Fconcurrent\u002FCompletableFuture.html",[264],"CompletableFutures",[279,816,817],{},"Futures can be an initially complex paradigm for some users - however, it is crucial that you have at least a basic understanding of how they work before attempting to use them.",[279,819,820],{},"As a general rule, it is advised that if it's convenient to do so, you conduct as much work with the API as possible within async scheduler tasks. Some methods don't return futures, but may still involve a number of relatively complex computations.",[453,822,430],{"id":823},"using-completablefutures",[249,825,826,827,831,832,837],{},"This is a super quick guide. If you'd like more comprehensive info, see the ",[260,828,830],{"href":812,"rel":829},[264],"CompletableFuture"," or ",[260,833,836],{"href":834,"rel":835},"https:\u002F\u002Fdocs.oracle.com\u002Fjavase\u002F8\u002Fdocs\u002Fapi\u002Fjava\u002Futil\u002Fconcurrent\u002FCompletionStage.html",[264],"CompletionStage"," JavaDoc pages.",[249,839,840,841,844],{},"For the purposes of explaining, take the following method in the ",[271,842,843],{},"ActionLogger"," class.",[464,846,848],{"className":665,"code":847,"language":667,"meta":469,"style":469},"CompletableFuture\u003CActionLog> getLog();\n",[271,849,850],{"__ignoreMap":469},[473,851,852],{"class":475,"line":476},[473,853,847],{},[249,855,856,857,860,861,864,865,867,868,870],{},"After calling the method, we get a ",[271,858,859],{},"CompletableFuture\u003CActionLog>"," - the object we actually want is the ",[271,862,863],{},"ActionLog",". The ",[271,866,830],{}," represents the result of some computation (in this case the computation to obtain the ActionLog), and provides us with methods to obtain the ",[271,869,863],{}," object.",[249,872,873],{},"If the context of our method call is already asynchronous (if we're calling the method from an async scheduler task), then we can do-away with the future entirely.",[464,875,877],{"className":665,"code":876,"language":667,"meta":469,"style":469},"\u002F*\n  Calling this method \"requests\" an ActionLog from the API.\n  \n  However, it's unlikely that the log will be available immediately...\n  We need to wait for it to be supplied.\n*\u002F\nCompletableFuture\u003CActionLog> logFuture = actionLogger.getLog();\n\n\u002F*\n  Since we're already on an async thread, it doesn't matter how long we\n  have to wait for the elusive Log to show up.\n  \n  The #join method will block - and wait until the Log has been supplied,\n  and then return it.\n  \n  If for whatever reason the process to obtain a ActionLog threw an exception,\n  this method will rethrow an the same exception wrapped in a CompletionException\n*\u002F\nActionLog log = logFuture.join();\n",[271,878,879,884,889,894,899,904,909,914,918,923,929,935,940,946,952,957,963,969,974],{"__ignoreMap":469},[473,880,881],{"class":475,"line":476},[473,882,883],{},"\u002F*\n",[473,885,886],{"class":475,"line":482},[473,887,888],{},"  Calling this method \"requests\" an ActionLog from the API.\n",[473,890,891],{"class":475,"line":488},[473,892,893],{},"  \n",[473,895,896],{"class":475,"line":494},[473,897,898],{},"  However, it's unlikely that the log will be available immediately...\n",[473,900,901],{"class":475,"line":500},[473,902,903],{},"  We need to wait for it to be supplied.\n",[473,905,906],{"class":475,"line":506},[473,907,908],{},"*\u002F\n",[473,910,911],{"class":475,"line":512},[473,912,913],{},"CompletableFuture\u003CActionLog> logFuture = actionLogger.getLog();\n",[473,915,916],{"class":475,"line":518},[473,917,559],{"emptyLinePlaceholder":558},[473,919,921],{"class":475,"line":920},9,[473,922,883],{},[473,924,926],{"class":475,"line":925},10,[473,927,928],{},"  Since we're already on an async thread, it doesn't matter how long we\n",[473,930,932],{"class":475,"line":931},11,[473,933,934],{},"  have to wait for the elusive Log to show up.\n",[473,936,938],{"class":475,"line":937},12,[473,939,893],{},[473,941,943],{"class":475,"line":942},13,[473,944,945],{},"  The #join method will block - and wait until the Log has been supplied,\n",[473,947,949],{"class":475,"line":948},14,[473,950,951],{},"  and then return it.\n",[473,953,955],{"class":475,"line":954},15,[473,956,893],{},[473,958,960],{"class":475,"line":959},16,[473,961,962],{},"  If for whatever reason the process to obtain a ActionLog threw an exception,\n",[473,964,966],{"class":475,"line":965},17,[473,967,968],{},"  this method will rethrow an the same exception wrapped in a CompletionException\n",[473,970,972],{"class":475,"line":971},18,[473,973,908],{},[473,975,977],{"class":475,"line":976},19,[473,978,979],{},"ActionLog log = logFuture.join();\n",[249,981,982,983,986,987,990],{},"An alternative to using ",[271,984,985],{},"#join"," is to register a callback with the CompletableFuture, to be executed once the ",[271,988,989],{},"Log"," is supplied.",[249,992,993],{},"If we need to use the instance on the main server thread, then a special executor can be passed to the callback is executed on the server thread.",[464,995,997],{"className":665,"code":996,"language":667,"meta":469,"style":469},"\u002F\u002F Create an executor that will run our callback on the server thread.\nExecutor executor = runnable -> Bukkit.getScheduler().runTask(plugin, runnable);\n\n\u002F\u002F Register a callback with the future.\nlogFuture.whenCompleteAsync(new BiConsumer\u003CActionLog, Throwable>() { \u002F\u002F can be reduced to a lambda, I've left it as an anonymous class for clarity\n    @Override\n    public void accept(ActionLog log, Throwable exception) {\n        if (exception != null) {\n            \u002F\u002F There was some error whilst getting the log.\n            return;\n        }\n\n        \u002F\u002F Use the log for something...\n    }\n}, executor);\n",[271,998,999,1004,1009,1013,1018,1023,1028,1033,1038,1043,1048,1053,1057,1062,1067],{"__ignoreMap":469},[473,1000,1001],{"class":475,"line":476},[473,1002,1003],{},"\u002F\u002F Create an executor that will run our callback on the server thread.\n",[473,1005,1006],{"class":475,"line":482},[473,1007,1008],{},"Executor executor = runnable -> Bukkit.getScheduler().runTask(plugin, runnable);\n",[473,1010,1011],{"class":475,"line":488},[473,1012,559],{"emptyLinePlaceholder":558},[473,1014,1015],{"class":475,"line":494},[473,1016,1017],{},"\u002F\u002F Register a callback with the future.\n",[473,1019,1020],{"class":475,"line":500},[473,1021,1022],{},"logFuture.whenCompleteAsync(new BiConsumer\u003CActionLog, Throwable>() { \u002F\u002F can be reduced to a lambda, I've left it as an anonymous class for clarity\n",[473,1024,1025],{"class":475,"line":506},[473,1026,1027],{},"    @Override\n",[473,1029,1030],{"class":475,"line":512},[473,1031,1032],{},"    public void accept(ActionLog log, Throwable exception) {\n",[473,1034,1035],{"class":475,"line":518},[473,1036,1037],{},"        if (exception != null) {\n",[473,1039,1040],{"class":475,"line":920},[473,1041,1042],{},"            \u002F\u002F There was some error whilst getting the log.\n",[473,1044,1045],{"class":475,"line":925},[473,1046,1047],{},"            return;\n",[473,1049,1050],{"class":475,"line":931},[473,1051,1052],{},"        }\n",[473,1054,1055],{"class":475,"line":937},[473,1056,559],{"emptyLinePlaceholder":558},[473,1058,1059],{"class":475,"line":942},[473,1060,1061],{},"        \u002F\u002F Use the log for something...\n",[473,1063,1064],{"class":475,"line":948},[473,1065,1066],{},"    }\n",[473,1068,1069],{"class":475,"line":954},[473,1070,1071],{},"}, executor);\n",[249,1073,1074],{},"If you don't care about errors, this can be simplified further.",[464,1076,1078],{"className":665,"code":1077,"language":667,"meta":469,"style":469},"logFuture.thenAcceptAsync(log -> { \u002F* Use the log for something *\u002F }, executor);\n",[271,1079,1080],{"__ignoreMap":469},[473,1081,1082],{"class":475,"line":476},[473,1083,1077],{},[249,1085,1086],{},"The CompletableFuture class can initially be very confusing to use (it's still a relatively new API in Java!), however it is a great way to encapsulate async computations, and in the case of Minecraft, ensures that users don't accidentally block the server thread waiting on lengthy I\u002FO calls.",[453,1088,436],{"id":1089},"asynchronous-events-callbacks",[276,1091,1092,1095],{},[279,1093,1094],{},"The vast majority of LuckPerms' work is done in async tasks away from the server thread.",[279,1096,1097],{},"With that in mind, it would be silly to call LuckPerms events synchronously - meaning that, without exception, all events listeners are called asynchronously.",[249,1099,1100],{},"Please keep in mind that many parts of Bukkit, Sponge and the Minecraft server in general are not thread-safe, and should only be interacted with from the server thread. If you need to use Bukkit or Sponge methods from within LuckPerms event listeners or callbacks, you need to perform your action using the scheduler.",[1102,1103,1104],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":469,"searchDepth":488,"depth":488,"links":1106},[1107,1108,1111],{"id":246,"depth":482,"text":247},{"id":254,"depth":482,"text":255,"children":1109},[1110],{"id":302,"depth":488,"text":303},{"id":343,"depth":482,"text":344,"children":1112},[1113,1118,1123],{"id":442,"depth":488,"text":352,"children":1114},[1115,1116,1117],{"id":455,"depth":494,"text":360},{"id":524,"depth":494,"text":366},{"id":614,"depth":494,"text":372},{"id":643,"depth":488,"text":378,"children":1119},[1120,1121,1122],{"id":656,"depth":494,"text":386},{"id":696,"depth":494,"text":392},{"id":732,"depth":494,"text":733},{"id":767,"depth":488,"text":404,"children":1124},[1125,1126,1127,1128,1129],{"id":776,"depth":494,"text":412},{"id":787,"depth":494,"text":418},{"id":798,"depth":494,"text":424},{"id":823,"depth":494,"text":430},{"id":1089,"depth":494,"text":436},"Introduction to the LuckPerms API.","md",{},{"title":95,"description":1130},null,"pTtkHVjhVSzP74-g2ORFjfJl7hxQQQIYHBZs0k3MMco",[1137,1138],{"title":85,"path":86,"stem":87,"children":-1},{"title":99,"path":100,"stem":101,"children":-1},{"editUrl":1140},"https:\u002F\u002Fgithub.com\u002FTurbotailz\u002Fwiki\u002Fedit\u002Fv3-structure\u002Fen\u002Fdevelopers\u002Fapi.md",[1142],{"title":5,"icon":6,"path":7,"stem":8,"children":1143},[1144,1145,1152,1164,1165,1171,1172,1184,1185,1195,1200,1206],{"title":11,"path":7,"stem":12},{"title":14,"icon":15,"path":16,"stem":17,"children":1146,"page":39},[1147,1148,1149,1150,1151],{"title":20,"path":21,"stem":22},{"title":24,"path":25,"stem":26},{"title":28,"path":29,"stem":30},{"title":32,"path":33,"stem":34},{"title":36,"path":37,"stem":38},{"title":41,"icon":42,"path":43,"stem":44,"children":1153},[1154,1155,1156,1157,1158,1159,1160,1161,1162,1163],{"title":47,"path":43,"stem":44},{"title":49,"path":50,"stem":51},{"title":53,"path":54,"stem":55},{"title":57,"path":58,"stem":59},{"title":61,"path":62,"stem":63},{"title":65,"path":66,"stem":67},{"title":69,"path":70,"stem":71},{"title":73,"path":74,"stem":75},{"title":77,"path":78,"stem":79},{"title":81,"path":82,"stem":83},{"title":85,"path":86,"stem":87},{"title":89,"icon":90,"path":91,"stem":92,"children":1166,"page":39},[1167,1168,1169,1170],{"title":95,"path":96,"stem":97},{"title":99,"path":100,"stem":101},{"title":103,"path":104,"stem":105},{"title":107,"path":108,"stem":109},{"title":111,"path":112,"stem":113},{"title":115,"icon":116,"path":117,"stem":118,"children":1173,"page":39},[1174,1175,1176,1177,1178,1179,1183],{"title":121,"path":122,"stem":123},{"title":125,"path":126,"stem":127},{"title":129,"path":130,"stem":131},{"title":133,"path":134,"stem":135},{"title":137,"path":138,"stem":139},{"title":141,"path":142,"stem":143,"children":1180},[1181,1182],{"title":146,"path":142,"stem":143},{"title":148,"path":149,"stem":150},{"title":152,"path":153,"stem":154},{"title":156,"path":157,"stem":158},{"title":160,"icon":161,"path":162,"stem":163,"children":1186,"page":39},[1187,1188,1189,1190,1191,1192,1193,1194],{"title":166,"path":167,"stem":168},{"title":170,"path":171,"stem":172},{"title":174,"path":175,"stem":176},{"title":178,"path":179,"stem":180},{"title":182,"path":183,"stem":184},{"title":186,"path":187,"stem":188},{"title":190,"path":191,"stem":192},{"title":194,"path":195,"stem":196},{"title":198,"icon":199,"path":200,"stem":201,"children":1196},[1197,1198,1199],{"title":198,"path":200,"stem":201},{"title":205,"path":206,"stem":207},{"title":209,"path":210,"stem":211},{"title":213,"icon":214,"path":215,"stem":216,"children":1201,"page":39},[1202,1203,1204,1205],{"title":219,"path":220,"stem":221},{"title":223,"path":224,"stem":225},{"title":227,"path":228,"stem":229},{"title":231,"path":232,"stem":233},{"title":235,"path":236,"stem":237},1789086424640]