Last active
March 4, 2024 03:32
-
-
Save dylanh724/68067b4e843ea6e99fbd297fe1a87c49 to your computer and use it in GitHub Desktop.
SpacetimeDB | Docs | Unity Pt1 | Rust Parity: lib.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// using SpacetimeDB; // Useful if I wanted to exclude `SpacetimeDB` attribute prefixes | |
using SpacetimeDB.Module; | |
using static SpacetimeDB.Runtime; | |
/// Code From the Unity Pt1 Basic Tutorial: https://spacetimedb.com/docs/unity/part-1 | |
static partial class Module | |
{ | |
[SpacetimeDB.Reducer(ReducerKind.Update)] | |
public static void OnConnect(DbEventArgs dbEventArgs) | |
{ | |
Log("User connected"); | |
} | |
/// We're using this table as a singleton, | |
/// so there should typically only be one element where the version is 0. | |
[SpacetimeDB.Table] | |
public partial class Config | |
{ | |
[SpacetimeDB.Column(ColumnAttrs.PrimaryKey)] | |
public int Version; | |
public string? MessageOfTheDay; | |
} | |
/// This allows us to store 3D points in tables. | |
[SpacetimeDB.Type] | |
public partial class StdbVector3 | |
{ | |
public float X; | |
public float Y; | |
public float Z; | |
} | |
/// This stores information related to all entities in our game. In this tutorial | |
/// all entities must at least have an entity_id, a position, a direction and they | |
/// must specify whether or not they are moving. | |
[SpacetimeDB.Table] | |
public partial class EntityComponent | |
{ | |
[SpacetimeDB.Column(ColumnAttrs.PrimaryKeyAuto)] | |
public ulong EntityId; | |
public StdbVector3? Position; | |
public float Direction; | |
public bool Moving; | |
} | |
/// All players have this component and it associates an entity with the user's | |
/// Identity. It also stores their username and whether or not they're logged in. | |
[SpacetimeDB.Table] | |
public partial class PlayerComponent | |
{ | |
// An EntityId that matches an EntityId in the `EntityComponent` table. | |
[SpacetimeDB.Column(ColumnAttrs.PrimaryKey)] | |
public ulong EntityId; | |
// The user's identity, which is unique to each player | |
[SpacetimeDB.Column(ColumnAttrs.Unique)] | |
public Identity Identity; | |
public string? Username; | |
public bool LoggedIn; | |
} | |
/// This reducer is called when the user logs in for the first time and | |
/// enters a username. | |
[SpacetimeDB.Reducer] | |
public static void CreatePlayer(DbEventArgs dbEvent, string username) | |
{ | |
// Get the Identity of the client who called this reducer | |
Identity sender = dbEvent.Sender; | |
// Make sure we don't already have a player with this identity | |
PlayerComponent? player = PlayerComponent.FindByIdentity(sender); | |
if (player is not null) | |
{ | |
throw new ArgumentException("Player already exists"); | |
} | |
// Create a new entity for this player | |
try | |
{ | |
new EntityComponent | |
{ | |
EntityId = 0, // TODO: is 0 redundantly the same as leaving null due to `PrimaryKeyAuto`? | |
Position = new StdbVector3 { X = 0, Y = 0, Z = 0 }, | |
Direction = 0, | |
Moving = false, | |
}.Insert(); | |
} | |
catch | |
{ | |
Log("Error: Failed to create a unique PlayerComponent", LogLevel.Error); | |
throw; | |
} | |
// The PlayerComponent uses the same entity_id and stores the identity of | |
// the owner, username, and whether or not they are logged in. | |
try | |
{ | |
new PlayerComponent | |
{ | |
// EntityId = 0, // 0 is the same as leaving null to get a new, unique Id | |
Identity = dbEvent.Sender, | |
Username = username, | |
LoggedIn = true, | |
}.Insert(); | |
} | |
catch | |
{ | |
Log("Error: Failed to insert PlayerComponent", LogLevel.Error); | |
throw; | |
} | |
Log($"Player created: {username}"); | |
} | |
/// Called when the module is initially published | |
[SpacetimeDB.Reducer(ReducerKind.Init)] | |
public static void OnInit() | |
{ | |
try | |
{ | |
new Config | |
{ | |
Version = 0, | |
MessageOfTheDay = "Hello, World!", | |
}.Insert(); | |
} | |
catch | |
{ | |
Log("Error: Failed to insert Config", LogLevel.Error); | |
throw; | |
} | |
} | |
/// Called when the client connects, we update the LoggedIn state to true | |
[SpacetimeDB.Reducer(ReducerKind.Init)] | |
public static void ClientConnected(DbEventArgs dbEvent) => | |
UpdatePlayerLoginState(dbEvent, loggedIn:true); | |
/// Called when the client disconnects, we update the logged_in state to false | |
[SpacetimeDB.Reducer(ReducerKind.Disconnect)] | |
public static void ClientDisonnected(DbEventArgs dbEvent) => | |
UpdatePlayerLoginState(dbEvent, loggedIn:false); | |
/// This helper function gets the PlayerComponent, sets the LoggedIn | |
/// variable and updates the PlayerComponent table row. | |
private static void UpdatePlayerLoginState(DbEventArgs dbEvent, bool loggedIn) | |
{ | |
PlayerComponent? player = PlayerComponent.FindByIdentity(dbEvent.Sender); | |
if (player is null) | |
{ | |
throw new ArgumentException("Player not found"); | |
} | |
player.LoggedIn = loggedIn; | |
PlayerComponent.UpdateByIdentity(dbEvent.Sender, player); | |
} | |
/// Updates the position of a player. This is also called when the player stops moving. | |
[SpacetimeDB.Reducer] | |
private static void UpdatePlayerPosition( | |
DbEventArgs dbEvent, | |
StdbVector3 position, | |
float direction, | |
bool moving) | |
{ | |
// First, look up the player using the sender identity | |
PlayerComponent? player = PlayerComponent.FindByIdentity(dbEvent.Sender); | |
if (player is null) | |
{ | |
throw new ArgumentException("Player not found"); | |
} | |
// Use the Player's EntityId to retrieve and update the EntityComponent | |
ulong playerEntityId = player.EntityId; | |
EntityComponent? entity = EntityComponent.FindByEntityId(playerEntityId); | |
if (entity is null) | |
{ | |
throw new ArgumentException($"Player Entity '{playerEntityId}' not found"); | |
} | |
entity.Position = position; | |
entity.Direction = direction; | |
entity.Moving = moving; | |
EntityComponent.UpdateByEntityId(playerEntityId, entity); | |
} | |
[SpacetimeDB.Table] | |
public partial class ChatMessage | |
{ | |
// The primary key for this table will be auto-incremented | |
[SpacetimeDB.Column(ColumnAttrs.PrimaryKeyAuto)] | |
// The entity id of the player that sent the message | |
public ulong SenderId; | |
// Message contents | |
public string? Text; | |
} | |
/// Adds a chat entry to the ChatMessage table | |
[SpacetimeDB.Reducer] | |
public static void SendChatMessage(DbEventArgs dbEvent, string text) | |
{ | |
// Get the player's entity id | |
PlayerComponent? player = PlayerComponent.FindByIdentity(dbEvent.Sender); | |
if (player is null) | |
{ | |
throw new ArgumentException("Player not found"); | |
} | |
// Insert the chat message | |
new ChatMessage | |
{ | |
SenderId = player.EntityId, | |
Text = text, | |
}.Insert(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment