Skip to content

Commit

Permalink
Merge branch 'master' into libdonet-docs
Browse files Browse the repository at this point in the history
  • Loading branch information
maxrdz committed Feb 26, 2024
2 parents aa09bff + d2649a5 commit fc637ff
Show file tree
Hide file tree
Showing 11 changed files with 273 additions and 50 deletions.
26 changes: 5 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<img src="logo/donet_banner.png" align="right" width="47%"/>
![GitHub Build Status](https://img.shields.io/github/actions/workflow/status/donet-server/donet/build.yml?logo=github&label=Build)
[![Coverage Status](https://codecov.io/gh/donet-server/donet/branch/master/graph/badge.svg)](https://codecov.io/gh/donet-server/donet)
[![Discord](https://img.shields.io/discord/1066973060357443644?color=blue&label=Discord&logo=discord&logoColor=white)](https://discord.gg/T6jGjEutfy)

# donet

_**D**istributed **O**bject **Net**work Engine_

![](https://img.shields.io/github/actions/workflow/status/donet-server/donet/build.yml?logo=github&label=Build)
[![Coverage Status](https://codecov.io/gh/donet-server/donet/branch/master/graph/badge.svg)](https://codecov.io/gh/donet-server/donet)
[![](https://img.shields.io/discord/1066973060357443644?color=blue&label=Discord&logo=discord&logoColor=white)](https://discord.gg/T6jGjEutfy)
<img src="logo/donet_banner.png" alt="Donet logo artwork by honeymatsu." align="right" width="40%"/>

Donet is a free and open source network engine designed after the Distributed Networking protocol,
as defined in the high-level networking API of the [Panda3D](https://panda3d.org) game engine,
Expand All @@ -15,24 +13,10 @@ with their in-house server technology, the OTP (*Online Theme Park*) server, whi
their massive multiplayer online games, such as Toontown Online and Pirates of the Caribbean Online,
from 2001 to 2013.

Donet is currently in its early stages, but it aims to be a drop-in replacement for [Astron](https://github.com/astron/astron).

How is the Donet project **unique** from Astron?

- Donet source is licensed under the GNU Affero General Public License, which is a **copyleft free software license** that
classifies public network use as distribution under its terms. Astron uses the Modified BSD License, which is a permissive
software license.
- The libdonet core library is made to be **fully backwards compatible** with Panda's legacy DC file parser, which includes
support for DC switch statements for more complex/dynamic fields. This is beneficial for maintaining projects with legacy code.
- Donet development comes with **unit testing** and code coverage reports. Functional testing is also in the works. Along with
the benefits of safety with Rust, we do our best to guarantee the integrity of the Donet server.
- Donet is a brand new open source project! We're in **active development** and plan to make more improvements in the future.
We welcome with open arms new contributors to share in the development of Donet.

## Getting Started
The Donet repository houses two different Rust projects:
- **donet** - The Donet daemon source, which includes all the Donet services. See [donet-server.org](https://www.donet-server.org).
- **libdonet** - The core utilities for Donet services, including Datagrams and the DC file parser. See [libdonet.rs](https://libdonet.rs).
- **libdonet** - The core utilities for Donet services, including datagram utilities and the DC file parser. See [libdonet.rs](https://libdonet.rs).

Please read the [introduction to Donet](./docs/01-Introduction.md) for an overview of the project
and how the engine works.
Expand Down
6 changes: 3 additions & 3 deletions donet/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,10 @@ fn main() -> std::io::Result<()> {
info!("libdonet: DC read of {:?}", dc_check_files);
let dc_read: DCReadResult = read_dc_files(dc_check_files.to_owned());

if let Ok(mut dc_file) = dc_read {
let h: u32 = dc_file.get_hash();
if let Ok(dc_file) = dc_read {
let h: u32 = dc_file.lock().unwrap().get_hash();
let sh: i32 = h as i32;
let ph: String = dc_file.get_pretty_hash();
let ph: String = dc_file.lock().unwrap().get_pretty_hash();
info!("No issues found. File hash is {} (signed {}, hex {})", h, sh, ph);
return Ok(());
}
Expand Down
17 changes: 14 additions & 3 deletions libdonet/src/dcatomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
use crate::dcfield::{DCField, DCFieldInterface};
use crate::dclass::DClass;
use crate::dcparameter::DCParameter;
use crate::dcparameter::{DCParameter, DCParameterInterface};
use crate::dctype::{DCTypeDefinition, DCTypeDefinitionInterface};
use crate::hashgen::DCHashGenerator;
use std::sync::{Arc, Mutex};
use std::ops::Deref;
use std::sync::{Arc, Mutex, MutexGuard};

/// Represents an atomic field of a Distributed Class.
/// This defines the interface to a DClass object, and is
Expand Down Expand Up @@ -57,9 +58,19 @@ impl DCAtomicFieldInterface for DCAtomicField {
}
}

/// Accumulates the properties of this DC element into the file hash.
fn generate_hash(&self, hashgen: &mut DCHashGenerator) {
self.base_field.generate_hash(hashgen);
// TODO!

hashgen.add_int(self.elements.len().try_into().unwrap());

for param_ptr in &self.elements {
let new_ptr: Arc<Mutex<DCParameter>> = param_ptr.clone();
let mutex_ref: &Mutex<DCParameter> = new_ptr.deref();
let param: MutexGuard<'_, DCParameter> = mutex_ref.lock().unwrap();

param.generate_hash(hashgen);
}
}

fn get_num_elements(&self) -> usize {
Expand Down
12 changes: 11 additions & 1 deletion libdonet/src/dcfield.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub struct DCField {
/// is always implemented as a remote procedure call (RPC). Unlike
/// attribute fields, atomic fields cannot be declared within structs.
///
/// DC Molecular Fields represent a collection of DC Attribute or
/// DC Molecular Fields represent a collection of one or more
/// DC Atomic Fields as one field under one identifier. The parameters
/// of a molecular field are the parameters of all the fields it
/// represents, joined together in the order in which they were declared
Expand All @@ -82,6 +82,7 @@ pub trait DCFieldInterface {
fn generate_hash(&self, hashgen: &mut DCHashGenerator);

fn get_field_id(&self) -> globals::FieldId;
fn get_field_name(&self) -> String;
fn get_dclass(&self) -> Arc<Mutex<DClass>>;

fn set_field_id(&mut self, id: globals::FieldId);
Expand Down Expand Up @@ -141,6 +142,7 @@ impl DCFieldInterface for DCField {
}
}

/// Accumulates the properties of this DC element into the file hash.
fn generate_hash(&self, hashgen: &mut DCHashGenerator) {
self.keyword_list.generate_hash(hashgen);
self.field_type.generate_hash(hashgen);
Expand All @@ -164,16 +166,23 @@ impl DCFieldInterface for DCField {
self.field_id
}

#[inline(always)]
fn get_field_name(&self) -> String {
self.field_name.clone()
}

fn get_dclass(&self) -> Arc<Mutex<DClass>> {
assert!(self.parent_is_dclass);
// clone option to unwrap w/o move, and clone Arc to return
self.dclass.clone().unwrap().clone()
}

#[inline(always)]
fn set_field_id(&mut self, id: globals::FieldId) {
self.field_id = id
}

#[inline(always)]
fn set_field_name(&mut self, name: String) {
self.field_name = name
}
Expand All @@ -190,6 +199,7 @@ impl DCFieldInterface for DCField {
self.default_value_stale = false;
}

#[inline(always)]
fn set_bogus_field(&mut self, is_bogus: bool) {
self.bogus_field = is_bogus
}
Expand Down
18 changes: 18 additions & 0 deletions libdonet/src/dcfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub struct DCFile {
pub trait DCFileInterface {
fn get_hash(&mut self) -> globals::DCFileHash;
fn generate_hash(&mut self, hashgen: &mut DCHashGenerator);
fn semantic_analysis(&self) -> Result<(), ()>;
fn get_pretty_hash(&mut self) -> String;
fn add_field(&mut self, field: DCField); // assigns unique ID for the whole DC file

Expand Down Expand Up @@ -133,6 +134,23 @@ impl DCFileInterface for DCFile {
}
}

/// Performs a semantic analysis on the object and its children
/// DC elements. In Panda, this is done on the go as you build the
/// DC file tree. Due to how we build it in memory, (and the fact
/// that we link all the objects together until we reduce to the
/// root production in the CFG) we have to perform this analysis
/// until the very end when all the elements are in the DCF struct.
fn semantic_analysis(&self) -> Result<(), ()> {
// Run semantic analysis chain of all distributed class objects.
// This should include semantic analysis for DC fields as well.
for dclass in &self.dclasses {
let locked_dclass: MutexGuard<'_, DClass> = dclass.lock().unwrap();
locked_dclass.semantic_analysis()?;
}
// TODO!
Ok(())
}

/// Returns a string with the hash as a pretty format hexadecimal.
fn get_pretty_hash(&mut self) -> String {
format!("0x{:0width$x}", self.get_hash(), width = 8) // 2 hex / byte = 8 hex
Expand Down
57 changes: 54 additions & 3 deletions libdonet/src/dclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
use crate::dcatomic::{DCAtomicField, DCAtomicFieldInterface};
use crate::dcfield::{ClassField, DCFieldInterface};
use crate::dcfile::DCFile;
use crate::dcmolecular::DCMolecularFieldInterface;
use crate::globals;
use crate::hashgen::DCHashGenerator;
use multimap::MultiMap;
Expand All @@ -29,8 +31,14 @@ use std::sync::{Arc, Mutex, MutexGuard};
pub type FieldName2Field = MultiMap<String, Arc<Mutex<ClassField>>>;
pub type FieldId2Field = MultiMap<globals::FieldId, Arc<Mutex<ClassField>>>;

/// Represents a Distributed Class defined in the DC file.
/// Contains a map of DC Fields, as well as atomic and
/// molecular fields that are declared within the class.
/// Also stores other properties such as its hierarchy.
#[derive(Debug)]
pub struct DClass {
dcfile: Arc<Mutex<DCFile>>, // read comment below. should reference REAL dcf by parse end.
dcf_assigned: bool, // due to how the parser works, we assign it 'til the end.
class_name: String,
class_id: globals::DClassId,
is_struct: bool,
Expand All @@ -46,8 +54,11 @@ pub struct DClass {
pub trait DClassInterface {
fn new(name: &str) -> Self;
fn generate_hash(&mut self, hashgen: &mut DCHashGenerator);
fn semantic_analysis(&self) -> Result<(), ()>;

fn set_parent(&mut self, parent: Arc<Mutex<DClass>>);
fn set_dcfile(&mut self, dcf: Arc<Mutex<DCFile>>);
fn add_parent(&mut self, parent: Arc<Mutex<DClass>>);
fn add_class_field(&mut self, field: ClassField);

fn get_name(&mut self) -> String;
fn get_dclass_id(&mut self) -> globals::DClassId;
Expand All @@ -61,6 +72,8 @@ pub trait DClassInterface {
impl DClassInterface for DClass {
fn new(name: &str) -> Self {
DClass {
dcfile: Arc::new(Mutex::new(DCFile::new())),
dcf_assigned: false,
class_name: name.to_owned(),
class_id: 0, // assigned later
is_struct: false,
Expand All @@ -74,6 +87,7 @@ impl DClassInterface for DClass {
}
}

/// Accumulates the properties of this DC element into the file hash.
fn generate_hash(&mut self, hashgen: &mut DCHashGenerator) {
hashgen.add_string(self.get_name());
hashgen.add_int(self.get_num_parents().try_into().unwrap());
Expand Down Expand Up @@ -102,40 +116,77 @@ impl DClassInterface for DClass {
match &field.deref() {
ClassField::Field(field) => field.generate_hash(hashgen),
ClassField::Atomic(atomic) => atomic.generate_hash(hashgen),
ClassField::Molecular(_) => todo!(),
ClassField::Molecular(molecular) => molecular.generate_hash(hashgen),
}
}
}

fn set_parent(&mut self, parent: Arc<Mutex<DClass>>) {
/// Performs a semantic analysis on the object and its children.
fn semantic_analysis(&self) -> Result<(), ()> {
assert!(
self.dcf_assigned,
"No DC file pointer found in '{}' dclass!",
self.class_name,
);
// TODO!
Ok(())
}

fn set_dcfile(&mut self, dcf: Arc<Mutex<DCFile>>) {
assert!(
!self.dcf_assigned,
"Tried to reassign DC file pointer to '{}' class",
self.class_name
);
self.dcfile = dcf;
self.dcf_assigned = true;
}

#[inline(always)]
fn add_parent(&mut self, parent: Arc<Mutex<DClass>>) {
self.class_parents.push(parent);
}

/// Adds a newly allocated DC field to this class. The field structure
/// in memory is moved into ownership of this class structure, and is
/// wrapped in a Mutex and an Arc pointer to pass references to other
/// elements, such as molecular fields.
fn add_class_field(&mut self, field: ClassField) {
self.fields.push(Arc::new(Mutex::new(field)));
}

#[inline(always)]
fn get_name(&mut self) -> String {
self.class_name.clone()
}

#[inline(always)]
fn get_dclass_id(&mut self) -> globals::DClassId {
self.class_id
}

#[inline(always)]
fn set_dclass_id(&mut self, id: globals::DClassId) {
self.class_id = id;
}

#[inline(always)]
fn get_num_parents(&mut self) -> usize {
self.class_parents.len()
}

#[inline(always)]
fn get_parent(&mut self, index: usize) -> Option<Arc<Mutex<DClass>>> {
// copy the reference inside the option instead of a reference to the reference
self.class_parents.get(index).cloned()
}

#[inline(always)]
fn has_constructor(&mut self) -> bool {
self.constructor.is_some()
}

#[inline(always)]
fn get_constructor(&mut self) -> Option<Arc<Mutex<DCAtomicField>>> {
self.constructor.clone()
}
Expand Down
62 changes: 61 additions & 1 deletion libdonet/src/dcmolecular.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,69 @@
//! Data model for a DC Molecular field, which represents
//! a form of a field 'alias' for a collection of fields.
use crate::dcfield::DCField;
use crate::dcatomic::{DCAtomicField, DCAtomicFieldInterface};
use crate::dcfield::{DCField, DCFieldInterface};
use crate::dclass::DClass;
use crate::dctype::{DCTypeDefinition, DCTypeDefinitionInterface};
use crate::hashgen::DCHashGenerator;
use std::ops::Deref;
use std::sync::{Arc, Mutex, MutexGuard};

/// An abstract field which provides an interface to access
/// multiple atomic fields under one field and one identifier.
#[derive(Debug)]
pub struct DCMolecularField {
base_field: DCField,
atomic_fields: Vec<Arc<Mutex<DCAtomicField>>>,
}

pub trait DCMolecularFieldInterface {
fn new(name: &str, parent: Arc<Mutex<DClass>>) -> Self;
fn generate_hash(&self, hashgen: &mut DCHashGenerator);

fn add_atomic_field(&mut self, atomic_ptr: Arc<Mutex<DCAtomicField>>);

fn get_num_atomics(&self) -> usize;
fn get_atomic_field(&self, index: usize) -> Option<Arc<Mutex<DCAtomicField>>>;
}

impl DCMolecularFieldInterface for DCMolecularField {
fn new(name: &str, parent: Arc<Mutex<DClass>>) -> Self {
Self {
base_field: {
let mut new_field = DCField::new(name, DCTypeDefinition::new());
new_field.set_parent_dclass(parent);
new_field
},
atomic_fields: vec![],
}
}

/// Accumulates the properties of this DC element into the file hash.
fn generate_hash(&self, hashgen: &mut DCHashGenerator) {
self.base_field.generate_hash(hashgen);

hashgen.add_int(self.atomic_fields.len().try_into().unwrap());

for atomic_ptr in &self.atomic_fields {
let new_ptr: Arc<Mutex<DCAtomicField>> = atomic_ptr.clone();
let mutex_ref: &Mutex<DCAtomicField> = new_ptr.deref();
let atomic_field: MutexGuard<'_, DCAtomicField> = mutex_ref.lock().unwrap();

atomic_field.generate_hash(hashgen);
}
}

fn add_atomic_field(&mut self, atomic_ptr: Arc<Mutex<DCAtomicField>>) {
self.atomic_fields.push(atomic_ptr);
}

#[inline(always)]
fn get_num_atomics(&self) -> usize {
self.atomic_fields.len()
}

fn get_atomic_field(&self, index: usize) -> Option<Arc<Mutex<DCAtomicField>>> {
self.atomic_fields.get(index).cloned()
}
}
Loading

0 comments on commit fc637ff

Please sign in to comment.