Add collaborative surface drawing
This commit is contained in:
parent
6b7ef4c11b
commit
b92c55562d
28 changed files with 3504 additions and 2 deletions
284
tests/surface_drawing_validation.gd
Normal file
284
tests/surface_drawing_validation.gd
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
extends SceneTree
|
||||
|
||||
const FINGERPRINT_A: String = (
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
)
|
||||
const FINGERPRINT_B: String = (
|
||||
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
||||
)
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
_validate_palette()
|
||||
_validate_protocol_bounds()
|
||||
_validate_grid_snapping()
|
||||
await _validate_canvas_geometry_and_collaboration()
|
||||
await _validate_blocked_author_visibility()
|
||||
_validate_peer_capability_tracking()
|
||||
print("Surface drawing validation: PASS")
|
||||
quit()
|
||||
|
||||
|
||||
func _validate_palette() -> void:
|
||||
var ids: Array[StringName] = SurfaceDrawingPalette.get_color_ids()
|
||||
assert(ids.size() == 8)
|
||||
assert(ids.front() == SurfaceDrawingPalette.DEFAULT_COLOR_ID)
|
||||
for color_id: StringName in ids:
|
||||
assert(SurfaceDrawingPalette.has_color(color_id))
|
||||
assert(not SurfaceDrawingPalette.get_display_name(color_id).is_empty())
|
||||
assert(
|
||||
SurfaceDrawingPalette.filter_unlocked_ids([])
|
||||
== [SurfaceDrawingPalette.DEFAULT_COLOR_ID]
|
||||
)
|
||||
|
||||
|
||||
func _validate_protocol_bounds() -> void:
|
||||
assert(SurfaceDrawingProtocol.GRID_WIDTH == 32)
|
||||
assert(SurfaceDrawingProtocol.GRID_HEIGHT == 32)
|
||||
assert(is_equal_approx(SurfaceDrawingProtocol.CELL_SIZE, 0.075))
|
||||
assert(is_equal_approx(
|
||||
float(SurfaceDrawingProtocol.GRID_WIDTH)
|
||||
* SurfaceDrawingProtocol.CELL_SIZE,
|
||||
2.4,
|
||||
))
|
||||
var canvas_request: Dictionary = {
|
||||
"request_id": "canvas-1",
|
||||
"session_id": "session",
|
||||
"origin": [0.0, 1.0, 2.0],
|
||||
"normal": [0.0, 1.0, 0.0],
|
||||
"tangent": [1.0, 0.0, 0.0],
|
||||
"width": SurfaceDrawingProtocol.GRID_WIDTH,
|
||||
"height": SurfaceDrawingProtocol.GRID_HEIGHT,
|
||||
"cell_size": SurfaceDrawingProtocol.CELL_SIZE,
|
||||
}
|
||||
assert(SurfaceDrawingProtocol.validate_canvas_request(canvas_request))
|
||||
var malformed: Dictionary = canvas_request.duplicate(true)
|
||||
malformed["origin"] = [INF, 0.0, 0.0]
|
||||
assert(not SurfaceDrawingProtocol.validate_canvas_request(malformed))
|
||||
var edit_request: Dictionary = {
|
||||
"request_id": "edit-1",
|
||||
"session_id": "session",
|
||||
"canvas_id": "canvas-1",
|
||||
"stroke_id": "stroke-1",
|
||||
"edits": [{"x": 0, "y": 0, "color_id": "ocean_teal"}],
|
||||
}
|
||||
assert(SurfaceDrawingProtocol.validate_edit_request(edit_request))
|
||||
edit_request["edits"] = [{
|
||||
"x": SurfaceDrawingProtocol.GRID_WIDTH,
|
||||
"y": 0,
|
||||
"color_id": "ocean_teal",
|
||||
}]
|
||||
assert(not SurfaceDrawingProtocol.validate_edit_request(edit_request))
|
||||
var guide_request: Dictionary = {
|
||||
"request_id": "guide-1",
|
||||
"session_id": "session",
|
||||
"canvas_id": "canvas-1",
|
||||
"guide_visible": false,
|
||||
"finalized": false,
|
||||
}
|
||||
assert(SurfaceDrawingProtocol.validate_guide_request(guide_request))
|
||||
guide_request["guide_visible"] = 0
|
||||
assert(not SurfaceDrawingProtocol.validate_guide_request(guide_request))
|
||||
var undo_request: Dictionary = {
|
||||
"request_id": "undo-1",
|
||||
"session_id": "session",
|
||||
"stroke_id": "stroke-1",
|
||||
}
|
||||
assert(SurfaceDrawingProtocol.validate_undo_request(undo_request))
|
||||
|
||||
|
||||
func _validate_grid_snapping() -> void:
|
||||
var anchor: Dictionary = {
|
||||
"session_id": "session",
|
||||
"canvas_id": "anchor",
|
||||
"origin": [0.0, 0.0, 0.0],
|
||||
"normal": [0.0, 1.0, 0.0],
|
||||
"tangent": [1.0, 0.0, 0.0],
|
||||
"width": SurfaceDrawingProtocol.GRID_WIDTH,
|
||||
"height": SurfaceDrawingProtocol.GRID_HEIGHT,
|
||||
"cell_size": SurfaceDrawingProtocol.CELL_SIZE,
|
||||
"revision": 0,
|
||||
"guide_visible": false,
|
||||
"finalized": true,
|
||||
"layer": 1,
|
||||
"creator_fingerprint": FINGERPRINT_A,
|
||||
"cells": [],
|
||||
}
|
||||
var snapped: Dictionary = SurfaceDrawingPlacement.resolve(
|
||||
Vector3(2.28, 0.02, 0.08),
|
||||
Vector3.UP,
|
||||
Vector3.RIGHT,
|
||||
[anchor],
|
||||
)
|
||||
assert(bool(snapped["snapped"]))
|
||||
var snapped_origin: Vector3 = snapped["origin"]
|
||||
assert(snapped_origin.is_equal_approx(Vector3(2.4, 0.0, 0.0)))
|
||||
var unsnapped: Dictionary = SurfaceDrawingPlacement.resolve(
|
||||
Vector3(1.2, 0.0, 0.0),
|
||||
Vector3.UP,
|
||||
Vector3.RIGHT,
|
||||
[anchor],
|
||||
)
|
||||
assert(not bool(unsnapped["snapped"]))
|
||||
|
||||
|
||||
func _validate_canvas_geometry_and_collaboration() -> void:
|
||||
var world := Node3D.new()
|
||||
root.add_child(world)
|
||||
var canvas := SurfaceDrawingCanvas.new()
|
||||
world.add_child(canvas)
|
||||
var state: Dictionary = {
|
||||
"session_id": "session",
|
||||
"canvas_id": "canvas-1",
|
||||
"origin": [0.0, 0.0, 0.0],
|
||||
"normal": [0.0, 1.0, 0.0],
|
||||
"tangent": [1.0, 0.0, 0.0],
|
||||
"width": SurfaceDrawingProtocol.GRID_WIDTH,
|
||||
"height": SurfaceDrawingProtocol.GRID_HEIGHT,
|
||||
"cell_size": SurfaceDrawingProtocol.CELL_SIZE,
|
||||
"revision": 0,
|
||||
"creator_fingerprint": FINGERPRINT_A,
|
||||
"cells": [],
|
||||
}
|
||||
assert(canvas.setup(state, null))
|
||||
var first_center: Vector3 = canvas.get_cell_world_position(0, 0)
|
||||
assert(canvas.cell_at_world_point(first_center) == Vector2i(0, 0))
|
||||
assert(canvas.contains_world_point(first_center))
|
||||
var first_update: Dictionary = {
|
||||
"session_id": "session",
|
||||
"canvas_id": "canvas-1",
|
||||
"revision": 1,
|
||||
"edits": [{
|
||||
"x": 3,
|
||||
"y": 4,
|
||||
"color_id": "coral",
|
||||
"author_fingerprint": FINGERPRINT_A,
|
||||
}],
|
||||
}
|
||||
assert(canvas.apply_update(first_update))
|
||||
var finish_update: Dictionary = {
|
||||
"session_id": "session",
|
||||
"canvas_id": "canvas-1",
|
||||
"revision": 2,
|
||||
"guide_visible": false,
|
||||
"finalized": true,
|
||||
}
|
||||
assert(canvas.apply_guide_update(finish_update))
|
||||
assert(not canvas.is_guide_visible())
|
||||
assert(canvas.is_finalized())
|
||||
await process_frame
|
||||
var finished_pixel_scale: float = canvas.get_rendered_pixel_size()
|
||||
assert(
|
||||
is_equal_approx(
|
||||
finished_pixel_scale, SurfaceDrawingProtocol.CELL_SIZE
|
||||
),
|
||||
"finished pixel scale %f does not match cell size %f"
|
||||
% [finished_pixel_scale, SurfaceDrawingProtocol.CELL_SIZE],
|
||||
)
|
||||
var second_update: Dictionary = {
|
||||
"session_id": "session",
|
||||
"canvas_id": "canvas-1",
|
||||
"revision": 3,
|
||||
"edits": [{
|
||||
"x": 3,
|
||||
"y": 4,
|
||||
"color_id": "blue",
|
||||
"author_fingerprint": FINGERPRINT_B,
|
||||
}],
|
||||
}
|
||||
assert(canvas.apply_update(second_update))
|
||||
var cells: Array[Dictionary] = canvas.get_authoritative_cells()
|
||||
assert(cells.size() == 1)
|
||||
assert(cells[0]["color_id"] == "blue")
|
||||
assert(cells[0]["author_fingerprint"] == FINGERPRINT_B)
|
||||
var erase_update: Dictionary = {
|
||||
"session_id": "session",
|
||||
"canvas_id": "canvas-1",
|
||||
"revision": 4,
|
||||
"edits": [{
|
||||
"x": 3,
|
||||
"y": 4,
|
||||
"color_id": "",
|
||||
"author_fingerprint": "",
|
||||
}],
|
||||
}
|
||||
assert(canvas.apply_update(erase_update))
|
||||
assert(canvas.get_authoritative_cells().is_empty())
|
||||
world.queue_free()
|
||||
await process_frame
|
||||
|
||||
|
||||
func _validate_peer_capability_tracking() -> void:
|
||||
var registry := PeerRegistry.new()
|
||||
assert(registry.add_peer(
|
||||
1,
|
||||
"profile",
|
||||
"Voyager",
|
||||
NetworkProtocol.PROTOCOL_VERSION,
|
||||
FINGERPRINT_A,
|
||||
"public key fixture",
|
||||
PackedStringArray([str(SurfaceDrawingProtocol.CAPABILITY)]),
|
||||
))
|
||||
var record: PeerRegistry.PeerRecord = registry.get_peer(1)
|
||||
assert(record != null)
|
||||
assert(str(SurfaceDrawingProtocol.CAPABILITY) in record.capability_flags)
|
||||
|
||||
|
||||
func _validate_blocked_author_visibility() -> void:
|
||||
var relationships := PlayerRelationshipStore.new()
|
||||
relationships.set("_loaded", true)
|
||||
relationships.set("_records", {
|
||||
FINGERPRINT_B: {"blocked": true, "muted": true},
|
||||
})
|
||||
var world := Node3D.new()
|
||||
root.add_child(world)
|
||||
var canvas := SurfaceDrawingCanvas.new()
|
||||
world.add_child(canvas)
|
||||
var state: Dictionary = {
|
||||
"session_id": "session",
|
||||
"canvas_id": "blocked-author-canvas",
|
||||
"origin": [0.0, 0.0, 0.0],
|
||||
"normal": [0.0, 1.0, 0.0],
|
||||
"tangent": [1.0, 0.0, 0.0],
|
||||
"width": SurfaceDrawingProtocol.GRID_WIDTH,
|
||||
"height": SurfaceDrawingProtocol.GRID_HEIGHT,
|
||||
"cell_size": SurfaceDrawingProtocol.CELL_SIZE,
|
||||
"revision": 1,
|
||||
"creator_fingerprint": FINGERPRINT_A,
|
||||
"cells": [
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"color_id": "coral",
|
||||
"author_fingerprint": FINGERPRINT_A,
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
"color_id": "blue",
|
||||
"author_fingerprint": FINGERPRINT_B,
|
||||
},
|
||||
],
|
||||
}
|
||||
assert(canvas.setup(state, relationships))
|
||||
assert(_rendered_pixel_count(canvas) == 1)
|
||||
relationships.set("_records", {})
|
||||
canvas.refresh_relationship_visibility()
|
||||
await process_frame
|
||||
assert(_rendered_pixel_count(canvas) == 2)
|
||||
world.queue_free()
|
||||
await process_frame
|
||||
|
||||
|
||||
func _rendered_pixel_count(canvas: SurfaceDrawingCanvas) -> int:
|
||||
var count: int = 0
|
||||
for child: Node in canvas.get_children():
|
||||
if child is MultiMeshInstance3D:
|
||||
var instance := child as MultiMeshInstance3D
|
||||
if instance.multimesh != null:
|
||||
count += instance.multimesh.instance_count
|
||||
return count
|
||||
Loading…
Add table
Add a link
Reference in a new issue