Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

physics, groundwork for proxy and inventory #45

Merged
merged 34 commits into from
Apr 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
806f7a6
single Look that provides both _deg and _rad
Gjum Oct 21, 2022
9466fe0
more physics progress
Gjum Oct 19, 2022
19d63d6
fix bot setting yaw/pitch directly
Gjum Oct 21, 2022
01cb226
read more fields of JoinGame packet
Gjum Oct 21, 2022
7e3ff9c
move min_y and world_height to Dimension
Gjum Oct 21, 2022
f7c1764
create new dimension with min_y and world_height from JoinGame packet
Gjum Oct 21, 2022
5b408e8
handle Respawn packet
Gjum Oct 21, 2022
40dae13
Physics#move accepts nil to stop moving
Gjum Oct 21, 2022
7fc41e5
land on top surface of step block
Gjum Oct 21, 2022
795bb5e
move physics code to /control/ directory
Gjum Oct 22, 2022
891a2fb
fix physics packet using old data from Player
Gjum Oct 22, 2022
c650fd4
move all game asstes to /game_assets/
Gjum Oct 22, 2022
61686c3
load items mcdata
Gjum Oct 22, 2022
e7d41bb
handle HeldItemChange
Gjum Oct 22, 2022
b5cb4a4
add sneaking/crawling player hitbox sizes
Gjum Oct 22, 2022
2efd9e0
bot api
Gjum Oct 22, 2022
e12001b
Slot
Gjum Oct 22, 2022
7823320
packet registry, split connection from client
Gjum Oct 23, 2022
6531a9b
add status packets
Gjum Oct 23, 2022
dca96cb
read+write full JoinGame, ChunkData, PlayerPositionAndLook, Chat
Gjum Oct 23, 2022
dc2a165
read/write raw packets
Gjum Oct 23, 2022
040c53d
player list
Gjum Oct 23, 2022
44bed1a
raw_packet_handlers, read/write raw packets
Gjum Oct 23, 2022
bf604ef
Dimension stores name and nbt; flatten World:: namespace
Gjum Oct 25, 2022
e4197cb
improve Client.connection nilability/closedness situation
Gjum Oct 25, 2022
4e32494
chunk fixes
Gjum Nov 2, 2022
e85ebf1
Merge remote-tracking branch 'greps/main' into main
Gjum Mar 31, 2023
2fa473c
fix style issues and merge oversights
Gjum Mar 31, 2023
532241f
fix grow_palette
Gjum Mar 31, 2023
361ff16
disable lint for some not_nil
Gjum Mar 31, 2023
c316a04
fix lint
Gjum Mar 31, 2023
618fc8b
fix overflow when reading negative byte
Gjum Mar 31, 2023
451d720
fix physics, enforce aabb min/max
Gjum Mar 31, 2023
fa4c454
block place/pick item packets, packet fixes
Gjum Mar 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
File renamed without changes.
7,269 changes: 7,269 additions & 0 deletions game_assets/items.json

Large diffs are not rendered by default.

File renamed without changes.
1 change: 1 addition & 0 deletions shard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ version: 0.1.0

authors:
- grepsedawk <[email protected]>
- Gjum <[email protected]>

crystal: 1.4.1

Expand Down
27 changes: 13 additions & 14 deletions spec/integration/physics_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,26 @@ require "../spec_helper"

Spectator.describe Rosegold::Physics do
it "should fall due to gravity" do
Rosegold::Client.new("localhost", 25565).start do |client|
sleep 2
Rosegold::Client.new("localhost", 25565).join_game do |client|
sleep 2 # load chunks
client.queue_packet Rosegold::Serverbound::Chat.new "/tp 1 -58 1"
sleep 1
sleep 1 # teleport
sleep 1 # fall
expect(client.player.feet).to eq(Rosegold::Vec3d.new(1.5, -60, 1.5))
end
end

it "can move to location successfully" do
Rosegold::Client.new("localhost", 25565).start do |client|
sleep 2
Rosegold::Client.new("localhost", 25565).join_game do |client|
sleep 2 # load chunks
client.queue_packet Rosegold::Serverbound::Chat.new "/tp 1 -60 1"
sleep 1
client.physics.try do |physics|
physics.movement_target = Rosegold::Vec3d.new(5.5, -60, 5.5)
sleep 2
expect(client.player.feet).to eq(Rosegold::Vec3d.new(5.5, -60, 5.5))
physics.movement_target = Rosegold::Vec3d.new(5.5, -60, -5.5)
sleep 3
expect(client.player.feet).to eq(Rosegold::Vec3d.new(5.5, -60, -5.5))
end
sleep 1 # teleport

