1"use strict";(self.webpackChunkgeyser_wiki=self.webpackChunkgeyser_wiki||[]).push([[4994],{51023:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"geyser/extensions","title":"Geyser Extensions","description":"Geyser Extensions are the equivalent of \\"plugins\\", but specifically for the Geyser platform. This brings the advantage of them being platform-agnostic, meaning that you won\'t have to worry about supporting all platforms individually.","source":"@site/wiki/geyser/extensions.md","sourceDirName":"geyser","slug":"/geyser/extensions","permalink":"/wiki/geyser/extensions","draft":false,"unlisted":false,"editUrl":"https://github.com/GeyserMC/GeyserWebsite/tree/master/wiki/geyser/extensions.md","tags":[],"version":"current","frontMatter":{"title":"Geyser Extensions","description":"Geyser Extensions are the equivalent of \\"plugins\\", but specifically for the Geyser platform. This brings the advantage of them being platform-agnostic, meaning that you won\'t have to worry about supporting all platforms individually."},"sidebar":"geyserSidebar","previous":{"title":"Forms and Cumulus","permalink":"/wiki/geyser/forms"}}');var t=s(74848),r=s(28453);const o={title:"Geyser Extensions",description:'Geyser Extensions are the equivalent of "plugins", but specifically for the Geyser platform. This brings the advantage of them being platform-agnostic, meaning that you won\'t have to worry about supporting all platforms individually.'},a="Geyser Extensions",l={},d=[{value:"What can Geyser Extensions do?",id:"what-can-geyser-extensions-do",level:2},{value:"Which Geyser Extensions exist?",id:"which-geyser-extensions-exist",level:2},{value:"Installing Extensions",id:"installing-extensions",level:2},{value:"Updating Extensions",id:"updating-extensions",level:2},{value:"Creating Geyser Extensions",id:"creating-geyser-extensions",level:2},{value:"Creating the main class",id:"creating-the-main-class",level:2},{value:"Creating commands with Geyser Extensions",id:"creating-commands-with-geyser-extensions",level:2},{value:"Listening to Events",id:"listening-to-events",level:2},{value:"Facing troubles with extensions?",id:"facing-troubles-with-extensions",level:2}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"geyser-extensions",children:"Geyser Extensions"})}),"\n",(0,t.jsx)(n.p,{children:'Geyser Extensions are the equivalent of "plugins", but specifically for the Geyser platform.\nThis brings the advantage of them being platform-agnostic, meaning that you won\'t have to worry about supporting all platforms individually.\nAdditionally, they will be, by design, only applied for Bedrock players joining via Geyser.'}),"\n",(0,t.jsx)(n.h2,{id:"what-can-geyser-extensions-do",children:"What can Geyser Extensions do?"}),"\n",(0,t.jsxs)(n.p,{children:["Extensions can fully utilize the Geyser API to add additional functionality to Geyser.\nSee ",(0,t.jsx)(n.a,{href:"/wiki/geyser/api/",children:"Geyser API docs"})," for info on what is currently possible."]}),"\n",(0,t.jsx)(n.p,{children:"To name a few examples:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Register custom items and blocks"}),"\n",(0,t.jsx)(n.li,{children:"Hide commands from being suggested"}),"\n",(0,t.jsx)(n.li,{children:"Change the MOTD"}),"\n",(0,t.jsx)(n.li,{children:"Register your own commands"}),"\n",(0,t.jsx)(n.li,{children:"Listen to events, e.g. the emote event."}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"The underlying Geyser API is steadily expanding, creating more and more opportunities."}),"\n",(0,t.jsx)(n.h2,{id:"which-geyser-extensions-exist",children:"Which Geyser Extensions exist?"}),"\n",(0,t.jsx)(n.p,{children:'Check out Modrinth\'s Geyser extensions section under the "plugins" tab!'}),"\n",(0,t.jsx)(n.h2,{id:"installing-extensions",children:"Installing Extensions"}),"\n",(0,t.jsxs)(n.p,{children:["To install an extension, simply put the extension .jar file into Geyser's ",(0,t.jsx)(n.code,{children:"extensions"})," folder.\nThen, restart Geyser (or the server Geyser runs on)."]}),"\n",(0,t.jsx)(n.h2,{id:"updating-extensions",children:"Updating Extensions"}),"\n",(0,t.jsxs)(n.p,{children:["To update extensions, use the ",(0,t.jsx)(n.code,{children:"update"})," folder within the extensions directory as follows:"]}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["Copy the updated versions of your extension jars into the ",(0,t.jsx)(n.code,{children:"update"})," folder inside the ",(0,t.jsx)(n.code,{children:"extensions"})," directory."]}),"\n",(0,t.jsxs)(n.li,{children:["On the next server or application restart, any extensions in the ",(0,t.jsx)(n.code,{children:"update"})," folder will automatically replace the corresponding extensions in the main extensions directory. If an extension is new, it will be added."]}),"\n",(0,t.jsx)(n.li,{children:"If an update fails, it will be logged, and the server/application will proceed with loading extensions as usual. You can review the logs to address any issues."}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"creating-geyser-extensions",children:"Creating Geyser Extensions"}),"\n",(0,t.jsxs)(n.p,{children:["The easiest way to create an extension would be utilizing ",(0,t.jsx)(n.a,{href:"https://github.com/GeyserMC/GeyserExtensionTemplate/",children:"this official template"}),".\nSimply create a new repository from the template, customize the ",(0,t.jsx)(n.code,{children:"extension.yml"})," & ",(0,t.jsx)(n.code,{children:"settings.gradle"})," files, and get started making the extension."]}),"\n",(0,t.jsxs)(n.p,{children:["Geyser recognizes extensions when they have a file called ",(0,t.jsx)(n.code,{children:"extension.yml"})," in the jars ",(0,t.jsx)(n.code,{children:"resources"})," folder."]}
1),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-yml",metastring:'title="extension.yml"',children:"id: exampleid\nname: ExampleExtension\nmain: org.geyser.extension.exampleid.ExampleExtension\napi: 2.9.0\nversion: 1.0.0\nauthors: [ExampleAuthor]\ndependencies: # Optional\n exampledependency:\n # When this dependency should be loaded (BEFORE or AFTER your extension)\n load: BEFORE # Default: BEFORE\n # This determines whether or not this dependency is required for this extension to load\n required: true # Default: true\n"})}),"\n",(0,t.jsx)(n.p,{children:"Explanations for the individual fields:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["id: The id of the extension. Every extension needs to have their unique id - all lowercase letters. If you e.g. register a command for your extension, it will have the id as a prefix: e.g. ",(0,t.jsx)(n.code,{children:"/exampleid command"}),"."]}),"\n",(0,t.jsx)(n.li,{children:"name: The name of the extension."}),"\n",(0,t.jsx)(n.li,{children:"main: The main class of your extension."}),"\n",(0,t.jsx)(n.li,{children:"api: The Geyser API version your extension targets."}),"\n",(0,t.jsx)(n.li,{children:"authors: The author(s) of the extension. To add more than one entry, separate entries with a comma."}),"\n",(0,t.jsxs)(n.li,{children:["dependencies: The dependencies of the extension. Each dependency has a load order and required property with defaults of ",(0,t.jsx)(n.code,{children:"BEFORE"})," and ",(0,t.jsx)(n.code,{children:"true"})," respectively."]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"creating-the-main-class",children:"Creating the main class"}),"\n",(0,t.jsxs)(n.p,{children:["The main class, the entrypoint for the extension, needs to ",(0,t.jsxs)(n.a,{href:"https://github.com/GeyserMC/GeyserExtensionTemplate/blob/master/src/main/java/org/geyser/extension/exampleid/ExampleExtension.java#L15",children:["implement the ",(0,t.jsx)(n.strong,{children:"Extension"})," interface provided by Geyser"]}),".\nThat way, Geyser recognizes the extension, and gives you access to important methods - such as ",(0,t.jsx)(n.code,{children:"logger()"}),", to get your extensions logger.\nTo see all the methods provided by that interface, see ",(0,t.jsx)(n.a,{href:"https://github.com/GeyserMC/Geyser/blob/master/api/src/main/java/org/geysermc/geyser/api/extension/Extension.java",children:"here"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["Unlike plugins, extensions do not have a ",(0,t.jsx)(n.code,{children:"onEnable"})," or ",(0,t.jsx)(n.code,{children:"onDisable"})," method. Instead, most actions are done in events at different stages during Geyser's lifecycle using events.\nSome important ones are:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"GeyserPreInitializeEvent"}),": This event is fired when Geyser starts to initialize. If you e.g. need to register extension commands that are configured in your config,\nyou would need to load the config here to ensure that your config is ready before the ",(0,t.jsx)(n.code,{children:"GeyserDefineCommandsEvent"})," is fired."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"GeyserPostInitializeEvent"}),": It is called when Geyser has completed initializing. The bulk of your code should go here, as the GeyserAPI is fully available at this stage."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"GeyserShutdownEvent"}),": Called when Geyser is shutting down. You can use this to e.g. save data, or clean up resources."]}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"See below for an example:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:'@Subscribe\npublic void onPostInitialize(GeyserPostInitializeEvent event) {\n // example: show that your extension is loading.\n this.logger().info("Loading example extension...");\n}\n'})}),"\n",(0,t.jsxs)(n.p,{children:["If you wish to register custom items, global resource packs (or soon, custom blocks and entities), you will need to subscribe to the event using the @Subscribe annotation,\nand register them in the event. You can find an example for custom items ",(0,t.jsx)(n.a,{href:"/wiki/geyser/custom-items#geyser-extensions",children:"here"}),". For other events, see ",(0,t.jsx)(n.a,{href:"/wiki/geyser/events",children:"here"})," for documentation."]}),"\n",(0,t.jsx)(n.p,{children:"To build your extension, run the Gradle build task, and install the extension."}),"\n",(0,t.jsx)(n.h2,{id:"creating-commands-with-geyser-extensions",children:"Creating commands with Geyser Extensions"}),"\n",(0,t.jsxs)(n.p,{children:["To create a command, you would need to use the ",(0,t.jsx)(n.code,{children:"Commands"})," package in the Geyser API. Brief rundown:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"https://github.com/GeyserMC/Geyser/blob/master/api/src
1/main/java/org/geysermc/geyser/api/command/Command.java",children:"Command.java"}),"\nThis interface represents a command in Geyser - to make one, you can use the CommandBuilder. You can register it with the\n",(0,t.jsx)(n.a,{href:"https://github.com/GeyserMC/Geyser/blob/master/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCommandsEvent.java",children:"GeyserDefineCommandsEvent"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"https://github.com/GeyserMC/Geyser/blob/master/api/src/main/java/org/geysermc/geyser/api/command/CommandExecutor.java",children:"CommandExecutor.java"}),"\nThis interface represents a command execute handler in Geyser, and extends the CommandSource interface."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"https://github.com/GeyserMC/Geyser/blob/master/api/src/main/java/org/geysermc/geyser/api/command/CommandSource.java",children:"CommandSource.java"}),"\nThis interface represents a command source in Geyser. It can be used to e.g. send messages to the source, check if the source has permission to execute a command, or get the locale."]}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:'Command command = Command.builder(this) // "this" is the extension\'s main class\n .name("ExampleC
1ommand")\n .bedrockOnly(true)\n .source(CommandSource.class)\n .aliases(List.of("example", "ex"))\n .description("An example command")\n .executableOnConsole(false) \n .suggestedOpOnly(false)\n .permission("example.command")\n .executor((source, cmd, args) -> {\n // this is the command executor - this is where you would put your code to execute the command.\n // source is the source that executed the command\n // cmd is the command that was executed\n // args are the arguments passed to the command\n source.sendMessage("Hello World");\n })\n .build();\n'})}),"\n",(0,t.jsxs)(n.p,{children:["To register the command, you would need to subscribe to the ",(0,t.jsx)(n.code,{children:"GeyserDefineCommandsEvent"}),", and register the command there:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:"@Subscribe\npublic void onDefineCommands(GeyserDefineCommandsEvent event) {\n event.register(command);\n}\n"})}),"\n",(0,t.jsxs)(n.p,{children:["If everything went right, you should be able to execute the command in-game by running ",(0,t.jsx)(n.code,{children:"/extesionid [command]"})," - in our case, ",(0,t.jsx)(n.code,{children:"/exampleid examplecommand"}),'.\nHere, it would send "Hello World" to the source that ran the command.\nSince we also set aliases, you could also run ',(0,t.jsx)(n.code,{children:"/exampleid example"})," or ",(0,t.jsx)(n.code,{children:"/exampleid ex"})," for the same command.\nTo provide args, simple run ",(0,t.jsx)(n.code,{children:"/exampleid examplecommand [args]"})," - replacing ",(0,t.jsx)(n.code,{children:"[args]"})," with the arguments you want to pass to the command."]}),"\n",(0,t.jsx)(n.h2,{id:"listening-to-events",children:"Listening to Events"}),"\n",(0,t.jsxs)(n.p,{children:["See ",(0,t.jsx)(n.a,{href:"/wiki/geyser/events",children:"here"})," for documentation. You do not need to register the event listener, Geyser will do that for you."]}),"\n",(0,t.jsx)(n.hr,{}),"\n",(0,t.jsx)(n.h2,{id:"facing-troubles-with-extensions",children:"Facing troubles with extensions?"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Make sure you are using the latest version of Geyser - older versions might not have the latest API changes."}),"\n",(0,t.jsx)(n.li,{children:"Add debug prints."}),"\n",(0,t.jsxs)(n.li,{children:["Ask in the #development channel in the ",(0,t.jsx)(n.a,{href:"https://discord.gg/geysermc",children:"Geyser Discord server"}),"."]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(c,{...e})}):c(e)}},28453:(e,n,s)=>{s.d(n,{R:()=>o,x:()=>a});var i=s(96540);const t={},r=i.createContext(t);function o(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.