Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 27 additions & 36 deletions OpenDreamRuntime/DreamMapManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public void InitializeAtoms(List<DreamMapJson>? maps) {
for (var z = 1; z <= Levels; ++z) {
for (var y = Size.Y; y >= 1; --y) {
for (var x = Size.X; x >= 1; --x) {
_levels[z - 1].Cells[x - 1, y - 1].Turf?.SpawnProc("New");
_levels[z - 1].Cells[x - 1, y - 1].Turf.SpawnProc("New");
}
}
}
Expand All @@ -154,30 +154,18 @@ public void InitializeAtoms(List<DreamMapJson>? maps) {
}
}

private DreamObject SetTurf(Vector2i pos, int z, DreamObjectDefinition type, DreamProcArguments creationArguments, DreamObjectArea? area = null) {
private void SetTurf(Vector2i pos, int z, DreamObjectDefinition type, DreamProcArguments creationArguments) {
if (IsInvalidCoordinate(pos, z))
throw new ArgumentException("Invalid coordinates");

Cell cell = _levels[z - 1].Cells[pos.X - 1, pos.Y - 1];
var cell = _levels[z - 1].Cells[pos.X - 1, pos.Y - 1];

if(area is not null) {
cell.Area.Contents.RemoveValue(new(cell.Turf));
area.Contents.AddValue(new(cell.Turf));
}

if (cell.Turf != null) {
cell.Turf.SetTurfType(type);
} else {
cell.Turf = new DreamObjectTurf(type, pos.X, pos.Y, z, cell);
// Only add the /turf to .contents when it's created.
cell.Area.Contents.AddValue(new(cell.Turf));
}
cell.Turf.SetTurfType(type);

IconAppearance turfAppearance = _atomManager.GetAppearanceFromDefinition(cell.Turf.ObjectDefinition);
SetTurfAppearance(cell.Turf, turfAppearance);

cell.Turf.InitSpawn(creationArguments);
return cell.Turf;
}

public void SetTurf(DreamObjectTurf turf, DreamObjectDefinition type, DreamProcArguments creationArguments) {
Expand Down Expand Up @@ -215,7 +203,7 @@ public void SetAreaAppearance(DreamObjectArea area, IconAppearance appearance) {
_turfAreaLookup.Clear();
int oldAppearance = area.AppearanceId;
area.AppearanceId = _appearanceSystem.AddAppearance(appearance);
foreach (var turf in area.Contents.GetTurfs()) {
foreach (var turf in area.Turfs) {
var turfAppearance = _atomManager.MustGetAppearance(turf);

if(turfAppearance is null) continue;
Expand All @@ -238,7 +226,7 @@ public bool TryGetCellAt(Vector2i pos, int z, [NotNullWhen(true)] out Cell? cell
public bool TryGetTurfAt(Vector2i pos, int z, [NotNullWhen(true)] out DreamObjectTurf? turf) {
if (TryGetCellAt(pos, z, out var cell)) {
turf = cell.Turf;
return (turf != null);
return true;
}

turf = null;
Expand All @@ -264,8 +252,6 @@ public void SetWorldSize(Vector2i size) {
var newX = Math.Max(oldSize.X, size.X);
var newY = Math.Max(oldSize.Y, size.Y);

DreamObjectArea defaultArea = GetOrCreateArea(_defaultArea);

Size = (newX, newY);

if(Size.X > oldSize.X || Size.Y > oldSize.Y) {
Expand All @@ -280,7 +266,10 @@ public void SetWorldSize(Vector2i size) {
continue;
}

existingLevel.Cells[x - 1, y - 1] = new Cell(defaultArea);
var defaultTurf = new DreamObjectTurf(_defaultTurf.ObjectDefinition, x, y, existingLevel.Z);
var cell = new Cell(DefaultArea, defaultTurf);
defaultTurf.Cell = cell;
existingLevel.Cells[x - 1, y - 1] = cell;
SetTurf(new Vector2i(x, y), existingLevel.Z, _defaultTurf.ObjectDefinition, new());
}
}
Expand All @@ -298,7 +287,7 @@ public void SetWorldSize(Vector2i size) {
for (var y = 1; y <= oldSize.Y; y++) {
if (x > size.X || y > size.Y) {
var deleteCell = oldCells[x - 1, y - 1];
deleteCell.Turf?.Delete();
deleteCell.Turf.Delete();
_mapSystem.SetTile(existingLevel.Grid, new Vector2i(x, y), Tile.Empty);
foreach (var movableToDelete in deleteCell.Movables) {
movableToDelete.Delete();
Expand All @@ -314,14 +303,12 @@ public void SetWorldSize(Vector2i size) {

public void SetZLevels(int levels) {
if (levels > Levels) {
DreamObjectArea defaultArea = GetOrCreateArea(_defaultArea);

for (int z = Levels + 1; z <= levels; z++) {
MapId mapId = new(z);
_mapSystem.CreateMap(mapId);

var grid = _mapManager.CreateGridEntity(mapId);
Level level = new Level(z, grid, defaultArea, Size);
Level level = new Level(z, grid, _defaultTurf.ObjectDefinition, DefaultArea, Size);
_levels.Add(level);

for (int x = 1; x <= Size.X; x++) {
Expand Down Expand Up @@ -358,13 +345,9 @@ private void LoadMapAreasAndTurfs(MapBlockJson block, Dictionary<string, CellDef
DreamObjectArea area = GetOrCreateArea(cellDefinition.Area ?? _defaultArea);

Vector2i pos = (block.X + blockX - 1, block.Y + block.Height - blockY);
Level level = _levels[block.Z - 1];

var turf = SetTurf(pos, block.Z, CreateMapObjectDefinition(cellDefinition.Turf), new(), area);
// The following calls level.SetArea via an event on the area's `contents` var.
if (level.Cells[pos.X - 1, pos.Y - 1].Area != area) {
area.Contents.AddValue(new(turf));
}
_levels[block.Z - 1].Cells[pos.X - 1, pos.Y - 1].Area = area;
SetTurf(pos, block.Z, CreateMapObjectDefinition(cellDefinition.Turf), new());

blockX++;
if (blockX > block.Width) {
Expand Down Expand Up @@ -436,14 +419,18 @@ public sealed class Level {
public Cell[,] Cells;
public readonly Dictionary<Vector2i, Tile> QueuedTileUpdates = new();

public Level(int z, Entity<MapGridComponent> grid, DreamObjectArea area, Vector2i size) {
public Level(int z, Entity<MapGridComponent> grid, DreamObjectDefinition turfType, DreamObjectArea area, Vector2i size) {
Z = z;
Grid = grid;

Cells = new Cell[size.X, size.Y];
for (int x = 0; x < size.X; x++) {
for (int y = 0; y < size.Y; y++) {
Cells[x, y] = new Cell(area);
var turf = new DreamObjectTurf(turfType, x + 1, y + 1, z);
var cell = new Cell(area, turf);

turf.Cell = cell;
Cells[x, y] = cell;
}
}
}
Expand All @@ -453,20 +440,24 @@ public sealed class Cell {
public DreamObjectArea Area {
get => _area;
set {
_area.Turfs.Remove(Turf);
_area.ResetCoordinateCache();

_area = value;
_area.Turfs.Add(Turf);
_area.ResetCoordinateCache();
}
}

public DreamObjectTurf? Turf;
public readonly DreamObjectTurf Turf;
public readonly List<DreamObjectMovable> Movables = new();

private DreamObjectArea _area;

public Cell(DreamObjectArea area) {
public Cell(DreamObjectArea area, DreamObjectTurf turf) {
Turf = turf;
_area = area;
_area.ResetCoordinateCache();
Area = area;
}
}

Expand Down
44 changes: 16 additions & 28 deletions OpenDreamRuntime/Objects/Types/DreamList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ public override DreamValue GetValue(DreamValue key) {
if (DreamObject.TryGetVariable(varName, out var objectVar)) {
return objectVar;
}

throw new Exception($"Cannot get value of undefined var \"{key}\" on type {DreamObject.ObjectDefinition.Type}");
} else {
throw new Exception($"Invalid var index {key}");
Expand Down Expand Up @@ -1136,27 +1136,23 @@ public override int GetLength() {
}

// turf.contents list
public sealed class TurfContentsList : DreamList {
private readonly IDreamMapManager.Cell _cell;

public TurfContentsList(DreamObjectDefinition listDef, IDreamMapManager.Cell cell) : base(listDef, 0) {
_cell = cell;
}
public sealed class TurfContentsList(DreamObjectDefinition listDef, DreamObjectTurf turf) : DreamList(listDef, 0) {
private IDreamMapManager.Cell Cell => turf.Cell;

public override DreamValue GetValue(DreamValue key) {
if (!key.TryGetValueAsInteger(out var index))
throw new Exception($"Invalid index into turf contents list: {key}");
if (index < 1 || index > _cell.Movables.Count)
if (index < 1 || index > Cell.Movables.Count)
throw new Exception($"Out of bounds index on turf contents list: {index}");

return new DreamValue(_cell.Movables[index - 1]);
return new DreamValue(Cell.Movables[index - 1]);
}

// TODO: This would preferably be an IEnumerable<> method. Probably as part of #985.
public override List<DreamValue> GetValues() {
List<DreamValue> values = new(_cell.Movables.Count);
List<DreamValue> values = new(Cell.Movables.Count);

foreach (var movable in _cell.Movables) {
foreach (var movable in Cell.Movables) {
values.Add(new(movable));
}

Expand All @@ -1171,32 +1167,30 @@ public override void AddValue(DreamValue value) {
if (!value.TryGetValueAsDreamObject<DreamObjectMovable>(out var movable))
throw new Exception($"Cannot add {value} to turf contents");

movable.SetVariable("loc", new(_cell.Turf));
movable.SetVariable("loc", new(Cell.Turf));
}

public override void Cut(int start = 1, int end = 0) {
int movableCount = _cell.Movables.Count + 1;
int movableCount = Cell.Movables.Count + 1;
if (end == 0 || end > movableCount) end = movableCount;

for (int i = start; i < end; i++) {
_cell.Movables[i - 1].SetVariable("loc", DreamValue.Null);
Cell.Movables[i - 1].SetVariable("loc", DreamValue.Null);
}
}

public override int GetLength() {
return _cell.Movables.Count;
return Cell.Movables.Count;
}
}

// area.contents list
public sealed class AreaContentsList(DreamObjectDefinition listDef, DreamObjectArea area) : DreamList(listDef, 0) {
private readonly List<DreamObjectTurf> _turfs = new();

public override DreamValue GetValue(DreamValue key) {
if (!key.TryGetValueAsInteger(out var index))
throw new Exception($"Invalid index into area contents list: {key}");

foreach (var turf in _turfs) {
foreach (var turf in area.Turfs) {
if (index < 1)
break;

Expand All @@ -1217,9 +1211,9 @@ public override DreamValue GetValue(DreamValue key) {
}

public override List<DreamValue> GetValues() {
List<DreamValue> values = new(_turfs.Count);
List<DreamValue> values = new(area.Turfs.Count);

foreach (var turf in _turfs) {
foreach (var turf in area.Turfs) {
values.Add(new(turf));
values.AddRange(turf.Contents.GetValues());
}
Expand All @@ -1236,14 +1230,12 @@ public override void AddValue(DreamValue value) {
throw new Exception($"Cannot add {value} to area contents");

turf.Cell.Area = area;
_turfs.Add(turf);
}

public override void RemoveValue(DreamValue value) {
if (!value.TryGetValueAsDreamObject<DreamObjectTurf>(out var turf))
throw new Exception($"Cannot remove {value} from area contents");

_turfs.Remove(turf); // Remove first, in case the new area (default) is still this area
turf.Cell.Area = DreamMapManager.DefaultArea;
}

Expand All @@ -1252,17 +1244,13 @@ public override void Cut(int start = 1, int end = 0) {
}

public override int GetLength() {
int length = _turfs.Count;
int length = area.Turfs.Count;

foreach (var turf in _turfs)
foreach (var turf in area.Turfs)
length += turf.Contents.GetLength();

return length;
}

public IEnumerable<DreamObjectTurf> GetTurfs() {
return _turfs;
}
}

// proc args list
Expand Down
11 changes: 7 additions & 4 deletions OpenDreamRuntime/Objects/Types/DreamObjectArea.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,18 @@ public int Z {
}
}

public readonly AreaContentsList Contents;
public readonly HashSet<DreamObjectTurf> Turfs;
public int AppearanceId;

private readonly AreaContentsList _contents;

// Iterating all our turfs to find the one with the lowest coordinates is slow business
private int? _cachedX, _cachedY, _cachedZ;

public DreamObjectArea(DreamObjectDefinition objectDefinition) : base(objectDefinition) {
Contents = new(ObjectTree.List.ObjectDefinition, this);
Turfs = new();
AtomManager.SetAtomAppearance(this, AtomManager.GetAppearanceFromDefinition(ObjectDefinition));
_contents = new(ObjectTree.List.ObjectDefinition, this);
}

/// <summary>
Expand All @@ -52,7 +55,7 @@ protected override bool TryGetVar(string varName, out DreamValue value) {
value = new(Z);
return true;
case "contents":
value = new(Contents);
value = new(_contents);
return true;
default:
return base.TryGetVar(varName, out value);
Expand Down Expand Up @@ -106,7 +109,7 @@ private void UpdateCoordinateCache() {
if (_cachedX != null)
return;

foreach (var turf in Contents.GetTurfs()) {
foreach (var turf in Turfs) {
if (_cachedX != null) {
if (turf.Z > _cachedZ)
continue;
Expand Down
8 changes: 4 additions & 4 deletions OpenDreamRuntime/Objects/Types/DreamObjectTurf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

public sealed class DreamObjectTurf : DreamObjectAtom {
public readonly int X, Y, Z;
public readonly IDreamMapManager.Cell Cell;
public readonly TurfContentsList Contents;
public IDreamMapManager.Cell Cell;
public int AppearanceId;

public DreamObjectTurf(DreamObjectDefinition objectDefinition, int x, int y, int z, IDreamMapManager.Cell cell) : base(objectDefinition) {
public DreamObjectTurf(DreamObjectDefinition objectDefinition, int x, int y, int z) : base(objectDefinition) {
X = x;
Y = y;
Z = z;
Cell = cell;
Contents = new TurfContentsList(ObjectTree.List.ObjectDefinition, Cell);
Cell = default!; // NEEDS to be set by DreamMapManager after creation
Contents = new TurfContentsList(ObjectTree.List.ObjectDefinition, this);
}

public void SetTurfType(DreamObjectDefinition objectDefinition) {
Expand Down
Loading