Add wires to database

master
Louis Pearson 2022-08-08 21:56:26 -06:00
parent 1404d6067e
commit af85ae5ae7
4 changed files with 233 additions and 74 deletions

View File

@ -149,7 +149,7 @@ var frame_fba_buf: [8192]u8 = undefined;
var frame_fba = std.heap.FixedBufferAllocator.init(&frame_fba_buf);
var frame_alloc = frame_fba.allocator();
var db_fba_buf: [1024]u8 = undefined;
var db_fba_buf: [2046]u8 = undefined;
var db_fba = std.heap.FixedBufferAllocator.init(&db_fba_buf);
var db_alloc = db_fba.allocator();
@ -226,9 +226,11 @@ fn loadLevel(lvl: usize) !void {
{
_ = try wires.resize(0);
var a: usize = 0;
while (db.getWire(level, a)) |wire| : (a += 1) {
while (db.getWire(level, a)) |wireSlice| : (a += 1) {
const wire = try world.Wire.getEnds(wireSlice);
const coord0 = wire[0].coord.subC(levelc);
const coord1 = wire[1].coord.subC(levelc);
w4.tracef("---- Wire (%d, %d), (%d, %d)", coord0.val[0], coord0.val[1], coord1.val[0], coord1.val[1]);
const p1 = util.vec2ToVec2f(coord0.toVec2() * tile_size + Vec2{ 4, 4 });
const p2 = util.vec2ToVec2f(coord1.toVec2() * tile_size + Vec2{ 4, 4 });
@ -243,8 +245,8 @@ fn loadLevel(lvl: usize) !void {
w.begin().pos = p1;
w.end().pos = p2;
w.begin().pinned = wire[0].kind == world.EntityKind.WireAnchor;
w.end().pinned = wire[1].kind == world.EntityKind.WireEndAnchor;
w.begin().pinned = wire[0].anchored;
w.end().pinned = wire[1].anchored;
w.straighten();
}
@ -530,6 +532,7 @@ pub fn update(time: usize) !State {
return .Game;
}
/// Holds data related to selecting/interacting with the world
const Interaction = struct {
pos: Vec2,
details: union(enum) {

View File

@ -38,6 +38,7 @@ export fn update() void {
error.NoLevelUp => showErr(@errorName(e)),
error.NoLevelLeft => showErr(@errorName(e)),
error.NoLevelRight => showErr(@errorName(e)),
error.MissingEnds => showErr(@errorName(e)),
},
};
if (state != newState) {
@ -52,6 +53,7 @@ export fn update() void {
error.NullTiles => showErr(@errorName(e)),
error.SpawnOutOfBounds => showErr(@errorName(e)),
error.InvalidLevel => showErr(@errorName(e)),
error.MissingEnds => showErr(@errorName(e)),
},
}
}

View File

@ -190,6 +190,10 @@ pub const Coordinate = struct {
return .{ .val = .{ coord.val[0] - other.val[0], coord.val[1] - other.val[1] } };
}
pub fn addOffset(coord: Coordinate, val: [2]i4) Coordinate {
return .{ .val = .{ coord.val[0] + val[0], coord.val[1] + val[1] } };
}
pub fn eq(coord: Coordinate, other: Coordinate) bool {
return coord.val[0] == other.val[0] and coord.val[1] == other.val[1];
}
@ -209,6 +213,10 @@ pub const Coordinate = struct {
return .{ coord.val[0], coord.val[1] };
}
pub fn toOffset(coord: Coordinate) [2]i4 {
return .{ @intCast(i4, coord.val[0]), @intCast(i4, coord.val[1]) };
}
pub fn fromWorld(x: i8, y: i8) Coordinate {
return .{ .val = .{
@intCast(i16, x) * 20,
@ -429,10 +437,6 @@ pub const AutoTileset = struct {
pub const EntityKind = enum(u8) {
Player,
Coin,
WireNode,
WireAnchor,
WireEndNode,
WireEndAnchor,
Door,
Trapdoor,
Collected,
@ -461,12 +465,109 @@ pub const Entity = struct {
}
};
// Data format:
// | level count | node count |
// | level headers... |
// | node data... |
// | level data... |
const WireKind = enum {
Begin,
BeginPinned,
Point,
PointPinned,
End,
};
/// A wire is stored as a coordinate and at least one point relative to it,
/// and then an end byte
pub const Wire = union(enum) {
Begin: Coordinate,
BeginPinned: Coordinate,
/// Relative to the last point
Point: [2]i4,
/// Relative to the last point
PointPinned: [2]i4,
End,
const EndData = struct { coord: Coordinate, anchored: bool };
pub fn getEnds(wires: []Wire) ![2]EndData {
std.debug.assert(wires[0] == .Begin or wires[0] == .BeginPinned);
var ends: [2]EndData = undefined;
const w4 = @import("wasm4.zig");
for (wires) |wire| {
switch (wire) {
.Begin => |coord| {
ends[0] = .{ .coord = coord, .anchored = false };
ends[1] = ends[0];
w4.tracef("[getEnds] Begin (%d, %d)", coord.val[0], coord.val[1]);
},
.BeginPinned => |coord| {
ends[0] = .{ .coord = coord, .anchored = true };
ends[1] = ends[0];
w4.tracef("[getEnds] BeginPinned (%d, %d)", coord.val[0], coord.val[1]);
},
.Point => |offset| {
ends[1] = .{ .coord = ends[1].coord.addOffset(offset), .anchored = false };
const o1 = @intCast(i32, offset[0]);
const o2 = @intCast(i32, offset[1]);
w4.tracef("[getEnds] Point (%d, %d)", o1, o2);
},
.PointPinned => |offset| {
ends[1] = .{ .coord = ends[1].coord.addOffset(offset), .anchored = true };
const o1 = @intCast(i32, offset[0]);
const o2 = @intCast(i32, offset[1]);
w4.tracef("[getEnds] Point Pinned (%d, %d)", o1, o2);
},
.End => {
return ends;
},
}
}
return error.MissingEnds;
}
pub fn write(wire: Wire, writer: anytype) !void {
try writer.writeByte(@enumToInt(wire));
switch (wire) {
.Begin => |coord| {
try coord.write(writer);
},
.BeginPinned => |coord| {
try coord.write(writer);
},
.Point => |point| {
const byte = @bitCast(u8, @intCast(i8, point[0])) | @bitCast(u8, @intCast(i8, point[1])) << 4;
try writer.writeByte(byte);
},
.PointPinned => |point| {
const byte = @bitCast(u8, @intCast(i8, point[0])) | @bitCast(u8, @intCast(i8, point[1])) << 4;
try writer.writeByte(byte);
},
.End => {},
}
}
pub fn read(reader: anytype) !Wire {
const kind = @intToEnum(WireKind, try reader.readByte());
switch (kind) {
.Begin => return Wire{ .Begin = try Coord.read(reader) },
.BeginPinned => return Wire{ .BeginPinned = try Coord.read(reader) },
.Point => {
const byte = try reader.readByte();
return Wire{ .Point = .{
@bitCast(i4, @truncate(u4, 0b0000_1111 & byte)),
@bitCast(i4, @truncate(u4, (0b1111_0000 & byte) >> 4)),
} };
},
.PointPinned => {
const byte = try reader.readByte();
return Wire{ .PointPinned = .{
@bitCast(i4, @truncate(u4, 0b0000_1111 & byte)),
@bitCast(i4, @truncate(u4, (0b1111_0000 & byte) >> 4)),
} };
},
.End => return Wire.End,
}
}
};
/// Used to look up level data
pub const LevelHeader = struct {
x: i8,
y: i8,
@ -491,6 +592,7 @@ pub fn write(
writer: anytype,
level_headers: []LevelHeader,
entities: []Entity,
wires: []Wire,
circuit_nodes: []CircuitNode,
levels: []Level,
) !void {
@ -498,6 +600,8 @@ pub fn write(
try writer.writeInt(u16, @intCast(u16, level_headers.len), .Little);
// Write number of entities
try writer.writeInt(u16, @intCast(u16, entities.len), .Little);
// Write number of entities
try writer.writeInt(u16, @intCast(u16, wires.len), .Little);
// Write number of circuit nodes
try writer.writeInt(u16, @intCast(u16, circuit_nodes.len), .Little);
@ -511,6 +615,11 @@ pub fn write(
try entity.write(writer);
}
// Write wire data
for (wires) |wire| {
try wire.write(writer);
}
// Write node data
for (circuit_nodes) |node| {
try node.write(writer);
@ -527,6 +636,8 @@ pub const Database = struct {
cursor: Cursor,
level_info: []LevelHeader,
entities: []Entity,
wires: []Wire,
wire_count: usize,
circuit_info: []CircuitNode,
level_data_begin: usize,
@ -544,6 +655,8 @@ pub const Database = struct {
const level_count = try reader.readInt(u16, .Little);
// read number of entities
const entity_count = try reader.readInt(u16, .Little);
// read number of wires
const wire_count = try reader.readInt(u16, .Little);
// read number of nodes
const node_count = try reader.readInt(u16, .Little);
@ -561,6 +674,16 @@ pub const Database = struct {
entities[i] = try Entity.read(reader);
}
// read wires
// Allocate a fixed amount of space since wires are likely to be shuffled around
var wires = try alloc.alloc(Wire, 255);
{
var i: usize = 0;
while (i < wire_count) : (i += 1) {
wires[i] = try Wire.read(reader);
}
}
// read circuits
var circuit_nodes = try alloc.alloc(CircuitNode, node_count);
@ -575,6 +698,8 @@ pub const Database = struct {
.cursor = cursor,
.level_info = level_headers,
.entities = entities,
.wires = wires,
.wire_count = wire_count,
.circuit_info = circuit_nodes,
.level_data_begin = level_data_begin,
};
@ -732,20 +857,33 @@ pub const Database = struct {
db.entities[coin].kind = .Collected;
}
pub fn getWire(database: *Database, level: Level, num: usize) ?[2]Entity {
pub fn getWire(database: *Database, level: Level, num: usize) ?[]Wire {
const nw = Coord.fromWorld(level.world_x, level.world_y);
const se = nw.add(.{ 20, 20 });
var node_begin: ?Entity = null;
var node_begin: ?usize = null;
var wire_count: usize = 0;
for (database.entities) |entity| {
if (!entity.coord.within(nw, se)) continue;
if (entity.kind == .WireNode or entity.kind == .WireAnchor) {
node_begin = entity;
} else if (entity.kind == .WireEndNode or entity.kind == .WireEndAnchor) {
if (node_begin) |begin| {
if (wire_count == num) return [2]Entity{ begin, entity };
var i: usize = 0;
while (i < database.wire_count) : (i += 1) {
const wire = database.wires[i];
switch (wire) {
.Begin => |coord| {
if (!coord.within(nw, se)) continue;
node_begin = i;
},
.BeginPinned => |coord| {
if (!coord.within(nw, se)) continue;
node_begin = i;
},
.Point, .PointPinned => continue,
.End => {
if (node_begin) |node| {
if (wire_count == num) {
return database.wires[node..i + 1];
}
wire_count += 1;
node_begin = null;
}
},
}
}
return null;

View File

@ -58,6 +58,9 @@ fn make(step: *std.build.Step) !void {
var entity_array = std.ArrayList(world.Entity).init(allocator);
defer entity_array.deinit();
var wires = std.ArrayList(world.Wire).init(allocator);
defer wires.deinit();
for (ldtk.levels) |level| {
std.log.warn("Level: {}", .{levels.items.len});
const parsed_level = try parseLevel(.{
@ -65,6 +68,7 @@ fn make(step: *std.build.Step) !void {
.ldtk = ldtk,
.level = level,
.entity_array = &entity_array,
.wires = &wires,
});
try levels.append(parsed_level);
@ -80,6 +84,10 @@ fn make(step: *std.build.Step) !void {
std.log.warn("{:0>2}: {}", .{ i, node });
}
for (wires.items) |node, i| {
std.log.warn("Wire {:0>2}: {any}", .{ i, node });
}
// Calculate the offset of each level and store it in the headers.
// Offset is relative to the beginning of level.data
var level_headers = std.ArrayList(world.LevelHeader).init(allocator);
@ -109,7 +117,14 @@ fn make(step: *std.build.Step) !void {
defer data.deinit();
const writer = data.writer();
try world.write(writer, level_headers.items, entity_array.items, circuit.items, levels.items);
try world.write(
writer,
level_headers.items,
entity_array.items,
wires.items,
circuit.items,
levels.items,
);
// Open output file and write data into it
cwd.makePath(this.builder.getInstallPath(.lib, "")) catch |e| switch (e) {
@ -127,11 +142,13 @@ fn parseLevel(opt: struct {
ldtk: LDtk.Root,
level: LDtk.Level,
entity_array: *std.ArrayList(world.Entity),
wires: *std.ArrayList(world.Wire),
}) !world.Level {
const ldtk = opt.ldtk;
const level = opt.level;
const entity_array = opt.entity_array;
const allocator = opt.allocator;
const wires = opt.wires;
const layers = level.layerInstances orelse return error.NoLayers;
@ -147,11 +164,12 @@ fn parseLevel(opt: struct {
std.debug.assert(layer.__type == .Entities);
for (layer.entityInstances) |entity| {
var is_wire = false;
var kind_opt: ?world.EntityKind = null;
if (std.mem.eql(u8, entity.__identifier, "Player")) {
kind_opt = .Player;
} else if (std.mem.eql(u8, entity.__identifier, "Wire")) {
kind_opt = .WireNode;
is_wire = true;
} else if (std.mem.eql(u8, entity.__identifier, "Coin")) {
kind_opt = .Coin;
} else if (std.mem.eql(u8, entity.__identifier, "Door")) {
@ -160,21 +178,18 @@ fn parseLevel(opt: struct {
kind_opt = .Trapdoor;
}
const levelc = world.Coordinate.fromWorld(world_x, world_y);
// Parsing code for wire entities. They're a little more complex
// than the rest
if (kind_opt) |kind| {
const levelc = world.Coordinate.fromWorld(world_x, world_y);
if (kind != .WireNode) {
const entc = world.Coordinate.init(.{
@intCast(i16, entity.__grid[0]),
@intCast(i16, entity.__grid[1]),
});
const world_entity = world.Entity{
.kind = kind,
.coord = levelc.addC(entc)
};
const world_entity = world.Entity{ .kind = kind, .coord = levelc.addC(entc) };
try entity_array.append(world_entity);
} else {
}
if (is_wire) {
var anchor1 = false;
var anchor2 = false;
const p1_c = world.Coordinate.init(.{
@ -201,18 +216,19 @@ fn parseLevel(opt: struct {
};
}
}
const wire_begin = world.Entity{
.kind = if (anchor1) .WireAnchor else .WireNode,
.coord = p1_c.addC(levelc),
};
try entity_array.append(wire_begin);
const wire_end = world.Entity{
.kind = if (anchor2) .WireEndAnchor else .WireEndNode,
.coord = p2_c.addC(levelc),
};
try entity_array.append(wire_end);
if (anchor1) {
try wires.append(.{ .BeginPinned = p1_c.addC(levelc) });
} else {
try wires.append(.{ .Begin = p1_c.addC(levelc) });
}
if (anchor2) {
try wires.append(.{ .PointPinned = p2_c.subC(p1_c).toOffset() });
} else {
try wires.append(.{ .Point = p2_c.subC(p1_c).toOffset() });
}
try wires.append(.End);
}
}