From 06cd7624d197c16ed62d1024bcd8dfedc9af2708 Mon Sep 17 00:00:00 2001 From: jackdotink Date: Mon, 18 Dec 2023 15:35:23 -0600 Subject: [PATCH] add strict and optional instances --- docs/config/types.md | 40 +++++++++++++++++++++------------- zap/src/irgen/gen.rs | 11 ++++++---- zap/src/output/mod.rs | 8 ++++++- zap/src/parser/grammar.lalrpop | 9 ++++++-- zap/src/parser/mod.rs | 5 +++-- 5 files changed, 49 insertions(+), 24 deletions(-) diff --git a/docs/config/types.md b/docs/config/types.md index f14d4986..707ee8fe 100644 --- a/docs/config/types.md +++ b/docs/config/types.md @@ -4,7 +4,7 @@ outline: deep # Types -Zap supports a large number of complex types +Zap supports a large number of complex types ## Numbers @@ -12,23 +12,24 @@ There are there types of numbers in Zap, unsigned (`u`), signed (`i`), and float ### Unsigned Numbers -| Type | Min Value | Max Value | -|--------|-----------|---------------------------------------------------------------------------| -| `u8` | 0 | 255 | -| `u16` | 0 | 65,535 | -| `u32` | 0 | 4,294,967,295 | -| `u64` | 0 | ~ 1.84 × 1019 | +| Type | Min Value | Max Value | +| ----- | --------- | ------------------------------------------------------------------------ | +| `u8` | 0 | 255 | +| `u16` | 0 | 65,535 | +| `u32` | 0 | 4,294,967,295 | +| `u64` | 0 | ~ 1.84 × 1019 | ### Signed Numbers -| Type | Min Value | Max Value | -|--------|---------------------------------------------------------------------------|---------------------------------------------------------------------------| -| `i8` | -128 | 127 | -| `i16` | -32,768 | 32,767 | -| `i32` | -2,147,483,648 | 2,147,483,647 | -| `i64` | ~ -9.22 × 1018 | ~ 9.22 × 1018 | +| Type | Min Value | Max Value | +| ----- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------- | +| `i8` | -128 | 127 | +| `i16` | -32,768 | 32,767 | +| `i32` | -2,147,483,648 | 2,147,483,647 | +| `i64` | ~ -9.22 × 1018 | ~ 9.22 × 1018 | ### Float Numbers + Floats are floating point numbers. They are only in the 32 and 64 bit varients. Generally, `f32` is precise enough for most usecases, but where further precision is necessary an `f64` can be used. @@ -70,13 +71,14 @@ Arrays can also be constrained with to a specific length, such as for pathfindin - ## Structs -Structs are a collection of defined fields, with each field having its own type, such as: + +Structs are a collection of defined fields, with each field having its own type, such as: ## Maps + Maps are objects where it is indexed by a type, such as: @@ -87,8 +89,15 @@ Enums are values seperated by a comma (`,`) inside brackets (`()`). For example: ## Instances + Roblox Instances can be passed through Zap. +::: warning +If a non-optional instance results in `nil` when received, it will cause a deserialize error and the packet will be dropped. Instances are turned into `nil` when they don't exist on the reciever - for example: an instance from the server that isn't streamed into a client or an instance that only exists on the client. + +If you want to send an instance that may not exist, you must make it optional. +::: + ### Constraining the Subclass @@ -100,6 +109,7 @@ You can also specify which subclass (that must extend instance) that you would l Classes that inherit your specified class will be accepted, for example `Part`. ## Other Roblox Classes + The following Roblox Classes are also available as types in Zap: - `Vector3` diff --git a/zap/src/irgen/gen.rs b/zap/src/irgen/gen.rs index 4fa1d593..cf202300 100644 --- a/zap/src/irgen/gen.rs +++ b/zap/src/irgen/gen.rs @@ -377,7 +377,7 @@ pub fn gen_ser(ty: &Ty, from: Var, gen_checks: bool) -> Vec { } } - Ty::Instance(class) => { + Ty::Instance(strict, class) => { if gen_checks && class.is_some() { assert( &mut stmts, @@ -529,7 +529,7 @@ pub fn gen_des(ty: &Ty, to: Var, gen_checks: bool) -> Vec { } } - Ty::Instance(class) => { + Ty::Instance(strict, class) => { assign( &mut stmts, to.clone(), @@ -537,8 +537,11 @@ pub fn gen_des(ty: &Ty, to: Var, gen_checks: bool) -> Vec { ); // Assert that the instance is not nil even if we don't want checks - // because roblox cannot ensure the instance's existance at the destination - assert(&mut stmts, Expr::from(to.clone()).neq(Expr::Nil), None); + // because roblox cannot ensure the instance's existance at the destination. + // Only do this for strict instances, optional instances can be nil. + if *strict { + assert(&mut stmts, Expr::from(to.clone()).neq(Expr::Nil), None); + } if gen_checks && class.is_some() { assert( diff --git a/zap/src/output/mod.rs b/zap/src/output/mod.rs index 52d12bb0..0b00df97 100644 --- a/zap/src/output/mod.rs +++ b/zap/src/output/mod.rs @@ -129,7 +129,13 @@ pub trait Output { .to_string(), ), - Ty::Instance(name) => self.push(if let Some(name) = name { name } else { "Instance" }), + Ty::Instance(strict, name) => { + self.push(if let Some(name) = name { name } else { "Instance" }); + + if *strict { + self.push("?") + } + } Ty::Vector3 => self.push("Vector3"), Ty::Ref(name) => self.push(&name.to_string()), diff --git a/zap/src/parser/grammar.lalrpop b/zap/src/parser/grammar.lalrpop index 220d367c..a0a945bc 100644 --- a/zap/src/parser/grammar.lalrpop +++ b/zap/src/parser/grammar.lalrpop @@ -135,7 +135,8 @@ Ty: Ty = { "{" ":" )>> "}" => Ty::Struct { fields }, "(" )>> ")" => Ty::Enum { variants }, - "Instance" ")")?> => Ty::Instance(class), + "Instance" ")")?> => Ty::Instance(false, class), + "Vector3" => Ty::Vector3, => { @@ -143,7 +144,11 @@ Ty: Ty = { Ty::Ref(name) }, - "?" => Ty::Optional(Box::new(ty)), + "?" => match ty { + Ty::Instance(_, class) => Ty::Instance(true, class), + + _ => Ty::Optional(Box::new(ty)), + }, } Range: Range = { diff --git a/zap/src/parser/mod.rs b/zap/src/parser/mod.rs index e81ed0c6..5f0b6b64 100644 --- a/zap/src/parser/mod.rs +++ b/zap/src/parser/mod.rs @@ -90,7 +90,7 @@ pub enum Ty { Struct { fields: Vec<(String, Ty)> }, Enum { variants: Vec }, - Instance(Option), + Instance(bool, Option), Vector3, Ref(String), @@ -142,7 +142,8 @@ impl Ty { Ty::Enum { variants } => Some(NumTy::from_f64(0.0, variants.len() as f64).size()), - Ty::Instance(_) => Some(2), + Ty::Instance(_, _) => Some(2), + Ty::Vector3 => Some(12), // At some point this should evaluate the size of the referenced type