mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-31 20:32:34 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
55
.github/workflows/docs.yml
vendored
Normal file
55
.github/workflows/docs.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
# Based on https://vitepress.dev/guide/deploy#github-pages
|
||||
name: Deploy VitePress site to GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
workflow_dispatch:
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
|
||||
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
|
||||
concurrency:
|
||||
group: pages
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: npm
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v4
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Build with VitePress
|
||||
run: npm run docs:build
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: docs/.vitepress/dist
|
||||
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
name: Deploy
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -93,3 +93,8 @@ features.toml
|
||||
|
||||
|
||||
.vscode/settings.json
|
||||
|
||||
# Documentation
|
||||
docs/.vitepress/dist
|
||||
docs/.vitepress/cache
|
||||
node_modules
|
||||
|
||||
44
docs/.vitepress/config.mts
Normal file
44
docs/.vitepress/config.mts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { defineConfig } from "vitepress";
|
||||
|
||||
// https://vitepress.dev/reference/site-config
|
||||
export default defineConfig({
|
||||
title: "Pumpkin",
|
||||
description:
|
||||
"Empowering everyone to host fast and efficient Minecraft servers",
|
||||
lang: "en-US",
|
||||
base: "/Pumpkin/",
|
||||
themeConfig: {
|
||||
// https://vitepress.dev/reference/default-theme-config
|
||||
sidebar: [
|
||||
{
|
||||
text: "About",
|
||||
items: [
|
||||
{ text: "Introduction", link: "/about/introduction" },
|
||||
{ text: "Quick Start", link: "/about/quick-start" },
|
||||
{
|
||||
text: "Contributing",
|
||||
link: "https://github.com/Snowiiii/Pumpkin/blob/master/CONTRIBUTING.md",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "Plugins",
|
||||
items: [
|
||||
{ text: "About Plugins", link: "/plugins/about" },
|
||||
{
|
||||
text: "Getting Started in Rust",
|
||||
link: "/plugins/getting-started-rs",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
socialLinks: [
|
||||
{ icon: "github", link: "https://github.com/Snowiiii/Pumpkin" },
|
||||
{ icon: "discord", link: "https://discord.gg/RNm224ZsDq" },
|
||||
],
|
||||
|
||||
logo: "/assets/icon.png",
|
||||
},
|
||||
head: [["link", { rel: "icon", href: "/assets/favicon.ico" }]],
|
||||
});
|
||||
17
docs/.vitepress/theme/index.ts
Normal file
17
docs/.vitepress/theme/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
// https://vitepress.dev/guide/custom-theme
|
||||
import { h } from 'vue'
|
||||
import type { Theme } from 'vitepress'
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import './style.css'
|
||||
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
Layout: () => {
|
||||
return h(DefaultTheme.Layout, null, {
|
||||
// https://vitepress.dev/guide/extending-default-theme#layout-slots
|
||||
})
|
||||
},
|
||||
enhanceApp({ app, router, siteData }) {
|
||||
// ...
|
||||
}
|
||||
} satisfies Theme
|
||||
139
docs/.vitepress/theme/style.css
Normal file
139
docs/.vitepress/theme/style.css
Normal file
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* Customize default theme styling by overriding CSS variables:
|
||||
* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
|
||||
*/
|
||||
|
||||
/**
|
||||
* Colors
|
||||
*
|
||||
* Each colors have exact same color scale system with 3 levels of solid
|
||||
* colors with different brightness, and 1 soft color.
|
||||
*
|
||||
* - `XXX-1`: The most solid color used mainly for colored text. It must
|
||||
* satisfy the contrast ratio against when used on top of `XXX-soft`.
|
||||
*
|
||||
* - `XXX-2`: The color used mainly for hover state of the button.
|
||||
*
|
||||
* - `XXX-3`: The color for solid background, such as bg color of the button.
|
||||
* It must satisfy the contrast ratio with pure white (#ffffff) text on
|
||||
* top of it.
|
||||
*
|
||||
* - `XXX-soft`: The color used for subtle background such as custom container
|
||||
* or badges. It must satisfy the contrast ratio when putting `XXX-1` colors
|
||||
* on top of it.
|
||||
*
|
||||
* The soft color must be semi transparent alpha channel. This is crucial
|
||||
* because it allows adding multiple "soft" colors on top of each other
|
||||
* to create a accent, such as when having inline code block inside
|
||||
* custom containers.
|
||||
*
|
||||
* - `default`: The color used purely for subtle indication without any
|
||||
* special meanings attched to it such as bg color for menu hover state.
|
||||
*
|
||||
* - `brand`: Used for primary brand colors, such as link text, button with
|
||||
* brand theme, etc.
|
||||
*
|
||||
* - `tip`: Used to indicate useful information. The default theme uses the
|
||||
* brand color for this by default.
|
||||
*
|
||||
* - `warning`: Used to indicate warning to the users. Used in custom
|
||||
* container, badges, etc.
|
||||
*
|
||||
* - `danger`: Used to show error, or dangerous message to the users. Used
|
||||
* in custom container, badges, etc.
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-c-default-1: var(--vp-c-gray-1);
|
||||
--vp-c-default-2: var(--vp-c-gray-2);
|
||||
--vp-c-default-3: var(--vp-c-gray-3);
|
||||
--vp-c-default-soft: var(--vp-c-gray-soft);
|
||||
|
||||
--vp-c-brand-1: var(--vp-c-indigo-1);
|
||||
--vp-c-brand-2: var(--vp-c-indigo-2);
|
||||
--vp-c-brand-3: var(--vp-c-indigo-3);
|
||||
--vp-c-brand-soft: var(--vp-c-indigo-soft);
|
||||
|
||||
--vp-c-tip-1: var(--vp-c-brand-1);
|
||||
--vp-c-tip-2: var(--vp-c-brand-2);
|
||||
--vp-c-tip-3: var(--vp-c-brand-3);
|
||||
--vp-c-tip-soft: var(--vp-c-brand-soft);
|
||||
|
||||
--vp-c-warning-1: var(--vp-c-yellow-1);
|
||||
--vp-c-warning-2: var(--vp-c-yellow-2);
|
||||
--vp-c-warning-3: var(--vp-c-yellow-3);
|
||||
--vp-c-warning-soft: var(--vp-c-yellow-soft);
|
||||
|
||||
--vp-c-danger-1: var(--vp-c-red-1);
|
||||
--vp-c-danger-2: var(--vp-c-red-2);
|
||||
--vp-c-danger-3: var(--vp-c-red-3);
|
||||
--vp-c-danger-soft: var(--vp-c-red-soft);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Button
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-button-brand-border: transparent;
|
||||
--vp-button-brand-text: var(--vp-c-white);
|
||||
--vp-button-brand-bg: var(--vp-c-brand-3);
|
||||
--vp-button-brand-hover-border: transparent;
|
||||
--vp-button-brand-hover-text: var(--vp-c-white);
|
||||
--vp-button-brand-hover-bg: var(--vp-c-brand-2);
|
||||
--vp-button-brand-active-border: transparent;
|
||||
--vp-button-brand-active-text: var(--vp-c-white);
|
||||
--vp-button-brand-active-bg: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Home
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-home-hero-name-color: transparent;
|
||||
--vp-home-hero-name-background: -webkit-linear-gradient(
|
||||
120deg,
|
||||
#bd34fe 30%,
|
||||
#41d1ff
|
||||
);
|
||||
|
||||
--vp-home-hero-image-background-image: linear-gradient(
|
||||
-45deg,
|
||||
#bd34fe 50%,
|
||||
#47caff 50%
|
||||
);
|
||||
--vp-home-hero-image-filter: blur(44px);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
:root {
|
||||
--vp-home-hero-image-filter: blur(56px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
:root {
|
||||
--vp-home-hero-image-filter: blur(68px);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Custom Block
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-custom-block-tip-border: transparent;
|
||||
--vp-custom-block-tip-text: var(--vp-c-text-1);
|
||||
--vp-custom-block-tip-bg: var(--vp-c-brand-soft);
|
||||
--vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Algolia
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
.DocSearch {
|
||||
--docsearch-primary-color: var(--vp-c-brand-1) !important;
|
||||
}
|
||||
|
||||
22
docs/about/introduction.md
Normal file
22
docs/about/introduction.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Pumpkin
|
||||
|
||||
Pumpkin is a Minecraft server built entirely in **Rust**, offering a fast, efficient,
|
||||
and customizable experience. It prioritizes performance and player enjoyment while adhering to the core mechanics of the game.
|
||||
|
||||

|
||||
|
||||
## What Pumpkin wants to achieve
|
||||
|
||||
- **Performance**: Leveraging multi-threading for maximum speed and efficiency.
|
||||
- **Compatibility**: Supports the latest Minecraft server version and adheres to vanilla game mechanics.
|
||||
- **Security**: Prioritizes security by preventing known exploits.
|
||||
- **Flexibility**: Highly configurable with the ability to disable unnecessary features.
|
||||
- **Extensibility**: Provides a foundation for plugin development.
|
||||
|
||||
## What Pumpkin will not
|
||||
|
||||
- Provide compatibility with Vanilla or Bukkit servers (including configs and plugins).
|
||||
- Function as a framework for building a server from scratch.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Pumpkin is currently under heavy development. Check out our [Github Project](https://github.com/users/Snowiiii/projects/12/views/3) to see current progress
|
||||
41
docs/about/quick-start.md
Normal file
41
docs/about/quick-start.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Quick Start
|
||||
|
||||
There are currently no release builds, because there was no release :D.
|
||||
|
||||
To get Pumpkin running you first have to clone it:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/Snowiiii/Pumpkin.git
|
||||
cd Pumpkin
|
||||
```
|
||||
|
||||
You also may have to [install rust](https://www.rust-lang.org/tools/install) when you don't already have.
|
||||
|
||||
You can place a vanilla world into the Pumpkin/ directory when you want. Just name the World to `world`
|
||||
|
||||
Then run:
|
||||
|
||||
> [!NOTE]
|
||||
> This can take a while. Because we enabled heavy optimizations for release builds
|
||||
>
|
||||
> To apply further optimizations specfic to your CPU and use your CPU features. You should set the target-cpu=native
|
||||
> Rust flag.
|
||||
|
||||
```shell
|
||||
cargo run --release
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
Experimental Docker support is available.
|
||||
The image is currently not published anywhere, but you can use the following command to build it:
|
||||
|
||||
```shell
|
||||
docker build . -t pumpkin
|
||||
```
|
||||
|
||||
To run it use the following command:
|
||||
|
||||
```shell
|
||||
docker run --rm -v "./world:/pumpkin/world" pumpkin
|
||||
```
|
||||
BIN
docs/assets/favicon.ico
Normal file
BIN
docs/assets/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
docs/assets/icon.png
Normal file
BIN
docs/assets/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 836 KiB |
27
docs/index.md
Normal file
27
docs/index.md
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
# https://vitepress.dev/reference/default-theme-home-page
|
||||
layout: home
|
||||
|
||||
hero:
|
||||
name: 'Pumpkin'
|
||||
text: 'Minecraft Server'
|
||||
tagline: Empowering everyone to host fast and efficient Minecraft servers
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Quick Start
|
||||
link: /about/quick-start
|
||||
- theme: alt
|
||||
text: Documentation
|
||||
link: /about/introduction
|
||||
- theme: alt
|
||||
text: For developers
|
||||
link: /plugins/about
|
||||
|
||||
features:
|
||||
- title: Written in Rust
|
||||
details: Pumpkin is written 100% in Rust, ensuring memory safety and unmatched performance.
|
||||
- title: Feature complete
|
||||
details: With all vanilla features supported, you will have no issues.
|
||||
- title: Extensible
|
||||
details: Using Extism you can extend Pumpkin to your needs. Play your way!
|
||||
---
|
||||
15
docs/plugins/about.md
Normal file
15
docs/plugins/about.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Plugins
|
||||
|
||||
Pumpkin uses [Extism](https://extism.org/) for loading plugins.
|
||||
This means that you can write your plugins in any language that can compile to Extism WASM.
|
||||
These languages include:
|
||||
|
||||
- Rust
|
||||
- JavaScript / TypeScript
|
||||
- Golang
|
||||
- C#
|
||||
- F#
|
||||
- C
|
||||
- Haskell
|
||||
- Zig
|
||||
- AssemblyScript
|
||||
4
docs/plugins/getting-started-rs.md
Normal file
4
docs/plugins/getting-started-rs.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Getting Started in Rust
|
||||
|
||||
Rust in one of the supported plugin languages.
|
||||
This page has not been written yet.
|
||||
1062
package-lock.json
generated
Normal file
1062
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
11
package.json
Normal file
11
package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"scripts": {
|
||||
"docs:dev": "vitepress dev docs",
|
||||
"docs:build": "vitepress build docs",
|
||||
"docs:preview": "vitepress preview docs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vitepress": "^1.3.4",
|
||||
"vue": "^3.4.38"
|
||||
}
|
||||
}
|
||||
@@ -98,6 +98,12 @@ impl<T> From<(T, T, T)> for Vector3<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Vector3<T>> for (T, T, T) {
|
||||
fn from(vector: Vector3<T>) -> Self {
|
||||
(vector.x, vector.y, vector.z)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Math:
|
||||
Mul<Output = Self>
|
||||
+ Neg<Output = Self>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::{
|
||||
io::{self, Write},
|
||||
net::SocketAddr,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -71,7 +70,7 @@ pub struct Client {
|
||||
pub connection_state: ConnectionState,
|
||||
pub encryption: bool,
|
||||
pub closed: bool,
|
||||
pub token: Arc<Token>,
|
||||
pub token: Token,
|
||||
pub connection: TcpStream,
|
||||
pub address: SocketAddr,
|
||||
enc: PacketEncoder,
|
||||
@@ -82,7 +81,7 @@ pub struct Client {
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(token: Arc<Token>, connection: TcpStream, address: SocketAddr) -> Self {
|
||||
pub fn new(token: Token, connection: TcpStream, address: SocketAddr) -> Self {
|
||||
Self {
|
||||
protocol_version: 0,
|
||||
gameprofile: None,
|
||||
|
||||
@@ -76,9 +76,7 @@ impl Player {
|
||||
return;
|
||||
}
|
||||
let entity = &mut self.entity;
|
||||
self.lastx = entity.pos.x;
|
||||
self.lasty = entity.pos.y;
|
||||
self.lastz = entity.pos.z;
|
||||
self.last_position = entity.pos;
|
||||
entity.set_pos(
|
||||
Self::clamp_horizontal(position.x),
|
||||
Self::clamp_vertical(position.feet_y),
|
||||
@@ -89,13 +87,12 @@ impl Player {
|
||||
// send new position to all other players
|
||||
let on_ground = self.on_ground;
|
||||
let entity_id = entity.entity_id;
|
||||
let (x, lastx) = (entity.pos.x, self.lastx);
|
||||
let (y, lasty) = (entity.pos.y, self.lasty);
|
||||
let (z, lastz) = (entity.pos.z, self.lastz);
|
||||
let (x, y, z) = entity.pos.into();
|
||||
let (lastx, lasty, lastz) = self.last_position.into();
|
||||
let world = self.world.clone();
|
||||
let world = world.lock().await;
|
||||
world.broadcast_packet(
|
||||
&[&self.client.token],
|
||||
&[self.client.token],
|
||||
&CUpdateEntityPos::new(
|
||||
entity_id.into(),
|
||||
(x * 4096.0 - lastx * 4096.0) as i16,
|
||||
@@ -125,9 +122,7 @@ impl Player {
|
||||
}
|
||||
let entity = &mut self.entity;
|
||||
|
||||
self.lastx = entity.pos.x;
|
||||
self.lasty = entity.pos.y;
|
||||
self.lastz = entity.pos.z;
|
||||
self.last_position = entity.pos;
|
||||
entity.set_pos(
|
||||
Self::clamp_horizontal(position_rotation.x),
|
||||
Self::clamp_vertical(position_rotation.feet_y),
|
||||
@@ -139,9 +134,8 @@ impl Player {
|
||||
// send new position to all other players
|
||||
let on_ground = self.on_ground;
|
||||
let entity_id = entity.entity_id;
|
||||
let (x, lastx) = (entity.pos.x, self.lastx);
|
||||
let (y, lasty) = (entity.pos.y, self.lasty);
|
||||
let (z, lastz) = (entity.pos.z, self.lastz);
|
||||
let (x, y, z) = entity.pos.into();
|
||||
let (lastx, lasty, lastz) = self.last_position.into();
|
||||
let yaw = modulus(entity.yaw * 256.0 / 360.0, 256.0);
|
||||
let pitch = modulus(entity.pitch * 256.0 / 360.0, 256.0);
|
||||
// let head_yaw = (entity.head_yaw * 256.0 / 360.0).floor();
|
||||
@@ -149,7 +143,7 @@ impl Player {
|
||||
let world = world.lock().await;
|
||||
|
||||
world.broadcast_packet(
|
||||
&[&self.client.token],
|
||||
&[self.client.token],
|
||||
&CUpdateEntityPosRot::new(
|
||||
entity_id.into(),
|
||||
(x * 4096.0 - lastx * 4096.0) as i16,
|
||||
@@ -161,7 +155,7 @@ impl Player {
|
||||
),
|
||||
);
|
||||
world.broadcast_packet(
|
||||
&[&self.client.token],
|
||||
&[self.client.token],
|
||||
&CHeadRot::new(entity_id.into(), yaw as u8),
|
||||
);
|
||||
|
||||
@@ -186,10 +180,10 @@ impl Player {
|
||||
let world = self.world.lock().await;
|
||||
let packet = CUpdateEntityRot::new(entity_id.into(), yaw as u8, pitch as u8, on_ground);
|
||||
// self.client.send_packet(&packet);
|
||||
world.broadcast_packet(&[&self.client.token], &packet);
|
||||
world.broadcast_packet(&[self.client.token], &packet);
|
||||
let packet = CHeadRot::new(entity_id.into(), yaw as u8);
|
||||
// self.client.send_packet(&packet);
|
||||
world.broadcast_packet(&[&self.client.token], &packet);
|
||||
world.broadcast_packet(&[self.client.token], &packet);
|
||||
}
|
||||
|
||||
pub fn handle_chat_command(&mut self, server: &mut Server, command: SChatCommand) {
|
||||
@@ -248,7 +242,7 @@ impl Player {
|
||||
let id = self.entity_id();
|
||||
let world = self.world.lock().await;
|
||||
world.broadcast_packet(
|
||||
&[&self.client.token],
|
||||
&[self.client.token],
|
||||
&CEntityAnimation::new(id.into(), animation as u8),
|
||||
)
|
||||
}
|
||||
@@ -272,7 +266,7 @@ impl Player {
|
||||
|
||||
let world = self.world.lock().await;
|
||||
world.broadcast_packet(
|
||||
&[&self.client.token],
|
||||
&[self.client.token],
|
||||
&CPlayerChatMessage::new(
|
||||
pumpkin_protocol::uuid::UUID(gameprofile.id),
|
||||
1.into(),
|
||||
@@ -340,7 +334,7 @@ impl Player {
|
||||
let world = world.lock().await;
|
||||
let attacked_player = world.get_by_entityid(self, entity_id.0 as EntityId);
|
||||
if let Some(mut player) = attacked_player {
|
||||
let token = player.client.token.clone();
|
||||
let token = player.client.token;
|
||||
let velo = player.velocity;
|
||||
if config.protect_creative && player.gamemode == GameMode::Creative {
|
||||
return;
|
||||
@@ -371,7 +365,7 @@ impl Player {
|
||||
self.client.send_packet(packet);
|
||||
player.client.send_packet(packet);
|
||||
world.broadcast_packet(
|
||||
&[&self.client.token, &token],
|
||||
&[self.client.token, token],
|
||||
&CHurtAnimation::new(&entity_id, 10.0),
|
||||
)
|
||||
}
|
||||
@@ -411,12 +405,12 @@ impl Player {
|
||||
// TODO: currently this is always dirt replace it
|
||||
let world = self.world.lock().await;
|
||||
world.broadcast_packet(
|
||||
&[&self.client.token],
|
||||
&[self.client.token],
|
||||
&CWorldEvent::new(2001, &location, 11, false),
|
||||
);
|
||||
// AIR
|
||||
world.broadcast_packet(
|
||||
&[&self.client.token],
|
||||
&[self.client.token],
|
||||
&CBlockUpdate::new(&location, 0.into()),
|
||||
);
|
||||
}
|
||||
@@ -439,12 +433,12 @@ impl Player {
|
||||
// TODO: currently this is always dirt replace it
|
||||
let world = self.world.lock().await;
|
||||
world.broadcast_packet(
|
||||
&[&self.client.token],
|
||||
&[self.client.token],
|
||||
&CWorldEvent::new(2001, &location, 11, false),
|
||||
);
|
||||
// AIR
|
||||
world.broadcast_packet(
|
||||
&[&self.client.token],
|
||||
&[self.client.token],
|
||||
&CBlockUpdate::new(&location, 0.into()),
|
||||
);
|
||||
// TODO: Send this every tick
|
||||
@@ -491,11 +485,11 @@ impl Player {
|
||||
if let Ok(block_state_id) = BlockId::new(minecraft_id, None) {
|
||||
let world = self.world.lock().await;
|
||||
world.broadcast_packet(
|
||||
&[&self.client.token],
|
||||
&[self.client.token],
|
||||
&CBlockUpdate::new(&location, block_state_id.get_id_mojang_repr().into()),
|
||||
);
|
||||
world.broadcast_packet(
|
||||
&[&self.client.token],
|
||||
&[self.client.token],
|
||||
&CBlockUpdate::new(
|
||||
&WorldPosition(location.0 + face.to_offset()),
|
||||
block_state_id.get_id_mojang_repr().into(),
|
||||
|
||||
@@ -75,9 +75,7 @@ pub struct Player {
|
||||
/// send `send_abilties_update` when changed
|
||||
pub abilities: PlayerAbilities,
|
||||
|
||||
pub lastx: f64,
|
||||
pub lasty: f64,
|
||||
pub lastz: f64,
|
||||
pub last_position: Vector3<f64>,
|
||||
// Client side value, Should be not trusted
|
||||
pub on_ground: bool,
|
||||
|
||||
@@ -140,9 +138,7 @@ impl Player {
|
||||
abilities: PlayerAbilities::default(),
|
||||
gamemode,
|
||||
watched_section: Vector3::new(0, 0, 0),
|
||||
lastx: 0.0,
|
||||
lasty: 0.0,
|
||||
lastz: 0.0,
|
||||
last_position: Vector3::new(0.0, 0.0, 0.0),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +234,7 @@ impl Player {
|
||||
self.world
|
||||
.lock()
|
||||
.await
|
||||
.broadcast_packet(&[&self.client.token], &packet);
|
||||
.broadcast_packet(&[self.client.token], &packet);
|
||||
}
|
||||
|
||||
pub async fn set_pose(&mut self, pose: EntityPose) {
|
||||
@@ -252,7 +248,7 @@ impl Player {
|
||||
self.world
|
||||
.lock()
|
||||
.await
|
||||
.broadcast_packet(&[&self.client.token], &packet)
|
||||
.broadcast_packet(&[self.client.token], &packet)
|
||||
}
|
||||
|
||||
pub fn teleport(&mut self, x: f64, y: f64, z: f64, yaw: f32, pitch: f32) {
|
||||
@@ -263,9 +259,7 @@ impl Player {
|
||||
}
|
||||
let entity = &mut self.entity;
|
||||
entity.set_pos(x, y, z);
|
||||
self.lastx = x;
|
||||
self.lasty = y;
|
||||
self.lastz = z;
|
||||
self.last_position = entity.pos;
|
||||
entity.yaw = yaw;
|
||||
entity.pitch = pitch;
|
||||
self.awaiting_teleport = Some((self.teleport_id_count.into(), Vector3::new(x, y, z)));
|
||||
@@ -334,7 +328,7 @@ impl Player {
|
||||
}],
|
||||
));
|
||||
self.world.lock().await.broadcast_packet(
|
||||
&[&self.client.token],
|
||||
&[self.client.token],
|
||||
&CPlayerInfoUpdate::new(
|
||||
0x04,
|
||||
&[pumpkin_protocol::client::play::Player {
|
||||
|
||||
@@ -81,7 +81,7 @@ fn main() -> io::Result<()> {
|
||||
let rcon = ADVANCED_CONFIG.rcon.clone();
|
||||
|
||||
let mut clients: HashMap<Token, Client> = HashMap::new();
|
||||
let mut players: HashMap<Arc<Token>, Arc<Mutex<Player>>> = HashMap::new();
|
||||
let mut players: HashMap<Token, Arc<Mutex<Player>>> = HashMap::new();
|
||||
|
||||
let server = Arc::new(tokio::sync::Mutex::new(Server::new()));
|
||||
log::info!("Started Server took {}ms", time.elapsed().as_millis());
|
||||
@@ -150,32 +150,28 @@ fn main() -> io::Result<()> {
|
||||
token,
|
||||
Interest::READABLE.add(Interest::WRITABLE),
|
||||
)?;
|
||||
let rc_token = Arc::new(token);
|
||||
let client = Client::new(Arc::clone(&rc_token), connection, addr);
|
||||
let client = Client::new(token, connection, addr);
|
||||
clients.insert(token, client);
|
||||
},
|
||||
|
||||
token => {
|
||||
// Poll Players
|
||||
let done = if let Some(player) = players.get_mut(&token) {
|
||||
if let Some(player) = players.get_mut(&token) {
|
||||
let mut player = player.lock().unwrap();
|
||||
player.client.poll(event).await;
|
||||
if !player.client.closed {
|
||||
let mut server = server.lock().await;
|
||||
player.process_packets(&mut server).await;
|
||||
}
|
||||
player.client.closed
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if done {
|
||||
if let Some(player) = players.remove(&token) {
|
||||
let mut player = player.lock().unwrap();
|
||||
player.remove().await;
|
||||
poll.registry().deregister(&mut player.client.connection)?;
|
||||
if player.client.closed {
|
||||
drop(player);
|
||||
if let Some(player) = players.remove(&token) {
|
||||
let mut player = player.lock().unwrap();
|
||||
player.remove().await;
|
||||
poll.registry().deregister(&mut player.client.connection)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Poll current Clients (non players)
|
||||
// Maybe received an event for a TCP connection.
|
||||
@@ -195,10 +191,9 @@ fn main() -> io::Result<()> {
|
||||
if done {
|
||||
poll.registry().deregister(&mut client.connection)?;
|
||||
} else if make_player {
|
||||
let token = client.token.clone();
|
||||
let token = client.token;
|
||||
let mut server = server.lock().await;
|
||||
let (player, world) =
|
||||
server.add_player(token.clone(), client).await;
|
||||
let (player, world) = server.add_player(token, client).await;
|
||||
players.insert(token, player.clone());
|
||||
let mut world = world.lock().await;
|
||||
world.spawn_player(&BASIC_CONFIG, player).await;
|
||||
|
||||
@@ -112,7 +112,7 @@ impl Server {
|
||||
|
||||
pub async fn add_player(
|
||||
&mut self,
|
||||
token: Arc<Token>,
|
||||
token: Token,
|
||||
client: Client,
|
||||
) -> (Arc<Mutex<Player>>, Arc<tokio::sync::Mutex<World>>) {
|
||||
let entity_id = self.new_entity_id();
|
||||
@@ -145,12 +145,12 @@ impl Server {
|
||||
}
|
||||
|
||||
/// Sends a Packet to all Players in all worlds
|
||||
pub fn broadcast_packet_all<P>(&self, expect: &[&Arc<Token>], packet: &P)
|
||||
pub fn broadcast_packet_all<P>(&self, except: &[Token], packet: &P)
|
||||
where
|
||||
P: ClientPacket,
|
||||
{
|
||||
for world in &self.worlds {
|
||||
world.blocking_lock().broadcast_packet(expect, packet)
|
||||
world.blocking_lock().broadcast_packet(except, packet)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ use crate::{client::Client, entity::player::Player};
|
||||
|
||||
pub struct World {
|
||||
pub level: Arc<Mutex<Level>>,
|
||||
pub current_players: HashMap<Arc<Token>, Arc<Mutex<Player>>>,
|
||||
pub current_players: HashMap<Token, Arc<Mutex<Player>>>,
|
||||
// entities, players...
|
||||
}
|
||||
|
||||
@@ -39,14 +39,14 @@ impl World {
|
||||
}
|
||||
|
||||
/// Sends a Packet to all Players, Expect some players. Because we can't lock them twice
|
||||
pub fn broadcast_packet<P>(&self, expect: &[&Arc<Token>], packet: &P)
|
||||
pub fn broadcast_packet<P>(&self, except: &[Token], packet: &P)
|
||||
where
|
||||
P: ClientPacket,
|
||||
{
|
||||
for (_, player) in self
|
||||
.current_players
|
||||
.iter()
|
||||
.filter(|c| !expect.contains(&c.0))
|
||||
.filter(|c| !except.contains(c.0))
|
||||
{
|
||||
let mut player = player.lock().unwrap();
|
||||
player.client.send_packet(packet);
|
||||
@@ -118,7 +118,7 @@ impl World {
|
||||
}],
|
||||
));
|
||||
self.broadcast_packet(
|
||||
&[&player.client.token],
|
||||
&[player.client.token],
|
||||
&CPlayerInfoUpdate::new(
|
||||
0x01 | 0x08,
|
||||
&[pumpkin_protocol::client::play::Player {
|
||||
@@ -139,7 +139,7 @@ impl World {
|
||||
for (_, playerr) in self
|
||||
.current_players
|
||||
.iter()
|
||||
.filter(|c| c.0 != &player.client.token)
|
||||
.filter(|(c, _)| **c != player.client.token)
|
||||
{
|
||||
let playerr = playerr.as_ref().lock().unwrap();
|
||||
let gameprofile = &playerr.gameprofile;
|
||||
@@ -165,7 +165,7 @@ impl World {
|
||||
|
||||
// spawn player for every client
|
||||
self.broadcast_packet(
|
||||
&[&player.client.token],
|
||||
&[player.client.token],
|
||||
// TODO: add velo
|
||||
&CSpawnEntity::new(
|
||||
entity_id.into(),
|
||||
@@ -184,7 +184,7 @@ impl World {
|
||||
),
|
||||
);
|
||||
// spawn players for our client
|
||||
let token = player.client.token.clone();
|
||||
let token = player.client.token;
|
||||
for (_, existing_player) in self.current_players.iter().filter(|c| c.0 != &token) {
|
||||
let existing_player = existing_player.as_ref().lock().unwrap();
|
||||
let entity = &existing_player.entity;
|
||||
@@ -213,7 +213,7 @@ impl World {
|
||||
Metadata::new(17, VarInt(0), config.skin_parts),
|
||||
);
|
||||
player.client.send_packet(&packet);
|
||||
self.broadcast_packet(&[&player.client.token], &packet)
|
||||
self.broadcast_packet(&[player.client.token], &packet)
|
||||
}
|
||||
|
||||
// Spawn in inital chunks
|
||||
@@ -277,7 +277,7 @@ impl World {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn add_player(&mut self, token: Arc<Token>, player: Arc<Mutex<Player>>) {
|
||||
pub fn add_player(&mut self, token: Token, player: Arc<Mutex<Player>>) {
|
||||
self.current_players.insert(token, player);
|
||||
}
|
||||
|
||||
@@ -288,9 +288,9 @@ impl World {
|
||||
let id = player.entity_id();
|
||||
let uuid = player.gameprofile.id;
|
||||
self.broadcast_packet(
|
||||
&[&player.client.token],
|
||||
&[player.client.token],
|
||||
&CRemovePlayerInfo::new(1.into(), &[UUID(uuid)]),
|
||||
);
|
||||
self.broadcast_packet(&[&player.client.token], &CRemoveEntities::new(&[id.into()]))
|
||||
self.broadcast_packet(&[player.client.token], &CRemoveEntities::new(&[id.into()]))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user