Skip to content

Examples

3add edited this page May 23, 2026 · 30 revisions

This page lists examples of things you can do with PacketEventsSK. This page is made for you to understand the syntax and ideas of package management, do not just copy paste the listed content.

Welcome

Based on PacketEventsSK v1.1.3 with SkBee v3.23.0 on Paper v26.1.2

on join:
    set {_p} to player

    set {_meta} to a new fake text display meta:
        display billboard: center
        display content: "<rainbow>WELCOME %{_p}%"

    set {_display} to a new fake text display entity:
        location: location 2 blocks infront of player
        viewers: player
        meta: {_meta}
 
    set {_interactionMeta} to a new fake interaction meta:
        interaction height: 1
        interaction width: 2

    set {_interactable} to a new fake interaction entity:
        location: location 2 blocks infront of player
        viewers: player
        meta: {_interactionMeta}

    set {-interactables::%{_p}'s uuid%} to fake entity id of {_interactable}

    wait 5 seconds

    kill fake entities {_display} and {_interactable}
    clear {-interactables::%player's uuid%}

on serverbound interact entity:
    set {_id} to packet field entity id of event-packet
    set {_hand} to packet field hand of event-packet
    set {_sneaking} to packet field sneaking state of event-packet

    if all:
        {_id} is {-interactables::%player's uuid%}
        # this packet is sent for each hand when just regular clicking
        # "main hand" is parsed as equipment slot if literal so we parse from text
        {_hand} is "main hand" parsed as interaction hand
        {_sneaking} is false
    then:
        send "<rainbow>welcome player!"

Reduced Debug Toggle

Based on PacketEventsSK v1.1.4 with SkBee v3.23.0 on Paper v26.1.2

This examples can be used to hide things such as coordinates from players' f3 menus. It's a rather simple example. Full list can be found here: Debug Screen info lines (more info on entity status can be found here: Entity Statuses)

# hides certain things (including XYZ) from the f3 menu
command toggleDebug:
    trigger:
        set {_entityId} to protocol id of player

        if {-debugMode::%player's uuid%} is true:
            set {-debugMode::%player's uuid%} to false
            set {_status} to 23
        else:
            set {-debugMode::%player's uuid%} to true
            set {_status} to 22

        set {_packet} to a new clientbound entity status packet:
            entity id: {_entityId}
            status: {_status}

        send packet {_packet} to player

Confetti

Based on PacketEventsSK v1.1.3 with SkBee v3.23.0 on Paper v26.1.2

Created by Crebs huge shoutout!

Confetti using text displays

function confetti(p: player):
    loop 1000 times:
        confettiPiece({_p})
        wait 1 tick

local function emptyText(loc: location):: fake entity:

    set {_meta} to text display meta data:
        display content: " "
        display text shadowed state: true
        display billboard: center
        display scale: vector(1.2,1.2,1.2)
        display translation: vector(-0.03,0.65,0)
        display background color: rgb(random integer between 0 and 255, random integer between 0 and 255, random integer between 0 and 255)
        display view range: 1
        display transform interpolation duration: 2 ticks
        display interpolation delay: 0 ticks

    return a new fake text display entity:
        viewers: all players
        location: {_loc} ~ vector(0,0.5,0)
        meta: {_meta}

local function confettiPiece(p: player):
    set {_loc} to {_p}'s location ~ (vector in direction of {_p})*vector(2.5, 2.25, 2.5)
    set {_e} to emptyText({_loc})

    set {_v} to vector(random number between -0.25 and 0.25, random number between 0.15 and 0.35, random number between -0.25 and 0.25)

    set {_axis} to vector(random number between -1 and 1, random number between -1 and 1, random number between -1 and 1)
    set {_angle} to random number between 0 and 360
    set {_spin} to random number between 10 and 25

    run 1 tick later repeating every 2 ticks:
        add 1 to {_c}
        if {_c} >= 70:
            kill fake entity {_e}
            stop

        set {_v} to ({_v} * vector(0.93, 1, 0.93)) - vector(0, 0.05, 0) + vector(random number between -0.01 and 0.01, 0, random number between -0.01 and 0.01)

        set {_t} to vector(-0.03, 0.65, 0) + {_v}
        set meta display translation of {_e} to {_t}
        add {_spin} to {_angle}
        set meta display left rotation of {_e} to axisAngle({_angle}, {_axis})

Sign Exploit

Based on PacketEventsSK v1.1.3 with SkBee v3.23.0 on Paper v26.1.2

This example makes use of a sign exploit described in MC-265322 and on wurst wiki. It can be used to see which mods are or aren't installed on a connected player. (and is thus very powerful for anti cheating purposes)

Basically the way it works:

  1. server sends a fake sign with a line having a translatable component or keybind component (clientbound block change packet and clientbound block entity data packet)
  2. server forces the client to open the editor of the sign (clientbound open sign editor packet)
  3. server forces the client to close the editor (clientbound close window packet)
  4. client closes the editor and as a response sends the "new content" (which is unchanged) to the server (serverbound update sign packet received by server on line 57)
  5. server reads the new content: if it parsed the translatable/keybind component it has the keybind set and thus has the mod otherwise not
on load:
    delete {-blackListedKeybinds::*}
    add "key.freecam.toggle" to {-blackListedKeybinds::*}
    add "key.freecam.playerControl" to {-blackListedKeybinds::*}
    add "key.freecam.tripodReset" to {-blackListedKeybinds::*}
    add "key.freecam.configGui" to {-blackListedKeybinds::*}

function createSignNBT(bind: string) :: nbt compound:
    set {_nbtString} to "{front_text:{messages:[{""keybind"":""%{_bind}%""},{""text"":""""},{""text"":""""},{""text"":""""}]}}"
    return nbt compound from {_nbtString}

function startKeybindChecks(p: player):
    set {_uuid} to uuid of {_p}
    
    delete {-keybindQueue::%{_uuid}%::*}
    
    loop {-blackListedKeybinds::*}:
        add loop-value to {-keybindQueue::%{_uuid}%::*}
        
    checkNextKeybind({_p})

function checkNextKeybind(p: player):
    set {_uuid} to uuid of {_p}
    
    set {_keybind} to first element of {-keybindQueue::%{_uuid}%::*}
    
    if {_keybind} is set:
        check({_p}, {_keybind})
    else:
        delete {-keybindQueue::%{_uuid}%::*}

function check(p: player, keybind: string):
    set {_pos} to vector of {_p}'s location

    set {_blockPacket} to a new clientbound block change packet:
        block position: {_pos}
        block state: oak sign[]

    set {_setTextPacket} to a new clientbound block entity data packet:
        block position: {_pos}
        block entity type: sign block entity type
        nbt compound: createSignNBT({_keybind})

    set {_signPacket} to clientbound open sign editor packet:
        block position: {_pos}
        sign side: front
    
    set {_closeWindowPacket} to a clientbound close window packet

    set {_revertBlockPacket} to new clientbound block change packet:
        block position: {_pos}
        block state: air[]
    
    # Sends the packets (order sensitive)
    send packet {_blockPacket}, {_setTextPacket}, {_signPacket}, {_closeWindowPacket} and {_revertBlockPacket} to {_p} 

on serverbound update sign packet sync processed:
    set {_p} to event-player
    set {_uuid} to uuid of {_p}
    
    if {-keybindQueue::%{_uuid}%::*} is set:
        
        set {_firstIndex} to first element of indices of {-keybindQueue::%{_uuid}%::*}
        set {_expected} to {-keybindQueue::%{_uuid}%::%{_firstIndex}%}
        
        delete {-keybindQueue::%{_uuid}%::%{_firstIndex}%}

        set {_updateSignPacket} to event-packet
        set {_text} to first element of packet sign lines of event-packet

        if {_text} is not {_expected}:
            delete {-keybindQueue::%{_uuid}%::*}
            kick {_p} due to "Unsupported client modification detected!"
        else:
            send "%{_p}% passed keybind check for: %{_expected}%" to console
            wait 1 tick
            if {_p} is online:
                checkNextKeybind({_p})
                
on join:
    wait 3 seconds
    startKeybindChecks(player)

Scrollable GUI

Based on PacketEventsSK v1.1.3 with SkBee v3.23.0 on Paper v26.1.2

This example makes use of another unintended feature of the minecraft protocol that allows for a scrollable GUI (where the content scrolls with you) There are multiple ways of doing this but one of the ways is intercepting a serverbound select bundle item packet and based of it's data determining in which direction the client scrolled. Works like this:

  1. user scrolls, the mc vanilla client sends serverbound select bundle item
  2. the server receives the packet and reads it's content (on line 34-36)
  3. we evaluate if the user scrolled up or down based on the data (line 68-87)
  4. we update the GUI accordingly
on load:
    set {-baseBundle} to a bundle with item flags hide additional tooltip
    add stone, stone, and stone to bundle contents of {-baseBundle}

command blocks:
    trigger:
        openBlocks(player)

function openBlocks(p: player, scroll: integer = 0):
    set {_gui} to new chest inventory with 6 rows named "Blocks"

    set {-prevPlayerScroll::%{_p}'s uuid%} to {_scroll}
    set {_skipAmount} to {_scroll} * 9
    set {_slot} to 0

    loop blocks:
        if any:
            loop-iteration <= {_skipAmount}
            type of loop-value is air
        then:
            continue
            
        if {_slot} >= 54:
            stop loop

        set {_i} to {-baseBundle} named proper case "&f%loop-value%"
        add stone, dirt and cobblestone to bundle contents of {_i}
        set item model of {_i} to "%namespaced key of loop-value%"
        
        set slot {_slot} of {_gui} to {_i}
    
        add 1 to {_slot}

    open {_gui} to {_p}
    
on serverbound select bundle item sync processed:
    set {_index} to packet selected item index of event-packet
    set {_slotId} to packet slot id of event-packet

    set {_action} to getScrollAction({-prevScroll::%{_slotId}%}, {_index}, 3)

    if {_action} is "DONE":
        clear {-prevScroll::%{_slotId}%}
    else:
        set {-prevScroll::%{_slotId}%} to {_index}
        
    if {_action} is "UP":
        clear {-prevScroll::%{_slotId}%}
        openBlocks(player, {-prevPlayerScroll::%player's uuid%} + 1)
    else if all:
        {_action} is "DOWN"
        {-prevPlayerScroll::%player's uuid%} - 1 > 0
    then:
        clear {-prevScroll::%{_slotId}%}
        openBlocks(player, {-prevPlayerScroll::%player's uuid%} - 1)

local function getScrollAction(prevIndex: integer, newIndex: integer, maxIndex: integer) :: string:
    if {_newIndex} is -1:
        return "DONE"

    if {_prevIndex} is not set: # first scroll
        if {_newIndex} is {_maxIndex} - 1:
            return "UP"
        else if {_newIndex} is 0:
            return "DOWN"

    if all:
        {_prevIndex} is {_maxIndex} - 1
        {_newIndex} is 0
    then:
        return "DOWN"

    if all:
        {_prevIndex} is 0
        {_newIndex} is {_maxIndex} - 1
    then:
        return "UP"

    if {_prevIndex} > {_newIndex}:
        return "UP"
    else:
        return "DOWN"

Clone this wiki locally