+ digmeout minigame, usability fixes

meow
Dominika 2022-02-14 01:54:31 +01:00
parent 4bdc24558e
commit 59d995019d
6 changed files with 314 additions and 81 deletions

180
demos/digmeout.sh Normal file
View File

@ -0,0 +1,180 @@
#!/usr/bin/env bash
# digmeout - a score-based minigame
# mine out as much ores before the time runs out
time_left=30
score=0
spawn_pos=(8 -40 8)
# palette expanded for easier randomization
palette+=("45") # gold
palette+=("47") # iron
palette+=("49") # coal
palette+=("8702") # lapis
palette+=("d21a") # diamond
palette+=("cf2a") # emerald
palette+=("9a8b01") # copper
palette+=("f11e") # redstone
for i in {1..15}; do
palette+=("01") # stone
palette+=("02") # granite
palette+=("04") # diorite
done
function hook_chunks() {
local ore
local plane
log "hooking chunks"
rm -R $TEMP/world/*
chunk_header
oremap=()
for (( y=0; y<16; y++ )); do
plane=''
for (( x=0; x<16; x++ )); do
for (( z=0; z<16; z++ )); do
ore=$(printf '%02x' $(((RANDOM%52)+31)))
chunk+="$ore"
plane+="$ore"
done
done
oremap+=("$plane")
done
chunk_footer
echo "${oremap[@]}" > $TEMP/players/$nick/oremap
echo "$chunk" > $TEMP/world/0000000000000000
pkt_chunk FFFFFFFF FFFFFFFF 00
pkt_chunk FFFFFFFF 00000000 00
pkt_chunk FFFFFFFF 00000001 00
pkt_chunk 00000000 FFFFFFFF 00
pkt_chunk 00000000 00000000
pkt_chunk 00000000 00000001 00
pkt_chunk 00000001 FFFFFFFF 00
pkt_chunk 00000001 00000000 00
pkt_chunk 00000001 00000001 00
echo '0' > $TEMP/players/$nick/score
pkt_title "Get, set..."
}
function hook_start() {
timer &
pkt_title "Go!"
}
function timer() {
while true; do
if [[ $time_left -le 0 ]]; then
pos=$(cat $TEMP/players/$nick/position)
pkt_effect $(awk -F, '{print $1}' <<< "$pos") $(awk -F, '{print $2}' <<< "$pos") $(awk -F, '{print $3}' <<< "$pos") 1032
sleep 1
break
elif [[ $time_left -le 5 ]]; then
sleep 1
pos=$(cat $TEMP/players/$nick/position)
pkt_effect $(awk -F, '{print $1}' <<< "$pos") $(awk -F, '{print $2}' <<< "$pos") $(awk -F, '{print $3}' <<< "$pos") 1000
time_left=$((time_left-1))
elif [[ $time_left -le 10 ]]; then
sleep 5
time_left=$((time_left-5))
else
sleep 10
time_left=$((time_left-10))
fi
pkt_chatmessage "§aTime left: §r${time_left}s" "00000000000000000000000000000000"
done
pkt_disconnect "Time's up! Your final score: §a$(cat $TEMP/players/$nick/score)"
}
function score() {
# egh, async in Bash sucks
score=$(cat $TEMP/players/$nick/score)
if [[ "$block" == 45 ]]; then
score=$((score+7))
elif [[ "$block" == 47 ]]; then
score=$((score+5))
elif [[ "$block" == 49 ]]; then
score=$((score+1))
elif [[ "$block" == 8702 ]]; then
score=$((score+6))
elif [[ "$block" == d21a ]]; then
score=$((score+25))
elif [[ "$block" == cf2a ]]; then
score=$((score+15))
elif [[ "$block" == 9a8b01 ]]; then
score=$((score+3))
elif [[ "$block" == f11e ]]; then
score=$((score+15))
fi
pkt_experience "$score"
echo "$score" > $TEMP/players/$nick/score
}
function dig_async() {
if [[ $block == 01 ]]; then
d=0.03
else
d=0.07
fi
for i in {1..9}; do
pkt_blockbreak $x $y $z 0$i
sleep $d
if [[ $(cat $TEMP/players/$nick/mining) != "$x,$y,$z" ]]; then
pkt_blockbreak $x $y $z ff
break
fi
done
if [[ $(cat $TEMP/players/$nick/mining) == "$x,$y,$z" ]]; then
pkt_diggingack $x $y $z 00 02
score
fi
}
function hook_dig() {
log $x
log $y
log $z
log $a
ore=$(cat $TEMP/players/$nick/oremap | awk '{print $'"$((y+64))"'}' | sed -E 's/.{32}/&\n/g' | head -n $((z+1)) | tail -n 1 | sed -E 's/(.{16})(.{16})/\2\1/g;s/.{2}/&\n/g' | tail -n $((x+2)) | head -n1)
block=${palette[$((0x$ore))]}
if [[ $a == "1a02"* ]]; then # finished digging?
score
elif [[ $a == "1a00"* ]]; then
echo "$x,$y,$z" > $TEMP/players/$nick/mining
dig_async &
elif [[ $a == "1a01"* ]]; then
echo "catgirls" > $TEMP/players/$nick/mining
fi
}
function hook_move() {
if [[ ${pos[1]} -lt -96 ]]; then
# utf-8 is actually only valid for strings created in the UTF world region
# everything else is just sparkling unicode
pkt_disconnect "$(xxd -p -r <<< "c2af5c5c5f28e38384295f2fc2af")"
fi
}
function hook_keepalive() {
keep_alive &
}
function hook_ping() {
json='{"version":{"name":"1.18.1","protocol":757},"players":{"max":1,"online":0,"sample":[]},"description":{"text":"Minigame: §adigmeout§r | '"$time_left"' seconds per game"},"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
}
function hook_inventory() {
items=($(repeat 36 "0 "))
items+=("721")
log ${items[1]}
pkt_inventory items
}

View File

@ -1,31 +0,0 @@
#!/usr/bin/env bash
function hook_chunks() {
log "hooking chunks"
echo "ffff081f00 01 09 0a 0e 0f 15 21 00 31 00 41 42 44 45 47 49 4d 9401 8402 8602 8702 8902 00 9602 00 00 00 00 00 f60a8004" > $TEMP/world/0000000000000000
map=""
for (( i=0; i<4097; i++ )); do
map+="$(printf '%02x' $((RANDOM%15)))"
done
echo "$map" >> $TEMP/world/0000000000000000
echo "000100000000000000010000000000000001000000000000000100000000000000010000000000000001000000000000000100000000000000010000000000000001000000000000000100000000000000010000000000000001000000000000000100000000000000010000000000000001000000000000000100000000000000010000000000000001000000000000000100000000000000010000000000000001000000000000000100000000000000010000000000000001000000000000000100000000000000010000000000000001" >> $TEMP/world/0000000000000000
pkt_chunk FFFFFFFF FFFFFFFF
pkt_chunk FFFFFFFF 00000000
pkt_chunk FFFFFFFF 00000001
pkt_chunk 00000000 FFFFFFFF
pkt_chunk 00000000 00000000
pkt_chunk 00000000 00000001
pkt_chunk 00000001 FFFFFFFF
pkt_chunk 00000001 00000000
pkt_chunk 00000001 00000001
}
function hook_block() {
}

62
mc.sh
View File

@ -4,6 +4,7 @@ dyed=0
keepalive=0
pos=(0 0 0)
players=()
time=1609000
TEMP=/dev/shm/witchcraft/
mkdir -p $TEMP $TEMP/players $TEMP/world
@ -22,10 +23,16 @@ fi
function keep_alive() {
while true; do
sleep 5
sleep 1
log "sending keepalive"
echo '092100000000000000ff' | xxd -p -r
# random data
res=$(printf '%016x' $time)
res=$res$res
log time: $res
time=$((time+240))
echo -n "$(hexpacket_len "$res")59$res" | xxd -p -r
done
}
@ -106,30 +113,13 @@ while true; do
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
hook_ping
state=''
elif [[ "$state" == '02' ]]; then
@ -137,7 +127,6 @@ while true; do
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
@ -149,14 +138,7 @@ while true; do
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="$eid" # entity id
#res+="00" # not hardcore
#res+="00" # survival mode
#res+="01" # ... as previously seen on Creative Mode (ignored)
@ -179,25 +161,19 @@ while true; do
#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
log "sent (hardcoded) join game"
#res="$(encode_position 10 10 10)"
#res+="00000000" # angle as float
echo -n "$(hexpacket_len "$res")14$res" | xxd -p -r
log "sent inventory"
#echo -n "$(hexpacket_len "$res")4B$res" | xxd -p -r
#log "sent spawn position"
hook_inventory
hook_chunks
pkt_pos
pkt_pos ${spawn_pos[0]} ${spawn_pos[1]} ${spawn_pos[2]}
spawn_players
(sleep 1; hook_start) &
state=''
else
if [[ $a == *"01" ]]; then # 01 - next state: status
@ -230,7 +206,7 @@ while true; do
elif [[ $a == "13"* ]]; then
log "received Player Rotation"
elif [[ $a == "1a"* ]]; then
#cut -c 3-
decode_position $(cut -c 5-20 <<< "$a")
hook_dig
elif [[ $a == "2c"* ]]; then
hook_swing

View File

@ -7,6 +7,8 @@ function chunk_header() {
chunk+="$(int2varint ${#palette[@]})" # palette - entries amount
chunk+="${palette[@]}"
chunk+="8004" # len of next array
}
function chunk_footer() {

View File

@ -1,6 +1,8 @@
#!/usr/bin/env bash
# hooks.sh - dummy hooks functions
spawn_pos=(0 0 0) # default spawn position
# on player dig
function hook_dig() {
log "received Player Dig"
@ -51,10 +53,30 @@ function hook_chunks() {
pkt_chunk 00000001 00000002
}
# after spawning the player
function hook_start() {
:
}
# during login; useful for disabling all multiplayer functionality
function hook_keepalive() {
keep_alive &
# sleep probably only needed for testing
sleep 1 && position_delta &
sleep 1 && handle_broadcast &
pkt_chatmessage "+ $nick" "00000000000000000000000000000000" > $TEMP/players/$nick/broadcast
}
# during server ping; allows you to respond with a custom message.
function hook_ping() {
#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
}
# on defining inventory contents
function hook_inventory() {
items=()
pkt_inventory items
}

View File

@ -1,10 +1,11 @@
#!/usr/bin/env bash
# packet.sh - play state packets
# pkt_pos(x, y, z)
function pkt_pos() {
res="0000001000000000" # X
res+="0000000000000000" # Y
res+="0000000000000000" # Z
res="$(to_ieee754 $1)" # X
res+="$(to_ieee754 $2)" # Y
res+="$(to_ieee754 $3)" # Z
res+="00000000" # yaw
res+="00000000" # pitch
res+="00" # bit field; all absolute
@ -40,7 +41,6 @@ function pkt_chunk() {
else
chunk_header
chunk+="8004" # len of next array
l=$(echo -n "8002" | xxd -p -r | varint2int)
chunk+="$(repeat $((l*16)) "$fill")"
@ -73,9 +73,9 @@ function pkt_effect() {
function pkt_particle() {
res="$(printf '%08x' $4)" # particle id
res+="01" # long distance
res+="0000000000000000" # X
res+="0000000000000000" # Y
res+="0000000000000000" # Z
res+="$(to_ieee754 $1)" # X
res+="$(to_ieee754 $2)" # Y
res+="$(to_ieee754 $3)" # Z
res+="3f800000" # X offset
res+="3f800000" # Y offset
res+="3f800000" # Z offset
@ -84,6 +84,7 @@ function pkt_particle() {
res+="" # data (left blank)
echo -n "$(hexpacket_len "$res")24$res" | xxd -p -r
log $(to_ieee754 $1) $(to_ieee754 $2) $(to_ieee754 $3)
rhexlog "$res"
log "sending particle"
@ -209,3 +210,86 @@ function pkt_title() {
res="$(str_len "$txt")$(echo -n "$txt" | xxd -p)"
echo -n "$(hexpacket_len "$res")5a$res" | xxd -p -r
}
# pkt_disconnect(reason)
function pkt_disconnect() {
txt='{"text":"'"$1"'"}'
res="$(str_len "$txt")$(echo -n "$txt" | xxd -p)"
log "$txt"
echo -n "$(hexpacket_len "$res")1a$res" | xxd -p -r
pkill -P $$
pkt_chatmessage "- $nick" "00000000000000000000000000000000" > $TEMP/players/$nick/broadcast
sleep 0.3
rm -R "$TEMP/players/$nick"
exit
}
# pkt_experience(lvl)
function pkt_experience() {
res="00000000" # experience bar
res+="$(int2varint $1)"
res+="00"
echo -n "$(hexpacket_len "$res")51$res" | xxd -p -r
}
# pkt_inventory(items)
function pkt_inventory() {
local -n _items=$1
res="00" # inventory id
res+="00" # state
res+="$(int2varint ${#_items[@]})" # item count
for i in ${!_items[@]}; do
if [[ $i == 0 ]]; then
res+="00"
else
res+="01 $(int2varint ${_items[$i]}) 01 00"
fi
done
res+="01 00 01 00"
echo -n "$(hexpacket_len "$res")14$res" | xxd -p -r
log "sent inventory"
}
# pkt_digginack(x, y, z, block, status)
function pkt_diggingack() {
res="$(encode_position $1 $2 $3)"
res+="$4"
res+="$5"
res+="01"
echo -n "$(hexpacket_len "$res")08$res" | xxd -p -r
log "sent dig ack"
}
# pkt_blockbreak(x, y, z, stage)
function pkt_blockbreak() {
res="$(int2varint $((0x$eid)))"
res+="$(encode_position $1 $2 $3)"
res+="$4"
echo -n "$(hexpacket_len "$res")09$res" | xxd -p -r
}
# pkt_soundeffect(x, y, z, id)
# TODO: unbreak this
function pkt_soundeffect() {
res="$(int2varint $4)" # sound ID
res+="05" # "block" category
res+="$(printf '%08x' $(($1*8)))" # x
res+="$(printf '%08x' $(($2*8)))" # y
res+="$(printf '%08x' $(($3*8)))" # z
res+="3f800000" # volume
res+="3f800000" # pitch
echo -n "$(hexpacket_len "$res")5d$res" | xxd -p -r
log "sound $(hexpacket_len "$res")5d$res"
}
# pkt_sendblock(x, y, z, id)
function pkt_sendblock() {
res="$(encode_position $1 $2 $3)"
res+="$(int2varint $4)"
echo -n "$(hexpacket_len "$res")0c$res" | xxd -p -r
}