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. **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. 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

View File

@ -1,11 +1,10 @@
#![recursion_limit="600"]
#![recursion_limit = "600"]
extern crate steven_shared as shared;
use crate::shared::{Axis, Direction, Position};
use collision::Aabb3;
use cgmath::Point3;
use collision::Aabb3;
use lazy_static::lazy_static;
use std::collections::HashMap;
@ -500,7 +499,7 @@ macro_rules! define_blocks {
#[derive(Clone, Copy)]
pub enum TintType {
Default,
Color{r: u8, g: u8, b: u8},
Color { r: u8, g: u8, b: u8 },
Grass,
Foliage,
}
@ -5625,59 +5624,65 @@ define_blocks! {
fn can_burn<W: WorldAccess>(world: &W, pos: Position) -> bool {
match world.get_block(pos) {
Block::Planks{..} |
Block::DoubleWoodenSlab{..} |
Block::WoodenSlab{..} |
Block::FenceGate{..} |
Block::SpruceFenceGate{..} |
Block::BirchFenceGate{..} |
Block::JungleFenceGate{..} |
Block::DarkOakFenceGate{..} |
Block::AcaciaFenceGate{..} |
Block::Fence{..} |
Block::SpruceFence{..} |
Block::BirchFence{..} |
Block::JungleFence{..} |
Block::DarkOakFence{..} |
Block::AcaciaFence{..} |
Block::OakStairs{..} |
Block::BirchStairs{..} |
Block::SpruceStairs{..} |
Block::JungleStairs{..} |
Block::AcaciaStairs{..} |
Block::DarkOakStairs{..} |
Block::Log{..} |
Block::Log2{..} |
Block::Leaves{..} |
Block::Leaves2{..} |
Block::BookShelf{..} |
Block::TNT{..} |
Block::TallGrass{..} |
Block::DoublePlant{..} |
Block::YellowFlower{..} |
Block::RedFlower{..} |
Block::DeadBush{..} |
Block::Wool{..} |
Block::Vine{..} |
Block::CoalBlock{..} |
Block::HayBlock{..} |
Block::Carpet{..} => true,
Block::Planks { .. }
| Block::DoubleWoodenSlab { .. }
| Block::WoodenSlab { .. }
| Block::FenceGate { .. }
| Block::SpruceFenceGate { .. }
| Block::BirchFenceGate { .. }
| Block::JungleFenceGate { .. }
| Block::DarkOakFenceGate { .. }
| Block::AcaciaFenceGate { .. }
| Block::Fence { .. }
| Block::SpruceFence { .. }
| Block::BirchFence { .. }
| Block::JungleFence { .. }
| Block::DarkOakFence { .. }
| Block::AcaciaFence { .. }
| Block::OakStairs { .. }
| Block::BirchStairs { .. }
| Block::SpruceStairs { .. }
| Block::JungleStairs { .. }
| Block::AcaciaStairs { .. }
| Block::DarkOakStairs { .. }
| Block::Log { .. }
| Block::Log2 { .. }
| Block::Leaves { .. }
| Block::Leaves2 { .. }
| Block::BookShelf { .. }
| Block::TNT { .. }
| Block::TallGrass { .. }
| Block::DoublePlant { .. }
| Block::YellowFlower { .. }
| Block::RedFlower { .. }
| Block::DeadBush { .. }
| Block::Wool { .. }
| Block::Vine { .. }
| Block::CoalBlock { .. }
| Block::HayBlock { .. }
| Block::Carpet { .. } => true,
_ => false,
}
}
fn is_snowy<W: WorldAccess>(world: &W, pos: Position) -> bool {
match world.get_block(pos.shift(Direction::Up)) {
Block::Snow{..} | Block::SnowLayer{..} => true,
Block::Snow { .. } | Block::SnowLayer { .. } => true,
_ => false,
}
}
fn can_connect_sides<F: Fn(Block) -> bool, W: WorldAccess>(world: &W, pos: Position, f: &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_sides<F: Fn(Block) -> bool, W: WorldAccess>(
world: &W,
pos: Position,
f: &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 {
@ -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 {
match block {
Block::Fence{..} |
Block::SpruceFence{..} |
Block::BirchFence{..} |
Block::JungleFence{..} |
Block::DarkOakFence{..} |
Block::AcaciaFence{..} |
Block::FenceGate{..} |
Block::SpruceFenceGate{..} |
Block::BirchFenceGate{..} |
Block::JungleFenceGate{..} |
Block::DarkOakFenceGate{..} |
Block::AcaciaFenceGate{..} => true,
Block::Fence { .. }
| Block::SpruceFence { .. }
| Block::BirchFence { .. }
| Block::JungleFence { .. }
| Block::DarkOakFence { .. }
| Block::AcaciaFence { .. }
| Block::FenceGate { .. }
| Block::SpruceFenceGate { .. }
| Block::BirchFenceGate { .. }
| Block::JungleFenceGate { .. }
| Block::DarkOakFenceGate { .. }
| Block::AcaciaFenceGate { .. } => true,
_ => false,
}
}
fn can_connect_glasspane(block: Block) -> bool {
match block {
Block::Glass{..} |
Block::StainedGlass{..} |
Block::GlassPane{..} |
Block::StainedGlassPane{..} => true,
Block::Glass { .. }
| Block::StainedGlass { .. }
| Block::GlassPane { .. }
| Block::StainedGlassPane { .. } => true,
_ => 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 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;
}
@ -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));
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;
}
RedstoneSide::None
}
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 }))
}
fn fence_gate_offset(facing: Direction, in_wall: bool, open: bool, powered: bool) -> Option<usize> {
Some(if powered { 0 } else { 1<<0 } +
if open { 0 } else { 1<<1 } +
if in_wall { 0 } else { 1<<2 } +
facing.horizontal_offset() * (1<<3))
Some(
if powered { 0 } else { 1 << 0 }
+ if open { 0 } else { 1 << 1 }
+ 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>> {
if open { return vec![]; }
if open {
return vec![];
}
let (min_x, min_y, min_z, max_x, max_y, max_z) = if in_wall {
match facing.axis() {
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::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),
_ => unreachable!(),
}
} else {
match facing.axis() {
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::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),
_ => unreachable!(),
}
};
vec![Aabb3::new(
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 {
if let Block::CobblestoneWall{..} = world.get_block(pos.shift(facing.clockwise())) {
if let Block::CobblestoneWall { .. } = world.get_block(pos.shift(facing.clockwise())) {
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;
}
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 {
DoorHalf::Upper => {
if facing == Direction::North && open {
Some(0x8
| (if hinge == Side::Right { 0x1 } else { 0x0 })
| (if powered { 0x2 } else { 0x0 }))
Some(
0x8 | (if hinge == Side::Right { 0x1 } else { 0x0 })
| (if powered { 0x2 } else { 0x0 }),
)
} else {
None
}
},
}
DoorHalf::Lower => {
if hinge == Side::Left && !powered {
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> {
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 door_offset(
facing: Direction,
half: DoorHalf,
hinge: Side,
open: bool,
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>(world: &W, pos: Position, ohalf: DoorHalf, ofacing: Direction, ohinge: Side, oopen: bool, opowered: bool) -> (Direction, Side, bool, bool) {
fn update_door_state<W: WorldAccess>(
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 };
match world.get_block(pos + (0, oy, 0)) {
Block::WoodenDoor{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} => {
Block::WoodenDoor {
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 ohalf == DoorHalf::Upper {
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);
}
}
},
_ => {},
}
_ => {}
}
(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;
let mut bounds = Aabb3::new(
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 {
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,
_ => 0.0,
};
angle += if open {
PI * 0.5
} else {
0.0
} * match hinge { Side::Left => 1.0, Side::Right => -1.0 };
angle += if open { PI * 0.5 } else { 0.0 }
* match hinge {
Side::Left => 1.0,
Side::Right => -1.0,
};
let c = angle.cos();
let s = angle.sin();
let x = bounds.min.x - 0.5;
let z = bounds.min.z - 0.5;
bounds.min.x = 0.5 + (x*c - z*s);
bounds.min.z = 0.5 + (z*c + x*s);
bounds.min.x = 0.5 + (x * c - z * s);
bounds.min.z = 0.5 + (z * c + x * s);
let x = bounds.max.x - 0.5;
let z = bounds.max.z - 0.5;
bounds.max.x = 0.5 + (x*c - z*s);
bounds.max.z = 0.5 + (z*c + x*s);
bounds.max.x = 0.5 + (x * c - z * s);
bounds.max.z = 0.5 + (z * c + x * s);
vec![bounds]
}
fn update_repeater_state<W: WorldAccess>(world: &W, pos: Position, facing: Direction) -> bool {
let f = |dir| {
match world.get_block(pos.shift(dir)) {
Block::RepeaterPowered{..} => true,
_ => false,
}
let f = |dir| match world.get_block(pos.shift(dir)) {
Block::RepeaterPowered { .. } => true,
_ => false,
};
f(facing.clockwise()) || f(facing.counter_clockwise())
}
fn update_double_plant_state<W: WorldAccess>(world: &W, pos: Position, ohalf: BlockHalf, ovariant: DoublePlantVariant) -> (BlockHalf, DoublePlantVariant) {
if ohalf != BlockHalf::Upper { return (ohalf, ovariant); }
fn update_double_plant_state<W: WorldAccess>(
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)) {
Block::DoublePlant{variant, ..} => (ohalf, variant),
Block::DoublePlant { variant, .. } => (ohalf, variant),
_ => (ohalf, ovariant),
}
}
@ -5909,65 +5999,65 @@ fn piston_collision(extended: bool, facing: Direction) -> Vec<Aabb3<f64>> {
vec![Aabb3::new(
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>> {
let (min_x, min_y, min_z, max_x, max_y, max_z) = if open {
match facing {
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::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::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::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),
_ => unreachable!(),
}
} else {
match half {
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::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),
_ => unreachable!(),
}
};
vec![Aabb3::new(
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>> {
let mut collision = vec![Aabb3::new(
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(3.0 / 8.0, 0.0, 3.0 / 8.0),
Point3::new(5.0 / 8.0, 1.5, 5.0 / 8.0),
)];
if north {
collision.push(Aabb3::new(
Point3::new(3.0/8.0, 0.0, 0.0),
Point3::new(5.0/8.0, 1.5, 3.0/8.0))
);
Point3::new(3.0 / 8.0, 0.0, 0.0),
Point3::new(5.0 / 8.0, 1.5, 3.0 / 8.0),
));
}
if south {
collision.push(Aabb3::new(
Point3::new(3.0/8.0, 0.0, 5.0/8.0),
Point3::new(5.0/8.0, 1.5, 1.0))
);
Point3::new(3.0 / 8.0, 0.0, 5.0 / 8.0),
Point3::new(5.0 / 8.0, 1.5, 1.0),
));
}
if west {
collision.push(Aabb3::new(
Point3::new(0.0, 0.0, 3.0/8.0),
Point3::new(3.0/8.0, 1.5, 5.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),
));
}
if east {
collision.push(Aabb3::new(
Point3::new(5.0/8.0, 0.0, 3.0/8.0),
Point3::new(1.0, 1.5, 5.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),
));
}
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>> {
let mut collision = vec![Aabb3::new(
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(7.0 / 16.0, 0.0, 7.0 / 16.0),
Point3::new(9.0 / 16.0, 1.0, 9.0 / 16.0),
)];
if north {
collision.push(Aabb3::new(
Point3::new(7.0/16.0, 0.0, 0.0),
Point3::new(9.0/16.0, 1.0, 9.0/16.0))
);
Point3::new(7.0 / 16.0, 0.0, 0.0),
Point3::new(9.0 / 16.0, 1.0, 9.0 / 16.0),
));
}
if south {
collision.push(Aabb3::new(
Point3::new(7.0/16.0, 0.0, 7.0/16.0),
Point3::new(9.0/16.0, 1.0, 1.0))
);
Point3::new(7.0 / 16.0, 0.0, 7.0 / 16.0),
Point3::new(9.0 / 16.0, 1.0, 1.0),
));
}
if west {
collision.push(Aabb3::new(
Point3::new(0.0, 0.0, 7.0/16.0),
Point3::new(9.0/16.0, 1.0, 9.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),
));
}
if east {
collision.push(Aabb3::new(
Point3::new(7.0/16.0, 0.0, 7.0/16.0),
Point3::new(1.0, 1.0, 9.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),
));
}
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)> {
match world.get_block(pos) {
Block::OakStairs{facing, half, ..} |
Block::StoneStairs{facing, half, ..} |
Block::BrickStairs{facing, half, ..} |
Block::StoneBrickStairs{facing, half, ..} |
Block::NetherBrickStairs{facing, half, ..} |
Block::SandstoneStairs{facing, half, ..} |
Block::SpruceStairs{facing, half, ..} |
Block::BirchStairs{facing, half, ..} |
Block::JungleStairs{facing, half, ..} |
Block::QuartzStairs{facing, half, ..} |
Block::AcaciaStairs{facing, half, ..} |
Block::DarkOakStairs{facing, half, ..} |
Block::RedSandstoneStairs{facing, half, ..} |
Block::PurpurStairs{facing, half, ..} => Some((facing, half)),
Block::OakStairs { facing, half, .. }
| Block::StoneStairs { facing, half, .. }
| Block::BrickStairs { facing, half, .. }
| Block::StoneBrickStairs { facing, half, .. }
| Block::NetherBrickStairs { facing, half, .. }
| Block::SandstoneStairs { facing, half, .. }
| Block::SpruceStairs { facing, half, .. }
| Block::BirchStairs { facing, half, .. }
| Block::JungleStairs { facing, half, .. }
| Block::QuartzStairs { facing, half, .. }
| Block::AcaciaStairs { facing, half, .. }
| Block::DarkOakStairs { facing, half, .. }
| Block::RedSandstoneStairs { facing, half, .. }
| Block::PurpurStairs { facing, half, .. } => Some((facing, half)),
_ => None,
}
}
@ -6054,18 +6144,34 @@ fn update_stair_shape<W: WorldAccess>(world: &W, pos: Position, facing: Directio
StairShape::Straight
}
fn stair_data(facing: Direction, half: BlockHalf, shape: StairShape, waterlogged: bool) -> Option<usize> {
if shape != StairShape::Straight { return None; }
if waterlogged { return None; }
fn stair_data(
facing: Direction,
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 }))
}
fn stair_offset(facing: Direction, half: BlockHalf, shape: StairShape, 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)
fn stair_offset(
facing: Direction,
half: BlockHalf,
shape: StairShape,
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)]
@ -6113,24 +6219,24 @@ fn stair_collision(facing: Direction, shape: StairShape, half: BlockHalf) -> Vec
for bound in &mut bounds {
let x = bound.min.x - 0.5;
let z = bound.min.z - 0.5;
bound.min.x = 0.5 + (x*c - z*s);
bound.min.z = 0.5 + (z*c + x*s);
bound.min.x = 0.5 + (x * c - z * s);
bound.min.z = 0.5 + (z * c + x * s);
let x = bound.max.x - 0.5;
let z = bound.max.z - 0.5;
bound.max.x = 0.5 + (x*c - z*s);
bound.max.z = 0.5 + (z*c + x*s);
bound.max.x = 0.5 + (x * c - z * s);
bound.max.z = 0.5 + (z * c + x * s);
if half == BlockHalf::Top {
let c = PI.cos();
let s = PI.sin();
let z = bound.min.z - 0.5;
let y = bound.min.y - 0.5;
bound.min.z = 0.5 + (z*c - y*s);
bound.min.y = 0.5 + (y*c + z*s);
bound.min.z = 0.5 + (z * c - y * s);
bound.min.y = 0.5 + (y * c + z * s);
let z = bound.max.z - 0.5;
let y = bound.max.y - 0.5;
bound.max.z = 0.5 + (z*c - y*s);
bound.max.y = 0.5 + (y*c + z*s);
bound.max.z = 0.5 + (z * c - y * s);
bound.max.y = 0.5 + (y * c + z * s);
bound.min.x = 1.0 - bound.min.x;
bound.max.x = 1.0 - bound.max.x;
@ -6150,7 +6256,7 @@ fn slab_collision(half: BlockHalf) -> Vec<Aabb3<f64>> {
vec![Aabb3::new(
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)]
pub enum BedPart {
Head,
Foot
Foot,
}
impl BedPart {
@ -6301,7 +6407,6 @@ impl NoteBlockInstrument {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum RedSandstoneVariant {
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> {
Some(match
(is_stem, west, up, south, north, east, down) {
fn mushroom_block_data(
is_stem: bool,
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, true, false, false, true, false, false) => 1,
(false, false, false, false, true, false, false) => 2,
(false, false, false, false, true, true, false) => 3,
(false, true, false, false, false, false, false) => 4,
(false, false, true, false, false, false, false) => 5,
(false, false, false, false, false, true, false) => 6,
(false, true, false, true, false, false, false) => 7,
(false, false, false, true, false, false, false) => 8,
(false, false, false, true, false, true, false) => 9,
(false, true, false, true, true, true, false) => 10,
(false, true, true, true, true, true, true) => 14,
(true, false, false, false, false, false, false) => 15,
(false, true, false, false, true, false, false) => 1,
(false, false, false, false, true, false, false) => 2,
(false, false, false, false, true, true, false) => 3,
(false, true, false, false, false, false, false) => 4,
(false, false, true, false, false, false, false) => 5,
(false, false, false, false, false, true, false) => 6,
(false, true, false, true, false, false, false) => 7,
(false, false, false, true, false, false, false) => 8,
(false, false, false, true, false, true, false) => 9,
(false, true, false, true, true, true, false) => 10,
(false, true, true, true, true, true, true) => 14,
(true, false, false, false, false, false, false) => 15,
_ => 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 {
None
} else {
Some(if west { 0 } else { 1<<0 } +
if up { 0 } else { 1<<1 } +
if south { 0 } else { 1<<2 } +
if north { 0 } else { 1<<3 } +
if east { 0 } else { 1<<4 } +
if down { 0 } else { 1<<5 })
Some(
if west { 0 } else { 1 << 0 }
+ if up { 0 } else { 1 << 1 }
+ if south { 0 } else { 1 << 2 }
+ if north { 0 } else { 1 << 3 }
+ if east { 0 } else { 1 << 4 }
+ if down { 0 } else { 1 << 5 },
)
}
}
fn mushroom_block_variant(is_stem: bool, west: bool, up: bool, south: bool, north: bool, east: bool, down: bool) -> String {
fn mushroom_block_variant(
is_stem: bool,
west: bool,
up: bool,
south: bool,
north: bool,
east: bool,
down: bool,
) -> String {
(if is_stem {
"all_stem"
} else {
match
(west, up, south, north, east, down) {
match (west, up, south, north, east, down) {
(false, false, false, false, false, false) => "all_inside",
(true, false, false, true, false, false) => "north_west",
(false, false, false, true, false, false) => "north",
(false, false, false, true, true, false) => "north_east",
(true, false, false, false, false, false) => "west",
(false, true, false, false, false, false) => "center",
(false, false, false, false, true, false) => "east",
(true, false, true, false, false, false) => "south_west",
(false, false, true, false, false, false) => "south",
(false, false, true, false, true, false) => "south_east",
(true, false, true, true, true, false) => "stem",
(true, true, true, true, true, true) => "all_outside",
(true, false, false, true, false, false) => "north_west",
(false, false, false, true, false, false) => "north",
(false, false, false, true, true, false) => "north_east",
(true, false, false, false, false, false) => "west",
(false, true, false, false, false, false) => "center",
(false, false, false, false, true, false) => "east",
(true, false, true, false, false, false) => "south_west",
(false, false, true, false, false, false) => "south",
(false, false, true, false, true, false) => "south_east",
(true, false, true, true, true, false) => "stem",
(true, true, true, true, true, true) => "all_outside",
_ => "all_stem",
}
}).to_string()
})
.to_string()
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum DoorHalf {
Upper,
Lower
Lower,
}
impl DoorHalf {
@ -6771,9 +6900,9 @@ impl StoneSlabVariant {
fn data(self) -> usize {
match self {
StoneSlabVariant::Stone |
StoneSlabVariant::RedSandstone |
StoneSlabVariant::Purpur => 0,
StoneSlabVariant::Stone | StoneSlabVariant::RedSandstone | StoneSlabVariant::Purpur => {
0
}
StoneSlabVariant::Sandstone => 1,
StoneSlabVariant::PetrifiedWood => 2,
StoneSlabVariant::Cobblestone => 3,
@ -7037,7 +7166,8 @@ impl AttachedFace {
(AttachedFace::Floor, Direction::East) => "up_x",
(AttachedFace::Ceiling, Direction::South) => "down_z",
_ => "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)]
pub enum TreeVariant {
Oak,
@ -7125,7 +7254,7 @@ impl TreeVariant {
TreeVariant::StrippedJungle => "stripped_jungle_log",
TreeVariant::StrippedAcacia => "stripped_acacia_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 renderable: 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::fs::File;
use std::io::BufWriter;
use std::path::Path;
use gl_generator::{Registry, Api, Profile, Fallbacks, GlobalGenerator};
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let dest = Path::new(&out_dir);
let mut file = BufWriter::new(File::create(&dest.join("bindings.rs")).unwrap());
Registry::new(Api::Gl,
(3, 2),
Profile::Core,
Fallbacks::All,
[])
Registry::new(Api::Gl, (3, 2), Profile::Core, Fallbacks::All, [])
.write_bindings(GlobalGenerator, &mut file)
.unwrap();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,34 +16,36 @@
#![allow(non_camel_case_types)]
use aes::Aes128;
use cfb8::Cfb8;
use cfb8::stream_cipher::{NewStreamCipher, StreamCipher};
use serde_json;
use std_or_web::fs;
use cfb8::Cfb8;
use hex;
#[cfg(not(target_arch = "wasm32"))]
use reqwest;
use hex;
use serde_json;
use std_or_web::fs;
pub mod mojang;
pub mod forge;
pub mod mojang;
use crate::nbt;
use crate::format;
use std::fmt;
use std::default;
use std::net::TcpStream;
use std::io;
use std::io::{Write, Read};
use std::convert;
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use crate::nbt;
use crate::shared::Position;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use flate2::read::{ZlibDecoder, ZlibEncoder};
use flate2::Compression;
use std::time::{Instant, Duration};
use crate::shared::Position;
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 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> {
let ty = buf.read_u8()?;
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> {
Result::Ok(Some(T::read_from(buf)?))
}
@ -318,11 +323,7 @@ impl Serializable for bool {
Result::Ok(buf.read_u8()? != 0)
}
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
buf.write_u8(if *self {
1
} else {
0
})?;
buf.write_u8(if *self { 1 } else { 0 })?;
Result::Ok(())
}
}
@ -433,9 +434,9 @@ impl UUID {
parts.extend_from_slice(&hex::decode(&s[24..36]).unwrap());
let mut high = 0u64;
let mut low = 0u64;
for i in 0 .. 8 {
high |= (parts[i] as u64) << (56 - i*8);
low |= (parts[i + 8] as u64) << (56 - i*8);
for i in 0..8 {
high |= (parts[i] as u64) << (56 - i * 8);
low |= (parts[i + 8] as u64) << (56 - i * 8);
}
UUID(high, low)
}
@ -449,8 +450,10 @@ impl Default for UUID {
impl Serializable for UUID {
fn read_from<R: io::Read>(buf: &mut R) -> Result<UUID, Error> {
Result::Ok(UUID(buf.read_u64::<BigEndian>()?,
buf.read_u64::<BigEndian>()?))
Result::Ok(UUID(
buf.read_u64::<BigEndian>()?,
buf.read_u64::<BigEndian>()?,
))
}
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
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 from_len(_: usize) -> Self;
}
@ -507,7 +509,7 @@ pub struct LenPrefixed<L: Lengthable, 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> {
LenPrefixed {
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> {
let len_data: L = Serializable::read_from(buf)?;
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 {
LenPrefixed {
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 {
self.data.fmt(f)
}
@ -563,7 +564,7 @@ pub struct LenPrefixedBytes<L: Lengthable> {
pub data: Vec<u8>,
}
impl <L: Lengthable> LenPrefixedBytes<L> {
impl<L: Lengthable> LenPrefixedBytes<L> {
pub fn new(data: Vec<u8>) -> LenPrefixedBytes<L> {
LenPrefixedBytes {
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> {
let len_data: L = Serializable::read_from(buf)?;
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 {
LenPrefixedBytes {
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 {
self.data.fmt(f)
}
@ -610,7 +610,11 @@ impl <L: Lengthable> fmt::Debug for LenPrefixedBytes<L> {
impl Lengthable for bool {
fn into_len(self) -> usize {
if self { 1 } else { 0 }
if self {
1
} else {
0
}
}
fn from_len(u: usize) -> bool {
@ -618,7 +622,6 @@ impl Lengthable for bool {
}
}
impl Lengthable for u8 {
fn into_len(self) -> 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 {
let x: f64 = (*self).into();
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 {
let x: f64 = (*self).into();
write!(f, "FixedPoint12(#{} = {}f)", self.0, x)
@ -751,7 +764,7 @@ impl Lengthable for VarInt {
impl Serializable for VarInt {
/// Decodes a `VarInt` from the Reader
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 val = 0u32;
loop {
@ -762,7 +775,7 @@ impl Serializable for VarInt {
return Result::Err(Error::Err("VarInt too big".to_owned()));
}
if (b & 0x80) == 0 {
break
break;
}
}
@ -771,7 +784,7 @@ impl Serializable for VarInt {
/// Encodes a `VarInt` into the Writer
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;
loop {
if (val & !PART) == 0 {
@ -826,7 +839,11 @@ impl Serializable for VarShort {
}
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 high = (self.0 & 0x7f8000) >> 15;
if high != 0 {
@ -873,7 +890,7 @@ impl Lengthable for VarLong {
impl Serializable for VarLong {
/// Decodes a `VarLong` from the Reader
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 val = 0u64;
loop {
@ -884,7 +901,7 @@ impl Serializable for VarLong {
return Result::Err(Error::Err("VarLong too big".to_owned()));
}
if (b & 0x80) == 0 {
break
break;
}
}
@ -893,7 +910,7 @@ impl Serializable for VarLong {
/// Encodes a `VarLong` into the Writer
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;
loop {
if (val & !PART) == 0 {
@ -924,7 +941,7 @@ impl Serializable for Position {
Ok(Position::new(
((pos as i64) >> 38) 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> {
@ -936,7 +953,6 @@ impl Serializable for Position {
}
}
/// Direction is used to define whether packets are going to the
/// server or the client.
#[derive(Clone, Copy, Debug)]
@ -1058,9 +1074,13 @@ impl Conn {
let mut write = ZlibEncoder::new(io::Cursor::new(buf), Compression::default());
write.read_to_end(&mut new)?;
if is_network_debug() {
debug!("Compressed for sending {} bytes to {} since > threshold {}, new={:?}",
uncompressed_size, new.len(), self.compression_threshold,
new);
debug!(
"Compressed for sending {} bytes to {} since > threshold {}, new={:?}",
uncompressed_size,
new.len(),
self.compression_threshold,
new
);
}
buf = new;
}
@ -1090,8 +1110,13 @@ impl Conn {
reader.read_to_end(&mut new)?;
}
if is_network_debug() {
debug!("Decompressed threshold={} len={} uncompressed_size={} to {} bytes",
self.compression_threshold, len, uncompressed_size, new.len());
debug!(
"Decompressed threshold={} len={} uncompressed_size={} to {} bytes",
self.compression_threshold,
len,
uncompressed_size,
new.len()
);
}
buf = io::Cursor::new(new);
}
@ -1104,7 +1129,10 @@ impl Conn {
};
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())?;
}
@ -1119,10 +1147,12 @@ impl Conn {
let pos = buf.position() as usize;
let ibuf = buf.into_inner();
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",
id,
ibuf.len() - pos)))
id,
ibuf.len() - pos
)));
}
Result::Ok(val)
}
@ -1140,10 +1170,10 @@ impl Conn {
}
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::status::serverbound::*;
use self::packet::Packet;
use serde_json::Value;
let host = self.host.clone();
let port = self.port;
self.write_packet(Handshake {
@ -1191,16 +1221,22 @@ impl Conn {
if let Value::Array(items) = modlist {
for item in items {
if let Value::Object(obj) = item {
let modid = obj.get("modid").unwrap().as_str().unwrap().to_string();
let version = obj.get("version").unwrap().as_str().unwrap().to_string();
let modid =
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 {
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 {
if let Value::Object(obj) = item {
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;
@ -1222,29 +1259,41 @@ impl Conn {
}
}
Ok((Status {
version: StatusVersion {
name: version.get("name").and_then(Value::as_str).ok_or(invalid_status())?
.to_owned(),
protocol: version.get("protocol")
.and_then(Value::as_i64)
.ok_or(invalid_status())? as i32,
Ok((
Status {
version: StatusVersion {
name: version
.get("name")
.and_then(Value::as_str)
.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 {
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))
ping,
))
}
}

View File

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

View File

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

View File

@ -1,22 +1,22 @@
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 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_8_9;
mod v1_9;
mod v1_9_2;
// https://wiki.vg/Protocol_History
// 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 {
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),

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 {
Map {
length: (bits.len()*64 + (size-1)) / size,
length: (bits.len() * 64 + (size - 1)) / size,
bit_size: size,
bits,
}

View File

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

View File

@ -34,7 +34,9 @@ fn test_set() {
impl 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) {

View File

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

View File

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

View File

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

View File

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

View File

@ -1,8 +1,8 @@
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::io::BufWriter;
use std::io::Write;
use std::path::{Path, PathBuf};
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
@ -13,7 +13,11 @@ fn main() {
build_map(&mut out, &base);
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();
for path in &out {
let mut absolute_path = std::env::current_dir().unwrap();
@ -22,10 +26,14 @@ fn main() {
let absolute = absolute_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();
}
fn build_map(out: &mut Vec<PathBuf>, path: &Path) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,16 +1,15 @@
use std::thread;
use std::sync::mpsc;
use std::sync::{Arc, RwLock};
use crate::world;
use crate::world::block;
use crate::model;
use crate::render;
use crate::resources;
use crate::model;
use crate::types::bit::Set;
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 std::sync::mpsc;
use std::sync::{Arc, RwLock};
use std::thread;
const NUM_WORKERS: usize = 8;
@ -24,18 +23,27 @@ pub struct ChunkBuilder {
}
impl ChunkBuilder {
pub fn new(resources: Arc<RwLock<resources::Manager>>, textures: Arc<RwLock<render::TextureManager>>) -> ChunkBuilder {
let models = Arc::new(RwLock::new(model::Factory::new(resources.clone(), textures)));
pub fn new(
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 free = vec![];
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 (work_send, work_recv) = mpsc::channel();
let models = models.clone();
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![]));
}
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 {
self.resource_version = version;
@ -58,35 +71,50 @@ impl ChunkBuilder {
while let Ok((id, mut val)) = self.built_recv.try_recv() {
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;
renderer.update_chunk_solid(&mut sec.render_buffer, &val.solid_buffer, val.solid_count);
renderer.update_chunk_trans(&mut sec.render_buffer, &val.trans_buffer, val.trans_count);
renderer.update_chunk_solid(
&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.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() {
return;
}
let dirty_sections = world.get_render_list().iter()
.map(|v| v.0)
.filter(|v| world.is_section_dirty(*v))
.collect::<Vec<_>>();
for (x,y, z) in dirty_sections {
let dirty_sections = world
.get_render_list()
.iter()
.map(|v| v.0)
.filter(|v| world.is_section_dirty(*v))
.collect::<Vec<_>>();
for (x, y, z) in dirty_sections {
let t_id = self.free_builders.pop().unwrap();
world.set_building_flag((x, y, z));
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);
snapshot.make_relative(-2, -2, -2);
self.threads[t_id.0].0.send(BuildReq {
snapshot,
position: (x, y, z),
solid_buffer: t_id.1,
trans_buffer: t_id.2,
}).unwrap();
self.threads[t_id.0]
.0
.send(BuildReq {
snapshot,
position: (x, y, z),
solid_buffer: t_id.1,
trans_buffer: t_id.2,
})
.unwrap();
if self.free_builders.is_empty() {
return;
}
@ -110,7 +138,12 @@ struct BuildReply {
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 {
let BuildReq {
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) >> 16) & 0xff) as u8,
((position.0 as u32) >> 24) as u8,
((position.1 as u32) & 0xff) as u8,
(((position.1 as u32) >> 8) & 0xff) as u8,
(((position.1 as u32) >> 16) & 0xff) as u8,
((position.1 as u32) >> 24) as u8,
((position.2 as u32) & 0xff) as u8,
(((position.2 as u32) >> 8) & 0xff) as u8,
(((position.2 as u32) >> 16) & 0xff) 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) >> 8) & 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 trans_count = 0;
for y in 0 .. 16 {
for x in 0 .. 16 {
for z in 0 .. 16 {
for y in 0..16 {
for x in 0..16 {
for z in 0..16 {
let block = snapshot.get_block(x, y, z);
let mat = block.get_material();
if !mat.renderable {
@ -161,26 +191,56 @@ fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::R
}
match block {
block::Block::Water{..} | block::Block::FlowingWater{..} => {
block::Block::Water { .. } | block::Block::FlowingWater { .. } => {
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;
},
block::Block::Lava{..} | block::Block::FlowingLava{..} => {
}
block::Block::Lava { .. } | block::Block::FlowingLava { .. } => {
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;
},
_ => {},
}
_ => {}
}
if mat.transparent {
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 {
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);
built_send.send((id, BuildReply {
position,
solid_buffer,
solid_count,
trans_buffer,
trans_count,
cull_info,
})).unwrap();
built_send
.send((
id,
BuildReply {
position,
solid_buffer,
solid_count,
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 info = CullInfo::new();
for y in 0 .. 16 {
for z in 0 .. 16 {
for x in 0 .. 16 {
for y in 0..16 {
for z in 0..16 {
for x in 0..16 {
if visited.get(x | (z << 4) | (y << 8)) {
continue;
}
@ -246,7 +311,11 @@ fn flood_fill(snapshot: &world::Snapshot, visited: &mut Set, x: i32, y: i32, z:
}
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;
}
@ -268,7 +337,7 @@ fn flood_fill(snapshot: &world::Snapshot, visited: &mut Set, x: i32, y: i32, z:
for d in Direction::all() {
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
@ -278,7 +347,9 @@ fn flood_fill(snapshot: &world::Snapshot, visited: &mut Set, x: i32, y: i32, z:
pub struct CullInfo(u64);
impl CullInfo {
pub fn new() -> CullInfo { Default::default() }
pub fn new() -> CullInfo {
Default::default()
}
pub fn all_vis() -> CullInfo {
CullInfo(0xFFFFFFFFFFFFFFFF)

View File

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

View File

@ -13,17 +13,17 @@
// limitations under the License.
use crate::types::bit::Set as BSet;
use std::collections::{HashMap, HashSet};
use std::hash::BuildHasherDefault;
use crate::types::hash::FNVHash;
use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::hash::BuildHasherDefault;
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use crate::world;
use crate::render;
use crate::world;
/// Used to reference an entity.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@ -38,7 +38,7 @@ pub struct Key<T> {
id: usize,
_t: PhantomData<T>,
}
impl <T> Clone for Key<T> {
impl<T> Clone for Key<T> {
fn clone(&self) -> Self {
Key {
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.
pub struct Filter {
@ -56,9 +56,7 @@ pub struct Filter {
impl Filter {
/// Creates an empty filter which matches everything
pub fn new() -> Filter {
Filter {
bits: BSet::new(0),
}
Filter { bits: BSet::new(0) }
}
/// Adds the component to the filter.
@ -74,12 +72,29 @@ impl Filter {
/// A system processes entities
pub trait System {
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 {
Manager {
num_components: 0,
entities: vec![(Some(EntityState {
last_components: BSet::new(0),
components: BSet::new(0),
removed: false,
}), 0)], // Has the world entity pre-defined
entities: vec![(
Some(EntityState {
last_components: BSet::new(0),
components: BSet::new(0),
removed: false,
}),
0,
)], // Has the world entity pre-defined
free_entities: vec![],
components: vec![],
@ -166,7 +184,11 @@ impl Manager {
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();
self.changed_entity_components = HashSet::with_hasher(BuildHasherDefault::default());
for entity in changes {
@ -177,11 +199,35 @@ impl Manager {
state.components.or(&state.last_components);
(cur, orig)
};
self.trigger_add_for_systems(entity, &state.last_components, &state.components, 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() {
self.trigger_add_for_systems(
entity,
&state.last_components,
&state.components,
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) {
let components = self.components.get_mut(i).and_then(|v| v.as_mut()).unwrap();
components.remove(entity.id);
@ -230,7 +276,7 @@ impl Manager {
return Entity {
id,
generation: entity.1,
}
};
}
let id = self.entities.len();
self.entities.push((
@ -239,12 +285,9 @@ impl Manager {
components: BSet::new(self.num_components),
removed: false,
}),
0
0,
));
Entity {
id,
generation: 0,
}
Entity { id, generation: 0 }
}
/// Deallocates an entity and frees its components
@ -257,12 +300,16 @@ impl Manager {
}
/// 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() {
if let Some(set) = e.0.as_mut() {
set.components = BSet::new(self.components.len());
set.removed = true;
self.changed_entity_components.insert(Entity{
self.changed_entity_components.insert(Entity {
id: id + 1,
generation: e.1,
});
@ -312,7 +359,13 @@ impl Manager {
}
let mut e = self.entities.get_mut(entity.id);
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"),
};
let set = match set.as_mut() {
@ -327,24 +380,44 @@ impl Manager {
}
set.components.set(key.id, true);
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);
}
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();
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);
}
}
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();
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);
}
}
@ -371,7 +444,13 @@ impl Manager {
}
let mut e = self.entities.get_mut(entity.id);
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"),
};
let set = match set.as_mut() {
@ -382,7 +461,7 @@ impl Manager {
panic!("Double change within a single tick");
}
if !set.components.get(key.id) {
return false
return false;
}
set.components.set(key.id, false);
self.changed_entity_components.insert(entity);
@ -390,20 +469,36 @@ impl Manager {
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();
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);
}
}
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();
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);
}
}
@ -424,7 +519,13 @@ impl Manager {
None => return None,
};
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,
};
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.
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()) {
Some(val) => val,
None => return None,
};
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,
};
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
/// 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();
self.get_component_mut(entity, key)
}
@ -479,12 +593,10 @@ impl ComponentMem {
ComponentMem {
data: vec![],
component_size: mem::size_of::<T>(),
drop_func: Box::new(|data| {
unsafe {
let mut val: T = mem::MaybeUninit::uninit().assume_init();
ptr::copy(data as *mut T, &mut val, 1);
mem::drop(val);
}
drop_func: Box::new(|data| unsafe {
let mut val: T = mem::MaybeUninit::uninit().assume_init();
ptr::copy(data as *mut T, &mut val, 1);
mem::drop(val);
}),
}
}
@ -496,7 +608,11 @@ impl ComponentMem {
let idx = index / COMPONENTS_PER_BLOCK;
let rem = index % COMPONENTS_PER_BLOCK;
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 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 use the drop_func which stores the type in its closure
// 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
};
@ -532,9 +650,7 @@ impl ComponentMem {
let rem = index % COMPONENTS_PER_BLOCK;
let data = self.data[idx].as_ref().unwrap();
let start = rem * self.component_size;
unsafe {
&*(data.0.as_ptr().offset(start as isize) as *const T)
}
unsafe { &*(data.0.as_ptr().offset(start as isize) as *const T) }
}
fn get_mut<T>(&mut self, index: usize) -> &mut T {
@ -542,9 +658,7 @@ impl ComponentMem {
let rem = index % COMPONENTS_PER_BLOCK;
let data = self.data[idx].as_mut().unwrap();
let start = rem * self.component_size;
unsafe {
&mut *(data.0.as_mut_ptr().offset(start as isize) as *mut T)
}
unsafe { &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) {
for data in &mut self.data {
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) {
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;
use crate::world::block::Block;
use crate::shared::Position;
use crate::ecs;
use crate::shared::Position;
use crate::world::block::Block;
pub fn add_systems(m: &mut ecs::Manager) {
sign::add_systems(m);
}
pub enum BlockEntityType {
Sign
Sign,
}
impl BlockEntityType {
pub fn get_block_entity(bl: Block) -> Option<BlockEntityType> {
match bl {
Block::StandingSign{..} | Block::WallSign{..} => Some(BlockEntityType::Sign),
Block::StandingSign { .. } | Block::WallSign { .. } => Some(BlockEntityType::Sign),
_ => None,
}
}

View File

@ -1,11 +1,10 @@
use crate::ecs;
use crate::format::{self, Component};
use crate::render;
use crate::render::model::{self, FormatState};
use crate::shared::{Direction, Position};
use crate::world;
use crate::world::block::Block;
use crate::render;
use crate::render::model::{self, FormatState};
pub fn add_systems(m: &mut ecs::Manager) {
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) {
m.add_component_direct(e, SignInfo {
model: None,
lines: [
Component::Text(format::TextComponent::new("")),
Component::Text(format::TextComponent::new("")),
Component::Text(format::TextComponent::new("")),
Component::Text(format::TextComponent::new("")),
],
offset_x: 0.0,
offset_y: 0.0,
offset_z: 0.0,
has_stand: false,
rotation: 0.0,
dirty: false,
});
m.add_component_direct(
e,
SignInfo {
model: None,
lines: [
Component::Text(format::TextComponent::new("")),
Component::Text(format::TextComponent::new("")),
Component::Text(format::TextComponent::new("")),
Component::Text(format::TextComponent::new("")),
],
offset_x: 0.0,
offset_y: 0.0,
offset_z: 0.0,
has_stand: false,
rotation: 0.0,
dirty: false,
},
);
}
pub struct SignInfo {
@ -54,9 +56,7 @@ impl SignRenderer {
let sign_info = m.get_key();
let position = m.get_key();
SignRenderer {
filter: ecs::Filter::new()
.with(position)
.with(sign_info),
filter: ecs::Filter::new().with(position).with(sign_info),
position,
sign_info,
}
@ -64,12 +64,16 @@ impl SignRenderer {
}
impl ecs::System for SignRenderer {
fn filter(&self) -> &ecs::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) {
let position = *m.get_component(e, self.position).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 cgmath::{Vector3, Matrix4, Decomposed, Rotation3, Rad, Quaternion};
let position = *m.get_component(e, self.position).unwrap();
let info = m.get_component_mut(e, self.sign_info).unwrap();
info.dirty = false;
match world.get_block(position) {
Block::WallSign{facing, ..} => {
Block::WallSign { facing, .. } => {
info.offset_z = 7.5 / 16.0;
match facing {
Direction::North => {},
Direction::North => {}
Direction::South => info.rotation = PI,
Direction::West => info.rotation = PI / 2.0,
Direction::East => info.rotation = -PI / 2.0,
_ => unreachable!(),
}
},
Block::StandingSign{rotation, ..} => {
}
Block::StandingSign { rotation, .. } => {
info.offset_y = 5.0 / 16.0;
info.has_stand = true;
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");
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))
);
};
}
let mut verts = vec![];
// 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, [
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
]);
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,
[
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 {
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, [
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
]);
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,
[
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() {
@ -154,15 +182,12 @@ impl ecs::System for SignRenderer {
// Center align text
for vert in &mut state.text {
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);
}
let model = renderer.model.create_model(
model::DEFAULT,
vec![verts]
);
let model = renderer.model.create_model(model::DEFAULT, vec![verts]);
{
let mdl = renderer.model.get_model(model).unwrap();
@ -173,14 +198,28 @@ impl ecs::System for SignRenderer {
mdl.matrix[0] = Matrix4::from(Decomposed {
scale: 1.0,
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),
}) * Matrix4::from_translation(Vector3::new(info.offset_x as f32, -info.offset_y as f32, info.offset_z as f32));
disp: Vector3::new(
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);
}
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();
if let Some(model) = info.model {
renderer.model.remove_model(model);

View File

@ -1,6 +1,5 @@
pub mod player;
pub mod block_entity;
pub mod player;
use crate::ecs;
use cgmath::Vector3;
@ -96,10 +95,7 @@ pub struct Rotation {
impl Rotation {
pub fn new(yaw: f64, pitch: f64) -> Rotation {
Rotation {
yaw,
pitch,
}
Rotation { yaw, pitch }
}
pub fn zero() -> Rotation {
@ -114,10 +110,7 @@ pub struct TargetRotation {
impl TargetRotation {
pub fn new(yaw: f64, pitch: f64) -> TargetRotation {
TargetRotation {
yaw,
pitch,
}
TargetRotation { yaw, pitch }
}
pub fn zero() -> TargetRotation {
@ -131,7 +124,9 @@ pub struct Gravity {
}
impl Gravity {
pub fn new() -> Gravity { Default::default() }
pub fn new() -> Gravity {
Default::default()
}
}
pub struct Bounds {
@ -140,9 +135,7 @@ pub struct Bounds {
impl Bounds {
pub fn new(bounds: Aabb3<f64>) -> Bounds {
Bounds {
bounds,
}
Bounds { bounds }
}
}
@ -152,7 +145,9 @@ pub struct GameInfo {
}
impl GameInfo {
pub fn new() -> GameInfo { Default::default() }
pub fn new() -> GameInfo {
Default::default()
}
}
#[derive(Default)]
@ -162,5 +157,7 @@ pub struct 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::{
Position,
TargetPosition,
Velocity,
Rotation,
TargetRotation,
Gravity,
Bounds,
GameInfo,
Light
Bounds, GameInfo, Gravity, Light, Position, Rotation, TargetPosition, TargetRotation, Velocity,
};
use crate::world;
use crate::ecs;
use crate::format;
use crate::render;
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::world;
use cgmath::{self, Decomposed, Matrix4, Point3, Quaternion, Rad, Rotation3, Vector3};
use collision::{Aabb, Aabb3};
use cgmath::{self, Point3, Vector3, Matrix4, Decomposed, Rotation3, Rad, Quaternion};
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
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) {
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, Gravity::new());
m.add_component_direct(entity, PlayerMovement::new());
m.add_component_direct(entity, 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,
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, Light::new());
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, TargetRotation::new(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(
Point3::new(-0.3, 0.0, -0.3),
Point3::new(0.3, 1.8, 0.3)
)));
m.add_component_direct(
entity,
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, Light::new());
entity
}
pub struct PlayerModel {
model: Option<model::ModelKey>,
skin_url: Option<String>,
@ -155,16 +151,23 @@ enum PlayerModelPart {
// TODO: Setup culling
impl ecs::System for PlayerRenderer {
fn filter(&self) -> &ecs::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::f64::consts::PI as PI64;
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) {
let player_model = m.get_component_mut(e, self.player_model).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;
let offset = if player_model.first_person {
let ox = (rotation.yaw - PI64/2.0).cos() * 0.25;
let oz = -(rotation.yaw - PI64/2.0).sin() * 0.25;
let ox = (rotation.yaw - PI64 / 2.0).cos() * 0.25;
let oz = -(rotation.yaw - PI64 / 2.0).sin() * 0.25;
Vector3::new(
position.position.x as f32 - ox as f32,
-position.position.y as f32,
@ -205,24 +208,28 @@ impl ecs::System for PlayerRenderer {
// TODO This sucks
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 {
scale: 1.0,
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 {
scale: 1.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,
rot: Quaternion::from_angle_x(Rad(0.0)),
disp: Vector3::new(0.0, -12.0/16.0 - 6.0/16.0, 0.0),
});
mdl.matrix[PlayerModelPart::Head as usize] = offset_matrix
* Matrix4::from(Decomposed {
scale: 1.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,
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 dir = player_model.dir;
@ -232,16 +239,18 @@ impl ecs::System for PlayerRenderer {
}
let ang = ((time / 15.0) - 1.0) * (PI64 / 4.0);
mdl.matrix[PlayerModelPart::LegRight as usize] = offset_matrix * Matrix4::from(Decomposed {
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),
});
mdl.matrix[PlayerModelPart::LegLeft as usize] = offset_matrix * Matrix4::from(Decomposed {
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),
});
mdl.matrix[PlayerModelPart::LegRight as usize] = offset_matrix
* Matrix4::from(Decomposed {
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),
});
mdl.matrix[PlayerModelPart::LegLeft as usize] = offset_matrix
* Matrix4::from(Decomposed {
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;
i_time += delta * 0.02;
@ -256,17 +265,31 @@ impl ecs::System for PlayerRenderer {
player_model.arm_time -= delta;
}
mdl.matrix[PlayerModelPart::ArmRight as usize] = offset_matrix * Matrix4::from_translation(
Vector3::new(6.0/16.0, -12.0/16.0-12.0/16.0, 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::ArmRight as usize] = offset_matrix
* Matrix4::from_translation(Vector3::new(
6.0 / 16.0,
-12.0 / 16.0 - 12.0 / 16.0,
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(
Vector3::new(-6.0/16.0, -12.0/16.0-12.0/16.0, 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)));
mdl.matrix[PlayerModelPart::ArmLeft as usize] = offset_matrix
* Matrix4::from_translation(Vector3::new(
-6.0 / 16.0,
-12.0 / 16.0 - 12.0 / 16.0,
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;
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();
player_model.dirty = false;
@ -309,76 +338,133 @@ impl ecs::System for PlayerRenderer {
};
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))
);
};
}
let mut head_verts = vec![];
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, [
srel!(16.0, 0.0, 8.0, 8.0), // Down
srel!(8.0, 0.0, 8.0, 8.0), // Up
srel!(8.0, 8.0, 8.0, 8.0), // North
srel!(24.0, 8.0, 8.0, 8.0), // South
srel!(16.0, 8.0, 8.0, 8.0), // West
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
]);
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,
[
srel!(16.0, 0.0, 8.0, 8.0), // Down
srel!(8.0, 0.0, 8.0, 8.0), // Up
srel!(8.0, 8.0, 8.0, 8.0), // North
srel!(24.0, 8.0, 8.0, 8.0), // South
srel!(16.0, 8.0, 8.0, 8.0), // West
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
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, [
srel!(28.0, 16.0, 8.0, 4.0), // Down
srel!(20.0, 16.0, 8.0, 4.0), // Up
srel!(20.0, 20.0, 8.0, 12.0), // North
srel!(32.0, 20.0, 8.0, 12.0), // South
srel!(16.0, 20.0, 4.0, 12.0), // West
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
]);
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,
[
srel!(28.0, 16.0, 8.0, 4.0), // Down
srel!(20.0, 16.0, 8.0, 4.0), // Up
srel!(20.0, 20.0, 8.0, 12.0), // North
srel!(32.0, 20.0, 8.0, 12.0), // South
srel!(16.0, 20.0, 4.0, 12.0), // West
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];
for (i, offsets) in [
[16.0, 48.0, 0.0, 48.0], // Left left
[0.0, 16.0, 0.0, 32.0], // Right Leg
[16.0, 48.0, 0.0, 48.0], // Left left
[0.0, 16.0, 0.0, 32.0], // Right Leg
[32.0, 48.0, 48.0, 48.0], // Left arm
[40.0, 16.0, 40.0, 32.0], // Right arm
].iter().enumerate() {
]
.iter()
.enumerate()
{
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, [
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
]);
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,
[
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]);
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, [
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
]);
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,
[
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![];
@ -423,17 +509,27 @@ impl ecs::System for PlayerRenderer {
part_verts[1].clone(),
part_verts[2].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();
if let Some(model) = player_model.model.take() {
renderer.model.remove_model(model);
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 {
pub fn new() -> PlayerMovement { Default::default() }
pub fn new() -> PlayerMovement {
Default::default()
}
fn calculate_movement(&self, player_yaw: f64) -> (f64, f64) {
use std::f64::consts::PI;
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) {
forward = 1.0;
if self.is_key_pressed(Stevenkey::Backward) {
@ -466,7 +564,9 @@ impl PlayerMovement {
(PI / 2.0) / (forward.abs() + 1.0)
} else if self.is_key_pressed(Stevenkey::Right) {
-(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) {
forward = 1.0;
}
@ -521,7 +621,6 @@ impl MovementHandler {
}
impl ecs::System for MovementHandler {
fn filter(&self) -> &ecs::Filter {
&self.filter
}
@ -542,8 +641,11 @@ impl ecs::System for MovementHandler {
if movement.when_last_jump_pressed.is_none() {
movement.when_last_jump_pressed = Some(Instant::now());
if !movement.when_last_jump_released.is_none() {
let dt = movement.when_last_jump_pressed.unwrap() - movement.when_last_jump_released.unwrap();
if dt.as_secs() == 0 && dt.subsec_millis() <= crate::settings::DOUBLE_JUMP_MS {
let dt = movement.when_last_jump_pressed.unwrap()
- 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;
//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;
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 mut speed = if movement.is_key_pressed(Stevenkey::Sprint) {
0.2806
} else { 0.21585 };
} else {
0.21585
};
if movement.flying {
speed *= 2.5;
@ -582,7 +689,8 @@ impl ecs::System for MovementHandler {
position.position.y -= speed;
}
} 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;
}
} else {
@ -604,12 +712,14 @@ impl ecs::System for MovementHandler {
// We handle each axis separately to allow for a sliding
// 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;
last_position.x = position.position.x;
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;
last_position.z = position.position.z;
@ -624,8 +734,12 @@ impl ecs::System for MovementHandler {
let mut oz = position.position.z;
position.position.x = target.x;
position.position.z = target.z;
for offset in 1 .. 9 {
let mini = player_bounds.add_v(cgmath::Vector3::new(0.0, offset as f64 / 16.0, 0.0));
for offset in 1..9 {
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);
if !hit {
target.y += offset as f64 / 16.0;
@ -639,7 +753,8 @@ impl ecs::System for MovementHandler {
}
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;
last_position.y = position.position.y;
if yhit {
@ -647,10 +762,8 @@ impl ecs::System for MovementHandler {
}
if let Some(gravity) = gravity {
let ground = Aabb3::new(
Point3::new(-0.3, -0.005, -0.3),
Point3::new(0.3, 0.0, 0.3)
);
let ground =
Aabb3::new(Point3::new(-0.3, -0.005, -0.3), Point3::new(0.3, 0.0, 0.3));
let prev = gravity.on_ground;
let (_, hit) = check_collisions(world, position, &last_position, ground);
gravity.on_ground = hit;
@ -664,8 +777,12 @@ impl ecs::System for MovementHandler {
}
}
fn check_collisions(world: &world::World, position: &mut TargetPosition, last_position: &Vector3<f64>, bounds: Aabb3<f64>) -> (Aabb3<f64>, bool) {
fn check_collisions(
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 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 mut hit = false;
for y in min_y .. max_y {
for z in min_z .. max_z {
for x in min_x .. max_x {
for y in min_y..max_y {
for z in min_z..max_z {
for x in min_x..max_x {
let block = world.get_block(BPosition::new(x, y, z));
if block.get_material().collidable {
for bb in block.get_collision_boxes() {
@ -705,14 +822,12 @@ trait Collidable<T> {
impl Collidable<Aabb3<f64>> for Aabb3<f64> {
fn collides(&self, t: &Aabb3<f64>) -> bool {
!(
t.min.x >= self.max.x ||
t.max.x <= self.min.x ||
t.min.y >= self.max.y ||
t.max.y <= self.min.y ||
t.min.z >= self.max.z ||
t.max.z <= self.min.z
)
!(t.min.x >= self.max.x
|| t.max.x <= self.min.x
|| t.min.y >= self.max.y
|| t.max.y <= self.min.y
|| t.min.z >= self.max.z
|| t.max.z <= self.min.z)
}
fn move_out_of(mut self, other: Self, dir: cgmath::Vector3<f64>) -> Self {

View File

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

View File

@ -14,15 +14,15 @@
extern crate steven_gl as gl;
use std::ops::BitOr;
use log::{error, info};
use std::ffi;
use std::mem;
use std::ptr;
use std::ops::BitOr;
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.
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 _);
}
@ -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]) {
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) {
unsafe { gl::DepthMask(f as u8); }
unsafe {
gl::DepthMask(f as u8);
}
}
/// `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 {
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,
target: TextureTarget,
level: i32,
format: TextureFormat,
ty: Type,
pixels: &mut [u8]) {
pub fn get_pixels(
&self,
target: TextureTarget,
level: i32,
format: TextureFormat,
ty: Type,
pixels: &mut [u8],
) {
unsafe {
gl::GetTexImage(target,
level,
format,
ty,
pixels.as_mut_ptr() as *mut gl::types::GLvoid);
gl::GetTexImage(
target,
level,
format,
ty,
pixels.as_mut_ptr() as *mut gl::types::GLvoid,
);
}
}
pub fn image_2d(&self,
target: TextureTarget,
level: i32,
width: u32,
height: u32,
format: TextureFormat,
ty: Type,
pix: Option<&[u8]>) {
pub fn image_2d(
&self,
target: TextureTarget,
level: i32,
width: u32,
height: u32,
format: TextureFormat,
ty: Type,
pix: Option<&[u8]>,
) {
unsafe {
let ptr = match pix {
Some(val) => val.as_ptr() as *const gl::types::GLvoid,
None => ptr::null(),
};
gl::TexImage2D(target,
level,
format as i32,
width as i32,
height as i32,
0,
format,
ty,
ptr
gl::TexImage2D(
target,
level,
format as i32,
width as i32,
height as i32,
0,
format,
ty,
ptr,
);
}
}
pub fn sub_image_2d(&self,
target: TextureTarget,
level: i32,
x: u32,
y: u32,
width: u32,
height: u32,
format: TextureFormat,
ty: Type,
pix: &[u8]) {
pub fn sub_image_2d(
&self,
target: TextureTarget,
level: i32,
x: u32,
y: u32,
width: u32,
height: u32,
format: TextureFormat,
ty: Type,
pix: &[u8],
) {
unsafe {
gl::TexSubImage2D(target,
level,
x as i32,
y as i32,
width as i32,
height as i32,
format,
ty,
pix.as_ptr() as *const _
gl::TexSubImage2D(
target,
level,
x as i32,
y as i32,
width as i32,
height as i32,
format,
ty,
pix.as_ptr() as *const _,
);
}
}
pub fn image_2d_ex(&self,
target: TextureTarget,
level: i32,
width: u32,
height: u32,
internal_format: TextureFormat,
format: TextureFormat,
ty: Type,
pix: Option<&[u8]>) {
pub fn image_2d_ex(
&self,
target: TextureTarget,
level: i32,
width: u32,
height: u32,
internal_format: TextureFormat,
format: TextureFormat,
ty: Type,
pix: Option<&[u8]>,
) {
unsafe {
let ptr = match pix {
Some(val) => val.as_ptr() as *const gl::types::GLvoid,
None => ptr::null(),
};
gl::TexImage2D(target,
level,
internal_format as i32,
width as i32,
height as i32,
0,
format,
ty,
ptr
gl::TexImage2D(
target,
level,
internal_format as i32,
width as i32,
height as i32,
0,
format,
ty,
ptr,
);
}
}
pub fn image_2d_sample(&self,
target: TextureTarget,
samples: i32,
width: u32,
height: u32,
format: TextureFormat,
fixed: bool) {
pub fn image_2d_sample(
&self,
target: TextureTarget,
samples: i32,
width: u32,
height: u32,
format: TextureFormat,
fixed: bool,
) {
unsafe {
let result: &mut [i32] = &mut [0; 1];
gl::GetIntegerv(gl::MAX_SAMPLES, &mut result[0]);
let use_samples =
if samples > result[0] {
info!("glTexImage2DMultisample: requested {} samples but GL_MAX_SAMPLES is {}", samples, result[0]);
result[0]
} else {
samples
};
let use_samples = if samples > result[0] {
info!(
"glTexImage2DMultisample: requested {} samples but GL_MAX_SAMPLES is {}",
samples, result[0]
);
result[0]
} else {
samples
};
gl::TexImage2DMultisample(target,
use_samples,
format,
width as i32,
height as i32,
fixed as u8
gl::TexImage2DMultisample(
target,
use_samples,
format,
width as i32,
height as i32,
fixed as u8,
);
}
}
pub fn image_3d(&self,
target: TextureTarget,
level: i32,
width: u32,
height: u32,
depth: u32,
format: TextureFormat,
ty: Type,
pix: &[u8]) {
pub fn image_3d(
&self,
target: TextureTarget,
level: i32,
width: u32,
height: u32,
depth: u32,
format: TextureFormat,
ty: Type,
pix: &[u8],
) {
unsafe {
gl::TexImage3D(target,
level,
format as i32,
width as i32,
height as i32,
depth as i32,
0,
format,
ty,
pix.as_ptr() as *const gl::types::GLvoid);
gl::TexImage3D(
target,
level,
format as i32,
width as i32,
height as i32,
depth as i32,
0,
format,
ty,
pix.as_ptr() as *const gl::types::GLvoid,
);
}
}
pub fn sub_image_3d(&self,
target: TextureTarget,
level: i32,
x: u32,
y: u32,
z: u32,
width: u32,
height: u32,
depth: u32,
format: TextureFormat,
ty: Type,
pix: &[u8]) {
pub fn sub_image_3d(
&self,
target: TextureTarget,
level: i32,
x: u32,
y: u32,
z: u32,
width: u32,
height: u32,
depth: u32,
format: TextureFormat,
ty: Type,
pix: &[u8],
) {
unsafe {
gl::TexSubImage3D(target,
level,
x as i32,
y as i32,
z as i32,
width as i32,
height as i32,
depth as i32,
format,
ty,
pix.as_ptr() as *const gl::types::GLvoid);
gl::TexSubImage3D(
target,
level,
x as i32,
y as i32,
z as i32,
width as i32,
height as i32,
depth as i32,
format,
ty,
pix.as_ptr() as *const gl::types::GLvoid,
);
}
}
pub fn set_parameter(&self,
target: TextureTarget,
param: TextureParameter,
value: TextureValue) {
pub fn set_parameter(
&self,
target: TextureTarget,
param: TextureParameter,
value: TextureValue,
) {
unsafe {
gl::TexParameteri(target, param, value);
}
@ -495,9 +536,8 @@ impl Program {
}
pub fn uniform_location(&self, name: &str) -> Option<Uniform> {
let u = unsafe {
gl::GetUniformLocation(self.0, ffi::CString::new(name).unwrap().as_ptr())
};
let u =
unsafe { gl::GetUniformLocation(self.0, ffi::CString::new(name).unwrap().as_ptr()) };
if u != -1 {
Some(Uniform(u))
} else {
@ -536,10 +576,7 @@ impl Shader {
pub fn set_source(&self, src: &str) {
unsafe {
let src_c = ffi::CString::new(src).unwrap();
gl::ShaderSource(self.0,
1,
&src_c.as_ptr(),
ptr::null());
gl::ShaderSource(self.0, 1, &src_c.as_ptr(), ptr::null());
}
}
@ -624,7 +661,8 @@ impl Uniform {
pub fn set_matrix4_multi(&self, m: &[::cgmath::Matrix4<f32>]) {
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) {
unsafe {
gl::VertexAttribPointer(self.0 as u32,
size,
ty,
normalized as u8,
stride,
offset as *const gl::types::GLvoid);
gl::VertexAttribPointer(
self.0 as u32,
size,
ty,
normalized as u8,
stride,
offset as *const gl::types::GLvoid,
);
}
}
pub fn vertex_pointer_int(&self, size: i32, ty: Type, stride: i32, offset: i32) {
unsafe {
gl::VertexAttribIPointer(self.0 as u32,
size,
ty,
stride,
offset as *const gl::types::GLvoid);
gl::VertexAttribIPointer(
self.0 as u32,
size,
ty,
stride,
offset as *const gl::types::GLvoid,
);
}
}
}
@ -753,10 +795,12 @@ impl Buffer {
pub fn set_data(&self, target: BufferTarget, data: &[u8], usage: BufferUsage) {
unsafe {
gl::BufferData(target,
data.len() as isize,
data.as_ptr() as *const gl::types::GLvoid,
usage);
gl::BufferData(
target,
data.len() as isize,
data.as_ptr() as *const gl::types::GLvoid,
usage,
);
}
}
@ -832,11 +876,12 @@ pub struct Framebuffer(u32);
pub fn check_framebuffer_status() {
unsafe {
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
let s =
match status {
let s = match status {
gl::FRAMEBUFFER_UNDEFINED => "GL_FRAMEBUFFER_UNDEFINED",
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_READ_BUFFER => "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER",
gl::FRAMEBUFFER_UNSUPPORTED => "GL_FRAMEBUFFER_UNSUPPORTED",
@ -845,11 +890,14 @@ pub fn check_framebuffer_status() {
gl::FRAMEBUFFER_COMPLETE => "GL_FRAMEBUFFER_COMPLETE",
//gl::FRAMEBUFFER_INCOMPLETE_DIMENSIONS => "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS",
_ => "unknown"
_ => "unknown",
};
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 {
let err = gl::GetError();
if err == gl::NO_ERROR {
break
break;
}
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 {
gl::FramebufferTexture2D(gl::FRAMEBUFFER, attachment, target, tex.0, level);
}
@ -929,10 +983,7 @@ pub fn unbind_framebuffer_draw() {
pub fn draw_buffers(bufs: &[Attachment]) {
unsafe {
gl::DrawBuffers(
bufs.len() as i32,
bufs.as_ptr()
);
gl::DrawBuffers(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(
sx0: i32, sy0: i32, sx1: i32, sy1: i32,
dx0: i32, dy0: i32, dx1: i32, dy1: i32,
mask: ClearFlags, filter: TextureValue) {
sx0: i32,
sy0: i32,
sx1: i32,
sy1: i32,
dx0: i32,
dy0: i32,
dx1: i32,
dy1: i32,
mask: ClearFlags,
filter: TextureValue,
) {
unsafe {
gl::BlitFramebuffer(
sx0, sy0, sx1, sy1,
dx0, dy0, dx1, dy1,
mask.internal(), filter as u32
sx0,
sy0,
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
// limitations under the License.
#![recursion_limit="300"]
#![recursion_limit = "300"]
use std::time::{Instant, Duration};
use log::{info, warn, error};
use log::{error, info, warn};
use std::time::{Duration, Instant};
extern crate steven_shared as shared;
use structopt::StructOpt;
@ -23,32 +23,32 @@ use structopt::StructOpt;
extern crate steven_protocol;
pub mod ecs;
use steven_protocol::protocol as protocol;
use steven_protocol::format as format;
use steven_protocol::nbt as nbt;
use steven_protocol::format;
use steven_protocol::nbt;
use steven_protocol::protocol;
pub mod gl;
use steven_protocol::types as 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;
use steven_protocol::types;
pub mod auth;
pub mod model;
pub mod chunk_builder;
pub mod console;
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 cfg_if::cfg_if;
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 {
ty: PhantomData,
@ -87,16 +87,24 @@ pub struct Game {
impl Game {
pub fn connect_to(&mut self, address: &str) {
let (protocol_version, forge_mods) = match protocol::Conn::new(&address, self.default_protocol_version)
.and_then(|conn| conn.do_status()) {
let (protocol_version, forge_mods) =
match protocol::Conn::new(&address, self.default_protocol_version)
.and_then(|conn| conn.do_status())
{
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)
},
}
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![])
},
}
};
let (tx, rx) = mpsc::channel();
@ -109,7 +117,14 @@ impl Game {
access_token: self.vars.get(auth::AUTH_TOKEN).clone(),
};
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() {
self.screen_sys.replace_screen(Box::new(screen::ServerList::new(
Some(disconnect_reason)
)));
self.screen_sys
.replace_screen(Box::new(screen::ServerList::new(Some(disconnect_reason))));
}
if !self.server.is_connected() {
self.focused = false;
@ -140,7 +154,7 @@ impl Game {
self.focused = true;
self.server.remove(&mut self.renderer);
self.server = val;
},
}
Err(err) => {
let msg = match err {
protocol::Error::Disconnect(val) => val,
@ -148,11 +162,10 @@ impl Game {
let mut msg = format::TextComponent::new(&format!("{}", err));
msg.modifier.color = Some(format::Color::Red);
format::Component::Text(msg)
},
}
};
self.screen_sys.replace_screen(Box::new(screen::ServerList::new(
Some(msg)
)));
self.screen_sys
.replace_screen(Box::new(screen::ServerList::new(Some(msg))));
}
}
}
@ -240,14 +253,19 @@ fn main2() {
let window = glutin::ContextBuilder::new()
.with_stencil_buffer(0)
.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_vsync(vsync)
.build_windowed(window_builder, &events_loop)
.expect("Could not create glutin window.");
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);
@ -271,14 +289,15 @@ fn main2() {
}
}
if let Some(username) = opt.username{
if let Some(username) = opt.username {
vars.set(auth::CL_USERNAME, username);
}
let textures = renderer.get_textures();
let dpi_factor = window.window().scale_factor();
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 {
server: server::Server::dummy_server(resource_manager.clone()),
focused: false,
@ -359,15 +378,24 @@ fn main2() {
game.renderer.update_camera(physical_width, physical_height);
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
.lock()
.unwrap()
.tick(&mut ui_container, &game.renderer, delta, width 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 {
let frame_time = now.elapsed();
@ -384,32 +412,38 @@ fn main2() {
});
}
fn handle_window_event<T>(window: &mut glutin::WindowedContext<glutin::PossiblyCurrent>,
game: &mut Game,
ui_container: &mut ui::Container,
event: glutin::event::Event<T>) -> bool {
fn handle_window_event<T>(
window: &mut glutin::WindowedContext<glutin::PossiblyCurrent>,
game: &mut Game,
ui_container: &mut ui::Container,
event: glutin::event::Event<T>,
) -> bool {
use glutin::event::*;
match event {
Event::MainEventsCleared => return true,
Event::DeviceEvent{event, ..} => match event {
Event::DeviceEvent { event, .. } => match event {
DeviceEvent::ModifiersChanged(modifiers_state) => {
game.is_ctrl_pressed = modifiers_state.ctrl();
game.is_logo_pressed = modifiers_state.logo();
},
}
DeviceEvent::MouseMotion{delta:(xrel, yrel)} => {
let (rx, ry) =
if xrel > 1000.0 || yrel > 1000.0 {
// Heuristic for if we were passed an absolute value instead of relative
// Workaround https://github.com/tomaka/glutin/issues/1084 MouseMotion event returns absolute instead of relative values, when running Linux in a VM
// Note SDL2 had a hint to handle this scenario:
// sdl2::hint::set_with_priority("SDL_MOUSE_RELATIVE_MODE_WARP", "1", &sdl2::hint::Hint::Override);
let s = 8000.0 + 0.01;
((xrel - game.last_mouse_xrel) / s, (yrel - game.last_mouse_yrel) / s)
} else {
let s = 2000.0 + 0.01;
(xrel / s, yrel / s)
};
DeviceEvent::MouseMotion {
delta: (xrel, yrel),
} => {
let (rx, ry) = if xrel > 1000.0 || yrel > 1000.0 {
// Heuristic for if we were passed an absolute value instead of relative
// Workaround https://github.com/tomaka/glutin/issues/1084 MouseMotion event returns absolute instead of relative values, when running Linux in a VM
// Note SDL2 had a hint to handle this scenario:
// sdl2::hint::set_with_priority("SDL_MOUSE_RELATIVE_MODE_WARP", "1", &sdl2::hint::Hint::Override);
let s = 8000.0 + 0.01;
(
(xrel - game.last_mouse_xrel) / 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_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_visible(false);
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.pitch -= ry;
if rotation.pitch < (PI/2.0) + 0.01 {
rotation.pitch = (PI/2.0) + 0.01;
if rotation.pitch < (PI / 2.0) + 0.01 {
rotation.pitch = (PI / 2.0) + 0.01;
}
if rotation.pitch > (PI/2.0)*3.0 - 0.01 {
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;
}
}
} else {
window.window().set_cursor_grab(false).unwrap();
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, ..} => {
match (state, button) {
WindowEvent::ReceivedCharacter(codepoint) => {
if !game.focused {
ui_container.key_type(game, codepoint);
}
}
WindowEvent::MouseInput { state, button, .. } => match (state, button) {
(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;
window.window().set_cursor_grab(true).unwrap();
window.window().set_cursor_visible(false);
@ -467,94 +512,114 @@ fn handle_window_event<T>(window: &mut glutin::WindowedContext<glutin::PossiblyC
if !game.focused {
window.window().set_cursor_grab(false).unwrap();
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) => {
if game.focused {
game.server.on_right_click(&mut game.renderer);
}
},
(_, _) => ()
}
},
WindowEvent::CursorMoved{position, ..} => {
let (x, y) = position.into();
game.last_mouse_x = x;
game.last_mouse_y = y;
}
(_, _) => (),
},
WindowEvent::CursorMoved { position, .. } => {
let (x, y) = position.into();
game.last_mouse_x = x;
game.last_mouse_y = y;
if !game.focused {
let (width, height) = window.window().inner_size().to_logical::<f64>(game.dpi_factor).into();
ui_container.hover_at(game, x, y, width, height);
if !game.focused {
let (width, height) = window
.window()
.inner_size()
.to_logical::<f64>(game.dpi_factor)
.into();
ui_container.hover_at(game, x, y, width, height);
}
}
},
WindowEvent::MouseWheel{delta, ..} => {
// TODO: line vs pixel delta? does pixel scrolling (e.g. touchpad) need scaling?
match delta {
MouseScrollDelta::LineDelta(x, y) => {
game.screen_sys.on_scroll(x.into(), y.into());
},
MouseScrollDelta::PixelDelta(position) => {
let (x, y) = position.into();
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();
WindowEvent::MouseWheel { delta, .. } => {
// TODO: line vs pixel delta? does pixel scrolling (e.g. touchpad) need scaling?
match delta {
MouseScrollDelta::LineDelta(x, y) => {
game.screen_sys.on_scroll(x.into(), y.into());
}
MouseScrollDelta::PixelDelta(position) => {
let (x, y) = position.into();
game.screen_sys.on_scroll(x, y);
}
}
(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::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 {
get_lava_level
} else {
@ -20,17 +27,25 @@ pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lav
} else {
(
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, y, z+1),
average_liquid_level(get_liquid, snapshot, x+1, y, z+1)
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 + 1, y, z + 1),
)
};
let tex = match snapshot.get_block(x, y, z) {
block::Block::Water{..} => render::Renderer::get_texture(&textures, "minecraft:blocks/water_still"),
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"),
block::Block::Water { .. } => {
render::Renderer::get_texture(&textures, "minecraft:blocks/water_still")
}
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!(),
};
let ux1 = 0i16;
@ -41,8 +56,11 @@ pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lav
for dir in Direction::all() {
let (ox, oy, oz) = dir.get_offset();
let special = dir == Direction::Up && (tl < 8 || tr < 8 || bl < 8 || br < 8);
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()) {
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())
{
let verts = BlockVertex::face_by_direction(dir);
for vert in verts {
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,
(_, _) => ((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;
@ -72,13 +90,15 @@ pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lav
let (bl, sl) = super::calculate_light(
snapshot,
x, y, z,
x,
y,
z,
vert.x as f64,
vert.y as f64,
vert.z as f64,
dir,
!lava,
false
false,
);
vert.block_light = bl;
vert.sky_light = sl;
@ -106,15 +126,18 @@ pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lav
fn average_liquid_level(
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 {
let mut level = 0;
for xx in -1 .. 1 {
for zz in -1 .. 1 {
if get(snapshot, x+xx, y+1, z+zz).is_some() {
for xx in -1..1 {
for zz in -1..1 {
if get(snapshot, x + xx, y + 1, z + zz).is_some() {
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);
if nl > level {
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> {
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,
}
}
fn get_lava_level(snapshot: &world::Snapshot, x: i32, y: i32, z: i32) -> Option<i32> {
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,
}
}

View File

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

View File

@ -26,7 +26,9 @@ pub struct Rect {
impl 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 {
x: 0,
y: 0,
@ -78,13 +80,15 @@ impl Atlas {
} else {
if t.height > height {
// Split by height
self.free_space.insert(0,
Rect {
x: t.x,
y: t.y + height,
width,
height: t.height - height,
});
self.free_space.insert(
0,
Rect {
x: t.x,
y: t.y + height,
width,
height: t.height - height,
},
);
target_index += 1;
}
t.x += width;

View File

@ -1,10 +1,9 @@
use std::sync::{Arc, RwLock};
use cgmath::{Point3, Matrix4};
use byteorder::{WriteBytesExt, NativeEndian};
use crate::gl;
use super::glsl;
use crate::gl;
use byteorder::{NativeEndian, WriteBytesExt};
use cgmath::{Matrix4, Point3};
use log::error;
pub struct Clouds {
@ -115,8 +114,8 @@ impl Clouds {
let mut data = vec![];
let mut num_points = 0;
for x in -160 .. 160 {
for z in -160 .. 160 {
for x in -160..160 {
for z in -160..160 {
let _ = data.write_f32::<NativeEndian>(x as f32);
let _ = data.write_f32::<NativeEndian>(128.0);
let _ = data.write_f32::<NativeEndian>(z as f32);
@ -126,11 +125,19 @@ impl Clouds {
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();
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_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;
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_sky_offset.set_float(sky_offset);
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(
tex.get_x() as f32,
tex.get_y() 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_cloud_offset.set_float((self.offset / 60.0) as f32);
@ -187,7 +206,17 @@ impl Clouds {
gl::active_texture(1);
self.texture.bind(gl::TEXTURE_2D);
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.u_cloud_map.set_int(1);

View File

@ -20,13 +20,16 @@ pub struct Registry {
}
impl Registry {
pub fn new() -> Registry { Default::default() }
pub fn new() -> Registry {
Default::default()
}
pub fn register(&mut self, name: &str, source: &str) {
if self.shaders.contains_key(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 {

View File

@ -16,29 +16,29 @@ mod atlas;
pub mod glsl;
#[macro_use]
pub mod shaders;
pub mod ui;
pub mod model;
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::resources;
use crate::world;
use byteorder::{NativeEndian, WriteBytesExt};
use cgmath::prelude::*;
use collision;
use image;
use image::{GenericImage, GenericImageView};
use byteorder::{WriteBytesExt, NativeEndian};
use serde_json;
use cgmath::prelude::*;
use crate::world;
use collision;
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 std::hash::BuildHasherDefault;
use std::sync::atomic::{AtomicIsize, Ordering};
use std::thread;
use std::sync::mpsc;
use std::thread;
#[cfg(not(target_arch = "wasm32"))]
use reqwest;
@ -100,7 +100,9 @@ pub struct ChunkBuffer {
}
impl ChunkBuffer {
pub fn new() -> ChunkBuffer { Default::default() }
pub fn new() -> ChunkBuffer {
Default::default()
}
}
struct ChunkRenderInfo {
@ -156,19 +158,19 @@ init_shader! {
impl Renderer {
pub fn new(res: Arc<RwLock<resources::Manager>>) -> Renderer {
let version = {
res.read().unwrap().version()
};
let version = { res.read().unwrap().version() };
let tex = gl::Texture::new();
tex.bind(gl::TEXTURE_2D_ARRAY);
tex.image_3d(gl::TEXTURE_2D_ARRAY,
0,
ATLAS_SIZE as u32,
ATLAS_SIZE as u32,
1,
gl::RGBA,
gl::UNSIGNED_BYTE,
&[0; ATLAS_SIZE * ATLAS_SIZE * 4]);
tex.image_3d(
gl::TEXTURE_2D_ARRAY,
0,
ATLAS_SIZE as u32,
ATLAS_SIZE as u32,
1,
gl::RGBA,
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_MIN_FILTER, gl::NEAREST);
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 {
self.resource_version = rm.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 aspect = (width as f32 / height as f32).max(1.0);
self.perspective_matrix = cgmath::Matrix4::from(
cgmath::PerspectiveFov {
fovy,
aspect,
near: 0.1f32,
far: 500.0f32,
}
);
self.perspective_matrix = cgmath::Matrix4::from(cgmath::PerspectiveFov {
fovy,
aspect,
near: 0.1f32,
far: 500.0f32,
});
self.init_trans(width, height);
}
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.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(
camera,
camera + 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)
camera
+ 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.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);
let trans = self.trans.as_mut().unwrap();
@ -302,18 +321,22 @@ impl Renderer {
let time_offset = self.sky_offset * 0.9;
gl::clear_color(
(122.0 / 255.0) * time_offset,
(165.0 / 255.0) * time_offset,
(247.0 / 255.0) * time_offset,
1.0
(122.0 / 255.0) * time_offset,
(165.0 / 255.0) * time_offset,
(247.0 / 255.0) * time_offset,
1.0,
);
gl::clear(gl::ClearFlags::Color | gl::ClearFlags::Depth);
// Chunk rendering
self.chunk_shader.program.use_program();
self.chunk_shader.perspective_matrix.set_matrix4(&self.perspective_matrix);
self.chunk_shader.camera_matrix.set_matrix4(&self.camera_matrix);
self.chunk_shader
.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.light_level.set_float(self.light_level);
self.chunk_shader.sky_offset.set_float(self.sky_offset);
@ -321,36 +344,71 @@ impl Renderer {
for (pos, info) in world.get_render_list() {
if let Some(solid) = info.solid.as_ref() {
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();
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
// 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) {
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
self.chunk_shader_alpha.program.use_program();
self.chunk_shader_alpha.perspective_matrix.set_matrix4(&self.perspective_matrix);
self.chunk_shader_alpha.camera_matrix.set_matrix4(&self.camera_matrix);
self.chunk_shader_alpha
.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.light_level.set_float(self.light_level);
self.chunk_shader_alpha.sky_offset.set_float(self.sky_offset);
self.chunk_shader_alpha
.light_level
.set_float(self.light_level);
self.chunk_shader_alpha
.sky_offset
.set_float(self.sky_offset);
// Copy the depth buffer
trans.main.bind_read();
trans.trans.bind_draw();
gl::blit_framebuffer(
0, 0, physical_width as i32, physical_height as i32,
0, 0, physical_width as i32, physical_height as i32,
gl::ClearFlags::Depth, gl::NEAREST
0,
0,
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);
@ -360,14 +418,26 @@ impl Renderer {
gl::clear(gl::ClearFlags::Color);
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::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() {
if let Some(trans) = info.trans.as_ref() {
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();
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);
self.element_buffer_type = ty;
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;
}
}
@ -432,16 +503,27 @@ impl Renderer {
info.buffer.bind(gl::ARRAY_BUFFER);
if new || 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 {
info.buffer.re_set_data(gl::ARRAY_BUFFER, data);
}
self.chunk_shader.position.vertex_pointer(3, gl::FLOAT, false, 40, 0);
self.chunk_shader.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);
self.chunk_shader
.position
.vertex_pointer(3, gl::FLOAT, false, 40, 0);
self.chunk_shader
.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;
}
@ -477,16 +559,27 @@ impl Renderer {
info.buffer.bind(gl::ARRAY_BUFFER);
if new || 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 {
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.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);
self.chunk_shader_alpha
.position
.vertex_pointer(3, gl::FLOAT, false, 40, 0);
self.chunk_shader_alpha
.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;
}
@ -501,19 +594,23 @@ impl Renderer {
unsafe {
data.set_len(len);
}
self.gl_texture.get_pixels(gl::TEXTURE_2D_ARRAY,
0,
gl::RGBA,
gl::UNSIGNED_BYTE,
&mut data[..]);
self.gl_texture.image_3d(gl::TEXTURE_2D_ARRAY,
0,
ATLAS_SIZE as u32,
ATLAS_SIZE as u32,
tex.atlases.len() as u32,
gl::RGBA,
gl::UNSIGNED_BYTE,
&data[..]);
self.gl_texture.get_pixels(
gl::TEXTURE_2D_ARRAY,
0,
gl::RGBA,
gl::UNSIGNED_BYTE,
&mut data[..],
);
self.gl_texture.image_3d(
gl::TEXTURE_2D_ARRAY,
0,
ATLAS_SIZE as u32,
ATLAS_SIZE as u32,
tex.atlases.len() as u32,
gl::RGBA,
gl::UNSIGNED_BYTE,
&data[..],
);
self.texture_layers = tex.atlases.len();
}
tex.pending_uploads.len()
@ -525,17 +622,19 @@ impl Renderer {
let atlas = upload.0;
let rect = upload.1;
let img = &upload.2;
self.gl_texture.sub_image_3d(gl::TEXTURE_2D_ARRAY,
0,
rect.x as u32,
rect.y as u32,
atlas as u32,
rect.width as u32,
rect.height as u32,
1,
gl::RGBA,
gl::UNSIGNED_BYTE,
&img[..]);
self.gl_texture.sub_image_3d(
gl::TEXTURE_2D_ARRAY,
0,
rect.x as u32,
rect.y as u32,
atlas as u32,
rect.width as u32,
rect.height as u32,
1,
gl::RGBA,
gl::UNSIGNED_BYTE,
&img[..],
);
}
tex.pending_uploads.clear();
}
@ -567,30 +666,36 @@ impl Renderer {
if ani.remaining_time <= 0.0 {
ani.current_frame = (ani.current_frame + 1) % ani.frames.len();
ani.remaining_time += ani.frames[ani.current_frame].time as f64;
let offset = ani.texture.width * ani.texture.width *
ani.frames[ani.current_frame].index * 4;
let offset =
ani.texture.width * ani.texture.width * ani.frames[ani.current_frame].index * 4;
let offset2 = offset + ani.texture.width * ani.texture.width * 4;
self.gl_texture.sub_image_3d(gl::TEXTURE_2D_ARRAY,
0,
ani.texture.get_x() as u32,
ani.texture.get_y() as u32,
ani.texture.atlas as u32,
ani.texture.get_width() as u32,
ani.texture.get_height() as u32,
1,
gl::RGBA,
gl::UNSIGNED_BYTE,
&ani.data[offset..offset2]);
self.gl_texture.sub_image_3d(
gl::TEXTURE_2D_ARRAY,
0,
ani.texture.get_x() as u32,
ani.texture.get_y() as u32,
ani.texture.atlas as u32,
ani.texture.get_width() as u32,
ani.texture.get_height() as u32,
1,
gl::RGBA,
gl::UNSIGNED_BYTE,
&ani.data[offset..offset2],
);
} else {
ani.remaining_time -= delta / 3.0;
}
}
}
fn init_trans(&mut self, width: u32, height: u32) {
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>> {
@ -616,9 +721,7 @@ impl Renderer {
}
pub fn get_texture(textures: &RwLock<TextureManager>, name: &str) -> Texture {
let tex = {
textures.read().unwrap().get_texture(name)
};
let tex = { textures.read().unwrap().get_texture(name) };
match tex {
Some(val) => val,
None => {
@ -636,9 +739,7 @@ impl Renderer {
}
pub fn get_skin(&self, textures: &RwLock<TextureManager>, url: &str) -> Texture {
let tex = {
textures.read().unwrap().get_skin(url)
};
let tex = { textures.read().unwrap().get_skin(url) };
match tex {
Some(val) => val,
None => {
@ -686,27 +787,59 @@ init_shader! {
}
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();
trans.bind();
let accum = gl::Texture::new();
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_MAX_LEVEL, gl::LINEAR);
trans.texture_2d(gl::COLOR_ATTACHMENT_0, gl::TEXTURE_2D, &accum, 0);
let revealage = gl::Texture::new();
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_MAX_LEVEL, gl::LINEAR);
trans.texture_2d(gl::COLOR_ATTACHMENT_1, gl::TEXTURE_2D, &revealage, 0);
let trans_depth = gl::Texture::new();
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_MAX_LEVEL, gl::LINEAR);
trans.texture_2d(gl::DEPTH_ATTACHMENT, gl::TEXTURE_2D, &trans_depth, 0);
@ -722,13 +855,37 @@ impl TransInfo {
let fb_color = gl::Texture::new();
fb_color.bind(gl::TEXTURE_2D_MULTISAMPLE);
fb_color.image_2d_sample(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);
fb_color.image_2d_sample(
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();
fb_depth.bind(gl::TEXTURE_2D_MULTISAMPLE);
fb_depth.image_2d_sample(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);
fb_depth.image_2d_sample(
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::unbind_framebuffer();
@ -740,7 +897,11 @@ impl TransInfo {
buffer.bind(gl::ARRAY_BUFFER);
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();
}
buffer.set_data(gl::ARRAY_BUFFER, &data, gl::STATIC_DRAW);
@ -798,7 +959,13 @@ pub struct 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 (stx, srx) = mpsc::channel();
let skin_thread = thread::spawn(|| Self::process_skins(srx, tx));
@ -824,31 +991,30 @@ impl TextureManager {
}
fn add_defaults(&mut self) {
self.put_texture("steven",
"missing_texture",
2,
2,
vec![
0, 0, 0, 255,
255, 0, 255, 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",
"missing_texture",
2,
2,
vec![
0, 0, 0, 255, 255, 0, 255, 255, 255, 0, 255, 255, 0, 0, 0, 255,
],
);
self.put_texture("steven", "solid", 1, 1, vec![255, 255, 255, 255]);
}
#[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"))]
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();
loop {
let hash = match recv.recv() {
@ -858,21 +1024,24 @@ impl TextureManager {
match Self::obtain_skin(&client, &hash) {
Ok(img) => {
let _ = reply.send((hash, Some(img)));
},
}
Err(err) => {
error!("Failed to get skin {:?}: {}", hash, err);
let _ = reply.send((hash, None));
},
}
}
}
}
#[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_or_web::fs;
use std::path::Path;
use std::io::{Error, ErrorKind};
use std::path::Path;
use std_or_web::fs;
let path = format!("skin-cache/{}/{}.png", &hash[..2], hash);
let cache_path = Path::new(&path);
fs::create_dir_all(cache_path.parent().unwrap())?;
@ -892,7 +1061,7 @@ impl TextureManager {
};
let mut buf = vec![];
match res.read_to_end(&mut buf) {
Ok(_) => {},
Ok(_) => {}
Err(err) => {
// TODO: different error for failure to read?
return Err(Error::new(ErrorKind::InvalidData, err));
@ -913,10 +1082,11 @@ impl TextureManager {
if height == 32 {
// Needs changing to the new format
let mut new = image::DynamicImage::new_rgba8(64, 64);
new.copy_from(&img, 0, 0).expect("Invalid png image in skin");
for xx in 0 .. 4 {
for yy in 0 .. 16 {
for section in 0 .. 4 {
new.copy_from(&img, 0, 0)
.expect("Invalid png image in skin");
for xx in 0..4 {
for yy in 0..16 {
for section in 0..4 {
let os = match section {
0 => 2,
1 => 1,
@ -924,8 +1094,16 @@ impl TextureManager {
3 => 3,
_ => unreachable!(),
};
new.put_pixel(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));
new.put_pixel(
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),
];
for bl in blacklist.iter() {
for x in bl.0 .. (bl.0 + bl.2) {
for y in bl.1 .. (bl.1 + bl.3) {
for x in bl.0..(bl.0 + bl.2) {
for y in bl.1..(bl.1 + bl.3) {
let mut col = img.get_pixel(x, y);
col.0[3] = 255;
img.put_pixel(x, y, col);
@ -977,7 +1155,8 @@ impl TextureManager {
let (width, height) = img.dimensions();
(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;
} else if !self.textures.contains_key(name) {
self.load_texture(name);
@ -1005,7 +1184,11 @@ impl TextureManager {
let res = self.resources.clone();
// TODO: This shouldn't be hardcoded to steve but instead
// 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();
val.read_to_end(&mut data).unwrap();
image::load_from_memory(&data).unwrap()
@ -1018,7 +1201,9 @@ impl TextureManager {
}
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 tex = self.get_texture(&name).unwrap();
let rect = atlas::Rect {
@ -1028,8 +1213,12 @@ impl TextureManager {
height: tex.height,
};
self.pending_uploads.push((tex.atlas, rect, img.to_rgba().into_vec()));
self.dynamic_textures.get_mut(&format!("skin-{}", hash)).unwrap().1 = img;
self.pending_uploads
.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> {
@ -1070,23 +1259,27 @@ impl TextureManager {
self.insert_texture_dummy(plugin, name);
}
fn load_animation(&mut self,
plugin: &str,
name: &str,
img: &image::DynamicImage,
data: Vec<u8>)
-> Option<AnimatedTexture> {
fn load_animation(
&mut self,
plugin: &str,
name: &str,
img: &image::DynamicImage,
data: Vec<u8>,
) -> Option<AnimatedTexture> {
let path = format!("textures/{}.png.mcmeta", name);
let res = self.resources.clone();
if let Some(val) = res.read().unwrap().open(plugin, &path) {
let meta: serde_json::Value = serde_json::from_reader(val).unwrap();
let animation = meta.get("animation").unwrap();
let frame_time = animation.get("frametime").and_then(|v| v.as_i64()).unwrap_or(1);
let interpolate = animation.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 frame_time = animation
.get("frametime")
.and_then(|v| v.as_i64())
.unwrap_or(1);
let interpolate = animation
.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());
for frame in frames {
if let Some(index) = frame.as_i64() {
@ -1095,7 +1288,7 @@ impl TextureManager {
time: frame_time,
})
} else {
out.push(AnimationFrame{
out.push(AnimationFrame {
index: frame.get("index").unwrap().as_i64().unwrap() as usize,
time: frame_time * frame.get("frameTime").unwrap().as_i64().unwrap(),
})
@ -1127,13 +1320,14 @@ impl TextureManager {
None
}
fn put_texture(&mut self,
plugin: &str,
name: &str,
width: u32,
height: u32,
data: Vec<u8>)
-> Texture {
fn put_texture(
&mut self,
plugin: &str,
name: &str,
width: u32,
height: u32,
data: Vec<u8>,
) -> Texture {
let (atlas, rect) = self.find_free(width as usize, height as usize);
self.pending_uploads.push((atlas, rect, data));
@ -1224,19 +1418,27 @@ impl TextureManager {
height,
};
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));
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
// work with the new name
let mut old = self.textures.remove(&old_name).unwrap();
old.name = format!("steven-dynamic:{}", name);
t.name = old.name.clone();
self.textures.insert(format!("steven-dynamic:{}", name), old);
self.textures
.insert(format!("steven-dynamic:{}", name), old);
t
} else {
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
}
}

View File

@ -1,17 +1,16 @@
use super::glsl;
use super::shaders;
use crate::format::{self, Component};
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 std::collections::HashMap;
use std::hash::BuildHasherDefault;
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 {
collections: Vec<Collection>,
@ -42,17 +41,25 @@ impl Manager {
m.add_collection(
&greg.get("model_vertex"),
&greg.get("model_frag"),
gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA
gl::SRC_ALPHA,
gl::ONE_MINUS_SRC_ALPHA,
);
m.add_collection(
&greg.get("sun_vertex"),
&greg.get("sun_frag"),
gl::SRC_ALPHA, gl::ONE_FACTOR
gl::SRC_ALPHA,
gl::ONE_FACTOR,
);
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 {
shader: ModelShader::new_manual(vert, frag),
models: HashMap::with_hasher(BuildHasherDefault::default()),
@ -84,11 +91,26 @@ impl Manager {
collection.shader.texture_offset.map(|v| v.enable());
collection.shader.color.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.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));
collection
.shader
.position
.map(|v| v.vertex_pointer(3, gl::FLOAT, false, 36, 0));
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 {
// For culling only
@ -125,7 +147,8 @@ impl Manager {
if self.max_index < 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.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.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_width() 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>(((vert.texture.get_height() as f64) * 16.0 * vert.texture_y) as i16);
let _ = buffer.write_i16::<NativeEndian>(
((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>(0);
let _ = buffer.write_u8(vert.r);
@ -174,12 +201,18 @@ impl Manager {
if buffer.len() < model.buffer_size {
model.buffer.re_set_data(gl::ARRAY_BUFFER, &buffer);
} 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();
}
}
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 (_, model) in &mut collection.models {
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);
for collection in &self.collections {
collection.shader.program.use_program();
collection.shader.perspective_matrix.map(|v| v.set_matrix4(perspective_matrix));
collection.shader.camera_matrix.map(|v| v.set_matrix4(camera_matrix));
collection
.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.sky_offset.map(|v| v.set_float(sky_offset));
collection.shader.light_level.map(|v| v.set_float(light_level));
collection
.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);
for model in collection.models.values() {
if model.radius > 0.0 && frustum.contains(&Sphere {
center: Point3::new(model.x, -model.y, model.z),
radius: model.radius
}) == collision::Relation::Out {
if model.radius > 0.0
&& frustum.contains(&Sphere {
center: Point3::new(model.x, -model.y, model.z),
radius: model.radius,
}) == collision::Relation::Out
{
continue;
}
model.array.bind();
collection.shader.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()));
collection
.shader
.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);
}
}
@ -301,23 +363,44 @@ init_shader! {
// Helper methods
pub fn append_box(
verts: &mut Vec<Vertex>,
x: f32, y: f32, z: f32,
w: f32, h: f32, d: f32, textures: [Option<super::Texture>; 6]
x: f32,
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, [
[1.0, 1.0],
[1.0, 1.0],
[1.0, 1.0],
[1.0, 1.0],
[1.0, 1.0],
[1.0, 1.0]
]);
append_box_texture_scale(
verts,
x,
y,
z,
w,
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(
verts: &mut Vec<Vertex>,
x: f32, y: f32, z: f32,
w: f32, h: f32, d: f32,
textures: [Option<super::Texture>; 6], texture_scale: [[f64; 2]; 6]) {
x: f32,
y: f32,
z: f32,
w: f32,
h: f32,
d: f32,
textures: [Option<super::Texture>; 6],
texture_scale: [[f64; 2]; 6],
) {
for dir in Direction::all() {
let tex = textures[dir.index()].clone();
if tex.is_none() {
@ -326,7 +409,11 @@ pub fn append_box_texture_scale(
let tex = tex.unwrap();
for vert in BlockVertex::face_by_direction(dir) {
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 {
(255, 255, 255)
};
@ -356,7 +443,7 @@ pub struct FormatState<'a> {
pub x_scale: f32,
}
impl <'a> FormatState<'a> {
impl<'a> FormatState<'a> {
pub fn build(&mut self, c: &Component, color: format::Color) {
match *c {
format::Component::Text(ref txt) => {

View File

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

View File

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

View File

@ -14,15 +14,15 @@
extern crate steven_resources as internal;
use std::thread;
use std::path;
use std::io;
use std_or_web::fs;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use serde_json;
use std::collections::HashMap;
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"))]
use reqwest;
@ -32,7 +32,8 @@ use crate::types::hash::FNVHash;
use crate::ui;
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_INDEX_URL: &str = "https://launchermeta.mojang.com/mc/assets/1.12/67e29e024e664064c1f04c728604f83c24cbc218/1.12.json";
@ -85,9 +86,7 @@ impl Manager {
version: 0,
vanilla_chan: None,
vanilla_assets_chan: None,
vanilla_progress: Arc::new(Mutex::new(Progress {
tasks: vec![],
})),
vanilla_progress: Arc::new(Mutex::new(Progress { tasks: vec![] })),
};
m.add_pack(Box::new(InternalPack));
#[cfg(not(target_arch = "wasm32"))]
@ -95,7 +94,13 @@ impl Manager {
m.download_vanilla();
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
@ -156,9 +161,12 @@ impl Manager {
progress.tasks.retain(|v| v.progress < v.total);
// Find out what we have to work with
for task in &progress.tasks {
if !mui.progress_ui.iter()
if !mui
.progress_ui
.iter()
.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;
// Add a ui element for it
let background = ui::ImageBuilder::new()
@ -217,16 +225,22 @@ impl Manager {
}
let mut found = false;
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_name == ui.task_name) {
.filter(|v| v.task_name == ui.task_name)
{
found = true;
prog = task.progress as f64 / task.total as f64;
}
let background = ui.background.borrow();
let bar = ui.progress_bar.borrow();
// 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.position = -UI_HEIGHT;
}
@ -258,7 +272,8 @@ impl Manager {
}
// 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>) {
@ -269,7 +284,12 @@ impl Manager {
fn load_vanilla(&mut self) {
let loc = format!("./resources-{}", RESOURCES_VERSION);
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;
}
@ -284,23 +304,34 @@ impl Manager {
let location = path::Path::new(&loc).to_owned();
let progress_info = self.vanilla_progress.clone();
let (send, recv) = mpsc::channel();
if fs::metadata(&location).is_ok(){
if fs::metadata(&location).is_ok() {
self.load_assets();
} else {
self.vanilla_assets_chan = Some(recv);
}
thread::spawn(move || {
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();
let res = client.get(ASSET_INDEX_URL)
.send()
.unwrap();
let res = client.get(ASSET_INDEX_URL).send().unwrap();
let length = res.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 length = res
.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 {
read: res,
progress: &progress_info,
@ -316,16 +347,25 @@ impl Manager {
let index: serde_json::Value = serde_json::from_reader(&file).unwrap();
let root_location = path::Path::new("./objects/");
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 {
let hash = v.get("hash").and_then(|v| v.as_str()).unwrap();
let hash_path = format!("{}/{}", &hash[..2], hash);
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();
let res = client.get(&format!("http://resources.download.minecraft.net/{}", hash_path))
.send()
.unwrap();
let res = client
.get(&format!(
"http://resources.download.minecraft.net/{}",
hash_path
))
.send()
.unwrap();
let length = v.get("size").and_then(|v| v.as_u64()).unwrap();
Self::add_task(&progress_info, "Downloading Asset", k, length);
let mut tmp_file = location.to_owned();
@ -361,14 +401,24 @@ impl Manager {
let progress_info = self.vanilla_progress.clone();
thread::spawn(move || {
let client = reqwest::blocking::Client::new();
let res = client.get(VANILLA_CLIENT_URL)
.send()
.unwrap();
let res = client.get(VANILLA_CLIENT_URL).send().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);
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 {
read: res,
@ -384,7 +434,12 @@ impl Manager {
let mut zip = zip::ZipArchive::new(file).unwrap();
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 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) {
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_name == name) {
.filter(|v| v.task_name == name)
{
task.progress += prog as u64;
}
}
@ -465,11 +523,12 @@ impl ObjectPack {
let objects = index.get("objects").and_then(|v| v.as_object()).unwrap();
let mut hash_objs = HashMap::with_hasher(BuildHasherDefault::default());
for (k, v) in objects {
hash_objs.insert(k.clone(), v.get("hash").and_then(|v| v.as_str()).unwrap().to_owned());
}
ObjectPack {
objects: hash_objs,
hash_objs.insert(
k.clone(),
v.get("hash").and_then(|v| v.as_str()).unwrap().to_owned(),
);
}
ObjectPack { objects: hash_objs }
}
}
@ -500,7 +559,7 @@ struct ProgressRead<'a, T> {
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> {
let size = self.read.read(buf)?;
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
// limitations under the License.
use crate::ui;
use crate::render;
use crate::ui;
pub struct Connecting {
elements: Option<UIElements>,
@ -27,7 +27,6 @@ struct UIElements {
_disclaimer: ui::TextRef,
}
impl Connecting {
pub fn new(target: &str) -> Connecting {
Connecting {
@ -74,10 +73,12 @@ impl super::Screen for Connecting {
self.elements = None
}
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();
elements.logo.tick(renderer);

View File

@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std_or_web::fs;
use std::collections::BTreeMap;
use std_or_web::fs;
use crate::ui;
use crate::render;
use crate::ui;
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()
.get_mut("servers")
.unwrap()
@ -76,7 +77,6 @@ impl EditServerEntry {
let mut out = fs::File::create("servers.json").unwrap();
serde_json::to_writer_pretty(&mut out, &servers_info).unwrap();
}
}
impl super::Screen for EditServerEntry {
@ -131,7 +131,8 @@ impl super::Screen for EditServerEntry {
&server_name.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
});
}
@ -150,7 +151,8 @@ impl super::Screen for EditServerEntry {
.attach(&mut *cancel);
cancel.add_text(txt);
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
});
}
@ -169,11 +171,12 @@ impl super::Screen for EditServerEntry {
self.elements = None
}
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();
elements.logo.tick(renderer);
None

View File

@ -19,12 +19,12 @@ use std::thread;
use rand::{self, Rng};
use crate::ui;
use crate::render;
use crate::auth;
use crate::console;
use crate::protocol;
use crate::protocol::mojang;
use crate::auth;
use crate::render;
use crate::ui;
pub struct Login {
elements: Option<UIElements>,
@ -47,10 +47,12 @@ struct UIElements {
profile: mojang::Profile,
}
impl 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
let login_error = ui::TextBuilder::new()
.text("")
@ -157,10 +158,12 @@ impl super::Screen for Login {
self.elements = None
}
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();
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();
let mut client_token = self.vars.get(auth::AUTH_CLIENT_TOKEN).clone();
if client_token.is_empty() {
client_token = std::iter::repeat(()).map(|()| rand::thread_rng()
.sample(&rand::distributions::Alphanumeric))
.take(20)
.collect();
client_token = std::iter::repeat(())
.map(|()| rand::thread_rng().sample(&rand::distributions::Alphanumeric))
.take(20)
.collect();
self.vars.set(auth::AUTH_CLIENT_TOKEN, client_token);
}
let client_token = self.vars.get(auth::AUTH_CLIENT_TOKEN).clone();
@ -186,7 +189,8 @@ impl super::Screen for Login {
if refresh {
tx.send(profile.refresh(&client_token)).unwrap();
} 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());
elements.profile = val;
return Some(Box::new(super::ServerList::new(None)));
},
}
Err(err) => {
elements.login_error.borrow_mut().text = format!("{}", err);
},
}
}
}
}

View File

@ -21,31 +21,30 @@ pub mod connecting;
pub mod edit_server;
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::ui;
pub trait Screen {
// Called once
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 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) {}
// May be called multiple times
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);
// 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 Screen>>;
fn tick(
&mut self,
delta: f64,
renderer: &mut render::Renderer,
ui_container: &mut ui::Container,
) -> Option<Box<dyn Screen>>;
// Events
fn on_scroll(&mut self, _x: f64, _y: f64) {
}
fn on_scroll(&mut self, _x: f64, _y: f64) {}
fn is_closable(&self) -> bool {
false
@ -65,7 +64,9 @@ pub struct 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>) {
self.screens.push(ScreenInfo {
@ -94,10 +95,12 @@ impl ScreenSystem {
}
}
pub fn tick(&mut self,
delta: f64,
renderer: &mut render::Renderer,
ui_container: &mut ui::Container) {
pub fn tick(
&mut self,
delta: f64,
renderer: &mut render::Renderer,
ui_container: &mut ui::Container,
) {
for screen in &mut self.remove_queue {
if screen.active {
screen.screen.on_deactive(renderer, ui_container);

View File

@ -12,24 +12,24 @@
// See the License for the specific language governing permissions and
// 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::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::{Component, TextComponent};
use crate::protocol;
use crate::render;
use crate::ui;
use serde_json;
use std::time::{Duration};
use image;
use base64;
use image;
use rand;
use rand::Rng;
use serde_json;
use std::time::Duration;
pub struct ServerList {
elements: Option<UIElements>,
@ -98,9 +98,11 @@ impl ServerList {
}
}
fn reload_server_list(&mut self,
renderer: &mut render::Renderer,
ui_container: &mut ui::Container) {
fn reload_server_list(
&mut self,
renderer: &mut render::Renderer,
ui_container: &mut ui::Container,
) {
let elements = self.elements.as_mut().unwrap();
*self.needs_reload.borrow_mut() = false;
{
@ -141,15 +143,12 @@ impl ServerList {
let mut backr = back.borrow_mut();
let address = address.clone();
backr.add_hover_func(move |this, over, _| {
this.colour.3 = if over {
200
} else {
100
};
this.colour.3 = if over { 200 } else { 100 };
false
});
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);
true
});
@ -168,7 +167,6 @@ impl ServerList {
.size(90.0, 90.0)
.attach(&mut *back.borrow_mut());
// Ping indicator
let ping = ui::ImageBuilder::new()
.texture("gui/icons")
@ -232,9 +230,13 @@ impl ServerList {
let sname = name.clone();
let saddr = address.clone();
btn.add_click_func(move |_, game| {
game.screen_sys.replace_screen(Box::new(super::edit_server::EditServerEntry::new(
Some((index, sname.clone(), saddr.clone()))
)));
game.screen_sys.replace_screen(Box::new(
super::edit_server::EditServerEntry::new(Some((
index,
sname.clone(),
saddr.clone(),
))),
));
true
})
}
@ -260,7 +262,9 @@ impl ServerList {
// Don't block the main thread whilst pinging the server
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) => {
let mut desc = res.0.description;
format::convert_legacy(&mut desc);
@ -345,9 +349,8 @@ impl super::Screen for ServerList {
.attach(&mut *add);
add.add_text(txt);
add.add_click_func(move |_, game| {
game.screen_sys.replace_screen(Box::new(super::edit_server::EditServerEntry::new(
None
)));
game.screen_sys
.replace_screen(Box::new(super::edit_server::EditServerEntry::new(None)));
true
})
}
@ -367,7 +370,8 @@ impl super::Screen for ServerList {
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *options);
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
});
}
@ -386,7 +390,10 @@ impl super::Screen for ServerList {
let background = ui::ImageBuilder::new()
.texture("steven:solid")
.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))
.alignment(ui::VAttach::Top, ui::HAttach::Center)
.draw_index(10)
@ -435,10 +442,12 @@ impl super::Screen for ServerList {
self.elements = None
}
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>> {
if *self.needs_reload.borrow() {
self.reload_server_list(renderer, ui_container);
}
@ -468,20 +477,23 @@ impl super::Screen for ServerList {
s.motd.borrow_mut().set_text(res.motd);
// Selects the icon for the given ping range
// 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 {
_x @ 0 ..= 75 => 16.0 / 256.0,
_x @ 76 ..= 150 => 24.0 / 256.0,
_x @ 151 ..= 225 => 32.0 / 256.0,
_x @ 226 ..= 350 => 40.0 / 256.0,
_x @ 351 ..= 999 => 48.0 / 256.0,
_x @ 0..=75 => 16.0 / 256.0,
_x @ 76..=150 => 24.0 / 256.0,
_x @ 151..=225 => 32.0 / 256.0,
_x @ 226..=350 => 40.0 / 256.0,
_x @ 351..=999 => 48.0 / 256.0,
_ => 56.0 / 256.0,
};
s.ping.borrow_mut().texture_coords.1 = y;
if res.exists {
{
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.2 = 255;
format!("{}/{}", res.online, res.max)
@ -492,8 +504,13 @@ impl super::Screen for ServerList {
};
players.text = txt;
}
let sm = format!("{} mods + {}", res.forge_mods.len(), res.protocol_name);
let st = if res.forge_mods.len() > 0 { &sm } else { &res.protocol_name };
let sm =
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);
txt.modifier.color = Some(format::Color::Yellow);
let mut msg = Component::Text(txt);
@ -501,15 +518,15 @@ impl super::Screen for ServerList {
s.version.borrow_mut().set_text(msg);
}
if let Some(favicon) = res.favicon {
let name: String = std::iter::repeat(()).map(|()| rand::thread_rng()
.sample(&rand::distributions::Alphanumeric))
.take(30)
.collect();
let name: String = std::iter::repeat(())
.map(|()| {
rand::thread_rng().sample(&rand::distributions::Alphanumeric)
})
.take(30)
.collect();
let tex = renderer.get_textures_ref();
s.icon_texture = Some(name.clone());
let icon_tex = tex.write()
.unwrap()
.put_dynamic(&name, favicon);
let icon_tex = tex.write().unwrap().put_dynamic(&name, favicon);
s.icon.borrow_mut().texture = icon_tex.name;
}
}

View File

@ -1,7 +1,7 @@
use crate::console;
use crate::render;
use crate::ui;
use crate::settings;
use crate::ui;
use std::rc::Rc;
@ -13,7 +13,7 @@ pub struct UIElements {
pub struct SettingsMenu {
_vars: Rc<console::Vars>,
elements: Option<UIElements>,
show_disconnect_button: bool
show_disconnect_button: bool,
}
impl SettingsMenu {
@ -21,7 +21,7 @@ impl SettingsMenu {
SettingsMenu {
_vars: vars,
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);
audio_settings.add_text(txt);
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
});
}
@ -70,7 +71,8 @@ impl super::Screen for SettingsMenu {
.attach(&mut *video_settings);
video_settings.add_text(txt);
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
});
}
@ -142,7 +144,8 @@ impl super::Screen for SettingsMenu {
disconnect_button.add_text(txt);
disconnect_button.add_click_func(|_, game| {
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
});
}
@ -153,14 +156,18 @@ impl super::Screen for SettingsMenu {
background,
_buttons: buttons,
});
}
fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
self.elements = None;
}
// 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 mode = ui_container.mode;
@ -178,9 +185,7 @@ impl super::Screen for SettingsMenu {
}
// Events
fn on_scroll(&mut self, _x: f64, _y: f64) {
}
fn on_scroll(&mut self, _x: f64, _y: f64) {}
fn is_closable(&self) -> bool {
true
@ -227,11 +232,14 @@ impl super::Screen for VideoSettingsMenu {
{
let mut fov_setting = fov_setting.borrow_mut();
let txt = ui::TextBuilder::new()
.text(format!("FOV: {}", match r_fov {
90 => "Normal".into(),
110 => "Quake pro".into(),
val => val.to_string(),
}))
.text(format!(
"FOV: {}",
match r_fov {
90 => "Normal".into(),
110 => "Quake pro".into(),
val => val.to_string(),
}
))
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *fov_setting);
fov_setting.add_text(txt);
@ -246,14 +254,18 @@ impl super::Screen for VideoSettingsMenu {
{
let mut vsync_setting = vsync_setting.borrow_mut();
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)
.attach(&mut *vsync_setting);
let txt_vsync = txt.clone();
vsync_setting.add_text(txt);
vsync_setting.add_click_func(move |_, game| {
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);
true
});
@ -269,10 +281,13 @@ impl super::Screen for VideoSettingsMenu {
{
let mut fps_setting = fps_setting.borrow_mut();
let txt = ui::TextBuilder::new()
.text(format!("FPS cap: {}", match r_max_fps {
0 => "Unlimited".into(),
val => val.to_string(),
}))
.text(format!(
"FPS cap: {}",
match r_max_fps {
0 => "Unlimited".into(),
val => val.to_string(),
}
))
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *fps_setting);
fps_setting.add_text(txt);
@ -302,14 +317,18 @@ impl super::Screen for VideoSettingsMenu {
background,
_buttons: buttons,
});
}
fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
self.elements = None;
}
// 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 mode = ui_container.mode;
@ -327,9 +346,7 @@ impl super::Screen for VideoSettingsMenu {
}
// Events
fn on_scroll(&mut self, _x: f64, _y: f64) {
}
fn on_scroll(&mut self, _x: f64, _y: f64) {}
fn is_closable(&self) -> bool {
true
@ -338,14 +355,14 @@ impl super::Screen for VideoSettingsMenu {
pub struct AudioSettingsMenu {
_vars: Rc<console::Vars>,
elements: Option<UIElements>
elements: Option<UIElements>,
}
impl AudioSettingsMenu {
pub fn new(vars: Rc<console::Vars>) -> AudioSettingsMenu {
AudioSettingsMenu {
_vars: vars,
elements: None
elements: None,
}
}
}
@ -387,14 +404,18 @@ impl super::Screen for AudioSettingsMenu {
background,
_buttons: buttons,
});
}
fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
self.elements = None;
}
// 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 mode = ui_container.mode;
@ -412,9 +433,7 @@ impl super::Screen for AudioSettingsMenu {
}
// Events
fn on_scroll(&mut self, _x: f64, _y: f64) {
}
fn on_scroll(&mut self, _x: f64, _y: f64) {}
fn is_closable(&self) -> bool {
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_i16;
use crate::protocol::{Serializable, VarShort};
@ -34,5 +33,4 @@ impl Brand {
data: crate::protocol::LenPrefixedBytes::<VarShort>::new(data),
}
}
}

View File

@ -1,7 +1,6 @@
use crate::render;
use crate::render::model;
use cgmath::{Vector3, Matrix4, Decomposed, Rotation3, Rad, Quaternion};
use cgmath::{Decomposed, Matrix4, Quaternion, Rad, Rotation3, Vector3};
pub struct SunModel {
sun: model::ModelKey,
@ -12,7 +11,6 @@ pub struct SunModel {
const SIZE: f32 = 50.0;
impl SunModel {
pub fn new(renderer: &mut render::Renderer) -> SunModel {
SunModel {
sun: SunModel::generate_sun(renderer),
@ -71,26 +69,123 @@ impl SunModel {
renderer.model.create_model(
model::SUN,
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{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}
]]
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 {
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 {
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 mpy = (phase / 4) as f64 * (1.0 / 2.0);
renderer.model.create_model(
model::SUN,
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{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}
]]
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 {
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::model;
use crate::shared::{Direction, Position};
use crate::world;
use crate::world::block;
use cgmath;
use collision::{self, Aabb};
pub struct Info {
@ -17,13 +16,13 @@ impl Info {
pub fn new() -> Info {
Info {
model: None,
last_block: block::Air{},
last_block: block::Air {},
last_pos: Position::new(0, 0, 0),
}
}
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() {
renderer.model.remove_model(model);
}
@ -44,16 +43,27 @@ impl Info {
let tex = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid");
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 [
(bound.min.x, bound.min.z),
(bound.min.x, bound.max.z),
(bound.max.x, bound.min.z),
(bound.max.x, bound.max.z),
].iter() {
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,
]
.iter()
{
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()),
@ -61,7 +71,8 @@ impl Info {
Some(tex.clone()),
Some(tex.clone()),
Some(tex.clone()),
]);
],
);
}
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.min.z, bound.min.x, bound.max.z),
(bound.max.x, bound.min.z, bound.max.x, bound.max.z),
].iter() {
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,
]
.iter()
{
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()),
@ -80,10 +98,16 @@ impl Info {
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,
((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.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()),
@ -91,7 +115,8 @@ impl Info {
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 posf = cgmath::Vector3::new(pos.x as f64, pos.y as f64, pos.z as f64);
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 LEFT: usize = 1;
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 max_t = [0.0, 0.0, 0.0];
let mut inside = true;
for i in 0 .. 3 {
for i in 0..3 {
if origin[i] < bound.min[i] {
quadrant[i] = LEFT;
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);
}
for i in 0 .. 3 {
for i in 0..3 {
if quadrant[i] != MIDDLE && dir[i] != 0.0 {
max_t[i] = (candidate_plane[i] - origin[i]) / dir[i];
}
}
let mut which_plane = 0;
for i in 1 .. 3 {
for i in 1..3 {
if max_t[which_plane] < max_t[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);
for i in 0 .. 3 {
for i in 0..3 {
if which_plane != i {
coord[i] = origin[i] + max_t[which_plane] * dir[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)
}
pub fn trace_ray<F, 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>) {
pub fn trace_ray<F, 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 {
count: i32,
base: f64,
@ -208,11 +253,7 @@ pub fn trace_ray<F, R>(world: &world::World, max: f64, s: cgmath::Vector3<f64>,
} else {
0.0
};
Gen {
count: 0,
base,
d,
}
Gen { count: 0, base, d }
}
fn next(&mut self) -> f64 {

View File

@ -1,6 +1,6 @@
use crate::console;
use std::marker::PhantomData;
use glutin::event::VirtualKeyCode;
use std::marker::PhantomData;
// Might just rename this to settings.rs
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 {
($keycode:ident, $name:expr, $description:expr) => (console::CVar {
ty: PhantomData,
name: $name,
description: $description,
mutable: true,
serializable: true,
default: &|| VirtualKeyCode::$keycode as i64
})
($keycode:ident, $name:expr, $description:expr) => {
console::CVar {
ty: PhantomData,
name: $name,
description: $description,
mutable: true,
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_BACKWARD: console::CVar<i64> = create_keybind!(S, "cl_keybind_backward", "Keybinding for moving backward");
pub const CL_KEYBIND_LEFT: console::CVar<i64> = create_keybind!(A, "cl_keybind_left", "Keybinding for moving the left");
pub const CL_KEYBIND_RIGHT: console::CVar<i64> = 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 CL_KEYBIND_FORWARD: console::CVar<i64> =
create_keybind!(W, "cl_keybind_forward", "Keybinding for moving forward");
pub const CL_KEYBIND_BACKWARD: console::CVar<i64> =
create_keybind!(S, "cl_keybind_backward", "Keybinding for moving backward");
pub const CL_KEYBIND_LEFT: console::CVar<i64> =
create_keybind!(A, "cl_keybind_left", "Keybinding for moving the left");
pub const CL_KEYBIND_RIGHT: console::CVar<i64> =
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;
@ -90,15 +103,22 @@ pub enum Stevenkey {
impl Stevenkey {
pub fn values() -> Vec<Stevenkey> {
vec!(Stevenkey::Forward, Stevenkey::Backward, Stevenkey::Left,
Stevenkey::Right, Stevenkey::OpenInv, Stevenkey::Sneak,
Stevenkey::Sprint, Stevenkey::Jump)
vec![
Stevenkey::Forward,
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> {
for steven_key in Stevenkey::values() {
if keycode as i64 == *vars.get(steven_key.get_cvar()) {
return Some(steven_key)
return Some(steven_key);
}
}
None
@ -113,7 +133,7 @@ impl Stevenkey {
Stevenkey::OpenInv => CL_KEYBIND_OPEN_INV,
Stevenkey::Sneak => CL_KEYBIND_SNEAK,
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::resources;
use std::time::{SystemTime, UNIX_EPOCH};
use crate::ui;
use rand::{self, seq::SliceRandom};
use rand_pcg;
use std::f64::consts;
use std::sync::{Arc, RwLock};
use std::time::{SystemTime, UNIX_EPOCH};
pub struct Logo {
_shadow: ui::BatchRef,
@ -20,9 +19,10 @@ pub struct Logo {
}
impl Logo {
pub fn new(resources: Arc<RwLock<resources::Manager>>,
ui_container: &mut ui::Container)
-> Logo {
pub fn new(
resources: Arc<RwLock<resources::Manager>>,
ui_container: &mut ui::Container,
) -> Logo {
let logo_str = {
let res = resources.read().unwrap();
let mut logo = res.open("steven", "logo/logo.txt").unwrap();
@ -66,14 +66,15 @@ impl Logo {
.colour((0, 0, 0, 100))
.attach(&mut *shadow_batch.borrow_mut());
ui::ImageBuilder::new()
.texture("minecraft:blocks/planks_oak")
.position(x as f64, y as f64)
.size(4.0, 8.0)
.texture_coords((
(x % 16) as f64 / 16.0, (y % 16) as f64 / 16.0,
4.0 / 16.0, 8.0 / 16.0
(x % 16) as f64 / 16.0,
(y % 16) as f64 / 16.0,
4.0 / 16.0,
8.0 / 16.0,
))
.colour((r, g, b, 255))
.attach(&mut *layer0.borrow_mut());
@ -101,7 +102,8 @@ impl Logo {
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);
}
@ -147,7 +149,7 @@ impl Logo {
if 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;
}
@ -160,6 +162,6 @@ impl Logo {
text.scale_x = (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;
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;
use std::rc::{Rc, Weak};
use std::cell::{RefCell, RefMut};
use crate::render;
use crate::format;
use glutin::event::VirtualKeyCode;
use crate::render;
#[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_HEIGHT: f64 = 480.0;
#[derive(Clone, Copy, PartialEq)]
pub enum Mode {
Scaled,
@ -56,8 +55,10 @@ struct Region {
impl Region {
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.y > o.y + o.h)
!(self.x + self.w < o.x
|| 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),
};
if self.last_sw != sw || self.last_sh != sh || self.last_width != width ||
self.last_height != height || self.version != renderer.ui.version || self.last_mode != self.mode {
if self.last_sw != sw
|| 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_sh = sh;
self.last_width = width;
@ -324,9 +330,12 @@ impl Container {
// If we don't have an element focused, focus one
if !self.focusable_elements.is_empty()
&& !self.focusable_elements.iter()
.flat_map(|v| v.upgrade())
.any(|v| v.is_focused()) {
&& !self
.focusable_elements
.iter()
.flat_map(|v| v.upgrade())
.any(|v| v.is_focused())
{
self.cycle_focus()
}
@ -380,13 +389,14 @@ impl Container {
if self.focusable_elements.is_empty() {
return;
}
let focusables = self.focusable_elements.iter()
let focusables = self
.focusable_elements
.iter()
.flat_map(|v| v.upgrade())
.collect::<Vec<_>>();
// Find the last focused element if there is one
let last_focus = focusables.iter()
.position(|v| v.is_focused());
let last_focus = focusables.iter().position(|v| v.is_focused());
let next_focus = last_focus.map_or(0, |v| v + 1) % focusables.len();
// Clear the last focus
@ -397,15 +407,20 @@ impl Container {
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 !down {
self.cycle_focus();
}
return;
}
for el in self.focusable_elements.iter()
.flat_map(|v| v.upgrade()) {
for el in self.focusable_elements.iter().flat_map(|v| v.upgrade()) {
if el.is_focused() {
el.key_press(game, key, down, ctrl_pressed);
}
@ -416,8 +431,7 @@ impl Container {
if c < ' ' {
return;
}
for el in self.focusable_elements.iter()
.flat_map(|v| v.upgrade()) {
for el in self.focusable_elements.iter().flat_map(|v| v.upgrade()) {
if el.is_focused() {
el.key_type(game, c);
}
@ -463,11 +477,27 @@ impl ElementHolder for Container {
}
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 is_dirty(&self) -> bool;
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 tick(&mut self, renderer: &mut render::Renderer);
}
@ -804,14 +834,29 @@ impl ImageBuilder {
}
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() {
self.data.clear();
let texture = render::Renderer::get_texture(renderer.get_textures_ref(), &self.texture);
let mut element = render::ui::UIElement::new(
&texture,
r.x, r.y, r.w, r.h,
self.texture_coords.0, self.texture_coords.1, self.texture_coords.2, self.texture_coords.3,
r.x,
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.g = self.colour.1;
@ -862,7 +907,16 @@ impl BatchBuilder {
}
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() {
self.data.clear();
self.super_draw(renderer, r, sw, sh, width, height, delta);
@ -916,15 +970,29 @@ element! {
}
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() {
self.data.clear();
let mut text = if self.rotation == 0.0 {
renderer.ui.new_text_scaled(
&self.text,
r.x, r.y, sw * self.scale_x, sh * self.scale_y,
self.colour.0, self.colour.1, self.colour.2,
r.x,
r.y,
sw * self.scale_x,
sh * self.scale_y,
self.colour.0,
self.colour.1,
self.colour.2,
)
} else {
let c = self.rotation.cos();
@ -934,11 +1002,15 @@ impl UIElement for Text {
let w = (tmpx * c - tmpy * s).abs();
let h = (tmpy * c + tmpx * s).abs();
renderer.ui.new_text_rotated(
&self.text,
r.x + w - (r.w / 2.0), r.y + h - (r.h / 2.0),
sw * self.scale_x, sh * self.scale_y,
self.rotation,
self.colour.0, self.colour.1, self.colour.2,
&self.text,
r.x + w - (r.w / 2.0),
r.y + h - (r.h / 2.0),
sw * self.scale_x,
sh * self.scale_y,
self.rotation,
self.colour.0,
self.colour.1,
self.colour.2,
)
};
for e in &mut text.elements {
@ -964,7 +1036,10 @@ impl UIElement for Text {
}
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 {
@ -976,8 +1051,6 @@ impl UIElement for Text {
}
}
element! {
ref FormattedRef
pub struct Formatted {
@ -1011,7 +1084,16 @@ element! {
}
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() {
self.data.clear();
@ -1058,7 +1140,10 @@ impl UIElement for Formatted {
}
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 {
@ -1075,7 +1160,11 @@ impl Formatted {
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 {
lines: 0,
width: 0.0,
@ -1098,14 +1187,13 @@ struct FormatState<'a> {
renderer: &'a render::Renderer,
}
impl <'a> ElementHolder for FormatState<'a> {
impl<'a> ElementHolder for FormatState<'a> {
fn add(&mut self, el: Element, _: bool) {
self.text.push(el);
}
}
impl <'a> FormatState<'a> {
impl<'a> FormatState<'a> {
fn build(&mut self, c: &format::Component, color: format::Color) {
match *c {
format::Component::Text(ref txt) => {
@ -1197,46 +1285,156 @@ impl ButtonBuilder {
}
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() {
self.data.clear();
let offset = match (self.disabled, self.hovered) {
(true, _) => 46.0,
(false, true) => 86.0,
(false, false) => 66.0,
(true, _) => 46.0,
(false, true) => 86.0,
(false, false) => 66.0,
};
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(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));
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 w = ((r.w / sw)/2.0) - 4.0;
self.data.extend(render::ui::UIElement::new(
&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(
&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(render::ui::UIElement::new(
&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)
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),
);
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;
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)
let w = ((r.w / sw) / 2.0) - 4.0;
self.data.extend(
render::ui::UIElement::new(
&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(
&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(
&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(
&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.data.extend(
render::ui::UIElement::new(
&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.last_disabled = self.disabled;
@ -1254,11 +1452,9 @@ impl UIElement for Button {
}
fn is_dirty(&self) -> bool {
self.last_disabled != self.disabled
|| self.last_hovered != self.hovered
self.last_disabled != self.disabled || self.last_hovered != self.hovered
}
fn post_init(s: Rc<RefCell<Self>>) {
s.borrow_mut().add_hover_func(move |this, hover, _| {
this.hovered = hover;
@ -1311,9 +1507,17 @@ impl TextBoxBuilder {
}
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) {
(VirtualKeyCode::Back, _) => {self.input.pop();},
(VirtualKeyCode::Back, _) => {
self.input.pop();
}
(VirtualKeyCode::Return, false) => {
use std::mem;
let len = self.submit_funcs.len();
@ -1322,7 +1526,7 @@ impl UIElement for TextBox {
(func)(self, game);
}
self.submit_funcs.append(&mut temp);
},
}
// TODO: wasm clipboard pasting, Clipboard API: https://www.w3.org/TR/clipboard-apis/
#[cfg(not(target_arch = "wasm32"))]
(VirtualKeyCode::V, true) => {
@ -1330,11 +1534,11 @@ impl UIElement for TextBox {
let mut clipboard: ClipboardContext = ClipboardProvider::new().unwrap();
match clipboard.get_contents() {
Ok(text) => self.input.push_str(&text),
Err(_) => ()
Err(_) => (),
}
}
},
_ => {},
}
_ => {}
}
}
@ -1342,7 +1546,16 @@ impl UIElement for TextBox {
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() {
self.data.clear();
self.cursor_tick += delta;
@ -1381,17 +1594,21 @@ impl UIElement for TextBox {
fn post_init(s: Rc<RefCell<Self>>) {
let mut textbox = s.borrow_mut();
textbox.button = Some(ButtonBuilder::new()
.position(0.0, 0.0)
.size(textbox.width, textbox.height)
.disabled(true)
.attach(&mut *textbox));
textbox.text = Some(TextBuilder::new()
.text("")
.position(5.0, 0.0)
.draw_index(1)
.alignment(VAttach::Middle, HAttach::Left)
.attach(&mut *textbox));
textbox.button = Some(
ButtonBuilder::new()
.position(0.0, 0.0)
.size(textbox.width, textbox.height)
.disabled(true)
.attach(&mut *textbox),
);
textbox.text = Some(
TextBuilder::new()
.text("")
.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 lazy_static::lazy_static;
@ -14,7 +13,7 @@ impl Biome {
Biome {
id,
temperature: t,
moisture: m*t,
moisture: m * t,
}
}
@ -23,21 +22,19 @@ impl Biome {
}
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);
(((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> {
if self.id == ROOFED_FOREST.id || self.id == ROOFED_FOREST_MOUNTAINS.id {
Rgba (
[
((col.0[0] as u32 + 0x28) / 2) as u8,
((col.0[1] as u32 + 0x34) / 2) as u8,
((col.0[2] as u32 + 0x0A) / 2) as u8,
255
]
)
Rgba([
((col.0[0] as u32 + 0x28) / 2) as u8,
((col.0[1] as u32 + 0x34) / 2) as u8,
((col.0[2] as u32 + 0x0A) / 2) as u8,
255,
])
} else {
col
}

View File

@ -14,21 +14,21 @@
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::ecs;
use crate::entity::block_entity;
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 std::collections::HashMap;
use std::collections::VecDeque;
use std::hash::BuildHasherDefault;
use std::io::Read;
pub mod biome;
@ -52,13 +52,19 @@ pub struct World {
pub enum BlockEntityAction {
Create(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)]
enum LightType {
Block,
Sky
Sky,
}
impl LightType {
@ -104,10 +110,12 @@ impl World {
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.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() {
self.block_entity_actions.push_back(BlockEntityAction::Create(pos));
self.block_entity_actions
.push_back(BlockEntityAction::Create(pos));
}
true
} else {
@ -116,9 +124,9 @@ impl World {
}
pub fn update_block(&mut self, pos: Position) {
for yy in -1 .. 2 {
for zz in -1 .. 2 {
for xx in -1 .. 2 {
for yy in -1..2 {
for zz in -1..2 {
for xx in -1..2 {
let bp = pos + (xx, yy, zz);
let current = self.get_block(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) {
for by in y1 .. y2 {
for bz in z1 .. z2 {
for bx in x1 .. x2 {
for by in y1..y2 {
for bz in z1..z2 {
for bx in x1..x2 {
let bp = Position::new(bx, by, bz);
let current = self.get_block(bp);
let new = current.update_state(self, bp);
@ -156,7 +164,7 @@ impl World {
pub fn get_block(&self, pos: Position) -> block::Block {
match self.chunks.get(&CPos(pos.x >> 4, pos.z >> 4)) {
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) {
self.light_updates.push_back(LightUpdate {
ty,
pos,
});
self.light_updates.push_back(LightUpdate { ty, pos });
}
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) {
use std::time::{Instant};
use std::time::Instant;
let start = Instant::now();
let mut updates_performed = 0;
while !self.light_updates.is_empty() {
updates_performed += 1;
self.do_light_update();
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;
}
}
@ -221,7 +227,7 @@ impl World {
m.remove_entity(entity);
}
}
},
}
BlockEntityAction::Create(pos) => {
if let Some(chunk) = self.chunks.get_mut(&CPos(pos.x >> 4, pos.z >> 4)) {
// Remove existing entity
@ -229,22 +235,19 @@ impl World {
m.remove_entity(entity);
}
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);
chunk.block_entities.insert(pos, entity);
}
}
},
}
BlockEntityAction::UpdateSignText(pos, line1, line2, line3, line4) => {
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(sign) = m.get_component_mut(*entity, sign_info) {
sign.lines = [
line1,
line2,
line3,
line4,
];
sign.lines = [line1, line2, line3, line4];
sign.dirty = true;
}
}
@ -257,7 +260,10 @@ impl World {
fn do_light_update(&mut self) {
use std::cmp;
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;
}
@ -280,7 +286,8 @@ impl World {
// Sky light doesn't decrease when going down at full brightness
if update.ty == LightType::Sky
&& 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;
}
@ -291,9 +298,9 @@ impl World {
// Use our new light value
update.ty.set_light(self, update.pos, best);
// Flag surrounding chunks as dirty
for yy in -1 .. 2 {
for zz in -1 .. 2 {
for xx in -1 .. 2 {
for yy in -1..2 {
for zz in -1..2 {
for xx in -1..2 {
let bp = update.pos + (xx, yy, zz);
self.set_dirty(bp.x >> 4, bp.y >> 4, bp.z >> 4);
}
@ -313,12 +320,11 @@ impl World {
if c.heightmap_dirty {
dirty = true;
c.heightmap_dirty = false;
for xx in 0 .. 16 {
for zz in 0 .. 16 {
data[
(((c.position.0 << 4) as usize + xx) & 0x1FF) +
((((c.position.1 << 4) as usize + zz) & 0x1FF) << 9)
] = c.heightmap[(zz << 4) | xx];
for xx in 0..16 {
for zz in 0..16 {
data[(((c.position.0 << 4) as usize + xx) & 0x1FF)
+ ((((c.position.1 << 4) as usize + zz) & 0x1FF) << 9)] =
c.heightmap[(zz << 4) | xx];
}
}
}
@ -339,25 +345,37 @@ impl World {
let start = (
((renderer.camera.pos.x 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);
process_queue.push_front((Direction::Invalid, start));
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 {
continue;
}
*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 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 {
let min = cgmath::Point3::new(
pos.0 as f32 * 16.0,
-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;
}
(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 {
continue;
};
@ -369,11 +387,14 @@ impl World {
for dir in Direction::all() {
let (ox, oy, oz) = dir.get_offset();
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 {
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));
}
}
@ -382,11 +403,14 @@ impl World {
}
pub fn get_render_list(&self) -> Vec<((i32, i32, i32), &render::ChunkBuffer)> {
self.render_list.iter().map(|v| {
let chunk = self.chunks.get(&CPos(v.0, v.2)).unwrap();
let sec = chunk.sections[v.1 as usize].as_ref().unwrap();
(*v, &sec.render_buffer)
}).collect()
self.render_list
.iter()
.map(|v| {
let chunk = self.chunks.get(&CPos(v.0, v.2)).unwrap();
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> {
@ -398,7 +422,12 @@ impl World {
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 {
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 {
use std::cmp::{min, max};
use std::cmp::{max, min};
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),
sky_light: nibble::Array::new((w * h * d) as usize),
biomes: vec![0; (w * d) as usize],
x, y, z,
w, _h: h, d,
x,
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);
}
@ -492,48 +525,58 @@ impl World {
let cy2 = (y + h + 15) >> 4;
let cz2 = (z + d + 15) >> 4;
for cx in cx1 .. cx2 {
for cz in cz1 .. cz2 {
for cx in cx1..cx2 {
for cz in cz1..cz2 {
let chunk = match self.chunks.get(&CPos(cx, cz)) {
Some(val) => val,
None => continue,
};
let x1 = min(16, max(0, x - (cx<<4)));
let x2 = min(16, max(0, x + w - (cx<<4)));
let z1 = min(16, max(0, z - (cz<<4)));
let z2 = min(16, max(0, z + d - (cz<<4)));
let x1 = min(16, max(0, x - (cx << 4)));
let x2 = min(16, max(0, x + w - (cx << 4)));
let z1 = min(16, max(0, z - (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 {
continue;
}
let section = &chunk.sections[cy as usize];
let y1 = min(16, max(0, y - (cy<<4)));
let y2 = min(16, max(0, y + h - (cy<<4)));
let y1 = min(16, max(0, y - (cy << 4)));
let y2 = min(16, max(0, y + h - (cy << 4)));
for yy in y1 .. y2 {
for zz in z1 .. z2 {
for xx in x1 .. x2 {
for yy in y1..y2 {
for zz in z1..z2 {
for xx in x1..x2 {
let ox = xx + (cx << 4);
let oy = yy + (cy << 4);
let oz = zz + (cz << 4);
match section.as_ref() {
Some(sec) => {
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_sky_light(ox, oy, oz, sec.get_sky_light(xx, yy, zz));
},
snapshot.set_block_light(
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 => {
snapshot.set_block(ox, oy, oz, block::Air{});
},
snapshot.set_block(ox, oy, oz, block::Air {});
}
}
}
}
}
}
for zz in z1 .. z2 {
for xx in x1 .. x2 {
for zz in z1..z2 {
for xx in x1..x2 {
let ox = xx + (cx << 4);
let oz = zz + (cz << 4);
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> {
let mut data = std::io::Cursor::new(data);
pub fn load_chunks18(
&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 {
let x = chunk_meta.x;
let z = chunk_meta.z;
let mask = chunk_meta.bitmask;
for chunk_meta in chunk_metas {
let x = chunk_meta.x;
let z = chunk_meta.z;
let mask = chunk_meta.bitmask;
self.load_chunk18(x, z, new, skylight, mask, &mut data)?;
}
Ok(())
self.load_chunk18(x, z, new, skylight, mask, &mut data)?;
}
Ok(())
}
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 {
continue;
}
for pos in [
(-1, 0, 0), (1, 0, 0),
(0, -1, 0), (0, 1, 0),
(0, 0, -1), (0, 0, 1)].iter() {
(-1, 0, 0),
(1, 0, 0),
(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.update_range(
(x<<4) - 1, (i<<4) - 1, (z<<4) - 1,
(x<<4) + 17, (i<<4) + 17, (z<<4) + 17
(x << 4) - 1,
(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;
let cpos = CPos(x, z);
@ -599,11 +666,9 @@ impl World {
self.chunks.get_mut(&cpos).unwrap()
};
for i in 0 .. 16 {
for i in 0..16 {
if chunk.sections[i].is_none() {
let mut fill_sky = chunk.sections.iter()
.skip(i)
.all(|v| v.is_none());
let mut fill_sky = chunk.sections.iter().skip(i).all(|v| v.is_none());
fill_sky &= (mask & !((1 << i) | ((1 << i) - 1))) == 0;
if !fill_sky || mask & (1 << i) != 0 {
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();
section.dirty = true;
for bi in 0 .. 4096 {
for bi in 0..4096 {
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
let b = section.blocks.get(bi);
@ -625,17 +697,23 @@ impl World {
let pos = Position::new(
(bi & 0xF) as i32,
(bi >> 8) as i32,
((bi >> 4) & 0xF) as i32
) + (chunk.position.0 << 4, (i << 4) as i32, chunk.position.1 << 4);
((bi >> 4) & 0xF) as i32,
) + (
chunk.position.0 << 4,
(i << 4) as i32,
chunk.position.1 << 4,
);
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 {
continue;
}
@ -644,7 +722,7 @@ impl World {
data.read_exact(&mut section.block_light.data)?;
}
for i in 0 .. 16 {
for i in 0..16 {
if mask & (1 << i) == 0 {
continue;
}
@ -664,7 +742,13 @@ impl World {
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 metadata = &data[data_length as usize..];
@ -692,16 +776,41 @@ impl World {
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> {
let mut zlib = ZlibDecoder::new(std::io::Cursor::new(compressed_data.to_vec()));
let mut data = Vec::new();
zlib.read_to_end(&mut data)?;
pub fn load_chunk17(
&mut self,
x: i32,
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;
self.load_uncompressed_chunk17(x, z, new, skylight, mask, mask_add, &mut std::io::Cursor::new(data))
let skylight = true;
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 chunk = if new {
@ -716,11 +825,9 @@ impl World {
// Block type array - whole byte per block
let mut block_types = [[0u8; 4096]; 16];
for i in 0 .. 16 {
for i in 0..16 {
if chunk.sections[i].is_none() {
let mut fill_sky = chunk.sections.iter()
.skip(i)
.all(|v| v.is_none());
let mut fill_sky = chunk.sections.iter().skip(i).all(|v| v.is_none());
fill_sky &= (mask & !((1 << i) | ((1 << i) - 1))) == 0;
if !fill_sky || mask & (1 << i) != 0 {
chunk.sections[i] = Some(Section::new(i as u8, fill_sky));
@ -738,13 +845,25 @@ impl World {
// Block metadata array - half byte per block
let mut block_meta: [nibble::Array; 16] = [
// 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 {
continue;
}
@ -753,7 +872,7 @@ impl World {
}
// Block light array - half byte per block
for i in 0 .. 16 {
for i in 0..16 {
if mask & (1 << i) == 0 {
continue;
}
@ -764,7 +883,7 @@ impl World {
// Sky light array - half byte per block - only if 'skylight' is true
if skylight {
for i in 0 .. 16 {
for i in 0..16 {
if mask & (1 << i) == 0 {
continue;
}
@ -777,13 +896,25 @@ impl World {
// Add array - half byte per block - uses secondary bitmask
let mut block_add: [nibble::Array; 16] = [
// 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 {
continue;
}
@ -791,16 +922,25 @@ impl World {
}
// 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 {
continue;
}
let section = chunk.sections[i as usize].as_mut().unwrap();
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);
section.blocks.set(bi, block::Block::by_vanilla_id(id as usize, self.protocol_version, &self.modded_block_ids));
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);
section.blocks.set(
bi,
block::Block::by_vanilla_id(
id as usize,
self.protocol_version,
&self.modded_block_ids,
),
);
// Spawn block entities
let b = section.blocks.get(bi);
@ -808,12 +948,18 @@ impl World {
let pos = Position::new(
(bi & 0xF) as i32,
(bi >> 8) as i32,
((bi >> 4) & 0xF) as i32
) + (chunk.position.0 << 4, (i << 4) as i32, chunk.position.1 << 4);
((bi >> 4) & 0xF) as i32,
) + (
chunk.position.0 << 4,
(i << 4) as i32,
chunk.position.1 << 4,
);
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(())
}
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)
}
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)
}
fn load_chunk19_or_115(&mut self, read_biomes: bool, x: i32, z: i32, new: bool, mask: u16, data: Vec<u8>) -> Result<(), protocol::Error> {
use std::io::Cursor;
fn load_chunk19_or_115(
&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 crate::protocol::{VarInt, Serializable, LenPrefixed};
use std::io::Cursor;
let mut data = Cursor::new(data);
@ -856,11 +1024,9 @@ impl World {
self.chunks.get_mut(&cpos).unwrap()
};
for i in 0 .. 16 {
for i in 0..16 {
if chunk.sections[i].is_none() {
let mut fill_sky = chunk.sections.iter()
.skip(i)
.all(|v| v.is_none());
let mut fill_sky = chunk.sections.iter().skip(i).all(|v| v.is_none());
fill_sky &= (mask & !((1 << i) | ((1 << i) - 1))) == 0;
if !fill_sky || mask & (1 << i) != 0 {
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();
section.dirty = true;
if self.protocol_version >= 451 {
let _block_count = data.read_u16::<byteorder::LittleEndian>()?;
// TODO: use block_count
}
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 {
bit_size = 13;
} else {
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 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);
}
}
@ -893,21 +1064,37 @@ impl World {
let bits = LenPrefixed::<VarInt, u64>::read_from(&mut data)?.data;
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);
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
let b = section.blocks.get(bi);
if block_entity::BlockEntityType::get_block_entity(b).is_some() {
let pos = Position::new(
(bi & 0xF) as i32,
(bi >> 8) as i32,
((bi >> 4) & 0xF) as i32
) + (chunk.position.0 << 4, (i << 4) as i32, chunk.position.1 << 4);
((bi >> 4) & 0xF) as i32,
) + (
chunk.position.0 << 4,
(i << 4) as i32,
chunk.position.1 << 4,
);
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 {
pub fn make_relative(&mut self, x: i32, y: i32, z: i32) {
self.x = x;
self.y = y;
@ -1033,10 +1219,8 @@ impl Chunk {
Chunk {
position: pos,
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],
biomes: [0; 16 * 16],
@ -1047,13 +1231,13 @@ impl Chunk {
}
fn calculate_heightmap(&mut self) {
for x in 0 .. 16 {
for z in 0 .. 16 {
let idx = ((z<<4)|x) as usize;
for yy in 0 .. 256 {
for x in 0..16 {
for z in 0..16 {
let idx = ((z << 4) | x) as usize;
for yy in 0..256 {
let sy = 255 - yy;
if let block::Air{..} = self.get_block(x, sy, z) {
continue
if let block::Air { .. } = self.get_block(x, sy, z) {
continue;
}
self.heightmap[idx] = sy as u8;
break;
@ -1073,9 +1257,7 @@ impl Chunk {
if let block::Air {} = b {
return false;
}
let fill_sky = self.sections.iter()
.skip(s_idx)
.all(|v| v.is_none());
let fill_sky = self.sections.iter().skip(s_idx).all(|v| v.is_none());
self.sections[s_idx] = Some(Section::new(s_idx as u8, fill_sky));
}
{
@ -1084,16 +1266,16 @@ impl Chunk {
return false;
}
}
let idx = ((z<<4)|x) as usize;
let idx = ((z << 4) | x) as usize;
if self.heightmap[idx] < y as u8 {
self.heightmap[idx] = y as u8;
self.heightmap_dirty = true;
} else if self.heightmap[idx] == y as u8 {
// Find a new lowest
for yy in 0 .. y {
for yy in 0..y {
let sy = y - yy - 1;
if let block::Air{..} = self.get_block(x, sy, z) {
continue
if let block::Air { .. } = self.get_block(x, sy, z) {
continue;
}
self.heightmap[idx] = sy as u8;
break;
@ -1106,11 +1288,11 @@ impl Chunk {
fn get_block(&self, x: i32, y: i32, z: i32) -> block::Block {
let s_idx = y >> 4;
if s_idx < 0 || s_idx > 15 {
return block::Missing{};
return block::Missing {};
}
match self.sections[s_idx as usize].as_ref() {
Some(sec) => sec.get_block(x, y & 0xF, z),
None => block::Air{},
None => block::Air {},
}
}
@ -1135,9 +1317,7 @@ impl Chunk {
if light == 0 {
return;
}
let fill_sky = self.sections.iter()
.skip(s_idx)
.all(|v| v.is_none());
let fill_sky = self.sections.iter().skip(s_idx).all(|v| v.is_none());
self.sections[s_idx] = Some(Section::new(s_idx as u8, fill_sky));
}
if let Some(sec) = self.sections[s_idx].as_mut() {
@ -1166,9 +1346,7 @@ impl Chunk {
if light == 15 {
return;
}
let fill_sky = self.sections.iter()
.skip(s_idx)
.all(|v| v.is_none());
let fill_sky = self.sections.iter().skip(s_idx).all(|v| v.is_none());
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() {
@ -1177,7 +1355,7 @@ impl Chunk {
}
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,
};
if fill_sky {
for i in 0 .. 16*16*16 {
for i in 0..16 * 16 * 16 {
section.sky_light.set(i, 0xF);
}
}

View File

@ -1,4 +1,3 @@
use crate::types::bit;
use crate::types::hash::FNVHash;
use crate::world::block;
@ -14,15 +13,13 @@ pub struct BlockStorage {
impl 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 {
let mut storage = BlockStorage {
blocks: bit::Map::new(size, 4),
block_map: vec![
(def, size as u32)
],
block_map: vec![(def, size as u32)],
rev_block_map: HashMap::with_hasher(BuildHasherDefault::default()),
};
storage.rev_block_map.insert(def, 0);
@ -45,7 +42,8 @@ impl BlockStorage {
let idx = *self.rev_block_map.get(&old).unwrap();
let info = &mut self.block_map[idx];
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);
}
}