Reformat all source with cargo fmt (#335)

This commit is contained in:
iceiix 2020-06-21 12:17:24 -07:00 committed by GitHub
parent 7279f4177e
commit 518b6a07f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
80 changed files with 5282 additions and 2858 deletions

View File

@ -97,7 +97,7 @@ There are a few basic ground-rules for contributors:
1. **Non-master branches** ought to be used for ongoing work. 1. **Non-master branches** ought to be used for ongoing work.
1. **External API changes and significant modifications** ought to be subject to an **internal pull-request** to solicit feedback from other contributors. 1. **External API changes and significant modifications** ought to be subject to an **internal pull-request** to solicit feedback from other contributors.
1. Internal pull-requests to solicit feedback are *encouraged* for any other non-trivial contribution but left to the discretion of the contributor. 1. Internal pull-requests to solicit feedback are *encouraged* for any other non-trivial contribution but left to the discretion of the contributor.
1. Contributors should attempt to adhere to the prevailing code-style. 1. Contributors should attempt to adhere to the prevailing code-style. Please install and run [cargo fmt](https://github.com/rust-lang/rustfmt) before merging any changes.
### Changes to this arrangement ### Changes to this arrangement

View File

@ -1,11 +1,10 @@
#![recursion_limit = "600"]
#![recursion_limit="600"]
extern crate steven_shared as shared; extern crate steven_shared as shared;
use crate::shared::{Axis, Direction, Position}; use crate::shared::{Axis, Direction, Position};
use collision::Aabb3;
use cgmath::Point3; use cgmath::Point3;
use collision::Aabb3;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use std::collections::HashMap; use std::collections::HashMap;
@ -500,7 +499,7 @@ macro_rules! define_blocks {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum TintType { pub enum TintType {
Default, Default,
Color{r: u8, g: u8, b: u8}, Color { r: u8, g: u8, b: u8 },
Grass, Grass,
Foliage, Foliage,
} }
@ -5625,59 +5624,65 @@ define_blocks! {
fn can_burn<W: WorldAccess>(world: &W, pos: Position) -> bool { fn can_burn<W: WorldAccess>(world: &W, pos: Position) -> bool {
match world.get_block(pos) { match world.get_block(pos) {
Block::Planks{..} | Block::Planks { .. }
Block::DoubleWoodenSlab{..} | | Block::DoubleWoodenSlab { .. }
Block::WoodenSlab{..} | | Block::WoodenSlab { .. }
Block::FenceGate{..} | | Block::FenceGate { .. }
Block::SpruceFenceGate{..} | | Block::SpruceFenceGate { .. }
Block::BirchFenceGate{..} | | Block::BirchFenceGate { .. }
Block::JungleFenceGate{..} | | Block::JungleFenceGate { .. }
Block::DarkOakFenceGate{..} | | Block::DarkOakFenceGate { .. }
Block::AcaciaFenceGate{..} | | Block::AcaciaFenceGate { .. }
Block::Fence{..} | | Block::Fence { .. }
Block::SpruceFence{..} | | Block::SpruceFence { .. }
Block::BirchFence{..} | | Block::BirchFence { .. }
Block::JungleFence{..} | | Block::JungleFence { .. }
Block::DarkOakFence{..} | | Block::DarkOakFence { .. }
Block::AcaciaFence{..} | | Block::AcaciaFence { .. }
Block::OakStairs{..} | | Block::OakStairs { .. }
Block::BirchStairs{..} | | Block::BirchStairs { .. }
Block::SpruceStairs{..} | | Block::SpruceStairs { .. }
Block::JungleStairs{..} | | Block::JungleStairs { .. }
Block::AcaciaStairs{..} | | Block::AcaciaStairs { .. }
Block::DarkOakStairs{..} | | Block::DarkOakStairs { .. }
Block::Log{..} | | Block::Log { .. }
Block::Log2{..} | | Block::Log2 { .. }
Block::Leaves{..} | | Block::Leaves { .. }
Block::Leaves2{..} | | Block::Leaves2 { .. }
Block::BookShelf{..} | | Block::BookShelf { .. }
Block::TNT{..} | | Block::TNT { .. }
Block::TallGrass{..} | | Block::TallGrass { .. }
Block::DoublePlant{..} | | Block::DoublePlant { .. }
Block::YellowFlower{..} | | Block::YellowFlower { .. }
Block::RedFlower{..} | | Block::RedFlower { .. }
Block::DeadBush{..} | | Block::DeadBush { .. }
Block::Wool{..} | | Block::Wool { .. }
Block::Vine{..} | | Block::Vine { .. }
Block::CoalBlock{..} | | Block::CoalBlock { .. }
Block::HayBlock{..} | | Block::HayBlock { .. }
Block::Carpet{..} => true, | Block::Carpet { .. } => true,
_ => false, _ => false,
} }
} }
fn is_snowy<W: WorldAccess>(world: &W, pos: Position) -> bool { fn is_snowy<W: WorldAccess>(world: &W, pos: Position) -> bool {
match world.get_block(pos.shift(Direction::Up)) { match world.get_block(pos.shift(Direction::Up)) {
Block::Snow{..} | Block::SnowLayer{..} => true, Block::Snow { .. } | Block::SnowLayer { .. } => true,
_ => false, _ => false,
} }
} }
fn can_connect_sides<F: Fn(Block) -> bool, W: WorldAccess>(world: &W, pos: Position, f: &F) -> (bool, bool, bool, bool) { fn can_connect_sides<F: Fn(Block) -> bool, W: WorldAccess>(
(can_connect(world, pos.shift(Direction::North), f), world: &W,
can_connect(world, pos.shift(Direction::South), f), pos: Position,
can_connect(world, pos.shift(Direction::West), f), f: &F,
can_connect(world, pos.shift(Direction::East), f)) ) -> (bool, bool, bool, bool) {
(
can_connect(world, pos.shift(Direction::North), f),
can_connect(world, pos.shift(Direction::South), f),
can_connect(world, pos.shift(Direction::West), f),
can_connect(world, pos.shift(Direction::East), f),
)
} }
fn can_connect<F: Fn(Block) -> bool, W: WorldAccess>(world: &W, pos: Position, f: &F) -> bool { fn can_connect<F: Fn(Block) -> bool, W: WorldAccess>(world: &W, pos: Position, f: &F) -> bool {
@ -5687,28 +5692,28 @@ fn can_connect<F: Fn(Block) -> bool, W: WorldAccess>(world: &W, pos: Position, f
fn can_connect_fence(block: Block) -> bool { fn can_connect_fence(block: Block) -> bool {
match block { match block {
Block::Fence{..} | Block::Fence { .. }
Block::SpruceFence{..} | | Block::SpruceFence { .. }
Block::BirchFence{..} | | Block::BirchFence { .. }
Block::JungleFence{..} | | Block::JungleFence { .. }
Block::DarkOakFence{..} | | Block::DarkOakFence { .. }
Block::AcaciaFence{..} | | Block::AcaciaFence { .. }
Block::FenceGate{..} | | Block::FenceGate { .. }
Block::SpruceFenceGate{..} | | Block::SpruceFenceGate { .. }
Block::BirchFenceGate{..} | | Block::BirchFenceGate { .. }
Block::JungleFenceGate{..} | | Block::JungleFenceGate { .. }
Block::DarkOakFenceGate{..} | | Block::DarkOakFenceGate { .. }
Block::AcaciaFenceGate{..} => true, | Block::AcaciaFenceGate { .. } => true,
_ => false, _ => false,
} }
} }
fn can_connect_glasspane(block: Block) -> bool { fn can_connect_glasspane(block: Block) -> bool {
match block { match block {
Block::Glass{..} | Block::Glass { .. }
Block::StainedGlass{..} | | Block::StainedGlass { .. }
Block::GlassPane{..} | | Block::GlassPane { .. }
Block::StainedGlassPane{..} => true, | Block::StainedGlassPane { .. } => true,
_ => false, _ => false,
} }
} }
@ -5721,7 +5726,11 @@ fn can_connect_redstone<W: WorldAccess>(world: &W, pos: Position, dir: Direction
let side_up = world.get_block(shift_pos.shift(Direction::Up)); let side_up = world.get_block(shift_pos.shift(Direction::Up));
let up = world.get_block(pos.shift(Direction::Up)); let up = world.get_block(pos.shift(Direction::Up));
if match side_up { Block::RedstoneWire{..} => true, _ => false,} && !up.get_material().should_cull_against { if match side_up {
Block::RedstoneWire { .. } => true,
_ => false,
} && !up.get_material().should_cull_against
{
return RedstoneSide::Up; return RedstoneSide::Up;
} }
@ -5729,71 +5738,90 @@ fn can_connect_redstone<W: WorldAccess>(world: &W, pos: Position, dir: Direction
} }
let side_down = world.get_block(shift_pos.shift(Direction::Down)); let side_down = world.get_block(shift_pos.shift(Direction::Down));
if match block { Block::RedstoneWire{..} => true, _ => false,} || match side_down { Block::RedstoneWire{..} => true, _ => false,} { if match block {
Block::RedstoneWire { .. } => true,
_ => false,
} || match side_down {
Block::RedstoneWire { .. } => true,
_ => false,
} {
return RedstoneSide::Side; return RedstoneSide::Side;
} }
RedstoneSide::None RedstoneSide::None
} }
fn fence_gate_data(facing: Direction, in_wall: bool, open: bool, powered: bool) -> Option<usize> { fn fence_gate_data(facing: Direction, in_wall: bool, open: bool, powered: bool) -> Option<usize> {
if in_wall || powered { return None; } if in_wall || powered {
return None;
}
Some(facing.horizontal_index() | (if open { 0x4 } else { 0x0 })) Some(facing.horizontal_index() | (if open { 0x4 } else { 0x0 }))
} }
fn fence_gate_offset(facing: Direction, in_wall: bool, open: bool, powered: bool) -> Option<usize> { fn fence_gate_offset(facing: Direction, in_wall: bool, open: bool, powered: bool) -> Option<usize> {
Some(if powered { 0 } else { 1<<0 } + Some(
if open { 0 } else { 1<<1 } + if powered { 0 } else { 1 << 0 }
if in_wall { 0 } else { 1<<2 } + + if open { 0 } else { 1 << 1 }
facing.horizontal_offset() * (1<<3)) + if in_wall { 0 } else { 1 << 2 }
+ facing.horizontal_offset() * (1 << 3),
)
} }
fn fence_gate_collision(facing: Direction, in_wall: bool, open: bool) -> Vec<Aabb3<f64>> { fn fence_gate_collision(facing: Direction, in_wall: bool, open: bool) -> Vec<Aabb3<f64>> {
if open { return vec![]; } if open {
return vec![];
}
let (min_x, min_y, min_z, max_x, max_y, max_z) = if in_wall { let (min_x, min_y, min_z, max_x, max_y, max_z) = if in_wall {
match facing.axis() { match facing.axis() {
Axis::Z => (0.0, 0.0, 3.0/8.0, 1.0, 13.0/16.0, 5.0/8.0), Axis::Z => (0.0, 0.0, 3.0 / 8.0, 1.0, 13.0 / 16.0, 5.0 / 8.0),
Axis::X => (3.0/8.0, 0.0, 0.0, 5.0/8.0, 13.0/16.0, 1.0), Axis::X => (3.0 / 8.0, 0.0, 0.0, 5.0 / 8.0, 13.0 / 16.0, 1.0),
_ => unreachable!(), _ => unreachable!(),
} }
} else { } else {
match facing.axis() { match facing.axis() {
Axis::Z => (0.0, 0.0, 3.0/8.0, 1.0, 1.0, 5.0/8.0), Axis::Z => (0.0, 0.0, 3.0 / 8.0, 1.0, 1.0, 5.0 / 8.0),
Axis::X => (3.0/8.0, 0.0, 0.0, 5.0/8.0, 1.0, 1.0), Axis::X => (3.0 / 8.0, 0.0, 0.0, 5.0 / 8.0, 1.0, 1.0),
_ => unreachable!(), _ => unreachable!(),
} }
}; };
vec![Aabb3::new( vec![Aabb3::new(
Point3::new(min_x, min_y, min_z), Point3::new(min_x, min_y, min_z),
Point3::new(max_x, max_y, max_z) Point3::new(max_x, max_y, max_z),
)] )]
} }
fn fence_gate_update_state<W: WorldAccess>(world: &W, pos: Position, facing: Direction) -> bool { fn fence_gate_update_state<W: WorldAccess>(world: &W, pos: Position, facing: Direction) -> bool {
if let Block::CobblestoneWall{..} = world.get_block(pos.shift(facing.clockwise())) { if let Block::CobblestoneWall { .. } = world.get_block(pos.shift(facing.clockwise())) {
return true; return true;
} }
if let Block::CobblestoneWall{..} = world.get_block(pos.shift(facing.counter_clockwise())) { if let Block::CobblestoneWall { .. } = world.get_block(pos.shift(facing.counter_clockwise())) {
return true; return true;
} }
false false
} }
fn door_data(facing: Direction, half: DoorHalf, hinge: Side, open: bool, powered: bool) -> Option<usize> { fn door_data(
facing: Direction,
half: DoorHalf,
hinge: Side,
open: bool,
powered: bool,
) -> Option<usize> {
match half { match half {
DoorHalf::Upper => { DoorHalf::Upper => {
if facing == Direction::North && open { if facing == Direction::North && open {
Some(0x8 Some(
| (if hinge == Side::Right { 0x1 } else { 0x0 }) 0x8 | (if hinge == Side::Right { 0x1 } else { 0x0 })
| (if powered { 0x2 } else { 0x0 })) | (if powered { 0x2 } else { 0x0 }),
)
} else { } else {
None None
} }
}, }
DoorHalf::Lower => { DoorHalf::Lower => {
if hinge == Side::Left && !powered { if hinge == Side::Left && !powered {
Some(facing.clockwise().horizontal_index() | (if open { 0x4 } else { 0x0 })) Some(facing.clockwise().horizontal_index() | (if open { 0x4 } else { 0x0 }))
@ -5804,26 +5832,83 @@ fn door_data(facing: Direction, half: DoorHalf, hinge: Side, open: bool, powered
} }
} }
fn door_offset(facing: Direction, half: DoorHalf, hinge: Side, open: bool, powered: bool) -> Option<usize> { fn door_offset(
Some(if powered { 0 } else { 1<<0 } + facing: Direction,
if open { 0 } else { 1<<1 } + half: DoorHalf,
if hinge == Side::Left { 0 } else { 1<<2 } + hinge: Side,
if half == DoorHalf::Upper { 0 } else { 1<<3 } + open: bool,
facing.horizontal_offset() * (1<<4)) powered: bool,
) -> Option<usize> {
Some(
if powered { 0 } else { 1 << 0 }
+ if open { 0 } else { 1 << 1 }
+ if hinge == Side::Left { 0 } else { 1 << 2 }
+ if half == DoorHalf::Upper { 0 } else { 1 << 3 }
+ facing.horizontal_offset() * (1 << 4),
)
} }
fn update_door_state<W: WorldAccess>(
fn update_door_state<W: WorldAccess>(world: &W, pos: Position, ohalf: DoorHalf, ofacing: Direction, ohinge: Side, oopen: bool, opowered: bool) -> (Direction, Side, bool, bool) { world: &W,
pos: Position,
ohalf: DoorHalf,
ofacing: Direction,
ohinge: Side,
oopen: bool,
opowered: bool,
) -> (Direction, Side, bool, bool) {
let oy = if ohalf == DoorHalf::Upper { -1 } else { 1 }; let oy = if ohalf == DoorHalf::Upper { -1 } else { 1 };
match world.get_block(pos + (0, oy, 0)) { match world.get_block(pos + (0, oy, 0)) {
Block::WoodenDoor{half, facing, hinge, open, powered} | Block::WoodenDoor {
Block::SpruceDoor{half, facing, hinge, open, powered} | half,
Block::BirchDoor{half, facing, hinge, open, powered} | facing,
Block::JungleDoor{half, facing, hinge, open, powered} | hinge,
Block::AcaciaDoor{half, facing, hinge, open, powered} | open,
Block::DarkOakDoor{half, facing, hinge, open, powered} | powered,
Block::IronDoor{half, facing, hinge, open, powered} => { }
| Block::SpruceDoor {
half,
facing,
hinge,
open,
powered,
}
| Block::BirchDoor {
half,
facing,
hinge,
open,
powered,
}
| Block::JungleDoor {
half,
facing,
hinge,
open,
powered,
}
| Block::AcaciaDoor {
half,
facing,
hinge,
open,
powered,
}
| Block::DarkOakDoor {
half,
facing,
hinge,
open,
powered,
}
| Block::IronDoor {
half,
facing,
hinge,
open,
powered,
} => {
if half != ohalf { if half != ohalf {
if ohalf == DoorHalf::Upper { if ohalf == DoorHalf::Upper {
return (facing, ohinge, open, opowered); return (facing, ohinge, open, opowered);
@ -5831,8 +5916,8 @@ fn update_door_state<W: WorldAccess>(world: &W, pos: Position, ohalf: DoorHalf,
return (ofacing, hinge, oopen, powered); return (ofacing, hinge, oopen, powered);
} }
} }
}, }
_ => {}, _ => {}
} }
(ofacing, ohinge, oopen, opowered) (ofacing, ohinge, oopen, opowered)
@ -5842,7 +5927,7 @@ fn door_collision(facing: Direction, hinge: Side, open: bool) -> Vec<Aabb3<f64>>
use std::f64::consts::PI; use std::f64::consts::PI;
let mut bounds = Aabb3::new( let mut bounds = Aabb3::new(
Point3::new(0.0, 0.0, 0.0), Point3::new(0.0, 0.0, 0.0),
Point3::new(1.0, 1.0, 3.0 / 16.0) Point3::new(1.0, 1.0, 3.0 / 16.0),
); );
let mut angle = match facing { let mut angle = match facing {
Direction::South => 0.0, Direction::South => 0.0,
@ -5851,43 +5936,48 @@ fn door_collision(facing: Direction, hinge: Side, open: bool) -> Vec<Aabb3<f64>>
Direction::East => PI * 1.5, Direction::East => PI * 1.5,
_ => 0.0, _ => 0.0,
}; };
angle += if open { angle += if open { PI * 0.5 } else { 0.0 }
PI * 0.5 * match hinge {
} else { Side::Left => 1.0,
0.0 Side::Right => -1.0,
} * match hinge { Side::Left => 1.0, Side::Right => -1.0 }; };
let c = angle.cos(); let c = angle.cos();
let s = angle.sin(); let s = angle.sin();
let x = bounds.min.x - 0.5; let x = bounds.min.x - 0.5;
let z = bounds.min.z - 0.5; let z = bounds.min.z - 0.5;
bounds.min.x = 0.5 + (x*c - z*s); bounds.min.x = 0.5 + (x * c - z * s);
bounds.min.z = 0.5 + (z*c + x*s); bounds.min.z = 0.5 + (z * c + x * s);
let x = bounds.max.x - 0.5; let x = bounds.max.x - 0.5;
let z = bounds.max.z - 0.5; let z = bounds.max.z - 0.5;
bounds.max.x = 0.5 + (x*c - z*s); bounds.max.x = 0.5 + (x * c - z * s);
bounds.max.z = 0.5 + (z*c + x*s); bounds.max.z = 0.5 + (z * c + x * s);
vec![bounds] vec![bounds]
} }
fn update_repeater_state<W: WorldAccess>(world: &W, pos: Position, facing: Direction) -> bool { fn update_repeater_state<W: WorldAccess>(world: &W, pos: Position, facing: Direction) -> bool {
let f = |dir| { let f = |dir| match world.get_block(pos.shift(dir)) {
match world.get_block(pos.shift(dir)) { Block::RepeaterPowered { .. } => true,
Block::RepeaterPowered{..} => true, _ => false,
_ => false,
}
}; };
f(facing.clockwise()) || f(facing.counter_clockwise()) f(facing.clockwise()) || f(facing.counter_clockwise())
} }
fn update_double_plant_state<W: WorldAccess>(world: &W, pos: Position, ohalf: BlockHalf, ovariant: DoublePlantVariant) -> (BlockHalf, DoublePlantVariant) { fn update_double_plant_state<W: WorldAccess>(
if ohalf != BlockHalf::Upper { return (ohalf, ovariant); } world: &W,
pos: Position,
ohalf: BlockHalf,
ovariant: DoublePlantVariant,
) -> (BlockHalf, DoublePlantVariant) {
if ohalf != BlockHalf::Upper {
return (ohalf, ovariant);
}
match world.get_block(pos.shift(Direction::Down)) { match world.get_block(pos.shift(Direction::Down)) {
Block::DoublePlant{variant, ..} => (ohalf, variant), Block::DoublePlant { variant, .. } => (ohalf, variant),
_ => (ohalf, ovariant), _ => (ohalf, ovariant),
} }
} }
@ -5909,65 +5999,65 @@ fn piston_collision(extended: bool, facing: Direction) -> Vec<Aabb3<f64>> {
vec![Aabb3::new( vec![Aabb3::new(
Point3::new(min_x, min_y, min_z), Point3::new(min_x, min_y, min_z),
Point3::new(max_x, max_y, max_z) Point3::new(max_x, max_y, max_z),
)] )]
} }
fn trapdoor_collision(facing: Direction, half: BlockHalf, open: bool) -> Vec<Aabb3<f64>> { fn trapdoor_collision(facing: Direction, half: BlockHalf, open: bool) -> Vec<Aabb3<f64>> {
let (min_x, min_y, min_z, max_x, max_y, max_z) = if open { let (min_x, min_y, min_z, max_x, max_y, max_z) = if open {
match facing { match facing {
Direction::North => (0.0, 0.0, 3.0/16.0, 1.0, 1.0, 1.0), Direction::North => (0.0, 0.0, 3.0 / 16.0, 1.0, 1.0, 1.0),
Direction::South => (0.0, 0.0, 0.0, 1.0, 1.0, 3.0/16.0), Direction::South => (0.0, 0.0, 0.0, 1.0, 1.0, 3.0 / 16.0),
Direction::West => (3.0/16.0, 0.0, 0.0, 1.0, 1.0, 1.0), Direction::West => (3.0 / 16.0, 0.0, 0.0, 1.0, 1.0, 1.0),
Direction::East => (0.0, 0.0, 0.0, 3.0/16.0, 1.0, 1.0), Direction::East => (0.0, 0.0, 0.0, 3.0 / 16.0, 1.0, 1.0),
_ => unreachable!(), _ => unreachable!(),
} }
} else { } else {
match half { match half {
BlockHalf::Bottom => (0.0, 0.0, 0.0, 1.0, 3.0/16.0, 1.0), BlockHalf::Bottom => (0.0, 0.0, 0.0, 1.0, 3.0 / 16.0, 1.0),
BlockHalf::Top => (0.0, 3.0/16.0, 0.0, 1.0, 1.0, 1.0), BlockHalf::Top => (0.0, 3.0 / 16.0, 0.0, 1.0, 1.0, 1.0),
_ => unreachable!(), _ => unreachable!(),
} }
}; };
vec![Aabb3::new( vec![Aabb3::new(
Point3::new(min_x, min_y, min_z), Point3::new(min_x, min_y, min_z),
Point3::new(max_x, max_y, max_z)) Point3::new(max_x, max_y, max_z),
] )]
} }
fn fence_collision(north: bool, south: bool, west: bool, east: bool) -> Vec<Aabb3<f64>> { fn fence_collision(north: bool, south: bool, west: bool, east: bool) -> Vec<Aabb3<f64>> {
let mut collision = vec![Aabb3::new( let mut collision = vec![Aabb3::new(
Point3::new(3.0/8.0, 0.0, 3.0/8.0), Point3::new(3.0 / 8.0, 0.0, 3.0 / 8.0),
Point3::new(5.0/8.0, 1.5, 5.0/8.0)) Point3::new(5.0 / 8.0, 1.5, 5.0 / 8.0),
]; )];
if north { if north {
collision.push(Aabb3::new( collision.push(Aabb3::new(
Point3::new(3.0/8.0, 0.0, 0.0), Point3::new(3.0 / 8.0, 0.0, 0.0),
Point3::new(5.0/8.0, 1.5, 3.0/8.0)) Point3::new(5.0 / 8.0, 1.5, 3.0 / 8.0),
); ));
} }
if south { if south {
collision.push(Aabb3::new( collision.push(Aabb3::new(
Point3::new(3.0/8.0, 0.0, 5.0/8.0), Point3::new(3.0 / 8.0, 0.0, 5.0 / 8.0),
Point3::new(5.0/8.0, 1.5, 1.0)) Point3::new(5.0 / 8.0, 1.5, 1.0),
); ));
} }
if west { if west {
collision.push(Aabb3::new( collision.push(Aabb3::new(
Point3::new(0.0, 0.0, 3.0/8.0), Point3::new(0.0, 0.0, 3.0 / 8.0),
Point3::new(3.0/8.0, 1.5, 5.0/8.0)) Point3::new(3.0 / 8.0, 1.5, 5.0 / 8.0),
); ));
} }
if east { if east {
collision.push(Aabb3::new( collision.push(Aabb3::new(
Point3::new(5.0/8.0, 0.0, 3.0/8.0), Point3::new(5.0 / 8.0, 0.0, 3.0 / 8.0),
Point3::new(1.0, 1.5, 5.0/8.0)) Point3::new(1.0, 1.5, 5.0 / 8.0),
); ));
} }
collision collision
@ -5975,36 +6065,36 @@ fn fence_collision(north: bool, south: bool, west: bool, east: bool) -> Vec<Aabb
fn pane_collision(north: bool, south: bool, east: bool, west: bool) -> Vec<Aabb3<f64>> { fn pane_collision(north: bool, south: bool, east: bool, west: bool) -> Vec<Aabb3<f64>> {
let mut collision = vec![Aabb3::new( let mut collision = vec![Aabb3::new(
Point3::new(7.0/16.0, 0.0, 7.0/16.0), Point3::new(7.0 / 16.0, 0.0, 7.0 / 16.0),
Point3::new(9.0/16.0, 1.0, 9.0/16.0)) Point3::new(9.0 / 16.0, 1.0, 9.0 / 16.0),
]; )];
if north { if north {
collision.push(Aabb3::new( collision.push(Aabb3::new(
Point3::new(7.0/16.0, 0.0, 0.0), Point3::new(7.0 / 16.0, 0.0, 0.0),
Point3::new(9.0/16.0, 1.0, 9.0/16.0)) Point3::new(9.0 / 16.0, 1.0, 9.0 / 16.0),
); ));
} }
if south { if south {
collision.push(Aabb3::new( collision.push(Aabb3::new(
Point3::new(7.0/16.0, 0.0, 7.0/16.0), Point3::new(7.0 / 16.0, 0.0, 7.0 / 16.0),
Point3::new(9.0/16.0, 1.0, 1.0)) Point3::new(9.0 / 16.0, 1.0, 1.0),
); ));
} }
if west { if west {
collision.push(Aabb3::new( collision.push(Aabb3::new(
Point3::new(0.0, 0.0, 7.0/16.0), Point3::new(0.0, 0.0, 7.0 / 16.0),
Point3::new(9.0/16.0, 1.0, 9.0/16.0)) Point3::new(9.0 / 16.0, 1.0, 9.0 / 16.0),
); ));
} }
if east { if east {
collision.push(Aabb3::new( collision.push(Aabb3::new(
Point3::new(7.0/16.0, 0.0, 7.0/16.0), Point3::new(7.0 / 16.0, 0.0, 7.0 / 16.0),
Point3::new(1.0, 1.0, 9.0/16.0)) Point3::new(1.0, 1.0, 9.0 / 16.0),
); ));
} }
collision collision
@ -6012,20 +6102,20 @@ fn pane_collision(north: bool, south: bool, east: bool, west: bool) -> Vec<Aabb3
fn get_stair_info<W: WorldAccess>(world: &W, pos: Position) -> Option<(Direction, BlockHalf)> { fn get_stair_info<W: WorldAccess>(world: &W, pos: Position) -> Option<(Direction, BlockHalf)> {
match world.get_block(pos) { match world.get_block(pos) {
Block::OakStairs{facing, half, ..} | Block::OakStairs { facing, half, .. }
Block::StoneStairs{facing, half, ..} | | Block::StoneStairs { facing, half, .. }
Block::BrickStairs{facing, half, ..} | | Block::BrickStairs { facing, half, .. }
Block::StoneBrickStairs{facing, half, ..} | | Block::StoneBrickStairs { facing, half, .. }
Block::NetherBrickStairs{facing, half, ..} | | Block::NetherBrickStairs { facing, half, .. }
Block::SandstoneStairs{facing, half, ..} | | Block::SandstoneStairs { facing, half, .. }
Block::SpruceStairs{facing, half, ..} | | Block::SpruceStairs { facing, half, .. }
Block::BirchStairs{facing, half, ..} | | Block::BirchStairs { facing, half, .. }
Block::JungleStairs{facing, half, ..} | | Block::JungleStairs { facing, half, .. }
Block::QuartzStairs{facing, half, ..} | | Block::QuartzStairs { facing, half, .. }
Block::AcaciaStairs{facing, half, ..} | | Block::AcaciaStairs { facing, half, .. }
Block::DarkOakStairs{facing, half, ..} | | Block::DarkOakStairs { facing, half, .. }
Block::RedSandstoneStairs{facing, half, ..} | | Block::RedSandstoneStairs { facing, half, .. }
Block::PurpurStairs{facing, half, ..} => Some((facing, half)), | Block::PurpurStairs { facing, half, .. } => Some((facing, half)),
_ => None, _ => None,
} }
} }
@ -6054,18 +6144,34 @@ fn update_stair_shape<W: WorldAccess>(world: &W, pos: Position, facing: Directio
StairShape::Straight StairShape::Straight
} }
fn stair_data(facing: Direction, half: BlockHalf, shape: StairShape, waterlogged: bool) -> Option<usize> { fn stair_data(
if shape != StairShape::Straight { return None; } facing: Direction,
if waterlogged { return None; } half: BlockHalf,
shape: StairShape,
waterlogged: bool,
) -> Option<usize> {
if shape != StairShape::Straight {
return None;
}
if waterlogged {
return None;
}
Some((5 - facing.index()) | (if half == BlockHalf::Top { 0x4 } else { 0x0 })) Some((5 - facing.index()) | (if half == BlockHalf::Top { 0x4 } else { 0x0 }))
} }
fn stair_offset(facing: Direction, half: BlockHalf, shape: StairShape, waterlogged: bool) -> Option<usize> { fn stair_offset(
Some(if waterlogged { 0 } else { 1 } + facing: Direction,
shape.offset() * 2 + half: BlockHalf,
if half == BlockHalf::Top { 0 } else { 2 * 5 } + shape: StairShape,
facing.horizontal_offset() * 2 * 5 * 2) waterlogged: bool,
) -> Option<usize> {
Some(
if waterlogged { 0 } else { 1 }
+ shape.offset() * 2
+ if half == BlockHalf::Top { 0 } else { 2 * 5 }
+ facing.horizontal_offset() * 2 * 5 * 2,
)
} }
#[allow(clippy::many_single_char_names)] #[allow(clippy::many_single_char_names)]
@ -6113,24 +6219,24 @@ fn stair_collision(facing: Direction, shape: StairShape, half: BlockHalf) -> Vec
for bound in &mut bounds { for bound in &mut bounds {
let x = bound.min.x - 0.5; let x = bound.min.x - 0.5;
let z = bound.min.z - 0.5; let z = bound.min.z - 0.5;
bound.min.x = 0.5 + (x*c - z*s); bound.min.x = 0.5 + (x * c - z * s);
bound.min.z = 0.5 + (z*c + x*s); bound.min.z = 0.5 + (z * c + x * s);
let x = bound.max.x - 0.5; let x = bound.max.x - 0.5;
let z = bound.max.z - 0.5; let z = bound.max.z - 0.5;
bound.max.x = 0.5 + (x*c - z*s); bound.max.x = 0.5 + (x * c - z * s);
bound.max.z = 0.5 + (z*c + x*s); bound.max.z = 0.5 + (z * c + x * s);
if half == BlockHalf::Top { if half == BlockHalf::Top {
let c = PI.cos(); let c = PI.cos();
let s = PI.sin(); let s = PI.sin();
let z = bound.min.z - 0.5; let z = bound.min.z - 0.5;
let y = bound.min.y - 0.5; let y = bound.min.y - 0.5;
bound.min.z = 0.5 + (z*c - y*s); bound.min.z = 0.5 + (z * c - y * s);
bound.min.y = 0.5 + (y*c + z*s); bound.min.y = 0.5 + (y * c + z * s);
let z = bound.max.z - 0.5; let z = bound.max.z - 0.5;
let y = bound.max.y - 0.5; let y = bound.max.y - 0.5;
bound.max.z = 0.5 + (z*c - y*s); bound.max.z = 0.5 + (z * c - y * s);
bound.max.y = 0.5 + (y*c + z*s); bound.max.y = 0.5 + (y * c + z * s);
bound.min.x = 1.0 - bound.min.x; bound.min.x = 1.0 - bound.min.x;
bound.max.x = 1.0 - bound.max.x; bound.max.x = 1.0 - bound.max.x;
@ -6150,7 +6256,7 @@ fn slab_collision(half: BlockHalf) -> Vec<Aabb3<f64>> {
vec![Aabb3::new( vec![Aabb3::new(
Point3::new(min_x, min_y, min_z), Point3::new(min_x, min_y, min_z),
Point3::new(max_x, max_y, max_z) Point3::new(max_x, max_y, max_z),
)] )]
} }
@ -6218,7 +6324,7 @@ impl DirtVariant {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum BedPart { pub enum BedPart {
Head, Head,
Foot Foot,
} }
impl BedPart { impl BedPart {
@ -6301,7 +6407,6 @@ impl NoteBlockInstrument {
} }
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum RedSandstoneVariant { pub enum RedSandstoneVariant {
Normal, Normal,
@ -6382,67 +6487,91 @@ impl PrismarineVariant {
} }
} }
fn mushroom_block_data(is_stem: bool, west: bool, up: bool, south: bool, north: bool, east: bool, down: bool) -> Option<usize> { fn mushroom_block_data(
Some(match is_stem: bool,
(is_stem, west, up, south, north, east, down) { west: bool,
up: bool,
south: bool,
north: bool,
east: bool,
down: bool,
) -> Option<usize> {
Some(match (is_stem, west, up, south, north, east, down) {
(false, false, false, false, false, false, false) => 0, (false, false, false, false, false, false, false) => 0,
(false, true, false, false, true, false, false) => 1, (false, true, false, false, true, false, false) => 1,
(false, false, false, false, true, false, false) => 2, (false, false, false, false, true, false, false) => 2,
(false, false, false, false, true, true, false) => 3, (false, false, false, false, true, true, false) => 3,
(false, true, false, false, false, false, false) => 4, (false, true, false, false, false, false, false) => 4,
(false, false, true, false, false, false, false) => 5, (false, false, true, false, false, false, false) => 5,
(false, false, false, false, false, true, false) => 6, (false, false, false, false, false, true, false) => 6,
(false, true, false, true, false, false, false) => 7, (false, true, false, true, false, false, false) => 7,
(false, false, false, true, false, false, false) => 8, (false, false, false, true, false, false, false) => 8,
(false, false, false, true, false, true, false) => 9, (false, false, false, true, false, true, false) => 9,
(false, true, false, true, true, true, false) => 10, (false, true, false, true, true, true, false) => 10,
(false, true, true, true, true, true, true) => 14, (false, true, true, true, true, true, true) => 14,
(true, false, false, false, false, false, false) => 15, (true, false, false, false, false, false, false) => 15,
_ => return None, _ => return None,
}) })
} }
fn mushroom_block_offset(is_stem: bool, west: bool, up: bool, south: bool, north: bool, east: bool, down: bool) -> Option<usize> { fn mushroom_block_offset(
is_stem: bool,
west: bool,
up: bool,
south: bool,
north: bool,
east: bool,
down: bool,
) -> Option<usize> {
if is_stem { if is_stem {
None None
} else { } else {
Some(if west { 0 } else { 1<<0 } + Some(
if up { 0 } else { 1<<1 } + if west { 0 } else { 1 << 0 }
if south { 0 } else { 1<<2 } + + if up { 0 } else { 1 << 1 }
if north { 0 } else { 1<<3 } + + if south { 0 } else { 1 << 2 }
if east { 0 } else { 1<<4 } + + if north { 0 } else { 1 << 3 }
if down { 0 } else { 1<<5 }) + if east { 0 } else { 1 << 4 }
+ if down { 0 } else { 1 << 5 },
)
} }
} }
fn mushroom_block_variant(
fn mushroom_block_variant(is_stem: bool, west: bool, up: bool, south: bool, north: bool, east: bool, down: bool) -> String { is_stem: bool,
west: bool,
up: bool,
south: bool,
north: bool,
east: bool,
down: bool,
) -> String {
(if is_stem { (if is_stem {
"all_stem" "all_stem"
} else { } else {
match match (west, up, south, north, east, down) {
(west, up, south, north, east, down) {
(false, false, false, false, false, false) => "all_inside", (false, false, false, false, false, false) => "all_inside",
(true, false, false, true, false, false) => "north_west", (true, false, false, true, false, false) => "north_west",
(false, false, false, true, false, false) => "north", (false, false, false, true, false, false) => "north",
(false, false, false, true, true, false) => "north_east", (false, false, false, true, true, false) => "north_east",
(true, false, false, false, false, false) => "west", (true, false, false, false, false, false) => "west",
(false, true, false, false, false, false) => "center", (false, true, false, false, false, false) => "center",
(false, false, false, false, true, false) => "east", (false, false, false, false, true, false) => "east",
(true, false, true, false, false, false) => "south_west", (true, false, true, false, false, false) => "south_west",
(false, false, true, false, false, false) => "south", (false, false, true, false, false, false) => "south",
(false, false, true, false, true, false) => "south_east", (false, false, true, false, true, false) => "south_east",
(true, false, true, true, true, false) => "stem", (true, false, true, true, true, false) => "stem",
(true, true, true, true, true, true) => "all_outside", (true, true, true, true, true, true) => "all_outside",
_ => "all_stem", _ => "all_stem",
} }
}).to_string() })
.to_string()
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum DoorHalf { pub enum DoorHalf {
Upper, Upper,
Lower Lower,
} }
impl DoorHalf { impl DoorHalf {
@ -6771,9 +6900,9 @@ impl StoneSlabVariant {
fn data(self) -> usize { fn data(self) -> usize {
match self { match self {
StoneSlabVariant::Stone | StoneSlabVariant::Stone | StoneSlabVariant::RedSandstone | StoneSlabVariant::Purpur => {
StoneSlabVariant::RedSandstone | 0
StoneSlabVariant::Purpur => 0, }
StoneSlabVariant::Sandstone => 1, StoneSlabVariant::Sandstone => 1,
StoneSlabVariant::PetrifiedWood => 2, StoneSlabVariant::PetrifiedWood => 2,
StoneSlabVariant::Cobblestone => 3, StoneSlabVariant::Cobblestone => 3,
@ -7037,7 +7166,8 @@ impl AttachedFace {
(AttachedFace::Floor, Direction::East) => "up_x", (AttachedFace::Floor, Direction::East) => "up_x",
(AttachedFace::Ceiling, Direction::South) => "down_z", (AttachedFace::Ceiling, Direction::South) => "down_z",
_ => "north", // TODO: support 1.13.2+ new directions _ => "north", // TODO: support 1.13.2+ new directions
}.to_owned() }
.to_owned()
} }
} }
@ -7094,7 +7224,6 @@ impl StructureBlockMode {
} }
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum TreeVariant { pub enum TreeVariant {
Oak, Oak,
@ -7125,7 +7254,7 @@ impl TreeVariant {
TreeVariant::StrippedJungle => "stripped_jungle_log", TreeVariant::StrippedJungle => "stripped_jungle_log",
TreeVariant::StrippedAcacia => "stripped_acacia_log", TreeVariant::StrippedAcacia => "stripped_acacia_log",
TreeVariant::StrippedDarkOak => "stripped_dark_oak_log", TreeVariant::StrippedDarkOak => "stripped_dark_oak_log",
TreeVariant::StrippedOak => "stripped_oak_log" TreeVariant::StrippedOak => "stripped_oak_log",
} }
} }
@ -7388,4 +7517,3 @@ impl CoralVariant {
} }
} }
} }

View File

@ -1,4 +1,3 @@
pub struct Material { pub struct Material {
pub renderable: bool, pub renderable: bool,
pub should_cull_against: bool, pub should_cull_against: bool,

View File

@ -1,19 +1,15 @@
use gl_generator::{Api, Fallbacks, GlobalGenerator, Profile, Registry};
use std::env; use std::env;
use std::fs::File; use std::fs::File;
use std::io::BufWriter; use std::io::BufWriter;
use std::path::Path; use std::path::Path;
use gl_generator::{Registry, Api, Profile, Fallbacks, GlobalGenerator};
fn main() { fn main() {
let out_dir = env::var("OUT_DIR").unwrap(); let out_dir = env::var("OUT_DIR").unwrap();
let dest = Path::new(&out_dir); let dest = Path::new(&out_dir);
let mut file = BufWriter::new(File::create(&dest.join("bindings.rs")).unwrap()); let mut file = BufWriter::new(File::create(&dest.join("bindings.rs")).unwrap());
Registry::new(Api::Gl, Registry::new(Api::Gl, (3, 2), Profile::Core, Fallbacks::All, [])
(3, 2),
Profile::Core,
Fallbacks::All,
[])
.write_bindings(GlobalGenerator, &mut file) .write_bindings(GlobalGenerator, &mut file)
.unwrap(); .unwrap();
} }

View File

@ -22,7 +22,6 @@ pub enum Component {
} }
impl Component { impl Component {
pub fn from_string(str: &str) -> Self { pub fn from_string(str: &str) -> Self {
let mut component; let mut component;
match serde_json::from_str::<serde_json::Value>(str) { match serde_json::from_str::<serde_json::Value>(str) {
@ -31,7 +30,7 @@ impl Component {
Err(_) => { Err(_) => {
component = Component::Text(TextComponent::new(str)); component = Component::Text(TextComponent::new(str));
convert_legacy(&mut component); convert_legacy(&mut component);
}, }
} }
component component
} }
@ -47,7 +46,9 @@ impl Component {
Component::Text(TextComponent::from_value(v, modifier)) Component::Text(TextComponent::from_value(v, modifier))
} else if v.get("translate").is_some() { } else if v.get("translate").is_some() {
// TODO: translations // TODO: translations
Component::Text(TextComponent::new(v.get("translate").unwrap().as_str().unwrap())) Component::Text(TextComponent::new(
v.get("translate").unwrap().as_str().unwrap(),
))
} else { } else {
modifier.color = Some(Color::RGB(255, 0, 0)); modifier.color = Some(Color::RGB(255, 0, 0));
Component::Text(TextComponent { Component::Text(TextComponent {
@ -100,9 +101,10 @@ impl Modifier {
underlined: v.get("underlined").map_or(Option::None, |v| v.as_bool()), underlined: v.get("underlined").map_or(Option::None, |v| v.as_bool()),
strikethrough: v.get("strikethrough").map_or(Option::None, |v| v.as_bool()), strikethrough: v.get("strikethrough").map_or(Option::None, |v| v.as_bool()),
obfuscated: v.get("obfuscated").map_or(Option::None, |v| v.as_bool()), obfuscated: v.get("obfuscated").map_or(Option::None, |v| v.as_bool()),
color: v.get("color") color: v
.map_or(Option::None, |v| v.as_str()) .get("color")
.map(|v| Color::from_string(&v.to_owned())), .map_or(Option::None, |v| v.as_str())
.map(|v| Color::from_string(&v.to_owned())),
extra: Option::None, extra: Option::None,
}; };
if let Some(extra) = v.get("extra") { if let Some(extra) = v.get("extra") {
@ -132,7 +134,9 @@ impl TextComponent {
pub fn new(val: &str) -> TextComponent { pub fn new(val: &str) -> TextComponent {
TextComponent { TextComponent {
text: val.to_owned(), text: val.to_owned(),
modifier: Modifier { ..Default::default() }, modifier: Modifier {
..Default::default()
},
} }
} }
@ -319,8 +323,9 @@ pub fn convert_legacy(c: &mut Component) {
current.text = txt.text[last..i].to_owned(); current.text = txt.text[last..i].to_owned();
last = next.0 + 1; last = next.0 + 1;
let mut modifier = if (color_char >= 'a' && color_char <= 'f') || let mut modifier = if (color_char >= 'a' && color_char <= 'f')
(color_char >= '0' && color_char <= '9') { || (color_char >= '0' && color_char <= '9')
{
Default::default() Default::default()
} else { } else {
current.modifier.clone() current.modifier.clone()

View File

@ -14,8 +14,8 @@
use crate::nbt; use crate::nbt;
use crate::protocol::{self, Serializable}; use crate::protocol::{self, Serializable};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use std::io; use std::io;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
#[derive(Debug)] #[derive(Debug)]
pub struct Stack { pub struct Stack {
@ -25,7 +25,6 @@ pub struct Stack {
tag: Option<nbt::NamedTag>, tag: Option<nbt::NamedTag>,
} }
impl Default for Stack { impl Default for Stack {
fn default() -> Stack { fn default() -> Stack {
Stack { Stack {
@ -44,7 +43,7 @@ impl Serializable for Option<Stack> {
if protocol_version >= 404 { if protocol_version >= 404 {
let present = buf.read_u8()? != 0; let present = buf.read_u8()? != 0;
if !present { if !present {
return Ok(None) return Ok(None);
} }
} }

View File

@ -1,10 +1,9 @@
#![recursion_limit = "300"]
#![recursion_limit="300"]
#[macro_use] #[macro_use]
pub mod macros; pub mod macros;
pub mod item;
pub mod format; pub mod format;
pub mod item;
pub mod nbt; pub mod nbt;
pub mod protocol; pub mod protocol;
pub mod types; pub mod types;

View File

@ -1,5 +1,3 @@
#[doc(hidden)] #[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! create_ids { macro_rules! create_ids {

View File

@ -16,9 +16,9 @@ use std::collections::HashMap;
use std::io; use std::io;
use std::io::Read; use std::io::Read;
use super::protocol::Serializable;
use super::protocol; use super::protocol;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; use super::protocol::Serializable;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Tag { pub enum Tag {
@ -41,7 +41,6 @@ pub enum Tag {
pub struct NamedTag(pub String, pub Tag); pub struct NamedTag(pub String, pub Tag);
impl Tag { impl Tag {
pub fn new_compound() -> Tag { pub fn new_compound() -> Tag {
Tag::Compound(HashMap::new()) Tag::Compound(HashMap::new())
} }
@ -163,7 +162,6 @@ impl Tag {
} }
} }
fn internal_id(&self) -> u8 { fn internal_id(&self) -> u8 {
match *self { match *self {
Tag::End => 0, Tag::End => 0,

View File

@ -1,10 +1,9 @@
/// Implements https://wiki.vg/Minecraft_Forge_Handshake
use std::io;
use byteorder::WriteBytesExt; use byteorder::WriteBytesExt;
use log::debug; use log::debug;
/// Implements https://wiki.vg/Minecraft_Forge_Handshake
use std::io;
use super::{Serializable, Error, LenPrefixed, VarInt}; use super::{Error, LenPrefixed, Serializable, VarInt};
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Phase { pub enum Phase {
@ -45,7 +44,6 @@ impl Serializable for Phase {
} }
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct ForgeMod { pub struct ForgeMod {
pub modid: String, pub modid: String,
@ -133,19 +131,20 @@ impl Serializable for FmlHs {
None None
}; };
debug!("FML|HS ServerHello: fml_protocol_version={}, override_dimension={:?}", fml_protocol_version, override_dimension); debug!(
"FML|HS ServerHello: fml_protocol_version={}, override_dimension={:?}",
fml_protocol_version, override_dimension
);
Ok(FmlHs::ServerHello { Ok(FmlHs::ServerHello {
fml_protocol_version, fml_protocol_version,
override_dimension, override_dimension,
}) })
}, }
1 => panic!("Received unexpected FML|HS ClientHello from server"), 1 => panic!("Received unexpected FML|HS ClientHello from server"),
2 => { 2 => Ok(FmlHs::ModList {
Ok(FmlHs::ModList { mods: Serializable::read_from(buf)?,
mods: Serializable::read_from(buf)?, }),
})
},
3 => { 3 => {
let protocol_version = super::current_protocol_version(); let protocol_version = super::current_protocol_version();
@ -161,34 +160,34 @@ impl Serializable for FmlHs {
Ok(FmlHs::ModIdData { Ok(FmlHs::ModIdData {
mappings: Serializable::read_from(buf)?, mappings: Serializable::read_from(buf)?,
block_substitutions: Serializable::read_from(buf)?, block_substitutions: Serializable::read_from(buf)?,
item_substitutions: Serializable::read_from(buf)?, item_substitutions: Serializable::read_from(buf)?,
}) })
} }
}, }
255 => { 255 => Ok(FmlHs::HandshakeAck {
Ok(FmlHs::HandshakeAck { phase: Serializable::read_from(buf)?,
phase: Serializable::read_from(buf)?, }),
})
},
_ => panic!("Unhandled FML|HS packet: discriminator={}", discriminator), _ => panic!("Unhandled FML|HS packet: discriminator={}", discriminator),
} }
} }
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> { fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
match self { match self {
FmlHs::ClientHello { fml_protocol_version } => { FmlHs::ClientHello {
fml_protocol_version,
} => {
buf.write_u8(1)?; buf.write_u8(1)?;
fml_protocol_version.write_to(buf) fml_protocol_version.write_to(buf)
}, }
FmlHs::ModList { mods } => { FmlHs::ModList { mods } => {
buf.write_u8(2)?; buf.write_u8(2)?;
mods.write_to(buf) mods.write_to(buf)
}, }
FmlHs::HandshakeAck { phase } => { FmlHs::HandshakeAck { phase } => {
buf.write_u8(255)?; buf.write_u8(255)?;
phase.write_to(buf) phase.write_to(buf)
}, }
_ => unimplemented!() _ => unimplemented!(),
} }
} }
} }

View File

@ -16,34 +16,36 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
use aes::Aes128; use aes::Aes128;
use cfb8::Cfb8;
use cfb8::stream_cipher::{NewStreamCipher, StreamCipher}; use cfb8::stream_cipher::{NewStreamCipher, StreamCipher};
use serde_json; use cfb8::Cfb8;
use std_or_web::fs; use hex;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use reqwest; use reqwest;
use hex; use serde_json;
use std_or_web::fs;
pub mod mojang;
pub mod forge; pub mod forge;
pub mod mojang;
use crate::nbt;
use crate::format; use crate::format;
use std::fmt; use crate::nbt;
use std::default; use crate::shared::Position;
use std::net::TcpStream; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use std::io;
use std::io::{Write, Read};
use std::convert;
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use flate2::read::{ZlibDecoder, ZlibEncoder}; use flate2::read::{ZlibDecoder, ZlibEncoder};
use flate2::Compression; use flate2::Compression;
use std::time::{Instant, Duration};
use crate::shared::Position;
use log::debug; use log::debug;
use std::convert;
use std::default;
use std::fmt;
use std::io;
use std::io::{Read, Write};
use std::net::TcpStream;
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
use std::time::{Duration, Instant};
pub const SUPPORTED_PROTOCOLS: [i32; 18] = [575, 498, 490, 485, 480, 477, 452, 451, 404, 340, 316, 315, 210, 109, 107, 74, 47, 5]; pub const SUPPORTED_PROTOCOLS: [i32; 18] = [
575, 498, 490, 485, 480, 477, 452, 451, 404, 340, 316, 315, 210, 109, 107, 74, 47, 5,
];
static CURRENT_PROTOCOL_VERSION: AtomicI32 = AtomicI32::new(SUPPORTED_PROTOCOLS[0]); static CURRENT_PROTOCOL_VERSION: AtomicI32 = AtomicI32::new(SUPPORTED_PROTOCOLS[0]);
static NETWORK_DEBUG: AtomicBool = AtomicBool::new(false); static NETWORK_DEBUG: AtomicBool = AtomicBool::new(false);
@ -233,7 +235,7 @@ impl Serializable for Vec<u8> {
} }
} }
impl Serializable for Option<nbt::NamedTag>{ impl Serializable for Option<nbt::NamedTag> {
fn read_from<R: io::Read>(buf: &mut R) -> Result<Option<nbt::NamedTag>, Error> { fn read_from<R: io::Read>(buf: &mut R) -> Result<Option<nbt::NamedTag>, Error> {
let ty = buf.read_u8()?; let ty = buf.read_u8()?;
if ty == 0 { if ty == 0 {
@ -257,7 +259,10 @@ impl Serializable for Option<nbt::NamedTag>{
} }
} }
impl <T> Serializable for Option<T> where T : Serializable { impl<T> Serializable for Option<T>
where
T: Serializable,
{
fn read_from<R: io::Read>(buf: &mut R) -> Result<Option<T>, Error> { fn read_from<R: io::Read>(buf: &mut R) -> Result<Option<T>, Error> {
Result::Ok(Some(T::read_from(buf)?)) Result::Ok(Some(T::read_from(buf)?))
} }
@ -318,11 +323,7 @@ impl Serializable for bool {
Result::Ok(buf.read_u8()? != 0) Result::Ok(buf.read_u8()? != 0)
} }
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> { fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
buf.write_u8(if *self { buf.write_u8(if *self { 1 } else { 0 })?;
1
} else {
0
})?;
Result::Ok(()) Result::Ok(())
} }
} }
@ -433,9 +434,9 @@ impl UUID {
parts.extend_from_slice(&hex::decode(&s[24..36]).unwrap()); parts.extend_from_slice(&hex::decode(&s[24..36]).unwrap());
let mut high = 0u64; let mut high = 0u64;
let mut low = 0u64; let mut low = 0u64;
for i in 0 .. 8 { for i in 0..8 {
high |= (parts[i] as u64) << (56 - i*8); high |= (parts[i] as u64) << (56 - i * 8);
low |= (parts[i + 8] as u64) << (56 - i*8); low |= (parts[i + 8] as u64) << (56 - i * 8);
} }
UUID(high, low) UUID(high, low)
} }
@ -449,8 +450,10 @@ impl Default for UUID {
impl Serializable for UUID { impl Serializable for UUID {
fn read_from<R: io::Read>(buf: &mut R) -> Result<UUID, Error> { fn read_from<R: io::Read>(buf: &mut R) -> Result<UUID, Error> {
Result::Ok(UUID(buf.read_u64::<BigEndian>()?, Result::Ok(UUID(
buf.read_u64::<BigEndian>()?)) buf.read_u64::<BigEndian>()?,
buf.read_u64::<BigEndian>()?,
))
} }
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> { fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
buf.write_u64::<BigEndian>(self.0)?; buf.write_u64::<BigEndian>(self.0)?;
@ -496,8 +499,7 @@ impl Serializable for Biomes3D {
} }
} }
pub trait Lengthable: Serializable + Copy + Default {
pub trait Lengthable : Serializable + Copy + Default {
fn into_len(self) -> usize; fn into_len(self) -> usize;
fn from_len(_: usize) -> Self; fn from_len(_: usize) -> Self;
} }
@ -507,7 +509,7 @@ pub struct LenPrefixed<L: Lengthable, V> {
pub data: Vec<V>, pub data: Vec<V>,
} }
impl <L: Lengthable, V: Default> LenPrefixed<L, V> { impl<L: Lengthable, V: Default> LenPrefixed<L, V> {
pub fn new(data: Vec<V>) -> LenPrefixed<L, V> { pub fn new(data: Vec<V>) -> LenPrefixed<L, V> {
LenPrefixed { LenPrefixed {
len: Default::default(), len: Default::default(),
@ -516,7 +518,7 @@ impl <L: Lengthable, V: Default> LenPrefixed<L, V> {
} }
} }
impl <L: Lengthable, V: Serializable> Serializable for LenPrefixed<L, V> { impl<L: Lengthable, V: Serializable> Serializable for LenPrefixed<L, V> {
fn read_from<R: io::Read>(buf: &mut R) -> Result<LenPrefixed<L, V>, Error> { fn read_from<R: io::Read>(buf: &mut R) -> Result<LenPrefixed<L, V>, Error> {
let len_data: L = Serializable::read_from(buf)?; let len_data: L = Serializable::read_from(buf)?;
let len: usize = len_data.into_len(); let len: usize = len_data.into_len();
@ -541,8 +543,7 @@ impl <L: Lengthable, V: Serializable> Serializable for LenPrefixed<L, V> {
} }
} }
impl<L: Lengthable, V: Default> Default for LenPrefixed<L, V> {
impl <L: Lengthable, V: Default> Default for LenPrefixed<L, V> {
fn default() -> Self { fn default() -> Self {
LenPrefixed { LenPrefixed {
len: default::Default::default(), len: default::Default::default(),
@ -551,7 +552,7 @@ impl <L: Lengthable, V: Default> Default for LenPrefixed<L, V> {
} }
} }
impl <L: Lengthable, V: fmt::Debug> fmt::Debug for LenPrefixed<L, V> { impl<L: Lengthable, V: fmt::Debug> fmt::Debug for LenPrefixed<L, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.data.fmt(f) self.data.fmt(f)
} }
@ -563,7 +564,7 @@ pub struct LenPrefixedBytes<L: Lengthable> {
pub data: Vec<u8>, pub data: Vec<u8>,
} }
impl <L: Lengthable> LenPrefixedBytes<L> { impl<L: Lengthable> LenPrefixedBytes<L> {
pub fn new(data: Vec<u8>) -> LenPrefixedBytes<L> { pub fn new(data: Vec<u8>) -> LenPrefixedBytes<L> {
LenPrefixedBytes { LenPrefixedBytes {
len: Default::default(), len: Default::default(),
@ -572,7 +573,7 @@ impl <L: Lengthable> LenPrefixedBytes<L> {
} }
} }
impl <L: Lengthable> Serializable for LenPrefixedBytes<L> { impl<L: Lengthable> Serializable for LenPrefixedBytes<L> {
fn read_from<R: io::Read>(buf: &mut R) -> Result<LenPrefixedBytes<L>, Error> { fn read_from<R: io::Read>(buf: &mut R) -> Result<LenPrefixedBytes<L>, Error> {
let len_data: L = Serializable::read_from(buf)?; let len_data: L = Serializable::read_from(buf)?;
let len: usize = len_data.into_len(); let len: usize = len_data.into_len();
@ -592,8 +593,7 @@ impl <L: Lengthable> Serializable for LenPrefixedBytes<L> {
} }
} }
impl<L: Lengthable> Default for LenPrefixedBytes<L> {
impl <L: Lengthable> Default for LenPrefixedBytes<L> {
fn default() -> Self { fn default() -> Self {
LenPrefixedBytes { LenPrefixedBytes {
len: default::Default::default(), len: default::Default::default(),
@ -602,7 +602,7 @@ impl <L: Lengthable> Default for LenPrefixedBytes<L> {
} }
} }
impl <L: Lengthable> fmt::Debug for LenPrefixedBytes<L> { impl<L: Lengthable> fmt::Debug for LenPrefixedBytes<L> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.data.fmt(f) self.data.fmt(f)
} }
@ -610,7 +610,11 @@ impl <L: Lengthable> fmt::Debug for LenPrefixedBytes<L> {
impl Lengthable for bool { impl Lengthable for bool {
fn into_len(self) -> usize { fn into_len(self) -> usize {
if self { 1 } else { 0 } if self {
1
} else {
0
}
} }
fn from_len(u: usize) -> bool { fn from_len(u: usize) -> bool {
@ -618,7 +622,6 @@ impl Lengthable for bool {
} }
} }
impl Lengthable for u8 { impl Lengthable for u8 {
fn into_len(self) -> usize { fn into_len(self) -> usize {
self as usize self as usize
@ -685,7 +688,12 @@ impl<T: NumCast> convert::From<FixedPoint5<T>> for f64 {
} }
} }
impl<T> fmt::Debug for FixedPoint5<T> where T: fmt::Display, f64: convert::From<T>, T: NumCast + Copy { impl<T> fmt::Debug for FixedPoint5<T>
where
T: fmt::Display,
f64: convert::From<T>,
T: NumCast + Copy,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let x: f64 = (*self).into(); let x: f64 = (*self).into();
write!(f, "FixedPoint5(#{} = {}f)", self.0, x) write!(f, "FixedPoint5(#{} = {}f)", self.0, x)
@ -726,7 +734,12 @@ impl<T: NumCast> convert::From<FixedPoint12<T>> for f64 {
} }
} }
impl<T> fmt::Debug for FixedPoint12<T> where T: fmt::Display, f64: convert::From<T>, T: NumCast + Copy { impl<T> fmt::Debug for FixedPoint12<T>
where
T: fmt::Display,
f64: convert::From<T>,
T: NumCast + Copy,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let x: f64 = (*self).into(); let x: f64 = (*self).into();
write!(f, "FixedPoint12(#{} = {}f)", self.0, x) write!(f, "FixedPoint12(#{} = {}f)", self.0, x)
@ -751,7 +764,7 @@ impl Lengthable for VarInt {
impl Serializable for VarInt { impl Serializable for VarInt {
/// Decodes a `VarInt` from the Reader /// Decodes a `VarInt` from the Reader
fn read_from<R: io::Read>(buf: &mut R) -> Result<VarInt, Error> { fn read_from<R: io::Read>(buf: &mut R) -> Result<VarInt, Error> {
const PART : u32 = 0x7F; const PART: u32 = 0x7F;
let mut size = 0; let mut size = 0;
let mut val = 0u32; let mut val = 0u32;
loop { loop {
@ -762,7 +775,7 @@ impl Serializable for VarInt {
return Result::Err(Error::Err("VarInt too big".to_owned())); return Result::Err(Error::Err("VarInt too big".to_owned()));
} }
if (b & 0x80) == 0 { if (b & 0x80) == 0 {
break break;
} }
} }
@ -771,7 +784,7 @@ impl Serializable for VarInt {
/// Encodes a `VarInt` into the Writer /// Encodes a `VarInt` into the Writer
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> { fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
const PART : u32 = 0x7F; const PART: u32 = 0x7F;
let mut val = self.0 as u32; let mut val = self.0 as u32;
loop { loop {
if (val & !PART) == 0 { if (val & !PART) == 0 {
@ -826,7 +839,11 @@ impl Serializable for VarShort {
} }
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> { fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
assert!(self.0 >= 0 && self.0 <= 0x7fffff, "VarShort invalid value: {}", self.0); assert!(
self.0 >= 0 && self.0 <= 0x7fffff,
"VarShort invalid value: {}",
self.0
);
let mut low = self.0 & 0x7fff; let mut low = self.0 & 0x7fff;
let high = (self.0 & 0x7f8000) >> 15; let high = (self.0 & 0x7f8000) >> 15;
if high != 0 { if high != 0 {
@ -873,7 +890,7 @@ impl Lengthable for VarLong {
impl Serializable for VarLong { impl Serializable for VarLong {
/// Decodes a `VarLong` from the Reader /// Decodes a `VarLong` from the Reader
fn read_from<R: io::Read>(buf: &mut R) -> Result<VarLong, Error> { fn read_from<R: io::Read>(buf: &mut R) -> Result<VarLong, Error> {
const PART : u64 = 0x7F; const PART: u64 = 0x7F;
let mut size = 0; let mut size = 0;
let mut val = 0u64; let mut val = 0u64;
loop { loop {
@ -884,7 +901,7 @@ impl Serializable for VarLong {
return Result::Err(Error::Err("VarLong too big".to_owned())); return Result::Err(Error::Err("VarLong too big".to_owned()));
} }
if (b & 0x80) == 0 { if (b & 0x80) == 0 {
break break;
} }
} }
@ -893,7 +910,7 @@ impl Serializable for VarLong {
/// Encodes a `VarLong` into the Writer /// Encodes a `VarLong` into the Writer
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> { fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
const PART : u64 = 0x7F; const PART: u64 = 0x7F;
let mut val = self.0 as u64; let mut val = self.0 as u64;
loop { loop {
if (val & !PART) == 0 { if (val & !PART) == 0 {
@ -924,7 +941,7 @@ impl Serializable for Position {
Ok(Position::new( Ok(Position::new(
((pos as i64) >> 38) as i32, ((pos as i64) >> 38) as i32,
(((pos as i64) >> 26) & 0xFFF) as i32, (((pos as i64) >> 26) & 0xFFF) as i32,
((pos as i64) << 38 >> 38) as i32 ((pos as i64) << 38 >> 38) as i32,
)) ))
} }
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> { fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
@ -936,7 +953,6 @@ impl Serializable for Position {
} }
} }
/// Direction is used to define whether packets are going to the /// Direction is used to define whether packets are going to the
/// server or the client. /// server or the client.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@ -1058,9 +1074,13 @@ impl Conn {
let mut write = ZlibEncoder::new(io::Cursor::new(buf), Compression::default()); let mut write = ZlibEncoder::new(io::Cursor::new(buf), Compression::default());
write.read_to_end(&mut new)?; write.read_to_end(&mut new)?;
if is_network_debug() { if is_network_debug() {
debug!("Compressed for sending {} bytes to {} since > threshold {}, new={:?}", debug!(
uncompressed_size, new.len(), self.compression_threshold, "Compressed for sending {} bytes to {} since > threshold {}, new={:?}",
new); uncompressed_size,
new.len(),
self.compression_threshold,
new
);
} }
buf = new; buf = new;
} }
@ -1090,8 +1110,13 @@ impl Conn {
reader.read_to_end(&mut new)?; reader.read_to_end(&mut new)?;
} }
if is_network_debug() { if is_network_debug() {
debug!("Decompressed threshold={} len={} uncompressed_size={} to {} bytes", debug!(
self.compression_threshold, len, uncompressed_size, new.len()); "Decompressed threshold={} len={} uncompressed_size={} to {} bytes",
self.compression_threshold,
len,
uncompressed_size,
new.len()
);
} }
buf = io::Cursor::new(new); buf = io::Cursor::new(new);
} }
@ -1104,7 +1129,10 @@ impl Conn {
}; };
if is_network_debug() { if is_network_debug() {
debug!("about to parse id={:x}, dir={:?} state={:?}", id, dir, self.state); debug!(
"about to parse id={:x}, dir={:?} state={:?}",
id, dir, self.state
);
fs::File::create("last-packet")?.write_all(buf.get_ref())?; fs::File::create("last-packet")?.write_all(buf.get_ref())?;
} }
@ -1119,10 +1147,12 @@ impl Conn {
let pos = buf.position() as usize; let pos = buf.position() as usize;
let ibuf = buf.into_inner(); let ibuf = buf.into_inner();
if ibuf.len() != pos { if ibuf.len() != pos {
return Result::Err(Error::Err(format!("Failed to read all of packet 0x{:X}, \ return Result::Err(Error::Err(format!(
"Failed to read all of packet 0x{:X}, \
had {} bytes left", had {} bytes left",
id, id,
ibuf.len() - pos))) ibuf.len() - pos
)));
} }
Result::Ok(val) Result::Ok(val)
} }
@ -1140,10 +1170,10 @@ impl Conn {
} }
pub fn do_status(mut self) -> Result<(Status, Duration), Error> { pub fn do_status(mut self) -> Result<(Status, Duration), Error> {
use serde_json::Value;
use self::packet::status::serverbound::*;
use self::packet::handshake::serverbound::Handshake; use self::packet::handshake::serverbound::Handshake;
use self::packet::status::serverbound::*;
use self::packet::Packet; use self::packet::Packet;
use serde_json::Value;
let host = self.host.clone(); let host = self.host.clone();
let port = self.port; let port = self.port;
self.write_packet(Handshake { self.write_packet(Handshake {
@ -1191,16 +1221,22 @@ impl Conn {
if let Value::Array(items) = modlist { if let Value::Array(items) = modlist {
for item in items { for item in items {
if let Value::Object(obj) = item { if let Value::Object(obj) = item {
let modid = obj.get("modid").unwrap().as_str().unwrap().to_string(); let modid =
let version = obj.get("version").unwrap().as_str().unwrap().to_string(); obj.get("modid").unwrap().as_str().unwrap().to_string();
let version =
obj.get("version").unwrap().as_str().unwrap().to_string();
forge_mods.push(crate::protocol::forge::ForgeMod { modid, version }); forge_mods
.push(crate::protocol::forge::ForgeMod { modid, version });
} }
} }
} }
} }
} else { } else {
panic!("Unrecognized modinfo type in server ping response: {} in {}", modinfo_type, modinfo); panic!(
"Unrecognized modinfo type in server ping response: {} in {}",
modinfo_type, modinfo
);
} }
} }
} }
@ -1211,7 +1247,8 @@ impl Conn {
for item in items { for item in items {
if let Value::Object(obj) = item { if let Value::Object(obj) = item {
let modid = obj.get("modId").unwrap().as_str().unwrap().to_string(); let modid = obj.get("modId").unwrap().as_str().unwrap().to_string();
let modmarker = obj.get("modmarker").unwrap().as_str().unwrap().to_string(); let modmarker =
obj.get("modmarker").unwrap().as_str().unwrap().to_string();
let version = modmarker; let version = modmarker;
@ -1222,29 +1259,41 @@ impl Conn {
} }
} }
Ok((Status { Ok((
version: StatusVersion { Status {
name: version.get("name").and_then(Value::as_str).ok_or(invalid_status())? version: StatusVersion {
.to_owned(), name: version
protocol: version.get("protocol") .get("name")
.and_then(Value::as_i64) .and_then(Value::as_str)
.ok_or(invalid_status())? as i32, .ok_or(invalid_status())?
.to_owned(),
protocol: version
.get("protocol")
.and_then(Value::as_i64)
.ok_or(invalid_status())? as i32,
},
players: StatusPlayers {
max: players
.get("max")
.and_then(Value::as_i64)
.ok_or(invalid_status())? as i32,
online: players
.get("online")
.and_then(Value::as_i64)
.ok_or(invalid_status())? as i32,
sample: Vec::new(), /* TODO */
},
description: format::Component::from_value(
val.get("description").ok_or(invalid_status())?,
),
favicon: val
.get("favicon")
.and_then(Value::as_str)
.map(|v| v.to_owned()),
forge_mods,
}, },
players: StatusPlayers { ping,
max: players.get("max") ))
.and_then(Value::as_i64)
.ok_or(invalid_status())? as i32,
online: players.get("online")
.and_then(Value::as_i64)
.ok_or(invalid_status())? as i32,
sample: Vec::new(), /* TODO */
},
description: format::Component::from_value(val.get("description")
.ok_or(invalid_status())?),
favicon: val.get("favicon").and_then(Value::as_str).map(|v| v.to_owned()),
forge_mods,
},
ping))
} }
} }

View File

@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use sha1::{self, Digest};
use serde_json::json;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use reqwest; use reqwest;
use serde_json::json;
use sha1::{self, Digest};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Profile { pub struct Profile {
@ -33,17 +33,18 @@ const VALIDATE_URL: &str = "https://authserver.mojang.com/validate";
impl Profile { impl Profile {
pub fn login(username: &str, password: &str, token: &str) -> Result<Profile, super::Error> { pub fn login(username: &str, password: &str, token: &str) -> Result<Profile, super::Error> {
let req_msg = json!({ let req_msg = json!({
"username": username, "username": username,
"password": password, "password": password,
"clientToken": token, "clientToken": token,
"agent": { "agent": {
"name": "Minecraft", "name": "Minecraft",
"version": 1 "version": 1
}}); }});
let req = serde_json::to_string(&req_msg)?; let req = serde_json::to_string(&req_msg)?;
let client = reqwest::blocking::Client::new(); let client = reqwest::blocking::Client::new();
let res = client.post(LOGIN_URL) let res = client
.post(LOGIN_URL)
.header(reqwest::header::CONTENT_TYPE, "application/json") .header(reqwest::header::CONTENT_TYPE, "application/json")
.body(req) .body(req)
.send()?; .send()?;
@ -53,33 +54,47 @@ impl Profile {
return Err(super::Error::Err(format!( return Err(super::Error::Err(format!(
"{}: {}", "{}: {}",
error, error,
ret.get("errorMessage").and_then(|v| v.as_str()).unwrap()) ret.get("errorMessage").and_then(|v| v.as_str()).unwrap()
)); )));
} }
Ok(Profile { Ok(Profile {
username: ret.pointer("/selectedProfile/name").and_then(|v| v.as_str()).unwrap().to_owned(), username: ret
id: ret.pointer("/selectedProfile/id").and_then(|v| v.as_str()).unwrap().to_owned(), .pointer("/selectedProfile/name")
access_token: ret.get("accessToken").and_then(|v| v.as_str()).unwrap().to_owned(), .and_then(|v| v.as_str())
.unwrap()
.to_owned(),
id: ret
.pointer("/selectedProfile/id")
.and_then(|v| v.as_str())
.unwrap()
.to_owned(),
access_token: ret
.get("accessToken")
.and_then(|v| v.as_str())
.unwrap()
.to_owned(),
}) })
} }
pub fn refresh(self, token: &str) -> Result<Profile, super::Error> { pub fn refresh(self, token: &str) -> Result<Profile, super::Error> {
let req_msg = json!({ let req_msg = json!({
"accessToken": self.access_token.clone(), "accessToken": self.access_token.clone(),
"clientToken": token "clientToken": token
}); });
let req = serde_json::to_string(&req_msg)?; let req = serde_json::to_string(&req_msg)?;
let client = reqwest::blocking::Client::new(); let client = reqwest::blocking::Client::new();
let res = client.post(VALIDATE_URL) let res = client
.post(VALIDATE_URL)
.header(reqwest::header::CONTENT_TYPE, "application/json") .header(reqwest::header::CONTENT_TYPE, "application/json")
.body(req) .body(req)
.send()?; .send()?;
if res.status() != reqwest::StatusCode::NO_CONTENT { if res.status() != reqwest::StatusCode::NO_CONTENT {
let req = serde_json::to_string(&req_msg)?; // TODO: fix parsing twice to avoid move let req = serde_json::to_string(&req_msg)?; // TODO: fix parsing twice to avoid move
// Refresh needed // Refresh needed
let res = client.post(REFRESH_URL) let res = client
.post(REFRESH_URL)
.header(reqwest::header::CONTENT_TYPE, "application/json") .header(reqwest::header::CONTENT_TYPE, "application/json")
.body(req) .body(req)
.send()?; .send()?;
@ -89,19 +104,36 @@ impl Profile {
return Err(super::Error::Err(format!( return Err(super::Error::Err(format!(
"{}: {}", "{}: {}",
error, error,
ret.get("errorMessage").and_then(|v| v.as_str()).unwrap()) ret.get("errorMessage").and_then(|v| v.as_str()).unwrap()
)); )));
} }
return Ok(Profile { return Ok(Profile {
username: ret.pointer("/selectedProfile/name").and_then(|v| v.as_str()).unwrap().to_owned(), username: ret
id: ret.pointer("/selectedProfile/id").and_then(|v| v.as_str()).unwrap().to_owned(), .pointer("/selectedProfile/name")
access_token: ret.get("accessToken").and_then(|v| v.as_str()).unwrap().to_owned(), .and_then(|v| v.as_str())
.unwrap()
.to_owned(),
id: ret
.pointer("/selectedProfile/id")
.and_then(|v| v.as_str())
.unwrap()
.to_owned(),
access_token: ret
.get("accessToken")
.and_then(|v| v.as_str())
.unwrap()
.to_owned(),
}); });
} }
Ok(self) Ok(self)
} }
pub fn join_server(&self, server_id: &str, shared_key: &[u8], public_key: &[u8]) -> Result<(), super::Error> { pub fn join_server(
&self,
server_id: &str,
shared_key: &[u8],
public_key: &[u8],
) -> Result<(), super::Error> {
let mut hasher = sha1::Sha1::new(); let mut hasher = sha1::Sha1::new();
hasher.input(server_id.as_bytes()); hasher.input(server_id.as_bytes());
hasher.input(shared_key); hasher.input(shared_key);
@ -114,7 +146,11 @@ impl Profile {
if negative { if negative {
twos_compliment(&mut hash); twos_compliment(&mut hash);
} }
let hash_str = hash.iter().map(|b| format!("{:02x}", b)).collect::<Vec<String>>().join(""); let hash_str = hash
.iter()
.map(|b| format!("{:02x}", b))
.collect::<Vec<String>>()
.join("");
let hash_val = hash_str.trim_start_matches('0'); let hash_val = hash_str.trim_start_matches('0');
let hash_str = if negative { let hash_str = if negative {
"-".to_owned() + &hash_val[..] "-".to_owned() + &hash_val[..]
@ -130,7 +166,8 @@ impl Profile {
let join = serde_json::to_string(&join_msg).unwrap(); let join = serde_json::to_string(&join_msg).unwrap();
let client = reqwest::blocking::Client::new(); let client = reqwest::blocking::Client::new();
let res = client.post(JOIN_URL) let res = client
.post(JOIN_URL)
.header(reqwest::header::CONTENT_TYPE, "application/json") .header(reqwest::header::CONTENT_TYPE, "application/json")
.body(join) .body(join)
.send()?; .send()?;

View File

@ -2193,7 +2193,8 @@ impl Serializable for Advancement {
}; };
let criteria: LenPrefixed<VarInt, String> = Serializable::read_from(buf)?; let criteria: LenPrefixed<VarInt, String> = Serializable::read_from(buf)?;
let requirements: LenPrefixed<VarInt, LenPrefixed<VarInt, String>> = Serializable::read_from(buf)?; let requirements: LenPrefixed<VarInt, LenPrefixed<VarInt, String>> =
Serializable::read_from(buf)?;
Ok(Advancement { Ok(Advancement {
id, id,
parent_id, parent_id,
@ -2210,7 +2211,6 @@ impl Serializable for Advancement {
self.criteria.write_to(buf)?; self.criteria.write_to(buf)?;
self.requirements.write_to(buf) self.requirements.write_to(buf)
} }
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -2264,7 +2264,6 @@ impl Serializable for AdvancementDisplay {
self.x_coord.write_to(buf)?; self.x_coord.write_to(buf)?;
self.y_coord.write_to(buf) self.y_coord.write_to(buf)
} }
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -2315,8 +2314,6 @@ impl Serializable for CriterionProgress {
} }
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EntityProperty { pub struct EntityProperty {
pub key: String, pub key: String,
@ -2363,7 +2360,6 @@ impl Serializable for EntityProperty_i16 {
} }
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct PropertyModifier { pub struct PropertyModifier {
pub uuid: UUID, pub uuid: UUID,
@ -2434,33 +2430,25 @@ impl Serializable for PlayerInfoData {
}; };
m.players.push(p); m.players.push(p);
} }
1 => { 1 => m.players.push(PlayerDetail::UpdateGamemode {
m.players.push(PlayerDetail::UpdateGamemode { uuid,
uuid, gamemode: Serializable::read_from(buf)?,
gamemode: Serializable::read_from(buf)?, }),
}) 2 => m.players.push(PlayerDetail::UpdateLatency {
} uuid,
2 => { ping: Serializable::read_from(buf)?,
m.players.push(PlayerDetail::UpdateLatency { }),
uuid, 3 => m.players.push(PlayerDetail::UpdateDisplayName {
ping: Serializable::read_from(buf)?, uuid,
}) display: {
} if bool::read_from(buf)? {
3 => { Some(Serializable::read_from(buf)?)
m.players.push(PlayerDetail::UpdateDisplayName { } else {
uuid, None
display: { }
if bool::read_from(buf)? { },
Some(Serializable::read_from(buf)?) }),
} else { 4 => m.players.push(PlayerDetail::Remove { uuid: uuid }),
None
}
},
})
}
4 => {
m.players.push(PlayerDetail::Remove { uuid: uuid })
}
_ => panic!(), _ => panic!(),
} }
} }
@ -2619,8 +2607,7 @@ impl Serializable for Recipe {
} }
}; };
let data = let data = match ty.as_ref() {
match ty.as_ref() {
"minecraft:crafting_shapeless" => RecipeData::Shapeless { "minecraft:crafting_shapeless" => RecipeData::Shapeless {
group: Serializable::read_from(buf)?, group: Serializable::read_from(buf)?,
ingredients: Serializable::read_from(buf)?, ingredients: Serializable::read_from(buf)?,
@ -2634,12 +2621,18 @@ impl Serializable for Recipe {
let capacity = width.0 as usize * height.0 as usize; let capacity = width.0 as usize * height.0 as usize;
let mut ingredients = Vec::with_capacity(capacity); let mut ingredients = Vec::with_capacity(capacity);
for _ in 0 .. capacity { for _ in 0..capacity {
ingredients.push(Serializable::read_from(buf)?); ingredients.push(Serializable::read_from(buf)?);
} }
let result: Option<item::Stack> = Serializable::read_from(buf)?; let result: Option<item::Stack> = Serializable::read_from(buf)?;
RecipeData::Shaped { width, height, group, ingredients, result } RecipeData::Shaped {
width,
height,
group,
ingredients,
result,
}
} }
"minecraft:crafting_special_armordye" => RecipeData::ArmorDye, "minecraft:crafting_special_armordye" => RecipeData::ArmorDye,
"minecraft:crafting_special_bookcloning" => RecipeData::BookCloning, "minecraft:crafting_special_bookcloning" => RecipeData::BookCloning,
@ -2688,7 +2681,7 @@ impl Serializable for Recipe {
ingredient: Serializable::read_from(buf)?, ingredient: Serializable::read_from(buf)?,
result: Serializable::read_from(buf)?, result: Serializable::read_from(buf)?,
}, },
_ => panic!("unrecognized recipe type: {}", ty) _ => panic!("unrecognized recipe type: {}", ty),
}; };
Ok(Recipe { id, ty, data }) Ok(Recipe { id, ty, data })
@ -2748,7 +2741,11 @@ impl Serializable for Trade {
xp: Serializable::read_from(buf)?, xp: Serializable::read_from(buf)?,
special_price: Serializable::read_from(buf)?, special_price: Serializable::read_from(buf)?,
price_multiplier: Serializable::read_from(buf)?, price_multiplier: Serializable::read_from(buf)?,
demand: if protocol_version >= 498 { Some(Serializable::read_from(buf)?) } else { None }, demand: if protocol_version >= 498 {
Some(Serializable::read_from(buf)?)
} else {
None
},
}) })
} }
@ -2757,7 +2754,6 @@ impl Serializable for Trade {
} }
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct CommandNode { pub struct CommandNode {
pub flags: u8, pub flags: u8,
@ -2843,7 +2839,6 @@ pub enum CommandProperty {
Dimension, Dimension,
} }
impl Serializable for CommandNode { impl Serializable for CommandNode {
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> { fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
let flags: u8 = Serializable::read_from(buf)?; let flags: u8 = Serializable::read_from(buf)?;
@ -2865,11 +2860,12 @@ impl Serializable for CommandNode {
None None
}; };
let name: Option<String> = if node_type == CommandNodeType::Argument || node_type == CommandNodeType::Literal { let name: Option<String> =
Serializable::read_from(buf)? if node_type == CommandNodeType::Argument || node_type == CommandNodeType::Literal {
} else { Serializable::read_from(buf)?
None } else {
}; None
};
let parser: Option<String> = if node_type == CommandNodeType::Argument { let parser: Option<String> = if node_type == CommandNodeType::Argument {
Serializable::read_from(buf)? Serializable::read_from(buf)?
} else { } else {
@ -2881,27 +2877,51 @@ impl Serializable for CommandNode {
"brigadier:bool" => CommandProperty::Bool, "brigadier:bool" => CommandProperty::Bool,
"brigadier:double" => { "brigadier:double" => {
let flags = Serializable::read_from(buf)?; let flags = Serializable::read_from(buf)?;
let min = if flags & 0x01 != 0 { Some(Serializable::read_from(buf)?) } else { None }; let min = if flags & 0x01 != 0 {
let max = if flags & 0x02 != 0 { Some(Serializable::read_from(buf)?) } else { None }; Some(Serializable::read_from(buf)?)
} else {
None
};
let max = if flags & 0x02 != 0 {
Some(Serializable::read_from(buf)?)
} else {
None
};
CommandProperty::Double { flags, min, max } CommandProperty::Double { flags, min, max }
}, }
"brigadier:float" => { "brigadier:float" => {
let flags = Serializable::read_from(buf)?; let flags = Serializable::read_from(buf)?;
let min = if flags & 0x01 != 0 { Some(Serializable::read_from(buf)?) } else { None }; let min = if flags & 0x01 != 0 {
let max = if flags & 0x02 != 0 { Some(Serializable::read_from(buf)?) } else { None }; Some(Serializable::read_from(buf)?)
} else {
None
};
let max = if flags & 0x02 != 0 {
Some(Serializable::read_from(buf)?)
} else {
None
};
CommandProperty::Float { flags, min, max } CommandProperty::Float { flags, min, max }
}, }
"brigadier:integer" => { "brigadier:integer" => {
let flags = Serializable::read_from(buf)?; let flags = Serializable::read_from(buf)?;
let min = if flags & 0x01 != 0 { Some(Serializable::read_from(buf)?) } else { None }; let min = if flags & 0x01 != 0 {
let max = if flags & 0x02 != 0 { Some(Serializable::read_from(buf)?) } else { None }; Some(Serializable::read_from(buf)?)
} else {
None
};
let max = if flags & 0x02 != 0 {
Some(Serializable::read_from(buf)?)
} else {
None
};
CommandProperty::Integer { flags, min, max } CommandProperty::Integer { flags, min, max }
}
"brigadier:string" => CommandProperty::String {
token_type: Serializable::read_from(buf)?,
}, },
"brigadier:string" => { "minecraft:entity" => CommandProperty::Entity {
CommandProperty::String { token_type: Serializable::read_from(buf)? } flags: Serializable::read_from(buf)?,
},
"minecraft:entity" => {
CommandProperty::Entity { flags: Serializable::read_from(buf)? }
}, },
"minecraft:game_profile" => CommandProperty::GameProfile, "minecraft:game_profile" => CommandProperty::GameProfile,
"minecraft:block_pos" => CommandProperty::BlockPos, "minecraft:block_pos" => CommandProperty::BlockPos,
@ -2926,8 +2946,8 @@ impl Serializable for CommandNode {
"minecraft:particle" => CommandProperty::Particle, "minecraft:particle" => CommandProperty::Particle,
"minecraft:rotation" => CommandProperty::Rotation, "minecraft:rotation" => CommandProperty::Rotation,
"minecraft:scoreboard_slot" => CommandProperty::ScoreboardSlot, "minecraft:scoreboard_slot" => CommandProperty::ScoreboardSlot,
"minecraft:score_holder" => { "minecraft:score_holder" => CommandProperty::ScoreHolder {
CommandProperty::ScoreHolder { flags: Serializable::read_from(buf)? } flags: Serializable::read_from(buf)?,
}, },
"minecraft:swizzle" => CommandProperty::Swizzle, "minecraft:swizzle" => CommandProperty::Swizzle,
"minecraft:team" => CommandProperty::Team, "minecraft:team" => CommandProperty::Team,
@ -2936,8 +2956,8 @@ impl Serializable for CommandNode {
"minecraft:mob_effect" => CommandProperty::MobEffect, "minecraft:mob_effect" => CommandProperty::MobEffect,
"minecraft:function" => CommandProperty::Function, "minecraft:function" => CommandProperty::Function,
"minecraft:entity_anchor" => CommandProperty::EntityAnchor, "minecraft:entity_anchor" => CommandProperty::EntityAnchor,
"minecraft:range" => { "minecraft:range" => CommandProperty::Range {
CommandProperty::Range { decimals: Serializable::read_from(buf)? } decimals: Serializable::read_from(buf)?,
}, },
"minecraft:int_range" => CommandProperty::IntRange, "minecraft:int_range" => CommandProperty::IntRange,
"minecraft:float_range" => CommandProperty::FloatRange, "minecraft:float_range" => CommandProperty::FloatRange,
@ -2956,12 +2976,18 @@ impl Serializable for CommandNode {
None None
}; };
Ok(CommandNode { flags, children, redirect_node, name, parser, properties, suggestions_type }) Ok(CommandNode {
flags,
children,
redirect_node,
name,
parser,
properties,
suggestions_type,
})
} }
fn write_to<W: io::Write>(&self, _: &mut W) -> Result<(), Error> { fn write_to<W: io::Write>(&self, _: &mut W) -> Result<(), Error> {
unimplemented!() unimplemented!()
} }
} }

View File

@ -1,22 +1,22 @@
use super::*; use super::*;
mod v1_15_1;
mod v1_14_4;
mod v1_14_3;
mod v1_14_2;
mod v1_14_1;
mod v1_14;
mod v19w02a;
mod v18w50a;
mod v1_13_2;
mod v1_12_2;
mod v1_11_2;
mod v1_10_2;
mod v1_9_2;
mod v1_9;
mod v15w39c; mod v15w39c;
mod v1_8_9; mod v18w50a;
mod v19w02a;
mod v1_10_2;
mod v1_11_2;
mod v1_12_2;
mod v1_13_2;
mod v1_14;
mod v1_14_1;
mod v1_14_2;
mod v1_14_3;
mod v1_14_4;
mod v1_15_1;
mod v1_7_10; mod v1_7_10;
mod v1_8_9;
mod v1_9;
mod v1_9_2;
// https://wiki.vg/Protocol_History // https://wiki.vg/Protocol_History
// https://wiki.vg/Protocol_version_numbers#Versions_after_the_Netty_rewrite // https://wiki.vg/Protocol_version_numbers#Versions_after_the_Netty_rewrite
@ -52,7 +52,13 @@ pub fn protocol_name_to_protocol_version(s: String) -> i32 {
} }
} }
pub fn translate_internal_packet_id_for_version(version: i32, state: State, dir: Direction, id: i32, to_internal: bool) -> i32 { pub fn translate_internal_packet_id_for_version(
version: i32,
state: State,
dir: Direction,
id: i32,
to_internal: bool,
) -> i32 {
match version { match version {
575 => v1_15_1::translate_internal_packet_id(state, dir, id, to_internal), 575 => v1_15_1::translate_internal_packet_id(state, dir, id, to_internal),
498 => v1_14_4::translate_internal_packet_id(state, dir, id, to_internal), 498 => v1_14_4::translate_internal_packet_id(state, dir, id, to_internal),

View File

@ -137,5 +137,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -168,5 +168,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -170,5 +170,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -141,5 +141,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -141,5 +141,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -148,5 +148,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -165,5 +165,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -175,5 +175,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -175,5 +175,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -175,5 +175,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -175,5 +175,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -176,5 +176,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -176,5 +176,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -124,5 +124,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -135,5 +135,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -142,5 +142,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -142,5 +142,3 @@ protocol_packet_ids!(
} }
} }
); );

View File

@ -61,7 +61,7 @@ impl Map {
} }
pub fn from_raw(bits: Vec<u64>, size: usize) -> Map { pub fn from_raw(bits: Vec<u64>, size: usize) -> Map {
Map { Map {
length: (bits.len()*64 + (size-1)) / size, length: (bits.len() * 64 + (size - 1)) / size,
bit_size: size, bit_size: size,
bits, bits,
} }

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
pub mod set;
pub mod map; pub mod map;
pub mod set;
pub use self::set::Set;
pub use self::map::Map; pub use self::map::Map;
pub use self::set::Set;

View File

@ -34,7 +34,9 @@ fn test_set() {
impl Set { impl Set {
pub fn new(size: usize) -> Set { pub fn new(size: usize) -> Set {
Set { data: vec![0; (size + 63) / 64] } Set {
data: vec![0; (size + 63) / 64],
}
} }
pub fn resize(&mut self, new_size: usize) { pub fn resize(&mut self, new_size: usize) {

View File

@ -1,5 +1,3 @@
use std::hash::Hasher; use std::hash::Hasher;
pub struct FNVHash(u64); pub struct FNVHash(u64);

View File

@ -12,24 +12,24 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::collections::HashMap;
use std::marker::PhantomData;
use std::io;
use std::fmt;
use crate::protocol;
use crate::protocol::Serializable;
use crate::protocol::LenPrefixed;
use crate::format; use crate::format;
use crate::item; use crate::item;
use crate::shared::Position;
use crate::nbt; use crate::nbt;
use crate::protocol;
use crate::protocol::LenPrefixed;
use crate::protocol::Serializable;
use crate::shared::Position;
use std::collections::HashMap;
use std::fmt;
use std::io;
use std::marker::PhantomData;
pub struct MetadataKey<T: MetaValue> { pub struct MetadataKey<T: MetaValue> {
index: i32, index: i32,
ty: PhantomData<T>, ty: PhantomData<T>,
} }
impl <T: MetaValue> MetadataKey<T> { impl<T: MetaValue> MetadataKey<T> {
#[allow(dead_code)] #[allow(dead_code)]
fn new(index: i32) -> MetadataKey<T> { fn new(index: i32) -> MetadataKey<T> {
MetadataKey { MetadataKey {
@ -45,7 +45,9 @@ pub struct Metadata {
impl Metadata { impl Metadata {
pub fn new() -> Metadata { pub fn new() -> Metadata {
Metadata { map: HashMap::new() } Metadata {
map: HashMap::new(),
}
} }
pub fn get<T: MetaValue>(&self, key: &MetadataKey<T>) -> Option<&T> { pub fn get<T: MetaValue>(&self, key: &MetadataKey<T>) -> Option<&T> {
@ -77,14 +79,22 @@ impl Metadata {
3 => m.put_raw(index, f32::read_from(buf)?), 3 => m.put_raw(index, f32::read_from(buf)?),
4 => m.put_raw(index, String::read_from(buf)?), 4 => m.put_raw(index, String::read_from(buf)?),
5 => m.put_raw(index, Option::<item::Stack>::read_from(buf)?), 5 => m.put_raw(index, Option::<item::Stack>::read_from(buf)?),
6 => m.put_raw(index, 6 => m.put_raw(
[i32::read_from(buf)?, index,
i32::read_from(buf)?, [
i32::read_from(buf)?]), i32::read_from(buf)?,
7 => m.put_raw(index, i32::read_from(buf)?,
[f32::read_from(buf)?, i32::read_from(buf)?,
f32::read_from(buf)?, ],
f32::read_from(buf)?]), ),
7 => m.put_raw(
index,
[
f32::read_from(buf)?,
f32::read_from(buf)?,
f32::read_from(buf)?,
],
),
_ => return Err(protocol::Error::Err("unknown metadata type".to_owned())), _ => return Err(protocol::Error::Err("unknown metadata type".to_owned())),
} }
} }
@ -100,8 +110,7 @@ impl Metadata {
let ty_index: u8 = *k as u8; let ty_index: u8 = *k as u8;
const TYPE_SHIFT: usize = 5; const TYPE_SHIFT: usize = 5;
match *v match *v {
{
Value::Byte(ref val) => { Value::Byte(ref val) => {
u8::write_to(&(ty_index | (0 << TYPE_SHIFT)), buf)?; u8::write_to(&(ty_index | (0 << TYPE_SHIFT)), buf)?;
val.write_to(buf)?; val.write_to(buf)?;
@ -165,10 +174,14 @@ impl Metadata {
4 => m.put_raw(index, format::Component::read_from(buf)?), 4 => m.put_raw(index, format::Component::read_from(buf)?),
5 => m.put_raw(index, Option::<item::Stack>::read_from(buf)?), 5 => m.put_raw(index, Option::<item::Stack>::read_from(buf)?),
6 => m.put_raw(index, bool::read_from(buf)?), 6 => m.put_raw(index, bool::read_from(buf)?),
7 => m.put_raw(index, 7 => m.put_raw(
[f32::read_from(buf)?, index,
f32::read_from(buf)?, [
f32::read_from(buf)?]), f32::read_from(buf)?,
f32::read_from(buf)?,
f32::read_from(buf)?,
],
),
8 => m.put_raw(index, Position::read_from(buf)?), 8 => m.put_raw(index, Position::read_from(buf)?),
9 => { 9 => {
if bool::read_from(buf)? { if bool::read_from(buf)? {
@ -287,13 +300,20 @@ impl Metadata {
2 => m.put_raw(index, f32::read_from(buf)?), 2 => m.put_raw(index, f32::read_from(buf)?),
3 => m.put_raw(index, String::read_from(buf)?), 3 => m.put_raw(index, String::read_from(buf)?),
4 => m.put_raw(index, format::Component::read_from(buf)?), 4 => m.put_raw(index, format::Component::read_from(buf)?),
5 => m.put_raw(index, LenPrefixed::<bool, format::Component>::read_from(buf)?), 5 => m.put_raw(
index,
LenPrefixed::<bool, format::Component>::read_from(buf)?,
),
6 => m.put_raw(index, Option::<item::Stack>::read_from(buf)?), 6 => m.put_raw(index, Option::<item::Stack>::read_from(buf)?),
7 => m.put_raw(index, bool::read_from(buf)?), 7 => m.put_raw(index, bool::read_from(buf)?),
8 => m.put_raw(index, 8 => m.put_raw(
[f32::read_from(buf)?, index,
f32::read_from(buf)?, [
f32::read_from(buf)?]), f32::read_from(buf)?,
f32::read_from(buf)?,
f32::read_from(buf)?,
],
),
9 => m.put_raw(index, Position::read_from(buf)?), 9 => m.put_raw(index, Position::read_from(buf)?),
10 => { 10 => {
if bool::read_from(buf)? { if bool::read_from(buf)? {
@ -328,7 +348,7 @@ impl Metadata {
} else { } else {
m.put_raw::<Option<protocol::VarInt>>(index, None); m.put_raw::<Option<protocol::VarInt>>(index, None);
} }
}, }
18 => m.put_raw(index, PoseData::read_from(buf)?), 18 => m.put_raw(index, PoseData::read_from(buf)?),
_ => return Err(protocol::Error::Err("unknown metadata type".to_owned())), _ => return Err(protocol::Error::Err("unknown metadata type".to_owned())),
} }
@ -427,8 +447,6 @@ impl Metadata {
u8::write_to(&0xFF, buf)?; u8::write_to(&0xFF, buf)?;
Ok(()) Ok(())
} }
} }
impl Serializable for Metadata { impl Serializable for Metadata {
@ -571,7 +589,7 @@ impl Serializable for ParticleData {
1 => ParticleData::AngryVillager, 1 => ParticleData::AngryVillager,
2 => ParticleData::Barrier, 2 => ParticleData::Barrier,
3 => ParticleData::Block { 3 => ParticleData::Block {
block_state: Serializable::read_from(buf)? block_state: Serializable::read_from(buf)?,
}, },
4 => ParticleData::Bubble, 4 => ParticleData::Bubble,
5 => ParticleData::Cloud, 5 => ParticleData::Cloud,
@ -649,7 +667,11 @@ impl Serializable for VillagerData {
let villager_type = protocol::VarInt::read_from(buf)?; let villager_type = protocol::VarInt::read_from(buf)?;
let profession = protocol::VarInt::read_from(buf)?; let profession = protocol::VarInt::read_from(buf)?;
let level = protocol::VarInt::read_from(buf)?; let level = protocol::VarInt::read_from(buf)?;
Ok(VillagerData { villager_type, profession, level }) Ok(VillagerData {
villager_type,
profession,
level,
})
} }
fn write_to<W: io::Write>(&self, _buf: &mut W) -> Result<(), protocol::Error> { fn write_to<W: io::Write>(&self, _buf: &mut W) -> Result<(), protocol::Error> {
@ -688,8 +710,6 @@ impl Serializable for PoseData {
} }
} }
pub trait MetaValue { pub trait MetaValue {
fn unwrap(_: &Value) -> &Self; fn unwrap(_: &Value) -> &Self;
fn wrap(self) -> Value; fn wrap(self) -> Value;
@ -779,7 +799,6 @@ impl MetaValue for LenPrefixed<bool, format::Component> {
} }
} }
impl MetaValue for Option<item::Stack> { impl MetaValue for Option<item::Stack> {
fn unwrap(value: &Value) -> &Self { fn unwrap(value: &Value) -> &Self {
match *value { match *value {
@ -936,14 +955,12 @@ impl MetaValue for PoseData {
} }
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use std::marker::PhantomData; use std::marker::PhantomData;
const TEST: MetadataKey<String> = const TEST: MetadataKey<String> = MetadataKey {
MetadataKey {
index: 0, index: 0,
ty: PhantomData, ty: PhantomData,
}; };

View File

@ -16,8 +16,8 @@ mod metadata;
pub use self::metadata::*; pub use self::metadata::*;
pub mod bit; pub mod bit;
pub mod nibble;
pub mod hash; pub mod hash;
pub mod nibble;
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub enum Gamemode { pub enum Gamemode {

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
pub struct Array { pub struct Array {
pub data: Vec<u8>, pub data: Vec<u8>,
} }
@ -25,8 +24,8 @@ impl Array {
} }
pub fn get(&self, idx: usize) -> u8 { pub fn get(&self, idx: usize) -> u8 {
let val = self.data[idx>>1]; let val = self.data[idx >> 1];
if idx&1 == 0 { if idx & 1 == 0 {
val & 0xF val & 0xF
} else { } else {
val >> 4 val >> 4
@ -36,7 +35,7 @@ impl Array {
pub fn set(&mut self, idx: usize, val: u8) { pub fn set(&mut self, idx: usize, val: u8) {
let i = idx >> 1; let i = idx >> 1;
let old = self.data[i]; let old = self.data[i];
if idx&1 == 0 { if idx & 1 == 0 {
self.data[i] = (old & 0xF0) | (val & 0xF); self.data[i] = (old & 0xF0) | (val & 0xF);
} else { } else {
self.data[i] = (old & 0x0F) | ((val & 0xF) << 4); self.data[i] = (old & 0x0F) | ((val & 0xF) << 4);

View File

@ -1,8 +1,8 @@
use std::env; use std::env;
use std::fs; use std::fs;
use std::path::{Path, PathBuf};
use std::io::BufWriter; use std::io::BufWriter;
use std::io::Write; use std::io::Write;
use std::path::{Path, PathBuf};
fn main() { fn main() {
let out_dir = env::var("OUT_DIR").unwrap(); let out_dir = env::var("OUT_DIR").unwrap();
@ -13,7 +13,11 @@ fn main() {
build_map(&mut out, &base); build_map(&mut out, &base);
let mut file = BufWriter::new(fs::File::create(&dest.join("resources.rs")).unwrap()); let mut file = BufWriter::new(fs::File::create(&dest.join("resources.rs")).unwrap());
write!(file, "pub fn get_file(name: &str) -> Option<&'static [u8]> {{\n").unwrap(); write!(
file,
"pub fn get_file(name: &str) -> Option<&'static [u8]> {{\n"
)
.unwrap();
write!(file, " match name {{\n").unwrap(); write!(file, " match name {{\n").unwrap();
for path in &out { for path in &out {
let mut absolute_path = std::env::current_dir().unwrap(); let mut absolute_path = std::env::current_dir().unwrap();
@ -22,10 +26,14 @@ fn main() {
let absolute = absolute_path.to_str().unwrap().replace("\\", "/"); let absolute = absolute_path.to_str().unwrap().replace("\\", "/");
let relative = path.to_str().unwrap().replace("\\", "/"); let relative = path.to_str().unwrap().replace("\\", "/");
write!(file, " {:?} => Some(include_bytes!(\"{}\")),\n", relative, absolute).unwrap(); write!(
file,
" {:?} => Some(include_bytes!(\"{}\")),\n",
relative, absolute
)
.unwrap();
} }
write!(file, " _ => None\n }}\n}}\n").unwrap(); write!(file, " _ => None\n }}\n}}\n").unwrap();
} }
fn build_map(out: &mut Vec<PathBuf>, path: &Path) { fn build_map(out: &mut Vec<PathBuf>, path: &Path) {

View File

@ -1,2 +1 @@
include!(concat!(env!("OUT_DIR"), "/resources.rs")); include!(concat!(env!("OUT_DIR"), "/resources.rs"));

View File

@ -1,10 +1,9 @@
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Axis { pub enum Axis {
Y, Y,
Z, Z,
X, X,
None None,
} }
impl Axis { impl Axis {

View File

@ -1,4 +1,3 @@
use crate::axis::Axis; use crate::axis::Axis;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -15,9 +14,12 @@ pub enum Direction {
impl Direction { impl Direction {
pub fn all() -> Vec<Direction> { pub fn all() -> Vec<Direction> {
vec![ vec![
Direction::Down, Direction::Up, Direction::Down,
Direction::North, Direction::South, Direction::Up,
Direction::West, Direction::East, Direction::North,
Direction::South,
Direction::West,
Direction::East,
] ]
} }
@ -117,7 +119,6 @@ impl Direction {
} }
} }
pub fn horizontal_index(&self) -> usize { pub fn horizontal_index(&self) -> usize {
match *self { match *self {
Direction::North => 2, Direction::North => 2,

View File

@ -1,4 +1,3 @@
pub mod axis; pub mod axis;
pub use self::axis::Axis; pub use self::axis::Axis;

View File

@ -1,6 +1,5 @@
use std::fmt;
use crate::direction::Direction; use crate::direction::Direction;
use std::fmt;
use std::ops; use std::ops;
#[derive(Clone, Copy, PartialEq, Eq, Hash)] #[derive(Clone, Copy, PartialEq, Eq, Hash)]
@ -12,11 +11,7 @@ pub struct Position {
impl Position { impl Position {
pub fn new(x: i32, y: i32, z: i32) -> Position { pub fn new(x: i32, y: i32, z: i32) -> Position {
Position { Position { x, y, z }
x,
y,
z,
}
} }
pub fn shift(self, dir: Direction) -> Position { pub fn shift(self, dir: Direction) -> Position {

View File

@ -1,16 +1,15 @@
use crate::model;
use std::thread;
use std::sync::mpsc;
use std::sync::{Arc, RwLock};
use crate::world;
use crate::world::block;
use crate::render; use crate::render;
use crate::resources; use crate::resources;
use crate::model;
use crate::types::bit::Set;
use crate::shared::Direction; use crate::shared::Direction;
use rand::{self, SeedableRng, Rng}; use crate::types::bit::Set;
use crate::world;
use crate::world::block;
use rand::{self, Rng, SeedableRng};
use rand_pcg; use rand_pcg;
use std::sync::mpsc;
use std::sync::{Arc, RwLock};
use std::thread;
const NUM_WORKERS: usize = 8; const NUM_WORKERS: usize = 8;
@ -24,18 +23,27 @@ pub struct ChunkBuilder {
} }
impl ChunkBuilder { impl ChunkBuilder {
pub fn new(resources: Arc<RwLock<resources::Manager>>, textures: Arc<RwLock<render::TextureManager>>) -> ChunkBuilder { pub fn new(
let models = Arc::new(RwLock::new(model::Factory::new(resources.clone(), textures))); resources: Arc<RwLock<resources::Manager>>,
textures: Arc<RwLock<render::TextureManager>>,
) -> ChunkBuilder {
let models = Arc::new(RwLock::new(model::Factory::new(
resources.clone(),
textures,
)));
let mut threads = vec![]; let mut threads = vec![];
let mut free = vec![]; let mut free = vec![];
let (built_send, built_recv) = mpsc::channel(); let (built_send, built_recv) = mpsc::channel();
for i in 0 .. NUM_WORKERS { for i in 0..NUM_WORKERS {
let built_send = built_send.clone(); let built_send = built_send.clone();
let (work_send, work_recv) = mpsc::channel(); let (work_send, work_recv) = mpsc::channel();
let models = models.clone(); let models = models.clone();
let id = i; let id = i;
threads.push((work_send, thread::spawn(move || build_func(id, models, work_recv, built_send)))); threads.push((
work_send,
thread::spawn(move || build_func(id, models, work_recv, built_send)),
));
free.push((i, vec![], vec![])); free.push((i, vec![], vec![]));
} }
ChunkBuilder { ChunkBuilder {
@ -47,7 +55,12 @@ impl ChunkBuilder {
} }
} }
pub fn tick(&mut self, world: &mut world::World, renderer: &mut render::Renderer, version: usize) { pub fn tick(
&mut self,
world: &mut world::World,
renderer: &mut render::Renderer,
version: usize,
) {
{ {
if version != self.resource_version { if version != self.resource_version {
self.resource_version = version; self.resource_version = version;
@ -58,35 +71,50 @@ impl ChunkBuilder {
while let Ok((id, mut val)) = self.built_recv.try_recv() { while let Ok((id, mut val)) = self.built_recv.try_recv() {
world.reset_building_flag(val.position); world.reset_building_flag(val.position);
if let Some(sec) = world.get_section_mut(val.position.0, val.position.1, val.position.2) { if let Some(sec) = world.get_section_mut(val.position.0, val.position.1, val.position.2)
{
sec.cull_info = val.cull_info; sec.cull_info = val.cull_info;
renderer.update_chunk_solid(&mut sec.render_buffer, &val.solid_buffer, val.solid_count); renderer.update_chunk_solid(
renderer.update_chunk_trans(&mut sec.render_buffer, &val.trans_buffer, val.trans_count); &mut sec.render_buffer,
&val.solid_buffer,
val.solid_count,
);
renderer.update_chunk_trans(
&mut sec.render_buffer,
&val.trans_buffer,
val.trans_count,
);
} }
val.solid_buffer.clear(); val.solid_buffer.clear();
val.trans_buffer.clear(); val.trans_buffer.clear();
self.free_builders.push((id, val.solid_buffer, val.trans_buffer)); self.free_builders
.push((id, val.solid_buffer, val.trans_buffer));
} }
if self.free_builders.is_empty() { if self.free_builders.is_empty() {
return; return;
} }
let dirty_sections = world.get_render_list().iter() let dirty_sections = world
.map(|v| v.0) .get_render_list()
.filter(|v| world.is_section_dirty(*v)) .iter()
.collect::<Vec<_>>(); .map(|v| v.0)
for (x,y, z) in dirty_sections { .filter(|v| world.is_section_dirty(*v))
.collect::<Vec<_>>();
for (x, y, z) in dirty_sections {
let t_id = self.free_builders.pop().unwrap(); let t_id = self.free_builders.pop().unwrap();
world.set_building_flag((x, y, z)); world.set_building_flag((x, y, z));
let (cx, cy, cz) = (x << 4, y << 4, z << 4); let (cx, cy, cz) = (x << 4, y << 4, z << 4);
let mut snapshot = world.capture_snapshot(cx - 2, cy - 2, cz - 2, 20, 20, 20); let mut snapshot = world.capture_snapshot(cx - 2, cy - 2, cz - 2, 20, 20, 20);
snapshot.make_relative(-2, -2, -2); snapshot.make_relative(-2, -2, -2);
self.threads[t_id.0].0.send(BuildReq { self.threads[t_id.0]
snapshot, .0
position: (x, y, z), .send(BuildReq {
solid_buffer: t_id.1, snapshot,
trans_buffer: t_id.2, position: (x, y, z),
}).unwrap(); solid_buffer: t_id.1,
trans_buffer: t_id.2,
})
.unwrap();
if self.free_builders.is_empty() { if self.free_builders.is_empty() {
return; return;
} }
@ -110,7 +138,12 @@ struct BuildReply {
cull_info: CullInfo, cull_info: CullInfo,
} }
fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::Receiver<BuildReq>, built_send: mpsc::Sender<(usize, BuildReply)>) { fn build_func(
id: usize,
models: Arc<RwLock<model::Factory>>,
work_recv: mpsc::Receiver<BuildReq>,
built_send: mpsc::Sender<(usize, BuildReply)>,
) {
loop { loop {
let BuildReq { let BuildReq {
snapshot, snapshot,
@ -127,17 +160,14 @@ fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::R
(((position.0 as u32) >> 8) & 0xff) as u8, (((position.0 as u32) >> 8) & 0xff) as u8,
(((position.0 as u32) >> 16) & 0xff) as u8, (((position.0 as u32) >> 16) & 0xff) as u8,
((position.0 as u32) >> 24) as u8, ((position.0 as u32) >> 24) as u8,
((position.1 as u32) & 0xff) as u8, ((position.1 as u32) & 0xff) as u8,
(((position.1 as u32) >> 8) & 0xff) as u8, (((position.1 as u32) >> 8) & 0xff) as u8,
(((position.1 as u32) >> 16) & 0xff) as u8, (((position.1 as u32) >> 16) & 0xff) as u8,
((position.1 as u32) >> 24) as u8, ((position.1 as u32) >> 24) as u8,
((position.2 as u32) & 0xff) as u8, ((position.2 as u32) & 0xff) as u8,
(((position.2 as u32) >> 8) & 0xff) as u8, (((position.2 as u32) >> 8) & 0xff) as u8,
(((position.2 as u32) >> 16) & 0xff) as u8, (((position.2 as u32) >> 16) & 0xff) as u8,
((position.2 as u32) >> 24) as u8, ((position.2 as u32) >> 24) as u8,
(((position.0 as u32 ^ position.2 as u32) | 1) & 0xff) as u8, (((position.0 as u32 ^ position.2 as u32) | 1) & 0xff) as u8,
((((position.0 as u32 ^ position.2 as u32) | 1) >> 8) & 0xff) as u8, ((((position.0 as u32 ^ position.2 as u32) | 1) >> 8) & 0xff) as u8,
((((position.0 as u32 ^ position.2 as u32) | 1) >> 16) & 0xff) as u8, ((((position.0 as u32 ^ position.2 as u32) | 1) >> 16) & 0xff) as u8,
@ -147,9 +177,9 @@ fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::R
let mut solid_count = 0; let mut solid_count = 0;
let mut trans_count = 0; let mut trans_count = 0;
for y in 0 .. 16 { for y in 0..16 {
for x in 0 .. 16 { for x in 0..16 {
for z in 0 .. 16 { for z in 0..16 {
let block = snapshot.get_block(x, y, z); let block = snapshot.get_block(x, y, z);
let mat = block.get_material(); let mat = block.get_material();
if !mat.renderable { if !mat.renderable {
@ -161,26 +191,56 @@ fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::R
} }
match block { match block {
block::Block::Water{..} | block::Block::FlowingWater{..} => { block::Block::Water { .. } | block::Block::FlowingWater { .. } => {
let tex = models.read().unwrap().textures.clone(); let tex = models.read().unwrap().textures.clone();
trans_count += model::liquid::render_liquid(tex, false, &snapshot, x, y, z, &mut trans_buffer); trans_count += model::liquid::render_liquid(
tex,
false,
&snapshot,
x,
y,
z,
&mut trans_buffer,
);
continue; continue;
}, }
block::Block::Lava{..} | block::Block::FlowingLava{..} => { block::Block::Lava { .. } | block::Block::FlowingLava { .. } => {
let tex = models.read().unwrap().textures.clone(); let tex = models.read().unwrap().textures.clone();
solid_count += model::liquid::render_liquid(tex, true, &snapshot, x, y, z, &mut solid_buffer); solid_count += model::liquid::render_liquid(
tex,
true,
&snapshot,
x,
y,
z,
&mut solid_buffer,
);
continue; continue;
}, }
_ => {}, _ => {}
} }
if mat.transparent { if mat.transparent {
trans_count += model::Factory::get_state_model( trans_count += model::Factory::get_state_model(
&models, block, &mut rng, &snapshot, x, y, z, &mut trans_buffer &models,
block,
&mut rng,
&snapshot,
x,
y,
z,
&mut trans_buffer,
); );
} else { } else {
solid_count += model::Factory::get_state_model( solid_count += model::Factory::get_state_model(
&models, block, &mut rng, &snapshot, x, y, z, &mut solid_buffer &models,
block,
&mut rng,
&snapshot,
x,
y,
z,
&mut solid_buffer,
); );
} }
} }
@ -189,14 +249,19 @@ fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::R
let cull_info = build_cull_info(&snapshot); let cull_info = build_cull_info(&snapshot);
built_send.send((id, BuildReply { built_send
position, .send((
solid_buffer, id,
solid_count, BuildReply {
trans_buffer, position,
trans_count, solid_buffer,
cull_info, solid_count,
})).unwrap(); trans_buffer,
trans_count,
cull_info,
},
))
.unwrap();
} }
} }
@ -204,9 +269,9 @@ fn build_cull_info(snapshot: &world::Snapshot) -> CullInfo {
let mut visited = Set::new(16 * 16 * 16); let mut visited = Set::new(16 * 16 * 16);
let mut info = CullInfo::new(); let mut info = CullInfo::new();
for y in 0 .. 16 { for y in 0..16 {
for z in 0 .. 16 { for z in 0..16 {
for x in 0 .. 16 { for x in 0..16 {
if visited.get(x | (z << 4) | (y << 8)) { if visited.get(x | (z << 4) | (y << 8)) {
continue; continue;
} }
@ -246,7 +311,11 @@ fn flood_fill(snapshot: &world::Snapshot, visited: &mut Set, x: i32, y: i32, z:
} }
visited.set(idx, true); visited.set(idx, true);
if snapshot.get_block(x, y, z).get_material().should_cull_against { if snapshot
.get_block(x, y, z)
.get_material()
.should_cull_against
{
continue; continue;
} }
@ -268,7 +337,7 @@ fn flood_fill(snapshot: &world::Snapshot, visited: &mut Set, x: i32, y: i32, z:
for d in Direction::all() { for d in Direction::all() {
let (ox, oy, oz) = d.get_offset(); let (ox, oy, oz) = d.get_offset();
next_position.push_back((x+ox, y+oy, z+oz)); next_position.push_back((x + ox, y + oy, z + oz));
} }
} }
touched touched
@ -278,7 +347,9 @@ fn flood_fill(snapshot: &world::Snapshot, visited: &mut Set, x: i32, y: i32, z:
pub struct CullInfo(u64); pub struct CullInfo(u64);
impl CullInfo { impl CullInfo {
pub fn new() -> CullInfo { Default::default() } pub fn new() -> CullInfo {
Default::default()
}
pub fn all_vis() -> CullInfo { pub fn all_vis() -> CullInfo {
CullInfo(0xFFFFFFFFFFFFFFFF) CullInfo(0xFFFFFFFFFFFFFFFF)

View File

@ -12,18 +12,18 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::marker::PhantomData; use log;
use std::collections::HashMap;
use std::any::Any; use std::any::Any;
use std::cell::{RefCell, Ref}; use std::cell::{Ref, RefCell};
use std::collections::HashMap;
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::marker::PhantomData;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std_or_web::fs; use std_or_web::fs;
use std::io::{BufWriter, Write, BufRead, BufReader};
use log;
use crate::ui; use crate::format::{Color, Component, TextComponent};
use crate::render; use crate::render;
use crate::format::{Component, TextComponent, Color}; use crate::ui;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use web_sys; use web_sys;
@ -126,21 +126,26 @@ pub struct Vars {
} }
impl Vars { impl Vars {
pub fn new() -> Vars { Default::default() } pub fn new() -> Vars {
Default::default()
}
pub fn register<T: Sized + Any>(&mut self, var: CVar<T>) pub fn register<T: Sized + Any>(&mut self, var: CVar<T>)
where CVar<T>: Var where
CVar<T>: Var,
{ {
if self.vars.contains_key(var.name) { if self.vars.contains_key(var.name) {
panic!("Key registered twice {}", var.name); panic!("Key registered twice {}", var.name);
} }
self.names.insert(var.name.to_owned(), var.name); self.names.insert(var.name.to_owned(), var.name);
self.var_values.insert(var.name, RefCell::new(Box::new((var.default)()))); self.var_values
.insert(var.name, RefCell::new(Box::new((var.default)())));
self.vars.insert(var.name, Box::new(var)); self.vars.insert(var.name, Box::new(var));
} }
pub fn get<T: Sized + Any>(&self, var: CVar<T>) -> Ref<T> pub fn get<T: Sized + Any>(&self, var: CVar<T>) -> Ref<T>
where CVar<T>: Var where
CVar<T>: Var,
{ {
// Should never fail // Should never fail
let var = self.var_values.get(var.name).unwrap().borrow(); let var = self.var_values.get(var.name).unwrap().borrow();
@ -148,7 +153,8 @@ impl Vars {
} }
pub fn set<T: Sized + Any>(&self, var: CVar<T>, val: T) pub fn set<T: Sized + Any>(&self, var: CVar<T>, val: T)
where CVar<T>: Var where
CVar<T>: Var,
{ {
*self.var_values.get(var.name).unwrap().borrow_mut() = Box::new(val); *self.var_values.get(var.name).unwrap().borrow_mut() = Box::new(val);
self.save_config(); self.save_config();
@ -162,7 +168,10 @@ impl Vars {
if line.starts_with('#') || line.is_empty() { if line.starts_with('#') || line.is_empty() {
continue; continue;
} }
let parts = line.splitn(2, ' ').map(|v| v.to_owned()).collect::<Vec<String>>(); let parts = line
.splitn(2, ' ')
.map(|v| v.to_owned())
.collect::<Vec<String>>();
let (name, arg) = (&parts[0], &parts[1]); let (name, arg) = (&parts[0], &parts[1]);
if let Some(var_name) = self.names.get(name) { if let Some(var_name) = self.names.get(name) {
let var = self.vars.get(var_name).unwrap(); let var = self.vars.get(var_name).unwrap();
@ -184,11 +193,13 @@ impl Vars {
for line in var.description().lines() { for line in var.description().lines() {
write!(file, "# {}\n", line).unwrap(); write!(file, "# {}\n", line).unwrap();
} }
write!(file, write!(
"{} {}\n\n", file,
name, "{} {}\n\n",
var.serialize(&self.var_values.get(name).unwrap().borrow())) name,
.unwrap(); var.serialize(&self.var_values.get(name).unwrap().borrow())
)
.unwrap();
} }
} }
} }
@ -227,11 +238,13 @@ impl Console {
self.active = !self.active; self.active = !self.active;
} }
pub fn tick(&mut self, pub fn tick(
ui_container: &mut ui::Container, &mut self,
renderer: &render::Renderer, ui_container: &mut ui::Container,
delta: f64, renderer: &render::Renderer,
width: f64) { delta: f64,
width: f64,
) {
if !self.active && self.position <= -220.0 { if !self.active && self.position <= -220.0 {
self.elements = None; self.elements = None;
return; return;
@ -281,12 +294,14 @@ impl Console {
break; break;
} }
let (_, height) = ui::Formatted::compute_size(renderer, line, w - 10.0); let (_, height) = ui::Formatted::compute_size(renderer, line, w - 10.0);
elements.lines.push(ui::FormattedBuilder::new() elements.lines.push(
.text(line.clone()) ui::FormattedBuilder::new()
.position(5.0, 5.0 + offset) .text(line.clone())
.max_width(w - 10.0) .position(5.0, 5.0 + offset)
.alignment(ui::VAttach::Bottom, ui::HAttach::Left) .max_width(w - 10.0)
.create(&mut *background)); .alignment(ui::VAttach::Bottom, ui::HAttach::Left)
.create(&mut *background),
);
offset += height; offset += height;
} }
} }
@ -304,11 +319,16 @@ impl Console {
file = &file[pos + 4..]; file = &file[pos + 4..];
} }
println_level(record.level(), format!("[{}:{}][{}] {}", println_level(
file, record.level(),
record.line().unwrap_or(0), format!(
record.level(), "[{}:{}][{}] {}",
record.args())); file,
record.line().unwrap_or(0),
record.level(),
record.args()
),
);
self.history.remove(0); self.history.remove(0);
let mut msg = TextComponent::new(""); let mut msg = TextComponent::new("");
msg.modifier.extra = Some(vec![ msg.modifier.extra = Some(vec![
@ -338,7 +358,7 @@ impl Console {
Component::Text(msg) Component::Text(msg)
}, },
Component::Text(TextComponent::new("] ")), Component::Text(TextComponent::new("] ")),
Component::Text(TextComponent::new(&format!("{}", record.args()))) Component::Text(TextComponent::new(&format!("{}", record.args()))),
]); ]);
self.history.push(Component::Text(msg)); self.history.push(Component::Text(msg));
self.dirty = true; self.dirty = true;
@ -366,8 +386,7 @@ impl log::Log for ConsoleProxy {
} }
} }
fn flush(&self) { fn flush(&self) {}
}
} }
unsafe impl Send for ConsoleProxy {} unsafe impl Send for ConsoleProxy {}

View File

@ -13,17 +13,17 @@
// limitations under the License. // limitations under the License.
use crate::types::bit::Set as BSet; use crate::types::bit::Set as BSet;
use std::collections::{HashMap, HashSet};
use std::hash::BuildHasherDefault;
use crate::types::hash::FNVHash; use crate::types::hash::FNVHash;
use std::any::{Any, TypeId}; use std::any::{Any, TypeId};
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::hash::BuildHasherDefault;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use crate::world;
use crate::render; use crate::render;
use crate::world;
/// Used to reference an entity. /// Used to reference an entity.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@ -38,7 +38,7 @@ pub struct Key<T> {
id: usize, id: usize,
_t: PhantomData<T>, _t: PhantomData<T>,
} }
impl <T> Clone for Key<T> { impl<T> Clone for Key<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Key { Key {
id: self.id, id: self.id,
@ -46,7 +46,7 @@ impl <T> Clone for Key<T> {
} }
} }
} }
impl <T> Copy for Key<T> {} impl<T> Copy for Key<T> {}
/// Used to search for entities with the requested components. /// Used to search for entities with the requested components.
pub struct Filter { pub struct Filter {
@ -56,9 +56,7 @@ pub struct Filter {
impl Filter { impl Filter {
/// Creates an empty filter which matches everything /// Creates an empty filter which matches everything
pub fn new() -> Filter { pub fn new() -> Filter {
Filter { Filter { bits: BSet::new(0) }
bits: BSet::new(0),
}
} }
/// Adds the component to the filter. /// Adds the component to the filter.
@ -74,12 +72,29 @@ impl Filter {
/// A system processes entities /// A system processes entities
pub trait System { pub trait System {
fn filter(&self) -> &Filter; fn filter(&self) -> &Filter;
fn update(&mut self, m: &mut Manager, world: &mut world::World, renderer: &mut render::Renderer); fn update(
&mut self,
m: &mut Manager,
world: &mut world::World,
renderer: &mut render::Renderer,
);
fn entity_added(&mut self, _m: &mut Manager, _e: Entity, _world: &mut world::World, _renderer: &mut render::Renderer) { fn entity_added(
&mut self,
_m: &mut Manager,
_e: Entity,
_world: &mut world::World,
_renderer: &mut render::Renderer,
) {
} }
fn entity_removed(&mut self, _m: &mut Manager, _e: Entity, _world: &mut world::World, _renderer: &mut render::Renderer) { fn entity_removed(
&mut self,
_m: &mut Manager,
_e: Entity,
_world: &mut world::World,
_renderer: &mut render::Renderer,
) {
} }
} }
@ -110,11 +125,14 @@ impl Manager {
pub fn new() -> Manager { pub fn new() -> Manager {
Manager { Manager {
num_components: 0, num_components: 0,
entities: vec![(Some(EntityState { entities: vec![(
last_components: BSet::new(0), Some(EntityState {
components: BSet::new(0), last_components: BSet::new(0),
removed: false, components: BSet::new(0),
}), 0)], // Has the world entity pre-defined removed: false,
}),
0,
)], // Has the world entity pre-defined
free_entities: vec![], free_entities: vec![],
components: vec![], components: vec![],
@ -166,7 +184,11 @@ impl Manager {
self.process_entity_changes(world, renderer); self.process_entity_changes(world, renderer);
} }
fn process_entity_changes(&mut self, world: &mut world::World, renderer: &mut render::Renderer) { fn process_entity_changes(
&mut self,
world: &mut world::World,
renderer: &mut render::Renderer,
) {
let changes = self.changed_entity_components.clone(); let changes = self.changed_entity_components.clone();
self.changed_entity_components = HashSet::with_hasher(BuildHasherDefault::default()); self.changed_entity_components = HashSet::with_hasher(BuildHasherDefault::default());
for entity in changes { for entity in changes {
@ -177,11 +199,35 @@ impl Manager {
state.components.or(&state.last_components); state.components.or(&state.last_components);
(cur, orig) (cur, orig)
}; };
self.trigger_add_for_systems(entity, &state.last_components, &state.components, world, renderer); self.trigger_add_for_systems(
self.trigger_add_for_render_systems(entity, &state.last_components, &state.components, world, renderer); entity,
self.trigger_remove_for_systems(entity, &state.last_components, &state.components, world, renderer); &state.last_components,
self.trigger_remove_for_render_systems(entity, &state.last_components, &state.components, world, renderer); &state.components,
for i in 0 .. self.components.len() { world,
renderer,
);
self.trigger_add_for_render_systems(
entity,
&state.last_components,
&state.components,
world,
renderer,
);
self.trigger_remove_for_systems(
entity,
&state.last_components,
&state.components,
world,
renderer,
);
self.trigger_remove_for_render_systems(
entity,
&state.last_components,
&state.components,
world,
renderer,
);
for i in 0..self.components.len() {
if !state.components.get(i) && state.last_components.get(i) { if !state.components.get(i) && state.last_components.get(i) {
let components = self.components.get_mut(i).and_then(|v| v.as_mut()).unwrap(); let components = self.components.get_mut(i).and_then(|v| v.as_mut()).unwrap();
components.remove(entity.id); components.remove(entity.id);
@ -230,7 +276,7 @@ impl Manager {
return Entity { return Entity {
id, id,
generation: entity.1, generation: entity.1,
} };
} }
let id = self.entities.len(); let id = self.entities.len();
self.entities.push(( self.entities.push((
@ -239,12 +285,9 @@ impl Manager {
components: BSet::new(self.num_components), components: BSet::new(self.num_components),
removed: false, removed: false,
}), }),
0 0,
)); ));
Entity { Entity { id, generation: 0 }
id,
generation: 0,
}
} }
/// Deallocates an entity and frees its components /// Deallocates an entity and frees its components
@ -257,12 +300,16 @@ impl Manager {
} }
/// Deallocates all entities/components excluding the world entity /// Deallocates all entities/components excluding the world entity
pub fn remove_all_entities(&mut self, world: &mut world::World, renderer: &mut render::Renderer) { pub fn remove_all_entities(
&mut self,
world: &mut world::World,
renderer: &mut render::Renderer,
) {
for (id, e) in self.entities[1..].iter_mut().enumerate() { for (id, e) in self.entities[1..].iter_mut().enumerate() {
if let Some(set) = e.0.as_mut() { if let Some(set) = e.0.as_mut() {
set.components = BSet::new(self.components.len()); set.components = BSet::new(self.components.len());
set.removed = true; set.removed = true;
self.changed_entity_components.insert(Entity{ self.changed_entity_components.insert(Entity {
id: id + 1, id: id + 1,
generation: e.1, generation: e.1,
}); });
@ -312,7 +359,13 @@ impl Manager {
} }
let mut e = self.entities.get_mut(entity.id); let mut e = self.entities.get_mut(entity.id);
let set = match e { let set = match e {
Some(ref mut val) => if val.1 == entity.generation { &mut val.0 } else { panic!("Missing entity") }, Some(ref mut val) => {
if val.1 == entity.generation {
&mut val.0
} else {
panic!("Missing entity")
}
}
None => panic!("Missing entity"), None => panic!("Missing entity"),
}; };
let set = match set.as_mut() { let set = match set.as_mut() {
@ -327,24 +380,44 @@ impl Manager {
} }
set.components.set(key.id, true); set.components.set(key.id, true);
self.changed_entity_components.insert(entity); self.changed_entity_components.insert(entity);
let components = self.components.get_mut(key.id).and_then(|v| v.as_mut()).unwrap(); let components = self
.components
.get_mut(key.id)
.and_then(|v| v.as_mut())
.unwrap();
components.add(entity.id, val); components.add(entity.id, val);
} }
fn trigger_add_for_systems(&mut self, e: Entity, old_set: &BSet, new_set: &BSet, world: &mut world::World, renderer: &mut render::Renderer) { fn trigger_add_for_systems(
&mut self,
e: Entity,
old_set: &BSet,
new_set: &BSet,
world: &mut world::World,
renderer: &mut render::Renderer,
) {
let mut systems = self.systems.take().unwrap(); let mut systems = self.systems.take().unwrap();
for sys in &mut systems { for sys in &mut systems {
if new_set.includes_set(&sys.filter().bits) && !old_set.includes_set(&sys.filter().bits) { if new_set.includes_set(&sys.filter().bits) && !old_set.includes_set(&sys.filter().bits)
{
sys.entity_added(self, e, world, renderer); sys.entity_added(self, e, world, renderer);
} }
} }
self.systems = Some(systems); self.systems = Some(systems);
} }
fn trigger_add_for_render_systems(&mut self, e: Entity, old_set: &BSet, new_set: &BSet, world: &mut world::World, renderer: &mut render::Renderer) { fn trigger_add_for_render_systems(
&mut self,
e: Entity,
old_set: &BSet,
new_set: &BSet,
world: &mut world::World,
renderer: &mut render::Renderer,
) {
let mut systems = self.render_systems.take().unwrap(); let mut systems = self.render_systems.take().unwrap();
for sys in &mut systems { for sys in &mut systems {
if new_set.includes_set(&sys.filter().bits) && !old_set.includes_set(&sys.filter().bits) { if new_set.includes_set(&sys.filter().bits) && !old_set.includes_set(&sys.filter().bits)
{
sys.entity_added(self, e, world, renderer); sys.entity_added(self, e, world, renderer);
} }
} }
@ -371,7 +444,13 @@ impl Manager {
} }
let mut e = self.entities.get_mut(entity.id); let mut e = self.entities.get_mut(entity.id);
let set = match e { let set = match e {
Some(ref mut val) => if val.1 == entity.generation { &mut val.0 } else { panic!("Missing entity") }, Some(ref mut val) => {
if val.1 == entity.generation {
&mut val.0
} else {
panic!("Missing entity")
}
}
None => panic!("Missing entity"), None => panic!("Missing entity"),
}; };
let set = match set.as_mut() { let set = match set.as_mut() {
@ -382,7 +461,7 @@ impl Manager {
panic!("Double change within a single tick"); panic!("Double change within a single tick");
} }
if !set.components.get(key.id) { if !set.components.get(key.id) {
return false return false;
} }
set.components.set(key.id, false); set.components.set(key.id, false);
self.changed_entity_components.insert(entity); self.changed_entity_components.insert(entity);
@ -390,20 +469,36 @@ impl Manager {
true true
} }
fn trigger_remove_for_systems(&mut self, e: Entity, old_set: &BSet, new_set: &BSet, world: &mut world::World, renderer: &mut render::Renderer) { fn trigger_remove_for_systems(
&mut self,
e: Entity,
old_set: &BSet,
new_set: &BSet,
world: &mut world::World,
renderer: &mut render::Renderer,
) {
let mut systems = self.systems.take().unwrap(); let mut systems = self.systems.take().unwrap();
for sys in &mut systems { for sys in &mut systems {
if !new_set.includes_set(&sys.filter().bits) && old_set.includes_set(&sys.filter().bits) { if !new_set.includes_set(&sys.filter().bits) && old_set.includes_set(&sys.filter().bits)
{
sys.entity_removed(self, e, world, renderer); sys.entity_removed(self, e, world, renderer);
} }
} }
self.systems = Some(systems); self.systems = Some(systems);
} }
fn trigger_remove_for_render_systems(&mut self, e: Entity, old_set: &BSet, new_set: &BSet, world: &mut world::World, renderer: &mut render::Renderer) { fn trigger_remove_for_render_systems(
&mut self,
e: Entity,
old_set: &BSet,
new_set: &BSet,
world: &mut world::World,
renderer: &mut render::Renderer,
) {
let mut systems = self.render_systems.take().unwrap(); let mut systems = self.render_systems.take().unwrap();
for sys in &mut systems { for sys in &mut systems {
if !new_set.includes_set(&sys.filter().bits) && old_set.includes_set(&sys.filter().bits) { if !new_set.includes_set(&sys.filter().bits) && old_set.includes_set(&sys.filter().bits)
{
sys.entity_removed(self, e, world, renderer); sys.entity_removed(self, e, world, renderer);
} }
} }
@ -424,7 +519,13 @@ impl Manager {
None => return None, None => return None,
}; };
let set = match self.entities.get(entity.id).as_ref() { let set = match self.entities.get(entity.id).as_ref() {
Some(val) => if val.1 == entity.generation { &val.0 } else { return None }, Some(val) => {
if val.1 == entity.generation {
&val.0
} else {
return None;
}
}
None => return None, None => return None,
}; };
if !set.as_ref().map_or(false, |v| v.components.get(key.id)) { if !set.as_ref().map_or(false, |v| v.components.get(key.id)) {
@ -442,13 +543,23 @@ impl Manager {
} }
/// Returns the given component that the key points to if it exists. /// Returns the given component that the key points to if it exists.
pub fn get_component_mut<'a, 'b: 'a, T>(&'a mut self, entity: Entity, key: Key<T>) -> Option<&'b mut T> { pub fn get_component_mut<'a, 'b: 'a, T>(
&'a mut self,
entity: Entity,
key: Key<T>,
) -> Option<&'b mut T> {
let components = match self.components.get_mut(key.id).and_then(|v| v.as_mut()) { let components = match self.components.get_mut(key.id).and_then(|v| v.as_mut()) {
Some(val) => val, Some(val) => val,
None => return None, None => return None,
}; };
let set = match self.entities.get(entity.id).as_ref() { let set = match self.entities.get(entity.id).as_ref() {
Some(val) => if val.1 == entity.generation { &val.0 } else { return None }, Some(val) => {
if val.1 == entity.generation {
&val.0
} else {
return None;
}
}
None => return None, None => return None,
}; };
if !set.as_ref().map_or(false, |v| v.components.get(key.id)) { if !set.as_ref().map_or(false, |v| v.components.get(key.id)) {
@ -460,7 +571,10 @@ impl Manager {
/// Same as `get_component_mut` but doesn't require a key. Using a key /// Same as `get_component_mut` but doesn't require a key. Using a key
/// is better for frequent lookups. /// is better for frequent lookups.
pub fn get_component_mut_direct<'a, 'b: 'a, T: Any>(&'a mut self, entity: Entity) -> Option<&'b mut T> { pub fn get_component_mut_direct<'a, 'b: 'a, T: Any>(
&'a mut self,
entity: Entity,
) -> Option<&'b mut T> {
let key = self.get_key(); let key = self.get_key();
self.get_component_mut(entity, key) self.get_component_mut(entity, key)
} }
@ -479,12 +593,10 @@ impl ComponentMem {
ComponentMem { ComponentMem {
data: vec![], data: vec![],
component_size: mem::size_of::<T>(), component_size: mem::size_of::<T>(),
drop_func: Box::new(|data| { drop_func: Box::new(|data| unsafe {
unsafe { let mut val: T = mem::MaybeUninit::uninit().assume_init();
let mut val: T = mem::MaybeUninit::uninit().assume_init(); ptr::copy(data as *mut T, &mut val, 1);
ptr::copy(data as *mut T, &mut val, 1); mem::drop(val);
mem::drop(val);
}
}), }),
} }
} }
@ -496,7 +608,11 @@ impl ComponentMem {
let idx = index / COMPONENTS_PER_BLOCK; let idx = index / COMPONENTS_PER_BLOCK;
let rem = index % COMPONENTS_PER_BLOCK; let rem = index % COMPONENTS_PER_BLOCK;
if self.data[idx].is_none() { if self.data[idx].is_none() {
self.data[idx] = Some((vec![0; self.component_size * COMPONENTS_PER_BLOCK], BSet::new(COMPONENTS_PER_BLOCK), 0)); self.data[idx] = Some((
vec![0; self.component_size * COMPONENTS_PER_BLOCK],
BSet::new(COMPONENTS_PER_BLOCK),
0,
));
} }
let data = self.data[idx].as_mut().unwrap(); let data = self.data[idx].as_mut().unwrap();
let start = rem * self.component_size; let start = rem * self.component_size;
@ -518,7 +634,9 @@ impl ComponentMem {
// We don't have access to the actual type in this method so // We don't have access to the actual type in this method so
// we use the drop_func which stores the type in its closure // we use the drop_func which stores the type in its closure
// to handle the dropping for us. // to handle the dropping for us.
unsafe { (self.drop_func)(data.0.as_mut_ptr().offset(start as isize)); } unsafe {
(self.drop_func)(data.0.as_mut_ptr().offset(start as isize));
}
data.2 -= 1; data.2 -= 1;
data.2 data.2
}; };
@ -532,9 +650,7 @@ impl ComponentMem {
let rem = index % COMPONENTS_PER_BLOCK; let rem = index % COMPONENTS_PER_BLOCK;
let data = self.data[idx].as_ref().unwrap(); let data = self.data[idx].as_ref().unwrap();
let start = rem * self.component_size; let start = rem * self.component_size;
unsafe { unsafe { &*(data.0.as_ptr().offset(start as isize) as *const T) }
&*(data.0.as_ptr().offset(start as isize) as *const T)
}
} }
fn get_mut<T>(&mut self, index: usize) -> &mut T { fn get_mut<T>(&mut self, index: usize) -> &mut T {
@ -542,9 +658,7 @@ impl ComponentMem {
let rem = index % COMPONENTS_PER_BLOCK; let rem = index % COMPONENTS_PER_BLOCK;
let data = self.data[idx].as_mut().unwrap(); let data = self.data[idx].as_mut().unwrap();
let start = rem * self.component_size; let start = rem * self.component_size;
unsafe { unsafe { &mut *(data.0.as_mut_ptr().offset(start as isize) as *mut T) }
&mut *(data.0.as_mut_ptr().offset(start as isize) as *mut T)
}
} }
} }
@ -552,10 +666,12 @@ impl Drop for ComponentMem {
fn drop(&mut self) { fn drop(&mut self) {
for data in &mut self.data { for data in &mut self.data {
if let Some(data) = data.as_mut() { if let Some(data) = data.as_mut() {
for i in 0 .. COMPONENTS_PER_BLOCK { for i in 0..COMPONENTS_PER_BLOCK {
if data.1.get(i) { if data.1.get(i) {
let start = i * self.component_size; let start = i * self.component_size;
unsafe { (self.drop_func)(data.0.as_mut_ptr().offset(start as isize)); } unsafe {
(self.drop_func)(data.0.as_mut_ptr().offset(start as isize));
}
} }
} }
} }

View File

@ -1,22 +1,21 @@
pub mod sign; pub mod sign;
use crate::world::block::Block;
use crate::shared::Position;
use crate::ecs; use crate::ecs;
use crate::shared::Position;
use crate::world::block::Block;
pub fn add_systems(m: &mut ecs::Manager) { pub fn add_systems(m: &mut ecs::Manager) {
sign::add_systems(m); sign::add_systems(m);
} }
pub enum BlockEntityType { pub enum BlockEntityType {
Sign Sign,
} }
impl BlockEntityType { impl BlockEntityType {
pub fn get_block_entity(bl: Block) -> Option<BlockEntityType> { pub fn get_block_entity(bl: Block) -> Option<BlockEntityType> {
match bl { match bl {
Block::StandingSign{..} | Block::WallSign{..} => Some(BlockEntityType::Sign), Block::StandingSign { .. } | Block::WallSign { .. } => Some(BlockEntityType::Sign),
_ => None, _ => None,
} }
} }

View File

@ -1,11 +1,10 @@
use crate::ecs; use crate::ecs;
use crate::format::{self, Component}; use crate::format::{self, Component};
use crate::render;
use crate::render::model::{self, FormatState};
use crate::shared::{Direction, Position}; use crate::shared::{Direction, Position};
use crate::world; use crate::world;
use crate::world::block::Block; use crate::world::block::Block;
use crate::render;
use crate::render::model::{self, FormatState};
pub fn add_systems(m: &mut ecs::Manager) { pub fn add_systems(m: &mut ecs::Manager) {
let sys = SignRenderer::new(m); let sys = SignRenderer::new(m);
@ -13,21 +12,24 @@ pub fn add_systems(m: &mut ecs::Manager) {
} }
pub fn init_entity(m: &mut ecs::Manager, e: ecs::Entity) { pub fn init_entity(m: &mut ecs::Manager, e: ecs::Entity) {
m.add_component_direct(e, SignInfo { m.add_component_direct(
model: None, e,
lines: [ SignInfo {
Component::Text(format::TextComponent::new("")), model: None,
Component::Text(format::TextComponent::new("")), lines: [
Component::Text(format::TextComponent::new("")), Component::Text(format::TextComponent::new("")),
Component::Text(format::TextComponent::new("")), Component::Text(format::TextComponent::new("")),
], Component::Text(format::TextComponent::new("")),
offset_x: 0.0, Component::Text(format::TextComponent::new("")),
offset_y: 0.0, ],
offset_z: 0.0, offset_x: 0.0,
has_stand: false, offset_y: 0.0,
rotation: 0.0, offset_z: 0.0,
dirty: false, has_stand: false,
}); rotation: 0.0,
dirty: false,
},
);
} }
pub struct SignInfo { pub struct SignInfo {
@ -54,9 +56,7 @@ impl SignRenderer {
let sign_info = m.get_key(); let sign_info = m.get_key();
let position = m.get_key(); let position = m.get_key();
SignRenderer { SignRenderer {
filter: ecs::Filter::new() filter: ecs::Filter::new().with(position).with(sign_info),
.with(position)
.with(sign_info),
position, position,
sign_info, sign_info,
} }
@ -64,12 +64,16 @@ impl SignRenderer {
} }
impl ecs::System for SignRenderer { impl ecs::System for SignRenderer {
fn filter(&self) -> &ecs::Filter { fn filter(&self) -> &ecs::Filter {
&self.filter &self.filter
} }
fn update(&mut self, m: &mut ecs::Manager, world: &mut world::World, renderer: &mut render::Renderer) { fn update(
&mut self,
m: &mut ecs::Manager,
world: &mut world::World,
renderer: &mut render::Renderer,
) {
for e in m.find(&self.filter) { for e in m.find(&self.filter) {
let position = *m.get_component(e, self.position).unwrap(); let position = *m.get_component(e, self.position).unwrap();
let info = m.get_component_mut(e, self.sign_info).unwrap(); let info = m.get_component_mut(e, self.sign_info).unwrap();
@ -85,24 +89,30 @@ impl ecs::System for SignRenderer {
} }
} }
fn entity_added(&mut self, m: &mut ecs::Manager, e: ecs::Entity, world: &mut world::World, renderer: &mut render::Renderer) { fn entity_added(
&mut self,
m: &mut ecs::Manager,
e: ecs::Entity,
world: &mut world::World,
renderer: &mut render::Renderer,
) {
use cgmath::{Decomposed, Matrix4, Quaternion, Rad, Rotation3, Vector3};
use std::f64::consts::PI; use std::f64::consts::PI;
use cgmath::{Vector3, Matrix4, Decomposed, Rotation3, Rad, Quaternion};
let position = *m.get_component(e, self.position).unwrap(); let position = *m.get_component(e, self.position).unwrap();
let info = m.get_component_mut(e, self.sign_info).unwrap(); let info = m.get_component_mut(e, self.sign_info).unwrap();
info.dirty = false; info.dirty = false;
match world.get_block(position) { match world.get_block(position) {
Block::WallSign{facing, ..} => { Block::WallSign { facing, .. } => {
info.offset_z = 7.5 / 16.0; info.offset_z = 7.5 / 16.0;
match facing { match facing {
Direction::North => {}, Direction::North => {}
Direction::South => info.rotation = PI, Direction::South => info.rotation = PI,
Direction::West => info.rotation = PI / 2.0, Direction::West => info.rotation = PI / 2.0,
Direction::East => info.rotation = -PI / 2.0, Direction::East => info.rotation = -PI / 2.0,
_ => unreachable!(), _ => unreachable!(),
} }
}, }
Block::StandingSign{rotation, ..} => { Block::StandingSign { rotation, .. } => {
info.offset_y = 5.0 / 16.0; info.offset_y = 5.0 / 16.0;
info.has_stand = true; info.has_stand = true;
info.rotation = -(rotation.data() as f64 / 16.0) * PI * 2.0 + PI; info.rotation = -(rotation.data() as f64 / 16.0) * PI * 2.0 + PI;
@ -112,30 +122,48 @@ impl ecs::System for SignRenderer {
let tex = render::Renderer::get_texture(renderer.get_textures_ref(), "entity/sign"); let tex = render::Renderer::get_texture(renderer.get_textures_ref(), "entity/sign");
macro_rules! rel { macro_rules! rel {
($x:expr, $y:expr, $w:expr, $h:expr) => ( ($x:expr, $y:expr, $w:expr, $h:expr) => {
Some(tex.relative(($x) / 64.0, ($y) / 32.0, ($w) / 64.0, ($h) / 32.0)) Some(tex.relative(($x) / 64.0, ($y) / 32.0, ($w) / 64.0, ($h) / 32.0))
); };
} }
let mut verts = vec![]; let mut verts = vec![];
// Backboard // Backboard
model::append_box(&mut verts, -0.5, -4.0/16.0, -0.5/16.0, 1.0, 8.0/16.0, 1.0/16.0, [ model::append_box(
rel!(26.0, 0.0, 24.0, 2.0), // Down &mut verts,
rel!(2.0, 0.0, 24.0, 2.0), // Up -0.5,
rel!(2.0, 2.0, 24.0, 12.0), // North -4.0 / 16.0,
rel!(26.0, 2.0, 24.0, 12.0), // South -0.5 / 16.0,
rel!(0.0, 2.0, 2.0, 12.0), // West 1.0,
rel!(50.0, 2.0, 2.0, 12.0), // East 8.0 / 16.0,
]); 1.0 / 16.0,
[
rel!(26.0, 0.0, 24.0, 2.0), // Down
rel!(2.0, 0.0, 24.0, 2.0), // Up
rel!(2.0, 2.0, 24.0, 12.0), // North
rel!(26.0, 2.0, 24.0, 12.0), // South
rel!(0.0, 2.0, 2.0, 12.0), // West
rel!(50.0, 2.0, 2.0, 12.0), // East
],
);
if info.has_stand { if info.has_stand {
model::append_box(&mut verts, -0.5/16.0, -0.25-9.0/16.0, -0.5/16.0, 1.0/16.0, 9.0/16.0, 1.0/16.0, [ model::append_box(
rel!(4.0, 14.0, 2.0, 2.0), // Down &mut verts,
rel!(2.0, 14.0, 2.0, 2.0), // Up -0.5 / 16.0,
rel!(2.0, 16.0, 2.0, 12.0), // North -0.25 - 9.0 / 16.0,
rel!(6.0, 16.0, 2.0, 12.0), // South -0.5 / 16.0,
rel!(0.0, 16.0, 2.0, 12.0), // West 1.0 / 16.0,
rel!(4.0, 16.0, 2.0, 12.0), // East 9.0 / 16.0,
]); 1.0 / 16.0,
[
rel!(4.0, 14.0, 2.0, 2.0), // Down
rel!(2.0, 14.0, 2.0, 2.0), // Up
rel!(2.0, 16.0, 2.0, 12.0), // North
rel!(6.0, 16.0, 2.0, 12.0), // South
rel!(0.0, 16.0, 2.0, 12.0), // West
rel!(4.0, 16.0, 2.0, 12.0), // East
],
);
} }
for (i, line) in info.lines.iter().enumerate() { for (i, line) in info.lines.iter().enumerate() {
@ -154,15 +182,12 @@ impl ecs::System for SignRenderer {
// Center align text // Center align text
for vert in &mut state.text { for vert in &mut state.text {
vert.x += width * 0.5; vert.x += width * 0.5;
vert.y -= (Y_SCALE + 0.4/16.0) * (i as f32); vert.y -= (Y_SCALE + 0.4 / 16.0) * (i as f32);
} }
verts.extend_from_slice(&state.text); verts.extend_from_slice(&state.text);
} }
let model = renderer.model.create_model( let model = renderer.model.create_model(model::DEFAULT, vec![verts]);
model::DEFAULT,
vec![verts]
);
{ {
let mdl = renderer.model.get_model(model).unwrap(); let mdl = renderer.model.get_model(model).unwrap();
@ -173,14 +198,28 @@ impl ecs::System for SignRenderer {
mdl.matrix[0] = Matrix4::from(Decomposed { mdl.matrix[0] = Matrix4::from(Decomposed {
scale: 1.0, scale: 1.0,
rot: Quaternion::from_angle_y(Rad(info.rotation as f32)), rot: Quaternion::from_angle_y(Rad(info.rotation as f32)),
disp: Vector3::new(position.x as f32 + 0.5, -position.y as f32 - 0.5, position.z as f32 + 0.5), disp: Vector3::new(
}) * Matrix4::from_translation(Vector3::new(info.offset_x as f32, -info.offset_y as f32, info.offset_z as f32)); position.x as f32 + 0.5,
-position.y as f32 - 0.5,
position.z as f32 + 0.5,
),
}) * Matrix4::from_translation(Vector3::new(
info.offset_x as f32,
-info.offset_y as f32,
info.offset_z as f32,
));
} }
info.model = Some(model); info.model = Some(model);
} }
fn entity_removed(&mut self, m: &mut ecs::Manager, e: ecs::Entity, _: &mut world::World, renderer: &mut render::Renderer) { fn entity_removed(
&mut self,
m: &mut ecs::Manager,
e: ecs::Entity,
_: &mut world::World,
renderer: &mut render::Renderer,
) {
let info = m.get_component_mut(e, self.sign_info).unwrap(); let info = m.get_component_mut(e, self.sign_info).unwrap();
if let Some(model) = info.model { if let Some(model) = info.model {
renderer.model.remove_model(model); renderer.model.remove_model(model);

View File

@ -1,6 +1,5 @@
pub mod player;
pub mod block_entity; pub mod block_entity;
pub mod player;
use crate::ecs; use crate::ecs;
use cgmath::Vector3; use cgmath::Vector3;
@ -96,10 +95,7 @@ pub struct Rotation {
impl Rotation { impl Rotation {
pub fn new(yaw: f64, pitch: f64) -> Rotation { pub fn new(yaw: f64, pitch: f64) -> Rotation {
Rotation { Rotation { yaw, pitch }
yaw,
pitch,
}
} }
pub fn zero() -> Rotation { pub fn zero() -> Rotation {
@ -114,10 +110,7 @@ pub struct TargetRotation {
impl TargetRotation { impl TargetRotation {
pub fn new(yaw: f64, pitch: f64) -> TargetRotation { pub fn new(yaw: f64, pitch: f64) -> TargetRotation {
TargetRotation { TargetRotation { yaw, pitch }
yaw,
pitch,
}
} }
pub fn zero() -> TargetRotation { pub fn zero() -> TargetRotation {
@ -131,7 +124,9 @@ pub struct Gravity {
} }
impl Gravity { impl Gravity {
pub fn new() -> Gravity { Default::default() } pub fn new() -> Gravity {
Default::default()
}
} }
pub struct Bounds { pub struct Bounds {
@ -140,9 +135,7 @@ pub struct Bounds {
impl Bounds { impl Bounds {
pub fn new(bounds: Aabb3<f64>) -> Bounds { pub fn new(bounds: Aabb3<f64>) -> Bounds {
Bounds { Bounds { bounds }
bounds,
}
} }
} }
@ -152,7 +145,9 @@ pub struct GameInfo {
} }
impl GameInfo { impl GameInfo {
pub fn new() -> GameInfo { Default::default() } pub fn new() -> GameInfo {
Default::default()
}
} }
#[derive(Default)] #[derive(Default)]
@ -162,5 +157,7 @@ pub struct Light {
} }
impl Light { impl Light {
pub fn new() -> Light { Default::default() } pub fn new() -> Light {
Default::default()
}
} }

View File

@ -1,29 +1,20 @@
use crate::ecs;
use super::{ use super::{
Position, Bounds, GameInfo, Gravity, Light, Position, Rotation, TargetPosition, TargetRotation, Velocity,
TargetPosition,
Velocity,
Rotation,
TargetRotation,
Gravity,
Bounds,
GameInfo,
Light
}; };
use crate::world; use crate::ecs;
use crate::format;
use crate::render; use crate::render;
use crate::render::model::{self, FormatState}; use crate::render::model::{self, FormatState};
use crate::settings::Stevenkey;
use crate::shared::Position as BPosition;
use crate::types::hash::FNVHash;
use crate::types::Gamemode; use crate::types::Gamemode;
use crate::world;
use cgmath::{self, Decomposed, Matrix4, Point3, Quaternion, Rad, Rotation3, Vector3};
use collision::{Aabb, Aabb3}; use collision::{Aabb, Aabb3};
use cgmath::{self, Point3, Vector3, Matrix4, Decomposed, Rotation3, Rad, Quaternion};
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::BuildHasherDefault; use std::hash::BuildHasherDefault;
use std::time::Instant; use std::time::Instant;
use crate::types::hash::FNVHash;
use crate::settings::Stevenkey;
use crate::shared::Position as BPosition;
use crate::format;
pub fn add_systems(m: &mut ecs::Manager) { pub fn add_systems(m: &mut ecs::Manager) {
let sys = MovementHandler::new(m); let sys = MovementHandler::new(m);
@ -43,10 +34,13 @@ pub fn create_local(m: &mut ecs::Manager) -> ecs::Entity {
m.add_component_direct(entity, Gamemode::Survival); m.add_component_direct(entity, Gamemode::Survival);
m.add_component_direct(entity, Gravity::new()); m.add_component_direct(entity, Gravity::new());
m.add_component_direct(entity, PlayerMovement::new()); m.add_component_direct(entity, PlayerMovement::new());
m.add_component_direct(entity, Bounds::new(Aabb3::new( m.add_component_direct(
Point3::new(-0.3, 0.0, -0.3), entity,
Point3::new(0.3, 1.8, 0.3) Bounds::new(Aabb3::new(
))); Point3::new(-0.3, 0.0, -0.3),
Point3::new(0.3, 1.8, 0.3),
)),
);
m.add_component_direct(entity, PlayerModel::new("", false, false, true)); m.add_component_direct(entity, PlayerModel::new("", false, false, true));
m.add_component_direct(entity, Light::new()); m.add_component_direct(entity, Light::new());
entity entity
@ -59,16 +53,18 @@ pub fn create_remote(m: &mut ecs::Manager, name: &str) -> ecs::Entity {
m.add_component_direct(entity, Rotation::new(0.0, 0.0)); m.add_component_direct(entity, Rotation::new(0.0, 0.0));
m.add_component_direct(entity, TargetRotation::new(0.0, 0.0)); m.add_component_direct(entity, TargetRotation::new(0.0, 0.0));
m.add_component_direct(entity, Velocity::new(0.0, 0.0, 0.0)); m.add_component_direct(entity, Velocity::new(0.0, 0.0, 0.0));
m.add_component_direct(entity, Bounds::new(Aabb3::new( m.add_component_direct(
Point3::new(-0.3, 0.0, -0.3), entity,
Point3::new(0.3, 1.8, 0.3) Bounds::new(Aabb3::new(
))); Point3::new(-0.3, 0.0, -0.3),
Point3::new(0.3, 1.8, 0.3),
)),
);
m.add_component_direct(entity, PlayerModel::new(name, true, true, false)); m.add_component_direct(entity, PlayerModel::new(name, true, true, false));
m.add_component_direct(entity, Light::new()); m.add_component_direct(entity, Light::new());
entity entity
} }
pub struct PlayerModel { pub struct PlayerModel {
model: Option<model::ModelKey>, model: Option<model::ModelKey>,
skin_url: Option<String>, skin_url: Option<String>,
@ -155,16 +151,23 @@ enum PlayerModelPart {
// TODO: Setup culling // TODO: Setup culling
impl ecs::System for PlayerRenderer { impl ecs::System for PlayerRenderer {
fn filter(&self) -> &ecs::Filter { fn filter(&self) -> &ecs::Filter {
&self.filter &self.filter
} }
fn update(&mut self, m: &mut ecs::Manager, world: &mut world::World, renderer: &mut render::Renderer) { fn update(
&mut self,
m: &mut ecs::Manager,
world: &mut world::World,
renderer: &mut render::Renderer,
) {
use std::f32::consts::PI; use std::f32::consts::PI;
use std::f64::consts::PI as PI64; use std::f64::consts::PI as PI64;
let world_entity = m.get_world(); let world_entity = m.get_world();
let delta = m.get_component_mut(world_entity, self.game_info).unwrap().delta; let delta = m
.get_component_mut(world_entity, self.game_info)
.unwrap()
.delta;
for e in m.find(&self.filter) { for e in m.find(&self.filter) {
let player_model = m.get_component_mut(e, self.player_model).unwrap(); let player_model = m.get_component_mut(e, self.player_model).unwrap();
let position = m.get_component_mut(e, self.position).unwrap(); let position = m.get_component_mut(e, self.position).unwrap();
@ -183,8 +186,8 @@ impl ecs::System for PlayerRenderer {
mdl.sky_light = light.sky_light; mdl.sky_light = light.sky_light;
let offset = if player_model.first_person { let offset = if player_model.first_person {
let ox = (rotation.yaw - PI64/2.0).cos() * 0.25; let ox = (rotation.yaw - PI64 / 2.0).cos() * 0.25;
let oz = -(rotation.yaw - PI64/2.0).sin() * 0.25; let oz = -(rotation.yaw - PI64 / 2.0).sin() * 0.25;
Vector3::new( Vector3::new(
position.position.x as f32 - ox as f32, position.position.x as f32 - ox as f32,
-position.position.y as f32, -position.position.y as f32,
@ -205,24 +208,28 @@ impl ecs::System for PlayerRenderer {
// TODO This sucks // TODO This sucks
if player_model.has_name_tag { if player_model.has_name_tag {
let ang = (position.position.x - renderer.camera.pos.x).atan2(position.position.z - renderer.camera.pos.z) as f32; let ang = (position.position.x - renderer.camera.pos.x)
.atan2(position.position.z - renderer.camera.pos.z)
as f32;
mdl.matrix[PlayerModelPart::NameTag as usize] = Matrix4::from(Decomposed { mdl.matrix[PlayerModelPart::NameTag as usize] = Matrix4::from(Decomposed {
scale: 1.0, scale: 1.0,
rot: Quaternion::from_angle_y(Rad(ang)), rot: Quaternion::from_angle_y(Rad(ang)),
disp: offset + Vector3::new(0.0, (-24.0/16.0) - 0.6, 0.0), disp: offset + Vector3::new(0.0, (-24.0 / 16.0) - 0.6, 0.0),
}); });
} }
mdl.matrix[PlayerModelPart::Head as usize] = offset_matrix * Matrix4::from(Decomposed { mdl.matrix[PlayerModelPart::Head as usize] = offset_matrix
scale: 1.0, * Matrix4::from(Decomposed {
rot: Quaternion::from_angle_x(Rad(-rotation.pitch as f32)), scale: 1.0,
disp: Vector3::new(0.0, -12.0/16.0 - 12.0/16.0, 0.0), rot: Quaternion::from_angle_x(Rad(-rotation.pitch as f32)),
}); disp: Vector3::new(0.0, -12.0 / 16.0 - 12.0 / 16.0, 0.0),
mdl.matrix[PlayerModelPart::Body as usize] = offset_matrix * Matrix4::from(Decomposed { });
scale: 1.0, mdl.matrix[PlayerModelPart::Body as usize] = offset_matrix
rot: Quaternion::from_angle_x(Rad(0.0)), * Matrix4::from(Decomposed {
disp: Vector3::new(0.0, -12.0/16.0 - 6.0/16.0, 0.0), scale: 1.0,
}); rot: Quaternion::from_angle_x(Rad(0.0)),
disp: Vector3::new(0.0, -12.0 / 16.0 - 6.0 / 16.0, 0.0),
});
let mut time = player_model.time; let mut time = player_model.time;
let mut dir = player_model.dir; let mut dir = player_model.dir;
@ -232,16 +239,18 @@ impl ecs::System for PlayerRenderer {
} }
let ang = ((time / 15.0) - 1.0) * (PI64 / 4.0); let ang = ((time / 15.0) - 1.0) * (PI64 / 4.0);
mdl.matrix[PlayerModelPart::LegRight as usize] = offset_matrix * Matrix4::from(Decomposed { mdl.matrix[PlayerModelPart::LegRight as usize] = offset_matrix
scale: 1.0, * Matrix4::from(Decomposed {
rot: Quaternion::from_angle_x(Rad(ang as f32)), scale: 1.0,
disp: Vector3::new(2.0/16.0, -12.0/16.0, 0.0), rot: Quaternion::from_angle_x(Rad(ang as f32)),
}); disp: Vector3::new(2.0 / 16.0, -12.0 / 16.0, 0.0),
mdl.matrix[PlayerModelPart::LegLeft as usize] = offset_matrix * Matrix4::from(Decomposed { });
scale: 1.0, mdl.matrix[PlayerModelPart::LegLeft as usize] = offset_matrix
rot: Quaternion::from_angle_x(Rad(-ang as f32)), * Matrix4::from(Decomposed {
disp: Vector3::new(-2.0/16.0, -12.0/16.0, 0.0), scale: 1.0,
}); rot: Quaternion::from_angle_x(Rad(-ang as f32)),
disp: Vector3::new(-2.0 / 16.0, -12.0 / 16.0, 0.0),
});
let mut i_time = player_model.idle_time; let mut i_time = player_model.idle_time;
i_time += delta * 0.02; i_time += delta * 0.02;
@ -256,17 +265,31 @@ impl ecs::System for PlayerRenderer {
player_model.arm_time -= delta; player_model.arm_time -= delta;
} }
mdl.matrix[PlayerModelPart::ArmRight as usize] = offset_matrix * Matrix4::from_translation( mdl.matrix[PlayerModelPart::ArmRight as usize] = offset_matrix
Vector3::new(6.0/16.0, -12.0/16.0-12.0/16.0, 0.0) * Matrix4::from_translation(Vector3::new(
) * Matrix4::from(Quaternion::from_angle_x(Rad(-(ang * 0.75) as f32))) 6.0 / 16.0,
* Matrix4::from(Quaternion::from_angle_z(Rad((i_time.cos() * 0.06 - 0.06) as f32))) -12.0 / 16.0 - 12.0 / 16.0,
* Matrix4::from(Quaternion::from_angle_x(Rad((i_time.sin() * 0.06 - ((7.5 - (player_model.arm_time-7.5).abs()) / 7.5)) as f32))); 0.0,
))
* Matrix4::from(Quaternion::from_angle_x(Rad(-(ang * 0.75) as f32)))
* Matrix4::from(Quaternion::from_angle_z(Rad(
(i_time.cos() * 0.06 - 0.06) as f32
)))
* Matrix4::from(Quaternion::from_angle_x(Rad((i_time.sin() * 0.06
- ((7.5 - (player_model.arm_time - 7.5).abs()) / 7.5))
as f32)));
mdl.matrix[PlayerModelPart::ArmLeft as usize] = offset_matrix * Matrix4::from_translation( mdl.matrix[PlayerModelPart::ArmLeft as usize] = offset_matrix
Vector3::new(-6.0/16.0, -12.0/16.0-12.0/16.0, 0.0) * Matrix4::from_translation(Vector3::new(
) * Matrix4::from(Quaternion::from_angle_x(Rad((ang * 0.75) as f32))) -6.0 / 16.0,
* Matrix4::from(Quaternion::from_angle_z(Rad(-(i_time.cos() * 0.06 - 0.06) as f32))) -12.0 / 16.0 - 12.0 / 16.0,
* Matrix4::from(Quaternion::from_angle_x(Rad(-(i_time.sin() * 0.06) as f32))); 0.0,
))
* Matrix4::from(Quaternion::from_angle_x(Rad((ang * 0.75) as f32)))
* Matrix4::from(Quaternion::from_angle_z(Rad(
-(i_time.cos() * 0.06 - 0.06) as f32
)))
* Matrix4::from(Quaternion::from_angle_x(Rad(-(i_time.sin() * 0.06) as f32)));
let mut update = true; let mut update = true;
if position.moved { if position.moved {
@ -297,7 +320,13 @@ impl ecs::System for PlayerRenderer {
} }
} }
fn entity_added(&mut self, m: &mut ecs::Manager, e: ecs::Entity, _: &mut world::World, renderer: &mut render::Renderer) { fn entity_added(
&mut self,
m: &mut ecs::Manager,
e: ecs::Entity,
_: &mut world::World,
renderer: &mut render::Renderer,
) {
let player_model = m.get_component_mut(e, self.player_model).unwrap(); let player_model = m.get_component_mut(e, self.player_model).unwrap();
player_model.dirty = false; player_model.dirty = false;
@ -309,76 +338,133 @@ impl ecs::System for PlayerRenderer {
}; };
macro_rules! srel { macro_rules! srel {
($x:expr, $y:expr, $w:expr, $h:expr) => ( ($x:expr, $y:expr, $w:expr, $h:expr) => {
Some(skin.relative(($x) / 64.0, ($y) / 64.0, ($w) / 64.0, ($h) / 64.0)) Some(skin.relative(($x) / 64.0, ($y) / 64.0, ($w) / 64.0, ($h) / 64.0))
); };
} }
let mut head_verts = vec![]; let mut head_verts = vec![];
if player_model.has_head { if player_model.has_head {
model::append_box(&mut head_verts, -4.0/16.0, 0.0, -4.0/16.0, 8.0/16.0, 8.0/16.0, 8.0/16.0, [ model::append_box(
srel!(16.0, 0.0, 8.0, 8.0), // Down &mut head_verts,
srel!(8.0, 0.0, 8.0, 8.0), // Up -4.0 / 16.0,
srel!(8.0, 8.0, 8.0, 8.0), // North 0.0,
srel!(24.0, 8.0, 8.0, 8.0), // South -4.0 / 16.0,
srel!(16.0, 8.0, 8.0, 8.0), // West 8.0 / 16.0,
srel!(0.0, 8.0, 8.0, 8.0), // East 8.0 / 16.0,
]); 8.0 / 16.0,
model::append_box(&mut head_verts, -4.2/16.0, -0.2/16.0, -4.2/16.0, 8.4/16.0, 8.4/16.0, 8.4/16.0, [ [
srel!((16.0 + 32.0), 0.0, 8.0, 8.0), // Down srel!(16.0, 0.0, 8.0, 8.0), // Down
srel!((8.0 + 32.0), 0.0, 8.0, 8.0), // Up srel!(8.0, 0.0, 8.0, 8.0), // Up
srel!((8.0 + 32.0), 8.0, 8.0, 8.0), // North srel!(8.0, 8.0, 8.0, 8.0), // North
srel!((24.0 + 32.0), 8.0, 8.0, 8.0), // South srel!(24.0, 8.0, 8.0, 8.0), // South
srel!((16.0 + 32.0), 8.0, 8.0, 8.0), // West srel!(16.0, 8.0, 8.0, 8.0), // West
srel!((0.0 + 32.0), 8.0, 8.0, 8.0), // East srel!(0.0, 8.0, 8.0, 8.0), // East
]); ],
);
model::append_box(
&mut head_verts,
-4.2 / 16.0,
-0.2 / 16.0,
-4.2 / 16.0,
8.4 / 16.0,
8.4 / 16.0,
8.4 / 16.0,
[
srel!((16.0 + 32.0), 0.0, 8.0, 8.0), // Down
srel!((8.0 + 32.0), 0.0, 8.0, 8.0), // Up
srel!((8.0 + 32.0), 8.0, 8.0, 8.0), // North
srel!((24.0 + 32.0), 8.0, 8.0, 8.0), // South
srel!((16.0 + 32.0), 8.0, 8.0, 8.0), // West
srel!((0.0 + 32.0), 8.0, 8.0, 8.0), // East
],
);
} }
// TODO: Cape // TODO: Cape
let mut body_verts = vec![]; let mut body_verts = vec![];
model::append_box(&mut body_verts, -4.0/16.0, -6.0/16.0, -2.0/16.0, 8.0/16.0, 12.0/16.0, 4.0/16.0, [ model::append_box(
srel!(28.0, 16.0, 8.0, 4.0), // Down &mut body_verts,
srel!(20.0, 16.0, 8.0, 4.0), // Up -4.0 / 16.0,
srel!(20.0, 20.0, 8.0, 12.0), // North -6.0 / 16.0,
srel!(32.0, 20.0, 8.0, 12.0), // South -2.0 / 16.0,
srel!(16.0, 20.0, 4.0, 12.0), // West 8.0 / 16.0,
srel!(28.0, 20.0, 4.0, 12.0), // East 12.0 / 16.0,
]); 4.0 / 16.0,
model::append_box(&mut body_verts, -4.2/16.0, -6.2/16.0, -2.2/16.0, 8.4/16.0, 12.4/16.0, 4.4/16.0, [ [
srel!(28.0, 16.0 + 16.0, 8.0, 4.0), // Down srel!(28.0, 16.0, 8.0, 4.0), // Down
srel!(20.0, 16.0 + 16.0, 8.0, 4.0), // Up srel!(20.0, 16.0, 8.0, 4.0), // Up
srel!(20.0, 20.0 + 16.0, 8.0, 12.0), // North srel!(20.0, 20.0, 8.0, 12.0), // North
srel!(32.0, 20.0 + 16.0, 8.0, 12.0), // South srel!(32.0, 20.0, 8.0, 12.0), // South
srel!(16.0, 20.0 + 16.0, 4.0, 12.0), // West srel!(16.0, 20.0, 4.0, 12.0), // West
srel!(28.0, 20.0 + 16.0, 4.0, 12.0), // East srel!(28.0, 20.0, 4.0, 12.0), // East
]); ],
);
model::append_box(
&mut body_verts,
-4.2 / 16.0,
-6.2 / 16.0,
-2.2 / 16.0,
8.4 / 16.0,
12.4 / 16.0,
4.4 / 16.0,
[
srel!(28.0, 16.0 + 16.0, 8.0, 4.0), // Down
srel!(20.0, 16.0 + 16.0, 8.0, 4.0), // Up
srel!(20.0, 20.0 + 16.0, 8.0, 12.0), // North
srel!(32.0, 20.0 + 16.0, 8.0, 12.0), // South
srel!(16.0, 20.0 + 16.0, 4.0, 12.0), // West
srel!(28.0, 20.0 + 16.0, 4.0, 12.0), // East
],
);
let mut part_verts = vec![vec![]; 4]; let mut part_verts = vec![vec![]; 4];
for (i, offsets) in [ for (i, offsets) in [
[16.0, 48.0, 0.0, 48.0], // Left left [16.0, 48.0, 0.0, 48.0], // Left left
[0.0, 16.0, 0.0, 32.0], // Right Leg [0.0, 16.0, 0.0, 32.0], // Right Leg
[32.0, 48.0, 48.0, 48.0], // Left arm [32.0, 48.0, 48.0, 48.0], // Left arm
[40.0, 16.0, 40.0, 32.0], // Right arm [40.0, 16.0, 40.0, 32.0], // Right arm
].iter().enumerate() { ]
.iter()
.enumerate()
{
let (ox, oy) = (offsets[0], offsets[1]); let (ox, oy) = (offsets[0], offsets[1]);
model::append_box(&mut part_verts[i], -2.0/16.0, -12.0/16.0, -2.0/16.0, 4.0/16.0, 12.0/16.0, 4.0/16.0, [ model::append_box(
srel!(ox + 8.0, oy + 0.0, 4.0, 4.0), // Down &mut part_verts[i],
srel!(ox + 4.0, oy + 0.0, 4.0, 4.0), // Up -2.0 / 16.0,
srel!(ox + 4.0, oy + 4.0, 4.0, 12.0), // North -12.0 / 16.0,
srel!(ox + 12.0, oy + 4.0, 4.0, 12.0), // South -2.0 / 16.0,
srel!(ox + 8.0, oy + 4.0, 4.0, 12.0), // West 4.0 / 16.0,
srel!(ox + 0.0, oy + 4.0, 4.0, 12.0), // East 12.0 / 16.0,
]); 4.0 / 16.0,
[
srel!(ox + 8.0, oy + 0.0, 4.0, 4.0), // Down
srel!(ox + 4.0, oy + 0.0, 4.0, 4.0), // Up
srel!(ox + 4.0, oy + 4.0, 4.0, 12.0), // North
srel!(ox + 12.0, oy + 4.0, 4.0, 12.0), // South
srel!(ox + 8.0, oy + 4.0, 4.0, 12.0), // West
srel!(ox + 0.0, oy + 4.0, 4.0, 12.0), // East
],
);
let (ox, oy) = (offsets[2], offsets[3]); let (ox, oy) = (offsets[2], offsets[3]);
model::append_box(&mut part_verts[i], -2.2/16.0, -12.2/16.0, -2.2/16.0, 4.4/16.0, 12.4/16.0, 4.4/16.0, [ model::append_box(
srel!(ox + 8.0, oy + 0.0, 4.0, 4.0), // Down &mut part_verts[i],
srel!(ox + 4.0, oy + 0.0, 4.0, 4.0), // Up -2.2 / 16.0,
srel!(ox + 4.0, oy + 4.0, 4.0, 12.0), // North -12.2 / 16.0,
srel!(ox + 12.0, oy + 4.0, 4.0, 12.0), // South -2.2 / 16.0,
srel!(ox + 8.0, oy + 4.0, 4.0, 12.0), // West 4.4 / 16.0,
srel!(ox + 0.0, oy + 4.0, 4.0, 12.0), // East 12.4 / 16.0,
]); 4.4 / 16.0,
[
srel!(ox + 8.0, oy + 0.0, 4.0, 4.0), // Down
srel!(ox + 4.0, oy + 0.0, 4.0, 4.0), // Up
srel!(ox + 4.0, oy + 4.0, 4.0, 12.0), // North
srel!(ox + 12.0, oy + 4.0, 4.0, 12.0), // South
srel!(ox + 8.0, oy + 4.0, 4.0, 12.0), // West
srel!(ox + 0.0, oy + 4.0, 4.0, 12.0), // East
],
);
} }
let mut name_verts = vec![]; let mut name_verts = vec![];
@ -423,17 +509,27 @@ impl ecs::System for PlayerRenderer {
part_verts[1].clone(), part_verts[1].clone(),
part_verts[2].clone(), part_verts[2].clone(),
part_verts[3].clone(), part_verts[3].clone(),
name_verts name_verts,
] ],
)); ));
} }
fn entity_removed(&mut self, m: &mut ecs::Manager, e: ecs::Entity, _: &mut world::World, renderer: &mut render::Renderer) { fn entity_removed(
&mut self,
m: &mut ecs::Manager,
e: ecs::Entity,
_: &mut world::World,
renderer: &mut render::Renderer,
) {
let player_model = m.get_component_mut(e, self.player_model).unwrap(); let player_model = m.get_component_mut(e, self.player_model).unwrap();
if let Some(model) = player_model.model.take() { if let Some(model) = player_model.model.take() {
renderer.model.remove_model(model); renderer.model.remove_model(model);
if let Some(url) = player_model.skin_url.as_ref() { if let Some(url) = player_model.skin_url.as_ref() {
renderer.get_textures_ref().read().unwrap().release_skin(url); renderer
.get_textures_ref()
.read()
.unwrap()
.release_skin(url);
} }
} }
} }
@ -450,12 +546,14 @@ pub struct PlayerMovement {
} }
impl PlayerMovement { impl PlayerMovement {
pub fn new() -> PlayerMovement { Default::default() } pub fn new() -> PlayerMovement {
Default::default()
}
fn calculate_movement(&self, player_yaw: f64) -> (f64, f64) { fn calculate_movement(&self, player_yaw: f64) -> (f64, f64) {
use std::f64::consts::PI; use std::f64::consts::PI;
let mut forward = 0.0f64; let mut forward = 0.0f64;
let mut yaw = player_yaw - (PI/2.0); let mut yaw = player_yaw - (PI / 2.0);
if self.is_key_pressed(Stevenkey::Forward) || self.is_key_pressed(Stevenkey::Backward) { if self.is_key_pressed(Stevenkey::Forward) || self.is_key_pressed(Stevenkey::Backward) {
forward = 1.0; forward = 1.0;
if self.is_key_pressed(Stevenkey::Backward) { if self.is_key_pressed(Stevenkey::Backward) {
@ -466,7 +564,9 @@ impl PlayerMovement {
(PI / 2.0) / (forward.abs() + 1.0) (PI / 2.0) / (forward.abs() + 1.0)
} else if self.is_key_pressed(Stevenkey::Right) { } else if self.is_key_pressed(Stevenkey::Right) {
-(PI / 2.0) / (forward.abs() + 1.0) -(PI / 2.0) / (forward.abs() + 1.0)
} else { 0.0 }; } else {
0.0
};
if self.is_key_pressed(Stevenkey::Left) || self.is_key_pressed(Stevenkey::Right) { if self.is_key_pressed(Stevenkey::Left) || self.is_key_pressed(Stevenkey::Right) {
forward = 1.0; forward = 1.0;
} }
@ -521,7 +621,6 @@ impl MovementHandler {
} }
impl ecs::System for MovementHandler { impl ecs::System for MovementHandler {
fn filter(&self) -> &ecs::Filter { fn filter(&self) -> &ecs::Filter {
&self.filter &self.filter
} }
@ -542,8 +641,11 @@ impl ecs::System for MovementHandler {
if movement.when_last_jump_pressed.is_none() { if movement.when_last_jump_pressed.is_none() {
movement.when_last_jump_pressed = Some(Instant::now()); movement.when_last_jump_pressed = Some(Instant::now());
if !movement.when_last_jump_released.is_none() { if !movement.when_last_jump_released.is_none() {
let dt = movement.when_last_jump_pressed.unwrap() - movement.when_last_jump_released.unwrap(); let dt = movement.when_last_jump_pressed.unwrap()
if dt.as_secs() == 0 && dt.subsec_millis() <= crate::settings::DOUBLE_JUMP_MS { - movement.when_last_jump_released.unwrap();
if dt.as_secs() == 0
&& dt.subsec_millis() <= crate::settings::DOUBLE_JUMP_MS
{
movement.want_to_fly = !movement.want_to_fly; movement.want_to_fly = !movement.want_to_fly;
//info!("double jump! dt={:?} toggle want_to_fly = {}", dt, movement.want_to_fly); //info!("double jump! dt={:?} toggle want_to_fly = {}", dt, movement.want_to_fly);
@ -567,11 +669,16 @@ impl ecs::System for MovementHandler {
let mut last_position = position.position; let mut last_position = position.position;
if world.is_chunk_loaded((position.position.x as i32) >> 4, (position.position.z as i32) >> 4) { if world.is_chunk_loaded(
(position.position.x as i32) >> 4,
(position.position.z as i32) >> 4,
) {
let (forward, yaw) = movement.calculate_movement(rotation.yaw); let (forward, yaw) = movement.calculate_movement(rotation.yaw);
let mut speed = if movement.is_key_pressed(Stevenkey::Sprint) { let mut speed = if movement.is_key_pressed(Stevenkey::Sprint) {
0.2806 0.2806
} else { 0.21585 }; } else {
0.21585
};
if movement.flying { if movement.flying {
speed *= 2.5; speed *= 2.5;
@ -582,7 +689,8 @@ impl ecs::System for MovementHandler {
position.position.y -= speed; position.position.y -= speed;
} }
} else if gravity.as_ref().map_or(false, |v| v.on_ground) { } else if gravity.as_ref().map_or(false, |v| v.on_ground) {
if movement.is_key_pressed(Stevenkey::Jump) && velocity.velocity.y.abs() < 0.001 { if movement.is_key_pressed(Stevenkey::Jump) && velocity.velocity.y.abs() < 0.001
{
velocity.velocity.y = 0.42; velocity.velocity.y = 0.42;
} }
} else { } else {
@ -604,12 +712,14 @@ impl ecs::System for MovementHandler {
// We handle each axis separately to allow for a sliding // We handle each axis separately to allow for a sliding
// effect when pushing up against walls. // effect when pushing up against walls.
let (bounds, xhit) = check_collisions(world, position, &last_position, player_bounds); let (bounds, xhit) =
check_collisions(world, position, &last_position, player_bounds);
position.position.x = bounds.min.x + 0.3; position.position.x = bounds.min.x + 0.3;
last_position.x = position.position.x; last_position.x = position.position.x;
position.position.z = target.z; position.position.z = target.z;
let (bounds, zhit) = check_collisions(world, position, &last_position, player_bounds); let (bounds, zhit) =
check_collisions(world, position, &last_position, player_bounds);
position.position.z = bounds.min.z + 0.3; position.position.z = bounds.min.z + 0.3;
last_position.z = position.position.z; last_position.z = position.position.z;
@ -624,8 +734,12 @@ impl ecs::System for MovementHandler {
let mut oz = position.position.z; let mut oz = position.position.z;
position.position.x = target.x; position.position.x = target.x;
position.position.z = target.z; position.position.z = target.z;
for offset in 1 .. 9 { for offset in 1..9 {
let mini = player_bounds.add_v(cgmath::Vector3::new(0.0, offset as f64 / 16.0, 0.0)); let mini = player_bounds.add_v(cgmath::Vector3::new(
0.0,
offset as f64 / 16.0,
0.0,
));
let (_, hit) = check_collisions(world, position, &last_position, mini); let (_, hit) = check_collisions(world, position, &last_position, mini);
if !hit { if !hit {
target.y += offset as f64 / 16.0; target.y += offset as f64 / 16.0;
@ -639,7 +753,8 @@ impl ecs::System for MovementHandler {
} }
position.position.y = target.y; position.position.y = target.y;
let (bounds, yhit) = check_collisions(world, position, &last_position, player_bounds); let (bounds, yhit) =
check_collisions(world, position, &last_position, player_bounds);
position.position.y = bounds.min.y; position.position.y = bounds.min.y;
last_position.y = position.position.y; last_position.y = position.position.y;
if yhit { if yhit {
@ -647,10 +762,8 @@ impl ecs::System for MovementHandler {
} }
if let Some(gravity) = gravity { if let Some(gravity) = gravity {
let ground = Aabb3::new( let ground =
Point3::new(-0.3, -0.005, -0.3), Aabb3::new(Point3::new(-0.3, -0.005, -0.3), Point3::new(0.3, 0.0, 0.3));
Point3::new(0.3, 0.0, 0.3)
);
let prev = gravity.on_ground; let prev = gravity.on_ground;
let (_, hit) = check_collisions(world, position, &last_position, ground); let (_, hit) = check_collisions(world, position, &last_position, ground);
gravity.on_ground = hit; gravity.on_ground = hit;
@ -664,8 +777,12 @@ impl ecs::System for MovementHandler {
} }
} }
fn check_collisions(
fn check_collisions(world: &world::World, position: &mut TargetPosition, last_position: &Vector3<f64>, bounds: Aabb3<f64>) -> (Aabb3<f64>, bool) { world: &world::World,
position: &mut TargetPosition,
last_position: &Vector3<f64>,
bounds: Aabb3<f64>,
) -> (Aabb3<f64>, bool) {
let mut bounds = bounds.add_v(position.position); let mut bounds = bounds.add_v(position.position);
let dir = position.position - last_position; let dir = position.position - last_position;
@ -678,9 +795,9 @@ fn check_collisions(world: &world::World, position: &mut TargetPosition, last_po
let max_z = (bounds.max.z + 1.0) as i32; let max_z = (bounds.max.z + 1.0) as i32;
let mut hit = false; let mut hit = false;
for y in min_y .. max_y { for y in min_y..max_y {
for z in min_z .. max_z { for z in min_z..max_z {
for x in min_x .. max_x { for x in min_x..max_x {
let block = world.get_block(BPosition::new(x, y, z)); let block = world.get_block(BPosition::new(x, y, z));
if block.get_material().collidable { if block.get_material().collidable {
for bb in block.get_collision_boxes() { for bb in block.get_collision_boxes() {
@ -705,14 +822,12 @@ trait Collidable<T> {
impl Collidable<Aabb3<f64>> for Aabb3<f64> { impl Collidable<Aabb3<f64>> for Aabb3<f64> {
fn collides(&self, t: &Aabb3<f64>) -> bool { fn collides(&self, t: &Aabb3<f64>) -> bool {
!( !(t.min.x >= self.max.x
t.min.x >= self.max.x || || t.max.x <= self.min.x
t.max.x <= self.min.x || || t.min.y >= self.max.y
t.min.y >= self.max.y || || t.max.y <= self.min.y
t.max.y <= self.min.y || || t.min.z >= self.max.z
t.min.z >= self.max.z || || t.max.z <= self.min.z)
t.max.z <= self.min.z
)
} }
fn move_out_of(mut self, other: Self, dir: cgmath::Vector3<f64>) -> Self { fn move_out_of(mut self, other: Self, dir: cgmath::Vector3<f64>) -> Self {

View File

@ -1,9 +1,8 @@
use super::*; use super::*;
use crate::ecs; use crate::ecs;
use crate::world;
use crate::render; use crate::render;
use crate::shared::Position as BPos; use crate::shared::Position as BPos;
use crate::world;
use cgmath::InnerSpace; use cgmath::InnerSpace;
pub struct ApplyVelocity { pub struct ApplyVelocity {
@ -18,9 +17,7 @@ impl ApplyVelocity {
let position = m.get_key(); let position = m.get_key();
let velocity = m.get_key(); let velocity = m.get_key();
ApplyVelocity { ApplyVelocity {
filter: ecs::Filter::new() filter: ecs::Filter::new().with(position).with(velocity),
.with(position)
.with(velocity),
position, position,
velocity, velocity,
movement: m.get_key(), movement: m.get_key(),
@ -29,7 +26,6 @@ impl ApplyVelocity {
} }
impl ecs::System for ApplyVelocity { impl ecs::System for ApplyVelocity {
fn filter(&self) -> &ecs::Filter { fn filter(&self) -> &ecs::Filter {
&self.filter &self.filter
} }
@ -58,9 +54,7 @@ impl ApplyGravity {
let gravity = m.get_key::<Gravity>(); let gravity = m.get_key::<Gravity>();
let velocity = m.get_key(); let velocity = m.get_key();
ApplyGravity { ApplyGravity {
filter: ecs::Filter::new() filter: ecs::Filter::new().with(gravity).with(velocity),
.with(gravity)
.with(velocity),
velocity, velocity,
movement: m.get_key(), movement: m.get_key(),
} }
@ -68,7 +62,6 @@ impl ApplyGravity {
} }
impl ecs::System for ApplyGravity { impl ecs::System for ApplyGravity {
fn filter(&self) -> &ecs::Filter { fn filter(&self) -> &ecs::Filter {
&self.filter &self.filter
} }
@ -98,15 +91,13 @@ impl UpdateLastPosition {
pub fn new(m: &mut ecs::Manager) -> UpdateLastPosition { pub fn new(m: &mut ecs::Manager) -> UpdateLastPosition {
let position = m.get_key(); let position = m.get_key();
UpdateLastPosition { UpdateLastPosition {
filter: ecs::Filter::new() filter: ecs::Filter::new().with(position),
.with(position),
position, position,
} }
} }
} }
impl ecs::System for UpdateLastPosition { impl ecs::System for UpdateLastPosition {
fn filter(&self) -> &ecs::Filter { fn filter(&self) -> &ecs::Filter {
&self.filter &self.filter
} }
@ -133,9 +124,7 @@ impl LerpPosition {
let position = m.get_key(); let position = m.get_key();
let target_position = m.get_key(); let target_position = m.get_key();
LerpPosition { LerpPosition {
filter: ecs::Filter::new() filter: ecs::Filter::new().with(position).with(target_position),
.with(position)
.with(target_position),
position, position,
target_position, target_position,
game_info: m.get_key(), game_info: m.get_key(),
@ -144,20 +133,24 @@ impl LerpPosition {
} }
impl ecs::System for LerpPosition { impl ecs::System for LerpPosition {
fn filter(&self) -> &ecs::Filter { fn filter(&self) -> &ecs::Filter {
&self.filter &self.filter
} }
fn update(&mut self, m: &mut ecs::Manager, _: &mut world::World, _: &mut render::Renderer) { fn update(&mut self, m: &mut ecs::Manager, _: &mut world::World, _: &mut render::Renderer) {
let world_entity = m.get_world(); let world_entity = m.get_world();
let delta = m.get_component_mut(world_entity, self.game_info).unwrap().delta.min(5.0); let delta = m
.get_component_mut(world_entity, self.game_info)
.unwrap()
.delta
.min(5.0);
for e in m.find(&self.filter) { for e in m.find(&self.filter) {
let pos = m.get_component_mut(e, self.position).unwrap(); let pos = m.get_component_mut(e, self.position).unwrap();
let target_pos = m.get_component(e, self.target_position).unwrap(); let target_pos = m.get_component(e, self.target_position).unwrap();
pos.position = pos.position + (target_pos.position - pos.position) * delta * target_pos.lerp_amount; pos.position = pos.position
let len = (pos.position - target_pos.position).magnitude2() ; + (target_pos.position - pos.position) * delta * target_pos.lerp_amount;
let len = (pos.position - target_pos.position).magnitude2();
if len < 0.001 || len > 100.0 * 100.0 { if len < 0.001 || len > 100.0 * 100.0 {
pos.position = target_pos.position; pos.position = target_pos.position;
} }
@ -177,9 +170,7 @@ impl LerpRotation {
let rotation = m.get_key(); let rotation = m.get_key();
let target_rotation = m.get_key(); let target_rotation = m.get_key();
LerpRotation { LerpRotation {
filter: ecs::Filter::new() filter: ecs::Filter::new().with(rotation).with(target_rotation),
.with(rotation)
.with(target_rotation),
rotation, rotation,
target_rotation, target_rotation,
game_info: m.get_key(), game_info: m.get_key(),
@ -188,7 +179,6 @@ impl LerpRotation {
} }
impl ecs::System for LerpRotation { impl ecs::System for LerpRotation {
fn filter(&self) -> &ecs::Filter { fn filter(&self) -> &ecs::Filter {
&self.filter &self.filter
} }
@ -196,12 +186,16 @@ impl ecs::System for LerpRotation {
fn update(&mut self, m: &mut ecs::Manager, _: &mut world::World, _: &mut render::Renderer) { fn update(&mut self, m: &mut ecs::Manager, _: &mut world::World, _: &mut render::Renderer) {
use std::f64::consts::PI; use std::f64::consts::PI;
let world_entity = m.get_world(); let world_entity = m.get_world();
let delta = m.get_component_mut(world_entity, self.game_info).unwrap().delta.min(5.0); let delta = m
.get_component_mut(world_entity, self.game_info)
.unwrap()
.delta
.min(5.0);
for e in m.find(&self.filter) { for e in m.find(&self.filter) {
let rot = m.get_component_mut(e, self.rotation).unwrap(); let rot = m.get_component_mut(e, self.rotation).unwrap();
let target_rot = m.get_component_mut(e, self.target_rotation).unwrap(); let target_rot = m.get_component_mut(e, self.target_rotation).unwrap();
target_rot.yaw = (PI*2.0 + target_rot.yaw) % (PI*2.0); target_rot.yaw = (PI * 2.0 + target_rot.yaw) % (PI * 2.0);
target_rot.pitch = (PI*2.0 + target_rot.pitch) % (PI*2.0); target_rot.pitch = (PI * 2.0 + target_rot.pitch) % (PI * 2.0);
let mut delta_yaw = target_rot.yaw - rot.yaw; let mut delta_yaw = target_rot.yaw - rot.yaw;
let mut delta_pitch = target_rot.pitch - rot.pitch; let mut delta_pitch = target_rot.pitch - rot.pitch;
@ -215,8 +209,8 @@ impl ecs::System for LerpRotation {
rot.yaw += delta_yaw * 0.2 * delta; rot.yaw += delta_yaw * 0.2 * delta;
rot.pitch += delta_pitch * 0.2 * delta; rot.pitch += delta_pitch * 0.2 * delta;
rot.yaw = (PI*2.0 + rot.yaw) % (PI*2.0); rot.yaw = (PI * 2.0 + rot.yaw) % (PI * 2.0);
rot.pitch = (PI*2.0 + rot.pitch) % (PI*2.0); rot.pitch = (PI * 2.0 + rot.pitch) % (PI * 2.0);
} }
} }
} }
@ -225,7 +219,7 @@ pub struct LightEntity {
filter: ecs::Filter, filter: ecs::Filter,
position: ecs::Key<Position>, position: ecs::Key<Position>,
bounds: ecs::Key<Bounds>, bounds: ecs::Key<Bounds>,
light: ecs::Key<Light> light: ecs::Key<Light>,
} }
impl LightEntity { impl LightEntity {
@ -234,10 +228,7 @@ impl LightEntity {
let bounds = m.get_key(); let bounds = m.get_key();
let light = m.get_key(); let light = m.get_key();
LightEntity { LightEntity {
filter: ecs::Filter::new() filter: ecs::Filter::new().with(position).with(bounds).with(light),
.with(position)
.with(bounds)
.with(light),
position, position,
bounds, bounds,
light, light,
@ -246,7 +237,6 @@ impl LightEntity {
} }
impl ecs::System for LightEntity { impl ecs::System for LightEntity {
fn filter(&self) -> &ecs::Filter { fn filter(&self) -> &ecs::Filter {
&self.filter &self.filter
} }
@ -269,14 +259,13 @@ impl ecs::System for LightEntity {
let length = (bounds.bounds.max - bounds.bounds.min).magnitude() as f32; let length = (bounds.bounds.max - bounds.bounds.min).magnitude() as f32;
for y in min_y .. max_y { for y in min_y..max_y {
for z in min_z .. max_z { for z in min_z..max_z {
for x in min_x .. max_x { for x in min_x..max_x {
let dist = length - ( let dist = length
((x as f32 + 0.5) - pos.position.x as f32).powi(2) - (((x as f32 + 0.5) - pos.position.x as f32).powi(2)
+ ((y as f32 + 0.5) - pos.position.y as f32).powi(2) + ((y as f32 + 0.5) - pos.position.y as f32).powi(2)
+ ((z as f32 + 0.5) - pos.position.z as f32).powi(2) + ((z as f32 + 0.5) - pos.position.z as f32).powi(2))
)
.sqrt() .sqrt()
.min(length); .min(length);
let dist = dist / length; let dist = dist / length;

View File

@ -14,15 +14,15 @@
extern crate steven_gl as gl; extern crate steven_gl as gl;
use std::ops::BitOr; use log::{error, info};
use std::ffi; use std::ffi;
use std::mem; use std::mem;
use std::ptr; use std::ops::BitOr;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use log::{error, info}; use std::ptr;
/// Inits the gl library. This should be called once a context is ready. /// Inits the gl library. This should be called once a context is ready.
pub fn init(vid: & glutin::WindowedContext<glutin::PossiblyCurrent>) { pub fn init(vid: &glutin::WindowedContext<glutin::PossiblyCurrent>) {
gl::load_with(|s| vid.get_proc_address(s) as *const _); gl::load_with(|s| vid.get_proc_address(s) as *const _);
} }
@ -54,7 +54,13 @@ pub fn draw_elements(ty: DrawType, count: i32, dty: Type, offset: usize) {
pub fn multi_draw_elements(ty: DrawType, count: &[i32], dty: Type, offsets: &[usize]) { pub fn multi_draw_elements(ty: DrawType, count: &[i32], dty: Type, offsets: &[usize]) {
unsafe { unsafe {
gl::MultiDrawElements(ty, count.as_ptr(), dty, offsets.as_ptr() as *const _, count.len() as i32); gl::MultiDrawElements(
ty,
count.as_ptr(),
dty,
offsets.as_ptr() as *const _,
count.len() as i32,
);
} }
} }
@ -107,7 +113,9 @@ pub fn clear(flags: ClearFlags) {
} }
pub fn depth_mask(f: bool) { pub fn depth_mask(f: bool) {
unsafe { gl::DepthMask(f as u8); } unsafe {
gl::DepthMask(f as u8);
}
} }
/// `Func` is a function to be preformed on two values. /// `Func` is a function to be preformed on two values.
@ -171,7 +179,12 @@ pub fn blend_func(s_factor: Factor, d_factor: Factor) {
} }
} }
pub fn blend_func_separate(s_factor_rgb: Factor, d_factor_rgb: Factor, s_factor_a: Factor, d_factor_a: Factor) { pub fn blend_func_separate(
s_factor_rgb: Factor,
d_factor_rgb: Factor,
s_factor_a: Factor,
d_factor_a: Factor,
) {
unsafe { unsafe {
gl::BlendFuncSeparate(s_factor_rgb, d_factor_rgb, s_factor_a, d_factor_a); gl::BlendFuncSeparate(s_factor_rgb, d_factor_rgb, s_factor_a, d_factor_a);
} }
@ -270,180 +283,208 @@ impl Texture {
} }
} }
pub fn get_pixels(&self, pub fn get_pixels(
target: TextureTarget, &self,
level: i32, target: TextureTarget,
format: TextureFormat, level: i32,
ty: Type, format: TextureFormat,
pixels: &mut [u8]) { ty: Type,
pixels: &mut [u8],
) {
unsafe { unsafe {
gl::GetTexImage(target, gl::GetTexImage(
level, target,
format, level,
ty, format,
pixels.as_mut_ptr() as *mut gl::types::GLvoid); ty,
pixels.as_mut_ptr() as *mut gl::types::GLvoid,
);
} }
} }
pub fn image_2d(&self, pub fn image_2d(
target: TextureTarget, &self,
level: i32, target: TextureTarget,
width: u32, level: i32,
height: u32, width: u32,
format: TextureFormat, height: u32,
ty: Type, format: TextureFormat,
pix: Option<&[u8]>) { ty: Type,
pix: Option<&[u8]>,
) {
unsafe { unsafe {
let ptr = match pix { let ptr = match pix {
Some(val) => val.as_ptr() as *const gl::types::GLvoid, Some(val) => val.as_ptr() as *const gl::types::GLvoid,
None => ptr::null(), None => ptr::null(),
}; };
gl::TexImage2D(target, gl::TexImage2D(
level, target,
format as i32, level,
width as i32, format as i32,
height as i32, width as i32,
0, height as i32,
format, 0,
ty, format,
ptr ty,
ptr,
); );
} }
} }
pub fn sub_image_2d(&self, pub fn sub_image_2d(
target: TextureTarget, &self,
level: i32, target: TextureTarget,
x: u32, level: i32,
y: u32, x: u32,
width: u32, y: u32,
height: u32, width: u32,
format: TextureFormat, height: u32,
ty: Type, format: TextureFormat,
pix: &[u8]) { ty: Type,
pix: &[u8],
) {
unsafe { unsafe {
gl::TexSubImage2D(target, gl::TexSubImage2D(
level, target,
x as i32, level,
y as i32, x as i32,
width as i32, y as i32,
height as i32, width as i32,
format, height as i32,
ty, format,
pix.as_ptr() as *const _ ty,
pix.as_ptr() as *const _,
); );
} }
} }
pub fn image_2d_ex(&self, pub fn image_2d_ex(
target: TextureTarget, &self,
level: i32, target: TextureTarget,
width: u32, level: i32,
height: u32, width: u32,
internal_format: TextureFormat, height: u32,
format: TextureFormat, internal_format: TextureFormat,
ty: Type, format: TextureFormat,
pix: Option<&[u8]>) { ty: Type,
pix: Option<&[u8]>,
) {
unsafe { unsafe {
let ptr = match pix { let ptr = match pix {
Some(val) => val.as_ptr() as *const gl::types::GLvoid, Some(val) => val.as_ptr() as *const gl::types::GLvoid,
None => ptr::null(), None => ptr::null(),
}; };
gl::TexImage2D(target, gl::TexImage2D(
level, target,
internal_format as i32, level,
width as i32, internal_format as i32,
height as i32, width as i32,
0, height as i32,
format, 0,
ty, format,
ptr ty,
ptr,
); );
} }
} }
pub fn image_2d_sample(&self, pub fn image_2d_sample(
target: TextureTarget, &self,
samples: i32, target: TextureTarget,
width: u32, samples: i32,
height: u32, width: u32,
format: TextureFormat, height: u32,
fixed: bool) { format: TextureFormat,
fixed: bool,
) {
unsafe { unsafe {
let result: &mut [i32] = &mut [0; 1]; let result: &mut [i32] = &mut [0; 1];
gl::GetIntegerv(gl::MAX_SAMPLES, &mut result[0]); gl::GetIntegerv(gl::MAX_SAMPLES, &mut result[0]);
let use_samples = let use_samples = if samples > result[0] {
if samples > result[0] { info!(
info!("glTexImage2DMultisample: requested {} samples but GL_MAX_SAMPLES is {}", samples, result[0]); "glTexImage2DMultisample: requested {} samples but GL_MAX_SAMPLES is {}",
result[0] samples, result[0]
} else { );
samples result[0]
}; } else {
samples
};
gl::TexImage2DMultisample(target, gl::TexImage2DMultisample(
use_samples, target,
format, use_samples,
width as i32, format,
height as i32, width as i32,
fixed as u8 height as i32,
fixed as u8,
); );
} }
} }
pub fn image_3d(&self, pub fn image_3d(
target: TextureTarget, &self,
level: i32, target: TextureTarget,
width: u32, level: i32,
height: u32, width: u32,
depth: u32, height: u32,
format: TextureFormat, depth: u32,
ty: Type, format: TextureFormat,
pix: &[u8]) { ty: Type,
pix: &[u8],
) {
unsafe { unsafe {
gl::TexImage3D(target, gl::TexImage3D(
level, target,
format as i32, level,
width as i32, format as i32,
height as i32, width as i32,
depth as i32, height as i32,
0, depth as i32,
format, 0,
ty, format,
pix.as_ptr() as *const gl::types::GLvoid); ty,
pix.as_ptr() as *const gl::types::GLvoid,
);
} }
} }
pub fn sub_image_3d(&self, pub fn sub_image_3d(
target: TextureTarget, &self,
level: i32, target: TextureTarget,
x: u32, level: i32,
y: u32, x: u32,
z: u32, y: u32,
width: u32, z: u32,
height: u32, width: u32,
depth: u32, height: u32,
format: TextureFormat, depth: u32,
ty: Type, format: TextureFormat,
pix: &[u8]) { ty: Type,
pix: &[u8],
) {
unsafe { unsafe {
gl::TexSubImage3D(target, gl::TexSubImage3D(
level, target,
x as i32, level,
y as i32, x as i32,
z as i32, y as i32,
width as i32, z as i32,
height as i32, width as i32,
depth as i32, height as i32,
format, depth as i32,
ty, format,
pix.as_ptr() as *const gl::types::GLvoid); ty,
pix.as_ptr() as *const gl::types::GLvoid,
);
} }
} }
pub fn set_parameter(&self, pub fn set_parameter(
target: TextureTarget, &self,
param: TextureParameter, target: TextureTarget,
value: TextureValue) { param: TextureParameter,
value: TextureValue,
) {
unsafe { unsafe {
gl::TexParameteri(target, param, value); gl::TexParameteri(target, param, value);
} }
@ -495,9 +536,8 @@ impl Program {
} }
pub fn uniform_location(&self, name: &str) -> Option<Uniform> { pub fn uniform_location(&self, name: &str) -> Option<Uniform> {
let u = unsafe { let u =
gl::GetUniformLocation(self.0, ffi::CString::new(name).unwrap().as_ptr()) unsafe { gl::GetUniformLocation(self.0, ffi::CString::new(name).unwrap().as_ptr()) };
};
if u != -1 { if u != -1 {
Some(Uniform(u)) Some(Uniform(u))
} else { } else {
@ -536,10 +576,7 @@ impl Shader {
pub fn set_source(&self, src: &str) { pub fn set_source(&self, src: &str) {
unsafe { unsafe {
let src_c = ffi::CString::new(src).unwrap(); let src_c = ffi::CString::new(src).unwrap();
gl::ShaderSource(self.0, gl::ShaderSource(self.0, 1, &src_c.as_ptr(), ptr::null());
1,
&src_c.as_ptr(),
ptr::null());
} }
} }
@ -624,7 +661,8 @@ impl Uniform {
pub fn set_matrix4_multi(&self, m: &[::cgmath::Matrix4<f32>]) { pub fn set_matrix4_multi(&self, m: &[::cgmath::Matrix4<f32>]) {
unsafe { unsafe {
gl::UniformMatrix4fv(self.0, m.len() as i32, false as u8, m.as_ptr() as *const _); // TODO: Most likely isn't safe gl::UniformMatrix4fv(self.0, m.len() as i32, false as u8, m.as_ptr() as *const _);
// TODO: Most likely isn't safe
} }
} }
} }
@ -647,22 +685,26 @@ impl Attribute {
pub fn vertex_pointer(&self, size: i32, ty: Type, normalized: bool, stride: i32, offset: i32) { pub fn vertex_pointer(&self, size: i32, ty: Type, normalized: bool, stride: i32, offset: i32) {
unsafe { unsafe {
gl::VertexAttribPointer(self.0 as u32, gl::VertexAttribPointer(
size, self.0 as u32,
ty, size,
normalized as u8, ty,
stride, normalized as u8,
offset as *const gl::types::GLvoid); stride,
offset as *const gl::types::GLvoid,
);
} }
} }
pub fn vertex_pointer_int(&self, size: i32, ty: Type, stride: i32, offset: i32) { pub fn vertex_pointer_int(&self, size: i32, ty: Type, stride: i32, offset: i32) {
unsafe { unsafe {
gl::VertexAttribIPointer(self.0 as u32, gl::VertexAttribIPointer(
size, self.0 as u32,
ty, size,
stride, ty,
offset as *const gl::types::GLvoid); stride,
offset as *const gl::types::GLvoid,
);
} }
} }
} }
@ -753,10 +795,12 @@ impl Buffer {
pub fn set_data(&self, target: BufferTarget, data: &[u8], usage: BufferUsage) { pub fn set_data(&self, target: BufferTarget, data: &[u8], usage: BufferUsage) {
unsafe { unsafe {
gl::BufferData(target, gl::BufferData(
data.len() as isize, target,
data.as_ptr() as *const gl::types::GLvoid, data.len() as isize,
usage); data.as_ptr() as *const gl::types::GLvoid,
usage,
);
} }
} }
@ -832,11 +876,12 @@ pub struct Framebuffer(u32);
pub fn check_framebuffer_status() { pub fn check_framebuffer_status() {
unsafe { unsafe {
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER); let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
let s = let s = match status {
match status {
gl::FRAMEBUFFER_UNDEFINED => "GL_FRAMEBUFFER_UNDEFINED", gl::FRAMEBUFFER_UNDEFINED => "GL_FRAMEBUFFER_UNDEFINED",
gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT", gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT",
gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT", gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => {
"GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"
}
gl::FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER => "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER", gl::FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER => "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER",
gl::FRAMEBUFFER_INCOMPLETE_READ_BUFFER => "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER", gl::FRAMEBUFFER_INCOMPLETE_READ_BUFFER => "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER",
gl::FRAMEBUFFER_UNSUPPORTED => "GL_FRAMEBUFFER_UNSUPPORTED", gl::FRAMEBUFFER_UNSUPPORTED => "GL_FRAMEBUFFER_UNSUPPORTED",
@ -845,11 +890,14 @@ pub fn check_framebuffer_status() {
gl::FRAMEBUFFER_COMPLETE => "GL_FRAMEBUFFER_COMPLETE", gl::FRAMEBUFFER_COMPLETE => "GL_FRAMEBUFFER_COMPLETE",
//gl::FRAMEBUFFER_INCOMPLETE_DIMENSIONS => "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS", //gl::FRAMEBUFFER_INCOMPLETE_DIMENSIONS => "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS",
_ => "unknown" _ => "unknown",
}; };
if status != gl::FRAMEBUFFER_COMPLETE { if status != gl::FRAMEBUFFER_COMPLETE {
panic!("glBindFramebuffer failed, glCheckFrameBufferStatus(GL_FRAMEBUFFER) = {} {}", status, s); panic!(
"glBindFramebuffer failed, glCheckFrameBufferStatus(GL_FRAMEBUFFER) = {} {}",
status, s
);
} }
} }
} }
@ -859,7 +907,7 @@ pub fn check_gl_error() {
loop { loop {
let err = gl::GetError(); let err = gl::GetError();
if err == gl::NO_ERROR { if err == gl::NO_ERROR {
break break;
} }
error!("glGetError = {}", err); error!("glGetError = {}", err);
@ -894,7 +942,13 @@ impl Framebuffer {
} }
} }
pub fn texture_2d(&self, attachment: Attachment, target: TextureTarget, tex: &Texture, level: i32) { pub fn texture_2d(
&self,
attachment: Attachment,
target: TextureTarget,
tex: &Texture,
level: i32,
) {
unsafe { unsafe {
gl::FramebufferTexture2D(gl::FRAMEBUFFER, attachment, target, tex.0, level); gl::FramebufferTexture2D(gl::FRAMEBUFFER, attachment, target, tex.0, level);
} }
@ -929,10 +983,7 @@ pub fn unbind_framebuffer_draw() {
pub fn draw_buffers(bufs: &[Attachment]) { pub fn draw_buffers(bufs: &[Attachment]) {
unsafe { unsafe {
gl::DrawBuffers( gl::DrawBuffers(bufs.len() as i32, bufs.as_ptr());
bufs.len() as i32,
bufs.as_ptr()
);
} }
} }
@ -944,14 +995,29 @@ pub fn bind_frag_data_location(p: &Program, cn: u32, name: &str) {
} }
pub fn blit_framebuffer( pub fn blit_framebuffer(
sx0: i32, sy0: i32, sx1: i32, sy1: i32, sx0: i32,
dx0: i32, dy0: i32, dx1: i32, dy1: i32, sy0: i32,
mask: ClearFlags, filter: TextureValue) { sx1: i32,
sy1: i32,
dx0: i32,
dy0: i32,
dx1: i32,
dy1: i32,
mask: ClearFlags,
filter: TextureValue,
) {
unsafe { unsafe {
gl::BlitFramebuffer( gl::BlitFramebuffer(
sx0, sy0, sx1, sy1, sx0,
dx0, dy0, dx1, dy1, sy0,
mask.internal(), filter as u32 sx1,
sy1,
dx0,
dy0,
dx1,
dy1,
mask.internal(),
filter as u32,
); );
} }
} }

View File

@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#![recursion_limit="300"] #![recursion_limit = "300"]
use std::time::{Instant, Duration}; use log::{error, info, warn};
use log::{info, warn, error}; use std::time::{Duration, Instant};
extern crate steven_shared as shared; extern crate steven_shared as shared;
use structopt::StructOpt; use structopt::StructOpt;
@ -23,32 +23,32 @@ use structopt::StructOpt;
extern crate steven_protocol; extern crate steven_protocol;
pub mod ecs; pub mod ecs;
use steven_protocol::protocol as protocol; use steven_protocol::format;
use steven_protocol::format as format; use steven_protocol::nbt;
use steven_protocol::nbt as nbt; use steven_protocol::protocol;
pub mod gl; pub mod gl;
use steven_protocol::types as types; use steven_protocol::types;
pub mod resources;
pub mod render;
pub mod ui;
pub mod screen;
pub mod settings;
pub mod console;
pub mod server;
pub mod world;
pub mod chunk_builder;
pub mod auth; pub mod auth;
pub mod model; pub mod chunk_builder;
pub mod console;
pub mod entity; pub mod entity;
pub mod model;
pub mod render;
pub mod resources;
pub mod screen;
pub mod server;
pub mod settings;
pub mod ui;
pub mod world;
use cfg_if::cfg_if;
use std::sync::{Arc, RwLock, Mutex};
use std::rc::Rc;
use std::marker::PhantomData;
use std::thread;
use std::sync::mpsc;
use crate::protocol::mojang; use crate::protocol::mojang;
use cfg_if::cfg_if;
use glutin; use glutin;
use std::marker::PhantomData;
use std::rc::Rc;
use std::sync::mpsc;
use std::sync::{Arc, Mutex, RwLock};
use std::thread;
const CL_BRAND: console::CVar<String> = console::CVar { const CL_BRAND: console::CVar<String> = console::CVar {
ty: PhantomData, ty: PhantomData,
@ -87,16 +87,24 @@ pub struct Game {
impl Game { impl Game {
pub fn connect_to(&mut self, address: &str) { pub fn connect_to(&mut self, address: &str) {
let (protocol_version, forge_mods) = match protocol::Conn::new(&address, self.default_protocol_version) let (protocol_version, forge_mods) =
.and_then(|conn| conn.do_status()) { match protocol::Conn::new(&address, self.default_protocol_version)
.and_then(|conn| conn.do_status())
{
Ok(res) => { Ok(res) => {
info!("Detected server protocol version {}", res.0.version.protocol); info!(
"Detected server protocol version {}",
res.0.version.protocol
);
(res.0.version.protocol, res.0.forge_mods) (res.0.version.protocol, res.0.forge_mods)
}, }
Err(err) => { Err(err) => {
warn!("Error pinging server {} to get protocol version: {:?}, defaulting to {}", address, err, self.default_protocol_version); warn!(
"Error pinging server {} to get protocol version: {:?}, defaulting to {}",
address, err, self.default_protocol_version
);
(self.default_protocol_version, vec![]) (self.default_protocol_version, vec![])
}, }
}; };
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
@ -109,7 +117,14 @@ impl Game {
access_token: self.vars.get(auth::AUTH_TOKEN).clone(), access_token: self.vars.get(auth::AUTH_TOKEN).clone(),
}; };
thread::spawn(move || { thread::spawn(move || {
tx.send(server::Server::connect(resources, profile, &address, protocol_version, forge_mods)).unwrap(); tx.send(server::Server::connect(
resources,
profile,
&address,
protocol_version,
forge_mods,
))
.unwrap();
}); });
} }
@ -122,9 +137,8 @@ impl Game {
} }
if let Some(disconnect_reason) = self.server.disconnect_reason.take() { if let Some(disconnect_reason) = self.server.disconnect_reason.take() {
self.screen_sys.replace_screen(Box::new(screen::ServerList::new( self.screen_sys
Some(disconnect_reason) .replace_screen(Box::new(screen::ServerList::new(Some(disconnect_reason))));
)));
} }
if !self.server.is_connected() { if !self.server.is_connected() {
self.focused = false; self.focused = false;
@ -140,7 +154,7 @@ impl Game {
self.focused = true; self.focused = true;
self.server.remove(&mut self.renderer); self.server.remove(&mut self.renderer);
self.server = val; self.server = val;
}, }
Err(err) => { Err(err) => {
let msg = match err { let msg = match err {
protocol::Error::Disconnect(val) => val, protocol::Error::Disconnect(val) => val,
@ -148,11 +162,10 @@ impl Game {
let mut msg = format::TextComponent::new(&format!("{}", err)); let mut msg = format::TextComponent::new(&format!("{}", err));
msg.modifier.color = Some(format::Color::Red); msg.modifier.color = Some(format::Color::Red);
format::Component::Text(msg) format::Component::Text(msg)
}, }
}; };
self.screen_sys.replace_screen(Box::new(screen::ServerList::new( self.screen_sys
Some(msg) .replace_screen(Box::new(screen::ServerList::new(Some(msg))));
)));
} }
} }
} }
@ -240,14 +253,19 @@ fn main2() {
let window = glutin::ContextBuilder::new() let window = glutin::ContextBuilder::new()
.with_stencil_buffer(0) .with_stencil_buffer(0)
.with_depth_buffer(24) .with_depth_buffer(24)
.with_gl(glutin::GlRequest::GlThenGles{opengl_version: (3, 2), opengles_version: (2, 0)}) .with_gl(glutin::GlRequest::GlThenGles {
opengl_version: (3, 2),
opengles_version: (2, 0),
})
.with_gl_profile(glutin::GlProfile::Core) .with_gl_profile(glutin::GlProfile::Core)
.with_vsync(vsync) .with_vsync(vsync)
.build_windowed(window_builder, &events_loop) .build_windowed(window_builder, &events_loop)
.expect("Could not create glutin window."); .expect("Could not create glutin window.");
let mut window = unsafe { let mut window = unsafe {
window.make_current().expect("Could not set current context.") window
.make_current()
.expect("Could not set current context.")
}; };
gl::init(&window); gl::init(&window);
@ -271,14 +289,15 @@ fn main2() {
} }
} }
if let Some(username) = opt.username{ if let Some(username) = opt.username {
vars.set(auth::CL_USERNAME, username); vars.set(auth::CL_USERNAME, username);
} }
let textures = renderer.get_textures(); let textures = renderer.get_textures();
let dpi_factor = window.window().scale_factor(); let dpi_factor = window.window().scale_factor();
let default_protocol_version = protocol::versions::protocol_name_to_protocol_version( let default_protocol_version = protocol::versions::protocol_name_to_protocol_version(
opt.default_protocol_version.unwrap_or("".to_string())); opt.default_protocol_version.unwrap_or("".to_string()),
);
let mut game = Game { let mut game = Game {
server: server::Server::dummy_server(resource_manager.clone()), server: server::Server::dummy_server(resource_manager.clone()),
focused: false, focused: false,
@ -359,15 +378,24 @@ fn main2() {
game.renderer.update_camera(physical_width, physical_height); game.renderer.update_camera(physical_width, physical_height);
game.server.world.compute_render_list(&mut game.renderer); game.server.world.compute_render_list(&mut game.renderer);
game.chunk_builder.tick(&mut game.server.world, &mut game.renderer, version); game.chunk_builder
.tick(&mut game.server.world, &mut game.renderer, version);
game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container); game.screen_sys
.tick(delta, &mut game.renderer, &mut ui_container);
game.console game.console
.lock() .lock()
.unwrap() .unwrap()
.tick(&mut ui_container, &game.renderer, delta, width as f64); .tick(&mut ui_container, &game.renderer, delta, width as f64);
ui_container.tick(&mut game.renderer, delta, width as f64, height as f64); ui_container.tick(&mut game.renderer, delta, width as f64, height as f64);
game.renderer.tick(&mut game.server.world, delta, width, height, physical_width, physical_height); game.renderer.tick(
&mut game.server.world,
delta,
width,
height,
physical_width,
physical_height,
);
if fps_cap > 0 && !vsync { if fps_cap > 0 && !vsync {
let frame_time = now.elapsed(); let frame_time = now.elapsed();
@ -384,32 +412,38 @@ fn main2() {
}); });
} }
fn handle_window_event<T>(window: &mut glutin::WindowedContext<glutin::PossiblyCurrent>, fn handle_window_event<T>(
game: &mut Game, window: &mut glutin::WindowedContext<glutin::PossiblyCurrent>,
ui_container: &mut ui::Container, game: &mut Game,
event: glutin::event::Event<T>) -> bool { ui_container: &mut ui::Container,
event: glutin::event::Event<T>,
) -> bool {
use glutin::event::*; use glutin::event::*;
match event { match event {
Event::MainEventsCleared => return true, Event::MainEventsCleared => return true,
Event::DeviceEvent{event, ..} => match event { Event::DeviceEvent { event, .. } => match event {
DeviceEvent::ModifiersChanged(modifiers_state) => { DeviceEvent::ModifiersChanged(modifiers_state) => {
game.is_ctrl_pressed = modifiers_state.ctrl(); game.is_ctrl_pressed = modifiers_state.ctrl();
game.is_logo_pressed = modifiers_state.logo(); game.is_logo_pressed = modifiers_state.logo();
}, }
DeviceEvent::MouseMotion{delta:(xrel, yrel)} => { DeviceEvent::MouseMotion {
let (rx, ry) = delta: (xrel, yrel),
if xrel > 1000.0 || yrel > 1000.0 { } => {
// Heuristic for if we were passed an absolute value instead of relative let (rx, ry) = if xrel > 1000.0 || yrel > 1000.0 {
// Workaround https://github.com/tomaka/glutin/issues/1084 MouseMotion event returns absolute instead of relative values, when running Linux in a VM // Heuristic for if we were passed an absolute value instead of relative
// Note SDL2 had a hint to handle this scenario: // Workaround https://github.com/tomaka/glutin/issues/1084 MouseMotion event returns absolute instead of relative values, when running Linux in a VM
// sdl2::hint::set_with_priority("SDL_MOUSE_RELATIVE_MODE_WARP", "1", &sdl2::hint::Hint::Override); // Note SDL2 had a hint to handle this scenario:
let s = 8000.0 + 0.01; // sdl2::hint::set_with_priority("SDL_MOUSE_RELATIVE_MODE_WARP", "1", &sdl2::hint::Hint::Override);
((xrel - game.last_mouse_xrel) / s, (yrel - game.last_mouse_yrel) / s) let s = 8000.0 + 0.01;
} else { (
let s = 2000.0 + 0.01; (xrel - game.last_mouse_xrel) / s,
(xrel / s, yrel / s) (yrel - game.last_mouse_yrel) / s,
}; )
} else {
let s = 2000.0 + 0.01;
(xrel / s, yrel / s)
};
game.last_mouse_xrel = xrel; game.last_mouse_xrel = xrel;
game.last_mouse_yrel = yrel; game.last_mouse_yrel = yrel;
@ -420,46 +454,57 @@ fn handle_window_event<T>(window: &mut glutin::WindowedContext<glutin::PossiblyC
window.window().set_cursor_grab(true).unwrap(); window.window().set_cursor_grab(true).unwrap();
window.window().set_cursor_visible(false); window.window().set_cursor_visible(false);
if let Some(player) = game.server.player { if let Some(player) = game.server.player {
let rotation = game.server.entities.get_component_mut(player, game.server.rotation).unwrap(); let rotation = game
.server
.entities
.get_component_mut(player, game.server.rotation)
.unwrap();
rotation.yaw -= rx; rotation.yaw -= rx;
rotation.pitch -= ry; rotation.pitch -= ry;
if rotation.pitch < (PI/2.0) + 0.01 { if rotation.pitch < (PI / 2.0) + 0.01 {
rotation.pitch = (PI/2.0) + 0.01; rotation.pitch = (PI / 2.0) + 0.01;
} }
if rotation.pitch > (PI/2.0)*3.0 - 0.01 { if rotation.pitch > (PI / 2.0) * 3.0 - 0.01 {
rotation.pitch = (PI/2.0)*3.0 - 0.01; rotation.pitch = (PI / 2.0) * 3.0 - 0.01;
} }
} }
} else { } else {
window.window().set_cursor_grab(false).unwrap(); window.window().set_cursor_grab(false).unwrap();
window.window().set_cursor_visible(true); window.window().set_cursor_visible(true);
} }
},
_ => ()
},
Event::WindowEvent{event, ..} => match event {
WindowEvent::CloseRequested => game.should_close = true,
WindowEvent::Resized(physical_size) => {
window.resize(physical_size);
},
WindowEvent::ScaleFactorChanged{scale_factor, ..} => {
game.dpi_factor = scale_factor;
} }
WindowEvent::ReceivedCharacter(codepoint) => { _ => (),
if !game.focused { },
ui_container.key_type(game, codepoint);
Event::WindowEvent { event, .. } => {
match event {
WindowEvent::CloseRequested => game.should_close = true,
WindowEvent::Resized(physical_size) => {
window.resize(physical_size);
}
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
game.dpi_factor = scale_factor;
} }
},
WindowEvent::MouseInput{state, button, ..} => { WindowEvent::ReceivedCharacter(codepoint) => {
match (state, button) { if !game.focused {
ui_container.key_type(game, codepoint);
}
}
WindowEvent::MouseInput { state, button, .. } => match (state, button) {
(ElementState::Released, MouseButton::Left) => { (ElementState::Released, MouseButton::Left) => {
let (width, height) = window.window().inner_size().to_logical::<f64>(game.dpi_factor).into(); let (width, height) = window
.window()
.inner_size()
.to_logical::<f64>(game.dpi_factor)
.into();
if game.server.is_connected() && !game.focused && !game.screen_sys.is_current_closable() { if game.server.is_connected()
&& !game.focused
&& !game.screen_sys.is_current_closable()
{
game.focused = true; game.focused = true;
window.window().set_cursor_grab(true).unwrap(); window.window().set_cursor_grab(true).unwrap();
window.window().set_cursor_visible(false); window.window().set_cursor_visible(false);
@ -467,94 +512,114 @@ fn handle_window_event<T>(window: &mut glutin::WindowedContext<glutin::PossiblyC
if !game.focused { if !game.focused {
window.window().set_cursor_grab(false).unwrap(); window.window().set_cursor_grab(false).unwrap();
window.window().set_cursor_visible(true); window.window().set_cursor_visible(true);
ui_container.click_at(game, game.last_mouse_x, game.last_mouse_y, width, height); ui_container.click_at(
game,
game.last_mouse_x,
game.last_mouse_y,
width,
height,
);
} }
} }
}, }
(ElementState::Pressed, MouseButton::Right) => { (ElementState::Pressed, MouseButton::Right) => {
if game.focused { if game.focused {
game.server.on_right_click(&mut game.renderer); game.server.on_right_click(&mut game.renderer);
} }
}, }
(_, _) => () (_, _) => (),
} },
}, WindowEvent::CursorMoved { position, .. } => {
WindowEvent::CursorMoved{position, ..} => { let (x, y) = position.into();
let (x, y) = position.into(); game.last_mouse_x = x;
game.last_mouse_x = x; game.last_mouse_y = y;
game.last_mouse_y = y;
if !game.focused { if !game.focused {
let (width, height) = window.window().inner_size().to_logical::<f64>(game.dpi_factor).into(); let (width, height) = window
ui_container.hover_at(game, x, y, width, height); .window()
.inner_size()
.to_logical::<f64>(game.dpi_factor)
.into();
ui_container.hover_at(game, x, y, width, height);
}
} }
}, WindowEvent::MouseWheel { delta, .. } => {
WindowEvent::MouseWheel{delta, ..} => { // TODO: line vs pixel delta? does pixel scrolling (e.g. touchpad) need scaling?
// TODO: line vs pixel delta? does pixel scrolling (e.g. touchpad) need scaling? match delta {
match delta { MouseScrollDelta::LineDelta(x, y) => {
MouseScrollDelta::LineDelta(x, y) => { game.screen_sys.on_scroll(x.into(), y.into());
game.screen_sys.on_scroll(x.into(), y.into()); }
}, MouseScrollDelta::PixelDelta(position) => {
MouseScrollDelta::PixelDelta(position) => { let (x, y) = position.into();
let (x, y) = position.into(); game.screen_sys.on_scroll(x, y);
game.screen_sys.on_scroll(x, y);
},
}
},
WindowEvent::KeyboardInput{input, ..} => {
match (input.state, input.virtual_keycode) {
(ElementState::Released, Some(VirtualKeyCode::Escape)) => {
if game.focused {
window.window().set_cursor_grab(false).unwrap();
window.window().set_cursor_visible(true);
game.focused = false;
game.screen_sys.replace_screen(Box::new(screen::SettingsMenu::new(game.vars.clone(), true)));
} else if game.screen_sys.is_current_closable() {
window.window().set_cursor_grab(true).unwrap();
window.window().set_cursor_visible(false);
game.focused = true;
game.screen_sys.pop_screen();
} }
} }
(ElementState::Pressed, Some(VirtualKeyCode::Grave)) => {
game.console.lock().unwrap().toggle();
},
(ElementState::Pressed, Some(VirtualKeyCode::F11)) => {
if !game.is_fullscreen {
// TODO: support options for exclusive and simple fullscreen
// see https://docs.rs/glutin/0.22.0-alpha5/glutin/window/struct.Window.html#method.set_fullscreen
window.window().set_fullscreen(Some(glutin::window::Fullscreen::Borderless(window.window().current_monitor())));
} else {
window.window().set_fullscreen(None);
}
game.is_fullscreen = !game.is_fullscreen;
},
(ElementState::Pressed, Some(key)) => {
if game.focused {
if let Some(steven_key) = settings::Stevenkey::get_by_keycode(key, &game.vars) {
game.server.key_press(true, steven_key);
}
} else {
let ctrl_pressed = game.is_ctrl_pressed || game.is_logo_pressed;
ui_container.key_press(game, key, true, ctrl_pressed);
}
},
(ElementState::Released, Some(key)) => {
if game.focused {
if let Some(steven_key) = settings::Stevenkey::get_by_keycode(key, &game.vars) {
game.server.key_press(false, steven_key);
}
} else {
let ctrl_pressed = game.is_ctrl_pressed;
ui_container.key_press(game, key, false, ctrl_pressed);
}
},
(_, None) => ()
} }
}, WindowEvent::KeyboardInput { input, .. } => {
_ => () match (input.state, input.virtual_keycode) {
}, (ElementState::Released, Some(VirtualKeyCode::Escape)) => {
if game.focused {
window.window().set_cursor_grab(false).unwrap();
window.window().set_cursor_visible(true);
game.focused = false;
game.screen_sys.replace_screen(Box::new(
screen::SettingsMenu::new(game.vars.clone(), true),
));
} else if game.screen_sys.is_current_closable() {
window.window().set_cursor_grab(true).unwrap();
window.window().set_cursor_visible(false);
game.focused = true;
game.screen_sys.pop_screen();
}
}
(ElementState::Pressed, Some(VirtualKeyCode::Grave)) => {
game.console.lock().unwrap().toggle();
}
(ElementState::Pressed, Some(VirtualKeyCode::F11)) => {
if !game.is_fullscreen {
// TODO: support options for exclusive and simple fullscreen
// see https://docs.rs/glutin/0.22.0-alpha5/glutin/window/struct.Window.html#method.set_fullscreen
window.window().set_fullscreen(Some(
glutin::window::Fullscreen::Borderless(
window.window().current_monitor(),
),
));
} else {
window.window().set_fullscreen(None);
}
game.is_fullscreen = !game.is_fullscreen;
}
(ElementState::Pressed, Some(key)) => {
if game.focused {
if let Some(steven_key) =
settings::Stevenkey::get_by_keycode(key, &game.vars)
{
game.server.key_press(true, steven_key);
}
} else {
let ctrl_pressed = game.is_ctrl_pressed || game.is_logo_pressed;
ui_container.key_press(game, key, true, ctrl_pressed);
}
}
(ElementState::Released, Some(key)) => {
if game.focused {
if let Some(steven_key) =
settings::Stevenkey::get_by_keycode(key, &game.vars)
{
game.server.key_press(false, steven_key);
}
} else {
let ctrl_pressed = game.is_ctrl_pressed;
ui_container.key_press(game, key, false, ctrl_pressed);
}
}
(_, None) => (),
}
}
_ => (),
}
}
_ => (), _ => (),
} }

View File

@ -1,12 +1,19 @@
use std::io::Write;
use std::sync::{Arc, RwLock};
use crate::world::{self, block};
use crate::shared::Direction;
use crate::model::BlockVertex; use crate::model::BlockVertex;
use crate::render; use crate::render;
use crate::shared::Direction;
use crate::world::{self, block};
use std::io::Write;
use std::sync::{Arc, RwLock};
pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lava: bool, snapshot: &world::Snapshot, x: i32, y: i32, z: i32, buf: &mut W) -> usize { pub fn render_liquid<W: Write>(
textures: Arc<RwLock<render::TextureManager>>,
lava: bool,
snapshot: &world::Snapshot,
x: i32,
y: i32,
z: i32,
buf: &mut W,
) -> usize {
let get_liquid = if lava { let get_liquid = if lava {
get_lava_level get_lava_level
} else { } else {
@ -20,17 +27,25 @@ pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lav
} else { } else {
( (
average_liquid_level(get_liquid, snapshot, x, y, z), average_liquid_level(get_liquid, snapshot, x, y, z),
average_liquid_level(get_liquid, snapshot, x+1, y, z), average_liquid_level(get_liquid, snapshot, x + 1, y, z),
average_liquid_level(get_liquid, snapshot, x, y, z+1), average_liquid_level(get_liquid, snapshot, x, y, z + 1),
average_liquid_level(get_liquid, snapshot, x+1, y, z+1) average_liquid_level(get_liquid, snapshot, x + 1, y, z + 1),
) )
}; };
let tex = match snapshot.get_block(x, y, z) { let tex = match snapshot.get_block(x, y, z) {
block::Block::Water{..} => render::Renderer::get_texture(&textures, "minecraft:blocks/water_still"), block::Block::Water { .. } => {
block::Block::FlowingWater{..} => render::Renderer::get_texture(&textures, "minecraft:blocks/water_flow"), render::Renderer::get_texture(&textures, "minecraft:blocks/water_still")
block::Block::Lava{..} => render::Renderer::get_texture(&textures, "minecraft:blocks/lava_still"), }
block::Block::FlowingLava{..} => render::Renderer::get_texture(&textures, "minecraft:blocks/lava_flow"), block::Block::FlowingWater { .. } => {
render::Renderer::get_texture(&textures, "minecraft:blocks/water_flow")
}
block::Block::Lava { .. } => {
render::Renderer::get_texture(&textures, "minecraft:blocks/lava_still")
}
block::Block::FlowingLava { .. } => {
render::Renderer::get_texture(&textures, "minecraft:blocks/lava_flow")
}
_ => unreachable!(), _ => unreachable!(),
}; };
let ux1 = 0i16; let ux1 = 0i16;
@ -41,8 +56,11 @@ pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lav
for dir in Direction::all() { for dir in Direction::all() {
let (ox, oy, oz) = dir.get_offset(); let (ox, oy, oz) = dir.get_offset();
let special = dir == Direction::Up && (tl < 8 || tr < 8 || bl < 8 || br < 8); let special = dir == Direction::Up && (tl < 8 || tr < 8 || bl < 8 || br < 8);
let block = snapshot.get_block(x+ox, y+oy, z+oz); let block = snapshot.get_block(x + ox, y + oy, z + oz);
if special || (!block.get_material().should_cull_against && get_liquid(snapshot, x+ox, y+oy, z+oz).is_none()) { if special
|| (!block.get_material().should_cull_against
&& get_liquid(snapshot, x + ox, y + oy, z + oz).is_none())
{
let verts = BlockVertex::face_by_direction(dir); let verts = BlockVertex::face_by_direction(dir);
for vert in verts { for vert in verts {
let mut vert = vert.clone(); let mut vert = vert.clone();
@ -64,7 +82,7 @@ pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lav
(0, _) => ((16.0 / 8.0) * (bl as f32)) as i32, (0, _) => ((16.0 / 8.0) * (bl as f32)) as i32,
(_, _) => ((16.0 / 8.0) * (br as f32)) as i32, (_, _) => ((16.0 / 8.0) * (br as f32)) as i32,
}; };
vert.y = (height as f32)/16.0 + (y as f32); vert.y = (height as f32) / 16.0 + (y as f32);
} }
vert.x += x as f32; vert.x += x as f32;
@ -72,13 +90,15 @@ pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lav
let (bl, sl) = super::calculate_light( let (bl, sl) = super::calculate_light(
snapshot, snapshot,
x, y, z, x,
y,
z,
vert.x as f64, vert.x as f64,
vert.y as f64, vert.y as f64,
vert.z as f64, vert.z as f64,
dir, dir,
!lava, !lava,
false false,
); );
vert.block_light = bl; vert.block_light = bl;
vert.sky_light = sl; vert.sky_light = sl;
@ -106,15 +126,18 @@ pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lav
fn average_liquid_level( fn average_liquid_level(
get: fn(&world::Snapshot, i32, i32, i32) -> Option<i32>, get: fn(&world::Snapshot, i32, i32, i32) -> Option<i32>,
snapshot: &world::Snapshot, x: i32, y: i32, z: i32 snapshot: &world::Snapshot,
x: i32,
y: i32,
z: i32,
) -> i32 { ) -> i32 {
let mut level = 0; let mut level = 0;
for xx in -1 .. 1 { for xx in -1..1 {
for zz in -1 .. 1 { for zz in -1..1 {
if get(snapshot, x+xx, y+1, z+zz).is_some() { if get(snapshot, x + xx, y + 1, z + zz).is_some() {
return 8; return 8;
} }
if let Some(l) = get(snapshot, x+xx, y, z+zz) { if let Some(l) = get(snapshot, x + xx, y, z + zz) {
let nl = 7 - (l & 0x7); let nl = 7 - (l & 0x7);
if nl > level { if nl > level {
level = nl; level = nl;
@ -127,14 +150,14 @@ fn average_liquid_level(
fn get_water_level(snapshot: &world::Snapshot, x: i32, y: i32, z: i32) -> Option<i32> { fn get_water_level(snapshot: &world::Snapshot, x: i32, y: i32, z: i32) -> Option<i32> {
match snapshot.get_block(x, y, z) { match snapshot.get_block(x, y, z) {
block::Block::Water{level} | block::Block::FlowingWater{level} => Some(level as i32), block::Block::Water { level } | block::Block::FlowingWater { level } => Some(level as i32),
_ => None, _ => None,
} }
} }
fn get_lava_level(snapshot: &world::Snapshot, x: i32, y: i32, z: i32) -> Option<i32> { fn get_lava_level(snapshot: &world::Snapshot, x: i32, y: i32, z: i32) -> Option<i32> {
match snapshot.get_block(x, y, z) { match snapshot.get_block(x, y, z) {
block::Block::Lava{level} | block::Block::FlowingLava{level} => Some(level as i32), block::Block::Lava { level } | block::Block::FlowingLava { level } => Some(level as i32),
_ => None, _ => None,
} }
} }

View File

@ -1,25 +1,24 @@
pub mod liquid; pub mod liquid;
use std::sync::{Arc, RwLock};
use std::collections::HashMap;
use std::cell::RefCell;
use std::io::Write;
use byteorder::{WriteBytesExt, NativeEndian};
use crate::resources;
use crate::render; use crate::render;
use crate::resources;
use crate::shared::Direction;
use crate::world; use crate::world;
use crate::world::block::{Block, TintType}; use crate::world::block::{Block, TintType};
use crate::shared::Direction; use byteorder::{NativeEndian, WriteBytesExt};
use serde_json; use serde_json;
use std::cell::RefCell;
use std::collections::HashMap;
use std::io::Write;
use std::sync::{Arc, RwLock};
use std::hash::BuildHasherDefault;
use crate::types::hash::FNVHash; use crate::types::hash::FNVHash;
use log::{error}; use log::error;
use std::hash::BuildHasherDefault;
use rand::Rng;
use rand::seq::SliceRandom;
use image::GenericImageView; use image::GenericImageView;
use rand::seq::SliceRandom;
use rand::Rng;
pub struct Factory { pub struct Factory {
resources: Arc<RwLock<resources::Manager>>, resources: Arc<RwLock<resources::Manager>>,
@ -35,7 +34,7 @@ pub struct Factory {
struct Key(String, String); struct Key(String, String);
macro_rules! try_log { macro_rules! try_log {
($e:expr) => ( ($e:expr) => {
match $e { match $e {
Ok(val) => val, Ok(val) => val,
Err(err) => { Err(err) => {
@ -43,8 +42,8 @@ macro_rules! try_log {
return false; return false;
} }
} }
); };
(opt $e:expr) => ( (opt $e:expr) => {
match $e { match $e {
Ok(val) => val, Ok(val) => val,
Err(err) => { Err(err) => {
@ -52,7 +51,7 @@ macro_rules! try_log {
return None; return None;
} }
} }
); };
} }
thread_local!( thread_local!(
@ -60,7 +59,10 @@ thread_local!(
); );
impl Factory { impl Factory {
pub fn new(resources: Arc<RwLock<resources::Manager>>, textures: Arc<RwLock<render::TextureManager>>) -> Factory { pub fn new(
resources: Arc<RwLock<resources::Manager>>,
textures: Arc<RwLock<render::TextureManager>>,
) -> Factory {
Factory { Factory {
grass_colors: Factory::load_biome_colors(resources.clone(), "grass"), grass_colors: Factory::load_biome_colors(resources.clone(), "grass"),
foliage_colors: Factory::load_biome_colors(resources.clone(), "foliage"), foliage_colors: Factory::load_biome_colors(resources.clone(), "foliage"),
@ -72,7 +74,11 @@ impl Factory {
} }
fn load_biome_colors(res: Arc<RwLock<resources::Manager>>, name: &str) -> image::DynamicImage { fn load_biome_colors(res: Arc<RwLock<resources::Manager>>, name: &str) -> image::DynamicImage {
let mut val = match res.read().unwrap().open("minecraft", &format!("textures/colormap/{}.png", name)) { let mut val = match res
.read()
.unwrap()
.open("minecraft", &format!("textures/colormap/{}.png", name))
{
Some(val) => val, Some(val) => val,
None => return image::DynamicImage::new_rgb8(256, 256), None => return image::DynamicImage::new_rgb8(256, 256),
}; };
@ -87,7 +93,17 @@ impl Factory {
self.foliage_colors = Factory::load_biome_colors(self.resources.clone(), "foliage"); self.foliage_colors = Factory::load_biome_colors(self.resources.clone(), "foliage");
} }
fn get_model<R: Rng, W: Write>(&self, key: Key, block: Block, rng: &mut R, snapshot: &world::Snapshot, x: i32, y: i32, z: i32, buf: &mut W) -> Result<usize, bool> { fn get_model<R: Rng, W: Write>(
&self,
key: Key,
block: Block,
rng: &mut R,
snapshot: &world::Snapshot,
x: i32,
y: i32,
z: i32,
buf: &mut W,
) -> Result<usize, bool> {
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
if let Some(model) = self.models.get(&key) { if let Some(model) = self.models.get(&key) {
if model.multipart.is_empty() { if model.multipart.is_empty() {
@ -103,7 +119,7 @@ impl Factory {
match entry { match entry {
Entry::Occupied(e) => { Entry::Occupied(e) => {
return Ok(e.get().render(self, snapshot, x, y, z, buf)); return Ok(e.get().render(self, snapshot, x, y, z, buf));
}, }
Entry::Vacant(e) => { Entry::Vacant(e) => {
let mut res: Option<Model> = None; let mut res: Option<Model> = None;
for rule in &model.multipart { for rule in &model.multipart {
@ -119,7 +135,7 @@ impl Factory {
if let Some(mdl) = res { if let Some(mdl) = res {
return Ok(e.insert(mdl).render(self, snapshot, x, y, z, buf)); return Ok(e.insert(mdl).render(self, snapshot, x, y, z, buf));
} }
}, }
}; };
Err(true) Err(true)
}); });
@ -143,7 +159,7 @@ impl Factory {
if !ok { if !ok {
return false; return false;
} }
}, }
Rule::Match(ref key, ref val) => { Rule::Match(ref key, ref val) => {
if !block.match_multipart(key, val) { if !block.match_multipart(key, val) {
return false; return false;
@ -154,8 +170,16 @@ impl Factory {
true true
} }
pub fn get_state_model<R: Rng, W: Write>(models: &Arc<RwLock<Factory>>, block: Block, rng: &mut R, pub fn get_state_model<R: Rng, W: Write>(
snapshot: &world::Snapshot, x: i32, y: i32, z: i32, buf: &mut W) -> usize { models: &Arc<RwLock<Factory>>,
block: Block,
rng: &mut R,
snapshot: &world::Snapshot,
x: i32,
y: i32,
z: i32,
buf: &mut W,
) -> usize {
let (plugin, name) = block.get_model(); let (plugin, name) = block.get_model();
let key = Key(plugin.to_owned(), name.to_owned()); let key = Key(plugin.to_owned(), name.to_owned());
let mut missing_variant; let mut missing_variant;
@ -177,23 +201,32 @@ impl Factory {
Err(val) => missing_variant = val, Err(val) => missing_variant = val,
}; };
} }
let ret = Factory::get_state_model(models, Block::Missing{}, rng, snapshot, x, y, z, buf); let ret = Factory::get_state_model(models, Block::Missing {}, rng, snapshot, x, y, z, buf);
if !missing_variant { if !missing_variant {
// Still no model, replace with placeholder // Still no model, replace with placeholder
let mut m = models.write().unwrap(); let mut m = models.write().unwrap();
let model = m.models.get(&Key("steven".to_owned(), "missing_block".to_owned())).unwrap().clone(); let model = m
.models
.get(&Key("steven".to_owned(), "missing_block".to_owned()))
.unwrap()
.clone();
m.models.insert(key, model); m.models.insert(key, model);
} }
ret ret
} }
fn load_model(&mut self, plugin: &str, name: &str) -> bool { fn load_model(&mut self, plugin: &str, name: &str) -> bool {
let file = match self.resources.read().unwrap().open(plugin, &format!("blockstates/{}.json", name)) { let file = match self
.resources
.read()
.unwrap()
.open(plugin, &format!("blockstates/{}.json", name))
{
Some(val) => val, Some(val) => val,
None => { None => {
error!("Error missing block state for {}:{}", plugin, name); error!("Error missing block state for {}:{}", plugin, name);
return false; return false;
}, }
}; };
let mdl: serde_json::Value = try_log!(serde_json::from_reader(file)); let mdl: serde_json::Value = try_log!(serde_json::from_reader(file));
@ -218,14 +251,12 @@ impl Factory {
if let Some(when) = rule.get("when").and_then(|v| v.as_object()) { if let Some(when) = rule.get("when").and_then(|v| v.as_object()) {
Self::parse_rules(when, &mut rules); Self::parse_rules(when, &mut rules);
} }
model.multipart.push(MultipartRule { model.multipart.push(MultipartRule { apply, rules })
apply,
rules,
})
} }
} }
self.models.insert(Key(plugin.to_owned(), name.to_owned()), model); self.models
.insert(Key(plugin.to_owned(), name.to_owned()), model);
true true
} }
@ -252,9 +283,7 @@ impl Factory {
} }
fn parse_model_list(&self, plugin: &str, v: &serde_json::Value) -> Variants { fn parse_model_list(&self, plugin: &str, v: &serde_json::Value) -> Variants {
let mut variants = Variants { let mut variants = Variants { models: vec![] };
models: vec![]
};
if let Some(list) = v.as_array() { if let Some(list) = v.as_array() {
for val in list { for val in list {
if let Some(mdl) = self.parse_block_state_variant(plugin, val) { if let Some(mdl) = self.parse_block_state_variant(plugin, val) {
@ -273,24 +302,35 @@ impl Factory {
None => { None => {
error!("Couldn't find model name"); error!("Couldn't find model name");
return None; return None;
}, }
}; };
let file = match self.resources.read().unwrap().open(plugin, &format!("models/block/{}.json", model_name)) { let file = match self
.resources
.read()
.unwrap()
.open(plugin, &format!("models/block/{}.json", model_name))
{
Some(val) => val, Some(val) => val,
None => { None => {
error!("Couldn't find model {}", format!("models/block/{}.json", model_name)); error!(
"Couldn't find model {}",
format!("models/block/{}.json", model_name)
);
return None; return None;
}, }
}; };
let block_model: serde_json::Value = try_log!(opt serde_json::from_reader(file)); let block_model: serde_json::Value = try_log!(opt serde_json::from_reader(file));
let mut model = match self.parse_model(plugin, &block_model) { let mut model = match self.parse_model(plugin, &block_model) {
Some(val) => val, Some(val) => val,
None => { None => {
error!("Failed to parse model {}", format!("models/block/{}.json", model_name)); error!(
"Failed to parse model {}",
format!("models/block/{}.json", model_name)
);
return None; return None;
}, }
}; };
model.y = v.get("y").and_then(|v| v.as_f64()).unwrap_or(0.0); model.y = v.get("y").and_then(|v| v.as_f64()).unwrap_or(0.0);
@ -303,20 +343,28 @@ impl Factory {
fn parse_model(&self, plugin: &str, v: &serde_json::Value) -> Option<RawModel> { fn parse_model(&self, plugin: &str, v: &serde_json::Value) -> Option<RawModel> {
let parent = v.get("parent").and_then(|v| v.as_str()).unwrap_or(""); let parent = v.get("parent").and_then(|v| v.as_str()).unwrap_or("");
let mut model = if !parent.is_empty() && !parent.starts_with("builtin/") { let mut model = if !parent.is_empty() && !parent.starts_with("builtin/") {
let file = match self.resources.read().unwrap().open(plugin, &format!("models/{}.json", parent)) { let file = match self
.resources
.read()
.unwrap()
.open(plugin, &format!("models/{}.json", parent))
{
Some(val) => val, Some(val) => val,
None => { None => {
error!("Couldn't find model {}", format!("models/{}.json", parent)); error!("Couldn't find model {}", format!("models/{}.json", parent));
return None; return None;
}, }
}; };
let block_model: serde_json::Value = try_log!(opt serde_json::from_reader(file)); let block_model: serde_json::Value = try_log!(opt serde_json::from_reader(file));
match self.parse_model(plugin, &block_model) { match self.parse_model(plugin, &block_model) {
Some(val) => val, Some(val) => val,
None => { None => {
error!("Failed to parse model {}", format!("models/{}.json", parent)); error!(
return None "Failed to parse model {}",
}, format!("models/{}.json", parent)
);
return None;
}
} }
} else { } else {
RawModel { RawModel {
@ -343,7 +391,9 @@ impl Factory {
if let Some(textures) = v.get("textures").and_then(|v| v.as_object()) { if let Some(textures) = v.get("textures").and_then(|v| v.as_object()) {
for (k, v) in textures { for (k, v) in textures {
model.texture_vars.insert(k.clone(), v.as_str().unwrap_or("").to_owned()); model
.texture_vars
.insert(k.clone(), v.as_str().unwrap_or("").to_owned());
} }
} }
@ -367,16 +417,28 @@ impl Factory {
fn parse_block_element(&self, v: &serde_json::Value) -> ModelElement { fn parse_block_element(&self, v: &serde_json::Value) -> ModelElement {
let mut element = ModelElement { let mut element = ModelElement {
from: v.get("from").and_then(|v| v.as_array()).map(|v| [ from: v
v[0].as_f64().unwrap(), .get("from")
v[1].as_f64().unwrap(), .and_then(|v| v.as_array())
v[2].as_f64().unwrap() .map(|v| {
]).unwrap(), [
to: v.get("to").and_then(|v| v.as_array()).map(|v| [ v[0].as_f64().unwrap(),
v[0].as_f64().unwrap(), v[1].as_f64().unwrap(),
v[1].as_f64().unwrap(), v[2].as_f64().unwrap(),
v[2].as_f64().unwrap() ]
]).unwrap(), })
.unwrap(),
to: v
.get("to")
.and_then(|v| v.as_array())
.map(|v| {
[
v[0].as_f64().unwrap(),
v[1].as_f64().unwrap(),
v[2].as_f64().unwrap(),
]
})
.unwrap(),
shade: v.get("shade").and_then(|v| v.as_bool()).unwrap_or(false), shade: v.get("shade").and_then(|v| v.as_bool()).unwrap_or(false),
faces: [None, None, None, None, None, None], faces: [None, None, None, None, None, None],
rotation: None, rotation: None,
@ -390,50 +452,58 @@ impl Factory {
let mut uv = [0.0, 0.0, 16.0, 16.0]; let mut uv = [0.0, 0.0, 16.0, 16.0];
match dir { match dir {
Direction::North | Direction::South => { Direction::North | Direction::South => {
uv[0] = element.from[0]; uv[0] = element.from[0];
uv[2] = element.to[0]; uv[2] = element.to[0];
uv[1] = 16.0 - element.to[1]; uv[1] = 16.0 - element.to[1];
uv[3] = 16.0 - element.from[1]; uv[3] = 16.0 - element.from[1];
}, }
Direction::West | Direction::East => { Direction::West | Direction::East => {
uv[0] = element.from[2]; uv[0] = element.from[2];
uv[2] = element.to[2]; uv[2] = element.to[2];
uv[1] = 16.0 - element.to[1]; uv[1] = 16.0 - element.to[1];
uv[3] = 16.0 - element.from[1]; uv[3] = 16.0 - element.from[1];
}, }
Direction::Down | Direction::Up => { Direction::Down | Direction::Up => {
uv[0] = element.from[0]; uv[0] = element.from[0];
uv[2] = element.to[0]; uv[2] = element.to[0];
uv[1] = 16.0 - element.to[2]; uv[1] = 16.0 - element.to[2];
uv[3] = 16.0 - element.from[2]; uv[3] = 16.0 - element.from[2];
}, }
_ => unreachable!(), _ => unreachable!(),
} }
uv uv
}, },
|v| [ |v| {
v[0].as_f64().unwrap(), [
v[1].as_f64().unwrap(), v[0].as_f64().unwrap(),
v[2].as_f64().unwrap(), v[1].as_f64().unwrap(),
v[3].as_f64().unwrap() v[2].as_f64().unwrap(),
] v[3].as_f64().unwrap(),
]
},
), ),
texture: face.get("texture") texture: face
.get("texture")
.and_then(|v| v.as_str()) .and_then(|v| v.as_str())
.map(|v| if v.starts_with('#') { .map(|v| {
v.to_owned() if v.starts_with('#') {
} else { v.to_owned()
"#".to_owned() + v } else {
}).unwrap(), "#".to_owned() + v
}
})
.unwrap(),
cull_face: Direction::from_string( cull_face: Direction::from_string(
face.get("cullface") face.get("cullface")
.and_then(|v| v.as_str()) .and_then(|v| v.as_str())
.unwrap_or("invalid") .unwrap_or("invalid"),
), ),
rotation: face.get("rotation") rotation: face
.get("rotation")
.and_then(|v| v.as_i64()) .and_then(|v| v.as_i64())
.map_or(0, |v| v as i32), .map_or(0, |v| v as i32),
tint_index: face.get("tintindex") tint_index: face
.get("tintindex")
.and_then(|v| v.as_i64()) .and_then(|v| v.as_i64())
.map_or(-1, |v| v as i32), .map_or(-1, |v| v as i32),
}); });
@ -443,14 +513,29 @@ impl Factory {
if let Some(rotation) = v.get("rotation") { if let Some(rotation) = v.get("rotation") {
element.rotation = Some(BlockRotation { element.rotation = Some(BlockRotation {
origin: rotation.get("origin").and_then(|v| v.as_array()).map_or([8.0, 8.0, 8.0], |v| [ origin: rotation.get("origin").and_then(|v| v.as_array()).map_or(
v[0].as_f64().unwrap(), [8.0, 8.0, 8.0],
v[1].as_f64().unwrap(), |v| {
v[2].as_f64().unwrap() [
]), v[0].as_f64().unwrap(),
axis: rotation.get("axis").and_then(|v| v.as_str()).unwrap_or("").to_owned(), v[1].as_f64().unwrap(),
angle: rotation.get("angle").and_then(|v| v.as_f64()).unwrap_or(0.0), v[2].as_f64().unwrap(),
rescale: rotation.get("rescale").and_then(|v| v.as_bool()).unwrap_or(false), ]
},
),
axis: rotation
.get("axis")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_owned(),
angle: rotation
.get("angle")
.and_then(|v| v.as_f64())
.unwrap_or(0.0),
rescale: rotation
.get("rescale")
.and_then(|v| v.as_bool())
.unwrap_or(false),
}); });
} }
@ -480,29 +565,33 @@ impl Factory {
}; };
if raw.x > 0.0 { if raw.x > 0.0 {
let o = (raw.x as i32) / 90; let o = (raw.x as i32) / 90;
processed_face.cull_face = rotate_direction(processed_face.cull_face, o, FACE_ROTATION_X, &[ processed_face.cull_face = rotate_direction(
Direction::East, processed_face.cull_face,
Direction::West, o,
Direction::Invalid, FACE_ROTATION_X,
]); &[Direction::East, Direction::West, Direction::Invalid],
processed_face.facing = rotate_direction(processed_face.facing, o, FACE_ROTATION_X, &[ );
Direction::East, processed_face.facing = rotate_direction(
Direction::West, processed_face.facing,
Direction::Invalid, o,
]); FACE_ROTATION_X,
&[Direction::East, Direction::West, Direction::Invalid],
);
} }
if raw.y > 0.0 { if raw.y > 0.0 {
let o = (raw.y as i32) / 90; let o = (raw.y as i32) / 90;
processed_face.cull_face = rotate_direction(processed_face.cull_face, o, FACE_ROTATION, &[ processed_face.cull_face = rotate_direction(
Direction::Up, processed_face.cull_face,
Direction::Down, o,
Direction::Invalid, FACE_ROTATION,
]); &[Direction::Up, Direction::Down, Direction::Invalid],
processed_face.facing = rotate_direction(processed_face.facing, o, FACE_ROTATION, &[ );
Direction::Up, processed_face.facing = rotate_direction(
Direction::Down, processed_face.facing,
Direction::Invalid, o,
]); FACE_ROTATION,
&[Direction::Up, Direction::Down, Direction::Invalid],
);
} }
let mut verts = BlockVertex::face_by_direction(all_dirs[i]).to_vec(); let mut verts = BlockVertex::face_by_direction(all_dirs[i]).to_vec();
@ -523,24 +612,24 @@ impl Factory {
let oy2 = uy2; let oy2 = uy2;
match face.rotation { match face.rotation {
270 => { 270 => {
uy1 = tw*16 - ox2; uy1 = tw * 16 - ox2;
uy2 = tw*16 - ox1; uy2 = tw * 16 - ox1;
ux1 = oy1; ux1 = oy1;
ux2 = oy2; ux2 = oy2;
}, }
180 => { 180 => {
uy1 = th*16 - oy2; uy1 = th * 16 - oy2;
uy2 = th*16 - oy1; uy2 = th * 16 - oy1;
ux1 = tw*16 - ox2; ux1 = tw * 16 - ox2;
ux2 = tw*16 - ox1; ux2 = tw * 16 - ox1;
}, }
90 => { 90 => {
uy1 = ox1; uy1 = ox1;
uy2 = ox2; uy2 = ox2;
ux1 = th*16 - oy2; ux1 = th * 16 - oy2;
ux2 = th*16 - oy1; ux2 = th * 16 - oy1;
}, }
_ => {}, _ => {}
} }
} }
@ -583,40 +672,40 @@ impl Factory {
let s = angle.sin(); let s = angle.sin();
let x = v.x; let x = v.x;
let z = v.z; let z = v.z;
v.x = x*c - z*s; v.x = x * c - z * s;
v.z = z*c + x*s; v.z = z * c + x * s;
if r.rescale { if r.rescale {
v.x *= ci; v.x *= ci;
v.z *= ci; v.z *= ci;
} }
}, }
"x" => { "x" => {
let c = angle.cos(); let c = angle.cos();
let s = angle.sin(); let s = angle.sin();
let z = v.z; let z = v.z;
let y = v.y; let y = v.y;
v.z = z*c - y*s; v.z = z * c - y * s;
v.y = y*c + z*s; v.y = y * c + z * s;
if r.rescale { if r.rescale {
v.z *= ci; v.z *= ci;
v.y *= ci; v.y *= ci;
} }
}, }
"z" => { "z" => {
let c = angle.cos(); let c = angle.cos();
let s = angle.sin(); let s = angle.sin();
let x = v.x; let x = v.x;
let y = v.y; let y = v.y;
v.x = x*c - y*s; v.x = x * c - y * s;
v.y = y*c + x*s; v.y = y * c + x * s;
if r.rescale { if r.rescale {
v.x *= ci; v.x *= ci;
v.y *= ci; v.y *= ci;
} }
}, }
_ => {} _ => {}
} }
v.x += (r.origin[0] / 16.0) as f32; v.x += (r.origin[0] / 16.0) as f32;
@ -630,8 +719,8 @@ impl Factory {
let s = rot_x.sin(); let s = rot_x.sin();
let z = v.z - 0.5; let z = v.z - 0.5;
let y = v.y - 0.5; let y = v.y - 0.5;
v.z = 0.5 + (z*c - y*s); v.z = 0.5 + (z * c - y * s);
v.y = 0.5 + (y*c + z*s); v.y = 0.5 + (y * c + z * s);
} }
if raw.y > 0.0 { if raw.y > 0.0 {
@ -640,8 +729,8 @@ impl Factory {
let s = rot_y.sin(); let s = rot_y.sin();
let x = v.x - 0.5; let x = v.x - 0.5;
let z = v.z - 0.5; let z = v.z - 0.5;
v.x = 0.5 + (x*c - z*s); v.x = 0.5 + (x * c - z * s);
v.z = 0.5 + (z*c + x*s); v.z = 0.5 + (z * c + x * s);
} }
if v.toffsetx == 0 { if v.toffsetx == 0 {
@ -657,35 +746,42 @@ impl Factory {
} }
if face.rotation > 0 { if face.rotation > 0 {
let rot_y = (-face.rotation as f64 * (::std::f64::consts::PI / 180.0)) as f32; let rot_y =
(-face.rotation as f64 * (::std::f64::consts::PI / 180.0)) as f32;
let c = rot_y.cos() as i16; let c = rot_y.cos() as i16;
let s = rot_y.sin() as i16; let s = rot_y.sin() as i16;
let x = v.toffsetx - 8*tw; let x = v.toffsetx - 8 * tw;
let y = v.toffsety - 8*th; let y = v.toffsety - 8 * th;
v.toffsetx = 8*tw + (x*c - y*s); v.toffsetx = 8 * tw + (x * c - y * s);
v.toffsety = 8*th + (y*c + x*s); v.toffsety = 8 * th + (y * c + x * s);
} }
if raw.uvlock && raw.y > 0.0 if raw.uvlock
&& (processed_face.facing == Direction::Up || processed_face.facing == Direction::Down) { && raw.y > 0.0
&& (processed_face.facing == Direction::Up
|| processed_face.facing == Direction::Down)
{
let rot_y = (raw.y * (::std::f64::consts::PI / 180.0)) as f32; let rot_y = (raw.y * (::std::f64::consts::PI / 180.0)) as f32;
let c = rot_y.cos() as i16; let c = rot_y.cos() as i16;
let s = rot_y.sin() as i16; let s = rot_y.sin() as i16;
let x = v.toffsetx - 8*tw; let x = v.toffsetx - 8 * tw;
let y = v.toffsety - 8*th; let y = v.toffsety - 8 * th;
v.toffsetx = 8*tw + (x*c - y*s); v.toffsetx = 8 * tw + (x * c - y * s);
v.toffsety = 8*th + (y*c + x*s); v.toffsety = 8 * th + (y * c + x * s);
} }
if raw.uvlock && raw.x > 0.0 if raw.uvlock
&& (processed_face.facing != Direction::Up && processed_face.facing != Direction::Down) { && raw.x > 0.0
&& (processed_face.facing != Direction::Up
&& processed_face.facing != Direction::Down)
{
let rot_x = (raw.x * (::std::f64::consts::PI / 180.0)) as f32; let rot_x = (raw.x * (::std::f64::consts::PI / 180.0)) as f32;
let c = rot_x.cos() as i16; let c = rot_x.cos() as i16;
let s = rot_x.sin() as i16; let s = rot_x.sin() as i16;
let x = v.toffsetx - 8*tw; let x = v.toffsetx - 8 * tw;
let y = v.toffsety - 8*th; let y = v.toffsety - 8 * th;
v.toffsetx = 8*tw + (x*c - y*s); v.toffsetx = 8 * tw + (x * c - y * s);
v.toffsety = 8*th + (y*c + x*s); v.toffsety = 8 * th + (y * c + x * s);
} }
} }
@ -713,15 +809,18 @@ const FACE_ROTATION_X: &[Direction] = &[
Direction::Up, Direction::Up,
]; ];
fn rotate_direction(val: Direction, offset: i32, rots: &[Direction], invalid: &[Direction]) -> Direction { fn rotate_direction(
val: Direction,
offset: i32,
rots: &[Direction],
invalid: &[Direction],
) -> Direction {
for d in invalid { for d in invalid {
if *d == val { if *d == val {
return val; return val;
} }
} }
let pos = rots.iter() let pos = rots.iter().position(|v| *v == val).unwrap_or(0) as i32;
.position(|v| *v == val)
.unwrap_or(0) as i32;
rots[(rots.len() as i32 + pos + offset) as usize % rots.len()] rots[(rots.len() as i32 + pos + offset) as usize % rots.len()]
} }
@ -767,7 +866,7 @@ enum BuiltinType {
Generated, Generated,
Entity, Entity,
Compass, Compass,
Clock Clock,
} }
#[derive(Debug)] #[derive(Debug)]
@ -789,7 +888,11 @@ struct RawModel {
impl RawModel { impl RawModel {
fn lookup_texture(&self, name: &str) -> String { fn lookup_texture(&self, name: &str) -> String {
if !name.is_empty() && name.starts_with('#') { if !name.is_empty() && name.starts_with('#') {
let tex = self.texture_vars.get(&name[1..]).cloned().unwrap_or("".to_owned()); let tex = self
.texture_vars
.get(&name[1..])
.cloned()
.unwrap_or("".to_owned());
return self.lookup_texture(&tex); return self.lookup_texture(&tex);
} }
name.to_owned() name.to_owned()
@ -852,7 +955,15 @@ impl Model {
self.faces.extend_from_slice(&other.faces); self.faces.extend_from_slice(&other.faces);
} }
fn render<W: Write>(&self, factory: &Factory, snapshot: &world::Snapshot, x: i32, y: i32, z: i32, buf: &mut W) -> usize { fn render<W: Write>(
&self,
factory: &Factory,
snapshot: &world::Snapshot,
x: i32,
y: i32,
z: i32,
buf: &mut W,
) -> usize {
let this = snapshot.get_block(x, y, z); let this = snapshot.get_block(x, y, z);
let this_mat = this.get_material(); let this_mat = this.get_material();
let mut indices = 0; let mut indices = 0;
@ -879,9 +990,19 @@ impl Model {
let (mut cr, mut cg, mut cb) = if face.tint_index == 0 { let (mut cr, mut cg, mut cb) = if face.tint_index == 0 {
match tint { match tint {
TintType::Default => (255, 255, 255), TintType::Default => (255, 255, 255),
TintType::Color{r, g, b} => (r, g, b), TintType::Color { r, g, b } => (r, g, b),
TintType::Grass => calculate_biome(snapshot, vert.x as i32, vert.z as i32, &factory.grass_colors), TintType::Grass => calculate_biome(
TintType::Foliage => calculate_biome(snapshot, vert.x as i32, vert.z as i32, &factory.foliage_colors), snapshot,
vert.x as i32,
vert.z as i32,
&factory.grass_colors,
),
TintType::Foliage => calculate_biome(
snapshot,
vert.x as i32,
vert.z as i32,
&factory.foliage_colors,
),
} }
} else { } else {
(255, 255, 255) (255, 255, 255)
@ -898,13 +1019,15 @@ impl Model {
let (bl, sl) = calculate_light( let (bl, sl) = calculate_light(
snapshot, snapshot,
x, y, z, x,
y,
z,
vert.x as f64, vert.x as f64,
vert.y as f64, vert.y as f64,
vert.z as f64, vert.z as f64,
face.facing, face.facing,
self.ambient_occlusion, self.ambient_occlusion,
this_mat.force_shade this_mat.force_shade,
); );
vert.block_light = bl; vert.block_light = bl;
vert.sky_light = sl; vert.sky_light = sl;
@ -915,15 +1038,20 @@ impl Model {
} }
} }
fn calculate_biome(snapshot: &world::Snapshot, x: i32, z: i32, img: &image::DynamicImage) -> (u8, u8, u8) { fn calculate_biome(
use std::cmp::{min, max}; snapshot: &world::Snapshot,
x: i32,
z: i32,
img: &image::DynamicImage,
) -> (u8, u8, u8) {
use std::cmp::{max, min};
let mut count = 0; let mut count = 0;
let mut r = 0; let mut r = 0;
let mut g = 0; let mut g = 0;
let mut b = 0; let mut b = 0;
for xx in -1 .. 2 { for xx in -1..2 {
for zz in -1 .. 2 { for zz in -1..2 {
let bi = snapshot.get_biome(x+xx, z+zz); let bi = snapshot.get_biome(x + xx, z + zz);
let color_index = bi.get_color_index(); let color_index = bi.get_color_index();
let ix = color_index & 0xFF; let ix = color_index & 0xFF;
let iy = color_index >> 8; let iy = color_index >> 8;
@ -939,13 +1067,23 @@ fn calculate_biome(snapshot: &world::Snapshot, x: i32, z: i32, img: &image::Dyna
count += 1; count += 1;
} }
} }
((r/count) as u8, (g/count) as u8, (b/count) as u8) ((r / count) as u8, (g / count) as u8, (b / count) as u8)
} }
fn calculate_light(snapshot: &world::Snapshot, orig_x: i32, orig_y: i32, orig_z: i32, fn calculate_light(
x: f64, y: f64, z: f64, face: Direction, smooth: bool, force: bool) -> (u16, u16) { snapshot: &world::Snapshot,
use std::cmp::max; orig_x: i32,
orig_y: i32,
orig_z: i32,
x: f64,
y: f64,
z: f64,
face: Direction,
smooth: bool,
force: bool,
) -> (u16, u16) {
use crate::world::block; use crate::world::block;
use std::cmp::max;
let (ox, oy, oz) = face.get_offset(); let (ox, oy, oz) = face.get_offset();
let s_block_light = snapshot.get_block_light(orig_x + ox, orig_y + oy, orig_z + oz); let s_block_light = snapshot.get_block_light(orig_x + ox, orig_y + oy, orig_z + oz);
@ -973,8 +1111,13 @@ fn calculate_light(snapshot: &world::Snapshot, orig_x: i32, orig_y: i32, orig_z:
let lz = (z + oz + dz).round() as i32; let lz = (z + oz + dz).round() as i32;
let mut bl = snapshot.get_block_light(lx, ly, lz); let mut bl = snapshot.get_block_light(lx, ly, lz);
let mut sl = snapshot.get_sky_light(lx, ly, lz); let mut sl = snapshot.get_sky_light(lx, ly, lz);
if (force && match snapshot.get_block(lx, ly, lz) { block::Air{} => false, _ => true }) if (force
|| (sl == 0 && bl == 0){ && match snapshot.get_block(lx, ly, lz) {
block::Air {} => false,
_ => true,
})
|| (sl == 0 && bl == 0)
{
bl = s_block_light; bl = s_block_light;
sl = s_sky_light; sl = s_sky_light;
} }
@ -985,43 +1128,50 @@ fn calculate_light(snapshot: &world::Snapshot, orig_x: i32, orig_y: i32, orig_z:
} }
} }
((((block_light * 4000) / count) as u16), (((sky_light * 4000) / count) as u16)) (
(((block_light * 4000) / count) as u16),
(((sky_light * 4000) / count) as u16),
)
} }
pub const PRECOMPUTED_VERTS: [&[BlockVertex; 4]; 6] = [ pub const PRECOMPUTED_VERTS: [&[BlockVertex; 4]; 6] = [
&[ // Up &[
// Up
BlockVertex::base(0.0, 1.0, 0.0, 0, 0), BlockVertex::base(0.0, 1.0, 0.0, 0, 0),
BlockVertex::base(1.0, 1.0, 0.0, 1, 0), BlockVertex::base(1.0, 1.0, 0.0, 1, 0),
BlockVertex::base(0.0, 1.0, 1.0, 0, 1), BlockVertex::base(0.0, 1.0, 1.0, 0, 1),
BlockVertex::base(1.0, 1.0, 1.0, 1, 1), BlockVertex::base(1.0, 1.0, 1.0, 1, 1),
], ],
&[ // Down &[
// Down
BlockVertex::base(0.0, 0.0, 0.0, 0, 1), BlockVertex::base(0.0, 0.0, 0.0, 0, 1),
BlockVertex::base(0.0, 0.0, 1.0, 0, 0), BlockVertex::base(0.0, 0.0, 1.0, 0, 0),
BlockVertex::base(1.0, 0.0, 0.0, 1, 1), BlockVertex::base(1.0, 0.0, 0.0, 1, 1),
BlockVertex::base(1.0, 0.0, 1.0, 1, 0), BlockVertex::base(1.0, 0.0, 1.0, 1, 0),
], ],
&[ // North &[
// North
BlockVertex::base(0.0, 0.0, 0.0, 1, 1), BlockVertex::base(0.0, 0.0, 0.0, 1, 1),
BlockVertex::base(1.0, 0.0, 0.0, 0, 1), BlockVertex::base(1.0, 0.0, 0.0, 0, 1),
BlockVertex::base(0.0, 1.0, 0.0, 1, 0), BlockVertex::base(0.0, 1.0, 0.0, 1, 0),
BlockVertex::base(1.0, 1.0, 0.0, 0, 0), BlockVertex::base(1.0, 1.0, 0.0, 0, 0),
], ],
&[ // South &[
// South
BlockVertex::base(0.0, 0.0, 1.0, 0, 1), BlockVertex::base(0.0, 0.0, 1.0, 0, 1),
BlockVertex::base(0.0, 1.0, 1.0, 0, 0), BlockVertex::base(0.0, 1.0, 1.0, 0, 0),
BlockVertex::base(1.0, 0.0, 1.0, 1, 1), BlockVertex::base(1.0, 0.0, 1.0, 1, 1),
BlockVertex::base(1.0, 1.0, 1.0, 1, 0), BlockVertex::base(1.0, 1.0, 1.0, 1, 0),
], ],
&[ // West &[
// West
BlockVertex::base(0.0, 0.0, 0.0, 0, 1), BlockVertex::base(0.0, 0.0, 0.0, 0, 1),
BlockVertex::base(0.0, 1.0, 0.0, 0, 0), BlockVertex::base(0.0, 1.0, 0.0, 0, 0),
BlockVertex::base(0.0, 0.0, 1.0, 1, 1), BlockVertex::base(0.0, 0.0, 1.0, 1, 1),
BlockVertex::base(0.0, 1.0, 1.0, 1, 0), BlockVertex::base(0.0, 1.0, 1.0, 1, 0),
], ],
&[ // East &[
// East
BlockVertex::base(1.0, 0.0, 0.0, 1, 1), BlockVertex::base(1.0, 0.0, 0.0, 1, 1),
BlockVertex::base(1.0, 0.0, 1.0, 0, 1), BlockVertex::base(1.0, 0.0, 1.0, 0, 1),
BlockVertex::base(1.0, 1.0, 0.0, 1, 0), BlockVertex::base(1.0, 1.0, 0.0, 1, 0),
@ -1051,11 +1201,21 @@ pub struct BlockVertex {
impl BlockVertex { impl BlockVertex {
const fn base(x: f32, y: f32, z: f32, tx: i16, ty: i16) -> BlockVertex { const fn base(x: f32, y: f32, z: f32, tx: i16, ty: i16) -> BlockVertex {
BlockVertex { BlockVertex {
x, y, z, x,
tx: 0, ty: 0, tw: 0, th: 0, y,
toffsetx: tx, toffsety: ty, tatlas: 0, z,
r: 0, g: 0, b: 0, tx: 0,
block_light: 0, sky_light: 0, ty: 0,
tw: 0,
th: 0,
toffsetx: tx,
toffsety: ty,
tatlas: 0,
r: 0,
g: 0,
b: 0,
block_light: 0,
sky_light: 0,
} }
} }
pub fn write<W: Write>(&self, w: &mut W) { pub fn write<W: Write>(&self, w: &mut W) {

View File

@ -26,7 +26,9 @@ pub struct Rect {
impl Atlas { impl Atlas {
pub fn new(width: usize, height: usize) -> Atlas { pub fn new(width: usize, height: usize) -> Atlas {
let mut a = Atlas { free_space: Vec::new() }; let mut a = Atlas {
free_space: Vec::new(),
};
a.free_space.push(Rect { a.free_space.push(Rect {
x: 0, x: 0,
y: 0, y: 0,
@ -78,13 +80,15 @@ impl Atlas {
} else { } else {
if t.height > height { if t.height > height {
// Split by height // Split by height
self.free_space.insert(0, self.free_space.insert(
Rect { 0,
x: t.x, Rect {
y: t.y + height, x: t.x,
width, y: t.y + height,
height: t.height - height, width,
}); height: t.height - height,
},
);
target_index += 1; target_index += 1;
} }
t.x += width; t.x += width;

View File

@ -1,10 +1,9 @@
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use cgmath::{Point3, Matrix4};
use byteorder::{WriteBytesExt, NativeEndian};
use crate::gl;
use super::glsl; use super::glsl;
use crate::gl;
use byteorder::{NativeEndian, WriteBytesExt};
use cgmath::{Matrix4, Point3};
use log::error; use log::error;
pub struct Clouds { pub struct Clouds {
@ -115,8 +114,8 @@ impl Clouds {
let mut data = vec![]; let mut data = vec![];
let mut num_points = 0; let mut num_points = 0;
for x in -160 .. 160 { for x in -160..160 {
for z in -160 .. 160 { for z in -160..160 {
let _ = data.write_f32::<NativeEndian>(x as f32); let _ = data.write_f32::<NativeEndian>(x as f32);
let _ = data.write_f32::<NativeEndian>(128.0); let _ = data.write_f32::<NativeEndian>(128.0);
let _ = data.write_f32::<NativeEndian>(z as f32); let _ = data.write_f32::<NativeEndian>(z as f32);
@ -126,11 +125,19 @@ impl Clouds {
buffer.set_data(gl::ARRAY_BUFFER, &data, gl::STATIC_DRAW); buffer.set_data(gl::ARRAY_BUFFER, &data, gl::STATIC_DRAW);
let heightmap_data = vec![0; 512*512]; let heightmap_data = vec![0; 512 * 512];
let texture = gl::Texture::new(); let texture = gl::Texture::new();
texture.bind(gl::TEXTURE_2D); texture.bind(gl::TEXTURE_2D);
texture.image_2d(gl::TEXTURE_2D, 0, 512, 512, gl::RED, gl::UNSIGNED_BYTE, Some(&heightmap_data)); texture.image_2d(
gl::TEXTURE_2D,
0,
512,
512,
gl::RED,
gl::UNSIGNED_BYTE,
Some(&heightmap_data),
);
texture.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST); texture.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST);
texture.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST); texture.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST);
@ -163,7 +170,15 @@ impl Clouds {
} }
} }
pub fn draw(&mut self, camera_pos: &Point3<f64>, perspective_matrix: &Matrix4<f32>, camera_matrix: &Matrix4<f32>, light_level: f32, sky_offset: f32, delta: f64) { pub fn draw(
&mut self,
camera_pos: &Point3<f64>,
perspective_matrix: &Matrix4<f32>,
camera_matrix: &Matrix4<f32>,
light_level: f32,
sky_offset: f32,
delta: f64,
) {
self.offset += delta; self.offset += delta;
let tex = super::Renderer::get_texture(&self.textures, "steven:environment/clouds"); let tex = super::Renderer::get_texture(&self.textures, "steven:environment/clouds");
@ -173,12 +188,16 @@ impl Clouds {
self.u_camera_matrix.set_matrix4(camera_matrix); self.u_camera_matrix.set_matrix4(camera_matrix);
self.u_sky_offset.set_float(sky_offset); self.u_sky_offset.set_float(sky_offset);
self.u_light_level.set_float(light_level); self.u_light_level.set_float(light_level);
self.u_offset.set_float3(camera_pos.x.floor() as f32, 0.0, camera_pos.z.floor() as f32); self.u_offset.set_float3(
camera_pos.x.floor() as f32,
0.0,
camera_pos.z.floor() as f32,
);
self.u_texture_info.set_float4( self.u_texture_info.set_float4(
tex.get_x() as f32, tex.get_x() as f32,
tex.get_y() as f32, tex.get_y() as f32,
tex.get_width() as f32, tex.get_width() as f32,
tex.get_height() as f32 tex.get_height() as f32,
); );
self.u_atlas.set_float(tex.atlas as f32); self.u_atlas.set_float(tex.atlas as f32);
self.u_cloud_offset.set_float((self.offset / 60.0) as f32); self.u_cloud_offset.set_float((self.offset / 60.0) as f32);
@ -187,7 +206,17 @@ impl Clouds {
gl::active_texture(1); gl::active_texture(1);
self.texture.bind(gl::TEXTURE_2D); self.texture.bind(gl::TEXTURE_2D);
if self.dirty { if self.dirty {
self.texture.sub_image_2d(gl::TEXTURE_2D, 0, 0, 0, 512, 512, gl::RED, gl::UNSIGNED_BYTE, &self.heightmap_data); self.texture.sub_image_2d(
gl::TEXTURE_2D,
0,
0,
0,
512,
512,
gl::RED,
gl::UNSIGNED_BYTE,
&self.heightmap_data,
);
self.dirty = false; self.dirty = false;
} }
self.u_cloud_map.set_int(1); self.u_cloud_map.set_int(1);

View File

@ -20,13 +20,16 @@ pub struct Registry {
} }
impl Registry { impl Registry {
pub fn new() -> Registry { Default::default() } pub fn new() -> Registry {
Default::default()
}
pub fn register(&mut self, name: &str, source: &str) { pub fn register(&mut self, name: &str, source: &str) {
if self.shaders.contains_key(name) { if self.shaders.contains_key(name) {
panic!("shader {} is already defined", name); panic!("shader {} is already defined", name);
} }
self.shaders.insert(name.to_owned(), source.trim().to_owned()); self.shaders
.insert(name.to_owned(), source.trim().to_owned());
} }
pub fn get(&self, name: &str) -> String { pub fn get(&self, name: &str) -> String {

View File

@ -16,29 +16,29 @@ mod atlas;
pub mod glsl; pub mod glsl;
#[macro_use] #[macro_use]
pub mod shaders; pub mod shaders;
pub mod ui;
pub mod model;
pub mod clouds; pub mod clouds;
pub mod model;
pub mod ui;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use std::io::Write;
use crate::resources;
use crate::gl; use crate::gl;
use crate::resources;
use crate::world;
use byteorder::{NativeEndian, WriteBytesExt};
use cgmath::prelude::*;
use collision;
use image; use image;
use image::{GenericImage, GenericImageView}; use image::{GenericImage, GenericImageView};
use byteorder::{WriteBytesExt, NativeEndian};
use serde_json;
use cgmath::prelude::*;
use crate::world;
use collision;
use log::{error, trace}; use log::{error, trace};
use serde_json;
use std::collections::HashMap;
use std::io::Write;
use std::sync::{Arc, RwLock};
use std::hash::BuildHasherDefault;
use crate::types::hash::FNVHash; use crate::types::hash::FNVHash;
use std::hash::BuildHasherDefault;
use std::sync::atomic::{AtomicIsize, Ordering}; use std::sync::atomic::{AtomicIsize, Ordering};
use std::thread;
use std::sync::mpsc; use std::sync::mpsc;
use std::thread;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use reqwest; use reqwest;
@ -100,7 +100,9 @@ pub struct ChunkBuffer {
} }
impl ChunkBuffer { impl ChunkBuffer {
pub fn new() -> ChunkBuffer { Default::default() } pub fn new() -> ChunkBuffer {
Default::default()
}
} }
struct ChunkRenderInfo { struct ChunkRenderInfo {
@ -156,19 +158,19 @@ init_shader! {
impl Renderer { impl Renderer {
pub fn new(res: Arc<RwLock<resources::Manager>>) -> Renderer { pub fn new(res: Arc<RwLock<resources::Manager>>) -> Renderer {
let version = { let version = { res.read().unwrap().version() };
res.read().unwrap().version()
};
let tex = gl::Texture::new(); let tex = gl::Texture::new();
tex.bind(gl::TEXTURE_2D_ARRAY); tex.bind(gl::TEXTURE_2D_ARRAY);
tex.image_3d(gl::TEXTURE_2D_ARRAY, tex.image_3d(
0, gl::TEXTURE_2D_ARRAY,
ATLAS_SIZE as u32, 0,
ATLAS_SIZE as u32, ATLAS_SIZE as u32,
1, ATLAS_SIZE as u32,
gl::RGBA, 1,
gl::UNSIGNED_BYTE, gl::RGBA,
&[0; ATLAS_SIZE * ATLAS_SIZE * 4]); gl::UNSIGNED_BYTE,
&[0; ATLAS_SIZE * ATLAS_SIZE * 4],
);
tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MAG_FILTER, gl::NEAREST); tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MAG_FILTER, gl::NEAREST);
tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MIN_FILTER, gl::NEAREST); tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MIN_FILTER, gl::NEAREST);
tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE); tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
@ -248,9 +250,13 @@ impl Renderer {
if rm.version() != self.resource_version { if rm.version() != self.resource_version {
self.resource_version = rm.version(); self.resource_version = rm.version();
trace!("Updating textures to {}", self.resource_version); trace!("Updating textures to {}", self.resource_version);
self.textures.write().unwrap().update_textures(self.resource_version); self.textures
.write()
.unwrap()
.update_textures(self.resource_version);
self.model.rebuild_models(self.resource_version, &self.textures); self.model
.rebuild_models(self.resource_version, &self.textures);
} }
} }
@ -262,34 +268,47 @@ impl Renderer {
let fovy = cgmath::Rad::from(cgmath::Deg(90.0_f32)); let fovy = cgmath::Rad::from(cgmath::Deg(90.0_f32));
let aspect = (width as f32 / height as f32).max(1.0); let aspect = (width as f32 / height as f32).max(1.0);
self.perspective_matrix = cgmath::Matrix4::from( self.perspective_matrix = cgmath::Matrix4::from(cgmath::PerspectiveFov {
cgmath::PerspectiveFov { fovy,
fovy, aspect,
aspect, near: 0.1f32,
near: 0.1f32, far: 500.0f32,
far: 500.0f32, });
}
);
self.init_trans(width, height); self.init_trans(width, height);
} }
self.view_vector = cgmath::Vector3::new( self.view_vector = cgmath::Vector3::new(
((self.camera.yaw - PI64/2.0).cos() * -self.camera.pitch.cos()) as f32, ((self.camera.yaw - PI64 / 2.0).cos() * -self.camera.pitch.cos()) as f32,
(-self.camera.pitch.sin()) as f32, (-self.camera.pitch.sin()) as f32,
(-(self.camera.yaw - PI64/2.0).sin() * -self.camera.pitch.cos()) as f32 (-(self.camera.yaw - PI64 / 2.0).sin() * -self.camera.pitch.cos()) as f32,
);
let camera = cgmath::Point3::new(
-self.camera.pos.x as f32,
-self.camera.pos.y as f32,
self.camera.pos.z as f32,
); );
let camera = cgmath::Point3::new(-self.camera.pos.x as f32, -self.camera.pos.y as f32, self.camera.pos.z as f32);
let camera_matrix = cgmath::Matrix4::look_at( let camera_matrix = cgmath::Matrix4::look_at(
camera, camera,
camera + cgmath::Point3::new(-self.view_vector.x, -self.view_vector.y, self.view_vector.z).to_vec(), camera
cgmath::Vector3::new(0.0, -1.0, 0.0) + cgmath::Point3::new(-self.view_vector.x, -self.view_vector.y, self.view_vector.z)
.to_vec(),
cgmath::Vector3::new(0.0, -1.0, 0.0),
); );
self.camera_matrix = camera_matrix * cgmath::Matrix4::from_nonuniform_scale(-1.0, 1.0, 1.0); self.camera_matrix = camera_matrix * cgmath::Matrix4::from_nonuniform_scale(-1.0, 1.0, 1.0);
self.frustum = collision::Frustum::from_matrix4(self.perspective_matrix * self.camera_matrix).unwrap(); self.frustum =
collision::Frustum::from_matrix4(self.perspective_matrix * self.camera_matrix).unwrap();
} }
pub fn tick(&mut self, world: &mut world::World, delta: f64, width: u32, height: u32, physical_width: u32, physical_height: u32) { pub fn tick(
&mut self,
world: &mut world::World,
delta: f64,
width: u32,
height: u32,
physical_width: u32,
physical_height: u32,
) {
self.update_textures(delta); self.update_textures(delta);
let trans = self.trans.as_mut().unwrap(); let trans = self.trans.as_mut().unwrap();
@ -302,18 +321,22 @@ impl Renderer {
let time_offset = self.sky_offset * 0.9; let time_offset = self.sky_offset * 0.9;
gl::clear_color( gl::clear_color(
(122.0 / 255.0) * time_offset, (122.0 / 255.0) * time_offset,
(165.0 / 255.0) * time_offset, (165.0 / 255.0) * time_offset,
(247.0 / 255.0) * time_offset, (247.0 / 255.0) * time_offset,
1.0 1.0,
); );
gl::clear(gl::ClearFlags::Color | gl::ClearFlags::Depth); gl::clear(gl::ClearFlags::Color | gl::ClearFlags::Depth);
// Chunk rendering // Chunk rendering
self.chunk_shader.program.use_program(); self.chunk_shader.program.use_program();
self.chunk_shader.perspective_matrix.set_matrix4(&self.perspective_matrix); self.chunk_shader
self.chunk_shader.camera_matrix.set_matrix4(&self.camera_matrix); .perspective_matrix
.set_matrix4(&self.perspective_matrix);
self.chunk_shader
.camera_matrix
.set_matrix4(&self.camera_matrix);
self.chunk_shader.texture.set_int(0); self.chunk_shader.texture.set_int(0);
self.chunk_shader.light_level.set_float(self.light_level); self.chunk_shader.light_level.set_float(self.light_level);
self.chunk_shader.sky_offset.set_float(self.sky_offset); self.chunk_shader.sky_offset.set_float(self.sky_offset);
@ -321,36 +344,71 @@ impl Renderer {
for (pos, info) in world.get_render_list() { for (pos, info) in world.get_render_list() {
if let Some(solid) = info.solid.as_ref() { if let Some(solid) = info.solid.as_ref() {
if solid.count > 0 { if solid.count > 0 {
self.chunk_shader.offset.set_int3(pos.0, pos.1 * 4096, pos.2); self.chunk_shader
.offset
.set_int3(pos.0, pos.1 * 4096, pos.2);
solid.array.bind(); solid.array.bind();
gl::draw_elements(gl::TRIANGLES, solid.count as i32, self.element_buffer_type, 0); gl::draw_elements(
gl::TRIANGLES,
solid.count as i32,
self.element_buffer_type,
0,
);
} }
} }
} }
// Line rendering // Line rendering
// Model rendering // Model rendering
self.model.draw(&self.frustum, &self.perspective_matrix, &self.camera_matrix, self.light_level, self.sky_offset); self.model.draw(
&self.frustum,
&self.perspective_matrix,
&self.camera_matrix,
self.light_level,
self.sky_offset,
);
if world.copy_cloud_heightmap(&mut self.clouds.heightmap_data) { if world.copy_cloud_heightmap(&mut self.clouds.heightmap_data) {
self.clouds.dirty = true; self.clouds.dirty = true;
} }
self.clouds.draw(&self.camera.pos, &self.perspective_matrix, &self.camera_matrix, self.light_level, self.sky_offset, delta); self.clouds.draw(
&self.camera.pos,
&self.perspective_matrix,
&self.camera_matrix,
self.light_level,
self.sky_offset,
delta,
);
// Trans chunk rendering // Trans chunk rendering
self.chunk_shader_alpha.program.use_program(); self.chunk_shader_alpha.program.use_program();
self.chunk_shader_alpha.perspective_matrix.set_matrix4(&self.perspective_matrix); self.chunk_shader_alpha
self.chunk_shader_alpha.camera_matrix.set_matrix4(&self.camera_matrix); .perspective_matrix
.set_matrix4(&self.perspective_matrix);
self.chunk_shader_alpha
.camera_matrix
.set_matrix4(&self.camera_matrix);
self.chunk_shader_alpha.texture.set_int(0); self.chunk_shader_alpha.texture.set_int(0);
self.chunk_shader_alpha.light_level.set_float(self.light_level); self.chunk_shader_alpha
self.chunk_shader_alpha.sky_offset.set_float(self.sky_offset); .light_level
.set_float(self.light_level);
self.chunk_shader_alpha
.sky_offset
.set_float(self.sky_offset);
// Copy the depth buffer // Copy the depth buffer
trans.main.bind_read(); trans.main.bind_read();
trans.trans.bind_draw(); trans.trans.bind_draw();
gl::blit_framebuffer( gl::blit_framebuffer(
0, 0, physical_width as i32, physical_height as i32, 0,
0, 0, physical_width as i32, physical_height as i32, 0,
gl::ClearFlags::Depth, gl::NEAREST physical_width as i32,
physical_height as i32,
0,
0,
physical_width as i32,
physical_height as i32,
gl::ClearFlags::Depth,
gl::NEAREST,
); );
gl::enable(gl::BLEND); gl::enable(gl::BLEND);
@ -360,14 +418,26 @@ impl Renderer {
gl::clear(gl::ClearFlags::Color); gl::clear(gl::ClearFlags::Color);
gl::clear_buffer(gl::COLOR, 0, &[0.0, 0.0, 0.0, 1.0]); gl::clear_buffer(gl::COLOR, 0, &[0.0, 0.0, 0.0, 1.0]);
gl::clear_buffer(gl::COLOR, 1, &[0.0, 0.0, 0.0, 0.0]); gl::clear_buffer(gl::COLOR, 1, &[0.0, 0.0, 0.0, 0.0]);
gl::blend_func_separate(gl::ONE_FACTOR, gl::ONE_FACTOR, gl::ZERO_FACTOR, gl::ONE_MINUS_SRC_ALPHA); gl::blend_func_separate(
gl::ONE_FACTOR,
gl::ONE_FACTOR,
gl::ZERO_FACTOR,
gl::ONE_MINUS_SRC_ALPHA,
);
for (pos, info) in world.get_render_list().iter().rev() { for (pos, info) in world.get_render_list().iter().rev() {
if let Some(trans) = info.trans.as_ref() { if let Some(trans) = info.trans.as_ref() {
if trans.count > 0 { if trans.count > 0 {
self.chunk_shader_alpha.offset.set_int3(pos.0, pos.1 * 4096, pos.2); self.chunk_shader_alpha
.offset
.set_int3(pos.0, pos.1 * 4096, pos.2);
trans.array.bind(); trans.array.bind();
gl::draw_elements(gl::TRIANGLES, trans.count as i32, self.element_buffer_type, 0); gl::draw_elements(
gl::TRIANGLES,
trans.count as i32,
self.element_buffer_type,
0,
);
} }
} }
} }
@ -396,7 +466,8 @@ impl Renderer {
let (data, ty) = self::generate_element_buffer(size); let (data, ty) = self::generate_element_buffer(size);
self.element_buffer_type = ty; self.element_buffer_type = ty;
self.element_buffer.bind(gl::ELEMENT_ARRAY_BUFFER); self.element_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
self.element_buffer.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW); self.element_buffer
.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW);
self.element_buffer_size = size; self.element_buffer_size = size;
} }
} }
@ -432,16 +503,27 @@ impl Renderer {
info.buffer.bind(gl::ARRAY_BUFFER); info.buffer.bind(gl::ARRAY_BUFFER);
if new || info.buffer_size < data.len() { if new || info.buffer_size < data.len() {
info.buffer_size = data.len(); info.buffer_size = data.len();
info.buffer.set_data(gl::ARRAY_BUFFER, data, gl::DYNAMIC_DRAW); info.buffer
.set_data(gl::ARRAY_BUFFER, data, gl::DYNAMIC_DRAW);
} else { } else {
info.buffer.re_set_data(gl::ARRAY_BUFFER, data); info.buffer.re_set_data(gl::ARRAY_BUFFER, data);
} }
self.chunk_shader.position.vertex_pointer(3, gl::FLOAT, false, 40, 0); self.chunk_shader
self.chunk_shader.texture_info.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 40, 12); .position
self.chunk_shader.texture_offset.vertex_pointer(3, gl::SHORT, false, 40, 20); .vertex_pointer(3, gl::FLOAT, false, 40, 0);
self.chunk_shader.color.vertex_pointer(3, gl::UNSIGNED_BYTE, true, 40, 28); self.chunk_shader
self.chunk_shader.lighting.vertex_pointer(2, gl::UNSIGNED_SHORT, false, 40, 32); .texture_info
.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 40, 12);
self.chunk_shader
.texture_offset
.vertex_pointer(3, gl::SHORT, false, 40, 20);
self.chunk_shader
.color
.vertex_pointer(3, gl::UNSIGNED_BYTE, true, 40, 28);
self.chunk_shader
.lighting
.vertex_pointer(2, gl::UNSIGNED_SHORT, false, 40, 32);
info.count = count; info.count = count;
} }
@ -477,16 +559,27 @@ impl Renderer {
info.buffer.bind(gl::ARRAY_BUFFER); info.buffer.bind(gl::ARRAY_BUFFER);
if new || info.buffer_size < data.len() { if new || info.buffer_size < data.len() {
info.buffer_size = data.len(); info.buffer_size = data.len();
info.buffer.set_data(gl::ARRAY_BUFFER, data, gl::DYNAMIC_DRAW); info.buffer
.set_data(gl::ARRAY_BUFFER, data, gl::DYNAMIC_DRAW);
} else { } else {
info.buffer.re_set_data(gl::ARRAY_BUFFER, data); info.buffer.re_set_data(gl::ARRAY_BUFFER, data);
} }
self.chunk_shader_alpha.position.vertex_pointer(3, gl::FLOAT, false, 40, 0); self.chunk_shader_alpha
self.chunk_shader_alpha.texture_info.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 40, 12); .position
self.chunk_shader_alpha.texture_offset.vertex_pointer(3, gl::SHORT, false, 40, 20); .vertex_pointer(3, gl::FLOAT, false, 40, 0);
self.chunk_shader_alpha.color.vertex_pointer(3, gl::UNSIGNED_BYTE, true, 40, 28); self.chunk_shader_alpha
self.chunk_shader_alpha.lighting.vertex_pointer(2, gl::UNSIGNED_SHORT, false, 40, 32); .texture_info
.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 40, 12);
self.chunk_shader_alpha
.texture_offset
.vertex_pointer(3, gl::SHORT, false, 40, 20);
self.chunk_shader_alpha
.color
.vertex_pointer(3, gl::UNSIGNED_BYTE, true, 40, 28);
self.chunk_shader_alpha
.lighting
.vertex_pointer(2, gl::UNSIGNED_SHORT, false, 40, 32);
info.count = count; info.count = count;
} }
@ -501,19 +594,23 @@ impl Renderer {
unsafe { unsafe {
data.set_len(len); data.set_len(len);
} }
self.gl_texture.get_pixels(gl::TEXTURE_2D_ARRAY, self.gl_texture.get_pixels(
0, gl::TEXTURE_2D_ARRAY,
gl::RGBA, 0,
gl::UNSIGNED_BYTE, gl::RGBA,
&mut data[..]); gl::UNSIGNED_BYTE,
self.gl_texture.image_3d(gl::TEXTURE_2D_ARRAY, &mut data[..],
0, );
ATLAS_SIZE as u32, self.gl_texture.image_3d(
ATLAS_SIZE as u32, gl::TEXTURE_2D_ARRAY,
tex.atlases.len() as u32, 0,
gl::RGBA, ATLAS_SIZE as u32,
gl::UNSIGNED_BYTE, ATLAS_SIZE as u32,
&data[..]); tex.atlases.len() as u32,
gl::RGBA,
gl::UNSIGNED_BYTE,
&data[..],
);
self.texture_layers = tex.atlases.len(); self.texture_layers = tex.atlases.len();
} }
tex.pending_uploads.len() tex.pending_uploads.len()
@ -525,17 +622,19 @@ impl Renderer {
let atlas = upload.0; let atlas = upload.0;
let rect = upload.1; let rect = upload.1;
let img = &upload.2; let img = &upload.2;
self.gl_texture.sub_image_3d(gl::TEXTURE_2D_ARRAY, self.gl_texture.sub_image_3d(
0, gl::TEXTURE_2D_ARRAY,
rect.x as u32, 0,
rect.y as u32, rect.x as u32,
atlas as u32, rect.y as u32,
rect.width as u32, atlas as u32,
rect.height as u32, rect.width as u32,
1, rect.height as u32,
gl::RGBA, 1,
gl::UNSIGNED_BYTE, gl::RGBA,
&img[..]); gl::UNSIGNED_BYTE,
&img[..],
);
} }
tex.pending_uploads.clear(); tex.pending_uploads.clear();
} }
@ -567,30 +666,36 @@ impl Renderer {
if ani.remaining_time <= 0.0 { if ani.remaining_time <= 0.0 {
ani.current_frame = (ani.current_frame + 1) % ani.frames.len(); ani.current_frame = (ani.current_frame + 1) % ani.frames.len();
ani.remaining_time += ani.frames[ani.current_frame].time as f64; ani.remaining_time += ani.frames[ani.current_frame].time as f64;
let offset = ani.texture.width * ani.texture.width * let offset =
ani.frames[ani.current_frame].index * 4; ani.texture.width * ani.texture.width * ani.frames[ani.current_frame].index * 4;
let offset2 = offset + ani.texture.width * ani.texture.width * 4; let offset2 = offset + ani.texture.width * ani.texture.width * 4;
self.gl_texture.sub_image_3d(gl::TEXTURE_2D_ARRAY, self.gl_texture.sub_image_3d(
0, gl::TEXTURE_2D_ARRAY,
ani.texture.get_x() as u32, 0,
ani.texture.get_y() as u32, ani.texture.get_x() as u32,
ani.texture.atlas as u32, ani.texture.get_y() as u32,
ani.texture.get_width() as u32, ani.texture.atlas as u32,
ani.texture.get_height() as u32, ani.texture.get_width() as u32,
1, ani.texture.get_height() as u32,
gl::RGBA, 1,
gl::UNSIGNED_BYTE, gl::RGBA,
&ani.data[offset..offset2]); gl::UNSIGNED_BYTE,
&ani.data[offset..offset2],
);
} else { } else {
ani.remaining_time -= delta / 3.0; ani.remaining_time -= delta / 3.0;
} }
} }
} }
fn init_trans(&mut self, width: u32, height: u32) { fn init_trans(&mut self, width: u32, height: u32) {
self.trans = None; self.trans = None;
self.trans = Some(TransInfo::new(width, height, &self.chunk_shader_alpha, &self.trans_shader)); self.trans = Some(TransInfo::new(
width,
height,
&self.chunk_shader_alpha,
&self.trans_shader,
));
} }
pub fn get_textures(&self) -> Arc<RwLock<TextureManager>> { pub fn get_textures(&self) -> Arc<RwLock<TextureManager>> {
@ -616,9 +721,7 @@ impl Renderer {
} }
pub fn get_texture(textures: &RwLock<TextureManager>, name: &str) -> Texture { pub fn get_texture(textures: &RwLock<TextureManager>, name: &str) -> Texture {
let tex = { let tex = { textures.read().unwrap().get_texture(name) };
textures.read().unwrap().get_texture(name)
};
match tex { match tex {
Some(val) => val, Some(val) => val,
None => { None => {
@ -636,9 +739,7 @@ impl Renderer {
} }
pub fn get_skin(&self, textures: &RwLock<TextureManager>, url: &str) -> Texture { pub fn get_skin(&self, textures: &RwLock<TextureManager>, url: &str) -> Texture {
let tex = { let tex = { textures.read().unwrap().get_skin(url) };
textures.read().unwrap().get_skin(url)
};
match tex { match tex {
Some(val) => val, Some(val) => val,
None => { None => {
@ -686,27 +787,59 @@ init_shader! {
} }
impl TransInfo { impl TransInfo {
pub fn new(width: u32, height: u32, chunk_shader: &ChunkShaderAlpha, shader: &TransShader) -> TransInfo { pub fn new(
width: u32,
height: u32,
chunk_shader: &ChunkShaderAlpha,
shader: &TransShader,
) -> TransInfo {
let trans = gl::Framebuffer::new(); let trans = gl::Framebuffer::new();
trans.bind(); trans.bind();
let accum = gl::Texture::new(); let accum = gl::Texture::new();
accum.bind(gl::TEXTURE_2D); accum.bind(gl::TEXTURE_2D);
accum.image_2d_ex(gl::TEXTURE_2D, 0, width, height, gl::RGBA16F, gl::RGBA, gl::FLOAT, None); accum.image_2d_ex(
gl::TEXTURE_2D,
0,
width,
height,
gl::RGBA16F,
gl::RGBA,
gl::FLOAT,
None,
);
accum.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR); accum.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR);
accum.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAX_LEVEL, gl::LINEAR); accum.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAX_LEVEL, gl::LINEAR);
trans.texture_2d(gl::COLOR_ATTACHMENT_0, gl::TEXTURE_2D, &accum, 0); trans.texture_2d(gl::COLOR_ATTACHMENT_0, gl::TEXTURE_2D, &accum, 0);
let revealage = gl::Texture::new(); let revealage = gl::Texture::new();
revealage.bind(gl::TEXTURE_2D); revealage.bind(gl::TEXTURE_2D);
revealage.image_2d_ex(gl::TEXTURE_2D, 0, width, height, gl::R16F, gl::RED, gl::FLOAT, None); revealage.image_2d_ex(
gl::TEXTURE_2D,
0,
width,
height,
gl::R16F,
gl::RED,
gl::FLOAT,
None,
);
revealage.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR); revealage.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR);
revealage.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAX_LEVEL, gl::LINEAR); revealage.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAX_LEVEL, gl::LINEAR);
trans.texture_2d(gl::COLOR_ATTACHMENT_1, gl::TEXTURE_2D, &revealage, 0); trans.texture_2d(gl::COLOR_ATTACHMENT_1, gl::TEXTURE_2D, &revealage, 0);
let trans_depth = gl::Texture::new(); let trans_depth = gl::Texture::new();
trans_depth.bind(gl::TEXTURE_2D); trans_depth.bind(gl::TEXTURE_2D);
trans_depth.image_2d_ex(gl::TEXTURE_2D, 0, width, height, gl::DEPTH_COMPONENT24, gl::DEPTH_COMPONENT, gl::UNSIGNED_BYTE, None); trans_depth.image_2d_ex(
gl::TEXTURE_2D,
0,
width,
height,
gl::DEPTH_COMPONENT24,
gl::DEPTH_COMPONENT,
gl::UNSIGNED_BYTE,
None,
);
trans_depth.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR); trans_depth.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR);
trans_depth.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAX_LEVEL, gl::LINEAR); trans_depth.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAX_LEVEL, gl::LINEAR);
trans.texture_2d(gl::DEPTH_ATTACHMENT, gl::TEXTURE_2D, &trans_depth, 0); trans.texture_2d(gl::DEPTH_ATTACHMENT, gl::TEXTURE_2D, &trans_depth, 0);
@ -722,13 +855,37 @@ impl TransInfo {
let fb_color = gl::Texture::new(); let fb_color = gl::Texture::new();
fb_color.bind(gl::TEXTURE_2D_MULTISAMPLE); fb_color.bind(gl::TEXTURE_2D_MULTISAMPLE);
fb_color.image_2d_sample(gl::TEXTURE_2D_MULTISAMPLE, NUM_SAMPLES, width, height, gl::RGBA8, false); fb_color.image_2d_sample(
main.texture_2d(gl::COLOR_ATTACHMENT_0, gl::TEXTURE_2D_MULTISAMPLE, &fb_color, 0); gl::TEXTURE_2D_MULTISAMPLE,
NUM_SAMPLES,
width,
height,
gl::RGBA8,
false,
);
main.texture_2d(
gl::COLOR_ATTACHMENT_0,
gl::TEXTURE_2D_MULTISAMPLE,
&fb_color,
0,
);
let fb_depth = gl::Texture::new(); let fb_depth = gl::Texture::new();
fb_depth.bind(gl::TEXTURE_2D_MULTISAMPLE); fb_depth.bind(gl::TEXTURE_2D_MULTISAMPLE);
fb_depth.image_2d_sample(gl::TEXTURE_2D_MULTISAMPLE, NUM_SAMPLES, width, height, gl::DEPTH_COMPONENT24, false); fb_depth.image_2d_sample(
main.texture_2d(gl::DEPTH_ATTACHMENT, gl::TEXTURE_2D_MULTISAMPLE, &fb_depth, 0); gl::TEXTURE_2D_MULTISAMPLE,
NUM_SAMPLES,
width,
height,
gl::DEPTH_COMPONENT24,
false,
);
main.texture_2d(
gl::DEPTH_ATTACHMENT,
gl::TEXTURE_2D_MULTISAMPLE,
&fb_depth,
0,
);
gl::check_framebuffer_status(); gl::check_framebuffer_status();
gl::unbind_framebuffer(); gl::unbind_framebuffer();
@ -740,7 +897,11 @@ impl TransInfo {
buffer.bind(gl::ARRAY_BUFFER); buffer.bind(gl::ARRAY_BUFFER);
let mut data = vec![]; let mut data = vec![];
for f in [-1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0].iter() { for f in [
-1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0,
]
.iter()
{
data.write_f32::<NativeEndian>(*f).unwrap(); data.write_f32::<NativeEndian>(*f).unwrap();
} }
buffer.set_data(gl::ARRAY_BUFFER, &data, gl::STATIC_DRAW); buffer.set_data(gl::ARRAY_BUFFER, &data, gl::STATIC_DRAW);
@ -798,7 +959,13 @@ pub struct TextureManager {
} }
impl TextureManager { impl TextureManager {
fn new(res: Arc<RwLock<resources::Manager>>) -> (TextureManager, mpsc::Sender<String>, mpsc::Receiver<(String, Option<image::DynamicImage>)>) { fn new(
res: Arc<RwLock<resources::Manager>>,
) -> (
TextureManager,
mpsc::Sender<String>,
mpsc::Receiver<(String, Option<image::DynamicImage>)>,
) {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
let (stx, srx) = mpsc::channel(); let (stx, srx) = mpsc::channel();
let skin_thread = thread::spawn(|| Self::process_skins(srx, tx)); let skin_thread = thread::spawn(|| Self::process_skins(srx, tx));
@ -824,31 +991,30 @@ impl TextureManager {
} }
fn add_defaults(&mut self) { fn add_defaults(&mut self) {
self.put_texture("steven", self.put_texture(
"missing_texture", "steven",
2, "missing_texture",
2, 2,
vec![ 2,
0, 0, 0, 255, vec![
255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 255, 0, 255, 255, 0, 0, 0, 255,
255, 0, 255, 255, ],
0, 0, 0, 255, );
]); self.put_texture("steven", "solid", 1, 1, vec![255, 255, 255, 255]);
self.put_texture("steven",
"solid",
1,
1,
vec![
255, 255, 255, 255,
]);
} }
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
fn process_skins(recv: mpsc::Receiver<String>, reply: mpsc::Sender<(String, Option<image::DynamicImage>)>) { fn process_skins(
recv: mpsc::Receiver<String>,
reply: mpsc::Sender<(String, Option<image::DynamicImage>)>,
) {
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
fn process_skins(recv: mpsc::Receiver<String>, reply: mpsc::Sender<(String, Option<image::DynamicImage>)>) { fn process_skins(
recv: mpsc::Receiver<String>,
reply: mpsc::Sender<(String, Option<image::DynamicImage>)>,
) {
let client = reqwest::blocking::Client::new(); let client = reqwest::blocking::Client::new();
loop { loop {
let hash = match recv.recv() { let hash = match recv.recv() {
@ -858,21 +1024,24 @@ impl TextureManager {
match Self::obtain_skin(&client, &hash) { match Self::obtain_skin(&client, &hash) {
Ok(img) => { Ok(img) => {
let _ = reply.send((hash, Some(img))); let _ = reply.send((hash, Some(img)));
}, }
Err(err) => { Err(err) => {
error!("Failed to get skin {:?}: {}", hash, err); error!("Failed to get skin {:?}: {}", hash, err);
let _ = reply.send((hash, None)); let _ = reply.send((hash, None));
}, }
} }
} }
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
fn obtain_skin(client: &::reqwest::blocking::Client, hash: &str) -> Result<image::DynamicImage, ::std::io::Error> { fn obtain_skin(
client: &::reqwest::blocking::Client,
hash: &str,
) -> Result<image::DynamicImage, ::std::io::Error> {
use std::io::Read; use std::io::Read;
use std_or_web::fs;
use std::path::Path;
use std::io::{Error, ErrorKind}; use std::io::{Error, ErrorKind};
use std::path::Path;
use std_or_web::fs;
let path = format!("skin-cache/{}/{}.png", &hash[..2], hash); let path = format!("skin-cache/{}/{}.png", &hash[..2], hash);
let cache_path = Path::new(&path); let cache_path = Path::new(&path);
fs::create_dir_all(cache_path.parent().unwrap())?; fs::create_dir_all(cache_path.parent().unwrap())?;
@ -892,7 +1061,7 @@ impl TextureManager {
}; };
let mut buf = vec![]; let mut buf = vec![];
match res.read_to_end(&mut buf) { match res.read_to_end(&mut buf) {
Ok(_) => {}, Ok(_) => {}
Err(err) => { Err(err) => {
// TODO: different error for failure to read? // TODO: different error for failure to read?
return Err(Error::new(ErrorKind::InvalidData, err)); return Err(Error::new(ErrorKind::InvalidData, err));
@ -913,10 +1082,11 @@ impl TextureManager {
if height == 32 { if height == 32 {
// Needs changing to the new format // Needs changing to the new format
let mut new = image::DynamicImage::new_rgba8(64, 64); let mut new = image::DynamicImage::new_rgba8(64, 64);
new.copy_from(&img, 0, 0).expect("Invalid png image in skin"); new.copy_from(&img, 0, 0)
for xx in 0 .. 4 { .expect("Invalid png image in skin");
for yy in 0 .. 16 { for xx in 0..4 {
for section in 0 .. 4 { for yy in 0..16 {
for section in 0..4 {
let os = match section { let os = match section {
0 => 2, 0 => 2,
1 => 1, 1 => 1,
@ -924,8 +1094,16 @@ impl TextureManager {
3 => 3, 3 => 3,
_ => unreachable!(), _ => unreachable!(),
}; };
new.put_pixel(16 + (3 - xx) + section * 4, 48 + yy, img.get_pixel(xx + os * 4, 16 + yy)); new.put_pixel(
new.put_pixel(32 + (3 - xx) + section * 4, 48 + yy, img.get_pixel(xx + 40 + os * 4, 16 + yy)); 16 + (3 - xx) + section * 4,
48 + yy,
img.get_pixel(xx + os * 4, 16 + yy),
);
new.put_pixel(
32 + (3 - xx) + section * 4,
48 + yy,
img.get_pixel(xx + 40 + os * 4, 16 + yy),
);
} }
} }
} }
@ -942,8 +1120,8 @@ impl TextureManager {
(40, 16, 16, 16), (40, 16, 16, 16),
]; ];
for bl in blacklist.iter() { for bl in blacklist.iter() {
for x in bl.0 .. (bl.0 + bl.2) { for x in bl.0..(bl.0 + bl.2) {
for y in bl.1 .. (bl.1 + bl.3) { for y in bl.1..(bl.1 + bl.3) {
let mut col = img.get_pixel(x, y); let mut col = img.get_pixel(x, y);
col.0[3] = 255; col.0[3] = 255;
img.put_pixel(x, y, col); img.put_pixel(x, y, col);
@ -977,7 +1155,8 @@ impl TextureManager {
let (width, height) = img.dimensions(); let (width, height) = img.dimensions();
(width, height, img.to_rgba().into_vec()) (width, height, img.to_rgba().into_vec())
}; };
let new_tex = self.put_texture("steven-dynamic", n, width as u32, height as u32, data); let new_tex =
self.put_texture("steven-dynamic", n, width as u32, height as u32, data);
self.dynamic_textures.get_mut(n).unwrap().0 = new_tex; self.dynamic_textures.get_mut(n).unwrap().0 = new_tex;
} else if !self.textures.contains_key(name) { } else if !self.textures.contains_key(name) {
self.load_texture(name); self.load_texture(name);
@ -1005,7 +1184,11 @@ impl TextureManager {
let res = self.resources.clone(); let res = self.resources.clone();
// TODO: This shouldn't be hardcoded to steve but instead // TODO: This shouldn't be hardcoded to steve but instead
// have a way to select alex as a default. // have a way to select alex as a default.
let img = if let Some(mut val) = res.read().unwrap().open("minecraft", "textures/entity/steve.png") { let img = if let Some(mut val) = res
.read()
.unwrap()
.open("minecraft", "textures/entity/steve.png")
{
let mut data = Vec::new(); let mut data = Vec::new();
val.read_to_end(&mut data).unwrap(); val.read_to_end(&mut data).unwrap();
image::load_from_memory(&data).unwrap() image::load_from_memory(&data).unwrap()
@ -1018,7 +1201,9 @@ impl TextureManager {
} }
fn update_skin(&mut self, hash: String, img: image::DynamicImage) { fn update_skin(&mut self, hash: String, img: image::DynamicImage) {
if !self.skins.contains_key(&hash) { return; } if !self.skins.contains_key(&hash) {
return;
}
let name = format!("steven-dynamic:skin-{}", hash); let name = format!("steven-dynamic:skin-{}", hash);
let tex = self.get_texture(&name).unwrap(); let tex = self.get_texture(&name).unwrap();
let rect = atlas::Rect { let rect = atlas::Rect {
@ -1028,8 +1213,12 @@ impl TextureManager {
height: tex.height, height: tex.height,
}; };
self.pending_uploads.push((tex.atlas, rect, img.to_rgba().into_vec())); self.pending_uploads
self.dynamic_textures.get_mut(&format!("skin-{}", hash)).unwrap().1 = img; .push((tex.atlas, rect, img.to_rgba().into_vec()));
self.dynamic_textures
.get_mut(&format!("skin-{}", hash))
.unwrap()
.1 = img;
} }
fn get_texture(&self, name: &str) -> Option<Texture> { fn get_texture(&self, name: &str) -> Option<Texture> {
@ -1070,23 +1259,27 @@ impl TextureManager {
self.insert_texture_dummy(plugin, name); self.insert_texture_dummy(plugin, name);
} }
fn load_animation(&mut self, fn load_animation(
plugin: &str, &mut self,
name: &str, plugin: &str,
img: &image::DynamicImage, name: &str,
data: Vec<u8>) img: &image::DynamicImage,
-> Option<AnimatedTexture> { data: Vec<u8>,
) -> Option<AnimatedTexture> {
let path = format!("textures/{}.png.mcmeta", name); let path = format!("textures/{}.png.mcmeta", name);
let res = self.resources.clone(); let res = self.resources.clone();
if let Some(val) = res.read().unwrap().open(plugin, &path) { if let Some(val) = res.read().unwrap().open(plugin, &path) {
let meta: serde_json::Value = serde_json::from_reader(val).unwrap(); let meta: serde_json::Value = serde_json::from_reader(val).unwrap();
let animation = meta.get("animation").unwrap(); let animation = meta.get("animation").unwrap();
let frame_time = animation.get("frametime").and_then(|v| v.as_i64()).unwrap_or(1); let frame_time = animation
let interpolate = animation.get("interpolate") .get("frametime")
.and_then(|v| v.as_bool()) .and_then(|v| v.as_i64())
.unwrap_or(false); .unwrap_or(1);
let frames = if let Some(frames) = animation.get("frames") let interpolate = animation
.and_then(|v| v.as_array()) { .get("interpolate")
.and_then(|v| v.as_bool())
.unwrap_or(false);
let frames = if let Some(frames) = animation.get("frames").and_then(|v| v.as_array()) {
let mut out = Vec::with_capacity(frames.len()); let mut out = Vec::with_capacity(frames.len());
for frame in frames { for frame in frames {
if let Some(index) = frame.as_i64() { if let Some(index) = frame.as_i64() {
@ -1095,7 +1288,7 @@ impl TextureManager {
time: frame_time, time: frame_time,
}) })
} else { } else {
out.push(AnimationFrame{ out.push(AnimationFrame {
index: frame.get("index").unwrap().as_i64().unwrap() as usize, index: frame.get("index").unwrap().as_i64().unwrap() as usize,
time: frame_time * frame.get("frameTime").unwrap().as_i64().unwrap(), time: frame_time * frame.get("frameTime").unwrap().as_i64().unwrap(),
}) })
@ -1127,13 +1320,14 @@ impl TextureManager {
None None
} }
fn put_texture(&mut self, fn put_texture(
plugin: &str, &mut self,
name: &str, plugin: &str,
width: u32, name: &str,
height: u32, width: u32,
data: Vec<u8>) height: u32,
-> Texture { data: Vec<u8>,
) -> Texture {
let (atlas, rect) = self.find_free(width as usize, height as usize); let (atlas, rect) = self.find_free(width as usize, height as usize);
self.pending_uploads.push((atlas, rect, data)); self.pending_uploads.push((atlas, rect, data));
@ -1224,19 +1418,27 @@ impl TextureManager {
height, height,
}; };
self.pending_uploads.push((tex.atlas, rect, data)); self.pending_uploads.push((tex.atlas, rect, data));
let mut t = tex.relative(0.0, 0.0, (width as f32) / (tex.width as f32), (height as f32) / (tex.height as f32)); let mut t = tex.relative(
0.0,
0.0,
(width as f32) / (tex.width as f32),
(height as f32) / (tex.height as f32),
);
let old_name = mem::replace(&mut tex.name, format!("steven-dynamic:{}", name)); let old_name = mem::replace(&mut tex.name, format!("steven-dynamic:{}", name));
self.dynamic_textures.insert(name.to_owned(), (tex.clone(), img)); self.dynamic_textures
.insert(name.to_owned(), (tex.clone(), img));
// We need to rename the texture itself so that get_texture calls // We need to rename the texture itself so that get_texture calls
// work with the new name // work with the new name
let mut old = self.textures.remove(&old_name).unwrap(); let mut old = self.textures.remove(&old_name).unwrap();
old.name = format!("steven-dynamic:{}", name); old.name = format!("steven-dynamic:{}", name);
t.name = old.name.clone(); t.name = old.name.clone();
self.textures.insert(format!("steven-dynamic:{}", name), old); self.textures
.insert(format!("steven-dynamic:{}", name), old);
t t
} else { } else {
let tex = self.put_texture("steven-dynamic", name, width as u32, height as u32, data); let tex = self.put_texture("steven-dynamic", name, width as u32, height as u32, data);
self.dynamic_textures.insert(name.to_owned(), (tex.clone(), img)); self.dynamic_textures
.insert(name.to_owned(), (tex.clone(), img));
tex tex
} }
} }

View File

@ -1,17 +1,16 @@
use super::glsl; use super::glsl;
use super::shaders; use super::shaders;
use crate::format::{self, Component};
use crate::gl; use crate::gl;
use cgmath::{Point3, Matrix4, SquareMatrix}; use crate::model::BlockVertex;
use crate::shared::Direction;
use crate::types::hash::FNVHash;
use byteorder::{NativeEndian, WriteBytesExt};
use cgmath::{Matrix4, Point3, SquareMatrix};
use collision::{self, Frustum, Sphere}; use collision::{self, Frustum, Sphere};
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::BuildHasherDefault; use std::hash::BuildHasherDefault;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use crate::types::hash::FNVHash;
use crate::shared::Direction;
use byteorder::{WriteBytesExt, NativeEndian};
use crate::model::BlockVertex;
use crate::format::{self, Component};
pub struct Manager { pub struct Manager {
collections: Vec<Collection>, collections: Vec<Collection>,
@ -42,17 +41,25 @@ impl Manager {
m.add_collection( m.add_collection(
&greg.get("model_vertex"), &greg.get("model_vertex"),
&greg.get("model_frag"), &greg.get("model_frag"),
gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA gl::SRC_ALPHA,
gl::ONE_MINUS_SRC_ALPHA,
); );
m.add_collection( m.add_collection(
&greg.get("sun_vertex"), &greg.get("sun_vertex"),
&greg.get("sun_frag"), &greg.get("sun_frag"),
gl::SRC_ALPHA, gl::ONE_FACTOR gl::SRC_ALPHA,
gl::ONE_FACTOR,
); );
m m
} }
pub fn add_collection(&mut self, vert: &str, frag: &str, blend_s: gl::Factor, blend_d: gl::Factor) -> CollectionKey { pub fn add_collection(
&mut self,
vert: &str,
frag: &str,
blend_s: gl::Factor,
blend_d: gl::Factor,
) -> CollectionKey {
let collection = Collection { let collection = Collection {
shader: ModelShader::new_manual(vert, frag), shader: ModelShader::new_manual(vert, frag),
models: HashMap::with_hasher(BuildHasherDefault::default()), models: HashMap::with_hasher(BuildHasherDefault::default()),
@ -84,11 +91,26 @@ impl Manager {
collection.shader.texture_offset.map(|v| v.enable()); collection.shader.texture_offset.map(|v| v.enable());
collection.shader.color.map(|v| v.enable()); collection.shader.color.map(|v| v.enable());
collection.shader.id.map(|v| v.enable()); collection.shader.id.map(|v| v.enable());
collection.shader.position.map(|v| v.vertex_pointer(3, gl::FLOAT, false, 36, 0)); collection
collection.shader.texture_info.map(|v| v.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 36, 12)); .shader
collection.shader.texture_offset.map(|v| v.vertex_pointer_int(3, gl::SHORT, 36, 20)); .position
collection.shader.color.map(|v| v.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 36, 28)); .map(|v| v.vertex_pointer(3, gl::FLOAT, false, 36, 0));
collection.shader.id.map(|v| v.vertex_pointer_int(1, gl::UNSIGNED_BYTE, 36, 32)); collection
.shader
.texture_info
.map(|v| v.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 36, 12));
collection
.shader
.texture_offset
.map(|v| v.vertex_pointer_int(3, gl::SHORT, 36, 20));
collection
.shader
.color
.map(|v| v.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 36, 28));
collection
.shader
.id
.map(|v| v.vertex_pointer_int(1, gl::UNSIGNED_BYTE, 36, 32));
let mut model = Model { let mut model = Model {
// For culling only // For culling only
@ -125,7 +147,8 @@ impl Manager {
if self.max_index < model.count as usize { if self.max_index < model.count as usize {
let (data, ty) = super::generate_element_buffer(model.count as usize); let (data, ty) = super::generate_element_buffer(model.count as usize);
self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER); self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
self.index_buffer.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW); self.index_buffer
.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW);
self.max_index = model.count as usize; self.max_index = model.count as usize;
self.index_type = ty; self.index_type = ty;
} }
@ -156,8 +179,12 @@ impl Manager {
let _ = buffer.write_u16::<NativeEndian>(vert.texture.get_y() as u16); let _ = buffer.write_u16::<NativeEndian>(vert.texture.get_y() as u16);
let _ = buffer.write_u16::<NativeEndian>(vert.texture.get_width() as u16); let _ = buffer.write_u16::<NativeEndian>(vert.texture.get_width() as u16);
let _ = buffer.write_u16::<NativeEndian>(vert.texture.get_height() as u16); let _ = buffer.write_u16::<NativeEndian>(vert.texture.get_height() as u16);
let _ = buffer.write_i16::<NativeEndian>(((vert.texture.get_width() as f64) * 16.0 * vert.texture_x) as i16); let _ = buffer.write_i16::<NativeEndian>(
let _ = buffer.write_i16::<NativeEndian>(((vert.texture.get_height() as f64) * 16.0 * vert.texture_y) as i16); ((vert.texture.get_width() as f64) * 16.0 * vert.texture_x) as i16,
);
let _ = buffer.write_i16::<NativeEndian>(
((vert.texture.get_height() as f64) * 16.0 * vert.texture_y) as i16,
);
let _ = buffer.write_i16::<NativeEndian>(vert.texture.atlas as i16); let _ = buffer.write_i16::<NativeEndian>(vert.texture.atlas as i16);
let _ = buffer.write_i16::<NativeEndian>(0); let _ = buffer.write_i16::<NativeEndian>(0);
let _ = buffer.write_u8(vert.r); let _ = buffer.write_u8(vert.r);
@ -174,12 +201,18 @@ impl Manager {
if buffer.len() < model.buffer_size { if buffer.len() < model.buffer_size {
model.buffer.re_set_data(gl::ARRAY_BUFFER, &buffer); model.buffer.re_set_data(gl::ARRAY_BUFFER, &buffer);
} else { } else {
model.buffer.set_data(gl::ARRAY_BUFFER, &buffer, gl::DYNAMIC_DRAW); model
.buffer
.set_data(gl::ARRAY_BUFFER, &buffer, gl::DYNAMIC_DRAW);
model.buffer_size = buffer.len(); model.buffer_size = buffer.len();
} }
} }
pub fn rebuild_models(&mut self, version: usize, textures: &Arc<RwLock<super::TextureManager>>) { pub fn rebuild_models(
&mut self,
version: usize,
textures: &Arc<RwLock<super::TextureManager>>,
) {
for collection in &mut self.collections { for collection in &mut self.collections {
for (_, model) in &mut collection.models { for (_, model) in &mut collection.models {
for vert in &mut model.verts { for vert in &mut model.verts {
@ -200,28 +233,57 @@ impl Manager {
} }
} }
pub fn draw(&mut self, frustum: &Frustum<f32>, perspective_matrix: &Matrix4<f32>, camera_matrix: &Matrix4<f32>, light_level: f32, sky_offset: f32) { pub fn draw(
&mut self,
frustum: &Frustum<f32>,
perspective_matrix: &Matrix4<f32>,
camera_matrix: &Matrix4<f32>,
light_level: f32,
sky_offset: f32,
) {
gl::enable(gl::BLEND); gl::enable(gl::BLEND);
for collection in &self.collections { for collection in &self.collections {
collection.shader.program.use_program(); collection.shader.program.use_program();
collection.shader.perspective_matrix.map(|v| v.set_matrix4(perspective_matrix)); collection
collection.shader.camera_matrix.map(|v| v.set_matrix4(camera_matrix)); .shader
.perspective_matrix
.map(|v| v.set_matrix4(perspective_matrix));
collection
.shader
.camera_matrix
.map(|v| v.set_matrix4(camera_matrix));
collection.shader.texture.map(|v| v.set_int(0)); collection.shader.texture.map(|v| v.set_int(0));
collection.shader.sky_offset.map(|v| v.set_float(sky_offset)); collection
collection.shader.light_level.map(|v| v.set_float(light_level)); .shader
.sky_offset
.map(|v| v.set_float(sky_offset));
collection
.shader
.light_level
.map(|v| v.set_float(light_level));
gl::blend_func(collection.blend_s, collection.blend_d); gl::blend_func(collection.blend_s, collection.blend_d);
for model in collection.models.values() { for model in collection.models.values() {
if model.radius > 0.0 && frustum.contains(&Sphere { if model.radius > 0.0
center: Point3::new(model.x, -model.y, model.z), && frustum.contains(&Sphere {
radius: model.radius center: Point3::new(model.x, -model.y, model.z),
}) == collision::Relation::Out { radius: model.radius,
}) == collision::Relation::Out
{
continue; continue;
} }
model.array.bind(); model.array.bind();
collection.shader.lighting.map(|v| v.set_float2(model.block_light, model.sky_light)); collection
collection.shader.model_matrix.map(|v| v.set_matrix4_multi(&model.matrix)); .shader
collection.shader.color_mul.map(|v| v.set_float_mutli_raw(model.colors.as_ptr() as *const _, model.colors.len())); .lighting
.map(|v| v.set_float2(model.block_light, model.sky_light));
collection
.shader
.model_matrix
.map(|v| v.set_matrix4_multi(&model.matrix));
collection.shader.color_mul.map(|v| {
v.set_float_mutli_raw(model.colors.as_ptr() as *const _, model.colors.len())
});
gl::draw_elements(gl::TRIANGLES, model.count, self.index_type, 0); gl::draw_elements(gl::TRIANGLES, model.count, self.index_type, 0);
} }
} }
@ -301,23 +363,44 @@ init_shader! {
// Helper methods // Helper methods
pub fn append_box( pub fn append_box(
verts: &mut Vec<Vertex>, verts: &mut Vec<Vertex>,
x: f32, y: f32, z: f32, x: f32,
w: f32, h: f32, d: f32, textures: [Option<super::Texture>; 6] y: f32,
z: f32,
w: f32,
h: f32,
d: f32,
textures: [Option<super::Texture>; 6],
) { ) {
append_box_texture_scale(verts, x, y, z, w, h, d, textures, [ append_box_texture_scale(
[1.0, 1.0], verts,
[1.0, 1.0], x,
[1.0, 1.0], y,
[1.0, 1.0], z,
[1.0, 1.0], w,
[1.0, 1.0] h,
]); d,
textures,
[
[1.0, 1.0],
[1.0, 1.0],
[1.0, 1.0],
[1.0, 1.0],
[1.0, 1.0],
[1.0, 1.0],
],
);
} }
pub fn append_box_texture_scale( pub fn append_box_texture_scale(
verts: &mut Vec<Vertex>, verts: &mut Vec<Vertex>,
x: f32, y: f32, z: f32, x: f32,
w: f32, h: f32, d: f32, y: f32,
textures: [Option<super::Texture>; 6], texture_scale: [[f64; 2]; 6]) { z: f32,
w: f32,
h: f32,
d: f32,
textures: [Option<super::Texture>; 6],
texture_scale: [[f64; 2]; 6],
) {
for dir in Direction::all() { for dir in Direction::all() {
let tex = textures[dir.index()].clone(); let tex = textures[dir.index()].clone();
if tex.is_none() { if tex.is_none() {
@ -326,7 +409,11 @@ pub fn append_box_texture_scale(
let tex = tex.unwrap(); let tex = tex.unwrap();
for vert in BlockVertex::face_by_direction(dir) { for vert in BlockVertex::face_by_direction(dir) {
let (rr, gg, bb) = if dir == Direction::West || dir == Direction::East { let (rr, gg, bb) = if dir == Direction::West || dir == Direction::East {
((255.0 * 0.8) as u8, (255.0 * 0.8) as u8, (255.0 * 0.8) as u8) (
(255.0 * 0.8) as u8,
(255.0 * 0.8) as u8,
(255.0 * 0.8) as u8,
)
} else { } else {
(255, 255, 255) (255, 255, 255)
}; };
@ -356,7 +443,7 @@ pub struct FormatState<'a> {
pub x_scale: f32, pub x_scale: f32,
} }
impl <'a> FormatState<'a> { impl<'a> FormatState<'a> {
pub fn build(&mut self, c: &Component, color: format::Color) { pub fn build(&mut self, c: &Component, color: format::Color) {
match *c { match *c {
format::Component::Text(ref txt) => { format::Component::Text(ref txt) => {

View File

@ -12,12 +12,15 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use crate::render::glsl;
use crate::gl; use crate::gl;
use crate::render::glsl;
use log::error; use log::error;
pub fn add_shaders(reg: &mut glsl::Registry) { pub fn add_shaders(reg: &mut glsl::Registry) {
reg.register("lookup_texture", include_str!("shaders/lookup_texture.glsl")); reg.register(
"lookup_texture",
include_str!("shaders/lookup_texture.glsl"),
);
reg.register("get_light", include_str!("shaders/get_light.glsl")); reg.register("get_light", include_str!("shaders/get_light.glsl"));
reg.register("ui_vertex", include_str!("shaders/ui_vertex.glsl")); reg.register("ui_vertex", include_str!("shaders/ui_vertex.glsl"));
@ -41,12 +44,12 @@ pub fn add_shaders(reg: &mut glsl::Registry) {
} }
macro_rules! get_shader { macro_rules! get_shader {
($reg:ident, $name:expr) => ( ($reg:ident, $name:expr) => {
$reg.get($name) $reg.get($name)
); };
($reg:ident, $name:expr, $def:expr) => ( ($reg:ident, $name:expr, $def:expr) => {
$reg.get_define($name, $def) $reg.get_define($name, $def)
) };
} }
#[macro_export] #[macro_export]

View File

@ -12,16 +12,16 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::sync::{Arc, RwLock};
use std::collections::HashMap;
use crate::resources;
use crate::gl; use crate::gl;
use crate::render; use crate::render;
use crate::render::glsl; use crate::render::glsl;
use crate::render::shaders; use crate::render::shaders;
use byteorder::{WriteBytesExt, NativeEndian}; use crate::resources;
use byteorder::{NativeEndian, WriteBytesExt};
use image; use image;
use image::GenericImageView; use image::GenericImageView;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
const UI_WIDTH: f64 = 854.0; const UI_WIDTH: f64 = 854.0;
const UI_HEIGHT: f64 = 480.0; const UI_HEIGHT: f64 = 480.0;
@ -69,10 +69,11 @@ init_shader! {
} }
impl UIState { impl UIState {
pub fn new(glsl: &glsl::Registry, pub fn new(
textures: Arc<RwLock<render::TextureManager>>, glsl: &glsl::Registry,
res: Arc<RwLock<resources::Manager>>) textures: Arc<RwLock<render::TextureManager>>,
-> UIState { res: Arc<RwLock<resources::Manager>>,
) -> UIState {
let shader = UIShader::new(glsl); let shader = UIShader::new(glsl);
let array = gl::VertexArray::new(); let array = gl::VertexArray::new();
@ -84,9 +85,15 @@ impl UIState {
shader.texture_offset.enable(); shader.texture_offset.enable();
shader.color.enable(); shader.color.enable();
shader.position.vertex_pointer_int(3, gl::SHORT, 28, 0); shader.position.vertex_pointer_int(3, gl::SHORT, 28, 0);
shader.texture_info.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 28, 8); shader
shader.texture_offset.vertex_pointer_int(3, gl::SHORT, 28, 16); .texture_info
shader.color.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 28, 24); .vertex_pointer(4, gl::UNSIGNED_SHORT, false, 28, 8);
shader
.texture_offset
.vertex_pointer_int(3, gl::SHORT, 28, 16);
shader
.color
.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 28, 24);
let index_buffer = gl::Buffer::new(); let index_buffer = gl::Buffer::new();
index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER); index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
@ -155,17 +162,21 @@ impl UIState {
let (data, ty) = render::generate_element_buffer(self.count); let (data, ty) = render::generate_element_buffer(self.count);
self.index_type = ty; self.index_type = ty;
self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER); self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
self.index_buffer.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW); self.index_buffer
.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW);
self.max_index = self.count; self.max_index = self.count;
} }
self.shader.screensize.set_float2(width as f32, height as f32); self.shader
.screensize
.set_float2(width as f32, height as f32);
self.buffer.bind(gl::ARRAY_BUFFER); self.buffer.bind(gl::ARRAY_BUFFER);
self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER); self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
if self.data.len() > self.prev_size { if self.data.len() > self.prev_size {
self.prev_size = self.data.len(); self.prev_size = self.data.len();
self.buffer.set_data(gl::ARRAY_BUFFER, &self.data, gl::STREAM_DRAW); self.buffer
.set_data(gl::ARRAY_BUFFER, &self.data, gl::STREAM_DRAW);
} else { } else {
self.buffer.re_set_data(gl::ARRAY_BUFFER, &self.data); self.buffer.re_set_data(gl::ARRAY_BUFFER, &self.data);
} }
@ -209,15 +220,19 @@ impl UIState {
if page == 0 { if page == 0 {
let sw = (self.page_width / 16.0) as u32; let sw = (self.page_width / 16.0) as u32;
let sh = (self.page_height / 16.0) as u32; let sh = (self.page_height / 16.0) as u32;
return p.relative((cx * sw + info.0 as u32) as f32 / (self.page_width as f32), return p.relative(
(cy * sh) as f32 / (self.page_height as f32), (cx * sw + info.0 as u32) as f32 / (self.page_width as f32),
(info.1 - info.0) as f32 / (self.page_width as f32), (cy * sh) as f32 / (self.page_height as f32),
(sh as f32) / (self.page_height as f32)) (info.1 - info.0) as f32 / (self.page_width as f32),
(sh as f32) / (self.page_height as f32),
);
} }
p.relative((cx * 16 + info.0 as u32) as f32 / 256.0, p.relative(
(cy * 16) as f32 / 256.0, (cx * 16 + info.0 as u32) as f32 / 256.0,
(info.1 - info.0) as f32 / 256.0, (cy * 16) as f32 / 256.0,
16.0 / 256.0) (info.1 - info.0) as f32 / 256.0,
16.0 / 256.0,
)
} }
pub fn size_of_string(&self, val: &str) -> f64 { pub fn size_of_string(&self, val: &str) -> f64 {
@ -296,44 +311,47 @@ impl UIState {
self.new_text_scaled(val, x, y, 1.0, 1.0, r, g, b) self.new_text_scaled(val, x, y, 1.0, 1.0, r, g, b)
} }
pub fn new_text_scaled(&mut self, pub fn new_text_scaled(
val: &str, &mut self,
x: f64, val: &str,
y: f64, x: f64,
sx: f64, y: f64,
sy: f64, sx: f64,
r: u8, sy: f64,
g: u8, r: u8,
b: u8) g: u8,
-> UIText { b: u8,
) -> UIText {
self.create_text(val, x, y, sx, sy, 0.0, r, g, b) self.create_text(val, x, y, sx, sy, 0.0, r, g, b)
} }
pub fn new_text_rotated(&mut self, pub fn new_text_rotated(
val: &str, &mut self,
x: f64, val: &str,
y: f64, x: f64,
sx: f64, y: f64,
sy: f64, sx: f64,
rotation: f64, sy: f64,
r: u8, rotation: f64,
g: u8, r: u8,
b: u8) g: u8,
-> UIText { b: u8,
) -> UIText {
self.create_text(val, x, y, sx, sy, rotation, r, g, b) self.create_text(val, x, y, sx, sy, rotation, r, g, b)
} }
fn create_text(&mut self, fn create_text(
val: &str, &mut self,
x: f64, val: &str,
y: f64, x: f64,
sx: f64, y: f64,
sy: f64, sx: f64,
rotation: f64, sy: f64,
r: u8, rotation: f64,
g: u8, r: u8,
b: u8) g: u8,
-> UIText { b: u8,
) -> UIText {
let mut elements = Vec::new(); let mut elements = Vec::new();
let mut offset = 0.0; let mut offset = 0.0;
for ch in val.chars() { for ch in val.chars() {
@ -361,30 +379,34 @@ impl UIState {
dy = (16.0 * 0.5) + (tmpy * c + tmpx * s); dy = (16.0 * 0.5) + (tmpy * c + tmpx * s);
} }
let mut shadow = UIElement::new(&texture, let mut shadow = UIElement::new(
x + dsx * sx, &texture,
y + dsy * sy, x + dsx * sx,
w * sx, y + dsy * sy,
16.0 * sy, w * sx,
0.0, 16.0 * sy,
0.0, 0.0,
1.0, 0.0,
1.0); 1.0,
1.0,
);
shadow.r = ((r as f64) * 0.25) as u8; shadow.r = ((r as f64) * 0.25) as u8;
shadow.g = ((g as f64) * 0.25) as u8; shadow.g = ((g as f64) * 0.25) as u8;
shadow.b = ((b as f64) * 0.25) as u8; shadow.b = ((b as f64) * 0.25) as u8;
shadow.rotation = rotation; shadow.rotation = rotation;
elements.push(shadow); elements.push(shadow);
let mut text = UIElement::new(&texture, let mut text = UIElement::new(
x + dx * sx, &texture,
y + dy * sy, x + dx * sx,
w * sx, y + dy * sy,
16.0 * sy, w * sx,
0.0, 16.0 * sy,
0.0, 0.0,
1.0, 0.0,
1.0); 1.0,
1.0,
);
text.r = r; text.r = r;
text.g = g; text.g = g;
text.b = b; text.b = b;
@ -437,16 +459,17 @@ pub struct UIElement {
} }
impl UIElement { impl UIElement {
pub fn new(tex: &render::Texture, pub fn new(
x: f64, tex: &render::Texture,
y: f64, x: f64,
width: f64, y: f64,
height: f64, width: f64,
tx: f64, height: f64,
ty: f64, tx: f64,
tw: f64, ty: f64,
th: f64) tw: f64,
-> UIElement { th: f64,
) -> UIElement {
let twidth = tex.get_width(); let twidth = tex.get_width();
let theight = tex.get_height(); let theight = tex.get_height();
UIElement { UIElement {
@ -474,46 +497,56 @@ impl UIElement {
pub fn bytes(&self, width: f64, height: f64) -> Vec<u8> { pub fn bytes(&self, width: f64, height: f64) -> Vec<u8> {
let mut buf = Vec::with_capacity(28 * 4); let mut buf = Vec::with_capacity(28 * 4);
self.append_vertex(&mut buf, self.append_vertex(
self.x, &mut buf,
self.y, self.x,
self.t_offsetx, self.y,
self.t_offsety, self.t_offsetx,
width, self.t_offsety,
height); width,
self.append_vertex(&mut buf, height,
self.x + self.w, );
self.y, self.append_vertex(
self.t_offsetx + self.t_sizew, &mut buf,
self.t_offsety, self.x + self.w,
width, self.y,
height); self.t_offsetx + self.t_sizew,
self.append_vertex(&mut buf, self.t_offsety,
self.x, width,
self.y + self.h, height,
self.t_offsetx, );
self.t_offsety + self.t_sizeh, self.append_vertex(
width, &mut buf,
height); self.x,
self.append_vertex(&mut buf, self.y + self.h,
self.x + self.w, self.t_offsetx,
self.y + self.h, self.t_offsety + self.t_sizeh,
self.t_offsetx + self.t_sizew, width,
self.t_offsety + self.t_sizeh, height,
width, );
height); self.append_vertex(
&mut buf,
self.x + self.w,
self.y + self.h,
self.t_offsetx + self.t_sizew,
self.t_offsety + self.t_sizeh,
width,
height,
);
buf buf
} }
#[allow(unused_must_use)] #[allow(unused_must_use)]
pub fn append_vertex(&self, pub fn append_vertex(
buf: &mut Vec<u8>, &self,
x: f64, buf: &mut Vec<u8>,
y: f64, x: f64,
tx: i16, y: f64,
ty: i16, tx: i16,
width: f64, ty: i16,
height: f64) { width: f64,
height: f64,
) {
let mut dx = x as f64; let mut dx = x as f64;
let mut dy = y as f64; let mut dy = y as f64;
if self.rotation != 0.0 { if self.rotation != 0.0 {

View File

@ -14,15 +14,15 @@
extern crate steven_resources as internal; extern crate steven_resources as internal;
use std::thread; use serde_json;
use std::path;
use std::io;
use std_or_web::fs;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::BuildHasherDefault; use std::hash::BuildHasherDefault;
use serde_json; use std::io;
use std::path;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::thread;
use std_or_web::fs;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use reqwest; use reqwest;
@ -32,7 +32,8 @@ use crate::types::hash::FNVHash;
use crate::ui; use crate::ui;
const RESOURCES_VERSION: &str = "1.12.2"; const RESOURCES_VERSION: &str = "1.12.2";
const VANILLA_CLIENT_URL: &str = "https://launcher.mojang.com/v1/objects/0f275bc1547d01fa5f56ba34bdc87d981ee12daf/client.jar"; const VANILLA_CLIENT_URL: &str =
"https://launcher.mojang.com/v1/objects/0f275bc1547d01fa5f56ba34bdc87d981ee12daf/client.jar";
const ASSET_VERSION: &str = "1.12"; const ASSET_VERSION: &str = "1.12";
const ASSET_INDEX_URL: &str = "https://launchermeta.mojang.com/mc/assets/1.12/67e29e024e664064c1f04c728604f83c24cbc218/1.12.json"; const ASSET_INDEX_URL: &str = "https://launchermeta.mojang.com/mc/assets/1.12/67e29e024e664064c1f04c728604f83c24cbc218/1.12.json";
@ -85,9 +86,7 @@ impl Manager {
version: 0, version: 0,
vanilla_chan: None, vanilla_chan: None,
vanilla_assets_chan: None, vanilla_assets_chan: None,
vanilla_progress: Arc::new(Mutex::new(Progress { vanilla_progress: Arc::new(Mutex::new(Progress { tasks: vec![] })),
tasks: vec![],
})),
}; };
m.add_pack(Box::new(InternalPack)); m.add_pack(Box::new(InternalPack));
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
@ -95,7 +94,13 @@ impl Manager {
m.download_vanilla(); m.download_vanilla();
m.download_assets(); m.download_assets();
} }
(m, ManagerUI { progress_ui: vec!{}, num_tasks: 0 }) (
m,
ManagerUI {
progress_ui: vec![],
num_tasks: 0,
},
)
} }
/// Returns the 'version' of the manager. The version is /// Returns the 'version' of the manager. The version is
@ -156,9 +161,12 @@ impl Manager {
progress.tasks.retain(|v| v.progress < v.total); progress.tasks.retain(|v| v.progress < v.total);
// Find out what we have to work with // Find out what we have to work with
for task in &progress.tasks { for task in &progress.tasks {
if !mui.progress_ui.iter() if !mui
.progress_ui
.iter()
.filter(|v| v.task_file == task.task_file) .filter(|v| v.task_file == task.task_file)
.any(|v| v.task_name == task.task_name) { .any(|v| v.task_name == task.task_name)
{
mui.num_tasks += 1; mui.num_tasks += 1;
// Add a ui element for it // Add a ui element for it
let background = ui::ImageBuilder::new() let background = ui::ImageBuilder::new()
@ -217,16 +225,22 @@ impl Manager {
} }
let mut found = false; let mut found = false;
let mut prog = 1.0; let mut prog = 1.0;
for task in progress.tasks.iter() for task in progress
.tasks
.iter()
.filter(|v| v.task_file == ui.task_file) .filter(|v| v.task_file == ui.task_file)
.filter(|v| v.task_name == ui.task_name) { .filter(|v| v.task_name == ui.task_name)
{
found = true; found = true;
prog = task.progress as f64 / task.total as f64; prog = task.progress as f64 / task.total as f64;
} }
let background = ui.background.borrow(); let background = ui.background.borrow();
let bar = ui.progress_bar.borrow(); let bar = ui.progress_bar.borrow();
// Let the progress bar finish // Let the progress bar finish
if !found && (background.y - ui.position).abs() < 0.7 * delta && (bar.width - 350.0).abs() < 1.0 * delta { if !found
&& (background.y - ui.position).abs() < 0.7 * delta
&& (bar.width - 350.0).abs() < 1.0 * delta
{
ui.closing = true; ui.closing = true;
ui.position = -UI_HEIGHT; ui.position = -UI_HEIGHT;
} }
@ -258,7 +272,8 @@ impl Manager {
} }
// Clean up dead elements // Clean up dead elements
mui.progress_ui.retain(|v| v.position >= -UI_HEIGHT || !v.closing); mui.progress_ui
.retain(|v| v.position >= -UI_HEIGHT || !v.closing);
} }
fn add_pack(&mut self, pck: Box<dyn Pack>) { fn add_pack(&mut self, pck: Box<dyn Pack>) {
@ -269,7 +284,12 @@ impl Manager {
fn load_vanilla(&mut self) { fn load_vanilla(&mut self) {
let loc = format!("./resources-{}", RESOURCES_VERSION); let loc = format!("./resources-{}", RESOURCES_VERSION);
let location = path::Path::new(&loc); let location = path::Path::new(&loc);
self.packs.insert(1, Box::new(DirPack { root: location.to_path_buf() })); self.packs.insert(
1,
Box::new(DirPack {
root: location.to_path_buf(),
}),
);
self.version += 1; self.version += 1;
} }
@ -284,23 +304,34 @@ impl Manager {
let location = path::Path::new(&loc).to_owned(); let location = path::Path::new(&loc).to_owned();
let progress_info = self.vanilla_progress.clone(); let progress_info = self.vanilla_progress.clone();
let (send, recv) = mpsc::channel(); let (send, recv) = mpsc::channel();
if fs::metadata(&location).is_ok(){ if fs::metadata(&location).is_ok() {
self.load_assets(); self.load_assets();
} else { } else {
self.vanilla_assets_chan = Some(recv); self.vanilla_assets_chan = Some(recv);
} }
thread::spawn(move || { thread::spawn(move || {
let client = reqwest::blocking::Client::new(); let client = reqwest::blocking::Client::new();
if fs::metadata(&location).is_err(){ if fs::metadata(&location).is_err() {
fs::create_dir_all(location.parent().unwrap()).unwrap(); fs::create_dir_all(location.parent().unwrap()).unwrap();
let res = client.get(ASSET_INDEX_URL) let res = client.get(ASSET_INDEX_URL).send().unwrap();
.send()
.unwrap();
let length = res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap().to_str().unwrap().parse::<u64>().unwrap(); let length = res
Self::add_task(&progress_info, "Downloading Asset Index", &*location.to_string_lossy(), length); .headers()
.get(reqwest::header::CONTENT_LENGTH)
.unwrap()
.to_str()
.unwrap()
.parse::<u64>()
.unwrap();
Self::add_task(
&progress_info,
"Downloading Asset Index",
&*location.to_string_lossy(),
length,
);
{ {
let mut file = fs::File::create(format!("index-{}.tmp", ASSET_VERSION)).unwrap(); let mut file =
fs::File::create(format!("index-{}.tmp", ASSET_VERSION)).unwrap();
let mut progress = ProgressRead { let mut progress = ProgressRead {
read: res, read: res,
progress: &progress_info, progress: &progress_info,
@ -316,16 +347,25 @@ impl Manager {
let index: serde_json::Value = serde_json::from_reader(&file).unwrap(); let index: serde_json::Value = serde_json::from_reader(&file).unwrap();
let root_location = path::Path::new("./objects/"); let root_location = path::Path::new("./objects/");
let objects = index.get("objects").and_then(|v| v.as_object()).unwrap(); let objects = index.get("objects").and_then(|v| v.as_object()).unwrap();
Self::add_task(&progress_info, "Downloading Assets", "./objects", objects.len() as u64); Self::add_task(
&progress_info,
"Downloading Assets",
"./objects",
objects.len() as u64,
);
for (k, v) in objects { for (k, v) in objects {
let hash = v.get("hash").and_then(|v| v.as_str()).unwrap(); let hash = v.get("hash").and_then(|v| v.as_str()).unwrap();
let hash_path = format!("{}/{}", &hash[..2], hash); let hash_path = format!("{}/{}", &hash[..2], hash);
let location = root_location.join(&hash_path); let location = root_location.join(&hash_path);
if fs::metadata(&location).is_err(){ if fs::metadata(&location).is_err() {
fs::create_dir_all(location.parent().unwrap()).unwrap(); fs::create_dir_all(location.parent().unwrap()).unwrap();
let res = client.get(&format!("http://resources.download.minecraft.net/{}", hash_path)) let res = client
.send() .get(&format!(
.unwrap(); "http://resources.download.minecraft.net/{}",
hash_path
))
.send()
.unwrap();
let length = v.get("size").and_then(|v| v.as_u64()).unwrap(); let length = v.get("size").and_then(|v| v.as_u64()).unwrap();
Self::add_task(&progress_info, "Downloading Asset", k, length); Self::add_task(&progress_info, "Downloading Asset", k, length);
let mut tmp_file = location.to_owned(); let mut tmp_file = location.to_owned();
@ -361,14 +401,24 @@ impl Manager {
let progress_info = self.vanilla_progress.clone(); let progress_info = self.vanilla_progress.clone();
thread::spawn(move || { thread::spawn(move || {
let client = reqwest::blocking::Client::new(); let client = reqwest::blocking::Client::new();
let res = client.get(VANILLA_CLIENT_URL) let res = client.get(VANILLA_CLIENT_URL).send().unwrap();
.send()
.unwrap();
let mut file = fs::File::create(format!("{}.tmp", RESOURCES_VERSION)).unwrap(); let mut file = fs::File::create(format!("{}.tmp", RESOURCES_VERSION)).unwrap();
let length = res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap().to_str().unwrap().parse::<u64>().unwrap(); let length = res
.headers()
.get(reqwest::header::CONTENT_LENGTH)
.unwrap()
.to_str()
.unwrap()
.parse::<u64>()
.unwrap();
let task_file = format!("./resources-{}", RESOURCES_VERSION); let task_file = format!("./resources-{}", RESOURCES_VERSION);
Self::add_task(&progress_info, "Downloading Core Assets", &task_file, length); Self::add_task(
&progress_info,
"Downloading Core Assets",
&task_file,
length,
);
{ {
let mut progress = ProgressRead { let mut progress = ProgressRead {
read: res, read: res,
@ -384,7 +434,12 @@ impl Manager {
let mut zip = zip::ZipArchive::new(file).unwrap(); let mut zip = zip::ZipArchive::new(file).unwrap();
let task_file = format!("./resources-{}", RESOURCES_VERSION); let task_file = format!("./resources-{}", RESOURCES_VERSION);
Self::add_task(&progress_info, "Unpacking Core Assets", &task_file, zip.len() as u64); Self::add_task(
&progress_info,
"Unpacking Core Assets",
&task_file,
zip.len() as u64,
);
let loc = format!("./resources-{}", RESOURCES_VERSION); let loc = format!("./resources-{}", RESOURCES_VERSION);
let location = path::Path::new(&loc); let location = path::Path::new(&loc);
@ -420,9 +475,12 @@ impl Manager {
fn add_task_progress(progress: &Arc<Mutex<Progress>>, name: &str, file: &str, prog: u64) { fn add_task_progress(progress: &Arc<Mutex<Progress>>, name: &str, file: &str, prog: u64) {
let mut progress = progress.lock().unwrap(); let mut progress = progress.lock().unwrap();
for task in progress.tasks.iter_mut() for task in progress
.tasks
.iter_mut()
.filter(|v| v.task_file == file) .filter(|v| v.task_file == file)
.filter(|v| v.task_name == name) { .filter(|v| v.task_name == name)
{
task.progress += prog as u64; task.progress += prog as u64;
} }
} }
@ -465,11 +523,12 @@ impl ObjectPack {
let objects = index.get("objects").and_then(|v| v.as_object()).unwrap(); let objects = index.get("objects").and_then(|v| v.as_object()).unwrap();
let mut hash_objs = HashMap::with_hasher(BuildHasherDefault::default()); let mut hash_objs = HashMap::with_hasher(BuildHasherDefault::default());
for (k, v) in objects { for (k, v) in objects {
hash_objs.insert(k.clone(), v.get("hash").and_then(|v| v.as_str()).unwrap().to_owned()); hash_objs.insert(
} k.clone(),
ObjectPack { v.get("hash").and_then(|v| v.as_str()).unwrap().to_owned(),
objects: hash_objs, );
} }
ObjectPack { objects: hash_objs }
} }
} }
@ -500,7 +559,7 @@ struct ProgressRead<'a, T> {
task_file: String, task_file: String,
} }
impl <'a, T: io::Read> io::Read for ProgressRead<'a, T> { impl<'a, T: io::Read> io::Read for ProgressRead<'a, T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let size = self.read.read(buf)?; let size = self.read.read(buf)?;
Manager::add_task_progress(self.progress, &self.task_name, &self.task_file, size as u64); Manager::add_task_progress(self.progress, &self.task_name, &self.task_file, size as u64);

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use crate::ui;
use crate::render; use crate::render;
use crate::ui;
pub struct Connecting { pub struct Connecting {
elements: Option<UIElements>, elements: Option<UIElements>,
@ -27,7 +27,6 @@ struct UIElements {
_disclaimer: ui::TextRef, _disclaimer: ui::TextRef,
} }
impl Connecting { impl Connecting {
pub fn new(target: &str) -> Connecting { pub fn new(target: &str) -> Connecting {
Connecting { Connecting {
@ -74,10 +73,12 @@ impl super::Screen for Connecting {
self.elements = None self.elements = None
} }
fn tick(&mut self, fn tick(
_delta: f64, &mut self,
renderer: &mut render::Renderer, _delta: f64,
_ui_container: &mut ui::Container) -> Option<Box<dyn super::Screen>>{ renderer: &mut render::Renderer,
_ui_container: &mut ui::Container,
) -> Option<Box<dyn super::Screen>> {
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
elements.logo.tick(renderer); elements.logo.tick(renderer);

View File

@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std_or_web::fs;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std_or_web::fs;
use crate::ui;
use crate::render; use crate::render;
use crate::ui;
use serde_json::{self, Value}; use serde_json::{self, Value};
@ -60,7 +60,8 @@ impl EditServerEntry {
}; };
{ {
let servers = servers_info.as_object_mut() let servers = servers_info
.as_object_mut()
.unwrap() .unwrap()
.get_mut("servers") .get_mut("servers")
.unwrap() .unwrap()
@ -76,7 +77,6 @@ impl EditServerEntry {
let mut out = fs::File::create("servers.json").unwrap(); let mut out = fs::File::create("servers.json").unwrap();
serde_json::to_writer_pretty(&mut out, &servers_info).unwrap(); serde_json::to_writer_pretty(&mut out, &servers_info).unwrap();
} }
} }
impl super::Screen for EditServerEntry { impl super::Screen for EditServerEntry {
@ -131,7 +131,8 @@ impl super::Screen for EditServerEntry {
&server_name.borrow().input, &server_name.borrow().input,
&server_address.borrow().input, &server_address.borrow().input,
); );
game.screen_sys.replace_screen(Box::new(super::ServerList::new(None))); game.screen_sys
.replace_screen(Box::new(super::ServerList::new(None)));
true true
}); });
} }
@ -150,7 +151,8 @@ impl super::Screen for EditServerEntry {
.attach(&mut *cancel); .attach(&mut *cancel);
cancel.add_text(txt); cancel.add_text(txt);
cancel.add_click_func(|_, game| { cancel.add_click_func(|_, game| {
game.screen_sys.replace_screen(Box::new(super::ServerList::new(None))); game.screen_sys
.replace_screen(Box::new(super::ServerList::new(None)));
true true
}); });
} }
@ -169,11 +171,12 @@ impl super::Screen for EditServerEntry {
self.elements = None self.elements = None
} }
fn tick(&mut self, fn tick(
_delta: f64, &mut self,
renderer: &mut render::Renderer, _delta: f64,
_ui_container: &mut ui::Container) -> Option<Box<dyn super::Screen>> { renderer: &mut render::Renderer,
_ui_container: &mut ui::Container,
) -> Option<Box<dyn super::Screen>> {
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
elements.logo.tick(renderer); elements.logo.tick(renderer);
None None

View File

@ -19,12 +19,12 @@ use std::thread;
use rand::{self, Rng}; use rand::{self, Rng};
use crate::ui; use crate::auth;
use crate::render;
use crate::console; use crate::console;
use crate::protocol; use crate::protocol;
use crate::protocol::mojang; use crate::protocol::mojang;
use crate::auth; use crate::render;
use crate::ui;
pub struct Login { pub struct Login {
elements: Option<UIElements>, elements: Option<UIElements>,
@ -47,10 +47,12 @@ struct UIElements {
profile: mojang::Profile, profile: mojang::Profile,
} }
impl Login { impl Login {
pub fn new(vars: Rc<console::Vars>) -> Login { pub fn new(vars: Rc<console::Vars>) -> Login {
Login { elements: None, vars: vars } Login {
elements: None,
vars: vars,
}
} }
} }
@ -82,7 +84,6 @@ impl super::Screen for Login {
}); });
} }
// Login Error // Login Error
let login_error = ui::TextBuilder::new() let login_error = ui::TextBuilder::new()
.text("") .text("")
@ -157,10 +158,12 @@ impl super::Screen for Login {
self.elements = None self.elements = None
} }
fn tick(&mut self, fn tick(
_delta: f64, &mut self,
renderer: &mut render::Renderer, _delta: f64,
_ui_container: &mut ui::Container) -> Option<Box<dyn super::Screen>> { renderer: &mut render::Renderer,
_ui_container: &mut ui::Container,
) -> Option<Box<dyn super::Screen>> {
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
if elements.try_login.get() && elements.login_res.is_none() { if elements.try_login.get() && elements.login_res.is_none() {
@ -171,10 +174,10 @@ impl super::Screen for Login {
elements.login_btn_text.borrow_mut().text = "Logging in...".into(); elements.login_btn_text.borrow_mut().text = "Logging in...".into();
let mut client_token = self.vars.get(auth::AUTH_CLIENT_TOKEN).clone(); let mut client_token = self.vars.get(auth::AUTH_CLIENT_TOKEN).clone();
if client_token.is_empty() { if client_token.is_empty() {
client_token = std::iter::repeat(()).map(|()| rand::thread_rng() client_token = std::iter::repeat(())
.sample(&rand::distributions::Alphanumeric)) .map(|()| rand::thread_rng().sample(&rand::distributions::Alphanumeric))
.take(20) .take(20)
.collect(); .collect();
self.vars.set(auth::AUTH_CLIENT_TOKEN, client_token); self.vars.set(auth::AUTH_CLIENT_TOKEN, client_token);
} }
let client_token = self.vars.get(auth::AUTH_CLIENT_TOKEN).clone(); let client_token = self.vars.get(auth::AUTH_CLIENT_TOKEN).clone();
@ -186,7 +189,8 @@ impl super::Screen for Login {
if refresh { if refresh {
tx.send(profile.refresh(&client_token)).unwrap(); tx.send(profile.refresh(&client_token)).unwrap();
} else { } else {
tx.send(mojang::Profile::login(&username, &password, &client_token)).unwrap(); tx.send(mojang::Profile::login(&username, &password, &client_token))
.unwrap();
} }
}); });
} }
@ -203,10 +207,10 @@ impl super::Screen for Login {
self.vars.set(auth::AUTH_TOKEN, val.access_token.clone()); self.vars.set(auth::AUTH_TOKEN, val.access_token.clone());
elements.profile = val; elements.profile = val;
return Some(Box::new(super::ServerList::new(None))); return Some(Box::new(super::ServerList::new(None)));
}, }
Err(err) => { Err(err) => {
elements.login_error.borrow_mut().text = format!("{}", err); elements.login_error.borrow_mut().text = format!("{}", err);
}, }
} }
} }
} }

View File

@ -21,31 +21,30 @@ pub mod connecting;
pub mod edit_server; pub mod edit_server;
pub mod settings_menu; pub mod settings_menu;
pub use self::settings_menu::{SettingsMenu, VideoSettingsMenu, AudioSettingsMenu}; pub use self::settings_menu::{AudioSettingsMenu, SettingsMenu, VideoSettingsMenu};
use crate::render; use crate::render;
use crate::ui; use crate::ui;
pub trait Screen { pub trait Screen {
// Called once // Called once
fn init(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) { fn init(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {}
} fn deinit(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {}
fn deinit(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
}
// May be called multiple times // May be called multiple times
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container); fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container);
fn on_deactive(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container); fn on_deactive(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container);
// Called every frame the screen is active // Called every frame the screen is active
fn tick(&mut self, fn tick(
delta: f64, &mut self,
renderer: &mut render::Renderer, delta: f64,
ui_container: &mut ui::Container) -> Option<Box<dyn Screen>>; renderer: &mut render::Renderer,
ui_container: &mut ui::Container,
) -> Option<Box<dyn Screen>>;
// Events // Events
fn on_scroll(&mut self, _x: f64, _y: f64) { fn on_scroll(&mut self, _x: f64, _y: f64) {}
}
fn is_closable(&self) -> bool { fn is_closable(&self) -> bool {
false false
@ -65,7 +64,9 @@ pub struct ScreenSystem {
} }
impl ScreenSystem { impl ScreenSystem {
pub fn new() -> ScreenSystem { Default::default() } pub fn new() -> ScreenSystem {
Default::default()
}
pub fn add_screen(&mut self, screen: Box<dyn Screen>) { pub fn add_screen(&mut self, screen: Box<dyn Screen>) {
self.screens.push(ScreenInfo { self.screens.push(ScreenInfo {
@ -94,10 +95,12 @@ impl ScreenSystem {
} }
} }
pub fn tick(&mut self, pub fn tick(
delta: f64, &mut self,
renderer: &mut render::Renderer, delta: f64,
ui_container: &mut ui::Container) { renderer: &mut render::Renderer,
ui_container: &mut ui::Container,
) {
for screen in &mut self.remove_queue { for screen in &mut self.remove_queue {
if screen.active { if screen.active {
screen.screen.on_deactive(renderer, ui_container); screen.screen.on_deactive(renderer, ui_container);

View File

@ -12,24 +12,24 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std_or_web::fs;
use std::thread;
use std::sync::mpsc;
use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;
use std_or_web::fs;
use crate::ui;
use crate::render;
use crate::format; use crate::format;
use crate::format::{Component, TextComponent}; use crate::format::{Component, TextComponent};
use crate::protocol; use crate::protocol;
use crate::render;
use crate::ui;
use serde_json;
use std::time::{Duration};
use image;
use base64; use base64;
use image;
use rand; use rand;
use rand::Rng; use rand::Rng;
use serde_json;
use std::time::Duration;
pub struct ServerList { pub struct ServerList {
elements: Option<UIElements>, elements: Option<UIElements>,
@ -98,9 +98,11 @@ impl ServerList {
} }
} }
fn reload_server_list(&mut self, fn reload_server_list(
renderer: &mut render::Renderer, &mut self,
ui_container: &mut ui::Container) { renderer: &mut render::Renderer,
ui_container: &mut ui::Container,
) {
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
*self.needs_reload.borrow_mut() = false; *self.needs_reload.borrow_mut() = false;
{ {
@ -141,15 +143,12 @@ impl ServerList {
let mut backr = back.borrow_mut(); let mut backr = back.borrow_mut();
let address = address.clone(); let address = address.clone();
backr.add_hover_func(move |this, over, _| { backr.add_hover_func(move |this, over, _| {
this.colour.3 = if over { this.colour.3 = if over { 200 } else { 100 };
200
} else {
100
};
false false
}); });
backr.add_click_func(move |_, game| { backr.add_click_func(move |_, game| {
game.screen_sys.replace_screen(Box::new(super::connecting::Connecting::new(&address))); game.screen_sys
.replace_screen(Box::new(super::connecting::Connecting::new(&address)));
game.connect_to(&address); game.connect_to(&address);
true true
}); });
@ -168,7 +167,6 @@ impl ServerList {
.size(90.0, 90.0) .size(90.0, 90.0)
.attach(&mut *back.borrow_mut()); .attach(&mut *back.borrow_mut());
// Ping indicator // Ping indicator
let ping = ui::ImageBuilder::new() let ping = ui::ImageBuilder::new()
.texture("gui/icons") .texture("gui/icons")
@ -232,9 +230,13 @@ impl ServerList {
let sname = name.clone(); let sname = name.clone();
let saddr = address.clone(); let saddr = address.clone();
btn.add_click_func(move |_, game| { btn.add_click_func(move |_, game| {
game.screen_sys.replace_screen(Box::new(super::edit_server::EditServerEntry::new( game.screen_sys.replace_screen(Box::new(
Some((index, sname.clone(), saddr.clone())) super::edit_server::EditServerEntry::new(Some((
))); index,
sname.clone(),
saddr.clone(),
))),
));
true true
}) })
} }
@ -260,7 +262,9 @@ impl ServerList {
// Don't block the main thread whilst pinging the server // Don't block the main thread whilst pinging the server
thread::spawn(move || { thread::spawn(move || {
match protocol::Conn::new(&address, protocol::SUPPORTED_PROTOCOLS[0]).and_then(|conn| conn.do_status()) { match protocol::Conn::new(&address, protocol::SUPPORTED_PROTOCOLS[0])
.and_then(|conn| conn.do_status())
{
Ok(res) => { Ok(res) => {
let mut desc = res.0.description; let mut desc = res.0.description;
format::convert_legacy(&mut desc); format::convert_legacy(&mut desc);
@ -345,9 +349,8 @@ impl super::Screen for ServerList {
.attach(&mut *add); .attach(&mut *add);
add.add_text(txt); add.add_text(txt);
add.add_click_func(move |_, game| { add.add_click_func(move |_, game| {
game.screen_sys.replace_screen(Box::new(super::edit_server::EditServerEntry::new( game.screen_sys
None .replace_screen(Box::new(super::edit_server::EditServerEntry::new(None)));
)));
true true
}) })
} }
@ -367,7 +370,8 @@ impl super::Screen for ServerList {
.alignment(ui::VAttach::Middle, ui::HAttach::Center) .alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *options); .attach(&mut *options);
options.add_click_func(|_, game| { options.add_click_func(|_, game| {
game.screen_sys.add_screen(Box::new(super::SettingsMenu::new(game.vars.clone(), false))); game.screen_sys
.add_screen(Box::new(super::SettingsMenu::new(game.vars.clone(), false)));
true true
}); });
} }
@ -386,7 +390,10 @@ impl super::Screen for ServerList {
let background = ui::ImageBuilder::new() let background = ui::ImageBuilder::new()
.texture("steven:solid") .texture("steven:solid")
.position(0.0, 3.0) .position(0.0, 3.0)
.size(width.max(renderer.ui.size_of_string("Disconnected")) + 4.0, height + 4.0 + 16.0) .size(
width.max(renderer.ui.size_of_string("Disconnected")) + 4.0,
height + 4.0 + 16.0,
)
.colour((0, 0, 0, 100)) .colour((0, 0, 0, 100))
.alignment(ui::VAttach::Top, ui::HAttach::Center) .alignment(ui::VAttach::Top, ui::HAttach::Center)
.draw_index(10) .draw_index(10)
@ -435,10 +442,12 @@ impl super::Screen for ServerList {
self.elements = None self.elements = None
} }
fn tick(&mut self, fn tick(
delta: f64, &mut self,
renderer: &mut render::Renderer, delta: f64,
ui_container: &mut ui::Container) -> Option<Box<dyn super::Screen>> { renderer: &mut render::Renderer,
ui_container: &mut ui::Container,
) -> Option<Box<dyn super::Screen>> {
if *self.needs_reload.borrow() { if *self.needs_reload.borrow() {
self.reload_server_list(renderer, ui_container); self.reload_server_list(renderer, ui_container);
} }
@ -468,20 +477,23 @@ impl super::Screen for ServerList {
s.motd.borrow_mut().set_text(res.motd); s.motd.borrow_mut().set_text(res.motd);
// Selects the icon for the given ping range // Selects the icon for the given ping range
// TODO: switch to as_millis() experimental duration_as_u128 #50202 once available? // TODO: switch to as_millis() experimental duration_as_u128 #50202 once available?
let ping_ms = (res.ping.subsec_nanos() as f64)/1000000.0 + (res.ping.as_secs() as f64)*1000.0; let ping_ms = (res.ping.subsec_nanos() as f64) / 1000000.0
+ (res.ping.as_secs() as f64) * 1000.0;
let y = match ping_ms.round() as u64 { let y = match ping_ms.round() as u64 {
_x @ 0 ..= 75 => 16.0 / 256.0, _x @ 0..=75 => 16.0 / 256.0,
_x @ 76 ..= 150 => 24.0 / 256.0, _x @ 76..=150 => 24.0 / 256.0,
_x @ 151 ..= 225 => 32.0 / 256.0, _x @ 151..=225 => 32.0 / 256.0,
_x @ 226 ..= 350 => 40.0 / 256.0, _x @ 226..=350 => 40.0 / 256.0,
_x @ 351 ..= 999 => 48.0 / 256.0, _x @ 351..=999 => 48.0 / 256.0,
_ => 56.0 / 256.0, _ => 56.0 / 256.0,
}; };
s.ping.borrow_mut().texture_coords.1 = y; s.ping.borrow_mut().texture_coords.1 = y;
if res.exists { if res.exists {
{ {
let mut players = s.players.borrow_mut(); let mut players = s.players.borrow_mut();
let txt = if protocol::SUPPORTED_PROTOCOLS.contains(&res.protocol_version) { let txt = if protocol::SUPPORTED_PROTOCOLS
.contains(&res.protocol_version)
{
players.colour.1 = 255; players.colour.1 = 255;
players.colour.2 = 255; players.colour.2 = 255;
format!("{}/{}", res.online, res.max) format!("{}/{}", res.online, res.max)
@ -492,8 +504,13 @@ impl super::Screen for ServerList {
}; };
players.text = txt; players.text = txt;
} }
let sm = format!("{} mods + {}", res.forge_mods.len(), res.protocol_name); let sm =
let st = if res.forge_mods.len() > 0 { &sm } else { &res.protocol_name }; format!("{} mods + {}", res.forge_mods.len(), res.protocol_name);
let st = if res.forge_mods.len() > 0 {
&sm
} else {
&res.protocol_name
};
let mut txt = TextComponent::new(&st); let mut txt = TextComponent::new(&st);
txt.modifier.color = Some(format::Color::Yellow); txt.modifier.color = Some(format::Color::Yellow);
let mut msg = Component::Text(txt); let mut msg = Component::Text(txt);
@ -501,15 +518,15 @@ impl super::Screen for ServerList {
s.version.borrow_mut().set_text(msg); s.version.borrow_mut().set_text(msg);
} }
if let Some(favicon) = res.favicon { if let Some(favicon) = res.favicon {
let name: String = std::iter::repeat(()).map(|()| rand::thread_rng() let name: String = std::iter::repeat(())
.sample(&rand::distributions::Alphanumeric)) .map(|()| {
.take(30) rand::thread_rng().sample(&rand::distributions::Alphanumeric)
.collect(); })
.take(30)
.collect();
let tex = renderer.get_textures_ref(); let tex = renderer.get_textures_ref();
s.icon_texture = Some(name.clone()); s.icon_texture = Some(name.clone());
let icon_tex = tex.write() let icon_tex = tex.write().unwrap().put_dynamic(&name, favicon);
.unwrap()
.put_dynamic(&name, favicon);
s.icon.borrow_mut().texture = icon_tex.name; s.icon.borrow_mut().texture = icon_tex.name;
} }
} }

View File

@ -1,7 +1,7 @@
use crate::console; use crate::console;
use crate::render; use crate::render;
use crate::ui;
use crate::settings; use crate::settings;
use crate::ui;
use std::rc::Rc; use std::rc::Rc;
@ -13,7 +13,7 @@ pub struct UIElements {
pub struct SettingsMenu { pub struct SettingsMenu {
_vars: Rc<console::Vars>, _vars: Rc<console::Vars>,
elements: Option<UIElements>, elements: Option<UIElements>,
show_disconnect_button: bool show_disconnect_button: bool,
} }
impl SettingsMenu { impl SettingsMenu {
@ -21,7 +21,7 @@ impl SettingsMenu {
SettingsMenu { SettingsMenu {
_vars: vars, _vars: vars,
elements: None, elements: None,
show_disconnect_button: show_disconnect_button show_disconnect_button: show_disconnect_button,
} }
} }
} }
@ -51,7 +51,8 @@ impl super::Screen for SettingsMenu {
.attach(&mut *audio_settings); .attach(&mut *audio_settings);
audio_settings.add_text(txt); audio_settings.add_text(txt);
audio_settings.add_click_func(|_, game| { audio_settings.add_click_func(|_, game| {
game.screen_sys.add_screen(Box::new(AudioSettingsMenu::new(game.vars.clone()))); game.screen_sys
.add_screen(Box::new(AudioSettingsMenu::new(game.vars.clone())));
true true
}); });
} }
@ -70,7 +71,8 @@ impl super::Screen for SettingsMenu {
.attach(&mut *video_settings); .attach(&mut *video_settings);
video_settings.add_text(txt); video_settings.add_text(txt);
video_settings.add_click_func(|_, game| { video_settings.add_click_func(|_, game| {
game.screen_sys.add_screen(Box::new(VideoSettingsMenu::new(game.vars.clone()))); game.screen_sys
.add_screen(Box::new(VideoSettingsMenu::new(game.vars.clone())));
true true
}); });
} }
@ -142,7 +144,8 @@ impl super::Screen for SettingsMenu {
disconnect_button.add_text(txt); disconnect_button.add_text(txt);
disconnect_button.add_click_func(|_, game| { disconnect_button.add_click_func(|_, game| {
game.server.disconnect(None); game.server.disconnect(None);
game.screen_sys.replace_screen(Box::new(super::ServerList::new(None))); game.screen_sys
.replace_screen(Box::new(super::ServerList::new(None)));
true true
}); });
} }
@ -153,14 +156,18 @@ impl super::Screen for SettingsMenu {
background, background,
_buttons: buttons, _buttons: buttons,
}); });
} }
fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) { fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
self.elements = None; self.elements = None;
} }
// Called every frame the screen is active // Called every frame the screen is active
fn tick(&mut self, _delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) -> Option<Box<dyn super::Screen>> { fn tick(
&mut self,
_delta: f64,
renderer: &mut render::Renderer,
ui_container: &mut ui::Container,
) -> Option<Box<dyn super::Screen>> {
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
{ {
let mode = ui_container.mode; let mode = ui_container.mode;
@ -178,9 +185,7 @@ impl super::Screen for SettingsMenu {
} }
// Events // Events
fn on_scroll(&mut self, _x: f64, _y: f64) { fn on_scroll(&mut self, _x: f64, _y: f64) {}
}
fn is_closable(&self) -> bool { fn is_closable(&self) -> bool {
true true
@ -227,11 +232,14 @@ impl super::Screen for VideoSettingsMenu {
{ {
let mut fov_setting = fov_setting.borrow_mut(); let mut fov_setting = fov_setting.borrow_mut();
let txt = ui::TextBuilder::new() let txt = ui::TextBuilder::new()
.text(format!("FOV: {}", match r_fov { .text(format!(
90 => "Normal".into(), "FOV: {}",
110 => "Quake pro".into(), match r_fov {
val => val.to_string(), 90 => "Normal".into(),
})) 110 => "Quake pro".into(),
val => val.to_string(),
}
))
.alignment(ui::VAttach::Middle, ui::HAttach::Center) .alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *fov_setting); .attach(&mut *fov_setting);
fov_setting.add_text(txt); fov_setting.add_text(txt);
@ -246,14 +254,18 @@ impl super::Screen for VideoSettingsMenu {
{ {
let mut vsync_setting = vsync_setting.borrow_mut(); let mut vsync_setting = vsync_setting.borrow_mut();
let txt = ui::TextBuilder::new() let txt = ui::TextBuilder::new()
.text(format!("VSync: {}", if r_vsync { "Enabled" } else { "Disabled" })) .text(format!(
"VSync: {}",
if r_vsync { "Enabled" } else { "Disabled" }
))
.alignment(ui::VAttach::Middle, ui::HAttach::Center) .alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *vsync_setting); .attach(&mut *vsync_setting);
let txt_vsync = txt.clone(); let txt_vsync = txt.clone();
vsync_setting.add_text(txt); vsync_setting.add_text(txt);
vsync_setting.add_click_func(move |_, game| { vsync_setting.add_click_func(move |_, game| {
let r_vsync = !*game.vars.get(settings::R_VSYNC); let r_vsync = !*game.vars.get(settings::R_VSYNC);
txt_vsync.borrow_mut().text = format!("VSync: {}", if r_vsync { "Enabled" } else { "Disabled" }); txt_vsync.borrow_mut().text =
format!("VSync: {}", if r_vsync { "Enabled" } else { "Disabled" });
game.vars.set(settings::R_VSYNC, r_vsync); game.vars.set(settings::R_VSYNC, r_vsync);
true true
}); });
@ -269,10 +281,13 @@ impl super::Screen for VideoSettingsMenu {
{ {
let mut fps_setting = fps_setting.borrow_mut(); let mut fps_setting = fps_setting.borrow_mut();
let txt = ui::TextBuilder::new() let txt = ui::TextBuilder::new()
.text(format!("FPS cap: {}", match r_max_fps { .text(format!(
0 => "Unlimited".into(), "FPS cap: {}",
val => val.to_string(), match r_max_fps {
})) 0 => "Unlimited".into(),
val => val.to_string(),
}
))
.alignment(ui::VAttach::Middle, ui::HAttach::Center) .alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *fps_setting); .attach(&mut *fps_setting);
fps_setting.add_text(txt); fps_setting.add_text(txt);
@ -302,14 +317,18 @@ impl super::Screen for VideoSettingsMenu {
background, background,
_buttons: buttons, _buttons: buttons,
}); });
} }
fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) { fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
self.elements = None; self.elements = None;
} }
// Called every frame the screen is active // Called every frame the screen is active
fn tick(&mut self, _delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) -> Option<Box<dyn super::Screen>> { fn tick(
&mut self,
_delta: f64,
renderer: &mut render::Renderer,
ui_container: &mut ui::Container,
) -> Option<Box<dyn super::Screen>> {
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
{ {
let mode = ui_container.mode; let mode = ui_container.mode;
@ -327,9 +346,7 @@ impl super::Screen for VideoSettingsMenu {
} }
// Events // Events
fn on_scroll(&mut self, _x: f64, _y: f64) { fn on_scroll(&mut self, _x: f64, _y: f64) {}
}
fn is_closable(&self) -> bool { fn is_closable(&self) -> bool {
true true
@ -338,14 +355,14 @@ impl super::Screen for VideoSettingsMenu {
pub struct AudioSettingsMenu { pub struct AudioSettingsMenu {
_vars: Rc<console::Vars>, _vars: Rc<console::Vars>,
elements: Option<UIElements> elements: Option<UIElements>,
} }
impl AudioSettingsMenu { impl AudioSettingsMenu {
pub fn new(vars: Rc<console::Vars>) -> AudioSettingsMenu { pub fn new(vars: Rc<console::Vars>) -> AudioSettingsMenu {
AudioSettingsMenu { AudioSettingsMenu {
_vars: vars, _vars: vars,
elements: None elements: None,
} }
} }
} }
@ -387,14 +404,18 @@ impl super::Screen for AudioSettingsMenu {
background, background,
_buttons: buttons, _buttons: buttons,
}); });
} }
fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) { fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
self.elements = None; self.elements = None;
} }
// Called every frame the screen is active // Called every frame the screen is active
fn tick(&mut self, _delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) -> Option<Box<dyn super::Screen>> { fn tick(
&mut self,
_delta: f64,
renderer: &mut render::Renderer,
ui_container: &mut ui::Container,
) -> Option<Box<dyn super::Screen>> {
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
{ {
let mode = ui_container.mode; let mode = ui_container.mode;
@ -412,9 +433,7 @@ impl super::Screen for AudioSettingsMenu {
} }
// Events // Events
fn on_scroll(&mut self, _x: f64, _y: f64) { fn on_scroll(&mut self, _x: f64, _y: f64) {}
}
fn is_closable(&self) -> bool { fn is_closable(&self) -> bool {
true true

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,3 @@
use crate::protocol::packet::play::serverbound::PluginMessageServerbound; use crate::protocol::packet::play::serverbound::PluginMessageServerbound;
use crate::protocol::packet::play::serverbound::PluginMessageServerbound_i16; use crate::protocol::packet::play::serverbound::PluginMessageServerbound_i16;
use crate::protocol::{Serializable, VarShort}; use crate::protocol::{Serializable, VarShort};
@ -34,5 +33,4 @@ impl Brand {
data: crate::protocol::LenPrefixedBytes::<VarShort>::new(data), data: crate::protocol::LenPrefixedBytes::<VarShort>::new(data),
} }
} }
} }

View File

@ -1,7 +1,6 @@
use crate::render; use crate::render;
use crate::render::model; use crate::render::model;
use cgmath::{Vector3, Matrix4, Decomposed, Rotation3, Rad, Quaternion}; use cgmath::{Decomposed, Matrix4, Quaternion, Rad, Rotation3, Vector3};
pub struct SunModel { pub struct SunModel {
sun: model::ModelKey, sun: model::ModelKey,
@ -12,7 +11,6 @@ pub struct SunModel {
const SIZE: f32 = 50.0; const SIZE: f32 = 50.0;
impl SunModel { impl SunModel {
pub fn new(renderer: &mut render::Renderer) -> SunModel { pub fn new(renderer: &mut render::Renderer) -> SunModel {
SunModel { SunModel {
sun: SunModel::generate_sun(renderer), sun: SunModel::generate_sun(renderer),
@ -71,26 +69,123 @@ impl SunModel {
renderer.model.create_model( renderer.model.create_model(
model::SUN, model::SUN,
vec![vec![ vec![vec![
model::Vertex{x: 0.0, y: -SIZE, z: -SIZE, texture_x: 0.0, texture_y: 1.0, texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0}, model::Vertex {
model::Vertex{x: 0.0, y: SIZE, z: -SIZE, texture_x: 0.0, texture_y: 0.0, texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0}, x: 0.0,
model::Vertex{x: 0.0, y: -SIZE, z: SIZE, texture_x: 1.0, texture_y: 1.0, texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0}, y: -SIZE,
model::Vertex{x: 0.0, y: SIZE, z: SIZE, texture_x: 1.0, texture_y: 0.0, texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0} z: -SIZE,
]] texture_x: 0.0,
texture_y: 1.0,
texture: tex.clone(),
r: 255,
g: 255,
b: 255,
a: 0,
id: 0,
},
model::Vertex {
x: 0.0,
y: SIZE,
z: -SIZE,
texture_x: 0.0,
texture_y: 0.0,
texture: tex.clone(),
r: 255,
g: 255,
b: 255,
a: 0,
id: 0,
},
model::Vertex {
x: 0.0,
y: -SIZE,
z: SIZE,
texture_x: 1.0,
texture_y: 1.0,
texture: tex.clone(),
r: 255,
g: 255,
b: 255,
a: 0,
id: 0,
},
model::Vertex {
x: 0.0,
y: SIZE,
z: SIZE,
texture_x: 1.0,
texture_y: 0.0,
texture: tex.clone(),
r: 255,
g: 255,
b: 255,
a: 0,
id: 0,
},
]],
) )
} }
pub fn generate_moon(renderer: &mut render::Renderer, phase: i32) -> model::ModelKey { pub fn generate_moon(renderer: &mut render::Renderer, phase: i32) -> model::ModelKey {
let tex = render::Renderer::get_texture(renderer.get_textures_ref(), "environment/moon_phases"); let tex =
render::Renderer::get_texture(renderer.get_textures_ref(), "environment/moon_phases");
let mpx = (phase % 4) as f64 * (1.0 / 4.0); let mpx = (phase % 4) as f64 * (1.0 / 4.0);
let mpy = (phase / 4) as f64 * (1.0 / 2.0); let mpy = (phase / 4) as f64 * (1.0 / 2.0);
renderer.model.create_model( renderer.model.create_model(
model::SUN, model::SUN,
vec![vec![ vec![vec![
model::Vertex{x: 0.0, y: -SIZE, z: -SIZE, texture_x: mpx, texture_y: mpy + (1.0 / 2.0), texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0}, model::Vertex {
model::Vertex{x: 0.0, y: SIZE, z: -SIZE, texture_x: mpx, texture_y: mpy, texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0}, x: 0.0,
model::Vertex{x: 0.0, y: -SIZE, z: SIZE, texture_x: mpx + (1.0 / 4.0), texture_y: mpy + (1.0 / 2.0), texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0}, y: -SIZE,
model::Vertex{x: 0.0, y: SIZE, z: SIZE, texture_x: mpx + (1.0 / 4.0), texture_y: mpy, texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0} z: -SIZE,
]] texture_x: mpx,
texture_y: mpy + (1.0 / 2.0),
texture: tex.clone(),
r: 255,
g: 255,
b: 255,
a: 0,
id: 0,
},
model::Vertex {
x: 0.0,
y: SIZE,
z: -SIZE,
texture_x: mpx,
texture_y: mpy,
texture: tex.clone(),
r: 255,
g: 255,
b: 255,
a: 0,
id: 0,
},
model::Vertex {
x: 0.0,
y: -SIZE,
z: SIZE,
texture_x: mpx + (1.0 / 4.0),
texture_y: mpy + (1.0 / 2.0),
texture: tex.clone(),
r: 255,
g: 255,
b: 255,
a: 0,
id: 0,
},
model::Vertex {
x: 0.0,
y: SIZE,
z: SIZE,
texture_x: mpx + (1.0 / 4.0),
texture_y: mpy,
texture: tex.clone(),
r: 255,
g: 255,
b: 255,
a: 0,
id: 0,
},
]],
) )
} }
} }

View File

@ -1,10 +1,9 @@
use crate::world;
use crate::world::block;
use crate::shared::{Position, Direction};
use cgmath;
use crate::render; use crate::render;
use crate::render::model; use crate::render::model;
use crate::shared::{Direction, Position};
use crate::world;
use crate::world::block;
use cgmath;
use collision::{self, Aabb}; use collision::{self, Aabb};
pub struct Info { pub struct Info {
@ -17,13 +16,13 @@ impl Info {
pub fn new() -> Info { pub fn new() -> Info {
Info { Info {
model: None, model: None,
last_block: block::Air{}, last_block: block::Air {},
last_pos: Position::new(0, 0, 0), last_pos: Position::new(0, 0, 0),
} }
} }
pub fn clear(&mut self, renderer: &mut render::Renderer) { pub fn clear(&mut self, renderer: &mut render::Renderer) {
self.last_block = block::Air{}; self.last_block = block::Air {};
if let Some(model) = self.model.take() { if let Some(model) = self.model.take() {
renderer.model.remove_model(model); renderer.model.remove_model(model);
} }
@ -44,16 +43,27 @@ impl Info {
let tex = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"); let tex = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid");
for bound in bl.get_collision_boxes() { for bound in bl.get_collision_boxes() {
let bound = bound.add_v(cgmath::Vector3::new(pos.x as f64, pos.y as f64, pos.z as f64)); let bound = bound.add_v(cgmath::Vector3::new(
pos.x as f64,
pos.y as f64,
pos.z as f64,
));
for point in [ for point in [
(bound.min.x, bound.min.z), (bound.min.x, bound.min.z),
(bound.min.x, bound.max.z), (bound.min.x, bound.max.z),
(bound.max.x, bound.min.z), (bound.max.x, bound.min.z),
(bound.max.x, bound.max.z), (bound.max.x, bound.max.z),
].iter() { ]
model::append_box(&mut parts, .iter()
(point.0-LINE_SIZE) as f32, (bound.min.y-LINE_SIZE) as f32, (point.1-LINE_SIZE) as f32, {
(LINE_SIZE*2.0) as f32, ((bound.max.y-bound.min.y)+LINE_SIZE*2.0) as f32, (LINE_SIZE*2.0) as f32, model::append_box(
&mut parts,
(point.0 - LINE_SIZE) as f32,
(bound.min.y - LINE_SIZE) as f32,
(point.1 - LINE_SIZE) as f32,
(LINE_SIZE * 2.0) as f32,
((bound.max.y - bound.min.y) + LINE_SIZE * 2.0) as f32,
(LINE_SIZE * 2.0) as f32,
[ [
Some(tex.clone()), Some(tex.clone()),
Some(tex.clone()), Some(tex.clone()),
@ -61,7 +71,8 @@ impl Info {
Some(tex.clone()), Some(tex.clone()),
Some(tex.clone()), Some(tex.clone()),
Some(tex.clone()), Some(tex.clone()),
]); ],
);
} }
for point in [ for point in [
@ -69,10 +80,17 @@ impl Info {
(bound.min.x, bound.max.z, bound.max.x, bound.max.z), (bound.min.x, bound.max.z, bound.max.x, bound.max.z),
(bound.min.x, bound.min.z, bound.min.x, bound.max.z), (bound.min.x, bound.min.z, bound.min.x, bound.max.z),
(bound.max.x, bound.min.z, bound.max.x, bound.max.z), (bound.max.x, bound.min.z, bound.max.x, bound.max.z),
].iter() { ]
model::append_box(&mut parts, .iter()
(point.0-LINE_SIZE) as f32, (bound.min.y-LINE_SIZE) as f32, (point.1-LINE_SIZE) as f32, {
((point.2-point.0)+(LINE_SIZE*2.0)) as f32, (LINE_SIZE*2.0) as f32, ((point.3-point.1)+(LINE_SIZE*2.0)) as f32, model::append_box(
&mut parts,
(point.0 - LINE_SIZE) as f32,
(bound.min.y - LINE_SIZE) as f32,
(point.1 - LINE_SIZE) as f32,
((point.2 - point.0) + (LINE_SIZE * 2.0)) as f32,
(LINE_SIZE * 2.0) as f32,
((point.3 - point.1) + (LINE_SIZE * 2.0)) as f32,
[ [
Some(tex.clone()), Some(tex.clone()),
Some(tex.clone()), Some(tex.clone()),
@ -80,10 +98,16 @@ impl Info {
Some(tex.clone()), Some(tex.clone()),
Some(tex.clone()), Some(tex.clone()),
Some(tex.clone()), Some(tex.clone()),
]); ],
model::append_box(&mut parts, );
(point.0-LINE_SIZE) as f32, (bound.max.y-LINE_SIZE) as f32, (point.1-LINE_SIZE) as f32, model::append_box(
((point.2-point.0)+(LINE_SIZE*2.0)) as f32, (LINE_SIZE*2.0) as f32, ((point.3-point.1)+(LINE_SIZE*2.0)) as f32, &mut parts,
(point.0 - LINE_SIZE) as f32,
(bound.max.y - LINE_SIZE) as f32,
(point.1 - LINE_SIZE) as f32,
((point.2 - point.0) + (LINE_SIZE * 2.0)) as f32,
(LINE_SIZE * 2.0) as f32,
((point.3 - point.1) + (LINE_SIZE * 2.0)) as f32,
[ [
Some(tex.clone()), Some(tex.clone()),
Some(tex.clone()), Some(tex.clone()),
@ -91,7 +115,8 @@ impl Info {
Some(tex.clone()), Some(tex.clone()),
Some(tex.clone()), Some(tex.clone()),
Some(tex.clone()), Some(tex.clone()),
]); ],
);
} }
} }
@ -105,7 +130,15 @@ impl Info {
} }
} }
pub fn test_block(world: &world::World, pos: Position, s: cgmath::Vector3<f64>, d: cgmath::Vector3<f64>) -> (bool, Option<(Position, block::Block, Direction, cgmath::Vector3<f64>)>) { pub fn test_block(
world: &world::World,
pos: Position,
s: cgmath::Vector3<f64>,
d: cgmath::Vector3<f64>,
) -> (
bool,
Option<(Position, block::Block, Direction, cgmath::Vector3<f64>)>,
) {
let block = world.get_block(pos); let block = world.get_block(pos);
let posf = cgmath::Vector3::new(pos.x as f64, pos.y as f64, pos.z as f64); let posf = cgmath::Vector3::new(pos.x as f64, pos.y as f64, pos.z as f64);
for bound in block.get_collision_boxes() { for bound in block.get_collision_boxes() {
@ -137,7 +170,11 @@ fn find_face(bound: collision::Aabb3<f64>, hit: cgmath::Vector3<f64>) -> Directi
} }
} }
fn intersects_line(bound: collision::Aabb3<f64>, origin: cgmath::Vector3<f64>, dir: cgmath::Vector3<f64>) -> Option<cgmath::Vector3<f64>> { fn intersects_line(
bound: collision::Aabb3<f64>,
origin: cgmath::Vector3<f64>,
dir: cgmath::Vector3<f64>,
) -> Option<cgmath::Vector3<f64>> {
const RIGHT: usize = 0; const RIGHT: usize = 0;
const LEFT: usize = 1; const LEFT: usize = 1;
const MIDDLE: usize = 2; const MIDDLE: usize = 2;
@ -145,7 +182,7 @@ fn intersects_line(bound: collision::Aabb3<f64>, origin: cgmath::Vector3<f64>, d
let mut candidate_plane = [0.0, 0.0, 0.0]; let mut candidate_plane = [0.0, 0.0, 0.0];
let mut max_t = [0.0, 0.0, 0.0]; let mut max_t = [0.0, 0.0, 0.0];
let mut inside = true; let mut inside = true;
for i in 0 .. 3 { for i in 0..3 {
if origin[i] < bound.min[i] { if origin[i] < bound.min[i] {
quadrant[i] = LEFT; quadrant[i] = LEFT;
candidate_plane[i] = bound.min[i]; candidate_plane[i] = bound.min[i];
@ -162,13 +199,13 @@ fn intersects_line(bound: collision::Aabb3<f64>, origin: cgmath::Vector3<f64>, d
return Some(origin); return Some(origin);
} }
for i in 0 .. 3 { for i in 0..3 {
if quadrant[i] != MIDDLE && dir[i] != 0.0 { if quadrant[i] != MIDDLE && dir[i] != 0.0 {
max_t[i] = (candidate_plane[i] - origin[i]) / dir[i]; max_t[i] = (candidate_plane[i] - origin[i]) / dir[i];
} }
} }
let mut which_plane = 0; let mut which_plane = 0;
for i in 1 .. 3 { for i in 1..3 {
if max_t[which_plane] < max_t[i] { if max_t[which_plane] < max_t[i] {
which_plane = i; which_plane = i;
} }
@ -178,7 +215,7 @@ fn intersects_line(bound: collision::Aabb3<f64>, origin: cgmath::Vector3<f64>, d
} }
let mut coord = cgmath::Vector3::new(0.0, 0.0, 0.0); let mut coord = cgmath::Vector3::new(0.0, 0.0, 0.0);
for i in 0 .. 3 { for i in 0..3 {
if which_plane != i { if which_plane != i {
coord[i] = origin[i] + max_t[which_plane] * dir[i]; coord[i] = origin[i] + max_t[which_plane] * dir[i];
if coord[i] < bound.min[i] || coord[i] > bound.max[i] { if coord[i] < bound.min[i] || coord[i] > bound.max[i] {
@ -191,8 +228,16 @@ fn intersects_line(bound: collision::Aabb3<f64>, origin: cgmath::Vector3<f64>, d
Some(coord) Some(coord)
} }
pub fn trace_ray<F, R>(world: &world::World, max: f64, s: cgmath::Vector3<f64>, d: cgmath::Vector3<f64>, collide_func: F) -> Option<R> pub fn trace_ray<F, R>(
where F: Fn(&world::World, Position, cgmath::Vector3<f64>, cgmath::Vector3<f64>,) -> (bool, Option<R>) { world: &world::World,
max: f64,
s: cgmath::Vector3<f64>,
d: cgmath::Vector3<f64>,
collide_func: F,
) -> Option<R>
where
F: Fn(&world::World, Position, cgmath::Vector3<f64>, cgmath::Vector3<f64>) -> (bool, Option<R>),
{
struct Gen { struct Gen {
count: i32, count: i32,
base: f64, base: f64,
@ -208,11 +253,7 @@ pub fn trace_ray<F, R>(world: &world::World, max: f64, s: cgmath::Vector3<f64>,
} else { } else {
0.0 0.0
}; };
Gen { Gen { count: 0, base, d }
count: 0,
base,
d,
}
} }
fn next(&mut self) -> f64 { fn next(&mut self) -> f64 {

View File

@ -1,6 +1,6 @@
use crate::console; use crate::console;
use std::marker::PhantomData;
use glutin::event::VirtualKeyCode; use glutin::event::VirtualKeyCode;
use std::marker::PhantomData;
// Might just rename this to settings.rs // Might just rename this to settings.rs
pub const R_MAX_FPS: console::CVar<i64> = console::CVar { pub const R_MAX_FPS: console::CVar<i64> = console::CVar {
@ -40,24 +40,37 @@ pub const CL_MASTER_VOLUME: console::CVar<i64> = console::CVar {
}; };
macro_rules! create_keybind { macro_rules! create_keybind {
($keycode:ident, $name:expr, $description:expr) => (console::CVar { ($keycode:ident, $name:expr, $description:expr) => {
ty: PhantomData, console::CVar {
name: $name, ty: PhantomData,
description: $description, name: $name,
mutable: true, description: $description,
serializable: true, mutable: true,
default: &|| VirtualKeyCode::$keycode as i64 serializable: true,
}) default: &|| VirtualKeyCode::$keycode as i64,
}
};
} }
pub const CL_KEYBIND_FORWARD: console::CVar<i64> = create_keybind!(W, "cl_keybind_forward", "Keybinding for moving forward"); pub const CL_KEYBIND_FORWARD: console::CVar<i64> =
pub const CL_KEYBIND_BACKWARD: console::CVar<i64> = create_keybind!(S, "cl_keybind_backward", "Keybinding for moving backward"); create_keybind!(W, "cl_keybind_forward", "Keybinding for moving forward");
pub const CL_KEYBIND_LEFT: console::CVar<i64> = create_keybind!(A, "cl_keybind_left", "Keybinding for moving the left"); pub const CL_KEYBIND_BACKWARD: console::CVar<i64> =
pub const CL_KEYBIND_RIGHT: console::CVar<i64> = create_keybind!(D, "cl_keybind_right", "Keybinding for moving to the right"); create_keybind!(S, "cl_keybind_backward", "Keybinding for moving backward");
pub const CL_KEYBIND_OPEN_INV: console::CVar<i64> = create_keybind!(E, "cl_keybind_open_inv", "Keybinding for opening the inventory"); pub const CL_KEYBIND_LEFT: console::CVar<i64> =
pub const CL_KEYBIND_SNEAK: console::CVar<i64> = create_keybind!(LShift, "cl_keybind_sneak", "Keybinding for sneaking"); create_keybind!(A, "cl_keybind_left", "Keybinding for moving the left");
pub const CL_KEYBIND_SPRINT: console::CVar<i64> = create_keybind!(LControl, "cl_keybind_sprint", "Keybinding for sprinting"); pub const CL_KEYBIND_RIGHT: console::CVar<i64> =
pub const CL_KEYBIND_JUMP: console::CVar<i64> = create_keybind!(Space, "cl_keybind_jump", "Keybinding for jumping"); create_keybind!(D, "cl_keybind_right", "Keybinding for moving to the right");
pub const CL_KEYBIND_OPEN_INV: console::CVar<i64> = create_keybind!(
E,
"cl_keybind_open_inv",
"Keybinding for opening the inventory"
);
pub const CL_KEYBIND_SNEAK: console::CVar<i64> =
create_keybind!(LShift, "cl_keybind_sneak", "Keybinding for sneaking");
pub const CL_KEYBIND_SPRINT: console::CVar<i64> =
create_keybind!(LControl, "cl_keybind_sprint", "Keybinding for sprinting");
pub const CL_KEYBIND_JUMP: console::CVar<i64> =
create_keybind!(Space, "cl_keybind_jump", "Keybinding for jumping");
pub const DOUBLE_JUMP_MS: u32 = 100; pub const DOUBLE_JUMP_MS: u32 = 100;
@ -90,15 +103,22 @@ pub enum Stevenkey {
impl Stevenkey { impl Stevenkey {
pub fn values() -> Vec<Stevenkey> { pub fn values() -> Vec<Stevenkey> {
vec!(Stevenkey::Forward, Stevenkey::Backward, Stevenkey::Left, vec![
Stevenkey::Right, Stevenkey::OpenInv, Stevenkey::Sneak, Stevenkey::Forward,
Stevenkey::Sprint, Stevenkey::Jump) Stevenkey::Backward,
Stevenkey::Left,
Stevenkey::Right,
Stevenkey::OpenInv,
Stevenkey::Sneak,
Stevenkey::Sprint,
Stevenkey::Jump,
]
} }
pub fn get_by_keycode(keycode: VirtualKeyCode, vars: &console::Vars) -> Option<Stevenkey> { pub fn get_by_keycode(keycode: VirtualKeyCode, vars: &console::Vars) -> Option<Stevenkey> {
for steven_key in Stevenkey::values() { for steven_key in Stevenkey::values() {
if keycode as i64 == *vars.get(steven_key.get_cvar()) { if keycode as i64 == *vars.get(steven_key.get_cvar()) {
return Some(steven_key) return Some(steven_key);
} }
} }
None None
@ -113,7 +133,7 @@ impl Stevenkey {
Stevenkey::OpenInv => CL_KEYBIND_OPEN_INV, Stevenkey::OpenInv => CL_KEYBIND_OPEN_INV,
Stevenkey::Sneak => CL_KEYBIND_SNEAK, Stevenkey::Sneak => CL_KEYBIND_SNEAK,
Stevenkey::Sprint => CL_KEYBIND_SPRINT, Stevenkey::Sprint => CL_KEYBIND_SPRINT,
Stevenkey::Jump => CL_KEYBIND_JUMP Stevenkey::Jump => CL_KEYBIND_JUMP,
} }
} }
} }

View File

@ -1,12 +1,11 @@
use std::sync::{Arc, RwLock};
use std::f64::consts;
use crate::ui;
use crate::render; use crate::render;
use crate::resources; use crate::resources;
use std::time::{SystemTime, UNIX_EPOCH}; use crate::ui;
use rand::{self, seq::SliceRandom}; use rand::{self, seq::SliceRandom};
use rand_pcg; use rand_pcg;
use std::f64::consts;
use std::sync::{Arc, RwLock};
use std::time::{SystemTime, UNIX_EPOCH};
pub struct Logo { pub struct Logo {
_shadow: ui::BatchRef, _shadow: ui::BatchRef,
@ -20,9 +19,10 @@ pub struct Logo {
} }
impl Logo { impl Logo {
pub fn new(resources: Arc<RwLock<resources::Manager>>, pub fn new(
ui_container: &mut ui::Container) resources: Arc<RwLock<resources::Manager>>,
-> Logo { ui_container: &mut ui::Container,
) -> Logo {
let logo_str = { let logo_str = {
let res = resources.read().unwrap(); let res = resources.read().unwrap();
let mut logo = res.open("steven", "logo/logo.txt").unwrap(); let mut logo = res.open("steven", "logo/logo.txt").unwrap();
@ -66,14 +66,15 @@ impl Logo {
.colour((0, 0, 0, 100)) .colour((0, 0, 0, 100))
.attach(&mut *shadow_batch.borrow_mut()); .attach(&mut *shadow_batch.borrow_mut());
ui::ImageBuilder::new() ui::ImageBuilder::new()
.texture("minecraft:blocks/planks_oak") .texture("minecraft:blocks/planks_oak")
.position(x as f64, y as f64) .position(x as f64, y as f64)
.size(4.0, 8.0) .size(4.0, 8.0)
.texture_coords(( .texture_coords((
(x % 16) as f64 / 16.0, (y % 16) as f64 / 16.0, (x % 16) as f64 / 16.0,
4.0 / 16.0, 8.0 / 16.0 (y % 16) as f64 / 16.0,
4.0 / 16.0,
8.0 / 16.0,
)) ))
.colour((r, g, b, 255)) .colour((r, g, b, 255))
.attach(&mut *layer0.borrow_mut()); .attach(&mut *layer0.borrow_mut());
@ -101,7 +102,8 @@ impl Logo {
text_strings.push(line.to_owned().replace("\r", "")); text_strings.push(line.to_owned().replace("\r", ""));
} }
} }
let mut r: rand_pcg::Pcg32 = rand::SeedableRng::from_seed([45, 0, 0, 0, 64, 0, 0, 0, 32, 0, 0, 0, 12, 0, 0, 0]); let mut r: rand_pcg::Pcg32 =
rand::SeedableRng::from_seed([45, 0, 0, 0, 64, 0, 0, 0, 32, 0, 0, 0, 12, 0, 0, 0]);
text_strings.shuffle(&mut r); text_strings.shuffle(&mut r);
} }
@ -147,7 +149,7 @@ impl Logo {
if self.text_base_scale > 1.0 { if self.text_base_scale > 1.0 {
self.text_base_scale = 1.0; self.text_base_scale = 1.0;
} }
text.x =(-width / 2.0) * self.text_base_scale; text.x = (-width / 2.0) * self.text_base_scale;
self.text_orig_x = text.x; self.text_orig_x = text.x;
} }
@ -160,6 +162,6 @@ impl Logo {
text.scale_x = (0.7 + (offset / 3.0)) * self.text_base_scale; text.scale_x = (0.7 + (offset / 3.0)) * self.text_base_scale;
text.scale_y = (0.7 + (offset / 3.0)) * self.text_base_scale; text.scale_y = (0.7 + (offset / 3.0)) * self.text_base_scale;
let scale = text.scale_x; let scale = text.scale_x;
text.x =self.text_orig_x * scale * self.text_base_scale; text.x = self.text_orig_x * scale * self.text_base_scale;
} }
} }

View File

@ -14,18 +14,17 @@
pub mod logo; pub mod logo;
use std::rc::{Rc, Weak};
use std::cell::{RefCell, RefMut};
use crate::render;
use crate::format; use crate::format;
use glutin::event::VirtualKeyCode; use crate::render;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use clipboard::{ClipboardProvider, ClipboardContext}; use clipboard::{ClipboardContext, ClipboardProvider};
use glutin::event::VirtualKeyCode;
use std::cell::{RefCell, RefMut};
use std::rc::{Rc, Weak};
const SCALED_WIDTH: f64 = 854.0; const SCALED_WIDTH: f64 = 854.0;
const SCALED_HEIGHT: f64 = 480.0; const SCALED_HEIGHT: f64 = 480.0;
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
pub enum Mode { pub enum Mode {
Scaled, Scaled,
@ -56,8 +55,10 @@ struct Region {
impl Region { impl Region {
fn intersects(&self, o: &Region) -> bool { fn intersects(&self, o: &Region) -> bool {
!(self.x + self.w < o.x || self.x > o.x + o.w || self.y + self.h < o.y || !(self.x + self.w < o.x
self.y > o.y + o.h) || self.x > o.x + o.w
|| self.y + self.h < o.y
|| self.y > o.y + o.h)
} }
} }
@ -304,8 +305,13 @@ impl Container {
Mode::Unscaled(scale) => (scale, scale), Mode::Unscaled(scale) => (scale, scale),
}; };
if self.last_sw != sw || self.last_sh != sh || self.last_width != width || if self.last_sw != sw
self.last_height != height || self.version != renderer.ui.version || self.last_mode != self.mode { || self.last_sh != sh
|| self.last_width != width
|| self.last_height != height
|| self.version != renderer.ui.version
|| self.last_mode != self.mode
{
self.last_sw = sw; self.last_sw = sw;
self.last_sh = sh; self.last_sh = sh;
self.last_width = width; self.last_width = width;
@ -324,9 +330,12 @@ impl Container {
// If we don't have an element focused, focus one // If we don't have an element focused, focus one
if !self.focusable_elements.is_empty() if !self.focusable_elements.is_empty()
&& !self.focusable_elements.iter() && !self
.flat_map(|v| v.upgrade()) .focusable_elements
.any(|v| v.is_focused()) { .iter()
.flat_map(|v| v.upgrade())
.any(|v| v.is_focused())
{
self.cycle_focus() self.cycle_focus()
} }
@ -380,13 +389,14 @@ impl Container {
if self.focusable_elements.is_empty() { if self.focusable_elements.is_empty() {
return; return;
} }
let focusables = self.focusable_elements.iter() let focusables = self
.focusable_elements
.iter()
.flat_map(|v| v.upgrade()) .flat_map(|v| v.upgrade())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// Find the last focused element if there is one // Find the last focused element if there is one
let last_focus = focusables.iter() let last_focus = focusables.iter().position(|v| v.is_focused());
.position(|v| v.is_focused());
let next_focus = last_focus.map_or(0, |v| v + 1) % focusables.len(); let next_focus = last_focus.map_or(0, |v| v + 1) % focusables.len();
// Clear the last focus // Clear the last focus
@ -397,15 +407,20 @@ impl Container {
focusables[next_focus].set_focused(true); focusables[next_focus].set_focused(true);
} }
pub fn key_press(&mut self, game: &mut crate::Game, key: VirtualKeyCode, down: bool, ctrl_pressed: bool) { pub fn key_press(
&mut self,
game: &mut crate::Game,
key: VirtualKeyCode,
down: bool,
ctrl_pressed: bool,
) {
if key == VirtualKeyCode::Tab { if key == VirtualKeyCode::Tab {
if !down { if !down {
self.cycle_focus(); self.cycle_focus();
} }
return; return;
} }
for el in self.focusable_elements.iter() for el in self.focusable_elements.iter().flat_map(|v| v.upgrade()) {
.flat_map(|v| v.upgrade()) {
if el.is_focused() { if el.is_focused() {
el.key_press(game, key, down, ctrl_pressed); el.key_press(game, key, down, ctrl_pressed);
} }
@ -416,8 +431,7 @@ impl Container {
if c < ' ' { if c < ' ' {
return; return;
} }
for el in self.focusable_elements.iter() for el in self.focusable_elements.iter().flat_map(|v| v.upgrade()) {
.flat_map(|v| v.upgrade()) {
if el.is_focused() { if el.is_focused() {
el.key_type(game, c); el.key_type(game, c);
} }
@ -463,11 +477,27 @@ impl ElementHolder for Container {
} }
trait UIElement { trait UIElement {
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, sw: f64, sh: f64, width: f64, height: f64, delta: f64) -> &mut [u8]; fn draw(
&mut self,
renderer: &mut render::Renderer,
r: &Region,
sw: f64,
sh: f64,
width: f64,
height: f64,
delta: f64,
) -> &mut [u8];
fn get_size(&self) -> (f64, f64); fn get_size(&self) -> (f64, f64);
fn is_dirty(&self) -> bool; fn is_dirty(&self) -> bool;
fn post_init(_: Rc<RefCell<Self>>) {} fn post_init(_: Rc<RefCell<Self>>) {}
fn key_press(&mut self, _game: &mut crate::Game, _key: VirtualKeyCode, _down: bool, _ctrl_pressed: bool) {} fn key_press(
&mut self,
_game: &mut crate::Game,
_key: VirtualKeyCode,
_down: bool,
_ctrl_pressed: bool,
) {
}
fn key_type(&mut self, _game: &mut crate::Game, _c: char) {} fn key_type(&mut self, _game: &mut crate::Game, _c: char) {}
fn tick(&mut self, renderer: &mut render::Renderer); fn tick(&mut self, renderer: &mut render::Renderer);
} }
@ -804,14 +834,29 @@ impl ImageBuilder {
} }
impl UIElement for Image { impl UIElement for Image {
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, sw: f64, sh: f64, width: f64, height: f64, delta: f64) -> &mut [u8] { fn draw(
&mut self,
renderer: &mut render::Renderer,
r: &Region,
sw: f64,
sh: f64,
width: f64,
height: f64,
delta: f64,
) -> &mut [u8] {
if self.check_rebuild() { if self.check_rebuild() {
self.data.clear(); self.data.clear();
let texture = render::Renderer::get_texture(renderer.get_textures_ref(), &self.texture); let texture = render::Renderer::get_texture(renderer.get_textures_ref(), &self.texture);
let mut element = render::ui::UIElement::new( let mut element = render::ui::UIElement::new(
&texture, &texture,
r.x, r.y, r.w, r.h, r.x,
self.texture_coords.0, self.texture_coords.1, self.texture_coords.2, self.texture_coords.3, r.y,
r.w,
r.h,
self.texture_coords.0,
self.texture_coords.1,
self.texture_coords.2,
self.texture_coords.3,
); );
element.r = self.colour.0; element.r = self.colour.0;
element.g = self.colour.1; element.g = self.colour.1;
@ -862,7 +907,16 @@ impl BatchBuilder {
} }
impl UIElement for Batch { impl UIElement for Batch {
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, sw: f64, sh: f64, width: f64, height: f64, delta: f64) -> &mut [u8] { fn draw(
&mut self,
renderer: &mut render::Renderer,
r: &Region,
sw: f64,
sh: f64,
width: f64,
height: f64,
delta: f64,
) -> &mut [u8] {
if self.check_rebuild() { if self.check_rebuild() {
self.data.clear(); self.data.clear();
self.super_draw(renderer, r, sw, sh, width, height, delta); self.super_draw(renderer, r, sw, sh, width, height, delta);
@ -916,15 +970,29 @@ element! {
} }
impl UIElement for Text { impl UIElement for Text {
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, sw: f64, sh: f64, width: f64, height: f64, delta: f64) -> &mut [u8] { fn draw(
&mut self,
renderer: &mut render::Renderer,
r: &Region,
sw: f64,
sh: f64,
width: f64,
height: f64,
delta: f64,
) -> &mut [u8] {
if self.check_rebuild() { if self.check_rebuild() {
self.data.clear(); self.data.clear();
let mut text = if self.rotation == 0.0 { let mut text = if self.rotation == 0.0 {
renderer.ui.new_text_scaled( renderer.ui.new_text_scaled(
&self.text, &self.text,
r.x, r.y, sw * self.scale_x, sh * self.scale_y, r.x,
self.colour.0, self.colour.1, self.colour.2, r.y,
sw * self.scale_x,
sh * self.scale_y,
self.colour.0,
self.colour.1,
self.colour.2,
) )
} else { } else {
let c = self.rotation.cos(); let c = self.rotation.cos();
@ -934,11 +1002,15 @@ impl UIElement for Text {
let w = (tmpx * c - tmpy * s).abs(); let w = (tmpx * c - tmpy * s).abs();
let h = (tmpy * c + tmpx * s).abs(); let h = (tmpy * c + tmpx * s).abs();
renderer.ui.new_text_rotated( renderer.ui.new_text_rotated(
&self.text, &self.text,
r.x + w - (r.w / 2.0), r.y + h - (r.h / 2.0), r.x + w - (r.w / 2.0),
sw * self.scale_x, sh * self.scale_y, r.y + h - (r.h / 2.0),
self.rotation, sw * self.scale_x,
self.colour.0, self.colour.1, self.colour.2, sh * self.scale_y,
self.rotation,
self.colour.0,
self.colour.1,
self.colour.2,
) )
}; };
for e in &mut text.elements { for e in &mut text.elements {
@ -964,7 +1036,10 @@ impl UIElement for Text {
} }
fn get_size(&self) -> (f64, f64) { fn get_size(&self) -> (f64, f64) {
((self.width + 2.0) * self.scale_x, self.height * self.scale_y) (
(self.width + 2.0) * self.scale_x,
self.height * self.scale_y,
)
} }
fn is_dirty(&self) -> bool { fn is_dirty(&self) -> bool {
@ -976,8 +1051,6 @@ impl UIElement for Text {
} }
} }
element! { element! {
ref FormattedRef ref FormattedRef
pub struct Formatted { pub struct Formatted {
@ -1011,7 +1084,16 @@ element! {
} }
impl UIElement for Formatted { impl UIElement for Formatted {
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, sw: f64, sh: f64, width: f64, height: f64, delta: f64) -> &mut [u8] { fn draw(
&mut self,
renderer: &mut render::Renderer,
r: &Region,
sw: f64,
sh: f64,
width: f64,
height: f64,
delta: f64,
) -> &mut [u8] {
if self.check_rebuild() { if self.check_rebuild() {
self.data.clear(); self.data.clear();
@ -1058,7 +1140,10 @@ impl UIElement for Formatted {
} }
fn get_size(&self) -> (f64, f64) { fn get_size(&self) -> (f64, f64) {
((self.width + 2.0) * self.scale_x, self.height * self.scale_y) (
(self.width + 2.0) * self.scale_x,
self.height * self.scale_y,
)
} }
fn is_dirty(&self) -> bool { fn is_dirty(&self) -> bool {
@ -1075,7 +1160,11 @@ impl Formatted {
self.dirty = true; self.dirty = true;
} }
pub fn compute_size(renderer: &render::Renderer, text: &format::Component, max_width: f64) -> (f64, f64) { pub fn compute_size(
renderer: &render::Renderer,
text: &format::Component,
max_width: f64,
) -> (f64, f64) {
let mut state = FormatState { let mut state = FormatState {
lines: 0, lines: 0,
width: 0.0, width: 0.0,
@ -1098,14 +1187,13 @@ struct FormatState<'a> {
renderer: &'a render::Renderer, renderer: &'a render::Renderer,
} }
impl<'a> ElementHolder for FormatState<'a> {
impl <'a> ElementHolder for FormatState<'a> {
fn add(&mut self, el: Element, _: bool) { fn add(&mut self, el: Element, _: bool) {
self.text.push(el); self.text.push(el);
} }
} }
impl <'a> FormatState<'a> { impl<'a> FormatState<'a> {
fn build(&mut self, c: &format::Component, color: format::Color) { fn build(&mut self, c: &format::Component, color: format::Color) {
match *c { match *c {
format::Component::Text(ref txt) => { format::Component::Text(ref txt) => {
@ -1197,46 +1285,156 @@ impl ButtonBuilder {
} }
impl UIElement for Button { impl UIElement for Button {
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, sw: f64, sh: f64, width: f64, height: f64, delta: f64) -> &mut [u8] { fn draw(
&mut self,
renderer: &mut render::Renderer,
r: &Region,
sw: f64,
sh: f64,
width: f64,
height: f64,
delta: f64,
) -> &mut [u8] {
if self.check_rebuild() { if self.check_rebuild() {
self.data.clear(); self.data.clear();
let offset = match (self.disabled, self.hovered) { let offset = match (self.disabled, self.hovered) {
(true, _) => 46.0, (true, _) => 46.0,
(false, true) => 86.0, (false, true) => 86.0,
(false, false) => 66.0, (false, false) => 66.0,
}; };
let texture = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/widgets") let texture = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/widgets")
.relative(0.0, offset / 256.0, 200.0 / 256.0, 20.0 / 256.0); .relative(0.0, offset / 256.0, 200.0 / 256.0, 20.0 / 256.0);
self.data.extend(render::ui::UIElement::new(&texture, r.x, r.y, 4.0 * sw, 4.0 * sh, 0.0, 0.0, 2.0/200.0, 2.0/20.0).bytes(width, height)); self.data.extend(
self.data.extend(render::ui::UIElement::new(&texture, r.x + r.w - 4.0 * sw, r.y, 4.0 * sw, 4.0 * sh, 198.0/200.0, 0.0, 2.0/200.0, 2.0/20.0).bytes(width, height)); render::ui::UIElement::new(
self.data.extend(render::ui::UIElement::new(&texture, r.x, r.y + r.h - 6.0 * sh, 4.0 * sw, 6.0 * sh, 0.0, 17.0/20.0, 2.0/200.0, 3.0/20.0).bytes(width, height)); &texture,
self.data.extend(render::ui::UIElement::new(&texture, r.x + r.w - 4.0 * sw, r.y + r.h - 6.0 * sh, 4.0 * sw, 6.0 * sh, 198.0/200.0, 17.0/20.0, 2.0/200.0, 3.0/20.0).bytes(width, height)); r.x,
r.y,
let w = ((r.w / sw)/2.0) - 4.0; 4.0 * sw,
self.data.extend(render::ui::UIElement::new( 4.0 * sh,
&texture.relative(2.0/200.0, 0.0, 196.0/200.0, 2.0/20.0), 0.0,
r.x+4.0*sw, r.y, r.w - 8.0 * sw, 4.0 * sh, 0.0, 0.0, w/196.0, 1.0).bytes(width, height) 0.0,
2.0 / 200.0,
2.0 / 20.0,
)
.bytes(width, height),
); );
self.data.extend(render::ui::UIElement::new( self.data.extend(
&texture.relative(2.0/200.0, 17.0/20.0, 196.0/200.0, 3.0/20.0), render::ui::UIElement::new(
r.x+4.0*sw, r.y+r.h-6.0*sh, r.w - 8.0 * sw, 6.0 * sh, 0.0, 0.0, w/196.0, 1.0).bytes(width, height) &texture,
r.x + r.w - 4.0 * sw,
r.y,
4.0 * sw,
4.0 * sh,
198.0 / 200.0,
0.0,
2.0 / 200.0,
2.0 / 20.0,
)
.bytes(width, height),
);
self.data.extend(
render::ui::UIElement::new(
&texture,
r.x,
r.y + r.h - 6.0 * sh,
4.0 * sw,
6.0 * sh,
0.0,
17.0 / 20.0,
2.0 / 200.0,
3.0 / 20.0,
)
.bytes(width, height),
);
self.data.extend(
render::ui::UIElement::new(
&texture,
r.x + r.w - 4.0 * sw,
r.y + r.h - 6.0 * sh,
4.0 * sw,
6.0 * sh,
198.0 / 200.0,
17.0 / 20.0,
2.0 / 200.0,
3.0 / 20.0,
)
.bytes(width, height),
); );
let h = ((r.h / sh)/2.0) - 5.0; let w = ((r.w / sw) / 2.0) - 4.0;
self.data.extend(render::ui::UIElement::new( self.data.extend(
&texture.relative(0.0/200.0, 2.0/20.0, 2.0/200.0, 15.0/20.0), render::ui::UIElement::new(
r.x, r.y + 4.0*sh, 4.0 * sw, r.h - 10.0*sh, 0.0, 0.0, 1.0, h/16.0).bytes(width, height) &texture.relative(2.0 / 200.0, 0.0, 196.0 / 200.0, 2.0 / 20.0),
r.x + 4.0 * sw,
r.y,
r.w - 8.0 * sw,
4.0 * sh,
0.0,
0.0,
w / 196.0,
1.0,
)
.bytes(width, height),
); );
self.data.extend(render::ui::UIElement::new( self.data.extend(
&texture.relative(198.0/200.0, 2.0/20.0, 2.0/200.0, 15.0/20.0), render::ui::UIElement::new(
r.x+r.w - 4.0 * sw, r.y + 4.0*sh, 4.0 * sw, r.h - 10.0*sh, 0.0, 0.0, 1.0, h/16.0).bytes(width, height) &texture.relative(2.0 / 200.0, 17.0 / 20.0, 196.0 / 200.0, 3.0 / 20.0),
r.x + 4.0 * sw,
r.y + r.h - 6.0 * sh,
r.w - 8.0 * sw,
6.0 * sh,
0.0,
0.0,
w / 196.0,
1.0,
)
.bytes(width, height),
); );
let h = ((r.h / sh) / 2.0) - 5.0;
self.data.extend(
render::ui::UIElement::new(
&texture.relative(0.0 / 200.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0),
r.x,
r.y + 4.0 * sh,
4.0 * sw,
r.h - 10.0 * sh,
0.0,
0.0,
1.0,
h / 16.0,
)
.bytes(width, height),
);
self.data.extend(
render::ui::UIElement::new(
&texture.relative(198.0 / 200.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0),
r.x + r.w - 4.0 * sw,
r.y + 4.0 * sh,
4.0 * sw,
r.h - 10.0 * sh,
0.0,
0.0,
1.0,
h / 16.0,
)
.bytes(width, height),
);
self.data.extend(render::ui::UIElement::new( self.data.extend(
&texture.relative(2.0/200.0, 2.0/20.0, 196.0/200.0, 15.0/20.0), render::ui::UIElement::new(
r.x+4.0*sw, r.y+4.0*sh, r.w - 8.0 * sw, r.h - 10.0 * sh, 0.0, 0.0, w/196.0, h/16.0).bytes(width, height) &texture.relative(2.0 / 200.0, 2.0 / 20.0, 196.0 / 200.0, 15.0 / 20.0),
r.x + 4.0 * sw,
r.y + 4.0 * sh,
r.w - 8.0 * sw,
r.h - 10.0 * sh,
0.0,
0.0,
w / 196.0,
h / 16.0,
)
.bytes(width, height),
); );
self.super_draw(renderer, r, sw, sh, width, height, delta); self.super_draw(renderer, r, sw, sh, width, height, delta);
self.last_disabled = self.disabled; self.last_disabled = self.disabled;
@ -1254,11 +1452,9 @@ impl UIElement for Button {
} }
fn is_dirty(&self) -> bool { fn is_dirty(&self) -> bool {
self.last_disabled != self.disabled self.last_disabled != self.disabled || self.last_hovered != self.hovered
|| self.last_hovered != self.hovered
} }
fn post_init(s: Rc<RefCell<Self>>) { fn post_init(s: Rc<RefCell<Self>>) {
s.borrow_mut().add_hover_func(move |this, hover, _| { s.borrow_mut().add_hover_func(move |this, hover, _| {
this.hovered = hover; this.hovered = hover;
@ -1311,9 +1507,17 @@ impl TextBoxBuilder {
} }
impl UIElement for TextBox { impl UIElement for TextBox {
fn key_press(&mut self, game: &mut crate::Game, key: VirtualKeyCode, down: bool, ctrl_pressed: bool) { fn key_press(
&mut self,
game: &mut crate::Game,
key: VirtualKeyCode,
down: bool,
ctrl_pressed: bool,
) {
match (key, down) { match (key, down) {
(VirtualKeyCode::Back, _) => {self.input.pop();}, (VirtualKeyCode::Back, _) => {
self.input.pop();
}
(VirtualKeyCode::Return, false) => { (VirtualKeyCode::Return, false) => {
use std::mem; use std::mem;
let len = self.submit_funcs.len(); let len = self.submit_funcs.len();
@ -1322,7 +1526,7 @@ impl UIElement for TextBox {
(func)(self, game); (func)(self, game);
} }
self.submit_funcs.append(&mut temp); self.submit_funcs.append(&mut temp);
}, }
// TODO: wasm clipboard pasting, Clipboard API: https://www.w3.org/TR/clipboard-apis/ // TODO: wasm clipboard pasting, Clipboard API: https://www.w3.org/TR/clipboard-apis/
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
(VirtualKeyCode::V, true) => { (VirtualKeyCode::V, true) => {
@ -1330,11 +1534,11 @@ impl UIElement for TextBox {
let mut clipboard: ClipboardContext = ClipboardProvider::new().unwrap(); let mut clipboard: ClipboardContext = ClipboardProvider::new().unwrap();
match clipboard.get_contents() { match clipboard.get_contents() {
Ok(text) => self.input.push_str(&text), Ok(text) => self.input.push_str(&text),
Err(_) => () Err(_) => (),
} }
} }
}, }
_ => {}, _ => {}
} }
} }
@ -1342,7 +1546,16 @@ impl UIElement for TextBox {
self.input.push(c); self.input.push(c);
} }
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, sw: f64, sh: f64, width: f64, height: f64, delta: f64) -> &mut [u8] { fn draw(
&mut self,
renderer: &mut render::Renderer,
r: &Region,
sw: f64,
sh: f64,
width: f64,
height: f64,
delta: f64,
) -> &mut [u8] {
if self.check_rebuild() { if self.check_rebuild() {
self.data.clear(); self.data.clear();
self.cursor_tick += delta; self.cursor_tick += delta;
@ -1381,17 +1594,21 @@ impl UIElement for TextBox {
fn post_init(s: Rc<RefCell<Self>>) { fn post_init(s: Rc<RefCell<Self>>) {
let mut textbox = s.borrow_mut(); let mut textbox = s.borrow_mut();
textbox.button = Some(ButtonBuilder::new() textbox.button = Some(
.position(0.0, 0.0) ButtonBuilder::new()
.size(textbox.width, textbox.height) .position(0.0, 0.0)
.disabled(true) .size(textbox.width, textbox.height)
.attach(&mut *textbox)); .disabled(true)
textbox.text = Some(TextBuilder::new() .attach(&mut *textbox),
.text("") );
.position(5.0, 0.0) textbox.text = Some(
.draw_index(1) TextBuilder::new()
.alignment(VAttach::Middle, HAttach::Left) .text("")
.attach(&mut *textbox)); .position(5.0, 0.0)
.draw_index(1)
.alignment(VAttach::Middle, HAttach::Left)
.attach(&mut *textbox),
);
} }
} }

View File

@ -1,4 +1,3 @@
use image::Rgba; use image::Rgba;
use lazy_static::lazy_static; use lazy_static::lazy_static;
@ -14,7 +13,7 @@ impl Biome {
Biome { Biome {
id, id,
temperature: t, temperature: t,
moisture: m*t, moisture: m * t,
} }
} }
@ -23,21 +22,19 @@ impl Biome {
} }
pub fn get_color_index(self) -> usize { pub fn get_color_index(self) -> usize {
let t = (self.temperature as f64 / 100f64) .min(1.0).max(0.0); let t = (self.temperature as f64 / 100f64).min(1.0).max(0.0);
let m = (self.moisture as f64 / 100f64).min(1.0).max(0.0); let m = (self.moisture as f64 / 100f64).min(1.0).max(0.0);
(((1.0 - t) * 255.0) as usize) | ((((1.0 - (m*t)) * 255.0) as usize) << 8) (((1.0 - t) * 255.0) as usize) | ((((1.0 - (m * t)) * 255.0) as usize) << 8)
} }
pub fn process_color(self, col: Rgba<u8>) -> Rgba<u8> { pub fn process_color(self, col: Rgba<u8>) -> Rgba<u8> {
if self.id == ROOFED_FOREST.id || self.id == ROOFED_FOREST_MOUNTAINS.id { if self.id == ROOFED_FOREST.id || self.id == ROOFED_FOREST_MOUNTAINS.id {
Rgba ( Rgba([
[ ((col.0[0] as u32 + 0x28) / 2) as u8,
((col.0[0] as u32 + 0x28) / 2) as u8, ((col.0[1] as u32 + 0x34) / 2) as u8,
((col.0[1] as u32 + 0x34) / 2) as u8, ((col.0[2] as u32 + 0x0A) / 2) as u8,
((col.0[2] as u32 + 0x0A) / 2) as u8, 255,
255 ])
]
)
} else { } else {
col col
} }

View File

@ -14,21 +14,21 @@
pub use steven_blocks as block; pub use steven_blocks as block;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::hash::BuildHasherDefault;
use crate::types::{bit, nibble};
use crate::shared::{Position, Direction};
use crate::types::hash::FNVHash;
use crate::protocol;
use crate::render;
use collision;
use cgmath::prelude::*;
use crate::chunk_builder; use crate::chunk_builder;
use crate::ecs; use crate::ecs;
use crate::entity::block_entity; use crate::entity::block_entity;
use crate::format; use crate::format;
use crate::protocol;
use crate::render;
use crate::shared::{Direction, Position};
use crate::types::hash::FNVHash;
use crate::types::{bit, nibble};
use cgmath::prelude::*;
use collision;
use flate2::read::ZlibDecoder; use flate2::read::ZlibDecoder;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::hash::BuildHasherDefault;
use std::io::Read; use std::io::Read;
pub mod biome; pub mod biome;
@ -52,13 +52,19 @@ pub struct World {
pub enum BlockEntityAction { pub enum BlockEntityAction {
Create(Position), Create(Position),
Remove(Position), Remove(Position),
UpdateSignText(Position, format::Component, format::Component, format::Component, format::Component), UpdateSignText(
Position,
format::Component,
format::Component,
format::Component,
format::Component,
),
} }
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
enum LightType { enum LightType {
Block, Block,
Sky Sky,
} }
impl LightType { impl LightType {
@ -104,10 +110,12 @@ impl World {
let chunk = self.chunks.entry(cpos).or_insert_with(|| Chunk::new(cpos)); let chunk = self.chunks.entry(cpos).or_insert_with(|| Chunk::new(cpos));
if chunk.set_block(pos.x & 0xF, pos.y, pos.z & 0xF, b) { if chunk.set_block(pos.x & 0xF, pos.y, pos.z & 0xF, b) {
if chunk.block_entities.contains_key(&pos) { if chunk.block_entities.contains_key(&pos) {
self.block_entity_actions.push_back(BlockEntityAction::Remove(pos)); self.block_entity_actions
.push_back(BlockEntityAction::Remove(pos));
} }
if block_entity::BlockEntityType::get_block_entity(b).is_some() { if block_entity::BlockEntityType::get_block_entity(b).is_some() {
self.block_entity_actions.push_back(BlockEntityAction::Create(pos)); self.block_entity_actions
.push_back(BlockEntityAction::Create(pos));
} }
true true
} else { } else {
@ -116,9 +124,9 @@ impl World {
} }
pub fn update_block(&mut self, pos: Position) { pub fn update_block(&mut self, pos: Position) {
for yy in -1 .. 2 { for yy in -1..2 {
for zz in -1 .. 2 { for zz in -1..2 {
for xx in -1 .. 2 { for xx in -1..2 {
let bp = pos + (xx, yy, zz); let bp = pos + (xx, yy, zz);
let current = self.get_block(bp); let current = self.get_block(bp);
let new = current.update_state(self, bp); let new = current.update_state(self, bp);
@ -134,9 +142,9 @@ impl World {
} }
fn update_range(&mut self, x1: i32, y1: i32, z1: i32, x2: i32, y2: i32, z2: i32) { fn update_range(&mut self, x1: i32, y1: i32, z1: i32, x2: i32, y2: i32, z2: i32) {
for by in y1 .. y2 { for by in y1..y2 {
for bz in z1 .. z2 { for bz in z1..z2 {
for bx in x1 .. x2 { for bx in x1..x2 {
let bp = Position::new(bx, by, bz); let bp = Position::new(bx, by, bz);
let current = self.get_block(bp); let current = self.get_block(bp);
let new = current.update_state(self, bp); let new = current.update_state(self, bp);
@ -156,7 +164,7 @@ impl World {
pub fn get_block(&self, pos: Position) -> block::Block { pub fn get_block(&self, pos: Position) -> block::Block {
match self.chunks.get(&CPos(pos.x >> 4, pos.z >> 4)) { match self.chunks.get(&CPos(pos.x >> 4, pos.z >> 4)) {
Some(chunk) => chunk.get_block(pos.x & 0xF, pos.y, pos.z & 0xF), Some(chunk) => chunk.get_block(pos.x & 0xF, pos.y, pos.z & 0xF),
None => block::Missing{}, None => block::Missing {},
} }
} }
@ -187,10 +195,7 @@ impl World {
} }
fn update_light(&mut self, pos: Position, ty: LightType) { fn update_light(&mut self, pos: Position, ty: LightType) {
self.light_updates.push_back(LightUpdate { self.light_updates.push_back(LightUpdate { ty, pos });
ty,
pos,
});
} }
pub fn add_block_entity_action(&mut self, action: BlockEntityAction) { pub fn add_block_entity_action(&mut self, action: BlockEntityAction) {
@ -198,14 +203,15 @@ impl World {
} }
pub fn tick(&mut self, m: &mut ecs::Manager) { pub fn tick(&mut self, m: &mut ecs::Manager) {
use std::time::{Instant}; use std::time::Instant;
let start = Instant::now(); let start = Instant::now();
let mut updates_performed = 0; let mut updates_performed = 0;
while !self.light_updates.is_empty() { while !self.light_updates.is_empty() {
updates_performed += 1; updates_performed += 1;
self.do_light_update(); self.do_light_update();
if updates_performed & 0xFFF == 0 { if updates_performed & 0xFFF == 0 {
if start.elapsed().subsec_nanos() >= 5000000 { // 5 ms for light updates if start.elapsed().subsec_nanos() >= 5000000 {
// 5 ms for light updates
break; break;
} }
} }
@ -221,7 +227,7 @@ impl World {
m.remove_entity(entity); m.remove_entity(entity);
} }
} }
}, }
BlockEntityAction::Create(pos) => { BlockEntityAction::Create(pos) => {
if let Some(chunk) = self.chunks.get_mut(&CPos(pos.x >> 4, pos.z >> 4)) { if let Some(chunk) = self.chunks.get_mut(&CPos(pos.x >> 4, pos.z >> 4)) {
// Remove existing entity // Remove existing entity
@ -229,22 +235,19 @@ impl World {
m.remove_entity(entity); m.remove_entity(entity);
} }
let block = chunk.get_block(pos.x & 0xF, pos.y, pos.z & 0xF); let block = chunk.get_block(pos.x & 0xF, pos.y, pos.z & 0xF);
if let Some(entity_type) = block_entity::BlockEntityType::get_block_entity(block) { if let Some(entity_type) =
block_entity::BlockEntityType::get_block_entity(block)
{
let entity = entity_type.create_entity(m, pos); let entity = entity_type.create_entity(m, pos);
chunk.block_entities.insert(pos, entity); chunk.block_entities.insert(pos, entity);
} }
} }
}, }
BlockEntityAction::UpdateSignText(pos, line1, line2, line3, line4) => { BlockEntityAction::UpdateSignText(pos, line1, line2, line3, line4) => {
if let Some(chunk) = self.chunks.get(&CPos(pos.x >> 4, pos.z >> 4)) { if let Some(chunk) = self.chunks.get(&CPos(pos.x >> 4, pos.z >> 4)) {
if let Some(entity) = chunk.block_entities.get(&pos) { if let Some(entity) = chunk.block_entities.get(&pos) {
if let Some(sign) = m.get_component_mut(*entity, sign_info) { if let Some(sign) = m.get_component_mut(*entity, sign_info) {
sign.lines = [ sign.lines = [line1, line2, line3, line4];
line1,
line2,
line3,
line4,
];
sign.dirty = true; sign.dirty = true;
} }
} }
@ -257,7 +260,10 @@ impl World {
fn do_light_update(&mut self) { fn do_light_update(&mut self) {
use std::cmp; use std::cmp;
if let Some(update) = self.light_updates.pop_front() { if let Some(update) = self.light_updates.pop_front() {
if update.pos.y < 0 || update.pos.y > 255 || !self.is_chunk_loaded(update.pos.x >> 4, update.pos.z >> 4) { if update.pos.y < 0
|| update.pos.y > 255
|| !self.is_chunk_loaded(update.pos.x >> 4, update.pos.z >> 4)
{
return; return;
} }
@ -280,7 +286,8 @@ impl World {
// Sky light doesn't decrease when going down at full brightness // Sky light doesn't decrease when going down at full brightness
if update.ty == LightType::Sky if update.ty == LightType::Sky
&& block.absorbed_light == 0 && block.absorbed_light == 0
&& update.ty.get_light(self, update.pos.shift(Direction::Up)) == 15 { && update.ty.get_light(self, update.pos.shift(Direction::Up)) == 15
{
best = 15; best = 15;
} }
@ -291,9 +298,9 @@ impl World {
// Use our new light value // Use our new light value
update.ty.set_light(self, update.pos, best); update.ty.set_light(self, update.pos, best);
// Flag surrounding chunks as dirty // Flag surrounding chunks as dirty
for yy in -1 .. 2 { for yy in -1..2 {
for zz in -1 .. 2 { for zz in -1..2 {
for xx in -1 .. 2 { for xx in -1..2 {
let bp = update.pos + (xx, yy, zz); let bp = update.pos + (xx, yy, zz);
self.set_dirty(bp.x >> 4, bp.y >> 4, bp.z >> 4); self.set_dirty(bp.x >> 4, bp.y >> 4, bp.z >> 4);
} }
@ -313,12 +320,11 @@ impl World {
if c.heightmap_dirty { if c.heightmap_dirty {
dirty = true; dirty = true;
c.heightmap_dirty = false; c.heightmap_dirty = false;
for xx in 0 .. 16 { for xx in 0..16 {
for zz in 0 .. 16 { for zz in 0..16 {
data[ data[(((c.position.0 << 4) as usize + xx) & 0x1FF)
(((c.position.0 << 4) as usize + xx) & 0x1FF) + + ((((c.position.1 << 4) as usize + zz) & 0x1FF) << 9)] =
((((c.position.1 << 4) as usize + zz) & 0x1FF) << 9) c.heightmap[(zz << 4) | xx];
] = c.heightmap[(zz << 4) | xx];
} }
} }
} }
@ -339,25 +345,37 @@ impl World {
let start = ( let start = (
((renderer.camera.pos.x as i32) >> 4), ((renderer.camera.pos.x as i32) >> 4),
((renderer.camera.pos.y as i32) >> 4), ((renderer.camera.pos.y as i32) >> 4),
((renderer.camera.pos.z as i32) >> 4) ((renderer.camera.pos.z as i32) >> 4),
); );
let mut process_queue = VecDeque::with_capacity(self.chunks.len() * 16); let mut process_queue = VecDeque::with_capacity(self.chunks.len() * 16);
process_queue.push_front((Direction::Invalid, start)); process_queue.push_front((Direction::Invalid, start));
while let Some((from, pos)) = process_queue.pop_front() { while let Some((from, pos)) = process_queue.pop_front() {
let (exists, cull) = if let Some((sec, rendered_on)) = self.get_render_section_mut(pos.0, pos.1, pos.2) { let (exists, cull) = if let Some((sec, rendered_on)) =
self.get_render_section_mut(pos.0, pos.1, pos.2)
{
if *rendered_on == renderer.frame_id { if *rendered_on == renderer.frame_id {
continue; continue;
} }
*rendered_on = renderer.frame_id; *rendered_on = renderer.frame_id;
let min = cgmath::Point3::new(pos.0 as f32 * 16.0, -pos.1 as f32 * 16.0, pos.2 as f32 * 16.0); let min = cgmath::Point3::new(
let bounds = collision::Aabb3::new(min, min + cgmath::Vector3::new(16.0, -16.0, 16.0)); pos.0 as f32 * 16.0,
if renderer.frustum.contains(&bounds) == collision::Relation::Out && from != Direction::Invalid { -pos.1 as f32 * 16.0,
pos.2 as f32 * 16.0,
);
let bounds =
collision::Aabb3::new(min, min + cgmath::Vector3::new(16.0, -16.0, 16.0));
if renderer.frustum.contains(&bounds) == collision::Relation::Out
&& from != Direction::Invalid
{
continue; continue;
} }
(sec.is_some(), sec.map_or(chunk_builder::CullInfo::all_vis(), |v| v.cull_info)) (
sec.is_some(),
sec.map_or(chunk_builder::CullInfo::all_vis(), |v| v.cull_info),
)
} else { } else {
continue; continue;
}; };
@ -369,11 +387,14 @@ impl World {
for dir in Direction::all() { for dir in Direction::all() {
let (ox, oy, oz) = dir.get_offset(); let (ox, oy, oz) = dir.get_offset();
let opos = (pos.0 + ox, pos.1 + oy, pos.2 + oz); let opos = (pos.0 + ox, pos.1 + oy, pos.2 + oz);
if let Some((_, rendered_on)) = self.get_render_section_mut(opos.0, opos.1, opos.2) { if let Some((_, rendered_on)) = self.get_render_section_mut(opos.0, opos.1, opos.2)
{
if *rendered_on == renderer.frame_id { if *rendered_on == renderer.frame_id {
continue; continue;
} }
if from == Direction::Invalid || (valid_dirs[dir.index()] && cull.is_visible(from, dir)) { if from == Direction::Invalid
|| (valid_dirs[dir.index()] && cull.is_visible(from, dir))
{
process_queue.push_back((dir.opposite(), opos)); process_queue.push_back((dir.opposite(), opos));
} }
} }
@ -382,11 +403,14 @@ impl World {
} }
pub fn get_render_list(&self) -> Vec<((i32, i32, i32), &render::ChunkBuffer)> { pub fn get_render_list(&self) -> Vec<((i32, i32, i32), &render::ChunkBuffer)> {
self.render_list.iter().map(|v| { self.render_list
let chunk = self.chunks.get(&CPos(v.0, v.2)).unwrap(); .iter()
let sec = chunk.sections[v.1 as usize].as_ref().unwrap(); .map(|v| {
(*v, &sec.render_buffer) let chunk = self.chunks.get(&CPos(v.0, v.2)).unwrap();
}).collect() let sec = chunk.sections[v.1 as usize].as_ref().unwrap();
(*v, &sec.render_buffer)
})
.collect()
} }
pub fn get_section_mut(&mut self, x: i32, y: i32, z: i32) -> Option<&mut Section> { pub fn get_section_mut(&mut self, x: i32, y: i32, z: i32) -> Option<&mut Section> {
@ -398,7 +422,12 @@ impl World {
None None
} }
fn get_render_section_mut(&mut self, x: i32, y: i32, z: i32) -> Option<(Option<&mut Section>, &mut u32)> { fn get_render_section_mut(
&mut self,
x: i32,
y: i32,
z: i32,
) -> Option<(Option<&mut Section>, &mut u32)> {
if y < 0 || y > 15 { if y < 0 || y > 15 {
return None; return None;
} }
@ -471,17 +500,21 @@ impl World {
} }
pub fn capture_snapshot(&self, x: i32, y: i32, z: i32, w: i32, h: i32, d: i32) -> Snapshot { pub fn capture_snapshot(&self, x: i32, y: i32, z: i32, w: i32, h: i32, d: i32) -> Snapshot {
use std::cmp::{min, max}; use std::cmp::{max, min};
let mut snapshot = Snapshot { let mut snapshot = Snapshot {
blocks: storage::BlockStorage::new_default((w * h * d) as usize, block::Missing{}), blocks: storage::BlockStorage::new_default((w * h * d) as usize, block::Missing {}),
block_light: nibble::Array::new((w * h * d) as usize), block_light: nibble::Array::new((w * h * d) as usize),
sky_light: nibble::Array::new((w * h * d) as usize), sky_light: nibble::Array::new((w * h * d) as usize),
biomes: vec![0; (w * d) as usize], biomes: vec![0; (w * d) as usize],
x, y, z, x,
w, _h: h, d, y,
z,
w,
_h: h,
d,
}; };
for i in 0 .. (w * h * d) as usize { for i in 0..(w * h * d) as usize {
snapshot.sky_light.set(i, 0xF); snapshot.sky_light.set(i, 0xF);
} }
@ -492,48 +525,58 @@ impl World {
let cy2 = (y + h + 15) >> 4; let cy2 = (y + h + 15) >> 4;
let cz2 = (z + d + 15) >> 4; let cz2 = (z + d + 15) >> 4;
for cx in cx1 .. cx2 { for cx in cx1..cx2 {
for cz in cz1 .. cz2 { for cz in cz1..cz2 {
let chunk = match self.chunks.get(&CPos(cx, cz)) { let chunk = match self.chunks.get(&CPos(cx, cz)) {
Some(val) => val, Some(val) => val,
None => continue, None => continue,
}; };
let x1 = min(16, max(0, x - (cx<<4))); let x1 = min(16, max(0, x - (cx << 4)));
let x2 = min(16, max(0, x + w - (cx<<4))); let x2 = min(16, max(0, x + w - (cx << 4)));
let z1 = min(16, max(0, z - (cz<<4))); let z1 = min(16, max(0, z - (cz << 4)));
let z2 = min(16, max(0, z + d - (cz<<4))); let z2 = min(16, max(0, z + d - (cz << 4)));
for cy in cy1 .. cy2 { for cy in cy1..cy2 {
if cy < 0 || cy > 15 { if cy < 0 || cy > 15 {
continue; continue;
} }
let section = &chunk.sections[cy as usize]; let section = &chunk.sections[cy as usize];
let y1 = min(16, max(0, y - (cy<<4))); let y1 = min(16, max(0, y - (cy << 4)));
let y2 = min(16, max(0, y + h - (cy<<4))); let y2 = min(16, max(0, y + h - (cy << 4)));
for yy in y1 .. y2 { for yy in y1..y2 {
for zz in z1 .. z2 { for zz in z1..z2 {
for xx in x1 .. x2 { for xx in x1..x2 {
let ox = xx + (cx << 4); let ox = xx + (cx << 4);
let oy = yy + (cy << 4); let oy = yy + (cy << 4);
let oz = zz + (cz << 4); let oz = zz + (cz << 4);
match section.as_ref() { match section.as_ref() {
Some(sec) => { Some(sec) => {
snapshot.set_block(ox, oy, oz, sec.get_block(xx, yy, zz)); snapshot.set_block(ox, oy, oz, sec.get_block(xx, yy, zz));
snapshot.set_block_light(ox, oy, oz, sec.get_block_light(xx, yy, zz)); snapshot.set_block_light(
snapshot.set_sky_light(ox, oy, oz, sec.get_sky_light(xx, yy, zz)); ox,
}, oy,
oz,
sec.get_block_light(xx, yy, zz),
);
snapshot.set_sky_light(
ox,
oy,
oz,
sec.get_sky_light(xx, yy, zz),
);
}
None => { None => {
snapshot.set_block(ox, oy, oz, block::Air{}); snapshot.set_block(ox, oy, oz, block::Air {});
}, }
} }
} }
} }
} }
} }
for zz in z1 .. z2 { for zz in z1..z2 {
for xx in x1 .. x2 { for xx in x1..x2 {
let ox = xx + (cx << 4); let ox = xx + (cx << 4);
let oz = zz + (cz << 4); let oz = zz + (cz << 4);
snapshot.set_biome(ox, oz, chunk.get_biome(xx, zz)); snapshot.set_biome(ox, oz, chunk.get_biome(xx, zz));
@ -553,38 +596,62 @@ impl World {
} }
} }
pub fn load_chunks18(&mut self, new: bool, skylight: bool, chunk_metas: &[crate::protocol::packet::ChunkMeta], data: Vec<u8>) -> Result<(), protocol::Error> { pub fn load_chunks18(
let mut data = std::io::Cursor::new(data); &mut self,
new: bool,
skylight: bool,
chunk_metas: &[crate::protocol::packet::ChunkMeta],
data: Vec<u8>,
) -> Result<(), protocol::Error> {
let mut data = std::io::Cursor::new(data);
for chunk_meta in chunk_metas { for chunk_meta in chunk_metas {
let x = chunk_meta.x; let x = chunk_meta.x;
let z = chunk_meta.z; let z = chunk_meta.z;
let mask = chunk_meta.bitmask; let mask = chunk_meta.bitmask;
self.load_chunk18(x, z, new, skylight, mask, &mut data)?; self.load_chunk18(x, z, new, skylight, mask, &mut data)?;
} }
Ok(()) Ok(())
} }
fn dirty_chunks_by_bitmask(&mut self, x: i32, z: i32, mask: u16) { fn dirty_chunks_by_bitmask(&mut self, x: i32, z: i32, mask: u16) {
for i in 0 .. 16 { for i in 0..16 {
if mask & (1 << i) == 0 { if mask & (1 << i) == 0 {
continue; continue;
} }
for pos in [ for pos in [
(-1, 0, 0), (1, 0, 0), (-1, 0, 0),
(0, -1, 0), (0, 1, 0), (1, 0, 0),
(0, 0, -1), (0, 0, 1)].iter() { (0, -1, 0),
(0, 1, 0),
(0, 0, -1),
(0, 0, 1),
]
.iter()
{
self.flag_section_dirty(x + pos.0, i as i32 + pos.1, z + pos.2); self.flag_section_dirty(x + pos.0, i as i32 + pos.1, z + pos.2);
} }
self.update_range( self.update_range(
(x<<4) - 1, (i<<4) - 1, (z<<4) - 1, (x << 4) - 1,
(x<<4) + 17, (i<<4) + 17, (z<<4) + 17 (i << 4) - 1,
(z << 4) - 1,
(x << 4) + 17,
(i << 4) + 17,
(z << 4) + 17,
); );
} }
} }
pub fn load_chunk18(&mut self, x: i32, z: i32, new: bool, _skylight: bool, mask: u16, data: &mut std::io::Cursor<Vec<u8>>) -> Result<(), protocol::Error> { pub fn load_chunk18(
&mut self,
x: i32,
z: i32,
new: bool,
_skylight: bool,
mask: u16,
data: &mut std::io::Cursor<Vec<u8>>,
) -> Result<(), protocol::Error> {
use byteorder::ReadBytesExt; use byteorder::ReadBytesExt;
let cpos = CPos(x, z); let cpos = CPos(x, z);
@ -599,11 +666,9 @@ impl World {
self.chunks.get_mut(&cpos).unwrap() self.chunks.get_mut(&cpos).unwrap()
}; };
for i in 0 .. 16 { for i in 0..16 {
if chunk.sections[i].is_none() { if chunk.sections[i].is_none() {
let mut fill_sky = chunk.sections.iter() let mut fill_sky = chunk.sections.iter().skip(i).all(|v| v.is_none());
.skip(i)
.all(|v| v.is_none());
fill_sky &= (mask & !((1 << i) | ((1 << i) - 1))) == 0; fill_sky &= (mask & !((1 << i) | ((1 << i) - 1))) == 0;
if !fill_sky || mask & (1 << i) != 0 { if !fill_sky || mask & (1 << i) != 0 {
chunk.sections[i] = Some(Section::new(i as u8, fill_sky)); chunk.sections[i] = Some(Section::new(i as u8, fill_sky));
@ -615,9 +680,16 @@ impl World {
let section = chunk.sections[i as usize].as_mut().unwrap(); let section = chunk.sections[i as usize].as_mut().unwrap();
section.dirty = true; section.dirty = true;
for bi in 0 .. 4096 { for bi in 0..4096 {
let id = data.read_u16::<byteorder::LittleEndian>()?; let id = data.read_u16::<byteorder::LittleEndian>()?;
section.blocks.set(bi, block::Block::by_vanilla_id(id as usize, self.protocol_version, &self.modded_block_ids)); section.blocks.set(
bi,
block::Block::by_vanilla_id(
id as usize,
self.protocol_version,
&self.modded_block_ids,
),
);
// Spawn block entities // Spawn block entities
let b = section.blocks.get(bi); let b = section.blocks.get(bi);
@ -625,17 +697,23 @@ impl World {
let pos = Position::new( let pos = Position::new(
(bi & 0xF) as i32, (bi & 0xF) as i32,
(bi >> 8) as i32, (bi >> 8) as i32,
((bi >> 4) & 0xF) as i32 ((bi >> 4) & 0xF) as i32,
) + (chunk.position.0 << 4, (i << 4) as i32, chunk.position.1 << 4); ) + (
chunk.position.0 << 4,
(i << 4) as i32,
chunk.position.1 << 4,
);
if chunk.block_entities.contains_key(&pos) { if chunk.block_entities.contains_key(&pos) {
self.block_entity_actions.push_back(BlockEntityAction::Remove(pos)) self.block_entity_actions
.push_back(BlockEntityAction::Remove(pos))
} }
self.block_entity_actions.push_back(BlockEntityAction::Create(pos)) self.block_entity_actions
.push_back(BlockEntityAction::Create(pos))
} }
} }
} }
for i in 0 .. 16 { for i in 0..16 {
if mask & (1 << i) == 0 { if mask & (1 << i) == 0 {
continue; continue;
} }
@ -644,7 +722,7 @@ impl World {
data.read_exact(&mut section.block_light.data)?; data.read_exact(&mut section.block_light.data)?;
} }
for i in 0 .. 16 { for i in 0..16 {
if mask & (1 << i) == 0 { if mask & (1 << i) == 0 {
continue; continue;
} }
@ -664,7 +742,13 @@ impl World {
Ok(()) Ok(())
} }
pub fn load_chunks17(&mut self, chunk_column_count: u16, data_length: i32, skylight: bool, data: &[u8]) -> Result<(), protocol::Error> { pub fn load_chunks17(
&mut self,
chunk_column_count: u16,
data_length: i32,
skylight: bool,
data: &[u8],
) -> Result<(), protocol::Error> {
let compressed_chunk_data = &data[0..data_length as usize]; let compressed_chunk_data = &data[0..data_length as usize];
let metadata = &data[data_length as usize..]; let metadata = &data[data_length as usize..];
@ -692,16 +776,41 @@ impl World {
Ok(()) Ok(())
} }
pub fn load_chunk17(&mut self, x: i32, z: i32, new: bool, mask: u16, mask_add: u16, compressed_data: Vec<u8>) -> Result<(), protocol::Error> { pub fn load_chunk17(
let mut zlib = ZlibDecoder::new(std::io::Cursor::new(compressed_data.to_vec())); &mut self,
let mut data = Vec::new(); x: i32,
zlib.read_to_end(&mut data)?; z: i32,
new: bool,
mask: u16,
mask_add: u16,
compressed_data: Vec<u8>,
) -> Result<(), protocol::Error> {
let mut zlib = ZlibDecoder::new(std::io::Cursor::new(compressed_data.to_vec()));
let mut data = Vec::new();
zlib.read_to_end(&mut data)?;
let skylight = true; let skylight = true;
self.load_uncompressed_chunk17(x, z, new, skylight, mask, mask_add, &mut std::io::Cursor::new(data)) self.load_uncompressed_chunk17(
x,
z,
new,
skylight,
mask,
mask_add,
&mut std::io::Cursor::new(data),
)
} }
fn load_uncompressed_chunk17(&mut self, x: i32, z: i32, new: bool, skylight: bool, mask: u16, mask_add: u16, data: &mut std::io::Cursor<Vec<u8>>) -> Result<(), protocol::Error> { fn load_uncompressed_chunk17(
&mut self,
x: i32,
z: i32,
new: bool,
skylight: bool,
mask: u16,
mask_add: u16,
data: &mut std::io::Cursor<Vec<u8>>,
) -> Result<(), protocol::Error> {
let cpos = CPos(x, z); let cpos = CPos(x, z);
{ {
let chunk = if new { let chunk = if new {
@ -716,11 +825,9 @@ impl World {
// Block type array - whole byte per block // Block type array - whole byte per block
let mut block_types = [[0u8; 4096]; 16]; let mut block_types = [[0u8; 4096]; 16];
for i in 0 .. 16 { for i in 0..16 {
if chunk.sections[i].is_none() { if chunk.sections[i].is_none() {
let mut fill_sky = chunk.sections.iter() let mut fill_sky = chunk.sections.iter().skip(i).all(|v| v.is_none());
.skip(i)
.all(|v| v.is_none());
fill_sky &= (mask & !((1 << i) | ((1 << i) - 1))) == 0; fill_sky &= (mask & !((1 << i) | ((1 << i) - 1))) == 0;
if !fill_sky || mask & (1 << i) != 0 { if !fill_sky || mask & (1 << i) != 0 {
chunk.sections[i] = Some(Section::new(i as u8, fill_sky)); chunk.sections[i] = Some(Section::new(i as u8, fill_sky));
@ -738,13 +845,25 @@ impl World {
// Block metadata array - half byte per block // Block metadata array - half byte per block
let mut block_meta: [nibble::Array; 16] = [ let mut block_meta: [nibble::Array; 16] = [
// TODO: cleanup this initialization // TODO: cleanup this initialization
nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
]; ];
for i in 0 .. 16 { for i in 0..16 {
if mask & (1 << i) == 0 { if mask & (1 << i) == 0 {
continue; continue;
} }
@ -753,7 +872,7 @@ impl World {
} }
// Block light array - half byte per block // Block light array - half byte per block
for i in 0 .. 16 { for i in 0..16 {
if mask & (1 << i) == 0 { if mask & (1 << i) == 0 {
continue; continue;
} }
@ -764,7 +883,7 @@ impl World {
// Sky light array - half byte per block - only if 'skylight' is true // Sky light array - half byte per block - only if 'skylight' is true
if skylight { if skylight {
for i in 0 .. 16 { for i in 0..16 {
if mask & (1 << i) == 0 { if mask & (1 << i) == 0 {
continue; continue;
} }
@ -777,13 +896,25 @@ impl World {
// Add array - half byte per block - uses secondary bitmask // Add array - half byte per block - uses secondary bitmask
let mut block_add: [nibble::Array; 16] = [ let mut block_add: [nibble::Array; 16] = [
// TODO: cleanup this initialization // TODO: cleanup this initialization
nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16), nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
nibble::Array::new(16 * 16 * 16),
]; ];
for i in 0 .. 16 { for i in 0..16 {
if mask_add & (1 << i) == 0 { if mask_add & (1 << i) == 0 {
continue; continue;
} }
@ -791,16 +922,25 @@ impl World {
} }
// Now that we have the block types, metadata, and add, combine to initialize the blocks // Now that we have the block types, metadata, and add, combine to initialize the blocks
for i in 0 .. 16 { for i in 0..16 {
if mask & (1 << i) == 0 { if mask & (1 << i) == 0 {
continue; continue;
} }
let section = chunk.sections[i as usize].as_mut().unwrap(); let section = chunk.sections[i as usize].as_mut().unwrap();
for bi in 0 .. 4096 { for bi in 0..4096 {
let id = ((block_add[i].get(bi) as u16) << 12) | ((block_types[i][bi] as u16) << 4) | (block_meta[i].get(bi) as u16); let id = ((block_add[i].get(bi) as u16) << 12)
section.blocks.set(bi, block::Block::by_vanilla_id(id as usize, self.protocol_version, &self.modded_block_ids)); | ((block_types[i][bi] as u16) << 4)
| (block_meta[i].get(bi) as u16);
section.blocks.set(
bi,
block::Block::by_vanilla_id(
id as usize,
self.protocol_version,
&self.modded_block_ids,
),
);
// Spawn block entities // Spawn block entities
let b = section.blocks.get(bi); let b = section.blocks.get(bi);
@ -808,12 +948,18 @@ impl World {
let pos = Position::new( let pos = Position::new(
(bi & 0xF) as i32, (bi & 0xF) as i32,
(bi >> 8) as i32, (bi >> 8) as i32,
((bi >> 4) & 0xF) as i32 ((bi >> 4) & 0xF) as i32,
) + (chunk.position.0 << 4, (i << 4) as i32, chunk.position.1 << 4); ) + (
chunk.position.0 << 4,
(i << 4) as i32,
chunk.position.1 << 4,
);
if chunk.block_entities.contains_key(&pos) { if chunk.block_entities.contains_key(&pos) {
self.block_entity_actions.push_back(BlockEntityAction::Remove(pos)) self.block_entity_actions
.push_back(BlockEntityAction::Remove(pos))
} }
self.block_entity_actions.push_back(BlockEntityAction::Create(pos)) self.block_entity_actions
.push_back(BlockEntityAction::Create(pos))
} }
} }
} }
@ -829,18 +975,40 @@ impl World {
Ok(()) Ok(())
} }
pub fn load_chunk19(&mut self, x: i32, z: i32, new: bool, mask: u16, data: Vec<u8>) -> Result<(), protocol::Error> { pub fn load_chunk19(
&mut self,
x: i32,
z: i32,
new: bool,
mask: u16,
data: Vec<u8>,
) -> Result<(), protocol::Error> {
self.load_chunk19_or_115(true, x, z, new, mask, data) self.load_chunk19_or_115(true, x, z, new, mask, data)
} }
pub fn load_chunk115(&mut self, x: i32, z: i32, new: bool, mask: u16, data: Vec<u8>) -> Result<(), protocol::Error> { pub fn load_chunk115(
&mut self,
x: i32,
z: i32,
new: bool,
mask: u16,
data: Vec<u8>,
) -> Result<(), protocol::Error> {
self.load_chunk19_or_115(false, x, z, new, mask, data) self.load_chunk19_or_115(false, x, z, new, mask, data)
} }
fn load_chunk19_or_115(&mut self, read_biomes: bool, x: i32, z: i32, new: bool, mask: u16, data: Vec<u8>) -> Result<(), protocol::Error> { fn load_chunk19_or_115(
use std::io::Cursor; &mut self,
read_biomes: bool,
x: i32,
z: i32,
new: bool,
mask: u16,
data: Vec<u8>,
) -> Result<(), protocol::Error> {
use crate::protocol::{LenPrefixed, Serializable, VarInt};
use byteorder::ReadBytesExt; use byteorder::ReadBytesExt;
use crate::protocol::{VarInt, Serializable, LenPrefixed}; use std::io::Cursor;
let mut data = Cursor::new(data); let mut data = Cursor::new(data);
@ -856,11 +1024,9 @@ impl World {
self.chunks.get_mut(&cpos).unwrap() self.chunks.get_mut(&cpos).unwrap()
}; };
for i in 0 .. 16 { for i in 0..16 {
if chunk.sections[i].is_none() { if chunk.sections[i].is_none() {
let mut fill_sky = chunk.sections.iter() let mut fill_sky = chunk.sections.iter().skip(i).all(|v| v.is_none());
.skip(i)
.all(|v| v.is_none());
fill_sky &= (mask & !((1 << i) | ((1 << i) - 1))) == 0; fill_sky &= (mask & !((1 << i) | ((1 << i) - 1))) == 0;
if !fill_sky || mask & (1 << i) != 0 { if !fill_sky || mask & (1 << i) != 0 {
chunk.sections[i] = Some(Section::new(i as u8, fill_sky)); chunk.sections[i] = Some(Section::new(i as u8, fill_sky));
@ -871,21 +1037,26 @@ impl World {
} }
let section = chunk.sections[i as usize].as_mut().unwrap(); let section = chunk.sections[i as usize].as_mut().unwrap();
section.dirty = true; section.dirty = true;
if self.protocol_version >= 451 { if self.protocol_version >= 451 {
let _block_count = data.read_u16::<byteorder::LittleEndian>()?; let _block_count = data.read_u16::<byteorder::LittleEndian>()?;
// TODO: use block_count // TODO: use block_count
} }
let mut bit_size = data.read_u8()?; let mut bit_size = data.read_u8()?;
let mut mappings: HashMap<usize, block::Block, BuildHasherDefault<FNVHash>> = HashMap::with_hasher(BuildHasherDefault::default()); let mut mappings: HashMap<usize, block::Block, BuildHasherDefault<FNVHash>> =
HashMap::with_hasher(BuildHasherDefault::default());
if bit_size == 0 { if bit_size == 0 {
bit_size = 13; bit_size = 13;
} else { } else {
let count = VarInt::read_from(&mut data)?.0; let count = VarInt::read_from(&mut data)?.0;
for i in 0 .. count { for i in 0..count {
let id = VarInt::read_from(&mut data)?.0; let id = VarInt::read_from(&mut data)?.0;
let bl = block::Block::by_vanilla_id(id as usize, self.protocol_version, &self.modded_block_ids); let bl = block::Block::by_vanilla_id(
id as usize,
self.protocol_version,
&self.modded_block_ids,
);
mappings.insert(i as usize, bl); mappings.insert(i as usize, bl);
} }
} }
@ -893,21 +1064,37 @@ impl World {
let bits = LenPrefixed::<VarInt, u64>::read_from(&mut data)?.data; let bits = LenPrefixed::<VarInt, u64>::read_from(&mut data)?.data;
let m = bit::Map::from_raw(bits, bit_size as usize); let m = bit::Map::from_raw(bits, bit_size as usize);
for bi in 0 .. 4096 { for bi in 0..4096 {
let id = m.get(bi); let id = m.get(bi);
section.blocks.set(bi, mappings.get(&id).cloned().unwrap_or(block::Block::by_vanilla_id(id, self.protocol_version, &self.modded_block_ids))); section.blocks.set(
bi,
mappings
.get(&id)
.cloned()
.unwrap_or(block::Block::by_vanilla_id(
id,
self.protocol_version,
&self.modded_block_ids,
)),
);
// Spawn block entities // Spawn block entities
let b = section.blocks.get(bi); let b = section.blocks.get(bi);
if block_entity::BlockEntityType::get_block_entity(b).is_some() { if block_entity::BlockEntityType::get_block_entity(b).is_some() {
let pos = Position::new( let pos = Position::new(
(bi & 0xF) as i32, (bi & 0xF) as i32,
(bi >> 8) as i32, (bi >> 8) as i32,
((bi >> 4) & 0xF) as i32 ((bi >> 4) & 0xF) as i32,
) + (chunk.position.0 << 4, (i << 4) as i32, chunk.position.1 << 4); ) + (
chunk.position.0 << 4,
(i << 4) as i32,
chunk.position.1 << 4,
);
if chunk.block_entities.contains_key(&pos) { if chunk.block_entities.contains_key(&pos) {
self.block_entity_actions.push_back(BlockEntityAction::Remove(pos)) self.block_entity_actions
.push_back(BlockEntityAction::Remove(pos))
} }
self.block_entity_actions.push_back(BlockEntityAction::Create(pos)) self.block_entity_actions
.push_back(BlockEntityAction::Create(pos))
} }
} }
@ -964,7 +1151,6 @@ pub struct Snapshot {
} }
impl Snapshot { impl Snapshot {
pub fn make_relative(&mut self, x: i32, y: i32, z: i32) { pub fn make_relative(&mut self, x: i32, y: i32, z: i32) {
self.x = x; self.x = x;
self.y = y; self.y = y;
@ -1033,10 +1219,8 @@ impl Chunk {
Chunk { Chunk {
position: pos, position: pos,
sections: [ sections: [
None,None,None,None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None,None,None,None, None, None,
None,None,None,None,
None,None,None,None,
], ],
sections_rendered_on: [0; 16], sections_rendered_on: [0; 16],
biomes: [0; 16 * 16], biomes: [0; 16 * 16],
@ -1047,13 +1231,13 @@ impl Chunk {
} }
fn calculate_heightmap(&mut self) { fn calculate_heightmap(&mut self) {
for x in 0 .. 16 { for x in 0..16 {
for z in 0 .. 16 { for z in 0..16 {
let idx = ((z<<4)|x) as usize; let idx = ((z << 4) | x) as usize;
for yy in 0 .. 256 { for yy in 0..256 {
let sy = 255 - yy; let sy = 255 - yy;
if let block::Air{..} = self.get_block(x, sy, z) { if let block::Air { .. } = self.get_block(x, sy, z) {
continue continue;
} }
self.heightmap[idx] = sy as u8; self.heightmap[idx] = sy as u8;
break; break;
@ -1073,9 +1257,7 @@ impl Chunk {
if let block::Air {} = b { if let block::Air {} = b {
return false; return false;
} }
let fill_sky = self.sections.iter() let fill_sky = self.sections.iter().skip(s_idx).all(|v| v.is_none());
.skip(s_idx)
.all(|v| v.is_none());
self.sections[s_idx] = Some(Section::new(s_idx as u8, fill_sky)); self.sections[s_idx] = Some(Section::new(s_idx as u8, fill_sky));
} }
{ {
@ -1084,16 +1266,16 @@ impl Chunk {
return false; return false;
} }
} }
let idx = ((z<<4)|x) as usize; let idx = ((z << 4) | x) as usize;
if self.heightmap[idx] < y as u8 { if self.heightmap[idx] < y as u8 {
self.heightmap[idx] = y as u8; self.heightmap[idx] = y as u8;
self.heightmap_dirty = true; self.heightmap_dirty = true;
} else if self.heightmap[idx] == y as u8 { } else if self.heightmap[idx] == y as u8 {
// Find a new lowest // Find a new lowest
for yy in 0 .. y { for yy in 0..y {
let sy = y - yy - 1; let sy = y - yy - 1;
if let block::Air{..} = self.get_block(x, sy, z) { if let block::Air { .. } = self.get_block(x, sy, z) {
continue continue;
} }
self.heightmap[idx] = sy as u8; self.heightmap[idx] = sy as u8;
break; break;
@ -1106,11 +1288,11 @@ impl Chunk {
fn get_block(&self, x: i32, y: i32, z: i32) -> block::Block { fn get_block(&self, x: i32, y: i32, z: i32) -> block::Block {
let s_idx = y >> 4; let s_idx = y >> 4;
if s_idx < 0 || s_idx > 15 { if s_idx < 0 || s_idx > 15 {
return block::Missing{}; return block::Missing {};
} }
match self.sections[s_idx as usize].as_ref() { match self.sections[s_idx as usize].as_ref() {
Some(sec) => sec.get_block(x, y & 0xF, z), Some(sec) => sec.get_block(x, y & 0xF, z),
None => block::Air{}, None => block::Air {},
} }
} }
@ -1135,9 +1317,7 @@ impl Chunk {
if light == 0 { if light == 0 {
return; return;
} }
let fill_sky = self.sections.iter() let fill_sky = self.sections.iter().skip(s_idx).all(|v| v.is_none());
.skip(s_idx)
.all(|v| v.is_none());
self.sections[s_idx] = Some(Section::new(s_idx as u8, fill_sky)); self.sections[s_idx] = Some(Section::new(s_idx as u8, fill_sky));
} }
if let Some(sec) = self.sections[s_idx].as_mut() { if let Some(sec) = self.sections[s_idx].as_mut() {
@ -1166,9 +1346,7 @@ impl Chunk {
if light == 15 { if light == 15 {
return; return;
} }
let fill_sky = self.sections.iter() let fill_sky = self.sections.iter().skip(s_idx).all(|v| v.is_none());
.skip(s_idx)
.all(|v| v.is_none());
self.sections[s_idx] = Some(Section::new(s_idx as u8, fill_sky)); self.sections[s_idx] = Some(Section::new(s_idx as u8, fill_sky));
} }
if let Some(sec) = self.sections[s_idx as usize].as_mut() { if let Some(sec) = self.sections[s_idx as usize].as_mut() {
@ -1177,7 +1355,7 @@ impl Chunk {
} }
fn get_biome(&self, x: i32, z: i32) -> biome::Biome { fn get_biome(&self, x: i32, z: i32) -> biome::Biome {
biome::Biome::by_id(self.biomes[((z<<4)|x) as usize] as usize) biome::Biome::by_id(self.biomes[((z << 4) | x) as usize] as usize)
} }
} }
@ -1212,7 +1390,7 @@ impl Section {
building: false, building: false,
}; };
if fill_sky { if fill_sky {
for i in 0 .. 16*16*16 { for i in 0..16 * 16 * 16 {
section.sky_light.set(i, 0xF); section.sky_light.set(i, 0xF);
} }
} }

View File

@ -1,4 +1,3 @@
use crate::types::bit; use crate::types::bit;
use crate::types::hash::FNVHash; use crate::types::hash::FNVHash;
use crate::world::block; use crate::world::block;
@ -14,15 +13,13 @@ pub struct BlockStorage {
impl BlockStorage { impl BlockStorage {
pub fn new(size: usize) -> BlockStorage { pub fn new(size: usize) -> BlockStorage {
Self::new_default(size, block::Air{}) Self::new_default(size, block::Air {})
} }
pub fn new_default(size: usize, def: block::Block) -> BlockStorage { pub fn new_default(size: usize, def: block::Block) -> BlockStorage {
let mut storage = BlockStorage { let mut storage = BlockStorage {
blocks: bit::Map::new(size, 4), blocks: bit::Map::new(size, 4),
block_map: vec![ block_map: vec![(def, size as u32)],
(def, size as u32)
],
rev_block_map: HashMap::with_hasher(BuildHasherDefault::default()), rev_block_map: HashMap::with_hasher(BuildHasherDefault::default()),
}; };
storage.rev_block_map.insert(def, 0); storage.rev_block_map.insert(def, 0);
@ -45,7 +42,8 @@ impl BlockStorage {
let idx = *self.rev_block_map.get(&old).unwrap(); let idx = *self.rev_block_map.get(&old).unwrap();
let info = &mut self.block_map[idx]; let info = &mut self.block_map[idx];
info.1 -= 1; info.1 -= 1;
if info.1 == 0 { // None left of this type if info.1 == 0 {
// None left of this type
self.rev_block_map.remove(&old); self.rev_block_map.remove(&old);
} }
} }