Add artwork export and stamping
This commit is contained in:
parent
ba35db1015
commit
8107e2d89c
21 changed files with 1727 additions and 105 deletions
|
|
@ -481,6 +481,8 @@ func _run() -> void:
|
|||
var hide_button := toolbar.get_node("%HideGuideButton") as Button
|
||||
var restore_button := toolbar.get_node("%RestoreGuideButton") as Button
|
||||
var finalize_button := toolbar.get_node("%FinalizeGuideButton") as Button
|
||||
var export_button := toolbar.get_node("%ExportButton") as Button
|
||||
var stamp_button := toolbar.get_node("%StampButton") as Button
|
||||
assert(
|
||||
mode_button != null
|
||||
and eraser_button != null
|
||||
|
|
@ -488,7 +490,13 @@ func _run() -> void:
|
|||
and hide_button != null
|
||||
and restore_button != null
|
||||
and finalize_button != null
|
||||
and export_button != null
|
||||
and stamp_button != null
|
||||
)
|
||||
assert(export_button.text == "png")
|
||||
assert(export_button.tooltip_text == "export aimed artwork as PNG")
|
||||
assert(stamp_button.text == "stamp")
|
||||
assert(stamp_button.disabled)
|
||||
assert(toolbar.get_node_or_null("%CloseButton") == null)
|
||||
var expected_toolbar_icons: Dictionary[Button, String] = {
|
||||
mode_button: "/art/art_kit_marker.png",
|
||||
|
|
@ -511,6 +519,8 @@ func _run() -> void:
|
|||
hide_button,
|
||||
restore_button,
|
||||
finalize_button,
|
||||
export_button,
|
||||
stamp_button,
|
||||
]:
|
||||
assert(icon_button.custom_minimum_size == Vector2(48, 44))
|
||||
assert(icon_button.get_theme_constant("icon_max_width") == 40)
|
||||
|
|
@ -521,7 +531,9 @@ func _run() -> void:
|
|||
assert(is_equal_approx(icon_style.content_margin_top, 2.0))
|
||||
assert(mode_button.custom_minimum_size == Vector2(48, 48))
|
||||
assert(mode_button.get_theme_constant("icon_max_width") == 40)
|
||||
assert(mode_button.get_index() > finalize_button.get_index())
|
||||
assert(export_button.get_index() > finalize_button.get_index())
|
||||
assert(stamp_button.get_index() > export_button.get_index())
|
||||
assert(mode_button.get_index() > stamp_button.get_index())
|
||||
assert(hide_button.button_group != null)
|
||||
assert(hide_button.button_group == restore_button.button_group)
|
||||
assert(hide_button.button_group == finalize_button.button_group)
|
||||
|
|
@ -537,6 +549,8 @@ func _run() -> void:
|
|||
hide_button,
|
||||
restore_button,
|
||||
finalize_button,
|
||||
export_button,
|
||||
stamp_button,
|
||||
]:
|
||||
assert(pointer_only_control.focus_mode == Control.FOCUS_NONE)
|
||||
assert(brush_option.get_popup().unfocusable)
|
||||
|
|
@ -639,13 +653,31 @@ func _run() -> void:
|
|||
)) == 24)
|
||||
|
||||
for product_id: StringName in [
|
||||
&"marker_ocean_teal", &"brush_4x", &"grid_128x",
|
||||
&"marker_ocean_teal",
|
||||
&"brush_4x",
|
||||
&"grid_128x",
|
||||
PlayerArtUnlocks.STAMP_PRODUCT_ID,
|
||||
]:
|
||||
assert(player.art_unlocks.unlock_product(product_id))
|
||||
await process_frame
|
||||
assert(not (color_buttons[&"ocean_teal"] as Button).disabled)
|
||||
assert(not brush_option.get_popup().is_item_disabled(3))
|
||||
assert(not grid_option.get_popup().is_item_disabled(3))
|
||||
assert(not stamp_button.disabled)
|
||||
var stamp_library_panel := toolbar.get_node(
|
||||
"%StampLibraryPanel"
|
||||
) as PanelContainer
|
||||
var stamp_library_close := toolbar.get_node(
|
||||
"%StampLibraryClose"
|
||||
) as Button
|
||||
assert(stamp_library_panel != null and not stamp_library_panel.visible)
|
||||
stamp_button.pressed.emit()
|
||||
assert(stamp_library_panel.visible)
|
||||
var library_pointer := InputEventMouseMotion.new()
|
||||
library_pointer.position = stamp_library_panel.get_global_rect().get_center()
|
||||
assert(toolbar.owns_pointer_event(library_pointer))
|
||||
stamp_library_close.pressed.emit()
|
||||
assert(not stamp_library_panel.visible)
|
||||
assert(not locked_color_lock.visible)
|
||||
assert(str(brush_option.get_item_icon(3).get_meta(
|
||||
&"channel_mask_source", ""
|
||||
|
|
|
|||
|
|
@ -487,7 +487,7 @@ func _test_host_art_shop_purchase(
|
|||
for _frame: int in 4:
|
||||
await physics_frame
|
||||
var required_balance: int = (
|
||||
ArtShopStock.ART_KIT_PRICE + ArtShopStock.UPGRADE_PRICE * 3
|
||||
ArtShopStock.ART_KIT_PRICE + ArtShopStock.UPGRADE_PRICE * 4
|
||||
)
|
||||
if player.wallet.get_balance() < required_balance:
|
||||
assert(player.wallet.credit(required_balance - player.wallet.get_balance()))
|
||||
|
|
@ -505,7 +505,10 @@ func _test_host_art_shop_purchase(
|
|||
assert(art_item.icon.resource_path.ends_with("/art/art_kit.png"))
|
||||
assert(player.hotbar.assign_item(0, ArtShopStock.ART_KIT_ITEM_ID))
|
||||
for product_id: StringName in [
|
||||
&"marker_ocean_teal", &"brush_2x", &"grid_32x",
|
||||
&"marker_ocean_teal",
|
||||
&"brush_2x",
|
||||
&"grid_32x",
|
||||
PlayerArtUnlocks.STAMP_PRODUCT_ID,
|
||||
]:
|
||||
_shop_result.clear()
|
||||
assert(not shop_service.request_art_upgrade(product_id).is_empty())
|
||||
|
|
@ -844,7 +847,9 @@ func _test_fishing_shop_sale_ui(
|
|||
for child: Node in shop.get_node("%SuppliesList").get_children():
|
||||
if child is Label:
|
||||
stock_sections.append((child as Label).text)
|
||||
assert(stock_sections == ["art kit", "markers", "brushes", "grids"])
|
||||
assert(stock_sections == [
|
||||
"art kit", "markers", "brushes", "grids", "stamps",
|
||||
])
|
||||
var marker_icons := shop.find_children(
|
||||
"MarkerIcon", "TextureRect", true, false
|
||||
)
|
||||
|
|
@ -903,6 +908,17 @@ func _test_fishing_shop_sale_ui(
|
|||
)
|
||||
)
|
||||
assert(found_art_upgrade_icons == expected_art_upgrade_icons.size())
|
||||
var stamp_button: Button
|
||||
for upgrade_node: Node in shop.find_children("*", "Button", true, false):
|
||||
var upgrade_button := upgrade_node as Button
|
||||
if StringName(str(upgrade_button.get_meta(&"art_product_id", ""))) == (
|
||||
PlayerArtUnlocks.STAMP_PRODUCT_ID
|
||||
):
|
||||
stamp_button = upgrade_button
|
||||
break
|
||||
assert(stamp_button != null)
|
||||
assert(stamp_button.text == "stamp")
|
||||
assert(stamp_button.icon == null)
|
||||
var price_bubbles := shop.find_children(
|
||||
"PriceBubble", "PanelContainer", true, false
|
||||
)
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ func _run_host() -> void:
|
|||
assert(players_page != null)
|
||||
players_page.call("_refresh")
|
||||
assert(_has_button_text(players_page, "deop"))
|
||||
assert(_has_button_text(players_page, "clear art"))
|
||||
|
||||
var unban_deadline: int = Time.get_ticks_msec() + 12000
|
||||
while (
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ extends SceneTree
|
|||
|
||||
const MainScene: PackedScene = preload("res://main/main.tscn")
|
||||
const TEST_PORT: int = 18133
|
||||
const WAIT_MSEC: int = 20000
|
||||
const WAIT_MSEC: int = 60000
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
|
|
@ -83,6 +83,10 @@ func _run_host() -> void:
|
|||
str(overwritten_cell["author_fingerprint"])
|
||||
== remote_record.identity_fingerprint
|
||||
)
|
||||
assert(
|
||||
remote_record.identity_fingerprint
|
||||
in overwritten_state.get("participant_fingerprints", [])
|
||||
)
|
||||
|
||||
assert(service.request_cell_edits(canvas_id, [{
|
||||
"x": 8,
|
||||
|
|
@ -112,7 +116,61 @@ func _run_host() -> void:
|
|||
assert(service.request_guide_visibility(canvas_id, false, true))
|
||||
await create_timer(1.0).timeout
|
||||
assert(service.clear_session_artwork())
|
||||
var stamp_deadline: int = Time.get_ticks_msec() + WAIT_MSEC
|
||||
while (
|
||||
Time.get_ticks_msec() < stamp_deadline
|
||||
and service.get_canvas_ids().is_empty()
|
||||
):
|
||||
await process_frame
|
||||
assert(service.get_canvas_ids().size() == 1)
|
||||
var stamp_id: String = service.get_canvas_ids()[0]
|
||||
var stamp_state: Dictionary = service.get_canvas_state(stamp_id)
|
||||
assert(bool(stamp_state.get("stamp", false)))
|
||||
assert(bool(stamp_state["finalized"]))
|
||||
assert((stamp_state["cells"] as Array).size() == 1)
|
||||
assert(str(stamp_state["cells"][0]["color_id"]) == "coral")
|
||||
assert(
|
||||
stamp_state.get("participant_fingerprints", [])
|
||||
== [remote_record.identity_fingerprint]
|
||||
)
|
||||
# Give the client a full observation window before the authoritative clear.
|
||||
await create_timer(1.0).timeout
|
||||
assert(
|
||||
service.clear_artwork_by_fingerprint(
|
||||
remote_record.identity_fingerprint
|
||||
) == 1
|
||||
)
|
||||
assert(service.get_canvas_ids().is_empty())
|
||||
var second_stamp_deadline: int = Time.get_ticks_msec() + WAIT_MSEC
|
||||
while (
|
||||
Time.get_ticks_msec() < second_stamp_deadline
|
||||
and service.get_canvas_ids().is_empty()
|
||||
):
|
||||
await process_frame
|
||||
assert(service.get_canvas_ids().size() == 1)
|
||||
var player_list := main.get_node(
|
||||
"%NetworkPlayerListService"
|
||||
) as NetworkPlayerListService
|
||||
var remote_entry: PlayerListEntry = null
|
||||
for entry: PlayerListEntry in player_list.get_entries():
|
||||
if entry.peer_id == remote_peer_id:
|
||||
remote_entry = entry
|
||||
break
|
||||
assert(remote_entry != null and remote_entry.can_ban)
|
||||
assert(player_list.ban(
|
||||
remote_peer_id,
|
||||
remote_record.identity_fingerprint,
|
||||
remote_record.display_name,
|
||||
remote_entry.revision,
|
||||
))
|
||||
assert(service.get_canvas_ids().is_empty())
|
||||
var removed_deadline: int = Time.get_ticks_msec() + WAIT_MSEC
|
||||
while (
|
||||
Time.get_ticks_msec() < removed_deadline
|
||||
and session.is_authenticated_peer(remote_peer_id)
|
||||
):
|
||||
await process_frame
|
||||
assert(not session.is_authenticated_peer(remote_peer_id))
|
||||
print("Surface drawing multiplayer host validation: PASS")
|
||||
session.disconnect_session("")
|
||||
main.queue_free()
|
||||
|
|
@ -210,8 +268,63 @@ func _run_client() -> void:
|
|||
if service.get_canvas_ids().is_empty():
|
||||
break
|
||||
assert(service.get_canvas_ids().is_empty())
|
||||
var data_root := main.get("_data_root") as PlayerDataRoot
|
||||
var stamp_directory: String = data_root.root_path.path_join("artwork")
|
||||
assert(DirAccess.make_dir_recursive_absolute(stamp_directory) == OK)
|
||||
var stamp_path: String = stamp_directory.path_join("multiplayer-stamp.png")
|
||||
var stamp_image := Image.create(16, 16, false, Image.FORMAT_RGBA8)
|
||||
stamp_image.fill(Color.TRANSPARENT)
|
||||
stamp_image.set_pixel(3, 11, SurfaceDrawingPalette.get_color(&"coral"))
|
||||
assert(stamp_image.save_png(stamp_path) == OK)
|
||||
assert(service.select_saved_stamp(stamp_path))
|
||||
var stamp_surface: Dictionary = _surface_below_local_player(main)
|
||||
assert(not stamp_surface.is_empty())
|
||||
assert(service.request_stamp_at_surface(
|
||||
stamp_surface["position"], stamp_surface["normal"], Vector3.RIGHT
|
||||
))
|
||||
var shared_stamp_deadline: int = Time.get_ticks_msec() + WAIT_MSEC
|
||||
while (
|
||||
Time.get_ticks_msec() < shared_stamp_deadline
|
||||
and service.get_canvas_ids().is_empty()
|
||||
):
|
||||
await process_frame
|
||||
assert(service.get_canvas_ids().size() == 1)
|
||||
var stamp_state: Dictionary = service.get_canvas_state(
|
||||
service.get_canvas_ids()[0]
|
||||
)
|
||||
assert(bool(stamp_state.get("stamp", false)))
|
||||
assert(bool(stamp_state["finalized"]))
|
||||
assert(str(stamp_state["cells"][0]["color_id"]) == "coral")
|
||||
assert(
|
||||
session.get_local_identity_fingerprint()
|
||||
in stamp_state.get("participant_fingerprints", [])
|
||||
)
|
||||
var clear_deadline: int = Time.get_ticks_msec() + WAIT_MSEC
|
||||
while (
|
||||
Time.get_ticks_msec() < clear_deadline
|
||||
and not service.get_canvas_ids().is_empty()
|
||||
):
|
||||
await process_frame
|
||||
assert(service.get_canvas_ids().is_empty())
|
||||
assert(service.request_stamp_at_surface(
|
||||
stamp_surface["position"], stamp_surface["normal"], Vector3.RIGHT
|
||||
))
|
||||
var second_stamp_deadline: int = Time.get_ticks_msec() + WAIT_MSEC
|
||||
while (
|
||||
Time.get_ticks_msec() < second_stamp_deadline
|
||||
and service.get_canvas_ids().is_empty()
|
||||
):
|
||||
await process_frame
|
||||
assert(service.get_canvas_ids().size() == 1)
|
||||
var ban_deadline: int = Time.get_ticks_msec() + WAIT_MSEC
|
||||
while (
|
||||
Time.get_ticks_msec() < ban_deadline
|
||||
and session.state != NetworkSession.State.SERVER_LOST
|
||||
):
|
||||
await process_frame
|
||||
assert(session.state == NetworkSession.State.SERVER_LOST)
|
||||
assert(service.get_canvas_ids().is_empty())
|
||||
print("Surface drawing multiplayer client validation: PASS")
|
||||
session.disconnect_session("")
|
||||
main.queue_free()
|
||||
for _frame: int in 4:
|
||||
await process_frame
|
||||
|
|
|
|||
|
|
@ -67,6 +67,16 @@ func _run() -> void:
|
|||
state["cells"][0]["author_fingerprint"]
|
||||
== session.get_local_identity_fingerprint()
|
||||
)
|
||||
var export_path: String = service.export_canvas_png(canvas_id)
|
||||
assert(not export_path.is_empty())
|
||||
var data_root := main.get("_data_root") as PlayerDataRoot
|
||||
assert(export_path.begins_with(data_root.root_path.path_join("artwork")))
|
||||
assert(FileAccess.file_exists(export_path))
|
||||
var exported_image: Image = Image.load_from_file(export_path)
|
||||
assert(exported_image.get_size() == Vector2i(16, 16))
|
||||
assert(exported_image.get_pixel(8, 7).is_equal_approx(
|
||||
SurfaceDrawingPalette.get_color(&"ocean_teal")
|
||||
))
|
||||
assert(service.request_guide_visibility(canvas_id, false))
|
||||
state = service.get_canvas_state(canvas_id)
|
||||
assert(not bool(state["guide_visible"]))
|
||||
|
|
@ -78,6 +88,7 @@ func _run() -> void:
|
|||
assert(service.request_guide_visibility(canvas_id, false, true))
|
||||
assert(bool(service.get_canvas_state(canvas_id)["finalized"]))
|
||||
assert(canvas.is_finalized())
|
||||
assert(not canvas.has_guide_geometry())
|
||||
assert(service.request_canvas_at_surface(
|
||||
hit["position"], hit["normal"], Vector3.RIGHT
|
||||
))
|
||||
|
|
@ -109,6 +120,38 @@ func _run() -> void:
|
|||
assert(player_list.get_session_artwork_counts() == Vector2i(2, 1))
|
||||
assert(player_list.reset_session_artwork())
|
||||
assert(service.get_canvas_ids().is_empty())
|
||||
var stamp_entries: Array[Dictionary] = service.get_saved_stamp_entries()
|
||||
assert(stamp_entries.size() == 1)
|
||||
assert(str(stamp_entries[0]["path"]) == export_path)
|
||||
assert(int(stamp_entries[0]["grid_size"]) == 16)
|
||||
assert(bool(stamp_entries[0]["available"]))
|
||||
service.activate(Vector2(640.0, 360.0))
|
||||
assert(service.select_saved_stamp(export_path))
|
||||
assert(service.is_stamp_mode())
|
||||
assert(service.request_stamp_at_surface(
|
||||
hit["position"], hit["normal"], Vector3.RIGHT
|
||||
))
|
||||
assert(service.get_canvas_ids().size() == 1)
|
||||
var stamp_id: String = service.get_canvas_ids()[0]
|
||||
var stamp_state: Dictionary = service.get_canvas_state(stamp_id)
|
||||
assert(bool(stamp_state["stamp"]))
|
||||
assert(bool(stamp_state["finalized"]))
|
||||
assert(not bool(stamp_state["guide_visible"]))
|
||||
assert((stamp_state["cells"] as Array).size() == 1)
|
||||
assert(int(stamp_state["cells"][0]["x"]) == 8)
|
||||
assert(int(stamp_state["cells"][0]["y"]) == 8)
|
||||
assert(str(stamp_state["cells"][0]["color_id"]) == "ocean_teal")
|
||||
assert(
|
||||
stamp_state.get("participant_fingerprints", [])
|
||||
== [session.get_local_identity_fingerprint()]
|
||||
)
|
||||
var stamp_canvas_nodes: Dictionary = service.get("_canvas_nodes")
|
||||
var stamp_canvas := stamp_canvas_nodes[stamp_id] as SurfaceDrawingCanvas
|
||||
assert(stamp_canvas.is_finalized())
|
||||
assert(not stamp_canvas.has_guide_geometry())
|
||||
service.set_placement_mode(false)
|
||||
assert(not service.is_stamp_mode())
|
||||
assert(service.clear_session_artwork())
|
||||
|
||||
print("Surface drawing runtime validation: PASS")
|
||||
session.disconnect_session("")
|
||||
|
|
|
|||
101
tests/surface_drawing_texture_renderer_validation.gd
Normal file
101
tests/surface_drawing_texture_renderer_validation.gd
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
extends SceneTree
|
||||
|
||||
const CANVAS_COUNT: int = 5
|
||||
const GRID_SIZE: int = 32
|
||||
const FINGERPRINT: String = (
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
)
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
var world := Node3D.new()
|
||||
root.add_child(world)
|
||||
var color_ids: Array[StringName] = SurfaceDrawingPalette.get_color_ids()
|
||||
var cells: Array[Dictionary] = []
|
||||
for y: int in range(GRID_SIZE):
|
||||
for x: int in range(GRID_SIZE):
|
||||
cells.append({
|
||||
"x": x,
|
||||
"y": y,
|
||||
"color_id": str(color_ids[(x + y) % color_ids.size()]),
|
||||
"author_fingerprint": FINGERPRINT,
|
||||
})
|
||||
var canvases: Array[SurfaceDrawingCanvas] = []
|
||||
var persistent_meshes: Array[Mesh] = []
|
||||
var persistent_textures: Array[Texture2D] = []
|
||||
for canvas_index: int in range(CANVAS_COUNT):
|
||||
var canvas := SurfaceDrawingCanvas.new()
|
||||
world.add_child(canvas)
|
||||
assert(canvas.setup({
|
||||
"session_id": "texture-renderer-session",
|
||||
"canvas_id": "canvas-%d" % canvas_index,
|
||||
"origin": [float(canvas_index) * 3.0, 0.0, 0.0],
|
||||
"normal": [0.0, 1.0, 0.0],
|
||||
"tangent": [1.0, 0.0, 0.0],
|
||||
"width": GRID_SIZE,
|
||||
"height": GRID_SIZE,
|
||||
"cell_size": SurfaceDrawingProtocol.CELL_SIZE,
|
||||
"revision": 0,
|
||||
"guide_visible": true,
|
||||
"finalized": false,
|
||||
"layer": canvas_index,
|
||||
"creator_fingerprint": FINGERPRINT,
|
||||
"cells": cells,
|
||||
}, null))
|
||||
assert(canvas.get_rendered_pixel_count() == GRID_SIZE * GRID_SIZE)
|
||||
var pixel_instance := canvas.get("_pixel_instance") as MeshInstance3D
|
||||
assert(pixel_instance != null)
|
||||
assert(pixel_instance.mesh.get_surface_count() == 1)
|
||||
var material := pixel_instance.mesh.surface_get_material(
|
||||
0
|
||||
) as StandardMaterial3D
|
||||
assert(material != null)
|
||||
assert(material.albedo_texture is ImageTexture)
|
||||
canvases.append(canvas)
|
||||
persistent_meshes.append(pixel_instance.mesh)
|
||||
persistent_textures.append(material.albedo_texture)
|
||||
for canvas_index: int in range(CANVAS_COUNT):
|
||||
var canvas: SurfaceDrawingCanvas = canvases[canvas_index]
|
||||
assert(canvas.apply_update({
|
||||
"session_id": "texture-renderer-session",
|
||||
"canvas_id": "canvas-%d" % canvas_index,
|
||||
"revision": 1,
|
||||
"edits": [{
|
||||
"x": canvas_index,
|
||||
"y": canvas_index,
|
||||
"color_id": "coral",
|
||||
"author_fingerprint": FINGERPRINT,
|
||||
}],
|
||||
}))
|
||||
var pixel_instance := canvas.get("_pixel_instance") as MeshInstance3D
|
||||
var material := pixel_instance.mesh.surface_get_material(
|
||||
0
|
||||
) as StandardMaterial3D
|
||||
assert(pixel_instance.mesh == persistent_meshes[canvas_index])
|
||||
assert(material.albedo_texture == persistent_textures[canvas_index])
|
||||
assert(canvas.apply_guide_update({
|
||||
"session_id": "texture-renderer-session",
|
||||
"canvas_id": "canvas-%d" % canvas_index,
|
||||
"revision": 2,
|
||||
"guide_visible": false,
|
||||
"finalized": true,
|
||||
}))
|
||||
assert(not canvas.has_guide_geometry())
|
||||
await process_frame
|
||||
for canvas: SurfaceDrawingCanvas in canvases:
|
||||
var artwork_mesh_count: int = 0
|
||||
for child: Node in canvas.get_children():
|
||||
if child is MultiMeshInstance3D:
|
||||
assert(false, "Art Kit pixels regressed to per-color MultiMeshes.")
|
||||
if child is MeshInstance3D:
|
||||
artwork_mesh_count += 1
|
||||
assert(artwork_mesh_count == 1)
|
||||
assert(canvas.get_export_image().get_size() == Vector2i(32, 32))
|
||||
world.queue_free()
|
||||
await process_frame
|
||||
print("Surface drawing texture renderer validation: PASS")
|
||||
quit()
|
||||
1
tests/surface_drawing_texture_renderer_validation.gd.uid
Normal file
1
tests/surface_drawing_texture_renderer_validation.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://qj7jd2p3b4p8
|
||||
|
|
@ -90,6 +90,21 @@ func _validate_protocol_bounds() -> void:
|
|||
unsupported_size["width"] = 48
|
||||
unsupported_size["height"] = 48
|
||||
assert(not SurfaceDrawingProtocol.validate_canvas_request(unsupported_size))
|
||||
var stamp_pixels := PackedByteArray()
|
||||
stamp_pixels.resize(16 * 16)
|
||||
stamp_pixels[0] = 1
|
||||
var stamp_request: Dictionary = canvas_request.duplicate(true)
|
||||
stamp_request["request_id"] = "stamp-1"
|
||||
stamp_request["pixels"] = stamp_pixels
|
||||
assert(SurfaceDrawingProtocol.validate_stamp_request(stamp_request))
|
||||
var invalid_stamp: Dictionary = stamp_request.duplicate(true)
|
||||
var invalid_pixels: PackedByteArray = invalid_stamp["pixels"]
|
||||
invalid_pixels[0] = SurfaceDrawingPalette.COLORS.size() + 1
|
||||
invalid_stamp["pixels"] = invalid_pixels
|
||||
assert(not SurfaceDrawingProtocol.validate_stamp_request(invalid_stamp))
|
||||
var empty_stamp: Dictionary = stamp_request.duplicate(true)
|
||||
empty_stamp["pixels"] = PackedByteArray()
|
||||
assert(not SurfaceDrawingProtocol.validate_stamp_request(empty_stamp))
|
||||
var guide_request: Dictionary = {
|
||||
"request_id": "guide-1",
|
||||
"session_id": "session",
|
||||
|
|
@ -116,9 +131,11 @@ func _validate_art_unlocks() -> void:
|
|||
assert(unlocks.unlock_product(&"marker_ocean_teal"))
|
||||
assert(unlocks.unlock_product(&"brush_4x"))
|
||||
assert(unlocks.unlock_product(&"grid_128x"))
|
||||
assert(unlocks.unlock_product(PlayerArtUnlocks.STAMP_PRODUCT_ID))
|
||||
assert(unlocks.is_color_unlocked(&"ocean_teal"))
|
||||
assert(unlocks.is_brush_size_unlocked(4))
|
||||
assert(unlocks.is_grid_size_unlocked(128))
|
||||
assert(unlocks.is_stamp_unlocked())
|
||||
assert(not unlocks.restore_mask(PlayerArtUnlocks.ALL_UNLOCK_MASK + 1))
|
||||
unlocks.free()
|
||||
|
||||
|
|
@ -177,6 +194,16 @@ func _validate_canvas_geometry_and_collaboration() -> void:
|
|||
"cells": [],
|
||||
}
|
||||
assert(canvas.setup(state, null))
|
||||
var pixel_instance := canvas.get("_pixel_instance") as MeshInstance3D
|
||||
assert(pixel_instance != null)
|
||||
assert(pixel_instance.name == "ArtworkTexture")
|
||||
var persistent_mesh: Mesh = pixel_instance.mesh
|
||||
var pixel_material := persistent_mesh.surface_get_material(
|
||||
0
|
||||
) as StandardMaterial3D
|
||||
assert(pixel_material != null)
|
||||
var persistent_texture: Texture2D = pixel_material.albedo_texture
|
||||
assert(persistent_texture is ImageTexture)
|
||||
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))
|
||||
|
|
@ -192,6 +219,15 @@ func _validate_canvas_geometry_and_collaboration() -> void:
|
|||
}],
|
||||
}
|
||||
assert(canvas.apply_update(first_update))
|
||||
assert(pixel_instance.mesh == persistent_mesh)
|
||||
assert(pixel_material.albedo_texture == persistent_texture)
|
||||
assert(canvas.get_rendered_pixel_count() == 1)
|
||||
var export_image: Image = canvas.get_export_image()
|
||||
assert(export_image.get_size() == Vector2i(16, 16))
|
||||
assert(export_image.get_pixel(3, 11).is_equal_approx(
|
||||
SurfaceDrawingPalette.get_color(&"coral")
|
||||
))
|
||||
assert(export_image.get_pixel(0, 0).is_equal_approx(Color.TRANSPARENT))
|
||||
var finish_update: Dictionary = {
|
||||
"session_id": "session",
|
||||
"canvas_id": "canvas-1",
|
||||
|
|
@ -202,6 +238,9 @@ func _validate_canvas_geometry_and_collaboration() -> void:
|
|||
assert(canvas.apply_guide_update(finish_update))
|
||||
assert(not canvas.is_guide_visible())
|
||||
assert(canvas.is_finalized())
|
||||
assert(not canvas.has_guide_geometry())
|
||||
assert(pixel_instance.mesh == persistent_mesh)
|
||||
assert(pixel_material.albedo_texture == persistent_texture)
|
||||
await process_frame
|
||||
var finished_pixel_scale: float = canvas.get_rendered_pixel_size()
|
||||
assert(
|
||||
|
|
@ -223,6 +262,8 @@ func _validate_canvas_geometry_and_collaboration() -> void:
|
|||
}],
|
||||
}
|
||||
assert(canvas.apply_update(second_update))
|
||||
assert(pixel_instance.mesh == persistent_mesh)
|
||||
assert(pixel_material.albedo_texture == persistent_texture)
|
||||
var cells: Array[Dictionary] = canvas.get_authoritative_cells()
|
||||
assert(cells.size() == 1)
|
||||
assert(cells[0]["color_id"] == "blue")
|
||||
|
|
@ -240,6 +281,10 @@ func _validate_canvas_geometry_and_collaboration() -> void:
|
|||
}
|
||||
assert(canvas.apply_update(erase_update))
|
||||
assert(canvas.get_authoritative_cells().is_empty())
|
||||
assert(canvas.get_rendered_pixel_count() == 0)
|
||||
assert(canvas.get_export_image().get_pixel(3, 11).is_equal_approx(
|
||||
Color.TRANSPARENT
|
||||
))
|
||||
world.queue_free()
|
||||
await process_frame
|
||||
|
||||
|
|
@ -282,6 +327,7 @@ func _validate_blocked_author_visibility() -> void:
|
|||
"cell_size": SurfaceDrawingProtocol.CELL_SIZE,
|
||||
"revision": 1,
|
||||
"creator_fingerprint": FINGERPRINT_A,
|
||||
"participant_fingerprints": [FINGERPRINT_A, FINGERPRINT_B],
|
||||
"cells": [
|
||||
{
|
||||
"x": 1,
|
||||
|
|
@ -298,20 +344,30 @@ func _validate_blocked_author_visibility() -> void:
|
|||
],
|
||||
}
|
||||
assert(canvas.setup(state, relationships))
|
||||
assert(_rendered_pixel_count(canvas) == 1)
|
||||
assert(canvas.is_hidden_by_relationship())
|
||||
assert(canvas.get_rendered_pixel_count() == 0)
|
||||
relationships.set("_records", {})
|
||||
canvas.refresh_relationship_visibility()
|
||||
await process_frame
|
||||
assert(_rendered_pixel_count(canvas) == 2)
|
||||
assert(not canvas.is_hidden_by_relationship())
|
||||
assert(canvas.get_rendered_pixel_count() == 2)
|
||||
relationships.set("_records", {
|
||||
FINGERPRINT_B: {"blocked": true, "muted": true},
|
||||
})
|
||||
assert(canvas.apply_update({
|
||||
"session_id": "session",
|
||||
"canvas_id": "blocked-author-canvas",
|
||||
"revision": 2,
|
||||
"participant_fingerprints": [FINGERPRINT_A, FINGERPRINT_B],
|
||||
"edits": [{
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
"color_id": "",
|
||||
"author_fingerprint": "",
|
||||
}],
|
||||
}))
|
||||
canvas.refresh_relationship_visibility()
|
||||
assert(canvas.is_hidden_by_relationship())
|
||||
assert(canvas.get_rendered_pixel_count() == 0)
|
||||
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