252 lines
6.5 KiB
Bash
Executable File
252 lines
6.5 KiB
Bash
Executable File
#!/bin/bash
|
|
state=''
|
|
dyed=0
|
|
keepalive=0
|
|
pos=(0 0 0)
|
|
players=()
|
|
TEMP=/dev/shm/witchcraft/
|
|
mkdir -p $TEMP $TEMP/players $TEMP/world
|
|
|
|
source src/log.sh
|
|
source src/int.sh
|
|
source src/misc.sh
|
|
source src/palette.sh
|
|
source src/chunk.sh
|
|
source src/packet.sh
|
|
source src/hooks.sh
|
|
|
|
if [[ -f "$1" ]]; then
|
|
log "Loading plugin: $1"
|
|
source "$1"
|
|
fi
|
|
|
|
function keep_alive() {
|
|
while true; do
|
|
sleep 5
|
|
log "sending keepalive"
|
|
echo '092100000000000000ff' | xxd -p -r
|
|
# random data
|
|
done
|
|
}
|
|
|
|
function position_delta() {
|
|
local deltaX
|
|
local deltaY
|
|
local deltaZ
|
|
|
|
# pos[0]=0
|
|
# pos[1]=0
|
|
# pos[2]=0
|
|
pos_old[0]=0
|
|
pos_old[1]=0
|
|
pos_old[2]=0
|
|
|
|
while true; do
|
|
sleep 0.1
|
|
for i in $(ls "$TEMP/players/"); do
|
|
if [[ "$i" != "$nick" ]]; then
|
|
pos[0]=$(cat $TEMP/players/$i/position | awk -F, '{print($1)}') # idk, floating point broke
|
|
pos[1]=$(cat $TEMP/players/$i/position | awk -F, '{print($2)}')
|
|
pos[2]=$(cat $TEMP/players/$i/position | awk -F, '{print($3)}')
|
|
log "posX: ${pos[0]}"
|
|
deltaX=$((((${pos[0]}*32) - (${pos_old[0]}*32)) * 128))
|
|
deltaY=$(((${pos[1]}*32 - ${pos_old[1]}*32) * 128))
|
|
deltaZ=$(((${pos[2]}*32 - ${pos_old[2]}*32) * 128))
|
|
|
|
|
|
if [[ $deltaX != 0 || $deltaY != 0 || $deltaZ != 0 ]]; then
|
|
pkt_position $deltaX $deltaY $deltaZ $(cat $TEMP/players/$i/eid)
|
|
fi
|
|
pos_old=("${pos[@]}")
|
|
fi
|
|
done
|
|
done
|
|
}
|
|
|
|
function handle_broadcast() {
|
|
while true; do
|
|
for i in $(ls "$TEMP/players/"); do
|
|
if [[ "$i" != "$nick" ]]; then
|
|
if [[ -f $TEMP/players/$i/broadcast ]]; then
|
|
packet="$(cat $TEMP/players/$i/broadcast)"
|
|
if [[ "$last" != "$packet" ]]; then
|
|
cat $TEMP/players/$i/broadcast
|
|
last="$packet"
|
|
fi
|
|
else
|
|
last=''
|
|
fi
|
|
fi
|
|
done
|
|
sleep 1
|
|
done
|
|
}
|
|
|
|
function spawn_players() {
|
|
for i in $(ls "$TEMP/players/"); do # fite me
|
|
if [[ $i != $nick && ${players[@]} != *"$i"* ]]; then
|
|
log "name: $i EID: $eid"
|
|
pkt_playerinfo_add $i $(cat $TEMP/players/$i/eid)
|
|
pkt_spawnplayer $(cat $TEMP/players/$i/eid)
|
|
players+=("$nick")
|
|
fi
|
|
done
|
|
}
|
|
|
|
while true; do
|
|
len=$(varint2int)
|
|
|
|
a=$(dd count=$len bs=1 status=none | xxd -p)
|
|
if [[ "$a" == '' ]]; then
|
|
log "connection dyed"
|
|
pkill -P $$
|
|
pkt_chatmessage "- $nick" "00000000000000000000000000000000" > $TEMP/players/$nick/broadcast
|
|
sleep 0.3
|
|
rm -R "$TEMP/players/$nick"
|
|
exit
|
|
fi
|
|
|
|
if [[ -f /tmp/block ]]; then
|
|
res="$(encode_position 10 -10 10)"
|
|
res+="01"
|
|
|
|
log "$res"
|
|
echo -n "$(hexpacket_len "$res")0c$res" | xxd -p -r
|
|
rm -R /tmp/block
|
|
fi
|
|
|
|
if [[ -f /tmp/spawn ]]; then
|
|
spawn_players
|
|
rm /tmp/spawn
|
|
fi
|
|
|
|
if [[ $a == "00"* ]]; then
|
|
log "responding to 00; state: $state"
|
|
|
|
if [[ "$state" == '01' ]]; then
|
|
log "status response"
|
|
|
|
#json='{"version":{"name":"1.18.1","protocol":757},"players":{"max":100,"online":5,"sample":[{"name":"uwu","id":"4566e69f-c907-48ee-8d71-d7ba5aa00d20"}]},"description":{"text":"Hello world"}}'
|
|
json='{"version":{"name":"§a§kaaa§aUwU§kaaa","protocol":756},"players":{"max":1,"online":0,"sample":[]},"description":{"text":"§aUwU"},"favicon":"data:image/png;base64,'"$(base64 -w0 icon.png)"'"}'
|
|
res="$(str_len "$json")$(echo -n "$json" | xxd -p)"
|
|
echo "$(hexpacket_len "$res")00$res" | xxd -p -r
|
|
|
|
state=''
|
|
elif [[ "$state" == '02' ]]; then
|
|
nick=$(cut -c 5- <<< "$a" | xxd -p -r | grep -Poh '[A-Za-z0-9_-]*')
|
|
eid=$(printf "%04x" $RANDOM | cut -c 1-4)
|
|
mkdir -p $TEMP/players/$nick
|
|
echo -n $eid > $TEMP/players/$nick/eid
|
|
pkt_chatmessage "+ $nick" "00000000000000000000000000000000" > $TEMP/players/$nick/broadcast
|
|
log "login response"
|
|
if [[ $keepalive == 0 ]]; then
|
|
hook_keepalive
|
|
keepalive=1
|
|
fi
|
|
|
|
# random uuid string len string (nick)
|
|
res="0000000000000000000000000000$eid$(str_len "$nick")$(echo -n "$nick" | xxd -p)"
|
|
log "$(hexpacket_len "$res")02$res"
|
|
echo -n "$(hexpacket_len "$res")02$res" | xxd -p -r
|
|
|
|
|
|
res="$(encode_position 0 0 0)"
|
|
res+="00000000" # angle as float
|
|
|
|
echo -n "$(hexpacket_len "$res")4B$res" | xxd -p -r
|
|
log "sent spawn position"
|
|
|
|
#res="00000000" # entity id (0 or -2147483648, idk)
|
|
#res+="00" # not hardcore
|
|
#res+="00" # survival mode
|
|
#res+="01" # ... as previously seen on Creative Mode (ignored)
|
|
#res+="01" # one dimension
|
|
#res+="13$(echo -n "minecraft:overworld" | xxd -p)"
|
|
#res+="0a000000" # dimension codec
|
|
#res+="0a000000" # dimension
|
|
#res+="13$(echo -n "minecraft:overworld" | xxd -p)" # dimension being spawned into
|
|
#res+="0000000000000000" # beginning of sha256 of seed
|
|
#res+="0f" # max players (ignored)
|
|
#res+="02" # view distance (min 2 chunks)
|
|
#res+="02" # simulation distance
|
|
#res+="00" # reduced debug info? (false)
|
|
#res+="00" # enable respawn screen
|
|
#res+="00" # is debug (surprisingly, no)
|
|
#res+="01" # is flat (yeah, sure)
|
|
|
|
#rhexlog "$(hexpacket_len "$res")26$res"
|
|
#echo -n "$(hexpacket_len "$res")26$res" | xxd -p -r
|
|
#log "sent join game"
|
|
|
|
cat nbt_
|
|
log "sent (hardcoded) join game"
|
|
|
|
# send inventory (0x14)
|
|
res="00" # inventory id
|
|
res+="00" # state
|
|
res+="09" # item count
|
|
for i in {1..9}; do
|
|
res+="01 0$i 7f 00" # stone block
|
|
done
|
|
res+="01 00 01 00" # again, for held
|
|
|
|
echo -n "$(hexpacket_len "$res")14$res" | xxd -p -r
|
|
log "sent inventory"
|
|
|
|
hook_chunks
|
|
pkt_pos
|
|
spawn_players
|
|
|
|
|
|
state=''
|
|
else
|
|
if [[ $a == *"01" ]]; then # 01 - next state: status
|
|
log 'set status'
|
|
state='01'
|
|
else # 02 - next state: login
|
|
log 'set login'
|
|
state='02'
|
|
fi
|
|
fi
|
|
elif [[ $a == "01"* ]]; then
|
|
log "responding to 01"
|
|
echo "$len$a" | xxd -p -r
|
|
log "bye"
|
|
exit
|
|
elif [[ $a == "0f"* ]]; then
|
|
log "received keepalive"
|
|
date "+%s" > $TEMP/players/$nick/ping
|
|
elif [[ $a == "11"* ]]; then
|
|
pos[0]=$(from_ieee754 $(cut -c 3-18 <<< "$a"))
|
|
pos[1]=$(from_ieee754 $(cut -c 19-34 <<< "$a"))
|
|
pos[2]=$(from_ieee754 $(cut -c 35-50 <<< "$a"))
|
|
echo "${pos[0]},${pos[1]},${pos[2]}" > $TEMP/players/$nick/position
|
|
hook_move
|
|
elif [[ $a == "12"* ]]; then
|
|
pos[0]=$(from_ieee754 $(cut -c 3-18 <<< "$a"))
|
|
pos[1]=$(from_ieee754 $(cut -c 19-34 <<< "$a"))
|
|
pos[2]=$(from_ieee754 $(cut -c 35-50 <<< "$a"))
|
|
hook_move
|
|
elif [[ $a == "13"* ]]; then
|
|
log "received Player Rotation"
|
|
elif [[ $a == "1a"* ]]; then
|
|
#cut -c 3-
|
|
hook_dig
|
|
elif [[ $a == "2c"* ]]; then
|
|
hook_swing
|
|
elif [[ $a == "2e"* ]]; then
|
|
hook_block
|
|
elif [[ $a == "03"* ]]; then
|
|
if [[ $((0x$(cut -c 3-4 <<< "$a"))) -lt 127 ]]; then # lazy varint check
|
|
msg=$(cut -c 5- <<< "$a" | xxd -p -r)
|
|
else
|
|
msg=$(cut -c 3- <<< "$a" | xxd -p -r)
|
|
fi
|
|
hook_chat
|
|
else
|
|
log "unknown data from client"
|
|
rhexlog "$a"
|
|
fi
|
|
|
|
done
|