Merge branch 'master' into 1.13_assets
This commit is contained in:
commit
8f614e2f28
|
@ -17,7 +17,7 @@ jobs:
|
|||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: 1.44.1
|
||||
toolchain: 1.49.0
|
||||
components: clippy, rustfmt
|
||||
default: true
|
||||
- name: Install dependencies
|
||||
|
|
File diff suppressed because it is too large
Load Diff
40
Cargo.toml
40
Cargo.toml
|
@ -18,37 +18,37 @@ path = "src/main.rs"
|
|||
opt-level = 1
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "0.1.9"
|
||||
wasm-bindgen = "0.2.64"
|
||||
glutin = "0.22.0"
|
||||
cfg-if = "1.0.0"
|
||||
wasm-bindgen = "0.2.69"
|
||||
winit = { version = "0.24.0", features = [ "web-sys" ]}
|
||||
glow = "0.7.1"
|
||||
byteorder = "1.3.4"
|
||||
serde = "1.0.114"
|
||||
serde_json = "1.0.56"
|
||||
flate2 = { version = "1.0.16", features = ["rust_backend"], default-features = false }
|
||||
serde = "1.0.118"
|
||||
serde_json = "1.0.61"
|
||||
flate2 = { version = "1.0.19", features = ["rust_backend"], default-features = false }
|
||||
zip = { version = "0.5.6", features = ["deflate"], default-features = false }
|
||||
image = "0.23.6"
|
||||
rand = "0.7.3"
|
||||
rand_pcg = "0.2.1"
|
||||
base64 = "0.12.3"
|
||||
log = { version = "0.4.8", features = ["std"] }
|
||||
image = "0.23.12"
|
||||
getrandom = { version = "0.2", features = ["js"] }
|
||||
rand = "0.8.0"
|
||||
rand_pcg = "0.3.0"
|
||||
base64 = "0.13.0"
|
||||
log = { version = "0.4.11", features = ["std"] }
|
||||
cgmath = "0.17.0"
|
||||
lazy_static = "1.4.0"
|
||||
collision = "0.20.1"
|
||||
rsa_public_encrypt_pkcs1 = "0.2.0"
|
||||
structopt = "0.3.15"
|
||||
rsa_public_encrypt_pkcs1 = "0.3.0"
|
||||
structopt = "0.3.21"
|
||||
clipboard = "0.5.0"
|
||||
instant = "0.1.9"
|
||||
# clippy = "*"
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
reqwest = { version = "0.10.6", features = [ "blocking" ]}
|
||||
reqwest = { version = "0.10.10", features = [ "blocking" ]}
|
||||
glutin = "0.26.0"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
stdweb = "0.4.20"
|
||||
winit = { version = "0.20.0", features = [ "stdweb" ]}
|
||||
|
||||
[dependencies.steven_gl]
|
||||
path = "./gl"
|
||||
version = "0"
|
||||
console_error_panic_hook = "0.1.6"
|
||||
web-sys = "0.3.46"
|
||||
|
||||
[dependencies.steven_resources]
|
||||
path = "./resources"
|
||||
|
|
30
README.md
30
README.md
|
@ -1,7 +1,7 @@
|
|||
# Stevenarella
|
||||
[![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Ficeiix%2Fstevenarella%2Fbadge%3Fref%3Dmaster&style=plastic)](https://actions-badge.atrox.dev/iceiix/stevenarella/goto?ref=master)
|
||||
|
||||
Multi-protocol Minecraft-compatible client written in Rust
|
||||
Multi-protocol Minecraft-compatible client written in Rust.
|
||||
|
||||
Don't expect it to go anywhere, just doing this for fun.
|
||||
|
||||
|
@ -13,16 +13,20 @@ Don't expect it to go anywhere, just doing this for fun.
|
|||
|
||||
In action: http://gfycat.com/NeedyElaborateGypsymoth
|
||||
|
||||
## Community chatroom
|
||||
## Community
|
||||
|
||||
We have a chatroom on [EsperNet](https://esper.net): `irc.esper.net` server, `#stevenarella` channel.
|
||||
IRC channels: `#stevenarella` on [irc.freenode.net](https://freenode.net), or `#stevenarella` on [irc.esper.net](https://esper.net).
|
||||
|
||||
Discussion forum: [https://github.com/iceiix/stevenarella/discussions](https://github.com/iceiix/stevenarella/discussions).
|
||||
|
||||
Join with your favorite IRC client.
|
||||
|
||||
## Protocol support
|
||||
|
||||
| Game version | Protocol version | Supported? |
|
||||
| ------ | --- | --- |
|
||||
| 1.16.4 | 754 | ✓ |
|
||||
| 1.16.3 | 753 | ✓ |
|
||||
| 1.16.2 | 751 | ✓ |
|
||||
| 1.16.1 | 736 | ✓ |
|
||||
| 1.16 | 735 | ✓ |
|
||||
| 1.15.2 | 578 | ✓ |
|
||||
|
@ -60,9 +64,23 @@ Windows, Ubuntu Linux, and macOS users can download pre-compiled builds
|
|||
from [GitHub Actions](https://actions-badge.atrox.dev/iceiix/stevenarella/goto?ref=master).
|
||||
(Click the artifacts drop-down and select your platform.)
|
||||
|
||||
## Building
|
||||
## Dependencies
|
||||
|
||||
Requires Rust stable version 1.44.1 or newer to build.
|
||||
Requires Rust stable version 1.49.0 or newer.
|
||||
|
||||
**Debian/Ubuntu**
|
||||
|
||||
```bash
|
||||
sudo apt-get install libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxcb-composite0-dev
|
||||
```
|
||||
|
||||
**Alpine Linux**
|
||||
|
||||
```bash
|
||||
sudo apk add openssl-dev xcb-util-dev
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
Compile and run:
|
||||
```bash
|
||||
|
|
|
@ -2245,10 +2245,7 @@ define_blocks! {
|
|||
model { ("minecraft", "iron_bars") },
|
||||
collision pane_collision(north, south, east, west),
|
||||
update_state (world, pos) => {
|
||||
let f = |block| match block {
|
||||
Block::IronBars{..} => true,
|
||||
_ => false,
|
||||
};
|
||||
let f = |block| matches!(block, Block::IronBars{..});
|
||||
|
||||
let (north, south, west, east) = can_connect_sides(world, pos, &f);
|
||||
Block::IronBars{north, south, west, east, waterlogged}
|
||||
|
@ -2574,16 +2571,13 @@ define_blocks! {
|
|||
model { ("minecraft", "nether_brick_fence") },
|
||||
collision fence_collision(north, south, west, east),
|
||||
update_state (world, pos) => {
|
||||
let f = |block| match block {
|
||||
Block::NetherBrickFence{..} |
|
||||
let f = |block| matches!(block, Block::NetherBrickFence{..} |
|
||||
Block::FenceGate{..} |
|
||||
Block::SpruceFenceGate{..} |
|
||||
Block::BirchFenceGate{..} |
|
||||
Block::JungleFenceGate{..} |
|
||||
Block::DarkOakFenceGate{..} |
|
||||
Block::AcaciaFenceGate{..} => true,
|
||||
_ => false,
|
||||
};
|
||||
Block::AcaciaFenceGate{..});
|
||||
|
||||
let (north, south, west, east) = can_connect_sides(world, pos, &f);
|
||||
Block::NetherBrickFence{north, south, west, east, waterlogged}
|
||||
|
@ -3075,22 +3069,17 @@ define_blocks! {
|
|||
material material::NON_SOLID,
|
||||
model { ("minecraft", format!("{}_wall", variant.as_string())) },
|
||||
update_state (world, pos) => {
|
||||
let f = |block| match block {
|
||||
Block::CobblestoneWall{..} |
|
||||
let f = |block| matches!(block, Block::CobblestoneWall{..} |
|
||||
Block::FenceGate{..} |
|
||||
Block::SpruceFenceGate{..} |
|
||||
Block::BirchFenceGate{..} |
|
||||
Block::JungleFenceGate{..} |
|
||||
Block::DarkOakFenceGate{..} |
|
||||
Block::AcaciaFenceGate{..} => true,
|
||||
_ => false,
|
||||
};
|
||||
Block::AcaciaFenceGate{..});
|
||||
|
||||
let (north, south, west, east) = can_connect_sides(world, pos, &f);
|
||||
let up = !(match world.get_block(pos.shift(Direction::Up)) {
|
||||
Block::Air{..} => true,
|
||||
_ => false,
|
||||
}) || !((north && south && !west && !east) || (!north && !south && west && east));
|
||||
let up = !(matches!(world.get_block(pos.shift(Direction::Up)), Block::Air{..}))
|
||||
|| !((north && south && !west && !east) || (!north && !south && west && east));
|
||||
Block::CobblestoneWall{up, north, south, west, east, variant, waterlogged}
|
||||
},
|
||||
multipart (key, val) => match key {
|
||||
|
@ -4686,12 +4675,12 @@ define_blocks! {
|
|||
collision
|
||||
},
|
||||
update_state (world, pos) => Block::ChorusPlant {
|
||||
up: match world.get_block(pos.shift(Direction::Up)) { Block::ChorusPlant{..} | Block::ChorusFlower{..} => true, _ => false,},
|
||||
down: match world.get_block(pos.shift(Direction::Down)) { Block::ChorusPlant{..} | Block::ChorusFlower{..} | Block::EndStone{..} => true, _ => false,},
|
||||
north: match world.get_block(pos.shift(Direction::North)) { Block::ChorusPlant{..} | Block::ChorusFlower{..} => true, _ => false,},
|
||||
south: match world.get_block(pos.shift(Direction::South)) { Block::ChorusPlant{..} | Block::ChorusFlower{..} => true, _ => false,},
|
||||
west: match world.get_block(pos.shift(Direction::West)) { Block::ChorusPlant{..} | Block::ChorusFlower{..} => true, _ => false,},
|
||||
east: match world.get_block(pos.shift(Direction::East)) { Block::ChorusPlant{..} | Block::ChorusFlower{..} => true, _ => false,},
|
||||
up: matches!(world.get_block(pos.shift(Direction::Up)), Block::ChorusPlant{..} | Block::ChorusFlower{..}),
|
||||
down: matches!(world.get_block(pos.shift(Direction::Down)), Block::ChorusPlant{..} | Block::ChorusFlower{..} | Block::EndStone{..}),
|
||||
north: matches!(world.get_block(pos.shift(Direction::North)), Block::ChorusPlant{..} | Block::ChorusFlower{..}),
|
||||
south: matches!(world.get_block(pos.shift(Direction::South)), Block::ChorusPlant{..} | Block::ChorusFlower{..}),
|
||||
west: matches!(world.get_block(pos.shift(Direction::West)), Block::ChorusPlant{..} | Block::ChorusFlower{..}),
|
||||
east: matches!(world.get_block(pos.shift(Direction::East)), Block::ChorusPlant{..} | Block::ChorusFlower{..}),
|
||||
},
|
||||
multipart (key, val) => match key {
|
||||
"up" => up == (val == "true"),
|
||||
|
@ -5626,8 +5615,7 @@ define_blocks! {
|
|||
}
|
||||
|
||||
fn can_burn<W: WorldAccess>(world: &W, pos: Position) -> bool {
|
||||
match world.get_block(pos) {
|
||||
Block::Planks { .. }
|
||||
matches!(world.get_block(pos), Block::Planks { .. }
|
||||
| Block::DoubleWoodenSlab { .. }
|
||||
| Block::WoodenSlab { .. }
|
||||
| Block::FenceGate { .. }
|
||||
|
@ -5663,16 +5651,11 @@ fn can_burn<W: WorldAccess>(world: &W, pos: Position) -> bool {
|
|||
| Block::Vine { .. }
|
||||
| Block::CoalBlock { .. }
|
||||
| Block::HayBlock { .. }
|
||||
| Block::Carpet { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
| Block::Carpet { .. })
|
||||
}
|
||||
|
||||
fn is_snowy<W: WorldAccess>(world: &W, pos: Position) -> bool {
|
||||
match world.get_block(pos.shift(Direction::Up)) {
|
||||
Block::Snow { .. } | Block::SnowLayer { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(world.get_block(pos.shift(Direction::Up)), Block::Snow { .. } | Block::SnowLayer { .. })
|
||||
}
|
||||
|
||||
fn can_connect_sides<F: Fn(Block) -> bool, W: WorldAccess>(
|
||||
|
@ -5694,8 +5677,7 @@ 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 { .. }
|
||||
matches!(block, Block::Fence { .. }
|
||||
| Block::SpruceFence { .. }
|
||||
| Block::BirchFence { .. }
|
||||
| Block::JungleFence { .. }
|
||||
|
@ -5706,19 +5688,14 @@ fn can_connect_fence(block: Block) -> bool {
|
|||
| Block::BirchFenceGate { .. }
|
||||
| Block::JungleFenceGate { .. }
|
||||
| Block::DarkOakFenceGate { .. }
|
||||
| Block::AcaciaFenceGate { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
| Block::AcaciaFenceGate { .. })
|
||||
}
|
||||
|
||||
fn can_connect_glasspane(block: Block) -> bool {
|
||||
match block {
|
||||
Block::Glass { .. }
|
||||
matches!(block, Block::Glass { .. }
|
||||
| Block::StainedGlass { .. }
|
||||
| Block::GlassPane { .. }
|
||||
| Block::StainedGlassPane { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
| Block::StainedGlassPane { .. })
|
||||
}
|
||||
|
||||
fn can_connect_redstone<W: WorldAccess>(world: &W, pos: Position, dir: Direction) -> RedstoneSide {
|
||||
|
@ -5729,11 +5706,7 @@ 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 matches!(side_up, Block::RedstoneWire { .. }) && !up.get_material().should_cull_against {
|
||||
return RedstoneSide::Up;
|
||||
}
|
||||
|
||||
|
@ -5741,13 +5714,9 @@ 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 matches!(block, Block::RedstoneWire { .. })
|
||||
|| matches!(side_down, Block::RedstoneWire { .. })
|
||||
{
|
||||
return RedstoneSide::Side;
|
||||
}
|
||||
RedstoneSide::None
|
||||
|
@ -5961,10 +5930,7 @@ fn door_collision(facing: Direction, hinge: Side, open: bool) -> Vec<Aabb3<f64>>
|
|||
}
|
||||
|
||||
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| matches!(world.get_block(pos.shift(dir)), Block::RepeaterPowered { .. });
|
||||
|
||||
f(facing.clockwise()) || f(facing.counter_clockwise())
|
||||
}
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "gl_generator"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "khronos_api"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "steven_gl"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"gl_generator 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum gl_generator 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"
|
||||
"checksum khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
||||
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
"checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5"
|
|
@ -1,13 +0,0 @@
|
|||
[package]
|
||||
name = "steven_gl"
|
||||
version = "0.0.1"
|
||||
authors = [ "Thinkofdeath <thinkofdeath@spigotmc.org>" ]
|
||||
edition = "2018"
|
||||
build = "build.rs"
|
||||
|
||||
[build-dependencies]
|
||||
gl_generator = "0.14.0"
|
||||
khronos_api = "3.1.0"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.71"
|
15
gl/build.rs
15
gl/build.rs
|
@ -1,15 +0,0 @@
|
|||
use gl_generator::{Api, Fallbacks, GlobalGenerator, Profile, Registry};
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::BufWriter;
|
||||
use std::path::Path;
|
||||
|
||||
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, [])
|
||||
.write_bindings(GlobalGenerator, &mut file)
|
||||
.unwrap();
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
#![allow(clippy::unused_unit)]
|
||||
#![allow(clippy::missing_safety_doc)]
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
File diff suppressed because it is too large
Load Diff
|
@ -5,16 +5,17 @@ authors = [ "Thinkofdeath <thinkofdeath@spigotmc.org>", "iceiix <ice_ix@protonma
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
serde = "1.0.114"
|
||||
serde_json = "1.0.56"
|
||||
serde = "1.0.118"
|
||||
serde_json = "1.0.60"
|
||||
hex = "0.4.2"
|
||||
sha-1 = "0.9.1"
|
||||
aes = "0.4.0"
|
||||
cfb8 = "0.4.0"
|
||||
byteorder = "1.3.4"
|
||||
log = { version = "0.4.8", features = ["std"] }
|
||||
flate2 = { version = "1.0.16", features = ["rust_backend"], default-features = false }
|
||||
log = { version = "0.4.11", features = ["std"] }
|
||||
flate2 = { version = "1.0.19", features = ["rust_backend"], default-features = false }
|
||||
num-traits = "0.2.12"
|
||||
instant = "0.1.9"
|
||||
|
||||
[dependencies.steven_shared]
|
||||
path = "../shared"
|
||||
|
@ -25,4 +26,4 @@ path = "../std_or_web"
|
|||
version = "0"
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
reqwest = { version = "0.10.6", features = [ "blocking" ]}
|
||||
reqwest = { version = "0.10.10", features = [ "blocking" ]}
|
||||
|
|
|
@ -323,8 +323,8 @@ 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 ('a'..='f').contains(&color_char)
|
||||
|| ('0'..='9').contains(&color_char)
|
||||
{
|
||||
Default::default()
|
||||
} else {
|
||||
|
|
|
@ -72,10 +72,7 @@ impl Tag {
|
|||
}
|
||||
|
||||
pub fn is_compound(&self) -> bool {
|
||||
match *self {
|
||||
Tag::Compound(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(*self, Tag::Compound(_))
|
||||
}
|
||||
|
||||
pub fn as_byte(&self) -> Option<i8> {
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
use aes::Aes128;
|
||||
use cfb8::stream_cipher::{NewStreamCipher, StreamCipher};
|
||||
use cfb8::Cfb8;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use std_or_web::fs;
|
||||
|
||||
pub mod forge;
|
||||
|
@ -30,6 +29,7 @@ use crate::shared::Position;
|
|||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use flate2::read::{ZlibDecoder, ZlibEncoder};
|
||||
use flate2::Compression;
|
||||
use instant::{Duration, Instant};
|
||||
use log::debug;
|
||||
use std::convert;
|
||||
use std::default;
|
||||
|
@ -38,11 +38,10 @@ 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; 21] = [
|
||||
736, 735, 578, 575, 498, 490, 485, 480, 477, 452, 451, 404, 340, 316, 315, 210, 109, 107, 74,
|
||||
47, 5,
|
||||
pub const SUPPORTED_PROTOCOLS: [i32; 24] = [
|
||||
754, 753, 751, 736, 735, 578, 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]);
|
||||
|
@ -119,7 +118,7 @@ macro_rules! state_packets {
|
|||
packet::versions::translate_internal_packet_id_for_version(version, State::$stateName, Direction::$dirName, internal_ids::$name, false)
|
||||
}
|
||||
|
||||
fn write<W: io::Write>(self, buf: &mut W) -> Result<(), Error> {
|
||||
fn write<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
$(
|
||||
if true $(&& ($cond(&self)))* {
|
||||
self.$field.write_to(buf)?;
|
||||
|
@ -1156,6 +1155,8 @@ impl Conn {
|
|||
let pos = buf.position() as usize;
|
||||
let ibuf = buf.into_inner();
|
||||
if ibuf.len() != pos {
|
||||
debug!("pos = {:?}", pos);
|
||||
debug!("ibuf = {:?}", ibuf);
|
||||
return Result::Err(Error::Err(format!(
|
||||
"Failed to read all of packet 0x{:X}, \
|
||||
had {} bytes left",
|
||||
|
@ -1306,6 +1307,44 @@ impl Conn {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parse a clientbound packet, for debugging packet parsing issues (Conn::read_packet)
|
||||
pub fn try_parse_packet(ibuf: Vec<u8>, protocol_version: i32) {
|
||||
println!("trying to parse packet data {:?}", ibuf);
|
||||
|
||||
let mut buf = io::Cursor::new(ibuf);
|
||||
|
||||
let id = VarInt::read_from(&mut buf).unwrap().0;
|
||||
let dir = Direction::Clientbound;
|
||||
let state = State::Play; // TODO: allow parsing other states
|
||||
|
||||
println!(
|
||||
"about to parse id={:x}, dir={:?} state={:?}",
|
||||
id, dir, state
|
||||
);
|
||||
|
||||
let packet = packet::packet_by_id(protocol_version, state, dir, id, &mut buf).unwrap();
|
||||
|
||||
println!("packet = {:?}", packet);
|
||||
|
||||
match packet {
|
||||
Some(_val) => {
|
||||
let pos = buf.position() as usize;
|
||||
let ibuf = buf.into_inner();
|
||||
if ibuf.len() != pos {
|
||||
println!("pos = {:?}", pos);
|
||||
println!("ibuf = {:?}", ibuf);
|
||||
println!(
|
||||
"Failed to read all of packet 0x{:X}, \
|
||||
had {} bytes left",
|
||||
id,
|
||||
ibuf.len() - pos
|
||||
)
|
||||
}
|
||||
}
|
||||
None => println!("missing packet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Status {
|
||||
pub version: StatusVersion,
|
||||
|
@ -1387,5 +1426,5 @@ impl Clone for Conn {
|
|||
pub trait PacketType {
|
||||
fn packet_id(&self, protocol_version: i32) -> i32;
|
||||
|
||||
fn write<W: io::Write>(self, buf: &mut W) -> Result<(), Error>;
|
||||
fn write<W: io::Write>(&self, buf: &mut W) -> Result<(), Error>;
|
||||
}
|
||||
|
|
|
@ -353,6 +353,16 @@ state_packets!(
|
|||
field crafting_book_open: bool = when(|p: &CraftingBookData| p.action.0 == 1),
|
||||
field crafting_filter: bool = when(|p: &CraftingBookData| p.action.0 == 1),
|
||||
}
|
||||
/// SetDisplayedRecipe replaces CraftingBookData, type 0.
|
||||
packet SetDisplayedRecipe {
|
||||
field recipe_id: String =,
|
||||
}
|
||||
/// SetRecipeBookState replaces CraftingBookData, type 1.
|
||||
packet SetRecipeBookState {
|
||||
field book_id: VarInt =, // TODO: enum, 0: crafting, 1: furnace, 2: blast furnace, 3: smoker
|
||||
field book_open: bool =,
|
||||
field filter_active: bool =,
|
||||
}
|
||||
packet NameItem {
|
||||
field item_name: String =,
|
||||
}
|
||||
|
@ -881,6 +891,11 @@ state_packets!(
|
|||
field message: format::Component =,
|
||||
}
|
||||
/// MultiBlockChange is used to update a batch of blocks in a single packet.
|
||||
packet MultiBlockChange_Packed {
|
||||
field chunk_section_pos: u64 =,
|
||||
field no_trust_edges: bool =,
|
||||
field records: LenPrefixed<VarInt, VarLong> =,
|
||||
}
|
||||
packet MultiBlockChange_VarInt {
|
||||
field chunk_x: i32 =,
|
||||
field chunk_z: i32 =,
|
||||
|
@ -1047,6 +1062,16 @@ state_packets!(
|
|||
}
|
||||
/// ChunkData sends or updates a single chunk on the client. If New is set
|
||||
/// then biome data should be sent too.
|
||||
packet ChunkData_Biomes3D_VarInt {
|
||||
field chunk_x: i32 =,
|
||||
field chunk_z: i32 =,
|
||||
field new: bool =,
|
||||
field bitmask: VarInt =,
|
||||
field heightmaps: Option<nbt::NamedTag> =,
|
||||
field biomes: LenPrefixed<VarInt, VarInt> = when(|p: &ChunkData_Biomes3D_VarInt| p.new),
|
||||
field data: LenPrefixedBytes<VarInt> =,
|
||||
field block_entities: LenPrefixed<VarInt, Option<nbt::NamedTag>> =,
|
||||
}
|
||||
packet ChunkData_Biomes3D_bool {
|
||||
field chunk_x: i32 =,
|
||||
field chunk_z: i32 =,
|
||||
|
@ -1148,12 +1173,12 @@ state_packets!(
|
|||
field offset_z: f32 =,
|
||||
field speed: f32 =,
|
||||
field count: i32 =,
|
||||
field block_state: VarInt = when(|p: &Particle_f64| p.particle_id == 3 || p.particle_id == 20),
|
||||
field red: f32 = when(|p: &Particle_f64| p.particle_id == 11),
|
||||
field green: f32 = when(|p: &Particle_f64| p.particle_id == 11),
|
||||
field blue: f32 = when(|p: &Particle_f64| p.particle_id == 11),
|
||||
field scale: f32 = when(|p: &Particle_f64| p.particle_id == 11),
|
||||
field item: Option<nbt::NamedTag> = when(|p: &Particle_f64| p.particle_id == 27),
|
||||
field block_state: VarInt = when(|p: &Particle_f64| p.particle_id == 3 || p.particle_id == 23),
|
||||
field red: f32 = when(|p: &Particle_f64| p.particle_id == 14),
|
||||
field green: f32 = when(|p: &Particle_f64| p.particle_id == 14),
|
||||
field blue: f32 = when(|p: &Particle_f64| p.particle_id == 14),
|
||||
field scale: f32 = when(|p: &Particle_f64| p.particle_id == 14),
|
||||
field item: Option<nbt::NamedTag> = when(|p: &Particle_f64| p.particle_id == 32),
|
||||
}
|
||||
packet Particle_Data {
|
||||
field particle_id: i32 =,
|
||||
|
@ -1166,12 +1191,30 @@ state_packets!(
|
|||
field offset_z: f32 =,
|
||||
field speed: f32 =,
|
||||
field count: i32 =,
|
||||
field block_state: VarInt = when(|p: &Particle_Data| p.particle_id == 3 || p.particle_id == 20),
|
||||
field red: f32 = when(|p: &Particle_Data| p.particle_id == 11),
|
||||
field green: f32 = when(|p: &Particle_Data| p.particle_id == 11),
|
||||
field blue: f32 = when(|p: &Particle_Data| p.particle_id == 11),
|
||||
field scale: f32 = when(|p: &Particle_Data| p.particle_id == 11),
|
||||
field item: Option<nbt::NamedTag> = when(|p: &Particle_Data| p.particle_id == 27),
|
||||
field block_state: VarInt = when(|p: &Particle_Data| p.particle_id == 3 || p.particle_id == 23),
|
||||
field red: f32 = when(|p: &Particle_Data| p.particle_id == 14),
|
||||
field green: f32 = when(|p: &Particle_Data| p.particle_id == 14),
|
||||
field blue: f32 = when(|p: &Particle_Data| p.particle_id == 14),
|
||||
field scale: f32 = when(|p: &Particle_Data| p.particle_id == 14),
|
||||
field item: Option<nbt::NamedTag> = when(|p: &Particle_Data| p.particle_id == 32),
|
||||
}
|
||||
packet Particle_Data13 {
|
||||
field particle_id: i32 =,
|
||||
field long_distance: bool =,
|
||||
field x: f32 =,
|
||||
field y: f32 =,
|
||||
field z: f32 =,
|
||||
field offset_x: f32 =,
|
||||
field offset_y: f32 =,
|
||||
field offset_z: f32 =,
|
||||
field speed: f32 =,
|
||||
field count: i32 =,
|
||||
field block_state: VarInt = when(|p: &Particle_Data13| p.particle_id == 3 || p.particle_id == 20),
|
||||
field red: f32 = when(|p: &Particle_Data13| p.particle_id == 11),
|
||||
field green: f32 = when(|p: &Particle_Data13| p.particle_id == 11),
|
||||
field blue: f32 = when(|p: &Particle_Data13| p.particle_id == 11),
|
||||
field scale: f32 = when(|p: &Particle_Data13| p.particle_id == 11),
|
||||
field item: Option<nbt::NamedTag> = when(|p: &Particle_Data13| p.particle_id == 27),
|
||||
}
|
||||
packet Particle_VarIntArray {
|
||||
field particle_id: i32 =,
|
||||
|
@ -1200,6 +1243,39 @@ state_packets!(
|
|||
}
|
||||
/// JoinGame is sent after completing the login process. This
|
||||
/// sets the initial state for the client.
|
||||
packet JoinGame_WorldNames_IsHard {
|
||||
/// The entity id the client will be referenced by
|
||||
field entity_id: i32 =,
|
||||
/// Whether hardcore mode is enabled
|
||||
field is_hardcore: bool =,
|
||||
/// The starting gamemode of the client
|
||||
field gamemode: u8 =,
|
||||
/// The previous gamemode of the client
|
||||
field previous_gamemode: u8 =,
|
||||
/// Identifiers for all worlds on the server
|
||||
field world_names: LenPrefixed<VarInt, String> =,
|
||||
/// Represents a dimension registry
|
||||
field dimension_codec: Option<nbt::NamedTag> =,
|
||||
/// The dimension the client is starting in
|
||||
field dimension: Option<nbt::NamedTag> =,
|
||||
/// The world being spawned into
|
||||
field world_name: String =,
|
||||
/// Truncated SHA-256 hash of world's seed
|
||||
field hashed_seed: i64 =,
|
||||
/// The max number of players on the server
|
||||
field max_players: VarInt =,
|
||||
/// The render distance (2-32)
|
||||
field view_distance: VarInt =,
|
||||
/// Whether the client should reduce the amount of debug
|
||||
/// information it displays in F3 mode
|
||||
field reduced_debug_info: bool =,
|
||||
/// Whether to prompt or immediately respawn
|
||||
field enable_respawn_screen: bool =,
|
||||
/// Whether the world is in debug mode
|
||||
field is_debug: bool =,
|
||||
/// Whether the world is a superflat world
|
||||
field is_flat: bool =,
|
||||
}
|
||||
packet JoinGame_WorldNames {
|
||||
/// The entity id the client will be referenced by
|
||||
field entity_id: i32 =,
|
||||
|
@ -1231,7 +1307,6 @@ state_packets!(
|
|||
/// Whether the world is a superflat world
|
||||
field is_flat: bool =,
|
||||
}
|
||||
|
||||
packet JoinGame_HashedSeed_Respawn {
|
||||
/// The entity id the client will be referenced by
|
||||
field entity_id: i32 =,
|
||||
|
@ -1317,6 +1392,7 @@ state_packets!(
|
|||
field item_damage: VarInt =,
|
||||
field scale: i8 =,
|
||||
field tracking_position: bool =,
|
||||
field locked: bool =,
|
||||
field icons: LenPrefixed<VarInt, packet::MapIcon> =,
|
||||
field columns: u8 =,
|
||||
field rows: Option<u8> = when(|p: &Maps| p.columns > 0),
|
||||
|
@ -1324,6 +1400,17 @@ state_packets!(
|
|||
field z: Option<u8> = when(|p: &Maps| p.columns > 0),
|
||||
field data: Option<LenPrefixedBytes<VarInt>> = when(|p: &Maps| p.columns > 0),
|
||||
}
|
||||
packet Maps_NoLocked {
|
||||
field item_damage: VarInt =,
|
||||
field scale: i8 =,
|
||||
field tracking_position: bool =,
|
||||
field icons: LenPrefixed<VarInt, packet::MapIcon> =,
|
||||
field columns: u8 =,
|
||||
field rows: Option<u8> = when(|p: &Maps_NoLocked| p.columns > 0),
|
||||
field x: Option<u8> = when(|p: &Maps_NoLocked| p.columns > 0),
|
||||
field z: Option<u8> = when(|p: &Maps_NoLocked| p.columns > 0),
|
||||
field data: Option<LenPrefixedBytes<VarInt>> = when(|p: &Maps_NoLocked| p.columns > 0),
|
||||
}
|
||||
packet Maps_NoTracking {
|
||||
field item_damage: VarInt =,
|
||||
field scale: i8 =,
|
||||
|
@ -1527,6 +1614,19 @@ state_packets!(
|
|||
field recipe_ids: LenPrefixed<VarInt, String> =,
|
||||
field recipe_ids2: LenPrefixed<VarInt, String> = when(|p: &UnlockRecipes_WithSmelting| p.action.0 == 0),
|
||||
}
|
||||
packet UnlockRecipes_WithBlastSmoker {
|
||||
field action: VarInt =,
|
||||
field crafting_book_open: bool =,
|
||||
field filtering_craftable: bool =,
|
||||
field smelting_book_open: bool =,
|
||||
field filtering_smeltable: bool =,
|
||||
field blast_furnace_open: bool =,
|
||||
field filtering_blast_furnace: bool =,
|
||||
field smoker_open: bool =,
|
||||
field filtering_smoker: bool =,
|
||||
field recipe_ids: LenPrefixed<VarInt, String> =,
|
||||
field recipe_ids2: LenPrefixed<VarInt, String> = when(|p: &UnlockRecipes_WithBlastSmoker| p.action.0 == 0),
|
||||
}
|
||||
/// EntityDestroy destroys the entities with the ids in the provided slice.
|
||||
packet EntityDestroy {
|
||||
field entity_ids: LenPrefixed<VarInt, VarInt> =,
|
||||
|
@ -1564,6 +1664,16 @@ state_packets!(
|
|||
field gamemode: u8 =,
|
||||
field level_type: String =,
|
||||
}
|
||||
packet Respawn_NBT {
|
||||
field dimension: Option<nbt::NamedTag> =,
|
||||
field world_name: String =,
|
||||
field hashed_seed: i64 =,
|
||||
field gamemode: u8 =,
|
||||
field previous_gamemode: u8 =,
|
||||
field is_debug: bool =,
|
||||
field is_flat: bool =,
|
||||
field copy_metadata: bool =,
|
||||
}
|
||||
packet Respawn_WorldName {
|
||||
field dimension: String =,
|
||||
field world_name: String =,
|
||||
|
@ -1668,6 +1778,10 @@ state_packets!(
|
|||
/// EntityEquipment is sent to display an item on an entity, like a sword
|
||||
/// or armor. Slot 0 is the held item and slots 1 to 4 are boots, leggings
|
||||
/// chestplate and helmet respectively.
|
||||
packet EntityEquipment_Array {
|
||||
field entity_id: VarInt =,
|
||||
field equipments: packet::EntityEquipments =,
|
||||
}
|
||||
packet EntityEquipment_VarInt {
|
||||
field entity_id: VarInt =,
|
||||
field slot: VarInt =,
|
||||
|
@ -2435,6 +2549,57 @@ impl Serializable for CriterionProgress {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EntityEquipment {
|
||||
pub slot: u8,
|
||||
pub item: Option<item::Stack>,
|
||||
}
|
||||
|
||||
impl Serializable for EntityEquipment {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
Ok(EntityEquipment {
|
||||
slot: Serializable::read_from(buf)?,
|
||||
item: Serializable::read_from(buf)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
self.slot.write_to(buf)?;
|
||||
self.item.write_to(buf)
|
||||
}
|
||||
}
|
||||
|
||||
// Top-bit terminated array of EntityEquipment
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EntityEquipments {
|
||||
pub equipments: Vec<EntityEquipment>,
|
||||
}
|
||||
|
||||
impl Serializable for EntityEquipments {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
let mut equipments: Vec<EntityEquipment> = vec![];
|
||||
|
||||
loop {
|
||||
let e: EntityEquipment = Serializable::read_from(buf)?;
|
||||
equipments.push(EntityEquipment {
|
||||
slot: e.slot & 0x7f,
|
||||
item: e.item,
|
||||
});
|
||||
|
||||
if e.slot & 0x80 == 0 {
|
||||
break;
|
||||
}
|
||||
// TODO: detect infinite loop
|
||||
}
|
||||
|
||||
Ok(EntityEquipments { equipments })
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, _buf: &mut W) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EntityProperty {
|
||||
pub key: String,
|
||||
|
|
|
@ -14,6 +14,7 @@ mod v1_14_3;
|
|||
mod v1_14_4;
|
||||
mod v1_15;
|
||||
mod v1_16_1;
|
||||
mod v1_16_4;
|
||||
mod v1_7_10;
|
||||
mod v1_8_9;
|
||||
mod v1_9;
|
||||
|
@ -25,6 +26,9 @@ mod v1_9_2;
|
|||
pub fn protocol_name_to_protocol_version(s: String) -> i32 {
|
||||
match s.as_ref() {
|
||||
"" => SUPPORTED_PROTOCOLS[0],
|
||||
"1.16.4" => 754,
|
||||
"1.16.3" => 753,
|
||||
"1.16.2" => 751,
|
||||
"1.16.1" => 736,
|
||||
"1.16" => 735,
|
||||
"1.15.2" => 578,
|
||||
|
@ -64,6 +68,7 @@ pub fn translate_internal_packet_id_for_version(
|
|||
to_internal: bool,
|
||||
) -> i32 {
|
||||
match version {
|
||||
754 | 753 | 751 => v1_16_4::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
736 => v1_16_1::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
735 => v1_16_1::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
578 => v1_15::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
|
|
|
@ -74,7 +74,7 @@ protocol_packet_ids!(
|
|||
0x22 => Particle_VarIntArray
|
||||
0x23 => NamedSoundEffect_u8_NoCategory
|
||||
0x24 => JoinGame_i8
|
||||
0x25 => Maps
|
||||
0x25 => Maps_NoLocked
|
||||
0x26 => EntityMove_i8
|
||||
0x27 => EntityLookAndMove_i8
|
||||
0x28 => EntityLook_VarInt
|
||||
|
|
|
@ -91,7 +91,7 @@ protocol_packet_ids!(
|
|||
0x23 => Effect
|
||||
0x24 => Particle_VarIntArray
|
||||
0x25 => JoinGame_i32
|
||||
0x26 => Maps
|
||||
0x26 => Maps_NoLocked
|
||||
0x27 => Entity
|
||||
0x28 => EntityMove_i16
|
||||
0x29 => EntityLookAndMove_i16
|
||||
|
|
|
@ -89,7 +89,7 @@ protocol_packet_ids!(
|
|||
0x21 => KeepAliveClientbound_i64
|
||||
0x22 => ChunkData_HeightMap
|
||||
0x23 => Effect
|
||||
0x24 => Particle_Data
|
||||
0x24 => Particle_Data13
|
||||
0x25 => JoinGame_i32
|
||||
0x26 => Maps
|
||||
0x27 => Entity
|
||||
|
|
|
@ -76,7 +76,7 @@ protocol_packet_ids!(
|
|||
0x21 => Effect
|
||||
0x22 => Particle_VarIntArray
|
||||
0x23 => JoinGame_i32
|
||||
0x24 => Maps
|
||||
0x24 => Maps_NoLocked
|
||||
0x25 => EntityMove_i16
|
||||
0x26 => EntityLookAndMove_i16
|
||||
0x27 => EntityLook_VarInt
|
||||
|
|
|
@ -76,7 +76,7 @@ protocol_packet_ids!(
|
|||
0x21 => Effect
|
||||
0x22 => Particle_VarIntArray
|
||||
0x23 => JoinGame_i32
|
||||
0x24 => Maps
|
||||
0x24 => Maps_NoLocked
|
||||
0x25 => EntityMove_i16
|
||||
0x26 => EntityLookAndMove_i16
|
||||
0x27 => EntityLook_VarInt
|
||||
|
|
|
@ -79,7 +79,7 @@ protocol_packet_ids!(
|
|||
0x21 => Effect
|
||||
0x22 => Particle_VarIntArray
|
||||
0x23 => JoinGame_i32
|
||||
0x24 => Maps
|
||||
0x24 => Maps_NoLocked
|
||||
0x25 => Entity
|
||||
0x26 => EntityMove_i16
|
||||
0x27 => EntityLookAndMove_i16
|
||||
|
|
|
@ -89,9 +89,9 @@ protocol_packet_ids!(
|
|||
0x21 => KeepAliveClientbound_i64
|
||||
0x22 => ChunkData
|
||||
0x23 => Effect
|
||||
0x24 => Particle_Data
|
||||
0x24 => Particle_Data13
|
||||
0x25 => JoinGame_i32
|
||||
0x26 => Maps
|
||||
0x26 => Maps_NoLocked
|
||||
0x27 => Entity
|
||||
0x28 => EntityMove_i16
|
||||
0x29 => EntityLookAndMove_i16
|
||||
|
|
|
@ -128,7 +128,7 @@ protocol_packet_ids!(
|
|||
0x44 => EntityMetadata
|
||||
0x45 => EntityAttach
|
||||
0x46 => EntityVelocity
|
||||
0x47 => EntityEquipment_VarInt // TODO: changed to an array, but earlier than 1.16.1
|
||||
0x47 => EntityEquipment_Array
|
||||
0x48 => SetExperience
|
||||
0x49 => UpdateHealth
|
||||
0x4a => ScoreboardObjective
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
protocol_packet_ids!(
|
||||
handshake Handshaking {
|
||||
serverbound Serverbound {
|
||||
0x00 => Handshake
|
||||
}
|
||||
clientbound Clientbound {
|
||||
}
|
||||
}
|
||||
play Play {
|
||||
serverbound Serverbound {
|
||||
0x00 => TeleportConfirm
|
||||
0x01 => QueryBlockNBT
|
||||
0x02 => SetDifficulty
|
||||
0x03 => ChatMessage
|
||||
0x04 => ClientStatus
|
||||
0x05 => ClientSettings
|
||||
0x06 => TabComplete
|
||||
0x07 => ConfirmTransactionServerbound
|
||||
0x08 => ClickWindowButton
|
||||
0x09 => ClickWindow
|
||||
0x0a => CloseWindow
|
||||
0x0b => PluginMessageServerbound
|
||||
0x0c => EditBook
|
||||
0x0d => QueryEntityNBT
|
||||
0x0e => UseEntity_Sneakflag
|
||||
0x0f => GenerateStructure
|
||||
0x10 => KeepAliveServerbound_i64
|
||||
0x11 => LockDifficulty
|
||||
0x12 => PlayerPosition
|
||||
0x13 => PlayerPositionLook
|
||||
0x14 => PlayerLook
|
||||
0x15 => Player
|
||||
0x16 => VehicleMove
|
||||
0x17 => SteerBoat
|
||||
0x18 => PickItem
|
||||
0x19 => CraftRecipeRequest
|
||||
0x1a => ClientAbilities_u8
|
||||
0x1b => PlayerDigging
|
||||
0x1c => PlayerAction
|
||||
0x1d => SteerVehicle
|
||||
0x1e => SetDisplayedRecipe
|
||||
0x1f => SetRecipeBookState
|
||||
0x20 => NameItem
|
||||
0x21 => ResourcePackStatus
|
||||
0x22 => AdvancementTab
|
||||
0x23 => SelectTrade
|
||||
0x24 => SetBeaconEffect
|
||||
0x25 => HeldItemChange
|
||||
0x26 => UpdateCommandBlock
|
||||
0x27 => UpdateCommandBlockMinecart
|
||||
0x28 => CreativeInventoryAction
|
||||
0x29 => UpdateJigsawBlock_Joint
|
||||
0x2a => UpdateStructureBlock
|
||||
0x2b => SetSign
|
||||
0x2c => ArmSwing
|
||||
0x2d => SpectateTeleport
|
||||
0x2e => PlayerBlockPlacement_insideblock
|
||||
0x2f => UseItem
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => SpawnObject_VarInt
|
||||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnMob_NoMeta
|
||||
0x03 => SpawnPainting_VarInt
|
||||
0x04 => SpawnPlayer_f64_NoMeta
|
||||
0x05 => Animation
|
||||
0x06 => Statistics
|
||||
0x07 => AcknowledgePlayerDigging
|
||||
0x08 => BlockBreakAnimation
|
||||
0x09 => UpdateBlockEntity
|
||||
0x0a => BlockAction
|
||||
0x0b => BlockChange_VarInt
|
||||
0x0c => BossBar
|
||||
0x0d => ServerDifficulty_Locked
|
||||
0x0e => ServerMessage_Sender
|
||||
0x0f => TabCompleteReply
|
||||
0x10 => DeclareCommands
|
||||
0x11 => ConfirmTransaction
|
||||
0x12 => WindowClose
|
||||
0x13 => WindowItems
|
||||
0x14 => WindowProperty
|
||||
0x15 => WindowSetSlot
|
||||
0x16 => SetCooldown
|
||||
0x17 => PluginMessageClientbound
|
||||
0x18 => NamedSoundEffect
|
||||
0x19 => Disconnect
|
||||
0x1a => EntityAction
|
||||
0x1b => Explosion
|
||||
0x1c => ChunkUnload
|
||||
0x1d => ChangeGameState
|
||||
0x1e => WindowOpenHorse
|
||||
0x1f => KeepAliveClientbound_i64
|
||||
0x20 => ChunkData_Biomes3D_VarInt
|
||||
0x21 => Effect
|
||||
0x22 => Particle_f64
|
||||
0x23 => UpdateLight_WithTrust
|
||||
0x24 => JoinGame_WorldNames_IsHard
|
||||
0x25 => Maps
|
||||
0x26 => TradeList_WithRestock
|
||||
0x27 => EntityMove_i16
|
||||
0x28 => EntityLookAndMove_i16
|
||||
0x29 => EntityLook_VarInt
|
||||
0x2a => Entity
|
||||
0x2b => VehicleTeleport
|
||||
0x2c => OpenBook
|
||||
0x2d => WindowOpen_VarInt
|
||||
0x2e => SignEditorOpen
|
||||
0x2f => CraftRecipeResponse
|
||||
0x30 => PlayerAbilities
|
||||
0x31 => CombatEvent
|
||||
0x32 => PlayerInfo
|
||||
0x33 => FacePlayer
|
||||
0x34 => TeleportPlayer_WithConfirm
|
||||
0x35 => UnlockRecipes_WithBlastSmoker
|
||||
0x36 => EntityDestroy
|
||||
0x37 => EntityRemoveEffect
|
||||
0x38 => ResourcePackSend
|
||||
0x39 => Respawn_NBT
|
||||
0x3a => EntityHeadLook
|
||||
0x3b => MultiBlockChange_Packed
|
||||
0x3c => SelectAdvancementTab
|
||||
0x3d => WorldBorder
|
||||
0x3e => Camera
|
||||
0x3f => SetCurrentHotbarSlot
|
||||
0x40 => UpdateViewPosition
|
||||
0x41 => UpdateViewDistance
|
||||
0x42 => SpawnPosition
|
||||
0x43 => ScoreboardDisplay
|
||||
0x44 => EntityMetadata
|
||||
0x45 => EntityAttach
|
||||
0x46 => EntityVelocity
|
||||
0x47 => EntityEquipment_Array
|
||||
0x48 => SetExperience
|
||||
0x49 => UpdateHealth
|
||||
0x4a => ScoreboardObjective
|
||||
0x4b => SetPassengers
|
||||
0x4c => Teams_VarInt
|
||||
0x4d => UpdateScore
|
||||
0x4e => TimeUpdate
|
||||
0x4f => Title
|
||||
0x50 => EntitySoundEffect
|
||||
0x51 => SoundEffect
|
||||
0x52 => StopSound
|
||||
0x53 => PlayerListHeaderFooter
|
||||
0x54 => NBTQueryResponse
|
||||
0x55 => CollectItem
|
||||
0x56 => EntityTeleport_f64
|
||||
0x57 => Advancements
|
||||
0x58 => EntityProperties
|
||||
0x59 => EntityEffect
|
||||
0x5a => DeclareRecipes
|
||||
0x5b => TagsWithEntities
|
||||
}
|
||||
}
|
||||
login Login {
|
||||
serverbound Serverbound {
|
||||
0x00 => LoginStart
|
||||
0x01 => EncryptionResponse
|
||||
0x02 => LoginPluginResponse
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => LoginDisconnect
|
||||
0x01 => EncryptionRequest
|
||||
0x02 => LoginSuccess_UUID
|
||||
0x03 => SetInitialCompression
|
||||
0x04 => LoginPluginRequest
|
||||
}
|
||||
}
|
||||
status Status {
|
||||
serverbound Serverbound {
|
||||
0x00 => StatusRequest
|
||||
0x01 => StatusPing
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => StatusResponse
|
||||
0x01 => StatusPong
|
||||
}
|
||||
}
|
||||
);
|
|
@ -76,7 +76,7 @@ protocol_packet_ids!(
|
|||
0x21 => Effect
|
||||
0x22 => Particle_VarIntArray
|
||||
0x23 => JoinGame_i8
|
||||
0x24 => Maps
|
||||
0x24 => Maps_NoLocked
|
||||
0x25 => EntityMove_i16
|
||||
0x26 => EntityLookAndMove_i16
|
||||
0x27 => EntityLook_VarInt
|
||||
|
|
|
@ -76,7 +76,7 @@ protocol_packet_ids!(
|
|||
0x21 => Effect
|
||||
0x22 => Particle_VarIntArray
|
||||
0x23 => JoinGame_i32
|
||||
0x24 => Maps
|
||||
0x24 => Maps_NoLocked
|
||||
0x25 => EntityMove_i16
|
||||
0x26 => EntityLookAndMove_i16
|
||||
0x27 => EntityLook_VarInt
|
||||
|
|
|
@ -16,6 +16,7 @@ pub struct Map {
|
|||
bits: Vec<u64>,
|
||||
pub bit_size: usize,
|
||||
length: usize,
|
||||
padded: bool,
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -53,17 +54,20 @@ impl Map {
|
|||
bit_size: size,
|
||||
length: len,
|
||||
bits: Vec::with_capacity((len * size) / 64),
|
||||
padded: false,
|
||||
};
|
||||
for _ in 0..len {
|
||||
map.bits.push(0)
|
||||
}
|
||||
map
|
||||
}
|
||||
pub fn from_raw(bits: Vec<u64>, size: usize) -> Map {
|
||||
|
||||
pub fn from_raw(bits: Vec<u64>, size: usize, padded: bool) -> Map {
|
||||
Map {
|
||||
length: (bits.len() * 64 + (size - 1)) / size,
|
||||
bit_size: size,
|
||||
bits,
|
||||
padded,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,8 +79,17 @@ impl Map {
|
|||
n
|
||||
}
|
||||
|
||||
fn get_bit_offset(&self, i: usize) -> usize {
|
||||
let padding = if self.padded {
|
||||
i / (64 / self.bit_size) * (64 % self.bit_size)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
i * self.bit_size + padding
|
||||
}
|
||||
|
||||
pub fn set(&mut self, i: usize, val: usize) {
|
||||
let i = i * self.bit_size;
|
||||
let i = self.get_bit_offset(i);
|
||||
let pos = i / 64;
|
||||
let mask = (1u64 << self.bit_size) - 1;
|
||||
let ii = i % 64;
|
||||
|
@ -90,7 +103,7 @@ impl Map {
|
|||
}
|
||||
|
||||
pub fn get(&self, i: usize) -> usize {
|
||||
let i = i * self.bit_size;
|
||||
let i = self.get_bit_offset(i);
|
||||
let pos = i / 64;
|
||||
let mask = (1 << self.bit_size) - 1;
|
||||
let ii = i % 64;
|
||||
|
|
|
@ -39,23 +39,14 @@ impl Gamemode {
|
|||
}
|
||||
|
||||
pub fn can_fly(&self) -> bool {
|
||||
match *self {
|
||||
Gamemode::Creative | Gamemode::Spectator => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(*self, Gamemode::Creative | Gamemode::Spectator)
|
||||
}
|
||||
|
||||
pub fn always_fly(&self) -> bool {
|
||||
match *self {
|
||||
Gamemode::Spectator => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(*self, Gamemode::Spectator)
|
||||
}
|
||||
|
||||
pub fn noclip(&self) -> bool {
|
||||
match *self {
|
||||
Gamemode::Spectator => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(*self, Gamemode::Spectator)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,13 @@ use std::sync::mpsc;
|
|||
use std::sync::{Arc, RwLock};
|
||||
use std::thread;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
const NUM_WORKERS: usize = 8;
|
||||
|
||||
// TODO: threads or web workers on wasm
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
const NUM_WORKERS: usize = 0;
|
||||
|
||||
pub struct ChunkBuilder {
|
||||
threads: Vec<(mpsc::Sender<BuildReq>, thread::JoinHandle<()>)>,
|
||||
free_builders: Vec<(usize, Vec<u8>, Vec<u8>)>,
|
||||
|
@ -302,7 +307,11 @@ fn flood_fill(snapshot: &world::Snapshot, visited: &mut Set, x: i32, y: i32, z:
|
|||
let mut touched = 0;
|
||||
while let Some((x, y, z)) = next_position.pop_front() {
|
||||
let idx = (x | (z << 4) | (y << 8)) as usize;
|
||||
if x < 0 || x > 15 || y < 0 || y > 15 || z < 0 || z > 15 || visited.get(idx) {
|
||||
if !(0..=15).contains(&x)
|
||||
|| !(0..=15).contains(&y)
|
||||
|| !(0..=15).contains(&z)
|
||||
|| visited.get(idx)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
visited.set(idx, true);
|
||||
|
|
|
@ -12,9 +12,9 @@ use crate::types::Gamemode;
|
|||
use crate::world;
|
||||
use cgmath::{self, Decomposed, Matrix4, Point3, Quaternion, Rad, Rotation3, Vector3};
|
||||
use collision::{Aabb, Aabb3};
|
||||
use instant::Instant;
|
||||
use std::collections::HashMap;
|
||||
use std::hash::BuildHasherDefault;
|
||||
use std::time::Instant;
|
||||
|
||||
pub fn add_systems(m: &mut ecs::Manager) {
|
||||
let sys = MovementHandler::new(m);
|
||||
|
|
|
@ -151,7 +151,7 @@ impl ecs::System for LerpPosition {
|
|||
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 {
|
||||
if !(0.001..=100.0 * 100.0).contains(&len) {
|
||||
pos.position = target_pos.position;
|
||||
}
|
||||
}
|
||||
|
|
375
src/gl/mod.rs
375
src/gl/mod.rs
|
@ -12,18 +12,24 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
extern crate steven_gl as gl;
|
||||
|
||||
use log::{error, info};
|
||||
use std::ffi;
|
||||
use glow as gl;
|
||||
use glow::{HasContext, PixelPackData, PixelUnpackData};
|
||||
use log::error;
|
||||
use std::mem;
|
||||
use std::ops::BitOr;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ptr;
|
||||
|
||||
static mut CONTEXT: *mut glow::Context = 0 as *mut glow::Context;
|
||||
|
||||
/// Inits the gl library. This should be called once a context is ready.
|
||||
pub fn init(vid: &glutin::WindowedContext<glutin::PossiblyCurrent>) {
|
||||
gl::load_with(|s| vid.get_proc_address(s) as *const _);
|
||||
pub fn init(context: glow::Context) {
|
||||
unsafe {
|
||||
CONTEXT = Box::into_raw(Box::new(context));
|
||||
}
|
||||
}
|
||||
|
||||
fn glow_context() -> &'static glow::Context {
|
||||
unsafe { CONTEXT.as_ref().unwrap() }
|
||||
}
|
||||
|
||||
/// Dsed to specify how the vertices will be handled
|
||||
|
@ -42,32 +48,20 @@ pub const POINTS: DrawType = gl::POINTS;
|
|||
|
||||
pub fn draw_arrays(ty: DrawType, offset: usize, count: usize) {
|
||||
unsafe {
|
||||
gl::DrawArrays(ty, offset as i32, count as i32);
|
||||
glow_context().draw_arrays(ty, offset as i32, count as i32);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_elements(ty: DrawType, count: i32, dty: Type, offset: usize) {
|
||||
unsafe {
|
||||
gl::DrawElements(ty, count, dty, offset as *const gl::types::GLvoid);
|
||||
glow_context().draw_elements(ty, count, dty, offset as i32);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the size of the viewport of this context.
|
||||
// Sets the size of the viewport of this context.
|
||||
pub fn viewport(x: i32, y: i32, w: i32, h: i32) {
|
||||
unsafe {
|
||||
gl::Viewport(x, y, w, h);
|
||||
glow_context().viewport(x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +69,7 @@ pub fn viewport(x: i32, y: i32, w: i32, h: i32) {
|
|||
/// when Clear is called with the color flag.
|
||||
pub fn clear_color(r: f32, g: f32, b: f32, a: f32) {
|
||||
unsafe {
|
||||
gl::ClearColor(r, g, b, a);
|
||||
glow_context().clear_color(r, g, b, a);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,12 +103,12 @@ impl BitOr for ClearFlags {
|
|||
|
||||
/// Clears the buffers specified by the passed flags.
|
||||
pub fn clear(flags: ClearFlags) {
|
||||
unsafe { gl::Clear(flags.internal()) }
|
||||
unsafe { glow_context().clear(flags.internal()) }
|
||||
}
|
||||
|
||||
pub fn depth_mask(f: bool) {
|
||||
unsafe {
|
||||
gl::DepthMask(f as u8);
|
||||
glow_context().depth_mask(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,7 +124,7 @@ pub const EQUAL: Func = gl::EQUAL;
|
|||
|
||||
pub fn depth_func(f: Func) {
|
||||
unsafe {
|
||||
gl::DepthFunc(f);
|
||||
glow_context().depth_func(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,14 +140,14 @@ pub const MULTISAMPLE: Flag = gl::MULTISAMPLE;
|
|||
/// Enables the passed flag.
|
||||
pub fn enable(f: Flag) {
|
||||
unsafe {
|
||||
gl::Enable(f);
|
||||
glow_context().enable(f);
|
||||
}
|
||||
}
|
||||
|
||||
/// Disables the passed flag.
|
||||
pub fn disable(f: Flag) {
|
||||
unsafe {
|
||||
gl::Disable(f);
|
||||
glow_context().disable(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,7 +155,7 @@ pub fn disable(f: Flag) {
|
|||
/// currently active one.
|
||||
pub fn active_texture(id: u32) {
|
||||
unsafe {
|
||||
gl::ActiveTexture(gl::TEXTURE0 + id);
|
||||
glow_context().active_texture(gl::TEXTURE0 + id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +169,7 @@ pub const ZERO_FACTOR: Factor = gl::ZERO;
|
|||
/// Sets the factors to be used when blending.
|
||||
pub fn blend_func(s_factor: Factor, d_factor: Factor) {
|
||||
unsafe {
|
||||
gl::BlendFunc(s_factor, d_factor);
|
||||
glow_context().blend_func(s_factor, d_factor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,7 +180,7 @@ pub fn blend_func_separate(
|
|||
d_factor_a: Factor,
|
||||
) {
|
||||
unsafe {
|
||||
gl::BlendFuncSeparate(s_factor_rgb, d_factor_rgb, s_factor_a, d_factor_a);
|
||||
glow_context().blend_func_separate(s_factor_rgb, d_factor_rgb, s_factor_a, d_factor_a);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,7 +192,7 @@ pub const FRONT: Face = gl::FRONT;
|
|||
/// Sets the face to be culled by the gpu.
|
||||
pub fn cull_face(face: Face) {
|
||||
unsafe {
|
||||
gl::CullFace(face);
|
||||
glow_context().cull_face(face);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,7 +205,7 @@ pub const COUNTER_CLOCK_WISE: FaceDirection = gl::CCW;
|
|||
/// Sets the direction of vertices used to specify the
|
||||
/// front face (e.g. for culling).
|
||||
pub fn front_face(dir: FaceDirection) {
|
||||
unsafe { gl::FrontFace(dir) }
|
||||
unsafe { glow_context().front_face(dir) }
|
||||
}
|
||||
|
||||
/// `Type` is a type of data used by various operations.
|
||||
|
@ -219,6 +213,7 @@ pub type Type = u32;
|
|||
pub const UNSIGNED_BYTE: Type = gl::UNSIGNED_BYTE;
|
||||
pub const UNSIGNED_SHORT: Type = gl::UNSIGNED_SHORT;
|
||||
pub const UNSIGNED_INT: Type = gl::UNSIGNED_INT;
|
||||
pub const BYTE: Type = gl::BYTE;
|
||||
pub const SHORT: Type = gl::SHORT;
|
||||
pub const FLOAT: Type = gl::FLOAT;
|
||||
|
||||
|
@ -265,22 +260,22 @@ pub const CLAMP_TO_EDGE: TextureValue = gl::CLAMP_TO_EDGE as TextureValue;
|
|||
|
||||
/// `Texture` is a buffer of data used by fragment shaders.
|
||||
#[derive(Default)]
|
||||
pub struct Texture(u32);
|
||||
pub struct Texture(glow::Texture);
|
||||
|
||||
impl Texture {
|
||||
// Allocates a new texture.
|
||||
pub fn new() -> Texture {
|
||||
let mut t = Texture(0);
|
||||
unsafe {
|
||||
gl::GenTextures(1, &mut t.0);
|
||||
}
|
||||
t
|
||||
Texture(unsafe {
|
||||
glow_context()
|
||||
.create_texture()
|
||||
.expect("create texture failed")
|
||||
})
|
||||
}
|
||||
|
||||
/// Binds the texture to the passed target.
|
||||
pub fn bind(&self, target: TextureTarget) {
|
||||
unsafe {
|
||||
gl::BindTexture(target, self.0);
|
||||
glow_context().bind_texture(target, Some(self.0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,13 +288,7 @@ impl Texture {
|
|||
pixels: &mut [u8],
|
||||
) {
|
||||
unsafe {
|
||||
gl::GetTexImage(
|
||||
target,
|
||||
level,
|
||||
format,
|
||||
ty,
|
||||
pixels.as_mut_ptr() as *mut gl::types::GLvoid,
|
||||
);
|
||||
glow_context().get_tex_image(target, level, format, ty, PixelPackData::Slice(pixels));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,11 +303,7 @@ impl Texture {
|
|||
pix: Option<&[u8]>,
|
||||
) {
|
||||
unsafe {
|
||||
let ptr = match pix {
|
||||
Some(val) => val.as_ptr() as *const gl::types::GLvoid,
|
||||
None => ptr::null(),
|
||||
};
|
||||
gl::TexImage2D(
|
||||
glow_context().tex_image_2d(
|
||||
target,
|
||||
level,
|
||||
format as i32,
|
||||
|
@ -327,7 +312,7 @@ impl Texture {
|
|||
0,
|
||||
format,
|
||||
ty,
|
||||
ptr,
|
||||
pix,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -345,7 +330,7 @@ impl Texture {
|
|||
pix: &[u8],
|
||||
) {
|
||||
unsafe {
|
||||
gl::TexSubImage2D(
|
||||
glow_context().tex_sub_image_2d(
|
||||
target,
|
||||
level,
|
||||
x as i32,
|
||||
|
@ -354,7 +339,7 @@ impl Texture {
|
|||
height as i32,
|
||||
format,
|
||||
ty,
|
||||
pix.as_ptr() as *const _,
|
||||
PixelUnpackData::Slice(pix),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -371,11 +356,7 @@ impl Texture {
|
|||
pix: Option<&[u8]>,
|
||||
) {
|
||||
unsafe {
|
||||
let ptr = match pix {
|
||||
Some(val) => val.as_ptr() as *const gl::types::GLvoid,
|
||||
None => ptr::null(),
|
||||
};
|
||||
gl::TexImage2D(
|
||||
glow_context().tex_image_2d(
|
||||
target,
|
||||
level,
|
||||
internal_format as i32,
|
||||
|
@ -384,40 +365,7 @@ impl Texture {
|
|||
0,
|
||||
format,
|
||||
ty,
|
||||
ptr,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
gl::TexImage2DMultisample(
|
||||
target,
|
||||
use_samples,
|
||||
format,
|
||||
width as i32,
|
||||
height as i32,
|
||||
fixed as u8,
|
||||
pix,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -434,7 +382,7 @@ impl Texture {
|
|||
pix: &[u8],
|
||||
) {
|
||||
unsafe {
|
||||
gl::TexImage3D(
|
||||
glow_context().tex_image_3d(
|
||||
target,
|
||||
level,
|
||||
format as i32,
|
||||
|
@ -444,7 +392,7 @@ impl Texture {
|
|||
0,
|
||||
format,
|
||||
ty,
|
||||
pix.as_ptr() as *const gl::types::GLvoid,
|
||||
Some(pix),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -464,7 +412,7 @@ impl Texture {
|
|||
pix: &[u8],
|
||||
) {
|
||||
unsafe {
|
||||
gl::TexSubImage3D(
|
||||
glow_context().tex_sub_image_3d(
|
||||
target,
|
||||
level,
|
||||
x as i32,
|
||||
|
@ -475,7 +423,7 @@ impl Texture {
|
|||
depth as i32,
|
||||
format,
|
||||
ty,
|
||||
pix.as_ptr() as *const gl::types::GLvoid,
|
||||
PixelUnpackData::Slice(pix),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -487,7 +435,7 @@ impl Texture {
|
|||
value: TextureValue,
|
||||
) {
|
||||
unsafe {
|
||||
gl::TexParameteri(target, param, value);
|
||||
glow_context().tex_parameter_i32(target, param, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -495,7 +443,7 @@ impl Texture {
|
|||
impl Drop for Texture {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteTextures(1, &self.0);
|
||||
glow_context().delete_texture(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -512,35 +460,38 @@ pub const COMPILE_STATUS: ShaderParameter = gl::COMPILE_STATUS;
|
|||
pub const INFO_LOG_LENGTH: ShaderParameter = gl::INFO_LOG_LENGTH;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Program(u32);
|
||||
pub struct Program(glow::Program);
|
||||
|
||||
impl Program {
|
||||
pub fn new() -> Program {
|
||||
Program(unsafe { gl::CreateProgram() })
|
||||
Program(unsafe {
|
||||
glow_context()
|
||||
.create_program()
|
||||
.expect("program creation failed")
|
||||
})
|
||||
}
|
||||
|
||||
pub fn attach_shader(&self, shader: Shader) {
|
||||
unsafe {
|
||||
gl::AttachShader(self.0, shader.0);
|
||||
glow_context().attach_shader(self.0, shader.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn link(&self) {
|
||||
unsafe {
|
||||
gl::LinkProgram(self.0);
|
||||
glow_context().link_program(self.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn use_program(&self) {
|
||||
unsafe {
|
||||
gl::UseProgram(self.0);
|
||||
glow_context().use_program(Some(self.0));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uniform_location(&self, name: &str) -> Option<Uniform> {
|
||||
let c_name = ffi::CString::new(name).unwrap();
|
||||
let u = unsafe { gl::GetUniformLocation(self.0, c_name.as_ptr()) };
|
||||
if u != -1 {
|
||||
let u = unsafe { glow_context().get_uniform_location(self.0, name) };
|
||||
if let Some(u) = u {
|
||||
Some(Uniform(u))
|
||||
} else {
|
||||
None
|
||||
|
@ -548,12 +499,9 @@ impl Program {
|
|||
}
|
||||
|
||||
pub fn attribute_location(&self, name: &str) -> Option<Attribute> {
|
||||
let a = unsafe {
|
||||
let name_c = ffi::CString::new(name).unwrap();
|
||||
gl::GetAttribLocation(self.0, name_c.as_ptr())
|
||||
};
|
||||
if a != -1 {
|
||||
Some(Attribute(a))
|
||||
let a = unsafe { glow_context().get_attrib_location(self.0, name) };
|
||||
if let Some(a) = a {
|
||||
Some(Attribute(a as i32))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -563,107 +511,107 @@ impl Program {
|
|||
impl Drop for Program {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteProgram(self.0);
|
||||
glow_context().delete_program(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Shader(u32);
|
||||
pub struct Shader(glow::Shader);
|
||||
|
||||
impl Shader {
|
||||
pub fn new(ty: ShaderType) -> Shader {
|
||||
Shader(unsafe { gl::CreateShader(ty) })
|
||||
Shader(unsafe {
|
||||
glow_context()
|
||||
.create_shader(ty)
|
||||
.expect("failed to create 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());
|
||||
glow_context().shader_source(self.0, src);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile(&self) {
|
||||
unsafe {
|
||||
gl::CompileShader(self.0);
|
||||
glow_context().compile_shader(self.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_parameter(&self, param: ShaderParameter) -> i32 {
|
||||
let mut ret: i32 = 0;
|
||||
unsafe {
|
||||
gl::GetShaderiv(self.0, param, &mut ret);
|
||||
}
|
||||
ret
|
||||
pub fn get_shader_compile_status(&self) -> bool {
|
||||
unsafe { glow_context().get_shader_compile_status(self.0) }
|
||||
}
|
||||
|
||||
pub fn get_info_log(&self) -> String {
|
||||
let len = self.get_parameter(INFO_LOG_LENGTH);
|
||||
|
||||
let mut data = Vec::<u8>::with_capacity(len as usize);
|
||||
unsafe {
|
||||
data.set_len(len as usize);
|
||||
gl::GetShaderInfoLog(self.0, len, ptr::null_mut(), data.as_mut_ptr() as *mut i8);
|
||||
}
|
||||
String::from_utf8(data).unwrap()
|
||||
unsafe { glow_context().get_shader_info_log(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Uniform(i32);
|
||||
#[derive(Clone)]
|
||||
pub struct Uniform(glow::UniformLocation);
|
||||
|
||||
impl Uniform {
|
||||
pub fn set_int(&self, val: i32) {
|
||||
unsafe {
|
||||
gl::Uniform1i(self.0, val);
|
||||
glow_context().uniform_1_i32(Some(&self.0), val);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_int3(&self, x: i32, y: i32, z: i32) {
|
||||
unsafe {
|
||||
gl::Uniform3i(self.0, x, y, z);
|
||||
glow_context().uniform_3_i32(Some(&self.0), x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_float(&self, val: f32) {
|
||||
unsafe {
|
||||
gl::Uniform1f(self.0, val);
|
||||
glow_context().uniform_1_f32(Some(&self.0), val);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_float2(&self, x: f32, y: f32) {
|
||||
unsafe {
|
||||
gl::Uniform2f(self.0, x, y);
|
||||
glow_context().uniform_2_f32(Some(&self.0), x, y);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_float3(&self, x: f32, y: f32, z: f32) {
|
||||
unsafe {
|
||||
gl::Uniform3f(self.0, x, y, z);
|
||||
glow_context().uniform_3_f32(Some(&self.0), x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_float4(&self, x: f32, y: f32, z: f32, w: f32) {
|
||||
unsafe {
|
||||
gl::Uniform4f(self.0, x, y, z, w);
|
||||
glow_context().uniform_4_f32(Some(&self.0), x, y, z, w);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
pub unsafe fn set_float_multi_raw(&self, data: *const f32, len: usize) {
|
||||
gl::Uniform4fv(self.0, len as i32, data);
|
||||
pub fn set_float_multi(&self, v: &[[f32; 4]]) {
|
||||
unsafe {
|
||||
glow_context()
|
||||
.uniform_4_f32_slice(Some(&self.0), &*(v as *const [[f32; 4]] as *const [f32; 4]))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_matrix4(&self, m: &::cgmath::Matrix4<f32>) {
|
||||
use cgmath::Matrix;
|
||||
unsafe {
|
||||
gl::UniformMatrix4fv(self.0, 1, false as u8, m.as_ptr());
|
||||
glow_context().uniform_matrix_4_f32_slice(
|
||||
Some(&self.0),
|
||||
false,
|
||||
&*(m as *const cgmath::Matrix4<f32> as *const [f32; 4 * 4]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
glow_context().uniform_matrix_4_f32_slice(
|
||||
Some(&self.0),
|
||||
false,
|
||||
std::slice::from_raw_parts(m.as_ptr() as *const _, m.len() * 4 * 4),
|
||||
); // TODO: Most likely isn't safe
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -674,38 +622,32 @@ pub struct Attribute(i32);
|
|||
impl Attribute {
|
||||
pub fn enable(&self) {
|
||||
unsafe {
|
||||
gl::EnableVertexAttribArray(self.0 as u32);
|
||||
glow_context().enable_vertex_attrib_array(self.0 as u32);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disable(&self) {
|
||||
unsafe {
|
||||
gl::DisableVertexAttribArray(self.0 as u32);
|
||||
glow_context().disable_vertex_attrib_array(self.0 as u32);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vertex_pointer(&self, size: i32, ty: Type, normalized: bool, stride: i32, offset: i32) {
|
||||
unsafe {
|
||||
gl::VertexAttribPointer(
|
||||
glow_context().vertex_attrib_pointer_f32(
|
||||
self.0 as u32,
|
||||
size,
|
||||
ty,
|
||||
normalized as u8,
|
||||
normalized,
|
||||
stride,
|
||||
offset as *const gl::types::GLvoid,
|
||||
offset,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
glow_context().vertex_attrib_pointer_i32(self.0 as u32, size, ty, stride, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -714,16 +656,16 @@ impl Attribute {
|
|||
// This includes buffers, the format of the buffers and enabled
|
||||
// attributes.
|
||||
#[derive(Default)]
|
||||
pub struct VertexArray(u32);
|
||||
pub struct VertexArray(glow::VertexArray);
|
||||
|
||||
impl VertexArray {
|
||||
/// Allocates a new `VertexArray`.
|
||||
pub fn new() -> VertexArray {
|
||||
let mut va = VertexArray(0);
|
||||
unsafe {
|
||||
gl::GenVertexArrays(1, &mut va.0);
|
||||
}
|
||||
va
|
||||
VertexArray(unsafe {
|
||||
glow_context()
|
||||
.create_vertex_array()
|
||||
.expect("create vertex array failed")
|
||||
})
|
||||
}
|
||||
|
||||
/// Marks the `VertexArray` as the currently active one, this
|
||||
|
@ -731,7 +673,7 @@ impl VertexArray {
|
|||
/// this `VertexArray`.
|
||||
pub fn bind(&self) {
|
||||
unsafe {
|
||||
gl::BindVertexArray(self.0);
|
||||
glow_context().bind_vertex_array(Some(self.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -739,9 +681,9 @@ impl VertexArray {
|
|||
impl Drop for VertexArray {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteVertexArrays(1, &self.0);
|
||||
glow_context().delete_vertex_array(self.0);
|
||||
}
|
||||
self.0 = 0;
|
||||
self.0 = glow::VertexArray::default();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -775,16 +717,16 @@ pub const WRITE_ONLY: Access = gl::WRITE_ONLY;
|
|||
|
||||
/// `Buffer` is a storage for vertex data.
|
||||
#[derive(Default)]
|
||||
pub struct Buffer(u32);
|
||||
pub struct Buffer(glow::Buffer);
|
||||
|
||||
impl Buffer {
|
||||
/// Allocates a new Buffer.
|
||||
pub fn new() -> Buffer {
|
||||
let mut b = Buffer(0);
|
||||
unsafe {
|
||||
gl::GenBuffers(1, &mut b.0);
|
||||
}
|
||||
b
|
||||
Buffer(unsafe {
|
||||
glow_context()
|
||||
.create_buffer()
|
||||
.expect("create buffer failed")
|
||||
})
|
||||
}
|
||||
|
||||
/// Makes the buffer the currently active one for the given target.
|
||||
|
@ -792,24 +734,19 @@ impl Buffer {
|
|||
/// (Data, Map etc).
|
||||
pub fn bind(&self, target: BufferTarget) {
|
||||
unsafe {
|
||||
gl::BindBuffer(target, self.0);
|
||||
glow_context().bind_buffer(target, Some(self.0));
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
glow_context().buffer_data_u8_slice(target, data, usage);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn re_set_data(&self, target: BufferTarget, data: &[u8]) {
|
||||
unsafe {
|
||||
gl::BufferSubData(target, 0, data.len() as isize, data.as_ptr() as *const _);
|
||||
glow_context().buffer_sub_data_u8_slice(target, 0, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -823,7 +760,11 @@ impl Buffer {
|
|||
pub fn map(&self, target: BufferTarget, access: Access, length: usize) -> MappedBuffer {
|
||||
unsafe {
|
||||
MappedBuffer {
|
||||
inner: Vec::from_raw_parts(gl::MapBuffer(target, access) as *mut u8, 0, length),
|
||||
inner: Vec::from_raw_parts(
|
||||
glow_context().map_buffer_range(target, 0, length as i32, access) as *mut u8,
|
||||
0,
|
||||
length,
|
||||
),
|
||||
target,
|
||||
}
|
||||
}
|
||||
|
@ -833,7 +774,7 @@ impl Buffer {
|
|||
impl Drop for Buffer {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteBuffers(1, &self.0);
|
||||
glow_context().delete_buffer(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -860,7 +801,7 @@ impl DerefMut for MappedBuffer {
|
|||
impl Drop for MappedBuffer {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::UnmapBuffer(self.target);
|
||||
glow_context().unmap_buffer(self.target);
|
||||
}
|
||||
mem::forget(mem::replace(&mut self.inner, Vec::new()));
|
||||
}
|
||||
|
@ -875,11 +816,11 @@ pub const COLOR_ATTACHMENT_2: Attachment = gl::COLOR_ATTACHMENT2;
|
|||
pub const DEPTH_ATTACHMENT: Attachment = gl::DEPTH_ATTACHMENT;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Framebuffer(u32);
|
||||
pub struct Framebuffer(glow::Framebuffer);
|
||||
|
||||
pub fn check_framebuffer_status() {
|
||||
unsafe {
|
||||
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
|
||||
let status = glow_context().check_framebuffer_status(gl::FRAMEBUFFER);
|
||||
let s = match status {
|
||||
gl::FRAMEBUFFER_UNDEFINED => "GL_FRAMEBUFFER_UNDEFINED",
|
||||
gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT",
|
||||
|
@ -909,7 +850,7 @@ pub fn check_framebuffer_status() {
|
|||
pub fn check_gl_error() {
|
||||
unsafe {
|
||||
loop {
|
||||
let err = gl::GetError();
|
||||
let err = glow_context().get_error();
|
||||
if err == gl::NO_ERROR {
|
||||
break;
|
||||
}
|
||||
|
@ -921,28 +862,28 @@ pub fn check_gl_error() {
|
|||
|
||||
impl Framebuffer {
|
||||
pub fn new() -> Framebuffer {
|
||||
let mut fb = Framebuffer(0);
|
||||
unsafe {
|
||||
gl::GenFramebuffers(1, &mut fb.0);
|
||||
}
|
||||
fb
|
||||
Framebuffer(unsafe {
|
||||
glow_context()
|
||||
.create_framebuffer()
|
||||
.expect("create framebuffer failed")
|
||||
})
|
||||
}
|
||||
|
||||
pub fn bind(&self) {
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, self.0);
|
||||
glow_context().bind_framebuffer(gl::FRAMEBUFFER, Some(self.0));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bind_read(&self) {
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::READ_FRAMEBUFFER, self.0);
|
||||
glow_context().bind_framebuffer(gl::READ_FRAMEBUFFER, Some(self.0));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bind_draw(&self) {
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER, self.0);
|
||||
glow_context().bind_framebuffer(gl::DRAW_FRAMEBUFFER, Some(self.0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -954,7 +895,13 @@ impl Framebuffer {
|
|||
level: i32,
|
||||
) {
|
||||
unsafe {
|
||||
gl::FramebufferTexture2D(gl::FRAMEBUFFER, attachment, target, tex.0, level);
|
||||
glow_context().framebuffer_texture_2d(
|
||||
gl::FRAMEBUFFER,
|
||||
attachment,
|
||||
target,
|
||||
Some(tex.0),
|
||||
level,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -962,40 +909,37 @@ impl Framebuffer {
|
|||
impl Drop for Framebuffer {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteFramebuffers(1, &self.0);
|
||||
glow_context().delete_framebuffer(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unbind_framebuffer() {
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||
glow_context().bind_framebuffer(gl::FRAMEBUFFER, None);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unbind_framebuffer_read() {
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::READ_FRAMEBUFFER, 0);
|
||||
glow_context().bind_framebuffer(gl::READ_FRAMEBUFFER, None);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unbind_framebuffer_draw() {
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER, 0);
|
||||
glow_context().bind_framebuffer(gl::DRAW_FRAMEBUFFER, None);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_buffers(bufs: &[Attachment]) {
|
||||
unsafe {
|
||||
gl::DrawBuffers(bufs.len() as i32, bufs.as_ptr());
|
||||
glow_context().draw_buffers(bufs);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bind_frag_data_location(p: &Program, cn: u32, name: &str) {
|
||||
unsafe {
|
||||
let name_c = ffi::CString::new(name).unwrap();
|
||||
gl::BindFragDataLocation(p.0, cn, name_c.as_ptr());
|
||||
}
|
||||
unsafe { glow_context().bind_frag_data_location(p.0, cn, name) }
|
||||
}
|
||||
|
||||
pub fn blit_framebuffer(
|
||||
|
@ -1011,7 +955,7 @@ pub fn blit_framebuffer(
|
|||
filter: TextureValue,
|
||||
) {
|
||||
unsafe {
|
||||
gl::BlitFramebuffer(
|
||||
glow_context().blit_framebuffer(
|
||||
sx0,
|
||||
sy0,
|
||||
sx1,
|
||||
|
@ -1026,17 +970,12 @@ pub fn blit_framebuffer(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn read_buffer(a: Attachment) {
|
||||
unsafe {
|
||||
gl::ReadBuffer(a);
|
||||
}
|
||||
}
|
||||
|
||||
pub type TargetBuffer = u32;
|
||||
pub const COLOR: TargetBuffer = gl::COLOR;
|
||||
|
||||
pub fn clear_buffer(buffer: TargetBuffer, draw_buffer: i32, values: &[f32]) {
|
||||
pub fn clear_buffer(buffer: TargetBuffer, draw_buffer: u32, values: &mut [f32]) {
|
||||
unsafe {
|
||||
gl::ClearBufferfv(buffer, draw_buffer, values.as_ptr());
|
||||
// TODO: why does glow have &mut on clear buffer values, why would it change the color?
|
||||
glow_context().clear_buffer_f32_slice(buffer, draw_buffer, values);
|
||||
}
|
||||
}
|
||||
|
|
428
src/main.rs
428
src/main.rs
|
@ -17,8 +17,9 @@
|
|||
#![allow(clippy::many_single_char_names)] // short variable names provide concise clarity
|
||||
#![allow(clippy::float_cmp)] // float comparison used to check if changed
|
||||
|
||||
use instant::{Duration, Instant};
|
||||
use log::{error, info, warn};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::fs;
|
||||
extern crate steven_shared as shared;
|
||||
|
||||
use structopt::StructOpt;
|
||||
|
@ -46,6 +47,7 @@ pub mod world;
|
|||
|
||||
use crate::protocol::mojang;
|
||||
use cfg_if::cfg_if;
|
||||
use std::cell::RefCell;
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
use std::sync::mpsc;
|
||||
|
@ -193,6 +195,10 @@ struct Opt {
|
|||
#[structopt(short = "n", long = "network-debug")]
|
||||
network_debug: bool,
|
||||
|
||||
/// Parse a network packet from a file
|
||||
#[structopt(short = "N", long = "network-parse-packet")]
|
||||
network_parse_packet: Option<String>,
|
||||
|
||||
/// Protocol version to use in the autodetection ping
|
||||
#[structopt(short = "p", long = "default-protocol-version")]
|
||||
default_protocol_version: Option<String>,
|
||||
|
@ -200,6 +206,7 @@ struct Opt {
|
|||
|
||||
cfg_if! {
|
||||
if #[cfg(target_arch = "wasm32")] {
|
||||
use glow::HasRenderLoop;
|
||||
extern crate console_error_panic_hook;
|
||||
pub use console_error_panic_hook::set_once as set_panic_hook;
|
||||
} else {
|
||||
|
@ -209,7 +216,7 @@ cfg_if! {
|
|||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(target_os = "unknown")] {
|
||||
if #[cfg(target_arch = "wasm32")] {
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
|
@ -224,7 +231,6 @@ fn main2() {
|
|||
let opt = Opt::from_args();
|
||||
|
||||
set_panic_hook();
|
||||
std::env::set_var("RUST_BACKTRACE", "1");
|
||||
|
||||
let con = Arc::new(Mutex::new(console::Console::new()));
|
||||
let proxy = console::ConsoleProxy::new(con.clone());
|
||||
|
@ -234,7 +240,7 @@ fn main2() {
|
|||
|
||||
info!("Starting steven");
|
||||
|
||||
let (vars, vsync) = {
|
||||
let (vars, mut vsync) = {
|
||||
let mut vars = console::Vars::new();
|
||||
vars.register(CL_BRAND);
|
||||
auth::register_vars(&mut vars);
|
||||
|
@ -248,35 +254,88 @@ fn main2() {
|
|||
let (res, mut resui) = resources::Manager::new();
|
||||
let resource_manager = Arc::new(RwLock::new(res));
|
||||
|
||||
let events_loop = glutin::event_loop::EventLoop::new();
|
||||
let window_builder = glutin::window::WindowBuilder::new()
|
||||
.with_title("Stevenarella")
|
||||
.with_inner_size(glutin::dpi::LogicalSize::new(854.0, 480.0));
|
||||
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_profile(glutin::GlProfile::Core)
|
||||
.with_vsync(vsync)
|
||||
.build_windowed(window_builder, &events_loop)
|
||||
.expect("Could not create glutin window.");
|
||||
let events_loop = winit::event_loop::EventLoop::new();
|
||||
|
||||
let mut window = unsafe {
|
||||
window
|
||||
.make_current()
|
||||
.expect("Could not set current context.")
|
||||
let window_builder = winit::window::WindowBuilder::new()
|
||||
.with_title("Stevenarella")
|
||||
.with_inner_size(winit::dpi::LogicalSize::new(854.0, 480.0));
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let (context, shader_version, dpi_factor, winit_window, render_loop) = {
|
||||
let winit_window = window_builder.build(&events_loop).unwrap();
|
||||
let dpi_factor = winit_window.scale_factor();
|
||||
|
||||
use wasm_bindgen::JsCast;
|
||||
use winit::platform::web::WindowExtWebSys;
|
||||
|
||||
let canvas = winit_window.canvas();
|
||||
|
||||
let html_window = web_sys::window().unwrap();
|
||||
let document = html_window.document().unwrap();
|
||||
let body = document.body().unwrap();
|
||||
|
||||
body.append_child(&canvas)
|
||||
.expect("Append canvas to HTML body");
|
||||
|
||||
let canvas = canvas.dyn_into::<web_sys::HtmlCanvasElement>().unwrap();
|
||||
let webgl2_context = canvas
|
||||
.get_context("webgl2")
|
||||
.expect("Failed to get WebGL2 context")
|
||||
.expect("Failed to create WebGL2 context, is WebGL2 support enabled? (https://get.webgl.org/webgl2/)")
|
||||
.dyn_into::<web_sys::WebGl2RenderingContext>()
|
||||
.unwrap();
|
||||
(
|
||||
glow::Context::from_webgl2_context(webgl2_context),
|
||||
"#version 300 es", // WebGL 2
|
||||
dpi_factor,
|
||||
winit_window,
|
||||
glow::RenderLoop::from_request_animation_frame(),
|
||||
)
|
||||
};
|
||||
|
||||
gl::init(&window);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let (context, shader_version, dpi_factor, glutin_window) = {
|
||||
let glutin_window = glutin::ContextBuilder::new()
|
||||
.with_stencil_buffer(0)
|
||||
.with_depth_buffer(24)
|
||||
.with_gl(glutin::GlRequest::GlThenGles {
|
||||
opengl_version: (3, 2),
|
||||
opengles_version: (3, 0),
|
||||
})
|
||||
.with_gl_profile(glutin::GlProfile::Core)
|
||||
.with_vsync(vsync)
|
||||
.build_windowed(window_builder, &events_loop)
|
||||
.expect("Could not create glutin window.");
|
||||
let dpi_factor = glutin_window.window().scale_factor();
|
||||
|
||||
let renderer = render::Renderer::new(resource_manager.clone());
|
||||
let mut ui_container = ui::Container::new();
|
||||
let glutin_window = unsafe {
|
||||
glutin_window
|
||||
.make_current()
|
||||
.expect("Could not set current context.")
|
||||
};
|
||||
|
||||
let context = unsafe {
|
||||
glow::Context::from_loader_function(|s| glutin_window.get_proc_address(s) as *const _)
|
||||
};
|
||||
|
||||
let shader_version = match glutin_window.get_api() {
|
||||
glutin::Api::OpenGl => "#version 150", // OpenGL 3.2
|
||||
glutin::Api::OpenGlEs => "#version 300 es", // OpenGL ES 3.0 (similar to WebGL 2)
|
||||
glutin::Api::WebGl => {
|
||||
panic!("unexpectedly received WebGl API with glutin, expected to use glow codepath")
|
||||
}
|
||||
};
|
||||
|
||||
(context, shader_version, dpi_factor, glutin_window)
|
||||
};
|
||||
|
||||
gl::init(context);
|
||||
info!("Shader version: {}", shader_version);
|
||||
|
||||
let renderer = render::Renderer::new(resource_manager.clone(), shader_version);
|
||||
let ui_container = ui::Container::new();
|
||||
|
||||
let mut last_frame = Instant::now();
|
||||
let frame_time = 1e9f64 / 60.0;
|
||||
|
||||
let mut screen_sys = screen::ScreenSystem::new();
|
||||
if opt.server.is_none() {
|
||||
|
@ -296,7 +355,6 @@ fn main2() {
|
|||
}
|
||||
|
||||
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_else(|| "".to_string()),
|
||||
|
@ -328,110 +386,201 @@ fn main2() {
|
|||
protocol::enable_network_debug();
|
||||
}
|
||||
|
||||
if let Some(filename) = opt.network_parse_packet {
|
||||
let data = fs::read(filename).unwrap();
|
||||
protocol::try_parse_packet(data, default_protocol_version);
|
||||
return;
|
||||
}
|
||||
|
||||
if opt.server.is_some() {
|
||||
game.connect_to(&opt.server.unwrap());
|
||||
}
|
||||
|
||||
let mut last_resource_version = 0;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let winit_window = Rc::new(RefCell::new(winit_window));
|
||||
|
||||
let game = Rc::new(RefCell::new(game));
|
||||
let ui_container = Rc::new(RefCell::new(ui_container));
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
let winit_window = Rc::clone(&winit_window);
|
||||
let game = Rc::clone(&game);
|
||||
let ui_container = Rc::clone(&ui_container);
|
||||
|
||||
render_loop.run(move |running: &mut bool| {
|
||||
let winit_window = winit_window.borrow_mut();
|
||||
let mut game = game.borrow_mut();
|
||||
let mut ui_container = ui_container.borrow_mut();
|
||||
|
||||
tick_all(
|
||||
&winit_window,
|
||||
&mut game,
|
||||
&mut ui_container,
|
||||
&mut last_frame,
|
||||
&mut resui,
|
||||
&mut last_resource_version,
|
||||
&mut vsync,
|
||||
);
|
||||
println!("render_loop");
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let winit_window = Rc::clone(&winit_window);
|
||||
|
||||
let game = Rc::clone(&game);
|
||||
let ui_container = Rc::clone(&ui_container);
|
||||
events_loop.run(move |event, _event_loop, control_flow| {
|
||||
*control_flow = glutin::event_loop::ControlFlow::Poll;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let winit_window = winit_window.borrow_mut();
|
||||
|
||||
if !handle_window_event(&mut window, &mut game, &mut ui_container, event) {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let winit_window = glutin_window.window();
|
||||
|
||||
let mut game = game.borrow_mut();
|
||||
let mut ui_container = ui_container.borrow_mut();
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
*control_flow = winit::event_loop::ControlFlow::Wait;
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
*control_flow = winit::event_loop::ControlFlow::Poll;
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
if let winit::event::Event::WindowEvent {
|
||||
event: winit::event::WindowEvent::Resized(physical_size),
|
||||
..
|
||||
} = event
|
||||
{
|
||||
glutin_window.resize(physical_size);
|
||||
}
|
||||
|
||||
if !handle_window_event(&winit_window, &mut game, &mut ui_container, event) {
|
||||
return;
|
||||
}
|
||||
|
||||
let now = Instant::now();
|
||||
let diff = now.duration_since(last_frame);
|
||||
last_frame = now;
|
||||
let delta = (diff.subsec_nanos() as f64) / frame_time;
|
||||
let physical_size = window.window().inner_size();
|
||||
let (physical_width, physical_height) = physical_size.into();
|
||||
let (width, height) = physical_size.to_logical::<f64>(game.dpi_factor).into();
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
tick_all(
|
||||
&winit_window,
|
||||
&mut game,
|
||||
&mut ui_container,
|
||||
&mut last_frame,
|
||||
&mut resui,
|
||||
&mut last_resource_version,
|
||||
&mut vsync,
|
||||
);
|
||||
|
||||
let version = {
|
||||
let try_res = game.resource_manager.try_write();
|
||||
if let Ok(mut res) = try_res {
|
||||
res.tick(&mut resui, &mut ui_container, delta);
|
||||
res.version()
|
||||
} else {
|
||||
// TODO: why does game.resource_manager.write() sometimes deadlock?
|
||||
//warn!("Failed to obtain mutable reference to resource manager!");
|
||||
last_resource_version
|
||||
}
|
||||
};
|
||||
last_resource_version = version;
|
||||
|
||||
let vsync_changed = *game.vars.get(settings::R_VSYNC);
|
||||
if vsync != vsync_changed {
|
||||
error!("Changing vsync currently requires restarting");
|
||||
game.should_close = true;
|
||||
// TODO: after https://github.com/tomaka/glutin/issues/693 Allow changing vsync on a Window
|
||||
//vsync = vsync_changed;
|
||||
glutin_window
|
||||
.swap_buffers()
|
||||
.expect("Failed to swap GL buffers");
|
||||
}
|
||||
let fps_cap = *game.vars.get(settings::R_MAX_FPS);
|
||||
|
||||
game.tick(delta);
|
||||
game.server.tick(&mut game.renderer, delta);
|
||||
|
||||
// Check if window is valid, it might be minimized
|
||||
if physical_width == 0 || physical_height == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
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.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,
|
||||
);
|
||||
|
||||
if fps_cap > 0 && !vsync {
|
||||
let frame_time = now.elapsed();
|
||||
let sleep_interval = Duration::from_millis(1000 / fps_cap as u64);
|
||||
if frame_time < sleep_interval {
|
||||
thread::sleep(sleep_interval - frame_time);
|
||||
}
|
||||
}
|
||||
window.swap_buffers().expect("Failed to swap GL buffers");
|
||||
|
||||
if game.should_close {
|
||||
*control_flow = glutin::event_loop::ControlFlow::Exit;
|
||||
*control_flow = winit::event_loop::ControlFlow::Exit;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn tick_all(
|
||||
window: &winit::window::Window,
|
||||
game: &mut Game,
|
||||
mut ui_container: &mut ui::Container,
|
||||
last_frame: &mut Instant,
|
||||
mut resui: &mut resources::ManagerUI,
|
||||
last_resource_version: &mut usize,
|
||||
vsync: &mut bool,
|
||||
) {
|
||||
let now = Instant::now();
|
||||
let diff = now.duration_since(*last_frame);
|
||||
*last_frame = now;
|
||||
let frame_time = 1e9f64 / 60.0;
|
||||
let delta = (diff.subsec_nanos() as f64) / frame_time;
|
||||
let physical_size = window.inner_size();
|
||||
let (physical_width, physical_height) = physical_size.into();
|
||||
let (width, height) = physical_size.to_logical::<f64>(game.dpi_factor).into();
|
||||
|
||||
let version = {
|
||||
let try_res = game.resource_manager.try_write();
|
||||
if let Ok(mut res) = try_res {
|
||||
res.tick(&mut resui, &mut ui_container, delta);
|
||||
res.version()
|
||||
} else {
|
||||
// TODO: why does game.resource_manager.write() sometimes deadlock?
|
||||
//warn!("Failed to obtain mutable reference to resource manager!");
|
||||
*last_resource_version
|
||||
}
|
||||
};
|
||||
*last_resource_version = version;
|
||||
|
||||
let vsync_changed = *game.vars.get(settings::R_VSYNC);
|
||||
if *vsync != vsync_changed {
|
||||
error!("Changing vsync currently requires restarting");
|
||||
game.should_close = true;
|
||||
// TODO: after https://github.com/tomaka/glutin/issues/693 Allow changing vsync on a Window
|
||||
//vsync = vsync_changed;
|
||||
}
|
||||
let fps_cap = *game.vars.get(settings::R_MAX_FPS);
|
||||
|
||||
game.tick(delta);
|
||||
game.server.tick(&mut game.renderer, delta);
|
||||
|
||||
// Check if window is valid, it might be minimized
|
||||
if physical_width == 0 || physical_height == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
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.screen_sys
|
||||
.tick(delta, &mut game.renderer, &mut ui_container);
|
||||
game.console
|
||||
.lock()
|
||||
.unwrap()
|
||||
.tick(&mut ui_container, &game.renderer, delta, width);
|
||||
ui_container.tick(&mut game.renderer, delta, width, height);
|
||||
game.renderer.tick(
|
||||
&mut game.server.world,
|
||||
delta,
|
||||
width as u32,
|
||||
height as u32,
|
||||
physical_width,
|
||||
physical_height,
|
||||
);
|
||||
|
||||
if fps_cap > 0 && !*vsync {
|
||||
let frame_time = now.elapsed();
|
||||
let sleep_interval = Duration::from_millis(1000 / fps_cap as u64);
|
||||
if frame_time < sleep_interval {
|
||||
thread::sleep(sleep_interval - frame_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_window_event<T>(
|
||||
window: &mut glutin::WindowedContext<glutin::PossiblyCurrent>,
|
||||
window: &winit::window::Window,
|
||||
game: &mut Game,
|
||||
ui_container: &mut ui::Container,
|
||||
event: glutin::event::Event<T>,
|
||||
event: winit::event::Event<T>,
|
||||
) -> bool {
|
||||
use glutin::event::*;
|
||||
use winit::event::*;
|
||||
match event {
|
||||
Event::MainEventsCleared => return true,
|
||||
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 {
|
||||
Event::DeviceEvent { event, .. } => {
|
||||
if let DeviceEvent::MouseMotion {
|
||||
delta: (xrel, yrel),
|
||||
} => {
|
||||
} = event
|
||||
{
|
||||
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
|
||||
|
@ -453,8 +602,8 @@ fn handle_window_event<T>(
|
|||
use std::f64::consts::PI;
|
||||
|
||||
if game.focused {
|
||||
window.window().set_cursor_grab(true).unwrap();
|
||||
window.window().set_cursor_visible(false);
|
||||
window.set_cursor_grab(true).unwrap();
|
||||
window.set_cursor_visible(false);
|
||||
if let Some(player) = game.server.player {
|
||||
let rotation = game
|
||||
.server
|
||||
|
@ -471,20 +620,19 @@ fn handle_window_event<T>(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
window.window().set_cursor_grab(false).unwrap();
|
||||
window.window().set_cursor_visible(true);
|
||||
window.set_cursor_grab(false).unwrap();
|
||||
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::ModifiersChanged(modifiers_state) => {
|
||||
game.is_ctrl_pressed = modifiers_state.ctrl();
|
||||
game.is_logo_pressed = modifiers_state.logo();
|
||||
}
|
||||
WindowEvent::CloseRequested => game.should_close = true,
|
||||
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
|
||||
game.dpi_factor = scale_factor;
|
||||
}
|
||||
|
@ -497,22 +645,22 @@ fn handle_window_event<T>(
|
|||
|
||||
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 physical_size = window.inner_size();
|
||||
let (width, height) =
|
||||
physical_size.to_logical::<f64>(game.dpi_factor).into();
|
||||
|
||||
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);
|
||||
window.set_cursor_grab(true).unwrap();
|
||||
window.set_cursor_visible(false);
|
||||
} else if !game.focused {
|
||||
window.window().set_cursor_grab(false).unwrap();
|
||||
window.window().set_cursor_visible(true);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
// TODO: after Pointer Lock https://github.com/rust-windowing/winit/issues/1674
|
||||
window.set_cursor_grab(false).unwrap();
|
||||
window.set_cursor_visible(true);
|
||||
ui_container.click_at(
|
||||
game,
|
||||
game.last_mouse_x,
|
||||
|
@ -530,16 +678,14 @@ fn handle_window_event<T>(
|
|||
(_, _) => (),
|
||||
},
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
let (x, y) = position.into();
|
||||
let (x, y) = position.to_logical::<f64>(game.dpi_factor).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();
|
||||
let physical_size = window.inner_size();
|
||||
let (width, height) =
|
||||
physical_size.to_logical::<f64>(game.dpi_factor).into();
|
||||
ui_container.hover_at(game, x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
@ -559,15 +705,15 @@ fn handle_window_event<T>(
|
|||
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);
|
||||
window.set_cursor_grab(false).unwrap();
|
||||
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);
|
||||
window.set_cursor_grab(true).unwrap();
|
||||
window.set_cursor_visible(false);
|
||||
game.focused = true;
|
||||
game.screen_sys.pop_screen();
|
||||
}
|
||||
|
@ -579,13 +725,11 @@ fn handle_window_event<T>(
|
|||
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(),
|
||||
),
|
||||
));
|
||||
window.set_fullscreen(Some(winit::window::Fullscreen::Borderless(
|
||||
window.current_monitor(),
|
||||
)));
|
||||
} else {
|
||||
window.window().set_fullscreen(None);
|
||||
window.set_fullscreen(None);
|
||||
}
|
||||
|
||||
game.is_fullscreen = !game.is_fullscreen;
|
||||
|
|
|
@ -1114,11 +1114,7 @@ fn calculate_light(
|
|||
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,
|
||||
})
|
||||
if (force && !matches!(snapshot.get_block(lx, ly, lz), block::Air {}))
|
||||
|| (sl == 0 && bl == 0)
|
||||
{
|
||||
bl = s_block_light;
|
||||
|
|
|
@ -46,7 +46,7 @@ impl Clouds {
|
|||
v.set_source(&vertex);
|
||||
v.compile();
|
||||
|
||||
if v.get_parameter(gl::COMPILE_STATUS) == 0 {
|
||||
if !v.get_shader_compile_status() {
|
||||
error!("Src: {}", vertex);
|
||||
panic!("Shader error: {}", v.get_info_log());
|
||||
} else {
|
||||
|
@ -61,7 +61,7 @@ impl Clouds {
|
|||
g.set_source(&geo);
|
||||
g.compile();
|
||||
|
||||
if g.get_parameter(gl::COMPILE_STATUS) == 0 {
|
||||
if !g.get_shader_compile_status() {
|
||||
error!("Src: {}", geo);
|
||||
panic!("Shader error: {}", g.get_info_log());
|
||||
} else {
|
||||
|
@ -76,7 +76,7 @@ impl Clouds {
|
|||
f.set_source(&fragment);
|
||||
f.compile();
|
||||
|
||||
if f.get_parameter(gl::COMPILE_STATUS) == 0 {
|
||||
if !f.get_shader_compile_status() {
|
||||
error!("Src: {}", fragment);
|
||||
panic!("Shader error: {}", f.get_info_log());
|
||||
} else {
|
||||
|
|
|
@ -17,11 +17,15 @@ use std::collections::HashMap;
|
|||
#[derive(Default)]
|
||||
pub struct Registry {
|
||||
shaders: HashMap<String, String>,
|
||||
shader_version: String,
|
||||
}
|
||||
|
||||
impl Registry {
|
||||
pub fn new() -> Registry {
|
||||
Default::default()
|
||||
pub fn new(shader_version: &str) -> Registry {
|
||||
Registry {
|
||||
shaders: Default::default(),
|
||||
shader_version: shader_version.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register(&mut self, name: &str, source: &str) {
|
||||
|
@ -32,19 +36,32 @@ impl Registry {
|
|||
.insert(name.to_owned(), source.trim().to_owned());
|
||||
}
|
||||
|
||||
fn add_version(&self, out: &mut String) {
|
||||
out.push_str(&self.shader_version);
|
||||
out.push('\n');
|
||||
if self.shader_version.ends_with(" es") {
|
||||
out.push_str(
|
||||
r#"precision mediump float;
|
||||
precision mediump sampler2DArray;
|
||||
#define ES
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, name: &str) -> String {
|
||||
let mut out = String::new();
|
||||
out.push_str("#version 150\n");
|
||||
self.add_version(&mut out);
|
||||
self.get_internal(&mut out, name);
|
||||
out
|
||||
}
|
||||
|
||||
pub fn get_define(&self, name: &str, define: &str) -> String {
|
||||
let mut out = String::new();
|
||||
out.push_str("#version 150\n");
|
||||
self.add_version(&mut out);
|
||||
out.push_str("#define ");
|
||||
out.push_str(define);
|
||||
out.push_str("\n");
|
||||
out.push('\n');
|
||||
self.get_internal(&mut out, name);
|
||||
out
|
||||
}
|
||||
|
@ -52,13 +69,13 @@ impl Registry {
|
|||
fn get_internal(&self, out: &mut String, name: &str) {
|
||||
let src = self.shaders.get(name).unwrap();
|
||||
for line in src.lines() {
|
||||
if line.starts_with("#include ") {
|
||||
let inc = line["#include ".len()..].trim();
|
||||
if let Some(stripped) = line.strip_prefix("#include ") {
|
||||
let inc = stripped.trim();
|
||||
self.get_internal(out, inc);
|
||||
continue;
|
||||
}
|
||||
out.push_str(line);
|
||||
out.push_str("\n");
|
||||
out.push('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,13 +37,8 @@ use std::sync::atomic::{AtomicIsize, Ordering};
|
|||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
|
||||
const ATLAS_SIZE: usize = 1024;
|
||||
|
||||
// TEMP
|
||||
const NUM_SAMPLES: i32 = 2;
|
||||
|
||||
pub struct Camera {
|
||||
pub pos: cgmath::Point3<f64>,
|
||||
pub yaw: f64,
|
||||
|
@ -56,7 +51,7 @@ pub struct Renderer {
|
|||
textures: Arc<RwLock<TextureManager>>,
|
||||
pub ui: ui::UIState,
|
||||
pub model: model::Manager,
|
||||
pub clouds: clouds::Clouds,
|
||||
pub clouds: Option<clouds::Clouds>,
|
||||
|
||||
gl_texture: gl::Texture,
|
||||
texture_layers: usize,
|
||||
|
@ -153,7 +148,7 @@ init_shader! {
|
|||
}
|
||||
|
||||
impl Renderer {
|
||||
pub fn new(res: Arc<RwLock<resources::Manager>>) -> Renderer {
|
||||
pub fn new(res: Arc<RwLock<resources::Manager>>, shader_version: &str) -> Renderer {
|
||||
let version = { res.read().unwrap().version() };
|
||||
let tex = gl::Texture::new();
|
||||
tex.bind(gl::TEXTURE_2D_ARRAY);
|
||||
|
@ -175,7 +170,7 @@ impl Renderer {
|
|||
let (textures, skin_req, skin_reply) = TextureManager::new(res.clone());
|
||||
let textures = Arc::new(RwLock::new(textures));
|
||||
|
||||
let mut greg = glsl::Registry::new();
|
||||
let mut greg = glsl::Registry::new(shader_version);
|
||||
shaders::add_shaders(&mut greg);
|
||||
let ui = ui::UIState::new(&greg, textures.clone(), res.clone());
|
||||
|
||||
|
@ -196,10 +191,18 @@ impl Renderer {
|
|||
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
|
||||
gl::depth_func(gl::LESS_OR_EQUAL);
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let clouds = Some(clouds::Clouds::new(&greg, textures.clone()));
|
||||
|
||||
// No clouds on wasm since no geo shaders on WebGL
|
||||
// TODO: setting to disable clouds on native, too, if desired
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let clouds = None;
|
||||
|
||||
Renderer {
|
||||
resource_version: version,
|
||||
model: model::Manager::new(&greg),
|
||||
clouds: clouds::Clouds::new(&greg, textures.clone()),
|
||||
clouds,
|
||||
textures,
|
||||
ui,
|
||||
resources: res,
|
||||
|
@ -313,6 +316,7 @@ impl Renderer {
|
|||
gl::active_texture(0);
|
||||
self.gl_texture.bind(gl::TEXTURE_2D_ARRAY);
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
gl::enable(gl::MULTISAMPLE);
|
||||
|
||||
let time_offset = self.sky_offset * 0.9;
|
||||
|
@ -363,17 +367,19 @@ impl Renderer {
|
|||
self.light_level,
|
||||
self.sky_offset,
|
||||
);
|
||||
if world.copy_cloud_heightmap(&mut self.clouds.heightmap_data) {
|
||||
self.clouds.dirty = true;
|
||||
if let Some(clouds) = &mut self.clouds {
|
||||
if world.copy_cloud_heightmap(&mut clouds.heightmap_data) {
|
||||
clouds.dirty = true;
|
||||
}
|
||||
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();
|
||||
|
@ -412,8 +418,8 @@ impl Renderer {
|
|||
trans.trans.bind();
|
||||
gl::clear_color(0.0, 0.0, 0.0, 1.0);
|
||||
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::clear_buffer(gl::COLOR, 0, &mut [0.0, 0.0, 0.0, 1.0]);
|
||||
gl::clear_buffer(gl::COLOR, 1, &mut [0.0, 0.0, 0.0, 0.0]);
|
||||
gl::blend_func_separate(
|
||||
gl::ONE_FACTOR,
|
||||
gl::ONE_FACTOR,
|
||||
|
@ -448,6 +454,8 @@ impl Renderer {
|
|||
gl::enable(gl::DEPTH_TEST);
|
||||
gl::depth_mask(true);
|
||||
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
gl::disable(gl::MULTISAMPLE);
|
||||
|
||||
self.ui.tick(width, height);
|
||||
|
@ -777,7 +785,6 @@ init_shader! {
|
|||
required accum => "taccum",
|
||||
required revealage => "trevealage",
|
||||
required color => "tcolor",
|
||||
required samples => "samples",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -805,7 +812,7 @@ impl TransInfo {
|
|||
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);
|
||||
accum.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR);
|
||||
trans.texture_2d(gl::COLOR_ATTACHMENT_0, gl::TEXTURE_2D, &accum, 0);
|
||||
|
||||
let revealage = gl::Texture::new();
|
||||
|
@ -821,7 +828,7 @@ impl TransInfo {
|
|||
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);
|
||||
revealage.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR);
|
||||
trans.texture_2d(gl::COLOR_ATTACHMENT_1, gl::TEXTURE_2D, &revealage, 0);
|
||||
|
||||
let trans_depth = gl::Texture::new();
|
||||
|
@ -833,55 +840,58 @@ impl TransInfo {
|
|||
height,
|
||||
gl::DEPTH_COMPONENT24,
|
||||
gl::DEPTH_COMPONENT,
|
||||
gl::UNSIGNED_BYTE,
|
||||
gl::UNSIGNED_INT,
|
||||
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_depth.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR);
|
||||
trans.texture_2d(gl::DEPTH_ATTACHMENT, gl::TEXTURE_2D, &trans_depth, 0);
|
||||
|
||||
chunk_shader.program.use_program();
|
||||
gl::bind_frag_data_location(&chunk_shader.program, 0, "accum");
|
||||
gl::bind_frag_data_location(&chunk_shader.program, 1, "revealage");
|
||||
#[cfg(not(target_arch = "wasm32"))] // bound with layout(location=)
|
||||
{
|
||||
gl::bind_frag_data_location(&chunk_shader.program, 0, "accum");
|
||||
gl::bind_frag_data_location(&chunk_shader.program, 1, "revealage");
|
||||
}
|
||||
gl::check_framebuffer_status();
|
||||
gl::draw_buffers(&[gl::COLOR_ATTACHMENT_0, gl::COLOR_ATTACHMENT_1]);
|
||||
|
||||
let main = gl::Framebuffer::new();
|
||||
main.bind();
|
||||
|
||||
// TODO: support rendering to a multisample renderbuffer for MSAA, using glRenderbufferStorageMultisample
|
||||
// https://github.com/iceiix/stevenarella/pull/442
|
||||
let fb_color = gl::Texture::new();
|
||||
fb_color.bind(gl::TEXTURE_2D_MULTISAMPLE);
|
||||
fb_color.image_2d_sample(
|
||||
gl::TEXTURE_2D_MULTISAMPLE,
|
||||
NUM_SAMPLES,
|
||||
fb_color.bind(gl::TEXTURE_2D);
|
||||
fb_color.image_2d(
|
||||
gl::TEXTURE_2D,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
gl::RGBA8,
|
||||
false,
|
||||
);
|
||||
main.texture_2d(
|
||||
gl::COLOR_ATTACHMENT_0,
|
||||
gl::TEXTURE_2D_MULTISAMPLE,
|
||||
&fb_color,
|
||||
0,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
None,
|
||||
);
|
||||
fb_color.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR);
|
||||
fb_color.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR);
|
||||
|
||||
main.texture_2d(gl::COLOR_ATTACHMENT_0, gl::TEXTURE_2D, &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,
|
||||
fb_depth.bind(gl::TEXTURE_2D);
|
||||
fb_depth.image_2d_ex(
|
||||
gl::TEXTURE_2D,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
gl::DEPTH_COMPONENT24,
|
||||
false,
|
||||
);
|
||||
main.texture_2d(
|
||||
gl::DEPTH_ATTACHMENT,
|
||||
gl::TEXTURE_2D_MULTISAMPLE,
|
||||
&fb_depth,
|
||||
0,
|
||||
gl::DEPTH_COMPONENT,
|
||||
gl::UNSIGNED_INT,
|
||||
None,
|
||||
);
|
||||
fb_depth.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR);
|
||||
fb_depth.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR);
|
||||
|
||||
main.texture_2d(gl::DEPTH_ATTACHMENT, gl::TEXTURE_2D, &fb_depth, 0);
|
||||
gl::check_framebuffer_status();
|
||||
|
||||
gl::unbind_framebuffer();
|
||||
|
@ -925,13 +935,12 @@ impl TransInfo {
|
|||
gl::active_texture(1);
|
||||
self.revealage.bind(gl::TEXTURE_2D);
|
||||
gl::active_texture(2);
|
||||
self.fb_color.bind(gl::TEXTURE_2D_MULTISAMPLE);
|
||||
self.fb_color.bind(gl::TEXTURE_2D);
|
||||
|
||||
shader.program.use_program();
|
||||
shader.accum.set_int(0);
|
||||
shader.revealage.set_int(1);
|
||||
shader.color.set_int(2);
|
||||
shader.samples.set_int(NUM_SAMPLES);
|
||||
self.array.bind();
|
||||
gl::draw_arrays(gl::TRIANGLES, 0, 6);
|
||||
}
|
||||
|
@ -951,7 +960,7 @@ pub struct TextureManager {
|
|||
|
||||
skins: HashMap<String, AtomicIsize, BuildHasherDefault<FNVHash>>,
|
||||
|
||||
_skin_thread: thread::JoinHandle<()>,
|
||||
_skin_thread: Option<thread::JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl TextureManager {
|
||||
|
@ -966,7 +975,13 @@ impl TextureManager {
|
|||
) {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let (stx, srx) = mpsc::channel();
|
||||
let skin_thread = thread::spawn(|| Self::process_skins(srx, tx));
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let skin_thread = None;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let skin_thread = Some(thread::spawn(|| Self::process_skins(srx, tx)));
|
||||
|
||||
let mut tm = TextureManager {
|
||||
textures: HashMap::with_hasher(BuildHasherDefault::default()),
|
||||
version: {
|
||||
|
@ -1143,8 +1158,7 @@ impl TextureManager {
|
|||
self.add_defaults();
|
||||
|
||||
for name in map.keys() {
|
||||
if name.starts_with("steven-dynamic:") {
|
||||
let n = &name["steven-dynamic:".len()..];
|
||||
if let Some(n) = name.strip_prefix("steven-dynamic:") {
|
||||
let (width, height, data) = {
|
||||
let dynamic_texture = match self.dynamic_textures.get(n) {
|
||||
Some(val) => val,
|
||||
|
@ -1152,7 +1166,7 @@ impl TextureManager {
|
|||
};
|
||||
let img = &dynamic_texture.1;
|
||||
let (width, height) = img.dimensions();
|
||||
(width, height, img.to_rgba().into_vec())
|
||||
(width, height, img.to_rgba8().into_vec())
|
||||
};
|
||||
let new_tex =
|
||||
self.put_texture("steven-dynamic", n, width as u32, height as u32, data);
|
||||
|
@ -1213,7 +1227,7 @@ impl TextureManager {
|
|||
};
|
||||
|
||||
self.pending_uploads
|
||||
.push((tex.atlas, rect, img.to_rgba().into_vec()));
|
||||
.push((tex.atlas, rect, img.to_rgba8().into_vec()));
|
||||
self.dynamic_textures
|
||||
.get_mut(&format!("skin-{}", hash))
|
||||
.unwrap()
|
||||
|
@ -1243,7 +1257,7 @@ impl TextureManager {
|
|||
let (width, height) = img.dimensions();
|
||||
// Might be animated
|
||||
if (name.starts_with("blocks/") || name.starts_with("items/")) && width != height {
|
||||
let id = img.to_rgba().into_vec();
|
||||
let id = img.to_rgba8().into_vec();
|
||||
let frame = id[..(width * width * 4) as usize].to_owned();
|
||||
if let Some(mut ani) = self.load_animation(plugin, name, &img, id) {
|
||||
ani.texture = self.put_texture(plugin, name, width, width, frame);
|
||||
|
@ -1251,7 +1265,7 @@ impl TextureManager {
|
|||
return;
|
||||
}
|
||||
}
|
||||
self.put_texture(plugin, name, width, height, img.to_rgba().into_vec());
|
||||
self.put_texture(plugin, name, width, height, img.to_rgba8().into_vec());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1332,7 +1346,7 @@ impl TextureManager {
|
|||
|
||||
let mut full_name = String::new();
|
||||
full_name.push_str(plugin);
|
||||
full_name.push_str(":");
|
||||
full_name.push(':');
|
||||
full_name.push_str(name);
|
||||
|
||||
let tex = Texture {
|
||||
|
@ -1372,7 +1386,7 @@ impl TextureManager {
|
|||
|
||||
let mut full_name = String::new();
|
||||
full_name.push_str(plugin);
|
||||
full_name.push_str(":");
|
||||
full_name.push(':');
|
||||
full_name.push_str(name);
|
||||
|
||||
let t = Texture {
|
||||
|
@ -1406,7 +1420,7 @@ impl TextureManager {
|
|||
rect_pos = Some(i);
|
||||
}
|
||||
}
|
||||
let data = img.to_rgba().into_vec();
|
||||
let data = img.to_rgba8().into_vec();
|
||||
|
||||
if let Some(rect_pos) = rect_pos {
|
||||
let mut tex = self.free_dynamics.remove(rect_pos);
|
||||
|
|
|
@ -114,7 +114,7 @@ impl Manager {
|
|||
v.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 36, 28)
|
||||
}
|
||||
if let Some(v) = collection.shader.id {
|
||||
v.vertex_pointer_int(1, gl::UNSIGNED_BYTE, 36, 32)
|
||||
v.vertex_pointer_int(1, gl::BYTE, 36, 32)
|
||||
}
|
||||
|
||||
let mut model = Model {
|
||||
|
@ -249,19 +249,19 @@ impl Manager {
|
|||
gl::enable(gl::BLEND);
|
||||
for collection in &self.collections {
|
||||
collection.shader.program.use_program();
|
||||
if let Some(v) = collection.shader.perspective_matrix {
|
||||
if let Some(v) = &collection.shader.perspective_matrix {
|
||||
v.set_matrix4(perspective_matrix)
|
||||
}
|
||||
if let Some(v) = collection.shader.camera_matrix {
|
||||
if let Some(v) = &collection.shader.camera_matrix {
|
||||
v.set_matrix4(camera_matrix)
|
||||
}
|
||||
if let Some(v) = collection.shader.texture {
|
||||
if let Some(v) = &collection.shader.texture {
|
||||
v.set_int(0)
|
||||
}
|
||||
if let Some(v) = collection.shader.sky_offset {
|
||||
if let Some(v) = &collection.shader.sky_offset {
|
||||
v.set_float(sky_offset)
|
||||
}
|
||||
if let Some(v) = collection.shader.light_level {
|
||||
if let Some(v) = &collection.shader.light_level {
|
||||
v.set_float(light_level)
|
||||
}
|
||||
gl::blend_func(collection.blend_s, collection.blend_d);
|
||||
|
@ -276,16 +276,14 @@ impl Manager {
|
|||
continue;
|
||||
}
|
||||
model.array.bind();
|
||||
if let Some(v) = collection.shader.lighting {
|
||||
if let Some(v) = &collection.shader.lighting {
|
||||
v.set_float2(model.block_light, model.sky_light)
|
||||
}
|
||||
if let Some(v) = collection.shader.model_matrix {
|
||||
if let Some(v) = &collection.shader.model_matrix {
|
||||
v.set_matrix4_multi(&model.matrix)
|
||||
}
|
||||
if let Some(v) = collection.shader.color_mul {
|
||||
unsafe {
|
||||
v.set_float_multi_raw(model.colors.as_ptr() as *const _, model.colors.len())
|
||||
}
|
||||
if let Some(v) = &collection.shader.color_mul {
|
||||
v.set_float_multi(&model.colors)
|
||||
}
|
||||
gl::draw_elements(gl::TRIANGLES, model.count, self.index_type, 0);
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ pub fn create_program(vertex: &str, fragment: &str) -> gl::Program {
|
|||
v.set_source(vertex);
|
||||
v.compile();
|
||||
|
||||
if v.get_parameter(gl::COMPILE_STATUS) == 0 {
|
||||
if !v.get_shader_compile_status() {
|
||||
error!("Src: {}", vertex);
|
||||
panic!("Shader error: {}", v.get_info_log());
|
||||
} else {
|
||||
|
@ -146,7 +146,7 @@ pub fn create_program(vertex: &str, fragment: &str) -> gl::Program {
|
|||
f.set_source(fragment);
|
||||
f.compile();
|
||||
|
||||
if f.get_parameter(gl::COMPILE_STATUS) == 0 {
|
||||
if !f.get_shader_compile_status() {
|
||||
error!("Src: {}", fragment);
|
||||
panic!("Shader error: {}", f.get_info_log());
|
||||
} else {
|
||||
|
|
|
@ -7,12 +7,23 @@ in float vAtlas;
|
|||
in vec3 vLighting;
|
||||
|
||||
#ifndef alpha
|
||||
#ifdef ES
|
||||
layout(location = 2) out vec4 fragColor;
|
||||
#else
|
||||
out vec4 fragColor;
|
||||
#endif
|
||||
#else
|
||||
|
||||
#ifdef ES
|
||||
layout(location = 0) out vec4 accum;
|
||||
layout(location = 1) out float revealage;
|
||||
#else
|
||||
out vec4 accum;
|
||||
out float revealage;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include lookup_texture
|
||||
|
||||
void main() {
|
||||
|
|
|
@ -20,7 +20,7 @@ out vec3 vLighting;
|
|||
|
||||
void main() {
|
||||
vec3 pos = vec3(aPosition.x, -aPosition.y, aPosition.z);
|
||||
vec3 o = vec3(offset.x, -offset.y / 4096.0, offset.z);
|
||||
vec3 o = vec3(float(offset.x), -float(offset.y) / 4096.0, float(offset.z));
|
||||
gl_Position = perspectiveMatrix * cameraMatrix * vec4(pos + o * 16.0, 1.0);
|
||||
|
||||
vColor = aColor;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const float invAtlasSize = 1.0 / 1024;
|
||||
const float invAtlasSize = 1.0 / 1024.0;
|
||||
vec4 atlasTexture() {
|
||||
vec2 tPos = vTextureOffset;
|
||||
tPos = clamp(tPos, vec2(0.1), vTextureInfo.zw - 0.1);
|
||||
|
|
|
@ -26,8 +26,8 @@ void main() {
|
|||
|
||||
vColor = aColor;
|
||||
vTextureInfo = aTextureInfo;
|
||||
vTextureOffset = aTextureOffset.xy / 16.0;
|
||||
vAtlas = aTextureOffset.z;
|
||||
vTextureOffset = vec2(aTextureOffset.xy) / 16.0;
|
||||
vAtlas = float(aTextureOffset.z);
|
||||
vID = float(id);
|
||||
|
||||
vLighting = getLight(lighting);
|
||||
|
|
|
@ -21,7 +21,7 @@ void main() {
|
|||
gl_Position = perspectiveMatrix * cameraMatrix * modelMatrix[id] * vec4(pos, 1.0);
|
||||
|
||||
vTextureInfo = aTextureInfo;
|
||||
vTextureOffset = aTextureOffset.xy / 16.0;
|
||||
vAtlas = aTextureOffset.z;
|
||||
vTextureOffset = vec2(aTextureOffset.xy) / 16.0;
|
||||
vAtlas = float(aTextureOffset.z);
|
||||
vID = float(id);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
uniform sampler2D taccum;
|
||||
uniform sampler2D trevealage;
|
||||
uniform sampler2DMS tcolor;
|
||||
|
||||
uniform int samples;
|
||||
uniform sampler2D tcolor;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
|
@ -12,11 +10,6 @@ void main() {
|
|||
float aa = texelFetch(trevealage, C, 0).r;
|
||||
vec4 col = texelFetch(tcolor, C, 0);
|
||||
|
||||
for (int i = 1; i < samples; i++) {
|
||||
col += texelFetch(tcolor, C, i);
|
||||
}
|
||||
col /= float(samples);
|
||||
|
||||
float r = accum.a;
|
||||
accum.a = aa;
|
||||
if (r >= 1.0) {
|
||||
|
|
|
@ -11,10 +11,10 @@ out float vAtlas;
|
|||
uniform vec2 screenSize;
|
||||
|
||||
void main() {
|
||||
vec2 pos = aPosition.xy / screenSize;
|
||||
vec2 pos = vec2(aPosition.xy) / screenSize;
|
||||
gl_Position = vec4((pos.x-0.5)*2.0, -(pos.y-0.5)*2.0, float(-aPosition.z) / float(0xFFFF-1), 1.0);
|
||||
vColor = aColor;
|
||||
vTextureInfo = aTextureInfo;
|
||||
vTextureOffset = aTextureOffset.xy / 16.0;
|
||||
vAtlas = aTextureOffset.z;
|
||||
}
|
||||
vTextureOffset = vec2(aTextureOffset.xy) / 16.0;
|
||||
vAtlas = float(aTextureOffset.z);
|
||||
}
|
||||
|
|
|
@ -175,7 +175,7 @@ impl super::Screen for Login {
|
|||
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))
|
||||
.map(|()| rand::thread_rng().sample(&rand::distributions::Alphanumeric) as char)
|
||||
.take(20)
|
||||
.collect();
|
||||
self.vars.set(auth::AUTH_CLIENT_TOKEN, client_token);
|
||||
|
|
|
@ -24,8 +24,8 @@ use crate::protocol;
|
|||
use crate::render;
|
||||
use crate::ui;
|
||||
|
||||
use instant::Duration;
|
||||
use rand::Rng;
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct ServerList {
|
||||
elements: Option<UIElements>,
|
||||
|
@ -528,6 +528,7 @@ impl super::Screen for ServerList {
|
|||
let name: String = std::iter::repeat(())
|
||||
.map(|()| {
|
||||
rand::thread_rng().sample(&rand::distributions::Alphanumeric)
|
||||
as char
|
||||
})
|
||||
.take(30)
|
||||
.collect();
|
||||
|
|
|
@ -509,6 +509,7 @@ impl Server {
|
|||
self pck {
|
||||
PluginMessageClientbound_i16 => on_plugin_message_clientbound_i16,
|
||||
PluginMessageClientbound => on_plugin_message_clientbound_1,
|
||||
JoinGame_WorldNames_IsHard => on_game_join_worldnames_ishard,
|
||||
JoinGame_WorldNames => on_game_join_worldnames,
|
||||
JoinGame_HashedSeed_Respawn => on_game_join_hashedseed_respawn,
|
||||
JoinGame_i32_ViewDistance => on_game_join_i32_viewdistance,
|
||||
|
@ -518,9 +519,11 @@ impl Server {
|
|||
Respawn_Gamemode => on_respawn_gamemode,
|
||||
Respawn_HashedSeed => on_respawn_hashedseed,
|
||||
Respawn_WorldName => on_respawn_worldname,
|
||||
Respawn_NBT => on_respawn_nbt,
|
||||
KeepAliveClientbound_i64 => on_keep_alive_i64,
|
||||
KeepAliveClientbound_VarInt => on_keep_alive_varint,
|
||||
KeepAliveClientbound_i32 => on_keep_alive_i32,
|
||||
ChunkData_Biomes3D_VarInt => on_chunk_data_biomes3d_varint,
|
||||
ChunkData_Biomes3D_bool => on_chunk_data_biomes3d_bool,
|
||||
ChunkData => on_chunk_data,
|
||||
ChunkData_Biomes3D => on_chunk_data_biomes3d,
|
||||
|
@ -533,6 +536,7 @@ impl Server {
|
|||
ChunkUnload => on_chunk_unload,
|
||||
BlockChange_VarInt => on_block_change_varint,
|
||||
BlockChange_u8 => on_block_change_u8,
|
||||
MultiBlockChange_Packed => on_multi_block_change_packed,
|
||||
MultiBlockChange_VarInt => on_multi_block_change_varint,
|
||||
MultiBlockChange_u16 => on_multi_block_change_u16,
|
||||
TeleportPlayer_WithConfirm => on_teleport_player_withconfirm,
|
||||
|
@ -970,6 +974,13 @@ impl Server {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_game_join_worldnames_ishard(
|
||||
&mut self,
|
||||
join: packet::play::clientbound::JoinGame_WorldNames_IsHard,
|
||||
) {
|
||||
self.on_game_join(join.gamemode, join.entity_id)
|
||||
}
|
||||
|
||||
fn on_game_join_worldnames(&mut self, join: packet::play::clientbound::JoinGame_WorldNames) {
|
||||
self.on_game_join(join.gamemode, join.entity_id)
|
||||
}
|
||||
|
@ -1047,6 +1058,10 @@ impl Server {
|
|||
self.respawn(respawn.gamemode)
|
||||
}
|
||||
|
||||
fn on_respawn_nbt(&mut self, respawn: packet::play::clientbound::Respawn_NBT) {
|
||||
self.respawn(respawn.gamemode)
|
||||
}
|
||||
|
||||
fn respawn(&mut self, gamemode_u8: u8) {
|
||||
self.world = world::World::new(self.protocol_version);
|
||||
let gamemode = Gamemode::from_int((gamemode_u8 & 0x7) as i32);
|
||||
|
@ -1760,23 +1775,46 @@ impl Server {
|
|||
let x = block_entity.1.get("x").unwrap().as_int().unwrap();
|
||||
let y = block_entity.1.get("y").unwrap().as_int().unwrap();
|
||||
let z = block_entity.1.get("z").unwrap().as_int().unwrap();
|
||||
let tile_id = block_entity.1.get("id").unwrap().as_str().unwrap();
|
||||
let action;
|
||||
match tile_id {
|
||||
// Fake a sign update
|
||||
"Sign" => action = 9,
|
||||
// Not something we care about, so break the loop
|
||||
_ => continue,
|
||||
if let Some(tile_id) = block_entity.1.get("id") {
|
||||
let tile_id = tile_id.as_str().unwrap();
|
||||
let action;
|
||||
match tile_id {
|
||||
// Fake a sign update
|
||||
"Sign" => action = 9,
|
||||
// Not something we care about, so break the loop
|
||||
_ => continue,
|
||||
}
|
||||
self.on_block_entity_update(packet::play::clientbound::UpdateBlockEntity {
|
||||
location: Position::new(x, y, z),
|
||||
action,
|
||||
nbt: Some(block_entity.clone()),
|
||||
});
|
||||
} else {
|
||||
warn!(
|
||||
"Block entity at ({},{},{}) missing id tag: {:?}",
|
||||
x, y, z, block_entity
|
||||
);
|
||||
}
|
||||
self.on_block_entity_update(packet::play::clientbound::UpdateBlockEntity {
|
||||
location: Position::new(x, y, z),
|
||||
action,
|
||||
nbt: Some(block_entity.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_chunk_data_biomes3d_varint(
|
||||
&mut self,
|
||||
chunk_data: packet::play::clientbound::ChunkData_Biomes3D_VarInt,
|
||||
) {
|
||||
self.world
|
||||
.load_chunk115(
|
||||
chunk_data.chunk_x,
|
||||
chunk_data.chunk_z,
|
||||
chunk_data.new,
|
||||
chunk_data.bitmask.0 as u16,
|
||||
chunk_data.data.data,
|
||||
)
|
||||
.unwrap();
|
||||
self.load_block_entities(chunk_data.block_entities.data);
|
||||
}
|
||||
|
||||
fn on_chunk_data_biomes3d_bool(
|
||||
&mut self,
|
||||
chunk_data: packet::play::clientbound::ChunkData_Biomes3D_bool,
|
||||
|
@ -1934,6 +1972,31 @@ impl Server {
|
|||
);
|
||||
}
|
||||
|
||||
fn on_multi_block_change_packed(
|
||||
&mut self,
|
||||
block_change: packet::play::clientbound::MultiBlockChange_Packed,
|
||||
) {
|
||||
let sx = (block_change.chunk_section_pos >> 42) as i32;
|
||||
let sy = ((block_change.chunk_section_pos << 44) >> 44) as i32;
|
||||
let sz = ((block_change.chunk_section_pos << 22) >> 42) as i32;
|
||||
|
||||
for record in block_change.records.data {
|
||||
let block_raw_id = record.0 >> 12;
|
||||
let lz = (record.0 & 0xf) as i32;
|
||||
let ly = ((record.0 >> 4) & 0xf) as i32;
|
||||
let lx = ((record.0 >> 8) & 0xf) as i32;
|
||||
|
||||
self.world.set_block(
|
||||
Position::new(sx + lx as i32, sy + ly as i32, sz + lz as i32),
|
||||
block::Block::by_vanilla_id(
|
||||
block_raw_id as usize,
|
||||
self.protocol_version,
|
||||
&self.world.modded_block_ids,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_multi_block_change_varint(
|
||||
&mut self,
|
||||
block_change: packet::play::clientbound::MultiBlockChange_VarInt,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::console;
|
||||
use glutin::event::VirtualKeyCode;
|
||||
use std::marker::PhantomData;
|
||||
use winit::event::VirtualKeyCode;
|
||||
// Might just rename this to settings.rs
|
||||
|
||||
pub const R_MAX_FPS: console::CVar<i64> = console::CVar {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use crate::render;
|
||||
use crate::resources;
|
||||
use crate::ui;
|
||||
use instant::Instant;
|
||||
use rand::{self, seq::SliceRandom};
|
||||
use std::f64::consts;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
pub struct Logo {
|
||||
_shadow: ui::BatchRef,
|
||||
|
@ -15,6 +15,7 @@ pub struct Logo {
|
|||
text_orig_x: f64,
|
||||
text_index: isize,
|
||||
text_strings: Vec<String>,
|
||||
started: Instant,
|
||||
}
|
||||
|
||||
impl Logo {
|
||||
|
@ -131,11 +132,12 @@ impl Logo {
|
|||
text_orig_x,
|
||||
text_index: -1,
|
||||
text_strings,
|
||||
started: Instant::now(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, renderer: &mut render::Renderer) {
|
||||
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
let now = Instant::now().duration_since(self.started);
|
||||
|
||||
// Splash text
|
||||
let text_index = (now.as_secs() / 15) as isize % self.text_strings.len() as isize;
|
||||
|
|
|
@ -18,9 +18,9 @@ use crate::format;
|
|||
use crate::render;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use clipboard::{ClipboardContext, ClipboardProvider};
|
||||
use glutin::event::VirtualKeyCode;
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use std::rc::{Rc, Weak};
|
||||
use winit::event::VirtualKeyCode;
|
||||
|
||||
const SCALED_WIDTH: f64 = 854.0;
|
||||
const SCALED_HEIGHT: f64 = 480.0;
|
||||
|
|
|
@ -206,7 +206,7 @@ impl World {
|
|||
|
||||
#[allow(clippy::verbose_bit_mask)] // "llvm generates better code" for updates_performed & 0xFFF "on x86"
|
||||
pub fn tick(&mut self, m: &mut ecs::Manager) {
|
||||
use std::time::Instant;
|
||||
use instant::Instant;
|
||||
let start = Instant::now();
|
||||
let mut updates_performed = 0;
|
||||
while !self.light_updates.is_empty() {
|
||||
|
@ -430,7 +430,7 @@ impl World {
|
|||
y: i32,
|
||||
z: i32,
|
||||
) -> Option<(Option<&mut Section>, &mut u32)> {
|
||||
if y < 0 || y > 15 {
|
||||
if !(0..=15).contains(&y) {
|
||||
return None;
|
||||
}
|
||||
if let Some(chunk) = self.chunks.get_mut(&CPos(x, z)) {
|
||||
|
@ -540,7 +540,7 @@ impl World {
|
|||
let z2 = min(16, max(0, z + d - (cz << 4)));
|
||||
|
||||
for cy in cy1..cy2 {
|
||||
if cy < 0 || cy > 15 {
|
||||
if !(0..=15).contains(&cy) {
|
||||
continue;
|
||||
}
|
||||
let section = &chunk.sections[cy as usize];
|
||||
|
@ -1066,7 +1066,8 @@ impl World {
|
|||
}
|
||||
|
||||
let bits = LenPrefixed::<VarInt, u64>::read_from(&mut data)?.data;
|
||||
let m = bit::Map::from_raw(bits, bit_size as usize);
|
||||
let padded = self.protocol_version >= 736;
|
||||
let m = bit::Map::from_raw(bits, bit_size as usize, padded);
|
||||
|
||||
for bi in 0..4096 {
|
||||
let id = m.get(bi);
|
||||
|
@ -1123,7 +1124,7 @@ impl World {
|
|||
}
|
||||
|
||||
fn flag_section_dirty(&mut self, x: i32, y: i32, z: i32) {
|
||||
if y < 0 || y > 15 {
|
||||
if !(0..=15).contains(&y) {
|
||||
return;
|
||||
}
|
||||
let cpos = CPos(x, z);
|
||||
|
@ -1254,7 +1255,7 @@ impl Chunk {
|
|||
|
||||
fn set_block(&mut self, x: i32, y: i32, z: i32, b: block::Block) -> bool {
|
||||
let s_idx = y >> 4;
|
||||
if s_idx < 0 || s_idx > 15 {
|
||||
if !(0..=15).contains(&s_idx) {
|
||||
return false;
|
||||
}
|
||||
let s_idx = s_idx as usize;
|
||||
|
@ -1296,7 +1297,7 @@ 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 {
|
||||
if !(0..=15).contains(&s_idx) {
|
||||
return block::Missing {};
|
||||
}
|
||||
match self.sections[s_idx as usize].as_ref() {
|
||||
|
@ -1307,7 +1308,7 @@ impl Chunk {
|
|||
|
||||
fn get_block_light(&self, x: i32, y: i32, z: i32) -> u8 {
|
||||
let s_idx = y >> 4;
|
||||
if s_idx < 0 || s_idx > 15 {
|
||||
if !(0..=15).contains(&s_idx) {
|
||||
return 0;
|
||||
}
|
||||
match self.sections[s_idx as usize].as_ref() {
|
||||
|
@ -1318,7 +1319,7 @@ impl Chunk {
|
|||
|
||||
fn set_block_light(&mut self, x: i32, y: i32, z: i32, light: u8) {
|
||||
let s_idx = y >> 4;
|
||||
if s_idx < 0 || s_idx > 15 {
|
||||
if !(0..=15).contains(&s_idx) {
|
||||
return;
|
||||
}
|
||||
let s_idx = s_idx as usize;
|
||||
|
@ -1336,7 +1337,7 @@ impl Chunk {
|
|||
|
||||
fn get_sky_light(&self, x: i32, y: i32, z: i32) -> u8 {
|
||||
let s_idx = y >> 4;
|
||||
if s_idx < 0 || s_idx > 15 {
|
||||
if !(0..=15).contains(&s_idx) {
|
||||
return 15;
|
||||
}
|
||||
match self.sections[s_idx as usize].as_ref() {
|
||||
|
@ -1347,7 +1348,7 @@ impl Chunk {
|
|||
|
||||
fn set_sky_light(&mut self, x: i32, y: i32, z: i32, light: u8) {
|
||||
let s_idx = y >> 4;
|
||||
if s_idx < 0 || s_idx > 15 {
|
||||
if !(0..=15).contains(&s_idx) {
|
||||
return;
|
||||
}
|
||||
let s_idx = s_idx as usize;
|
||||
|
|
|
@ -1,276 +1,14 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "base-x"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "discard"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "localstoragefs"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stdweb 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.6.0"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "std_or_web"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"localstoragefs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stdweb-derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stdweb-internal-macros 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stdweb-internal-runtime 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-derive"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-internal-macros"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base-x 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-internal-runtime"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-macro 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-shared 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-macro-support 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-backend 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-shared 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum base-x 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b20b618342cf9891c292c4f5ac2cde7287cc5c87e87e9c769d617793607dec1"
|
||||
"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
||||
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
|
||||
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum localstoragefs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba6cbee6bbe7e6ea61ad375952239a9678624f216a0f442ae04a90260e76cdf"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
"checksum proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc"
|
||||
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
|
||||
"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
|
||||
"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7"
|
||||
"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
||||
"checksum stdweb 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5"
|
||||
"checksum stdweb-derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
|
||||
"checksum stdweb-internal-macros 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
|
||||
"checksum stdweb-internal-runtime 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
|
||||
"checksum syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8"
|
||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
"checksum wasm-bindgen 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)" = "99de4b68939a880d530aed51289a7c7baee154e3ea8ac234b542c49da7134aaf"
|
||||
"checksum wasm-bindgen-backend 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)" = "b58e66a093a7b7571cb76409763c495b8741ac4319ac20acc2b798f6766d92ee"
|
||||
"checksum wasm-bindgen-macro 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)" = "a80f89daea7b0a67b11f6e9f911422ed039de9963dce00048a653b63d51194bf"
|
||||
"checksum wasm-bindgen-macro-support 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)" = "4f9dbc3734ad6cff6b76b75b7df98c06982becd0055f651465a08f769bca5c61"
|
||||
"checksum wasm-bindgen-shared 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)" = "d907984f8506b3554eab48b8efff723e764ddbf76d4cd4a3fe4196bc00c49a70"
|
||||
|
|
|
@ -5,7 +5,4 @@ authors = [ "iceiix <ice_ix@protonmail.ch>" ]
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "0.1.10"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
localstoragefs = "0.1.0"
|
||||
cfg-if = "1.0.0"
|
||||
|
|
|
@ -2,7 +2,52 @@ use cfg_if::cfg_if;
|
|||
|
||||
cfg_if! {
|
||||
if #[cfg(target_arch = "wasm32")] {
|
||||
pub use localstoragefs::fs;
|
||||
// TODO: a real filesystem like https://emscripten.org/docs/api_reference/Filesystem-API.html
|
||||
pub mod fs {
|
||||
use std::convert::AsRef;
|
||||
use std::io::Result;
|
||||
use std::path::Path;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
pub struct File { }
|
||||
|
||||
impl File {
|
||||
pub fn create<P: AsRef<Path>>(path: P) -> Result<File> {
|
||||
println!("File create {}", path.as_ref().to_str().unwrap());
|
||||
Ok(File{})
|
||||
}
|
||||
|
||||
pub fn open<P: AsRef<Path>>(path: P) -> Result<File> {
|
||||
println!("File open {}", path.as_ref().to_str().unwrap());
|
||||
Err(std::io::Error::new(std::io::ErrorKind::Other, "No files exist on web"))
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for File {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Result<usize> {
|
||||
println!("File read");
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for &File {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Result<usize> {
|
||||
println!("&File read");
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for File {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
println!("File write {:?}", buf);
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pub use std::fs;
|
||||
}
|
||||
|
|
|
@ -2,12 +2,21 @@
|
|||
|
||||
Web app for running Stevenarella as WebAssembly
|
||||
|
||||
Status: very incomplete. It does not currently compile, due to required modifications to adapt to the web,
|
||||
for progress see: [https://github.com/iceiix/stevenarella/issues/171](https://github.com/iceiix/stevenarella/issues/171).
|
||||
Status: very incomplete. It currently compiles but does not run, due to required modifications to adapt to the web,
|
||||
for progress see: [🕸️ Web support](https://github.com/iceiix/stevenarella/issues/446)
|
||||
|
||||
## Building
|
||||
|
||||
To build for wasm32-unknown-unknown, run:
|
||||
To build for wasm32-unknown-unknown, run in the top-level directory (not www):
|
||||
|
||||
```sh
|
||||
rustup target add wasm32-unknown-unknown
|
||||
cargo install wasm-bindgen-cli
|
||||
cargo install wasm-pack
|
||||
wasm-pack build --dev
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```sh
|
||||
cargo web start --target wasm32-unknown-unknown
|
||||
|
@ -19,7 +28,7 @@ After building the Rust app, run the NodeJS web server as follows:
|
|||
|
||||
```sh
|
||||
cd pkg
|
||||
npm link
|
||||
sudo npm link
|
||||
cd ..
|
||||
cd www
|
||||
npm link stevenarella
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import * as wasm from "stevenarella";
|
||||
import * as wasm from "../pkg/stevenarella_bg.wasm";
|
||||
|
||||
wasm.main();
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -19,8 +19,8 @@
|
|||
},
|
||||
"homepage": "https://github.com/rustwasm/create-wasm-app#readme",
|
||||
"devDependencies": {
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"webpack": "^4.43.0",
|
||||
"copy-webpack-plugin": "^5.1.2",
|
||||
"webpack": "^4.44.2",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue