[{"data":1,"prerenderedAt":1228},["ShallowReactive",2],{"navigation":3,"reference-navigation":62,"\u002Fdocs\u002Fnetwork-apis":365,"\u002Fdocs\u002Fnetwork-apis-surround":1224},[4,22,26,30,34,38,42,46,50,54,58],{"title":5,"path":6,"stem":7,"children":8},"Bundle Developer","\u002Fdocs\u002Fbundle-developer","1.docs\u002F1.bundle-developer\u002Findex",[9,10,14,18],{"title":5,"path":6,"stem":7},{"title":11,"path":12,"stem":13},"Terminology","\u002Fdocs\u002Fbundle-developer\u002Fterminology","1.docs\u002F1.bundle-developer\u002F1.terminology",{"title":15,"path":16,"stem":17},"Prerequisites","\u002Fdocs\u002Fbundle-developer\u002Fprerequisites","1.docs\u002F1.bundle-developer\u002F2.prerequisites",{"title":19,"path":20,"stem":21},"Bundle Layout","\u002Fdocs\u002Fbundle-developer\u002Flayout","1.docs\u002F1.bundle-developer\u002F3.layout",{"title":23,"path":24,"stem":25},"Custom Registry Developer Guide","\u002Fdocs\u002Fcustom-registries","1.docs\u002Fcustom-registries",{"title":27,"path":28,"stem":29},"Defining Bundle Entities","\u002Fdocs\u002Fdefining-bundle-entities","1.docs\u002Fdefining-bundle-entities",{"title":31,"path":32,"stem":33},"Defining Bundle Sounds","\u002Fdocs\u002Fdefining-bundle-sounds","1.docs\u002Fdefining-bundle-sounds",{"title":35,"path":36,"stem":37},"Defining Bundle Tile Transitions","\u002Fdocs\u002Fdefining-bundle-tile-transitions","1.docs\u002Fdefining-bundle-tile-transitions",{"title":39,"path":40,"stem":41},"Defining Bundle Tiles","\u002Fdocs\u002Fdefining-bundle-tiles","1.docs\u002Fdefining-bundle-tiles",{"title":43,"path":44,"stem":45},"Defining Bundle Visuals","\u002Fdocs\u002Fdefining-bundle-visuals","1.docs\u002Fdefining-bundle-visuals",{"title":47,"path":48,"stem":49},"Bundle Event System Developer Guide","\u002Fdocs\u002Fevent-system","1.docs\u002Fevent-system",{"title":51,"path":52,"stem":53},"Getting Started with Selene Bundles","\u002Fdocs\u002Fgetting-started-bundles","1.docs\u002Fgetting-started-bundles",{"title":55,"path":56,"stem":57},"Making Resource Packs","\u002Fdocs\u002Fmaking-resource-packs","1.docs\u002Fmaking-resource-packs",{"title":59,"path":60,"stem":61},"Bundle Network API Developer Guide","\u002Fdocs\u002Fnetwork-apis","1.docs\u002Fnetwork-apis",[63,212,253],{"title":64,"path":65,"stem":66,"children":67,"page":121},"Modules","\u002Freference\u002Fmodules","2.reference\u002F1.modules",[68,122,167],{"title":69,"path":70,"stem":71,"children":72,"page":121},"Common","\u002Freference\u002Fmodules\u002Fcommon","2.reference\u002F1.modules\u002F1.common",[73,77,81,85,89,93,97,101,105,109,113,117],{"title":74,"path":75,"stem":76},"debug","\u002Freference\u002Fmodules\u002Fcommon\u002Fdebug","2.reference\u002F1.modules\u002F1.common\u002Fdebug",{"title":78,"path":79,"stem":80},"mathx","\u002Freference\u002Fmodules\u002Fcommon\u002Fmathx","2.reference\u002F1.modules\u002F1.common\u002Fmathx",{"title":82,"path":83,"stem":84},"os","\u002Freference\u002Fmodules\u002Fcommon\u002Fos","2.reference\u002F1.modules\u002F1.common\u002Fos",{"title":86,"path":87,"stem":88},"package","\u002Freference\u002Fmodules\u002Fcommon\u002Fpackage","2.reference\u002F1.modules\u002F1.common\u002Fpackage",{"title":90,"path":91,"stem":92},"selene.grid","\u002Freference\u002Fmodules\u002Fcommon\u002Fselene.grid","2.reference\u002F1.modules\u002F1.common\u002Fselene.grid",{"title":94,"path":95,"stem":96},"selene.http","\u002Freference\u002Fmodules\u002Fcommon\u002Fselene.http","2.reference\u002F1.modules\u002F1.common\u002Fselene.http",{"title":98,"path":99,"stem":100},"selene.i18n","\u002Freference\u002Fmodules\u002Fcommon\u002Fselene.i18n","2.reference\u002F1.modules\u002F1.common\u002Fselene.i18n",{"title":102,"path":103,"stem":104},"selene.registries","\u002Freference\u002Fmodules\u002Fcommon\u002Fselene.registries","2.reference\u002F1.modules\u002F1.common\u002Fselene.registries",{"title":106,"path":107,"stem":108},"selene.resources","\u002Freference\u002Fmodules\u002Fcommon\u002Fselene.resources","2.reference\u002F1.modules\u002F1.common\u002Fselene.resources",{"title":110,"path":111,"stem":112},"selene.schedules","\u002Freference\u002Fmodules\u002Fcommon\u002Fselene.schedules","2.reference\u002F1.modules\u002F1.common\u002Fselene.schedules",{"title":114,"path":115,"stem":116},"stringx","\u002Freference\u002Fmodules\u002Fcommon\u002Fstringx","2.reference\u002F1.modules\u002F1.common\u002Fstringx",{"title":118,"path":119,"stem":120},"tablex","\u002Freference\u002Fmodules\u002Fcommon\u002Ftablex","2.reference\u002F1.modules\u002F1.common\u002Ftablex",false,{"title":123,"path":124,"stem":125,"children":126,"page":121},"Server","\u002Freference\u002Fmodules\u002Fserver","2.reference\u002F1.modules\u002F2.server",[127,131,135,139,143,147,151,155,159,163],{"title":128,"path":129,"stem":130},"selene.attributes","\u002Freference\u002Fmodules\u002Fserver\u002Fselene.attributes","2.reference\u002F1.modules\u002F2.server\u002Fselene.attributes",{"title":132,"path":133,"stem":134},"selene.config","\u002Freference\u002Fmodules\u002Fserver\u002Fselene.config","2.reference\u002F1.modules\u002F2.server\u002Fselene.config",{"title":136,"path":137,"stem":138},"selene.dimensions","\u002Freference\u002Fmodules\u002Fserver\u002Fselene.dimensions","2.reference\u002F1.modules\u002F2.server\u002Fselene.dimensions",{"title":140,"path":141,"stem":142},"selene.entities","\u002Freference\u002Fmodules\u002Fserver\u002Fselene.entities","2.reference\u002F1.modules\u002F2.server\u002Fselene.entities",{"title":144,"path":145,"stem":146},"selene.map","\u002Freference\u002Fmodules\u002Fserver\u002Fselene.map","2.reference\u002F1.modules\u002F2.server\u002Fselene.map",{"title":148,"path":149,"stem":150},"selene.network","\u002Freference\u002Fmodules\u002Fserver\u002Fselene.network","2.reference\u002F1.modules\u002F2.server\u002Fselene.network",{"title":152,"path":153,"stem":154},"selene.players","\u002Freference\u002Fmodules\u002Fserver\u002Fselene.players","2.reference\u002F1.modules\u002F2.server\u002Fselene.players",{"title":156,"path":157,"stem":158},"selene.saves","\u002Freference\u002Fmodules\u002Fserver\u002Fselene.saves","2.reference\u002F1.modules\u002F2.server\u002Fselene.saves",{"title":160,"path":161,"stem":162},"selene.server","\u002Freference\u002Fmodules\u002Fserver\u002Fselene.server","2.reference\u002F1.modules\u002F2.server\u002Fselene.server",{"title":164,"path":165,"stem":166},"selene.sounds","\u002Freference\u002Fmodules\u002Fserver\u002Fselene.sounds","2.reference\u002F1.modules\u002F2.server\u002Fselene.sounds",{"title":168,"path":169,"stem":170,"children":171,"page":121},"Client","\u002Freference\u002Fmodules\u002Fclient","2.reference\u002F1.modules\u002F3.client",[172,176,179,183,187,190,194,197,200,204,208],{"title":173,"path":174,"stem":175},"selene.camera","\u002Freference\u002Fmodules\u002Fclient\u002Fselene.camera","2.reference\u002F1.modules\u002F3.client\u002Fselene.camera",{"title":140,"path":177,"stem":178},"\u002Freference\u002Fmodules\u002Fclient\u002Fselene.entities","2.reference\u002F1.modules\u002F3.client\u002Fselene.entities",{"title":180,"path":181,"stem":182},"selene.game","\u002Freference\u002Fmodules\u002Fclient\u002Fselene.game","2.reference\u002F1.modules\u002F3.client\u002Fselene.game",{"title":184,"path":185,"stem":186},"selene.input","\u002Freference\u002Fmodules\u002Fclient\u002Fselene.input","2.reference\u002F1.modules\u002F3.client\u002Fselene.input",{"title":144,"path":188,"stem":189},"\u002Freference\u002Fmodules\u002Fclient\u002Fselene.map","2.reference\u002F1.modules\u002F3.client\u002Fselene.map",{"title":191,"path":192,"stem":193},"selene.movement.grid","\u002Freference\u002Fmodules\u002Fclient\u002Fselene.movement.grid","2.reference\u002F1.modules\u002F3.client\u002Fselene.movement.grid",{"title":148,"path":195,"stem":196},"\u002Freference\u002Fmodules\u002Fclient\u002Fselene.network","2.reference\u002F1.modules\u002F3.client\u002Fselene.network",{"title":164,"path":198,"stem":199},"\u002Freference\u002Fmodules\u002Fclient\u002Fselene.sounds","2.reference\u002F1.modules\u002F3.client\u002Fselene.sounds",{"title":201,"path":202,"stem":203},"selene.textures","\u002Freference\u002Fmodules\u002Fclient\u002Fselene.textures","2.reference\u002F1.modules\u002F3.client\u002Fselene.textures",{"title":205,"path":206,"stem":207},"selene.ui.lml","\u002Freference\u002Fmodules\u002Fclient\u002Fselene.ui.lml","2.reference\u002F1.modules\u002F3.client\u002Fselene.ui.lml",{"title":209,"path":210,"stem":211},"selene.visuals","\u002Freference\u002Fmodules\u002Fclient\u002Fselene.visuals","2.reference\u002F1.modules\u002F3.client\u002Fselene.visuals",{"title":213,"path":214,"stem":215,"children":216,"page":121},"Data","\u002Freference\u002Fdata","2.reference\u002F2.data",[217,241],{"title":69,"path":218,"stem":219,"children":220,"page":121},"\u002Freference\u002Fdata\u002Fcommon","2.reference\u002F2.data\u002F1.common",[221,225,229,233,237],{"title":222,"path":223,"stem":224},"Component Definition","\u002Freference\u002Fdata\u002Fcommon\u002Fcomponentdefinition","2.reference\u002F2.data\u002F1.common\u002FComponentDefinition",{"title":226,"path":227,"stem":228},"Entity Definition","\u002Freference\u002Fdata\u002Fcommon\u002Fentitydefinition","2.reference\u002F2.data\u002F1.common\u002FEntityDefinition",{"title":230,"path":231,"stem":232},"Sound Definition","\u002Freference\u002Fdata\u002Fcommon\u002Fsounddefinition","2.reference\u002F2.data\u002F1.common\u002FSoundDefinition",{"title":234,"path":235,"stem":236},"Tile Definition","\u002Freference\u002Fdata\u002Fcommon\u002Ftiledefinition","2.reference\u002F2.data\u002F1.common\u002FTileDefinition",{"title":238,"path":239,"stem":240},"Transition Definition","\u002Freference\u002Fdata\u002Fcommon\u002Ftransitiondefinition","2.reference\u002F2.data\u002F1.common\u002FTransitionDefinition",{"title":168,"path":242,"stem":243,"children":244,"page":121},"\u002Freference\u002Fdata\u002Fclient","2.reference\u002F2.data\u002F3.client",[245,249],{"title":246,"path":247,"stem":248},"Audio Definition","\u002Freference\u002Fdata\u002Fclient\u002Faudiodefinition","2.reference\u002F2.data\u002F3.client\u002FAudioDefinition",{"title":250,"path":251,"stem":252},"Visual Definition","\u002Freference\u002Fdata\u002Fclient\u002Fvisualdefinition","2.reference\u002F2.data\u002F3.client\u002FVisualDefinition",{"title":254,"path":255,"stem":256,"children":257,"page":121},"Classes","\u002Freference\u002Fclasses","2.reference\u002F3.classes",[258,286,318],{"title":69,"path":259,"stem":260,"children":261,"page":121},"\u002Freference\u002Fclasses\u002Fcommon","2.reference\u002F3.classes\u002F1.common",[262,266,270,274,278,282],{"title":263,"path":264,"stem":265},"Coordinate","\u002Freference\u002Fclasses\u002Fcommon\u002Fcoordinate","2.reference\u002F3.classes\u002F1.common\u002FCoordinate",{"title":267,"path":268,"stem":269},"CustomRegistryObject","\u002Freference\u002Fclasses\u002Fcommon\u002Fcustomregistryobject","2.reference\u002F3.classes\u002F1.common\u002FCustomRegistryObject",{"title":271,"path":272,"stem":273},"LuaReference","\u002Freference\u002Fclasses\u002Fcommon\u002Fluareference","2.reference\u002F3.classes\u002F1.common\u002FLuaReference",{"title":275,"path":276,"stem":277},"Observable","\u002Freference\u002Fclasses\u002Fcommon\u002Fobservable","2.reference\u002F3.classes\u002F1.common\u002FObservable",{"title":279,"path":280,"stem":281},"RegistryObject","\u002Freference\u002Fclasses\u002Fcommon\u002Fregistryobject","2.reference\u002F3.classes\u002F1.common\u002FRegistryObject",{"title":283,"path":284,"stem":285},"Signal","\u002Freference\u002Fclasses\u002Fcommon\u002Fsignal","2.reference\u002F3.classes\u002F1.common\u002FSignal",{"title":123,"path":287,"stem":288,"children":289,"page":121},"\u002Freference\u002Fclasses\u002Fserver","2.reference\u002F3.classes\u002F2.server",[290,294,298,302,306,310,314],{"title":291,"path":292,"stem":293},"Dimension","\u002Freference\u002Fclasses\u002Fserver\u002Fdimension","2.reference\u002F3.classes\u002F2.server\u002FDimension",{"title":295,"path":296,"stem":297},"Entity","\u002Freference\u002Fclasses\u002Fserver\u002Fentity","2.reference\u002F3.classes\u002F2.server\u002FEntity",{"title":299,"path":300,"stem":301},"LoginQueueEntry","\u002Freference\u002Fclasses\u002Fserver\u002Floginqueueentry","2.reference\u002F3.classes\u002F2.server\u002FLoginQueueEntry",{"title":303,"path":304,"stem":305},"MapTree","\u002Freference\u002Fclasses\u002Fserver\u002Fmaptree","2.reference\u002F3.classes\u002F2.server\u002FMapTree",{"title":307,"path":308,"stem":309},"Player","\u002Freference\u002Fclasses\u002Fserver\u002Fplayer","2.reference\u002F3.classes\u002F2.server\u002FPlayer",{"title":311,"path":312,"stem":313},"ScopedChunkView","\u002Freference\u002Fclasses\u002Fserver\u002Fscopedchunkview","2.reference\u002F3.classes\u002F2.server\u002FScopedChunkView",{"title":315,"path":316,"stem":317},"TransientTile","\u002Freference\u002Fclasses\u002Fserver\u002Ftransienttile","2.reference\u002F3.classes\u002F2.server\u002FTransientTile",{"title":168,"path":319,"stem":320,"children":321,"page":121},"\u002Freference\u002Fclasses\u002Fclient","2.reference\u002F3.classes\u002F3.client",[322,326,330,334,337,341,345,349,353,357,361],{"title":323,"path":324,"stem":325},"Actor","\u002Freference\u002Fclasses\u002Fclient\u002Factor","2.reference\u002F3.classes\u002F3.client\u002FActor",{"title":327,"path":328,"stem":329},"Drawable","\u002Freference\u002Fclasses\u002Fclient\u002Fdrawable","2.reference\u002F3.classes\u002F3.client\u002FDrawable",{"title":331,"path":332,"stem":333},"DrawableVisual2D","\u002Freference\u002Fclasses\u002Fclient\u002Fdrawablevisual2d","2.reference\u002F3.classes\u002F3.client\u002FDrawableVisual2D",{"title":295,"path":335,"stem":336},"\u002Freference\u002Fclasses\u002Fclient\u002Fentity","2.reference\u002F3.classes\u002F3.client\u002FEntity",{"title":338,"path":339,"stem":340},"IsoVisualComponent","\u002Freference\u002Fclasses\u002Fclient\u002Fisovisualcomponent","2.reference\u002F3.classes\u002F3.client\u002FIsoVisualComponent",{"title":342,"path":343,"stem":344},"LuaTexture","\u002Freference\u002Fclasses\u002Fclient\u002Fluatexture","2.reference\u002F3.classes\u002F3.client\u002FLuaTexture",{"title":346,"path":347,"stem":348},"Skin","\u002Freference\u002Fclasses\u002Fclient\u002Fskin","2.reference\u002F3.classes\u002F3.client\u002FSkin",{"title":350,"path":351,"stem":352},"TextFieldTextFieldClickListener","\u002Freference\u002Fclasses\u002Fclient\u002Ftextfield.textfieldclicklistener","2.reference\u002F3.classes\u002F3.client\u002FTextField.TextFieldClickListener",{"title":354,"path":355,"stem":356},"Tile","\u002Freference\u002Fclasses\u002Fclient\u002Ftile","2.reference\u002F3.classes\u002F3.client\u002FTile",{"title":358,"path":359,"stem":360},"Visual2D","\u002Freference\u002Fclasses\u002Fclient\u002Fvisual2d","2.reference\u002F3.classes\u002F3.client\u002FVisual2D",{"title":362,"path":363,"stem":364},"Visual2DComponent","\u002Freference\u002Fclasses\u002Fclient\u002Fvisual2dcomponent","2.reference\u002F3.classes\u002F3.client\u002FVisual2DComponent",{"id":366,"title":59,"body":367,"description":1219,"extension":1220,"meta":1221,"navigation":465,"path":60,"seo":1222,"stem":61,"__hash__":1223},"docs\u002F1.docs\u002Fnetwork-apis.md",{"type":368,"value":369,"toc":1206},"minimark",[370,374,382,385,405,408,413,419,430,433,437,443,497,503,564,570,574,577,642,645,686,689,745,755,759,762,770,773,788,792,795,839,842,859,866,869,873,876,891,894,898,901,928,931,934,938,941,944,1008,1011,1104,1107,1111,1114,1140,1146,1150,1153,1170,1175,1178,1182,1185,1202],[371,372,59],"h1",{"id":373},"bundle-network-api-developer-guide",[375,376,377,378,381],"p",{},"The ",[379,380,148],"code",{}," module lets bundle scripts send custom payloads between client Lua and server Lua. Use it for gameplay messages that are not already covered by built-in systems, such as UI actions, chat commands, inventory requests, HUD updates, notifications, and small state snapshots.",[375,383,384],{},"The module exists on both platforms with different send functions:",[386,387,388,396,399],"ul",{},[389,390,391,392,395],"li",{},"Client scripts can send payloads to the server with ",[379,393,394],{},"sendToServer",".",[389,397,398],{},"Server scripts can send payloads to players, groups of players, or the players controlling entities.",[389,400,401,402,395],{},"Both sides can register incoming payload handlers with ",[379,403,404],{},"handlePayload",[375,406,407],{},"Network payloads are serialized as JSON objects. Treat every client-to-server payload as untrusted input and keep the server authoritative.",[409,410,412],"h2",{"id":411},"when-to-use-network-payloads","When to use network payloads",[375,414,415,416,418],{},"Use ",[379,417,148],{}," when a bundle needs an explicit client\u002Fserver message:",[386,420,421,424,427],{},[389,422,423],{},"A client UI button asks the server to use an item, cast a spell, or submit chat text.",[389,425,426],{},"The server sends HUD values, inventory slots, quest state, music changes, or notifications to a specific player.",[389,428,429],{},"The server sends entity-related UI updates to whoever controls that entity.",[375,431,432],{},"Do not use custom network payloads for data that the engine already synchronizes, such as normal map chunks, entity movement, camera packets, sound playback APIs, or resource bundle updates.",[409,434,436],{"id":435},"client-to-server-flow","Client to server flow",[375,438,439,440,395],{},"On the client, require the module from client Lua and call ",[379,441,442],{},"sendToServer(payloadId, payload)",[444,445,450],"pre",{"className":446,"code":447,"language":448,"meta":449,"style":449},"language-lua shiki shiki-themes github-light github-dark","local Network = require(\"selene.network\")\n\nlocal function requestUseSlot(slotIndex)\n  Network.sendToServer(\"myworld:inventory\u002Fuse_slot\", {\n    slot = slotIndex\n  })\nend\n","lua","",[379,451,452,460,467,473,479,485,491],{"__ignoreMap":449},[453,454,457],"span",{"class":455,"line":456},"line",1,[453,458,459],{},"local Network = require(\"selene.network\")\n",[453,461,463],{"class":455,"line":462},2,[453,464,466],{"emptyLinePlaceholder":465},true,"\n",[453,468,470],{"class":455,"line":469},3,[453,471,472],{},"local function requestUseSlot(slotIndex)\n",[453,474,476],{"class":455,"line":475},4,[453,477,478],{},"  Network.sendToServer(\"myworld:inventory\u002Fuse_slot\", {\n",[453,480,482],{"class":455,"line":481},5,[453,483,484],{},"    slot = slotIndex\n",[453,486,488],{"class":455,"line":487},6,[453,489,490],{},"  })\n",[453,492,494],{"class":455,"line":493},7,[453,495,496],{},"end\n",[375,498,499,500,502],{},"On the server, register a matching handler. Server handlers receive the ",[379,501,307],{}," that sent the payload as their first argument and the decoded payload table as their second argument.",[444,504,506],{"className":446,"code":505,"language":448,"meta":449,"style":449},"local Network = require(\"selene.network\")\n\nNetwork.handlePayload(\"myworld:inventory\u002Fuse_slot\", function(player, payload)\n  local slot = payload.slot\n  if type(slot) ~= \"number\" then\n    return\n  end\n\n  -- Look up the player's server-side inventory here and apply the action.\n  -- Never trust the client to decide whether the action is allowed.\nend)\n",[379,507,508,512,516,521,526,531,536,541,546,552,558],{"__ignoreMap":449},[453,509,510],{"class":455,"line":456},[453,511,459],{},[453,513,514],{"class":455,"line":462},[453,515,466],{"emptyLinePlaceholder":465},[453,517,518],{"class":455,"line":469},[453,519,520],{},"Network.handlePayload(\"myworld:inventory\u002Fuse_slot\", function(player, payload)\n",[453,522,523],{"class":455,"line":475},[453,524,525],{},"  local slot = payload.slot\n",[453,527,528],{"class":455,"line":481},[453,529,530],{},"  if type(slot) ~= \"number\" then\n",[453,532,533],{"class":455,"line":487},[453,534,535],{},"    return\n",[453,537,538],{"class":455,"line":493},[453,539,540],{},"  end\n",[453,542,544],{"class":455,"line":543},8,[453,545,466],{"emptyLinePlaceholder":465},[453,547,549],{"class":455,"line":548},9,[453,550,551],{},"  -- Look up the player's server-side inventory here and apply the action.\n",[453,553,555],{"class":455,"line":554},10,[453,556,557],{},"  -- Never trust the client to decide whether the action is allowed.\n",[453,559,561],{"class":455,"line":560},11,[453,562,563],{},"end)\n",[375,565,377,566,569],{},[379,567,568],{},"player"," argument is the authenticated connection's player object. Use it to scope the action to the sender instead of accepting a player id from the payload.",[409,571,573],{"id":572},"server-to-client-flow","Server to client flow",[375,575,576],{},"On the client, register a handler for the server payload.",[444,578,580],{"className":446,"code":579,"language":448,"meta":449,"style":449},"local Network = require(\"selene.network\")\n\nlocal currentHealth = 0\nlocal maxHealth = 0\n\nNetwork.handlePayload(\"myworld:hud\u002Fhealth\", function(payload)\n  if type(payload.current) ~= \"number\" or type(payload.max) ~= \"number\" then\n    return\n  end\n\n  currentHealth = payload.current\n  maxHealth = payload.max\nend)\n",[379,581,582,586,590,595,600,604,609,614,618,622,626,631,637],{"__ignoreMap":449},[453,583,584],{"class":455,"line":456},[453,585,459],{},[453,587,588],{"class":455,"line":462},[453,589,466],{"emptyLinePlaceholder":465},[453,591,592],{"class":455,"line":469},[453,593,594],{},"local currentHealth = 0\n",[453,596,597],{"class":455,"line":475},[453,598,599],{},"local maxHealth = 0\n",[453,601,602],{"class":455,"line":481},[453,603,466],{"emptyLinePlaceholder":465},[453,605,606],{"class":455,"line":487},[453,607,608],{},"Network.handlePayload(\"myworld:hud\u002Fhealth\", function(payload)\n",[453,610,611],{"class":455,"line":493},[453,612,613],{},"  if type(payload.current) ~= \"number\" or type(payload.max) ~= \"number\" then\n",[453,615,616],{"class":455,"line":543},[453,617,535],{},[453,619,620],{"class":455,"line":548},[453,621,540],{},[453,623,624],{"class":455,"line":554},[453,625,466],{"emptyLinePlaceholder":465},[453,627,628],{"class":455,"line":560},[453,629,630],{},"  currentHealth = payload.current\n",[453,632,634],{"class":455,"line":633},12,[453,635,636],{},"  maxHealth = payload.max\n",[453,638,640],{"class":455,"line":639},13,[453,641,563],{},[375,643,644],{},"On the server, send the payload to the target player.",[444,646,648],{"className":446,"code":647,"language":448,"meta":449,"style":449},"local Network = require(\"selene.network\")\n\nlocal function sendHealth(player, current, max)\n  Network.sendToPlayer(player, \"myworld:hud\u002Fhealth\", {\n    current = current,\n    max = max\n  })\nend\n",[379,649,650,654,658,663,668,673,678,682],{"__ignoreMap":449},[453,651,652],{"class":455,"line":456},[453,653,459],{},[453,655,656],{"class":455,"line":462},[453,657,466],{"emptyLinePlaceholder":465},[453,659,660],{"class":455,"line":469},[453,661,662],{},"local function sendHealth(player, current, max)\n",[453,664,665],{"class":455,"line":475},[453,666,667],{},"  Network.sendToPlayer(player, \"myworld:hud\u002Fhealth\", {\n",[453,669,670],{"class":455,"line":481},[453,671,672],{},"    current = current,\n",[453,674,675],{"class":455,"line":487},[453,676,677],{},"    max = max\n",[453,679,680],{"class":455,"line":493},[453,681,490],{},[453,683,684],{"class":455,"line":543},[453,685,496],{},[375,687,688],{},"The server can also send to multiple players or to the players currently controlling entities.",[444,690,692],{"className":446,"code":691,"language":448,"meta":449,"style":449},"Network.sendToPlayers(players, \"myworld:notice\", {\n  message = \"The gate opens.\"\n})\n\nNetwork.sendToEntity(entity, \"myworld:hud\u002Ftarget\", {\n  name = \"Training Dummy\"\n})\n\nNetwork.sendToEntities(entities, \"myworld:effects\u002Fpulse\", {\n  intensity = 0.75\n})\n",[379,693,694,699,704,709,713,718,723,727,731,736,741],{"__ignoreMap":449},[453,695,696],{"class":455,"line":456},[453,697,698],{},"Network.sendToPlayers(players, \"myworld:notice\", {\n",[453,700,701],{"class":455,"line":462},[453,702,703],{},"  message = \"The gate opens.\"\n",[453,705,706],{"class":455,"line":469},[453,707,708],{},"})\n",[453,710,711],{"class":455,"line":475},[453,712,466],{"emptyLinePlaceholder":465},[453,714,715],{"class":455,"line":481},[453,716,717],{},"Network.sendToEntity(entity, \"myworld:hud\u002Ftarget\", {\n",[453,719,720],{"class":455,"line":487},[453,721,722],{},"  name = \"Training Dummy\"\n",[453,724,725],{"class":455,"line":493},[453,726,708],{},[453,728,729],{"class":455,"line":543},[453,730,466],{"emptyLinePlaceholder":465},[453,732,733],{"class":455,"line":548},[453,734,735],{},"Network.sendToEntities(entities, \"myworld:effects\u002Fpulse\", {\n",[453,737,738],{"class":455,"line":554},[453,739,740],{},"  intensity = 0.75\n",[453,742,743],{"class":455,"line":560},[453,744,708],{},[375,746,747,750,751,754],{},[379,748,749],{},"sendToEntity"," and ",[379,752,753],{},"sendToEntities"," do not broadcast to everyone near an entity. They send to the controlling players of those entities.",[409,756,758],{"id":757},"payload-ids","Payload ids",[375,760,761],{},"Payload ids are plain strings. Use the same namespaced style as registry identifiers:",[444,763,768],{"className":764,"code":766,"language":767,"meta":449},[765],"language-text","myworld:inventory\u002Fuse_slot\nmyworld:hud\u002Fhealth\nmyworld:chat\u002Fsend\n","text",[379,769,766],{"__ignoreMap":449},[375,771,772],{},"Use one payload id per message shape. A clear id makes handlers easy to find and reduces accidental conflicts between bundles.",[375,774,775,776,779,780,783,784,787],{},"Avoid generic ids such as ",[379,777,778],{},"update",", ",[379,781,782],{},"message",", or ",[379,785,786],{},"data",". They are global within the payload handler registry on that side. Registering another handler for the same payload id replaces the previous one.",[409,789,791],{"id":790},"payload-shape","Payload shape",[375,793,794],{},"Payloads must be Lua tables that can be serialized to JSON. The top-level table must use string keys:",[444,796,798],{"className":446,"code":797,"language":448,"meta":449,"style":449},"Network.sendToServer(\"myworld:chat\u002Fsend\", {\n  text = \"Hello\",\n  channel = \"local\",\n  tags = { \"nearby\", \"roleplay\" },\n  metadata = {\n    color = \"white\"\n  }\n})\n",[379,799,800,805,810,815,820,825,830,835],{"__ignoreMap":449},[453,801,802],{"class":455,"line":456},[453,803,804],{},"Network.sendToServer(\"myworld:chat\u002Fsend\", {\n",[453,806,807],{"class":455,"line":462},[453,808,809],{},"  text = \"Hello\",\n",[453,811,812],{"class":455,"line":469},[453,813,814],{},"  channel = \"local\",\n",[453,816,817],{"class":455,"line":475},[453,818,819],{},"  tags = { \"nearby\", \"roleplay\" },\n",[453,821,822],{"class":455,"line":481},[453,823,824],{},"  metadata = {\n",[453,826,827],{"class":455,"line":487},[453,828,829],{},"    color = \"white\"\n",[453,831,832],{"class":455,"line":493},[453,833,834],{},"  }\n",[453,836,837],{"class":455,"line":543},[453,838,708],{},[375,840,841],{},"Supported values are:",[386,843,844,847,850,853,856],{},[389,845,846],{},"strings",[389,848,849],{},"numbers",[389,851,852],{},"booleans",[389,854,855],{},"nested tables with string keys",[389,857,858],{},"array-like tables",[375,860,861,862,865],{},"Do not send Lua functions, userdata, coroutine objects, or tables with mixed key types. They cannot be represented as a JSON payload. Omit absent fields instead of trying to send Lua ",[379,863,864],{},"nil"," values.",[375,867,868],{},"Keep payloads small and specific. Send identifiers, choices, and compact state rather than full registry objects or large map data.",[409,870,872],{"id":871},"optional-empty-payloads","Optional empty payloads",[375,874,875],{},"All send functions accept an omitted payload. The engine sends an empty table in that case.",[444,877,879],{"className":446,"code":878,"language":448,"meta":449,"style":449},"Network.sendToServer(\"myworld:ready\")\nNetwork.sendToPlayer(player, \"myworld:reload_hud\")\n",[379,880,881,886],{"__ignoreMap":449},[453,882,883],{"class":455,"line":456},[453,884,885],{},"Network.sendToServer(\"myworld:ready\")\n",[453,887,888],{"class":455,"line":462},[453,889,890],{},"Network.sendToPlayer(player, \"myworld:reload_hud\")\n",[375,892,893],{},"Handlers still receive a payload table, but it will be empty.",[409,895,897],{"id":896},"handler-lifetime","Handler lifetime",[375,899,900],{},"Register handlers from an entrypoint or module initialization path that runs when your bundle loads.",[444,902,904],{"className":446,"code":903,"language":448,"meta":449,"style":449},"local Network = require(\"selene.network\")\n\nNetwork.handlePayload(\"myworld:ready\", function(player, payload)\n  Network.sendToPlayer(player, \"myworld:ready_ack\")\nend)\n",[379,905,906,910,914,919,924],{"__ignoreMap":449},[453,907,908],{"class":455,"line":456},[453,909,459],{},[453,911,912],{"class":455,"line":462},[453,913,466],{"emptyLinePlaceholder":465},[453,915,916],{"class":455,"line":469},[453,917,918],{},"Network.handlePayload(\"myworld:ready\", function(player, payload)\n",[453,920,921],{"class":455,"line":475},[453,922,923],{},"  Network.sendToPlayer(player, \"myworld:ready_ack\")\n",[453,925,926],{"class":455,"line":481},[453,927,563],{},[375,929,930],{},"If a payload arrives with no registered handler, Selene ignores it. If a Lua handler errors, Selene logs the error with the payload id and the registration trace.",[375,932,933],{},"Because only one handler is stored per payload id on each side, centralize registration for a message instead of registering the same id from multiple files.",[409,935,937],{"id":936},"request-and-response-pattern","Request and response pattern",[375,939,940],{},"For client UI actions, prefer a request\u002Fresponse shape:",[375,942,943],{},"Client:",[444,945,947],{"className":446,"code":946,"language":448,"meta":449,"style":449},"local Network = require(\"selene.network\")\n\nNetwork.sendToServer(\"myworld:settings\u002Fset_title\", {\n  title = \"Blacksmith\"\n})\n\nNetwork.handlePayload(\"myworld:settings\u002Ftitle_result\", function(payload)\n  if payload.ok then\n    -- Update local UI state.\n  else\n    -- Show payload.reason in your UI if appropriate.\n  end\nend)\n",[379,948,949,953,957,962,967,971,975,980,985,990,995,1000,1004],{"__ignoreMap":449},[453,950,951],{"class":455,"line":456},[453,952,459],{},[453,954,955],{"class":455,"line":462},[453,956,466],{"emptyLinePlaceholder":465},[453,958,959],{"class":455,"line":469},[453,960,961],{},"Network.sendToServer(\"myworld:settings\u002Fset_title\", {\n",[453,963,964],{"class":455,"line":475},[453,965,966],{},"  title = \"Blacksmith\"\n",[453,968,969],{"class":455,"line":481},[453,970,708],{},[453,972,973],{"class":455,"line":487},[453,974,466],{"emptyLinePlaceholder":465},[453,976,977],{"class":455,"line":493},[453,978,979],{},"Network.handlePayload(\"myworld:settings\u002Ftitle_result\", function(payload)\n",[453,981,982],{"class":455,"line":543},[453,983,984],{},"  if payload.ok then\n",[453,986,987],{"class":455,"line":548},[453,988,989],{},"    -- Update local UI state.\n",[453,991,992],{"class":455,"line":554},[453,993,994],{},"  else\n",[453,996,997],{"class":455,"line":560},[453,998,999],{},"    -- Show payload.reason in your UI if appropriate.\n",[453,1001,1002],{"class":455,"line":633},[453,1003,540],{},[453,1005,1006],{"class":455,"line":639},[453,1007,563],{},[375,1009,1010],{},"Server:",[444,1012,1014],{"className":446,"code":1013,"language":448,"meta":449,"style":449},"local Network = require(\"selene.network\")\n\nNetwork.handlePayload(\"myworld:settings\u002Fset_title\", function(player, payload)\n  local title = payload.title\n  if type(title) ~= \"string\" or #title > 32 then\n    Network.sendToPlayer(player, \"myworld:settings\u002Ftitle_result\", {\n      ok = false,\n      reason = \"invalid_title\"\n    })\n    return\n  end\n\n  -- Persist the accepted title server-side.\n  Network.sendToPlayer(player, \"myworld:settings\u002Ftitle_result\", {\n    ok = true,\n    title = title\n  })\nend)\n",[379,1015,1016,1020,1024,1029,1034,1039,1044,1049,1054,1059,1063,1067,1071,1076,1082,1088,1094,1099],{"__ignoreMap":449},[453,1017,1018],{"class":455,"line":456},[453,1019,459],{},[453,1021,1022],{"class":455,"line":462},[453,1023,466],{"emptyLinePlaceholder":465},[453,1025,1026],{"class":455,"line":469},[453,1027,1028],{},"Network.handlePayload(\"myworld:settings\u002Fset_title\", function(player, payload)\n",[453,1030,1031],{"class":455,"line":475},[453,1032,1033],{},"  local title = payload.title\n",[453,1035,1036],{"class":455,"line":481},[453,1037,1038],{},"  if type(title) ~= \"string\" or #title > 32 then\n",[453,1040,1041],{"class":455,"line":487},[453,1042,1043],{},"    Network.sendToPlayer(player, \"myworld:settings\u002Ftitle_result\", {\n",[453,1045,1046],{"class":455,"line":493},[453,1047,1048],{},"      ok = false,\n",[453,1050,1051],{"class":455,"line":543},[453,1052,1053],{},"      reason = \"invalid_title\"\n",[453,1055,1056],{"class":455,"line":548},[453,1057,1058],{},"    })\n",[453,1060,1061],{"class":455,"line":554},[453,1062,535],{},[453,1064,1065],{"class":455,"line":560},[453,1066,540],{},[453,1068,1069],{"class":455,"line":633},[453,1070,466],{"emptyLinePlaceholder":465},[453,1072,1073],{"class":455,"line":639},[453,1074,1075],{},"  -- Persist the accepted title server-side.\n",[453,1077,1079],{"class":455,"line":1078},14,[453,1080,1081],{},"  Network.sendToPlayer(player, \"myworld:settings\u002Ftitle_result\", {\n",[453,1083,1085],{"class":455,"line":1084},15,[453,1086,1087],{},"    ok = true,\n",[453,1089,1091],{"class":455,"line":1090},16,[453,1092,1093],{},"    title = title\n",[453,1095,1097],{"class":455,"line":1096},17,[453,1098,490],{},[453,1100,1102],{"class":455,"line":1101},18,[453,1103,563],{},[375,1105,1106],{},"This keeps the client responsive without giving it authority over server state.",[409,1108,1110],{"id":1109},"targeting-choices-on-the-server","Targeting choices on the server",[375,1112,1113],{},"Choose the narrowest target that matches the gameplay event:",[386,1115,1116,1122,1128,1134],{},[389,1117,1118,1121],{},[379,1119,1120],{},"sendToPlayer(player, payloadId, payload)"," sends to one player.",[389,1123,1124,1127],{},[379,1125,1126],{},"sendToPlayers(players, payloadId, payload)"," sends the same payload to several players.",[389,1129,1130,1133],{},[379,1131,1132],{},"sendToEntity(entity, payloadId, payload)"," sends to all players controlling that entity.",[389,1135,1136,1139],{},[379,1137,1138],{},"sendToEntities(entities, payloadId, payload)"," sends to all players controlling any of those entities.",[375,1141,415,1142,1145],{},[379,1143,1144],{},"sendToPlayer"," for private UI state such as inventory, health, quests, and permissions. Use entity targeting when the message belongs to controlled-entity state and the controlling player set is the intended audience.",[409,1147,1149],{"id":1148},"validation-and-security","Validation and security",[375,1151,1152],{},"Client-to-server payloads are requests, not facts. Validate:",[386,1154,1155,1158,1161,1164,1167],{},[389,1156,1157],{},"field types",[389,1159,1160],{},"string length",[389,1162,1163],{},"numeric range",[389,1165,1166],{},"whether the sender is allowed to perform the action",[389,1168,1169],{},"whether referenced entities, items, coordinates, or registry ids are visible and usable by that player",[375,1171,1172,1173,395],{},"Avoid payloads where the client tells the server who the acting player is. The server handler already receives the authenticated ",[379,1174,568],{},[375,1176,1177],{},"For server-to-client payloads, do not send secrets or server-only state. Clients can inspect their local scripts and network data.",[409,1179,1181],{"id":1180},"reference","Reference",[375,1183,1184],{},"The Lua reference pages list the exact function signatures:",[386,1186,1187,1195],{},[389,1188,1189],{},[1190,1191,1192,1193],"a",{"href":149},"Server ",[379,1194,148],{},[389,1196,1197],{},[1190,1198,1199,1200],{"href":195},"Client ",[379,1201,148],{},[1203,1204,1205],"style",{},"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":449,"searchDepth":462,"depth":462,"links":1207},[1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218],{"id":411,"depth":462,"text":412},{"id":435,"depth":462,"text":436},{"id":572,"depth":462,"text":573},{"id":757,"depth":462,"text":758},{"id":790,"depth":462,"text":791},{"id":871,"depth":462,"text":872},{"id":896,"depth":462,"text":897},{"id":936,"depth":462,"text":937},{"id":1109,"depth":462,"text":1110},{"id":1148,"depth":462,"text":1149},{"id":1180,"depth":462,"text":1181},"Send custom payloads between Selene client and server bundle scripts with selene.network.","md",{},{"title":59,"description":1219},"YZc5KtZd-jnZTjQaHGHH71v1hosB3tlRXRY3BzaAcGA",[1225,1227],{"title":55,"path":56,"stem":57,"description":1226,"children":-1},"Learn how to create client-side resource packs by overriding assets and visual definitions through bundles.",null,1792747966455]