Skip to content

Commit 4921983

Browse files
bfopskazimuthgefjon
authored
C#/Unity SDK - Add some developer docs (#3140)
# Description of Changes Migrating clockworklabs/com.clockworklabs.spacetimedbsdk#349 since we are merging that repo into this one. > Add some developer docs. # API and ABI breaking changes None # Expected complexity level and risk 1 # Testing None. Docs only. --------- Co-authored-by: James Gilles <jameshgilles@gmail.com> Co-authored-by: Phoebe Goldman <phoebe@goldman-tribe.org> Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
1 parent 3faf1c5 commit 4921983

3 files changed

Lines changed: 116 additions & 115 deletions

File tree

demo/Blackholio/server-rust/src/lib.rs

Lines changed: 30 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pub mod math;
22

33
use math::DbVector2;
44
use rand::Rng;
5-
use spacetimedb::{spacetimedb_lib::ScheduleAt, Identity, ReducerContext, Table, Timestamp, TimeDuration};
5+
use spacetimedb::{spacetimedb_lib::ScheduleAt, Identity, ReducerContext, Table, TimeDuration, Timestamp};
66
use std::{collections::HashMap, time::Duration};
77

88
// TODO:
@@ -134,23 +134,18 @@ pub fn init(ctx: &ReducerContext) -> Result<(), String> {
134134
scheduled_id: 0,
135135
scheduled_at: ScheduleAt::Interval(Duration::from_millis(500).into()),
136136
})?;
137-
ctx.db
138-
.move_all_players_timer()
139-
.try_insert(MoveAllPlayersTimer {
140-
scheduled_id: 0,
141-
scheduled_at: ScheduleAt::Interval(Duration::from_millis(50).into()),
142-
})?;
137+
ctx.db.move_all_players_timer().try_insert(MoveAllPlayersTimer {
138+
scheduled_id: 0,
139+
scheduled_at: ScheduleAt::Interval(Duration::from_millis(50).into()),
140+
})?;
143141
Ok(())
144142
}
145143

146144
#[spacetimedb::reducer(client_connected)]
147145
pub fn connect(ctx: &ReducerContext) -> Result<(), String> {
148146
if let Some(player) = ctx.db.logged_out_player().identity().find(&ctx.sender) {
149147
ctx.db.player().insert(player.clone());
150-
ctx.db
151-
.logged_out_player()
152-
.identity()
153-
.delete(&player.identity);
148+
ctx.db.logged_out_player().identity().delete(&player.identity);
154149

155150
// Restore any circles for this player
156151
for circle in ctx.db.logged_out_circle().player_id().filter(&player.player_id) {
@@ -172,12 +167,7 @@ pub fn connect(ctx: &ReducerContext) -> Result<(), String> {
172167

173168
#[spacetimedb::reducer(client_disconnected)]
174169
pub fn disconnect(ctx: &ReducerContext) -> Result<(), String> {
175-
let player = ctx
176-
.db
177-
.player()
178-
.identity()
179-
.find(&ctx.sender)
180-
.ok_or("Player not found")?;
170+
let player = ctx.db.player().identity().find(&ctx.sender).ok_or("Player not found")?;
181171
let player_id = player.player_id;
182172
ctx.db.logged_out_player().insert(player);
183173
ctx.db.player().identity().delete(&ctx.sender);
@@ -208,23 +198,11 @@ pub fn enter_game(ctx: &ReducerContext, name: String) -> Result<(), String> {
208198

209199
fn spawn_player_initial_circle(ctx: &ReducerContext, player_id: u32) -> Result<Entity, String> {
210200
let mut rng = ctx.rng();
211-
let world_size = ctx
212-
.db
213-
.config()
214-
.id()
215-
.find(&0)
216-
.ok_or("Config not found")?
217-
.world_size;
201+
let world_size = ctx.db.config().id().find(&0).ok_or("Config not found")?.world_size;
218202
let player_start_radius = mass_to_radius(START_PLAYER_MASS);
219203
let x = rng.gen_range(player_start_radius..(world_size as f32 - player_start_radius));
220204
let y = rng.gen_range(player_start_radius..(world_size as f32 - player_start_radius));
221-
spawn_circle_at(
222-
ctx,
223-
player_id,
224-
START_PLAYER_MASS,
225-
DbVector2 { x, y },
226-
ctx.timestamp,
227-
)
205+
spawn_circle_at(ctx, player_id, START_PLAYER_MASS, DbVector2 { x, y }, ctx.timestamp)
228206
}
229207

230208
fn spawn_circle_at(
@@ -282,12 +260,7 @@ pub fn suicide(ctx: &ReducerContext) -> Result<(), String> {
282260

283261
#[spacetimedb::reducer]
284262
pub fn update_player_input(ctx: &ReducerContext, direction: DbVector2) -> Result<(), String> {
285-
let player = ctx
286-
.db
287-
.player()
288-
.identity()
289-
.find(&ctx.sender)
290-
.ok_or("Player not found")?;
263+
let player = ctx.db.player().identity().find(&ctx.sender).ok_or("Player not found")?;
291264
for mut circle in ctx.db.circle().player_id().filter(&player.player_id) {
292265
circle.direction = direction.normalized();
293266
circle.speed = direction.magnitude().clamp(0.0, 1.0);
@@ -324,13 +297,7 @@ fn mass_to_max_move_speed(mass: u32) -> f32 {
324297
pub fn move_all_players(ctx: &ReducerContext, _timer: MoveAllPlayersTimer) -> Result<(), String> {
325298
// TODO identity check
326299
// let span = spacetimedb::log_stopwatch::LogStopwatch::new("tick");
327-
let world_size = ctx
328-
.db
329-
.config()
330-
.id()
331-
.find(0)
332-
.ok_or("Config not found")?
333-
.world_size;
300+
let world_size = ctx.db.config().id().find(0).ok_or("Config not found")?.world_size;
334301

335302
let mut circle_directions: HashMap<u32, DbVector2> = ctx
336303
.db
@@ -341,12 +308,7 @@ pub fn move_all_players(ctx: &ReducerContext, _timer: MoveAllPlayersTimer) -> Re
341308

342309
// Split circle movement
343310
for player in ctx.db.player().iter() {
344-
let circles: Vec<Circle> = ctx
345-
.db
346-
.circle()
347-
.player_id()
348-
.filter(&player.player_id)
349-
.collect();
311+
let circles: Vec<Circle> = ctx.db.circle().player_id().filter(&player.player_id).collect();
350312
let mut player_entities: Vec<Entity> = circles
351313
.iter()
352314
.map(|c| ctx.db.entity().entity_id().find(&c.entity_id).unwrap())
@@ -381,12 +343,8 @@ pub fn move_all_players(ctx: &ReducerContext, _timer: MoveAllPlayersTimer) -> Re
381343
}
382344
let radius_sum = mass_to_radius(entity_i.mass) + mass_to_radius(entity_j.mass);
383345
if distance_sqr > radius_sum * radius_sum {
384-
let gravity_multiplier =
385-
1.0 - time_before_recombining / SPLIT_GRAV_PULL_BEFORE_RECOMBINE_SEC;
386-
let vec = diff.normalized()
387-
* (radius_sum - distance_sqr.sqrt())
388-
* gravity_multiplier
389-
* 0.05
346+
let gravity_multiplier = 1.0 - time_before_recombining / SPLIT_GRAV_PULL_BEFORE_RECOMBINE_SEC;
347+
let vec = diff.normalized() * (radius_sum - distance_sqr.sqrt()) * gravity_multiplier * 0.05
390348
/ count as f32;
391349
*circle_directions.get_mut(&entity_i.entity_id).unwrap() += vec / 2.0;
392350
*circle_directions.get_mut(&entity_j.entity_id).unwrap() -= vec / 2.0;
@@ -409,9 +367,7 @@ pub fn move_all_players(ctx: &ReducerContext, _timer: MoveAllPlayersTimer) -> Re
409367
let radius_sum = mass_to_radius(entity_i.mass) + mass_to_radius(entity_j.mass);
410368
let radius_sum_multiplied = radius_sum * ALLOWED_SPLIT_CIRCLE_OVERLAP_PCT;
411369
if distance_sqr < radius_sum_multiplied * radius_sum_multiplied {
412-
let vec = diff.normalized()
413-
* (radius_sum - distance_sqr.sqrt())
414-
* SELF_COLLISION_SPEED;
370+
let vec = diff.normalized() * (radius_sum - distance_sqr.sqrt()) * SELF_COLLISION_SPEED;
415371
*circle_directions.get_mut(&entity_i.entity_id).unwrap() += vec / 2.0;
416372
*circle_directions.get_mut(&entity_j.entity_id).unwrap() -= vec / 2.0;
417373
}
@@ -429,8 +385,7 @@ pub fn move_all_players(ctx: &ReducerContext, _timer: MoveAllPlayersTimer) -> Re
429385
let mut circle_entity = circle_entity.unwrap();
430386
let circle_radius = mass_to_radius(circle_entity.mass);
431387
let direction = *circle_directions.get(&circle.entity_id).unwrap();
432-
let new_pos =
433-
circle_entity.position + direction * mass_to_max_move_speed(circle_entity.mass);
388+
let new_pos = circle_entity.position + direction * mass_to_max_move_speed(circle_entity.mass);
434389
let min = circle_radius;
435390
let max = world_size as f32 - circle_radius;
436391
circle_entity.position.x = new_pos.x.clamp(min, max);
@@ -454,11 +409,7 @@ pub fn move_all_players(ctx: &ReducerContext, _timer: MoveAllPlayersTimer) -> Re
454409
if other_circle.player_id != circle.player_id {
455410
let mass_ratio = other_entity.mass as f32 / circle_entity.mass as f32;
456411
if mass_ratio < MINIMUM_SAFE_MASS_RATIO {
457-
schedule_consume_entity(
458-
ctx,
459-
circle_entity.entity_id,
460-
other_entity.entity_id,
461-
);
412+
schedule_consume_entity(ctx, circle_entity.entity_id, other_entity.entity_id);
462413
}
463414
}
464415
} else {
@@ -484,16 +435,8 @@ fn schedule_consume_entity(ctx: &ReducerContext, consumer_id: u32, consumed_id:
484435

485436
#[spacetimedb::reducer]
486437
pub fn consume_entity(ctx: &ReducerContext, request: ConsumeEntityTimer) -> Result<(), String> {
487-
let consumed_entity = ctx
488-
.db
489-
.entity()
490-
.entity_id()
491-
.find(&request.consumed_entity_id);
492-
let consumer_entity = ctx
493-
.db
494-
.entity()
495-
.entity_id()
496-
.find(&request.consumer_entity_id);
438+
let consumed_entity = ctx.db.entity().entity_id().find(&request.consumed_entity_id);
439+
let consumer_entity = ctx.db.entity().entity_id().find(&request.consumer_entity_id);
497440
if consumed_entity.is_none() {
498441
return Err("Consumed entity doesn't exist".into());
499442
}
@@ -526,12 +469,7 @@ pub fn player_split(ctx: &ReducerContext) -> Result<(), String> {
526469
.identity()
527470
.find(&ctx.sender)
528471
.ok_or("Sender has no player")?;
529-
let circles: Vec<Circle> = ctx
530-
.db
531-
.circle()
532-
.player_id()
533-
.filter(&player.player_id)
534-
.collect();
472+
let circles: Vec<Circle> = ctx.db.circle().player_id().filter(&player.player_id).collect();
535473
let mut circle_count = circles.len() as u32;
536474
if circle_count >= MAX_CIRCLES_PER_PLAYER {
537475
return Ok(());
@@ -564,15 +502,13 @@ pub fn player_split(ctx: &ReducerContext) -> Result<(), String> {
564502
}
565503
}
566504

567-
ctx.db
568-
.circle_recombine_timer()
569-
.insert(CircleRecombineTimer {
570-
scheduled_id: 0,
571-
scheduled_at: ScheduleAt::Time(
572-
ctx.timestamp + TimeDuration::from(Duration::from_secs_f32(SPLIT_RECOMBINE_DELAY_SEC))
573-
),
574-
player_id: player.player_id,
575-
});
505+
ctx.db.circle_recombine_timer().insert(CircleRecombineTimer {
506+
scheduled_id: 0,
507+
scheduled_at: ScheduleAt::Time(
508+
ctx.timestamp + TimeDuration::from(Duration::from_secs_f32(SPLIT_RECOMBINE_DELAY_SEC)),
509+
),
510+
player_id: player.player_id,
511+
});
576512

577513
log::warn!("Player split!");
578514

@@ -586,13 +522,7 @@ pub fn spawn_food(ctx: &ReducerContext, _timer: SpawnFoodTimer) -> Result<(), St
586522
return Ok(());
587523
}
588524

589-
let world_size = ctx
590-
.db
591-
.config()
592-
.id()
593-
.find(0)
594-
.ok_or("Config not found")?
595-
.world_size;
525+
let world_size = ctx.db.config().id().find(0).ok_or("Config not found")?.world_size;
596526

597527
let mut rng = ctx.rng();
598528
let mut food_count = ctx.db.food().count();
@@ -643,21 +573,10 @@ pub fn calculate_center_of_mass(entities: &[Entity]) -> DbVector2 {
643573

644574
#[spacetimedb::reducer]
645575
pub fn circle_recombine(ctx: &ReducerContext, timer: CircleRecombineTimer) -> Result<(), String> {
646-
let circles: Vec<Circle> = ctx
647-
.db
648-
.circle()
649-
.player_id()
650-
.filter(&timer.player_id)
651-
.collect();
576+
let circles: Vec<Circle> = ctx.db.circle().player_id().filter(&timer.player_id).collect();
652577
let recombining_entities: Vec<Entity> = circles
653578
.iter()
654-
.filter(|c| {
655-
ctx.timestamp
656-
.duration_since(c.last_split_time)
657-
.unwrap()
658-
.as_secs_f32()
659-
>= SPLIT_RECOMBINE_DELAY_SEC
660-
})
579+
.filter(|c| ctx.timestamp.duration_since(c.last_split_time).unwrap().as_secs_f32() >= SPLIT_RECOMBINE_DELAY_SEC)
661580
.map(|c| ctx.db.entity().entity_id().find(&c.entity_id).unwrap())
662581
.collect();
663582
if recombining_entities.len() <= 1 {

0 commit comments

Comments
 (0)