Skip to content

Commit

Permalink
add strict and optional instances
Browse files Browse the repository at this point in the history
  • Loading branch information
jackdotink committed Dec 18, 2023
1 parent 22492a4 commit 06cd762
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 24 deletions.
40 changes: 25 additions & 15 deletions docs/config/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,32 @@ outline: deep

# Types

Zap supports a large number of complex types
Zap supports a large number of complex types

## Numbers

There are there types of numbers in Zap, unsigned (`u`), signed (`i`), and floats (`f`). Each number has a limit, in relation to the amount of bytes (space) the number utilises.

### Unsigned Numbers

| Type | Min Value | Max Value |
|--------|-----------|---------------------------------------------------------------------------|
| `u8` | 0 | 255 |
| `u16` | 0 | 65,535 |
| `u32` | 0 | 4,294,967,295 |
| `u64` | 0 | <abbr title="18,446,744,073,709,551,615">~ 1.84 × 10<sup>19</sup></abbr> |
| Type | Min Value | Max Value |
| ----- | --------- | ------------------------------------------------------------------------ |
| `u8` | 0 | 255 |
| `u16` | 0 | 65,535 |
| `u32` | 0 | 4,294,967,295 |
| `u64` | 0 | <abbr title="18,446,744,073,709,551,615">~ 1.84 × 10<sup>19</sup></abbr> |

### 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` | <abbr title="-9,223,372,036,854,775,808">~ -9.22 × 10<sup>18</sup></abbr> | <abbr title="9,223,372,036,854,775,807">~ 9.22 × 10<sup>18</sup></abbr> |
| Type | Min Value | Max Value |
| ----- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `i8` | -128 | 127 |
| `i16` | -32,768 | 32,767 |
| `i32` | -2,147,483,648 | 2,147,483,647 |
| `i64` | <abbr title="-9,223,372,036,854,775,808">~ -9.22 × 10<sup>18</sup></abbr> | <abbr title="9,223,372,036,854,775,807">~ 9.22 × 10<sup>18</sup></abbr> |

### 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.
Expand Down Expand Up @@ -70,13 +71,14 @@ Arrays can also be constrained with to a specific length, such as for pathfindin

<CodeBlock code="type Path = u8[10..20]" />


## 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:

<CodeBlock :code="['type Item = {', '\tName: string,', '\tPrice: u16,', '}'].join('\n')" />

## Maps

Maps are objects where it is indexed by a type, such as:

<CodeBlock code="type Items = { [string]: Item }" />
Expand All @@ -87,8 +89,15 @@ Enums are values seperated by a comma (`,`) inside brackets (`()`). For example:
<CodeBlock code="type RoundStatus = ( Playing, Intermission )" />

## 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.
:::

<CodeBlock code="type Player = Instance" />

### Constraining the Subclass
Expand All @@ -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`
Expand Down
11 changes: 7 additions & 4 deletions zap/src/irgen/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ pub fn gen_ser(ty: &Ty, from: Var, gen_checks: bool) -> Vec<Stmt> {
}
}

Ty::Instance(class) => {
Ty::Instance(strict, class) => {
if gen_checks && class.is_some() {
assert(
&mut stmts,
Expand Down Expand Up @@ -529,16 +529,19 @@ pub fn gen_des(ty: &Ty, to: Var, gen_checks: bool) -> Vec<Stmt> {
}
}

Ty::Instance(class) => {
Ty::Instance(strict, class) => {
assign(
&mut stmts,
to.clone(),
Var::from("incoming_inst").eindex(buffer_readu16()).into(),
);

// 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(
Expand Down
8 changes: 7 additions & 1 deletion zap/src/output/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()),
Expand Down
9 changes: 7 additions & 2 deletions zap/src/parser/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -135,15 +135,20 @@ Ty: Ty = {
"{" <fields:Comma<(<Word> ":" <Ty>)>> "}" => Ty::Struct { fields },
"(" <variants:Comma<(<Word>)>> ")" => Ty::Enum { variants },

"Instance" <class:("(" <Word> ")")?> => Ty::Instance(class),
"Instance" <class:("(" <Word> ")")?> => Ty::Instance(false, class),

"Vector3" => Ty::Vector3,

<name:Word> => {
ref_used.insert(name.clone());
Ty::Ref(name)
},

<ty:Ty> "?" => Ty::Optional(Box::new(ty)),
<ty:Ty> "?" => match ty {
Ty::Instance(_, class) => Ty::Instance(true, class),

_ => Ty::Optional(Box::new(ty)),
},
}

Range: Range<f64> = {
Expand Down
5 changes: 3 additions & 2 deletions zap/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pub enum Ty {
Struct { fields: Vec<(String, Ty)> },
Enum { variants: Vec<String> },

Instance(Option<String>),
Instance(bool, Option<String>),
Vector3,

Ref(String),
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 06cd762

Please sign in to comment.