diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 736c1552..86365a99 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,10 +30,9 @@ jobs: - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: - toolchain: nightly + toolchain: stable target: ${{ matrix.target }} profile: minimal - override: true - uses: Swatinem/rust-cache@v1 with: key: ${{ matrix.target }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c50f700b..426d0051 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,8 +17,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: nightly - override: true + toolchain: stable - uses: Swatinem/rust-cache@v1 - name: Build run: cargo test --verbose \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index e4dfb985..7c384807 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1371,6 +1371,7 @@ dependencies = [ "mchprs_world", "md5", "mysql", + "once_cell", "petgraph", "rand", "redpiler_graph", @@ -1677,9 +1678,9 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "openssl" -version = "0.10.52" +version = "0.10.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56" +checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" dependencies = [ "bitflags", "cfg-if", @@ -1709,9 +1710,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.87" +version = "0.9.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e" +checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" dependencies = [ "cc", "libc", diff --git a/README.md b/README.md index 9413d1c9..f055938a 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,20 @@ Once complete, the optimized executable will be located at `./target/release/mch MCHPRS will generate a `Config.toml` file in the current working directory when starting the server if it does not exist. +The folowing options are available at the toplevel (under no header): +| Field | Description | Default | +| --- | --- |--- | +| `bind_address` | Bind address and port | `0.0.0.0:25565` | +| `motd` | Message of the day | `"Minecraft High Performance Redstone Server"` | +| `chat_format` | How to format chat message interpolating `username` and `message` with curly braces | `<{username}> {message}` | +| `max_players` | Maximum number of simultaneous players | `99999` | +| `view_distance` | Maximal distance (in chunks) between players and loaded chunks | `8` | +| `bungeecord` | Enable compatibility with [BungeeCord](https://github.com/SpigotMC/BungeeCord) | `false` | +| `whitelist` | Whether or not the whitelist (in `whitelist.json`) shoud be enabled | `false` | +| `schemati` | Mimic the verification and directory layout used by the Open Redstone Engineers [Schemati plugin](https://github.com/OpenRedstoneEngineers/Schemati) | `false` | +| `block_in_hitbox` | Allow placing blocks inside of players (hitbox logic is simplified) | true | +| `auto_redpiler` | Use redpiler automatically | true | + ### LuckPerms MCHPRS has basic support for LuckPerms with MySQL or MariaDB remote database storage. This implementation has no commands or interface and would have to be manged through LuckPerms running on a proxy (`/lpb`) or other server (`/lp`) diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 2b9005ce..6f6ea34c 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -31,7 +31,7 @@ ctrlc = { version = "3.1", features = ["termination"] } tracing = "0.1" chrono = "0.4" rand = "0.8" -regex = { version = "1.4", features = ["pattern"] } +regex = { version = "1.4" } backtrace = "0.3" rusqlite = { version="0.28", features=["bundled"] } anyhow = "1.0" @@ -42,6 +42,7 @@ reqwest = { version = "0.11", features = ["json"] } itertools = "0.10" impls = "1" bincode = "1.3" +once_cell = "1.14.0" smallvec = "1.9.0" petgraph = "0.6" redpiler_graph = { path = "../redpiler_graph" } diff --git a/crates/core/src/blocks/mod.rs b/crates/core/src/blocks/mod.rs index c182f4b3..d3e6f7c6 100644 --- a/crates/core/src/blocks/mod.rs +++ b/crates/core/src/blocks/mod.rs @@ -47,11 +47,30 @@ trait BlockTransform { fn flip(&mut self, dir: crate::blocks::FlipDirection); } -impl BlockTransform for T { - default fn rotate90(&mut self) {} - default fn flip(&mut self, _dir: crate::blocks::FlipDirection) {} +macro_rules! noop_block_transform { + ($($ty:ty),*$(,)?) => { + $( + impl BlockTransform for $ty { + fn rotate90(&mut self) {} + fn flip(&mut self, dir: crate::blocks::FlipDirection) {} + } + )* + }; } +noop_block_transform!( + u8, + u32, + bool, + BlockColorVariant, + BlockFacing, + TrapdoorHalf, + SignType, + redstone::ButtonFace, + redstone::LeverFace, + redstone::ComparatorMode, +); + impl BlockTransform for BlockDirection { fn flip(&mut self, dir: FlipDirection) { match dir { diff --git a/crates/core/src/blocks/redstone/redstone_wire.rs b/crates/core/src/blocks/redstone/redstone_wire.rs index 34768ec7..0240032c 100644 --- a/crates/core/src/blocks/redstone/redstone_wire.rs +++ b/crates/core/src/blocks/redstone/redstone_wire.rs @@ -4,6 +4,7 @@ use crate::blocks::{ }; use crate::world::World; use std::collections::HashMap; +use std::convert::TryInto; use std::str::FromStr; impl Block { @@ -628,16 +629,18 @@ impl RedstoneWireTurbo { if self.nodes[upd1.index].neighbors.is_none() { self.identify_neighbors(world, upd1); } - // FIXME: Get rid of this nasty clone - let neighbors = self.nodes[upd1.index].neighbors.clone().unwrap(); + + let neighbors: [NodeId; 24] = self.nodes[upd1.index].neighbors.as_ref().unwrap()[0..24] + .try_into() + .unwrap(); let layer1 = layer + 1; - for neighbor_id in &neighbors[0..24] { + for neighbor_id in neighbors { let neighbor = &mut self.nodes[neighbor_id.index]; if layer1 > neighbor.layer { neighbor.layer = layer1; - self.update_queue[1].push(*neighbor_id); + self.update_queue[1].push(neighbor_id); } } diff --git a/crates/core/src/chat.rs b/crates/core/src/chat.rs index 5f013820..6215e132 100644 --- a/crates/core/src/chat.rs +++ b/crates/core/src/chat.rs @@ -1,8 +1,8 @@ +use once_cell::sync::Lazy; use regex::Regex; use serde::Serialize; -use std::sync::LazyLock; -static URL_REGEX: LazyLock = LazyLock::new(|| { +static URL_REGEX: Lazy = Lazy::new(|| { Regex::new("([a-zA-Z0-9§\\-:/]+\\.[a-zA-Z/0-9§\\-:_#]+(\\.[a-zA-Z/0-9.§\\-:#\\?\\+=_]+)?)") .unwrap() }); @@ -220,7 +220,10 @@ impl ChatComponent { for component in components { let mut last = 0; let text = &component.text; - for (index, matched) in text.match_indices(&*URL_REGEX) { + + for match_ in URL_REGEX.find_iter(text) { + let index = match_.start(); + let matched = match_.as_str(); if last != index { let mut new = component.clone(); new.text = String::from(&text[last..index]); diff --git a/crates/core/src/config.rs b/crates/core/src/config.rs index 103bb055..295355ae 100644 --- a/crates/core/src/config.rs +++ b/crates/core/src/config.rs @@ -1,11 +1,11 @@ use crate::permissions::PermissionsConfig; +use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use std::fs; use std::io::Write; -use std::sync::LazyLock; use toml_edit::{value, Document}; -pub static CONFIG: LazyLock = LazyLock::new(|| ServerConfig::load("Config.toml")); +pub static CONFIG: Lazy = Lazy::new(|| ServerConfig::load("Config.toml")); trait ConfigSerializeDefault { fn fix_config(self, name: &str, doc: &mut Document); diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index e573c335..5e2a1b21 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -1,5 +1,4 @@ #![deny(rust_2018_idioms)] -#![feature(min_specialization, lazy_cell)] #[macro_use] mod utils; diff --git a/crates/core/src/permissions/mod.rs b/crates/core/src/permissions/mod.rs index 78b5d326..73d08cb4 100644 --- a/crates/core/src/permissions/mod.rs +++ b/crates/core/src/permissions/mod.rs @@ -3,10 +3,10 @@ use crate::utils::HyphenatedUUID; use anyhow::{anyhow, Context, Result}; use mysql::prelude::*; use mysql::{OptsBuilder, Pool, PooledConn, Row}; +use once_cell::sync::OnceCell; use serde::{Deserialize, Serialize}; -use std::sync::OnceLock; -static POOL: OnceLock = OnceLock::new(); +static POOL: OnceCell = OnceCell::new(); fn conn() -> Result { Ok(POOL diff --git a/crates/core/src/plot/commands.rs b/crates/core/src/plot/commands.rs index 948d9628..4c169cdf 100644 --- a/crates/core/src/plot/commands.rs +++ b/crates/core/src/plot/commands.rs @@ -14,9 +14,9 @@ use mchprs_network::packets::clientbound::{ use mchprs_network::packets::PacketEncoder; use mchprs_network::PlayerPacketSender; use mchprs_save_data::plot_data::Tps; +use once_cell::sync::Lazy; use std::ops::Add; use std::str::FromStr; -use std::sync::LazyLock; use std::time::Instant; use tracing::{debug, info, warn}; @@ -512,7 +512,7 @@ bitflags! { // For more information, see https://wiki.vg/Command_Data /// The `DeclareCommands` packet that is sent when the player joins. /// This is used for command autocomplete. -pub static DECLARE_COMMANDS: LazyLock = LazyLock::new(|| { +pub static DECLARE_COMMANDS: Lazy = Lazy::new(|| { CDeclareCommands { nodes: &[ // 0: Root Node diff --git a/crates/core/src/plot/data.rs b/crates/core/src/plot/data.rs index 4b31c6d0..c7931643 100644 --- a/crates/core/src/plot/data.rs +++ b/crates/core/src/plot/data.rs @@ -1,8 +1,8 @@ use super::{Plot, PlotWorld, PLOT_WIDTH}; use anyhow::{Context, Result}; use mchprs_save_data::plot_data::{ChunkData, PlotData, Tps}; +use once_cell::sync::Lazy; use std::path::Path; -use std::sync::LazyLock; use std::time::Duration; // TODO: where to put this? @@ -33,7 +33,7 @@ pub fn empty_plot() -> PlotData { EMPTY_PLOT.clone() } -static EMPTY_PLOT: LazyLock = LazyLock::new(|| { +static EMPTY_PLOT: Lazy = Lazy::new(|| { let template_path = Path::new("./world/plots/pTEMPLATE"); if template_path.exists() { PlotData::load_from_file(template_path).expect("failed to read template plot") diff --git a/crates/core/src/plot/database.rs b/crates/core/src/plot/database.rs index 8a884008..a992b364 100644 --- a/crates/core/src/plot/database.rs +++ b/crates/core/src/plot/database.rs @@ -1,7 +1,8 @@ +use once_cell::sync::Lazy; use rusqlite::{params, Connection}; -use std::sync::{LazyLock, Mutex, MutexGuard}; +use std::sync::{Mutex, MutexGuard}; -static CONN: LazyLock> = LazyLock::new(|| { +static CONN: Lazy> = Lazy::new(|| { Mutex::new(Connection::open("./world/plots.db").expect("Error opening plot database!")) }); diff --git a/crates/core/src/plot/worldedit/execute.rs b/crates/core/src/plot/worldedit/execute.rs index abaa274b..0c60524f 100644 --- a/crates/core/src/plot/worldedit/execute.rs +++ b/crates/core/src/plot/worldedit/execute.rs @@ -9,6 +9,7 @@ use mchprs_blocks::items::{Item, ItemStack}; use mchprs_blocks::{BlockFace, BlockFacing, BlockPos}; use mchprs_network::packets::clientbound::*; use mchprs_network::packets::SlotData; +use once_cell::sync::Lazy; use schematic::{load_schematic, save_schematic}; use std::time::Instant; use tracing::error; @@ -252,8 +253,8 @@ pub(super) fn execute_paste(ctx: CommandExecuteContext<'_>) { } } -static SCHEMATI_VALIDATE_REGEX: LazyLock = - LazyLock::new(|| Regex::new(r"[a-zA-Z0-9_.]+\.schem(atic)?").unwrap()); +static SCHEMATI_VALIDATE_REGEX: Lazy = + Lazy::new(|| Regex::new(r"[a-zA-Z0-9_.]+\.schem(atic)?").unwrap()); pub(super) fn execute_load(mut ctx: CommandExecuteContext<'_>) { let start_time = Instant::now(); diff --git a/crates/core/src/plot/worldedit/mod.rs b/crates/core/src/plot/worldedit/mod.rs index 841a23e9..948fa118 100644 --- a/crates/core/src/plot/worldedit/mod.rs +++ b/crates/core/src/plot/worldedit/mod.rs @@ -12,13 +12,13 @@ use execute::*; use mchprs_blocks::block_entities::{BlockEntity, ContainerType}; use mchprs_blocks::{BlockFacing, BlockPos}; use mchprs_utils::map; +use once_cell::sync::Lazy; use rand::Rng; use regex::Regex; use std::collections::HashMap; use std::fmt; use std::ops::RangeInclusive; use std::str::FromStr; -use std::sync::LazyLock; // Attempts to execute a worldedit command. Returns true of the command was handled. // The command is not handled if it is not found in the worldedit commands and alias lists. @@ -433,7 +433,7 @@ impl Default for WorldeditCommand { } } -static COMMANDS: LazyLock> = LazyLock::new(|| { +static COMMANDS: Lazy> = Lazy::new(|| { map! { "up" => WorldeditCommand { execute_fn: execute_up, @@ -727,7 +727,7 @@ static COMMANDS: LazyLock> = LazyLock::n } }); -static ALIASES: LazyLock> = LazyLock::new(|| { +static ALIASES: Lazy> = Lazy::new(|| { map! { "u" => "up", "desc" => "descend", @@ -803,7 +803,7 @@ impl FromStr for WorldEditPattern { fn from_str(pattern_str: &str) -> PatternParseResult { let mut pattern = WorldEditPattern { parts: Vec::new() }; for part in pattern_str.split(',') { - static RE: LazyLock = LazyLock::new(|| { + static RE: Lazy = Lazy::new(|| { Regex::new(r"^(([0-9]+(\.[0-9]+)?)%)?(=)?([0-9]+|(minecraft:)?[a-zA-Z_]+)(:([0-9]+)|\[(([a-zA-Z_]+=[a-zA-Z0-9]+,?)+?)\])?((\|([^|]*?)){1,4})?$").unwrap() }); diff --git a/crates/core/src/plot/worldedit/schematic.rs b/crates/core/src/plot/worldedit/schematic.rs index 8b4670f3..461742fb 100644 --- a/crates/core/src/plot/worldedit/schematic.rs +++ b/crates/core/src/plot/worldedit/schematic.rs @@ -9,12 +9,12 @@ use anyhow::{bail, Context, Result}; use itertools::Itertools; use mchprs_blocks::block_entities::BlockEntity; use mchprs_blocks::BlockPos; +use once_cell::sync::Lazy; use regex::Regex; use serde::Serialize; use std::collections::HashMap; use std::fs::{self, File}; use std::path::PathBuf; -use std::sync::LazyLock; macro_rules! nbt_as { // I'm not sure if path is the right type here. @@ -28,8 +28,8 @@ macro_rules! nbt_as { } fn parse_block(str: &str) -> Option { - static RE: LazyLock = - LazyLock::new(|| Regex::new(r"(?:minecraft:)?([a-z_]+)(?:\[([a-z=,0-9]+)\])?").unwrap()); + static RE: Lazy = + Lazy::new(|| Regex::new(r"(?:minecraft:)?([a-z_]+)(?:\[([a-z=,0-9]+)\])?").unwrap()); let captures = RE.captures(str)?; let mut block = Block::from_name(captures.get(1)?.as_str()).unwrap_or(Block::Air {}); if let Some(properties_match) = captures.get(2) { diff --git a/docker/Dockerfile b/docker/Dockerfile index bee98585..87a67189 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM rustlang/rust:nightly-slim +FROM rust:slim RUN apt-get update \ && apt-get install -y \ diff --git a/docker/Dockerfile-plot-scale-5 b/docker/Dockerfile-plot-scale-5 index e472f958..4730aed5 100644 --- a/docker/Dockerfile-plot-scale-5 +++ b/docker/Dockerfile-plot-scale-5 @@ -1,4 +1,4 @@ -FROM rustlang/rust:nightly-slim +FROM rust:slim RUN apt-get update \ && apt-get install -y \ diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index 5d56faf9..00000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "nightly"