client.physics.move Rosegold::Vec3d.new(5.5, -60, 5.5)
expect(client.player.feet).to eq(Rosegold::Vec3d.new(5.5, -60, 5.5))

client.physics.move Rosegold::Vec3d.new(5.5, -60, -5.5)
expect(client.player.feet).to eq(Rosegold::Vec3d.new(5.5, -60, -5.5))
end
end
end
68 changes: 58 additions & 10 deletions src/minecraft/io.cr
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
require "io/hexdump"
require "socket"
require "uuid"
require "../rosegold/world/slot"

module Minecraft::IO
def write(value : Bool)
write_byte value ? 1_u8 : 0_u8
end

def write(value : String)
write value.bytesize.to_u32
print value
def write(str : String)
write str.bytesize.to_u32
print str
end

def write(value : Float32 | Float64 | UInt8)
def write_opt_string(str : String?)
write !str.nil?
write str unless str.nil?
end

def write(value : Float32 | Float64 | UInt8 | Int8)
write_bytes value, ::IO::ByteFormat::BigEndian
end

Expand All @@ -21,6 +27,10 @@ module Minecraft::IO
write_bytes value, ::IO::ByteFormat::BigEndian
end

def write(uuid : UUID)
write uuid.bytes.to_slice
end

# writes var int
def write(value : UInt16 | Int16 | UInt32 | Int32 | UInt64 | Int64)
a = Array(UInt8).new
Expand All @@ -39,6 +49,18 @@ module Minecraft::IO
write a.to_unsafe.to_slice a.size
end

def write(nbt : NBT::Tag)
raise "Not implemented" # TODO
end

def write(slot : Rosegold::Slot)
write slot.empty?
return if slot.empty?
write slot.item_id
write slot.count
write slot.nbt || 0_u8
end

def write_position(x : Int32, y : Int32, z : Int32)
x, y, z = x.to_i64, y.to_i64, z.to_i64
write_full ((x & 0x3FFFFFF) << 38) | ((z & 0x3FFFFFF) << 12) | (y & 0xFFF)
Expand All @@ -58,6 +80,12 @@ module Minecraft::IO
buf[0]
end

def read_signed_byte
buf = Bytes.new 1
read_fully(buf)
buf[0].to_i8!
end

def read_bool
read_byte != 0
end
Expand Down Expand Up @@ -110,6 +138,11 @@ module Minecraft::IO
end
end

def read_opt_string : String?
return nil unless read_bool
read_var_string
end

def read_var_string : String
read_var_string(read_var_int)
end
Expand Down Expand Up @@ -137,6 +170,11 @@ module Minecraft::IO
NBT::Tag.read_named(self)[1]
end

def read_slot : Rosegold::Slot
return Rosegold::Slot.new unless read_bool
Rosegold::Slot.new(read_var_int, read_byte, read_nbt)
end

def read_position : Tuple(Int32, Int32, Int32)
value = read_long
# here ordered LSB to MSB; use arithmetic shift to preserve sign
Expand All @@ -147,6 +185,20 @@ module Minecraft::IO
end
end

class Minecraft::IO::Wrap < IO
include Minecraft::IO

def initialize(@io : ::IO); end

def read(slice : Bytes)
@io.read slice
end

def write(slice : Bytes) : Nil
@io.write slice
end
end

class Minecraft::IO::Memory < IO::Memory
include Minecraft::IO
end
Expand All @@ -159,7 +211,7 @@ class Minecraft::TCPSocket < TCPSocket
include Minecraft::IO
end

class Minecraft::EncryptedTCPSocket
class Minecraft::EncryptedTCPSocket < IO
include Minecraft::IO

getter read_cipher : OpenSSL::Cipher
Expand All @@ -176,7 +228,7 @@ class Minecraft::EncryptedTCPSocket
@write_cipher.iv = iv
end

def read_fully(slice : Bytes)
def read(slice : Bytes)
upstream_size = @io.read_fully slice
upstream = slice[0, upstream_size]
o = @read_cipher.update upstream
Expand All @@ -187,8 +239,4 @@ class Minecraft::EncryptedTCPSocket
def write(slice : Bytes) : Nil
@io.write @write_cipher.update(slice)
end

def flush
@io.flush
end
end
60 changes: 60 additions & 0 deletions src/minecraft/nbt.cr
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,66 @@ module Minecraft::NBT
end
end

def as_i8 : Int8
raise "Wrong type #{self}" unless self.is_a? ByteTag
self.value
end

def as_i16 : Int16
raise "Wrong type #{self}" unless self.is_a? ShortTag
self.value
end

def as_i32 : Int32
raise "Wrong type #{self}" unless self.is_a? IntTag
self.value
end

def as_i64 : Int64
raise "Wrong type #{self}" unless self.is_a? LongTag
self.value
end

def as_f32 : Float32
raise "Wrong type #{self}" unless self.is_a? FloatTag
self.value
end

def as_f64 : Float64
raise "Wrong type #{self}" unless self.is_a? DoubleTag
self.value
end

def as_byte_array : Array(Int8)
raise "Wrong type #{self}" unless self.is_a? ByteArrayTag
self.value
end

def as_str : String
raise "Wrong type #{self}" unless self.is_a? StringTag
self.value
end

def as_list : Array(Tag)
raise "Wrong type #{self}" unless self.is_a? ListTag
self.value
end

def as_compound : Hash(String, Tag)
raise "Wrong type #{self}" unless self.is_a? CompoundTag
self.value
end

def as_i32_array : Array(Int32)
raise "Wrong type #{self}" unless self.is_a? IntArrayTag
self.value
end

def as_i64_array : Array(Int64)
raise "Wrong type #{self}" unless self.is_a? LongArrayTag
self.value
end

def self.read(io : IO, tag_type = io.read_byte) : Tag
read(io, tag_type) { }
end
Expand Down
82 changes: 45 additions & 37 deletions src/play.cr
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
require "./rosegold"
require "./rosegold/bot"

include Rosegold

def show_help
puts "Rosegold v#{Rosegold::VERSION}"
Expand All @@ -7,53 +10,58 @@ def show_help
puts "\\position - Displays the current coordinates of the player"
end

Rosegold::Client.new("localhost", 25565).start do |bot|
Client.new("localhost").join_game do |client|
bot = Rosegold::Bot.new client

show_help

spawn do
loop do
bot.move_to rand(-10..10), -60, rand(-10..10)
bot.walk_to rand(-10..10), rand(-10..10)
sleep 3
end
end

loop do
gets.try do |input|
next if input.empty?

if input.starts_with? "\\"
command = input.split(" ")
case command.first
when "\\help"
show_help
when "\\position"
puts bot.player.feet
when "\\pitch"
if command.size > 1
bot.pitch = command[1].to_f
else
puts bot.pitch
end
when "\\yaw"
if command.size > 1
bot.yaw = command[1].to_f
else
puts bot.yaw
end
when "\\move"
bot.move_to command[1].to_f, command[2].to_f, command[3].to_f
when "\\jump"
bot.jump
when "\\debug"
Log.setup :debug
when "\\trace"
Log.setup :trace
end
while input = gets
next if input.empty?

next
end
bot.chat input unless input.starts_with? "\\"

bot.chat input
command = input.split(" ")
case command.first
when "\\help"
show_help
when "\\position"
puts bot.feet
when "\\pitch"
if command.size > 1
bot.look &.with_pitch_deg command[1].to_f.to_f32
else
puts bot.look.pitch_deg
end
when "\\yaw"
if command.size > 1
bot.look &.with_yaw_deg command[1].to_f.to_f32
else
puts bot.look.yaw_deg
end
when "\\move"
spawn do
location = Vec3d.new command[1].to_f, bot.feet.y, command[3].to_f
begin
bot.walk_to location
puts "Arrived at #{bot.feet}"
rescue ex
puts "Movement to #{location} failed:"
puts ex
end
end
when "\\jump"
bot.start_jump
when "\\debug"
Log.setup :debug
when "\\trace"
Log.setup :trace
end
end
end
Loading