Reformat all source with cargo fmt (#335)
This commit is contained in:
parent
7279f4177e
commit
518b6a07f8
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
pub struct Material {
|
||||
pub renderable: bool,
|
||||
pub should_cull_against: bool,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! create_ids {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -137,5 +137,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -168,5 +168,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -170,5 +170,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -141,5 +141,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -141,5 +141,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -148,5 +148,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -165,5 +165,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -175,5 +175,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -175,5 +175,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -175,5 +175,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -175,5 +175,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -176,5 +176,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -176,5 +176,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -124,5 +124,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -135,5 +135,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -142,5 +142,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -142,5 +142,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
use std::hash::Hasher;
|
||||
|
||||
pub struct FNVHash(u64);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
|
||||
include!(concat!(env!("OUT_DIR"), "/resources.rs"));
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Axis {
|
||||
Y,
|
||||
Z,
|
||||
X,
|
||||
None
|
||||
None,
|
||||
}
|
||||
|
||||
impl Axis {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
pub mod axis;
|
||||
pub use self::axis::Axis;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {}
|
||||
|
|
240
src/ecs/mod.rs
240
src/ecs/mod.rs
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
422
src/gl/mod.rs
422
src/gl/mod.rs
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
397
src/main.rs
397
src/main.rs
|
@ -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) => (),
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
556
src/model/mod.rs
556
src/model/mod.rs
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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]
|
||||
|
|
269
src/render/ui.rs
269
src/render/ui.rs
|
@ -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 {
|
||||
|
|
149
src/resources.rs
149
src/resources.rs
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
1160
src/server/mod.rs
1160
src/server/mod.rs
File diff suppressed because it is too large
Load Diff
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
]],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
401
src/ui/mod.rs
401
src/ui/mod.rs
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
562
src/world/mod.rs
562
src/world/mod.rs
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue