sync assets and microservice updates

This commit is contained in:
Zeeshaun 2026-01-27 20:41:28 -06:00
parent e54dd191f1
commit d8138fbe69
4 changed files with 167 additions and 168 deletions

View File

@ -19,4 +19,3 @@
- Flashlight: F - Flashlight: F
- Phone: Tab - Phone: Tab
- Pause menu: Esc - Pause menu: Esc

View File

@ -1,27 +1,27 @@
# CharacterApi document shapes # CharacterApi document shapes
This service expects JSON request bodies for character creation and stores This service expects JSON request bodies for character creation and stores
character documents in MongoDB. character documents in MongoDB.
Inbound JSON documents Inbound JSON documents
- CreateCharacterRequest (`POST /api/characters`) - CreateCharacterRequest (`POST /api/characters`)
```json ```json
{ {
"name": "string" "name": "string"
} }
``` ```
Stored documents (MongoDB) Stored documents (MongoDB)
- Character - Character
```json ```json
{ {
"id": "string (ObjectId)", "id": "string (ObjectId)",
"ownerUserId": "string", "ownerUserId": "string",
"name": "string", "name": "string",
"coord": { "coord": {
"x": "number", "x": "number",
"y": "number" "y": "number"
}, },
"createdUtc": "string (ISO-8601 datetime)" "createdUtc": "string (ISO-8601 datetime)"
} }
``` ```

View File

@ -1,8 +1,8 @@
namespace CharacterApi.Models; namespace CharacterApi.Models;
public class Coord public class Coord
{ {
public int X { get; set; } public int X { get; set; }
public int Y { get; set; } public int Y { get; set; }
} }

View File

@ -1,132 +1,132 @@
using LocationsApi.Models; using LocationsApi.Models;
using MongoDB.Bson; using MongoDB.Bson;
using MongoDB.Driver; using MongoDB.Driver;
namespace LocationsApi.Services; namespace LocationsApi.Services;
public class LocationStore public class LocationStore
{ {
private readonly IMongoCollection<Location> _col; private readonly IMongoCollection<Location> _col;
public LocationStore(IConfiguration cfg) public LocationStore(IConfiguration cfg)
{ {
var cs = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017"; var cs = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017";
var dbName = cfg["MongoDB:DatabaseName"] ?? "GameDb"; var dbName = cfg["MongoDB:DatabaseName"] ?? "GameDb";
var client = new MongoClient(cs); var client = new MongoClient(cs);
var db = client.GetDatabase(dbName); var db = client.GetDatabase(dbName);
var collectionName = "Locations"; var collectionName = "Locations";
EnsureLocationSchema(db, collectionName); EnsureLocationSchema(db, collectionName);
_col = db.GetCollection<Location>(collectionName); _col = db.GetCollection<Location>(collectionName);
var coordIndex = Builders<Location>.IndexKeys var coordIndex = Builders<Location>.IndexKeys
.Ascending(l => l.Coord.X) .Ascending(l => l.Coord.X)
.Ascending(l => l.Coord.Y); .Ascending(l => l.Coord.Y);
var coordIndexOptions = new CreateIndexOptions { Unique = true }; var coordIndexOptions = new CreateIndexOptions { Unique = true };
_col.Indexes.CreateOne(new CreateIndexModel<Location>(coordIndex, coordIndexOptions)); _col.Indexes.CreateOne(new CreateIndexModel<Location>(coordIndex, coordIndexOptions));
EnsureOriginLocation(); EnsureOriginLocation();
} }
private static void EnsureLocationSchema(IMongoDatabase db, string collectionName) private static void EnsureLocationSchema(IMongoDatabase db, string collectionName)
{ {
var validator = new BsonDocument var validator = new BsonDocument
{ {
{ {
"$jsonSchema", new BsonDocument "$jsonSchema", new BsonDocument
{ {
{ "bsonType", "object" }, { "bsonType", "object" },
{ "required", new BsonArray { "name", "coord", "createdUtc" } }, { "required", new BsonArray { "name", "coord", "createdUtc" } },
{ {
"properties", new BsonDocument "properties", new BsonDocument
{ {
{ "name", new BsonDocument { { "bsonType", "string" } } }, { "name", new BsonDocument { { "bsonType", "string" } } },
{ {
"coord", new BsonDocument "coord", new BsonDocument
{ {
{ "bsonType", "object" }, { "bsonType", "object" },
{ "required", new BsonArray { "x", "y" } }, { "required", new BsonArray { "x", "y" } },
{ {
"properties", new BsonDocument "properties", new BsonDocument
{ {
{ "x", new BsonDocument { { "bsonType", "int" } } }, { "x", new BsonDocument { { "bsonType", "int" } } },
{ "y", new BsonDocument { { "bsonType", "int" } } } { "y", new BsonDocument { { "bsonType", "int" } } }
} }
} }
} }
}, },
{ "createdUtc", new BsonDocument { { "bsonType", "date" } } } { "createdUtc", new BsonDocument { { "bsonType", "date" } } }
} }
} }
} }
} }
}; };
var collections = db.ListCollectionNames().ToList(); var collections = db.ListCollectionNames().ToList();
if (!collections.Contains(collectionName)) if (!collections.Contains(collectionName))
{ {
var createCommand = new BsonDocument var createCommand = new BsonDocument
{ {
{ "create", collectionName }, { "create", collectionName },
{ "validator", validator }, { "validator", validator },
{ "validationAction", "error" } { "validationAction", "error" }
}; };
db.RunCommand<BsonDocument>(createCommand); db.RunCommand<BsonDocument>(createCommand);
return; return;
} }
var command = new BsonDocument var command = new BsonDocument
{ {
{ "collMod", collectionName }, { "collMod", collectionName },
{ "validator", validator }, { "validator", validator },
{ "validationAction", "error" } { "validationAction", "error" }
}; };
db.RunCommand<BsonDocument>(command); db.RunCommand<BsonDocument>(command);
} }
public Task CreateAsync(Location location) => _col.InsertOneAsync(location); public Task CreateAsync(Location location) => _col.InsertOneAsync(location);
public Task<List<Location>> GetAllAsync() => public Task<List<Location>> GetAllAsync() =>
_col.Find(Builders<Location>.Filter.Empty).ToListAsync(); _col.Find(Builders<Location>.Filter.Empty).ToListAsync();
public async Task<bool> DeleteAsync(string id) public async Task<bool> DeleteAsync(string id)
{ {
var filter = Builders<Location>.Filter.Eq(l => l.Id, id); var filter = Builders<Location>.Filter.Eq(l => l.Id, id);
var result = await _col.DeleteOneAsync(filter); var result = await _col.DeleteOneAsync(filter);
return result.DeletedCount > 0; return result.DeletedCount > 0;
} }
public async Task<bool> UpdateNameAsync(string id, string name) public async Task<bool> UpdateNameAsync(string id, string name)
{ {
var filter = Builders<Location>.Filter.Eq(l => l.Id, id); var filter = Builders<Location>.Filter.Eq(l => l.Id, id);
var update = Builders<Location>.Update.Set(l => l.Name, name); var update = Builders<Location>.Update.Set(l => l.Name, name);
var result = await _col.UpdateOneAsync(filter, update); var result = await _col.UpdateOneAsync(filter, update);
return result.ModifiedCount > 0; return result.ModifiedCount > 0;
} }
private void EnsureOriginLocation() private void EnsureOriginLocation()
{ {
var filter = Builders<Location>.Filter.And( var filter = Builders<Location>.Filter.And(
Builders<Location>.Filter.Eq(l => l.Coord.X, 0), Builders<Location>.Filter.Eq(l => l.Coord.X, 0),
Builders<Location>.Filter.Eq(l => l.Coord.Y, 0) Builders<Location>.Filter.Eq(l => l.Coord.Y, 0)
); );
var existing = _col.Find(filter).FirstOrDefault(); var existing = _col.Find(filter).FirstOrDefault();
if (existing is not null) if (existing is not null)
return; return;
var origin = new Location var origin = new Location
{ {
Name = "Origin", Name = "Origin",
Coord = new Coord { X = 0, Y = 0 }, Coord = new Coord { X = 0, Y = 0 },
CreatedUtc = DateTime.UtcNow CreatedUtc = DateTime.UtcNow
}; };
try try
{ {
_col.InsertOne(origin); _col.InsertOne(origin);
} }
catch (MongoWriteException ex) when (ex.WriteError.Category == ServerErrorCategory.DuplicateKey) catch (MongoWriteException ex) when (ex.WriteError.Category == ServerErrorCategory.DuplicateKey)
{ {
// Another instance seeded it first. // Another instance seeded it first.
} }
} }
} }