Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,4 @@ tracing-appender = "0.2"
paste = "1.0"
chrono = "0.4"
clap = { version = "4.5", features = ["derive"] }
indexmap = "2.11"
107 changes: 16 additions & 91 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@ MCHPRS has made it possible to run programs such as [a limited form of Minecraft
- [Table of Contents](#table-of-contents)
- [Building](#building)
- [Configuration](#configuration)
- [Velocity](#velocity)
- [LuckPerms](#luckperms)
- [Usage](#usage)
- [General Commands](#general-commands)
- [Plot Ownership](#plot-ownership)
- [Worldedit](#worldedit)
- [Redpiler](#redpiler)
- [Acknowledgments](#acknowledgments)
- [Contributing](#contributing)
- [License](#license)
Expand All @@ -41,15 +38,15 @@ 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):
The following 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}` |
| `chat_format` | How to format chat messages 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` |
| `whitelist` | Whether or not the whitelist (in `whitelist.json`) shoud be enabled | `false` |
| `whitelist` | Whether or not the whitelist (in `whitelist.json`) should 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 | `false` |
Expand All @@ -72,7 +69,7 @@ secret = "<secret>"

### 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`)
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 managed through LuckPerms running on a proxy (`/lpb`) or other server (`/lp`).

To use LuckPerms, append this to your `Config.toml`:

Expand All @@ -85,98 +82,26 @@ db_name = "minecraft"
# Credentials for the database.
username = "minecraft"
password = "minecraft"
# The name of the server, used for server specific permissions.
# The name of the server, used for server-specific permissions.
# See: https://luckperms.net/wiki/Context
server_context = "global"
```

## Usage

### General Commands
| Command | Alias | Description |
| --- | --- |--- |
| `/rtps [rtps\|unlimited]` | None | Set the **redstone** ticks per second in the plot to `[rtps]`. (There are two game ticks in a redstone tick) |
| `/radvance [ticks]` | `/radv` | Advances the plot by `[ticks]` redstone ticks. |
| `/teleport [player]` | `/tp` | Teleports you to `[player]`. |
| `/teleport [x] [y] [z]` | `/tp` | Teleports you to `[x] [y] [z]`. Supports relative coordinates. Floats can be expressed as described [here](https://doc.rust-lang.org/std/primitive.f64.html#grammar). |
| `/speed [speed]` | None | Sets your flyspeed. |
| `/gamemode [mode]` | `/gmc`, `/gmsp` | Sets your gamemode. |
| `/container [type] [power]` | None | Gives you a container (e.g. barrel) which outputs a specified amount of power when used with a comparator. |
| `/toggleautorp` | None | Toggles automatic redpiler compilation. |
| `/stop` | None | Stops the server. |

### Plot Ownership
The plot ownership system in MCHPRS is very incomplete.
These are the commands that are currently implemented:
| Command | Alias | Description |
| --- | --- |--- |
| `/plot info` | `/p i` | Gets the owner of the plot you are in. |
| `/plot claim` | `/p c` | Claims the plot you are in if it is not already claimed. |
| `/plot auto` | `/p a` | Automatically finds an unclaimed plot and claims. |
| `/plot middle` | None | Teleports you to the center of the plot you are in. |
| `/plot visit [player]` | `/p v` | Teleports you to a player's plot. |
| `/plot tp [x] [z]` | None | Teleports you to the plot at `[x] [y]`. Supports relative coordinates. |
| `/plot lock` | None | Locks the player into the plot so moving outside of the plot bounds does not transfer you to other plots. |
| `/plot unlock` | None | Reverses the locking done by `/plot lock`. |
| `/plot select` | `/p sel` | Uses WorldEdit to select the entire plot. |

### Worldedit
MCHPRS provides its own implementation of [WorldEdit](https://github.com/EngineHub/WorldEdit). Visit their [documentation](https://worldedit.enginehub.org/en/latest/commands/) for more information.
These are the commands that are currently implemented:
| Command | Alias | Description |
| --- | --- | --- |
| `/up` | `/u` | Go upwards some distance |
| `/ascend` | `/asc` | Go up a floor |
| `/descend` | `/desc` | Go down a floor |
| `//pos1` | `//1` | Set position 1 |
| `//pos2` | `//2` | Set position 2 |
| `//hpos1` | `//h1` | Set position 1 to targeted block |
| `//hpos2` | `//h2` | Set position 2 to targeted block |
| `//sel` | None | Clears your worldedit first and second positions. |
| `//set` | None | Sets all the blocks in the region |
| `//replace` | None | Replace all blocks in a selection with another |
| `//copy` | `//c` | Copy the selection to the clipboard |
| `//cut` | `//x` | Cut the selection to the clipboard |
| `//paste` | `//v` | Paste the clipboard's contents (`-a` to ignore air, `-u` to also update) |
| `//undo` | None | Undoes the last action (from history) |
| `//redo` | None | Redoes the last action (from history) |
| `//rstack` | `//rs` | Stack with more options, Refer to [RedstoneTools](https://github.com/paulikauro/RedstoneTools) |
| `//stack` | `//s` | Repeat the contents of the selection |
| `//move` | None | Move the contents of the selection |
| `//count` | None | Counts the number of blocks matching a mask |
| `//load` | None | Loads a schematic from the `./schems/` folder. Make sure the schematic in the Sponge format if there are any issues. |
| `//save` | None | Save a schematic to the `./schems/` folder. |
| `//expand` | `//e` | Expand the selection area |
| `//contract` | None | Contract the selection area |
| `//shift` | None | Shift the selection area |
| `//flip` | `//f` | Flip the contents of the clipboard across the origin |
| `//rotate` | `//r` | Rotate the contents of the clipboard |
| `//update` | None | Updates all blocks in the selection (`-p` to update the entire plot) |
| `//help` | None | Displays help for WorldEdit commands |

### Redpiler

MCHPRS provides Redpiler, the redstone compiler. This allows redstone simulation much faster than otherwise possible.
While redpiler is running, all redstone connections are pre-computed, thus interaction with the world is limited in this state.
Placing or breaking blocks while redpiler is running will cause a reset and disable redpiler.

| Command | Alias | Description |
| --- | --- | --- |
| `/redpiler compile` | `/rp c` | Manually starts redpiler compilation. There are several flags available, described below. |
| `/redpiler reset` | `/rp r` | Stops redpiler. |
For a full list of commands, see [Commands](docs/Commands.md).

| Flag | Short | Description |
| --- | --- | --- |
| `--optimize` | `-o` | Enable redpiler optimizations. WARNING: This can, and will, break the state of your build. Use backups when using this flag. |
| `--io-only` | `-i` | Only send blocks updates of relavent input/output blocks. This includes trapdoors, lamps, note blocks, buttons, levers, and pressure plates. Using this flag can significantly reduce lag and improve simulation speed. |
| `--wire-dot-out` | `-d` | Consider wires in the dot shape as an output block for `-i`. Useful for e.g. color displays. |
| `--update` | `-u` | Update all blocks after redpiler resets. |
| `--export` | `-e` | Export the compile graph using a binary format. This can be useful for developing out-of-tree uses of redpiler graphs. |
| `--export-dot` | None | Create a graphvis dot file of backend graph. Used for debugging/development. |
The following categories of commands are implemented:
- **General** - Server control, player teleportation, and gamemode
- **Plot** - Claiming and managing plots
- **WorldEdit** - Selection, region operations, clipboard, and schematics
- **Redpiler** - Redstone compiler operations

Use the `/help [<command>]` command in-game to get detailed information about any specific command.

## Acknowledgments
- [@AL1L](https://github.com/AL1L) for his contributions to worldedit and other various features.
- [@DavidGarland](https://github.com/DavidGarland) for a faster and overall better implementation of `get_entry` in the in-memory storage. This simple function runs 30% of the runtime for redstone.
- [@DavidGarland](https://github.com/DavidGarland) for a faster and overall better implementation of `get_entry` in the in-memory storage. This simple function accounts for 30% of the redstone runtime.

## Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Expand Down
9 changes: 9 additions & 0 deletions crates/blocks/src/block_entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ impl ContainerType {
}
}

pub fn items_needed_for_signal_strength(self, signal_strength: u8) -> usize {
let slots = self.num_slots() as usize;
match signal_strength {
0 => 0,
15 => slots * 64,
_ => ((32 * slots * signal_strength as usize) as f32 / 7.0 - 1.0).ceil() as usize,
}
}

pub fn window_type(self) -> u8 {
// https://wiki.vg/Inventory
match self {
Expand Down
50 changes: 20 additions & 30 deletions crates/blocks/src/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,43 +17,33 @@ impl ItemStack {
ContainerType::Hopper => Item::Hopper {},
ContainerType::Furnace => Item::Furnace {},
};
let slots = container_ty.num_slots() as u32;

let items_needed = match ss {
0 => 0,
15 => slots * 64,
_ => ((32 * slots * ss as u32) as f32 / 7.0 - 1.0).ceil() as u32,
} as usize;
let items_needed = container_ty.items_needed_for_signal_strength(ss);

let nbt = match items_needed {
0 => None,
_ => Some({
let list = nbt::Value::List({
let mut items = Vec::new();
for (slot, items_added) in (0..items_needed).step_by(64).enumerate() {
let count = (items_needed - items_added).min(64);
items.push(nbt::Value::Compound(map! {
"Count" => nbt::Value::Byte(count as i8),
"id" => nbt::Value::String("minecraft:redstone".to_owned()),
"Slot" => nbt::Value::Byte(slot as i8)
}));
}
items
});
let list = nbt::Value::List({
let mut items = Vec::new();
for (slot, items_added) in (0..items_needed).step_by(64).enumerate() {
let count = (items_needed - items_added).min(64);
items.push(nbt::Value::Compound(map! {
"Count" => nbt::Value::Byte(count as i8),
"id" => nbt::Value::String("minecraft:redstone".to_owned()),
"Slot" => nbt::Value::Byte(slot as i8)
}));
}
items
});

nbt::Blob::with_content(map! {
"BlockEntityTag" => nbt::Value::Compound(map! {
"Items" => list,
"Id" => nbt::Value::String(container_ty.to_string())
})
})
}),
};
let nbt = nbt::Blob::with_content(map! {
"BlockEntityTag" => nbt::Value::Compound(map! {
"Items" => list,
"Id" => nbt::Value::String(container_ty.to_string())
})
});

ItemStack {
item_type: item,
count: 1,
nbt,
nbt: Some(nbt),
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,5 @@ once_cell = { workspace = true }
rustc-hash = { workspace = true }
hmac = { workspace = true }
sha2 = { workspace = true }
thiserror = { workspace = true }
indexmap = { workspace = true }
Loading