mirror of
https://github.com/italicsjenga/valence.git
synced 2025-01-11 15:21:31 +11:00
Spawn player entities in the conway example
This commit is contained in:
parent
a6bb67ecfe
commit
fb09ab7f8c
|
@ -1,3 +1,4 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
@ -6,12 +7,12 @@ use std::sync::Mutex;
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use num::Integer;
|
use num::Integer;
|
||||||
use rayon::iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator};
|
use rayon::iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator};
|
||||||
use valence::client::{Event, GameMode};
|
use valence::client::{ClientId, Event, GameMode};
|
||||||
use valence::config::{Config, ServerListPing};
|
use valence::config::{Config, ServerListPing};
|
||||||
use valence::text::Color;
|
use valence::text::Color;
|
||||||
use valence::{
|
use valence::{
|
||||||
async_trait, ident, Biome, BlockState, Dimension, DimensionId, Server, SharedServer,
|
async_trait, ident, Biome, BlockState, Dimension, DimensionId, EntityId, EntityType, Server,
|
||||||
ShutdownResult, TextFormat,
|
SharedServer, ShutdownResult, TextFormat,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main() -> ShutdownResult {
|
pub fn main() -> ShutdownResult {
|
||||||
|
@ -23,6 +24,7 @@ pub fn main() -> ShutdownResult {
|
||||||
valence::start_server(Game {
|
valence::start_server(Game {
|
||||||
player_count: AtomicUsize::new(0),
|
player_count: AtomicUsize::new(0),
|
||||||
state: Mutex::new(State {
|
state: Mutex::new(State {
|
||||||
|
player_entities: HashMap::new(),
|
||||||
board: vec![false; SIZE_X * SIZE_Z].into_boxed_slice(),
|
board: vec![false; SIZE_X * SIZE_Z].into_boxed_slice(),
|
||||||
board_buf: vec![false; SIZE_X * SIZE_Z].into_boxed_slice(),
|
board_buf: vec![false; SIZE_X * SIZE_Z].into_boxed_slice(),
|
||||||
}),
|
}),
|
||||||
|
@ -35,6 +37,7 @@ struct Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
|
player_entities: HashMap<ClientId, EntityId>,
|
||||||
board: Box<[bool]>,
|
board: Box<[bool]>,
|
||||||
board_buf: Box<[bool]>,
|
board_buf: Box<[bool]>,
|
||||||
}
|
}
|
||||||
|
@ -105,8 +108,20 @@ impl Config for Game {
|
||||||
SIZE_Z as f64 / 2.0,
|
SIZE_Z as f64 / 2.0,
|
||||||
];
|
];
|
||||||
|
|
||||||
server.clients.retain(|_, client| {
|
let State {
|
||||||
|
player_entities,
|
||||||
|
board,
|
||||||
|
board_buf,
|
||||||
|
} = &mut *self.state.lock().unwrap();
|
||||||
|
|
||||||
|
server.clients.retain(|client_id, client| {
|
||||||
if client.created_tick() == server.shared.current_tick() {
|
if client.created_tick() == server.shared.current_tick() {
|
||||||
|
if client.is_disconnected() {
|
||||||
|
self.player_count.fetch_sub(1, Ordering::SeqCst);
|
||||||
|
player_entities.remove(&client_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if self
|
if self
|
||||||
.player_count
|
.player_count
|
||||||
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |count| {
|
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |count| {
|
||||||
|
@ -131,21 +146,27 @@ impl Config for Game {
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
player_entities.insert(
|
||||||
|
client_id,
|
||||||
|
server
|
||||||
|
.entities
|
||||||
|
.create_with_uuid(client.uuid(), EntityType::Player)
|
||||||
|
.unwrap()
|
||||||
|
.0,
|
||||||
|
);
|
||||||
|
|
||||||
client.send_message("Welcome to Conway's game of life in Minecraft!".italic());
|
client.send_message("Welcome to Conway's game of life in Minecraft!".italic());
|
||||||
client.send_message("Hold the left mouse button to bring blocks to life.".italic());
|
client.send_message("Hold the left mouse button to bring blocks to life.".italic());
|
||||||
}
|
}
|
||||||
|
|
||||||
if client.is_disconnected() {
|
|
||||||
self.player_count.fetch_sub(1, Ordering::SeqCst);
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
true
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let State { board, board_buf } = &mut *self.state.lock().unwrap();
|
for (client_id, client) in server.clients.iter_mut() {
|
||||||
|
let player = server
|
||||||
for (_, client) in server.clients.iter_mut() {
|
.entities
|
||||||
|
.get_mut(player_entities[&client_id])
|
||||||
|
.unwrap();
|
||||||
while let Some(event) = client.pop_event() {
|
while let Some(event) = client.pop_event() {
|
||||||
match event {
|
match event {
|
||||||
Event::Digging(e) => {
|
Event::Digging(e) => {
|
||||||
|
@ -158,10 +179,17 @@ impl Config for Game {
|
||||||
board[pos.x as usize + pos.z as usize * SIZE_X] = true;
|
board[pos.x as usize + pos.z as usize * SIZE_X] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::Movement { position, .. } => {
|
Event::Movement { .. } => {
|
||||||
if position.y <= 0.0 {
|
if client.position().y <= 0.0 {
|
||||||
client.teleport(spawn_pos, client.yaw(), client.pitch());
|
client.teleport(spawn_pos, client.yaw(), client.pitch());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
player.set_world(client.world());
|
||||||
|
player.set_position(client.position());
|
||||||
|
player.set_yaw(client.yaw());
|
||||||
|
player.set_head_yaw(client.yaw());
|
||||||
|
player.set_pitch(client.pitch());
|
||||||
|
player.set_on_ground(client.on_ground());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,9 +70,8 @@ impl Config for Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.cows.lock().unwrap().extend((0..200).map(|_| {
|
self.cows.lock().unwrap().extend((0..200).map(|_| {
|
||||||
let (id, e) = server.entities.create();
|
let (id, e) = server.entities.create(EntityType::Cow);
|
||||||
e.set_world(world_id);
|
e.set_world(world_id);
|
||||||
e.set_type(EntityType::Cow);
|
|
||||||
id
|
id
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -565,7 +565,7 @@ impl Client {
|
||||||
C2sPlayPacket::SetJigsawBlock(_) => {}
|
C2sPlayPacket::SetJigsawBlock(_) => {}
|
||||||
C2sPlayPacket::SetStructureBlock(_) => {}
|
C2sPlayPacket::SetStructureBlock(_) => {}
|
||||||
C2sPlayPacket::SignUpdate(_) => {}
|
C2sPlayPacket::SignUpdate(_) => {}
|
||||||
C2sPlayPacket::Swing(_) => {}
|
C2sPlayPacket::Swing(p) => self.events.push_back(Event::ArmSwing(p.hand)),
|
||||||
C2sPlayPacket::TeleportToEntity(_) => {}
|
C2sPlayPacket::TeleportToEntity(_) => {}
|
||||||
C2sPlayPacket::UseItemOn(_) => {}
|
C2sPlayPacket::UseItemOn(_) => {}
|
||||||
C2sPlayPacket::UseItem(_) => {}
|
C2sPlayPacket::UseItem(_) => {}
|
||||||
|
|
|
@ -24,6 +24,7 @@ pub enum Event {
|
||||||
pitch: f32,
|
pitch: f32,
|
||||||
on_ground: bool,
|
on_ground: bool,
|
||||||
},
|
},
|
||||||
|
ArmSwing(Hand),
|
||||||
InteractWithEntity {
|
InteractWithEntity {
|
||||||
/// The ID of the entity being interacted with.
|
/// The ID of the entity being interacted with.
|
||||||
id: EntityId,
|
id: EntityId,
|
||||||
|
|
|
@ -37,11 +37,8 @@ impl Entities {
|
||||||
|
|
||||||
/// Spawns a new entity with the default data. The new entity's [`EntityId`]
|
/// Spawns a new entity with the default data. The new entity's [`EntityId`]
|
||||||
/// is returned.
|
/// is returned.
|
||||||
///
|
pub fn create(&mut self, typ: EntityType) -> (EntityId, &mut Entity) {
|
||||||
/// To actually see the new entity, set its position to somewhere nearby and
|
self.create_with_uuid(Uuid::from_bytes(rand::random()), typ)
|
||||||
/// [set its type](EntityData::set_type) to something visible.
|
|
||||||
pub fn create(&mut self) -> (EntityId, &mut Entity) {
|
|
||||||
self.create_with_uuid(Uuid::from_bytes(rand::random()))
|
|
||||||
.expect("UUID collision")
|
.expect("UUID collision")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,13 +47,17 @@ impl Entities {
|
||||||
///
|
///
|
||||||
/// The provided UUID must not conflict with an existing entity UUID in this
|
/// The provided UUID must not conflict with an existing entity UUID in this
|
||||||
/// world. If it does, `None` is returned and the entity is not spawned.
|
/// world. If it does, `None` is returned and the entity is not spawned.
|
||||||
pub fn create_with_uuid(&mut self, uuid: Uuid) -> Option<(EntityId, &mut Entity)> {
|
pub fn create_with_uuid(
|
||||||
|
&mut self,
|
||||||
|
uuid: Uuid,
|
||||||
|
typ: EntityType,
|
||||||
|
) -> Option<(EntityId, &mut Entity)> {
|
||||||
match self.uuid_to_entity.entry(uuid) {
|
match self.uuid_to_entity.entry(uuid) {
|
||||||
Entry::Occupied(_) => None,
|
Entry::Occupied(_) => None,
|
||||||
Entry::Vacant(ve) => {
|
Entry::Vacant(ve) => {
|
||||||
let (k, e) = self.sm.insert(Entity {
|
let (k, e) = self.sm.insert(Entity {
|
||||||
flags: EntityFlags(0),
|
flags: EntityFlags(0),
|
||||||
meta: EntityMeta::new(EntityType::Marker),
|
meta: EntityMeta::new(typ),
|
||||||
world: None,
|
world: None,
|
||||||
new_position: Vec3::default(),
|
new_position: Vec3::default(),
|
||||||
old_position: Vec3::default(),
|
old_position: Vec3::default(),
|
||||||
|
@ -222,15 +223,6 @@ impl Entity {
|
||||||
self.meta.typ()
|
self.meta.typ()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Changes the [`EntityType`] of this entity to the provided type.
|
|
||||||
///
|
|
||||||
/// All metadata of this entity is reset to the default values.
|
|
||||||
pub fn set_type(&mut self, typ: EntityType) {
|
|
||||||
self.meta = EntityMeta::new(typ);
|
|
||||||
// All metadata is lost so we must mark it as modified unconditionally.
|
|
||||||
self.flags.set_type_modified(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn world(&self) -> Option<WorldId> {
|
pub fn world(&self) -> Option<WorldId> {
|
||||||
self.world
|
self.world
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue