Skip to content

Commit

Permalink
feat: add ~system/Players and some sendBatch events (#98)
Browse files Browse the repository at this point in the history
* feat: add `~system/Players` and some `sendBatch` events
- change AvatarEmoteCommand as growonlyset
- move Rpc module as scene_api to DCL (remove common)
- entity_id as reference when it's forward it with references
- MISSING fix: add delete_entity crdt message
- change tuple to descriptive struct for dirty crdt state
- add local api calls vec to op_state

* fix avatar data and add todos

* apply review

* fix

* fix crash
  • Loading branch information
leanmendoza authored Nov 20, 2023
1 parent 0b96b73 commit 9a9512b
Show file tree
Hide file tree
Showing 25 changed files with 925 additions and 110 deletions.
3 changes: 2 additions & 1 deletion rust/decentraland-godot-lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ struct Component {

const PROTO_FILES_BASE_DIR: &str = "src/dcl/components/proto/";
const COMPONENT_BASE_DIR: &str = "src/dcl/components/proto/decentraland/sdk/components/";
const GROW_ONLY_SET_COMPONENTS: [&str; 2] = ["PointerEventsResult", "VideoEvent"];
const GROW_ONLY_SET_COMPONENTS: [&str; 3] =
["PointerEventsResult", "VideoEvent", "AvatarEmoteCommand"];

pub fn snake_to_pascal(input: &str) -> String {
input
Expand Down
1 change: 0 additions & 1 deletion rust/decentraland-godot-lib/src/common/mod.rs

This file was deleted.

19 changes: 19 additions & 0 deletions rust/decentraland-godot-lib/src/dcl/components/proto_components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ pub mod common {
godot::prelude::Color::from_rgba(self.r, self.g, self.b, self.a)
}

pub fn to_color_string(&self) -> String {
format!(
"#{:02x}{:02x}{:02x}{:02x}",
(self.r * 255.0) as u8,
(self.g * 255.0) as u8,
(self.b * 255.0) as u8,
(self.a * 255.0) as u8
)
}

pub fn multiply(&mut self, factor: f32) -> Self {
Self {
r: self.r * factor,
Expand Down Expand Up @@ -65,6 +75,15 @@ pub mod common {
godot::prelude::Color::from_rgba(self.r, self.g, self.b, 1.0)
}

pub fn to_color_string(&self) -> String {
format!(
"#{:02x}{:02x}{:02x}",
(self.r * 255.0) as u8,
(self.g * 255.0) as u8,
(self.b * 255.0) as u8
)
}

pub fn multiply(&mut self, factor: f32) -> Self {
Self {
r: self.r * factor,
Expand Down
4 changes: 3 additions & 1 deletion rust/decentraland-godot-lib/src/dcl/crdt/entity.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::dcl::{components::SceneEntityId, DirtyEntities};
use crate::dcl::components::SceneEntityId;
use std::collections::HashSet;

use super::DirtyEntities;

#[derive(Debug)]
pub struct SceneEntityContainer {
// fixed array of 65536=2^16 elements, each index is the entity_number
Expand Down
6 changes: 3 additions & 3 deletions rust/decentraland-godot-lib/src/dcl/crdt/grow_only_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub trait GenericGrowOnlySetComponent {

pub trait GenericGrowOnlySetComponentOperation<T: 'static + FromDclReader + ToDclWriter> {
fn append(&mut self, entity: SceneEntityId, value: T);
fn get(&self, entity: SceneEntityId) -> Option<&VecDeque<T>>;
fn get(&self, entity: &SceneEntityId) -> Option<&VecDeque<T>>;
}

impl<T> GrowOnlySet<T> {
Expand Down Expand Up @@ -104,8 +104,8 @@ impl<T: 'static + FromDclReader + ToDclWriter> GenericGrowOnlySetComponentOperat
*dirty_count += 1;
}

fn get(&self, entity: SceneEntityId) -> Option<&VecDeque<T>> {
self.values.get(&entity)
fn get(&self, entity: &SceneEntityId) -> Option<&VecDeque<T>> {
self.values.get(entity)
}
}

Expand Down
11 changes: 9 additions & 2 deletions rust/decentraland-godot-lib/src/dcl/crdt/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ pub fn process_many_messages(stream: &mut DclReader, scene_crdt_state: &mut Scen
}
}

const CRDT_DELETE_ENTITY_HEADER_SIZE: usize = CRDT_HEADER_SIZE + 4;
const CRDT_PUT_COMPONENT_HEADER_SIZE: usize = CRDT_HEADER_SIZE + 20;
const CRDT_DELETE_COMPONENT_HEADER_SIZE: usize = CRDT_HEADER_SIZE + 16;

Expand Down Expand Up @@ -152,15 +153,15 @@ pub fn append_gos_component(
scene_crdt_state: &SceneCrdtState,
entity_id: &SceneEntityId,
component_id: &SceneComponentId,
elements_count: usize,
elements_count: &usize,
writer: &mut DclWriter,
) -> Result<(), String> {
let Some(component_definition) = scene_crdt_state.get_gos_component_definition(*component_id)
else {
return Err("Component not found".into());
};

for i in 0..elements_count {
for i in 0..*elements_count {
// TODO: this can be improved by using the same writer, we don't know the component_data_length in advance to write the right length
// but if we have the position written we can overwrite then
let mut component_buf = Vec::new();
Expand All @@ -182,3 +183,9 @@ pub fn append_gos_component(

Ok(())
}

pub fn delete_entity(entity_id: &SceneEntityId, writer: &mut DclWriter) {
writer.write_u32(CRDT_DELETE_ENTITY_HEADER_SIZE as u32);
writer.write(&CrdtMessageType::DeleteEntity);
writer.write(entity_id);
}
38 changes: 29 additions & 9 deletions rust/decentraland-godot-lib/src/dcl/crdt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@ pub mod grow_only_set;
pub mod last_write_wins;
pub mod message;

use std::{any::Any, collections::HashMap};
use std::{
any::Any,
collections::{HashMap, HashSet},
};

use self::{
entity::SceneEntityContainer,
grow_only_set::{GenericGrowOnlySetComponent, GrowOnlySet},
last_write_wins::{GenericLastWriteWinsComponent, LastWriteWins},
};

use super::{
components::{
proto_components, transform_and_parent::DclTransformAndParent, SceneComponentId,
SceneEntityId,
},
DirtyEntities, DirtyGosComponents, DirtyLwwComponents,
use super::components::{
proto_components, transform_and_parent::DclTransformAndParent, SceneComponentId, SceneEntityId,
};

#[derive(Debug)]
Expand All @@ -25,6 +24,23 @@ pub struct SceneCrdtState {
pub entities: SceneEntityContainer,
}

pub type DirtyLwwComponents = HashMap<SceneComponentId, HashSet<SceneEntityId>>;
pub type DirtyGosComponents = HashMap<SceneComponentId, HashMap<SceneEntityId, usize>>;

// message from scene-thread describing new and deleted entities
#[derive(Debug, Default)]
pub struct DirtyEntities {
pub born: HashSet<SceneEntityId>,
pub died: HashSet<SceneEntityId>,
}

#[derive(Debug, Default)]
pub struct DirtyCrdtState {
pub entities: DirtyEntities,
pub lww: DirtyLwwComponents,
pub gos: DirtyGosComponents,
}

impl Default for SceneCrdtState {
fn default() -> Self {
Self::new()
Expand Down Expand Up @@ -177,7 +193,7 @@ impl SceneCrdtState {
Some(component)
}

pub fn take_dirty(&mut self) -> (DirtyEntities, DirtyLwwComponents, DirtyGosComponents) {
pub fn take_dirty(&mut self) -> DirtyCrdtState {
let mut dirty_lww_components: DirtyLwwComponents = HashMap::new();
let mut dirty_gos_components: DirtyGosComponents = HashMap::new();
let keys: Vec<SceneComponentId> = self.components.keys().cloned().collect(); // another way to do this?
Expand Down Expand Up @@ -215,7 +231,11 @@ impl SceneCrdtState {
}
}

(dirty_entities, dirty_lww_components, dirty_gos_components)
DirtyCrdtState {
entities: dirty_entities,
lww: dirty_lww_components,
gos: dirty_gos_components,
}
}

pub fn get_transform_mut(&mut self) -> &mut LastWriteWins<DclTransformAndParent> {
Expand Down
67 changes: 47 additions & 20 deletions rust/decentraland-godot-lib/src/dcl/js/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,24 @@ use std::{

use deno_core::{op, Op, OpDecl, OpState};

use crate::{
common::rpc::RpcCalls,
dcl::{
crdt::{
message::{append_gos_component, process_many_messages, put_or_delete_lww_component},
SceneCrdtState,
use crate::dcl::{
crdt::{
message::{
append_gos_component, delete_entity, process_many_messages, put_or_delete_lww_component,
},
js::{SceneDying, SceneMainCrdtFileContent},
serialization::{reader::DclReader, writer::DclWriter},
RendererResponse, SceneId, SceneResponse, SharedSceneCrdtState,
SceneCrdtState,
},
js::{SceneDying, SceneMainCrdtFileContent},
scene_apis::{LocalCall, RpcCall},
serialization::{reader::DclReader, writer::DclWriter},
RendererResponse, SceneId, SceneResponse, SharedSceneCrdtState,
};

use super::{SceneElapsedTime, SceneLogs};
use super::{
events::process_events,
players::{get_player_data, get_players},
SceneElapsedTime, SceneLogs,
};

// list of op declarations
pub fn ops() -> Vec<OpDecl> {
Expand Down Expand Up @@ -60,7 +64,7 @@ fn op_crdt_send_to_renderer(op_state: Rc<RefCell<OpState>>, messages: &[u8]) {
op_state.put(mutex_scene_crdt_state);
op_state.put(scene_id);

let rpc_calls = std::mem::take(op_state.borrow_mut::<RpcCalls>());
let rpc_calls = std::mem::take(op_state.borrow_mut::<Vec<RpcCall>>());

let sender = op_state.borrow_mut::<std::sync::mpsc::SyncSender<SceneResponse>>();

Expand Down Expand Up @@ -90,36 +94,35 @@ async fn op_crdt_recv_from_renderer(op_state: Rc<RefCell<OpState>>) -> Vec<Vec<u
let mut op_state = op_state.borrow_mut();
op_state.put(receiver);

let local_api_calls = op_state.take::<Vec<LocalCall>>();
let mutex_scene_crdt_state = op_state.take::<Arc<Mutex<SceneCrdtState>>>();
let cloned_scene_crdt = mutex_scene_crdt_state.clone();
let scene_crdt_state = cloned_scene_crdt.lock().unwrap();

let data = match response {
Some(RendererResponse::Ok(data)) => {
let (_dirty_entities, dirty_lww_components, dirty_gos_components) = data;

Some(RendererResponse::Ok(dirty)) => {
let mut data_buf = Vec::new();
let mut data_writter = DclWriter::new(&mut data_buf);

for (component_id, entities) in dirty_lww_components {
for (component_id, entities) in dirty.lww.iter() {
for entity_id in entities {
if let Err(err) = put_or_delete_lww_component(
&scene_crdt_state,
&entity_id,
&component_id,
entity_id,
component_id,
&mut data_writter,
) {
tracing::info!("error writing crdt message: {err}");
}
}
}

for (component_id, entities) in dirty_gos_components {
for (component_id, entities) in dirty.gos.iter() {
for (entity_id, element_count) in entities {
if let Err(err) = append_gos_component(
&scene_crdt_state,
&entity_id,
&component_id,
entity_id,
component_id,
element_count,
&mut data_writter,
) {
Expand All @@ -128,6 +131,13 @@ async fn op_crdt_recv_from_renderer(op_state: Rc<RefCell<OpState>>) -> Vec<Vec<u
}
}

for entity_id in dirty.entities.died.iter() {
delete_entity(entity_id, &mut data_writter);
}

process_local_api_calls(local_api_calls, &scene_crdt_state);
process_events(&mut op_state, &scene_crdt_state, &dirty);

data_buf
}
_ => {
Expand All @@ -141,6 +151,7 @@ async fn op_crdt_recv_from_renderer(op_state: Rc<RefCell<OpState>>) -> Vec<Vec<u
}
};

op_state.put(Vec::<LocalCall>::new());
op_state.put(mutex_scene_crdt_state);
let mut ret = Vec::<Vec<u8>>::with_capacity(1);
if let Some(main_crdt) = op_state.try_take::<SceneMainCrdtFileContent>() {
Expand All @@ -149,3 +160,19 @@ async fn op_crdt_recv_from_renderer(op_state: Rc<RefCell<OpState>>) -> Vec<Vec<u
ret.push(data);
ret
}

fn process_local_api_calls(local_api_calls: Vec<LocalCall>, crdt_state: &SceneCrdtState) {
for local_call in local_api_calls {
match local_call {
LocalCall::PlayersGetPlayerData { user_id, response } => {
response.send(get_player_data(user_id, crdt_state));
}
LocalCall::PlayersGetPlayersInScene { response } => {
response.send(get_players(crdt_state, true));
}
LocalCall::PlayersGetConnectedPlayers { response } => {
response.send(get_players(crdt_state, false));
}
}
}
}
Loading

0 comments on commit 9a9512b

Please sign in to comment.