Fix fish sale rejection handling
This commit is contained in:
parent
c3618fdea2
commit
093b35ba0e
2 changed files with 358 additions and 86 deletions
|
|
@ -92,12 +92,12 @@ func request_local_sale(catch_ids: Array[StringName]) -> String:
|
|||
for catch_id: StringName in catch_ids:
|
||||
if _reservations != null and _reservations.is_fish_reserved(catch_id):
|
||||
local_sale_finished.emit(
|
||||
"", false, "Reserved in a letter.", [], 0
|
||||
"", false, "Reserved in a letter.", _empty_catch_ids(), 0
|
||||
)
|
||||
return ""
|
||||
if is_local_sale_pending():
|
||||
local_sale_finished.emit(
|
||||
"", false, "Selling…", [], 0
|
||||
"", false, "Selling…", _empty_catch_ids(), 0
|
||||
)
|
||||
return ""
|
||||
if not can_request_sale():
|
||||
|
|
@ -105,13 +105,13 @@ func request_local_sale(catch_ids: Array[StringName]) -> String:
|
|||
"",
|
||||
false,
|
||||
"Selling is not supported by this server.",
|
||||
[],
|
||||
_empty_catch_ids(),
|
||||
0
|
||||
)
|
||||
return ""
|
||||
if catch_ids.is_empty() or _inventory == null:
|
||||
local_sale_finished.emit(
|
||||
"", false, "Sale could not be completed.", [], 0
|
||||
"", false, "Sale could not be completed.", _empty_catch_ids(), 0
|
||||
)
|
||||
return ""
|
||||
var evidence: Array[Dictionary] = []
|
||||
|
|
@ -119,7 +119,7 @@ func request_local_sale(catch_ids: Array[StringName]) -> String:
|
|||
var fish_catch: FishCatch = _inventory.get_catch_by_id(catch_id)
|
||||
if fish_catch == null:
|
||||
local_sale_finished.emit(
|
||||
"", false, "That catch is no longer available.", [], 0
|
||||
"", false, "That catch is no longer available.", _empty_catch_ids(), 0
|
||||
)
|
||||
return ""
|
||||
evidence.append(fish_catch.to_network_dict())
|
||||
|
|
@ -405,7 +405,9 @@ func _apply_sale_result(data: Dictionary) -> void:
|
|||
|
||||
|
||||
func _fail_local_apply(data: Dictionary, message: String) -> void:
|
||||
_finish_local_sale(data["request_id"], false, message, [], 0)
|
||||
_finish_local_sale(
|
||||
data["request_id"], false, message, _empty_catch_ids(), 0
|
||||
)
|
||||
_acknowledge_result(data, false, message)
|
||||
|
||||
|
||||
|
|
@ -539,10 +541,14 @@ func _on_session_state_changed(state: NetworkSession.State) -> void:
|
|||
_clear_session_state()
|
||||
if had_pending:
|
||||
local_sale_finished.emit(
|
||||
"", false, "Connection lost.", [], 0
|
||||
"", false, "Connection lost.", _empty_catch_ids(), 0
|
||||
)
|
||||
|
||||
|
||||
func _empty_catch_ids() -> Array[StringName]:
|
||||
return []
|
||||
|
||||
|
||||
func _clear_session_state() -> void:
|
||||
_request_ledgers.clear()
|
||||
_pending_by_peer.clear()
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ extends SceneTree
|
|||
const MainScene = preload("res://main/main.tscn")
|
||||
const FishCatchType = preload("res://fish/fish_catch.gd")
|
||||
|
||||
var _finished: Array[Variant] = []
|
||||
var _sale_result: Array[Variant] = []
|
||||
var _shop_result: Array[Variant] = []
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
|
|
@ -11,15 +12,22 @@ func _initialize() -> void:
|
|||
|
||||
|
||||
func _run() -> void:
|
||||
var arguments: PackedStringArray = OS.get_cmdline_user_args()
|
||||
if arguments.has("host"):
|
||||
await _run_multiplayer_host()
|
||||
return
|
||||
if arguments.has("client"):
|
||||
await _run_multiplayer_client()
|
||||
return
|
||||
root.size = Vector2i(1280, 720)
|
||||
var main := MainScene.instantiate()
|
||||
root.add_child(main)
|
||||
for _frame: int in 4:
|
||||
await process_frame
|
||||
if not bool(main.get("_application_initialized")):
|
||||
var data_root := main.get_node("%PlayerDataRoot") as PlayerDataRoot
|
||||
assert(data_root.select_new_root("", true))
|
||||
main.call("_configure_portable_stores")
|
||||
main.call("_initialize_after_data_root")
|
||||
# Use the same activation path as the real setup dialog so no modal is
|
||||
# left above the gameplay SubViewport during pointer validation.
|
||||
main.call("_activate_selected_data_path", "", true)
|
||||
for _frame: int in 8:
|
||||
await process_frame
|
||||
assert(bool(main.get("_application_initialized")))
|
||||
|
|
@ -33,89 +41,346 @@ func _run() -> void:
|
|||
var player := main.get("_player") as Player
|
||||
var catalog := main.get("fish_catalog") as FishPool
|
||||
var sale_service := main.get_node("%NetworkSaleService") as NetworkSaleService
|
||||
var shop_service := main.get_node("%NetworkShopService") as NetworkShopService
|
||||
var session := main.get_node("%NetworkSession") as NetworkSession
|
||||
var reservations := (
|
||||
main.get_node("%PlayerAssetReservationService")
|
||||
as PlayerAssetReservationService
|
||||
)
|
||||
var pelican := (
|
||||
main.get("_test_world") as TestWorld
|
||||
).get_pelican_convenience_landmark()
|
||||
assert(player != null)
|
||||
assert(catalog != null)
|
||||
assert(catalog != null and catalog.candidates.size() == 8)
|
||||
assert(sale_service != null)
|
||||
assert(shop_service != null)
|
||||
assert(session != null and session.is_host())
|
||||
assert(reservations != null)
|
||||
assert(pelican != null)
|
||||
sale_service.local_sale_finished.connect(_on_sale_finished)
|
||||
shop_service.local_purchase_finished.connect(_on_shop_finished)
|
||||
player.global_position = pelican.global_position
|
||||
await process_frame
|
||||
|
||||
var initial_balance: int = player.wallet.get_balance()
|
||||
var fish_catch: FishCatch = _make_catch(catalog.candidates.front())
|
||||
player.inventory.add_catch(fish_catch)
|
||||
assert(player.inventory.contains_catch_id(fish_catch.catch_id))
|
||||
_test_each_species(player, catalog, sale_service)
|
||||
_test_multi_sale(player, catalog, sale_service)
|
||||
_test_reservations(player, catalog, sale_service, reservations)
|
||||
_test_rejection_cleanup(player, catalog, sale_service, pelican)
|
||||
await _test_player_menu_sale(main, player, catalog, sale_service, pelican)
|
||||
|
||||
assert(session.set_host_open(true))
|
||||
assert(session.state == NetworkSession.State.OPEN_HOST)
|
||||
var open_catch := _make_catch(catalog.candidates.front())
|
||||
player.inventory.add_catch(open_catch)
|
||||
_assert_sale(player, sale_service, [open_catch.catch_id], true)
|
||||
assert(session.set_host_open(false))
|
||||
|
||||
await _test_host_shop_purchase(main, player, shop_service)
|
||||
assert(not sale_service.is_local_sale_pending())
|
||||
assert(not shop_service.is_local_purchase_pending())
|
||||
|
||||
print("Economy regression validation: PASS")
|
||||
session.disconnect_session("Economy validation complete.")
|
||||
main.queue_free()
|
||||
await process_frame
|
||||
quit()
|
||||
|
||||
|
||||
func _run_multiplayer_host() -> void:
|
||||
root.size = Vector2i(1280, 720)
|
||||
var main: Node = await _create_initialized_main()
|
||||
assert(bool(main.call("_prepare_private_host")))
|
||||
var save_manager := main.get("_save_manager") as PlayerSaveManager
|
||||
assert(save_manager.initialize_new_game())
|
||||
main.call("_enter_gameplay")
|
||||
var session := main.get_node("%NetworkSession") as NetworkSession
|
||||
assert(session.set_host_open(true))
|
||||
var client_connected := false
|
||||
var connection_deadline: int = Time.get_ticks_msec() + 30000
|
||||
while Time.get_ticks_msec() < connection_deadline:
|
||||
await process_frame
|
||||
if session.get_authenticated_peer_ids().size() >= 2:
|
||||
client_connected = true
|
||||
break
|
||||
assert(client_connected)
|
||||
var remote_peer_id := 0
|
||||
for authenticated_peer_id: int in session.get_authenticated_peer_ids():
|
||||
if authenticated_peer_id != 1:
|
||||
remote_peer_id = authenticated_peer_id
|
||||
break
|
||||
assert(remote_peer_id > 1)
|
||||
var spawn_service := main.get("_player_spawn_service") as PlayerSpawnService
|
||||
var remote_avatar := spawn_service.get_avatar(remote_peer_id)
|
||||
var pelican := (
|
||||
main.get("_test_world") as TestWorld
|
||||
).get_pelican_convenience_landmark()
|
||||
assert(remote_avatar != null and pelican != null)
|
||||
# The client cannot teleport its authoritative avatar. Place the host-owned
|
||||
# test avatar at each interaction so this fixture validates the remote
|
||||
# transaction path without conflating it with the movement suite.
|
||||
remote_avatar.global_position = pelican.global_position
|
||||
await create_timer(5.0).timeout
|
||||
var interaction := main.get("_shop_interaction") as FishingShopInteraction
|
||||
assert(interaction != null)
|
||||
remote_avatar.global_position = interaction.global_position
|
||||
var completion_deadline: int = Time.get_ticks_msec() + 30000
|
||||
while Time.get_ticks_msec() < completion_deadline:
|
||||
await process_frame
|
||||
if session.get_authenticated_peer_ids().size() < 2:
|
||||
break
|
||||
print("Economy multiplayer host validation: PASS")
|
||||
session.disconnect_session("Economy host validation complete.")
|
||||
main.queue_free()
|
||||
await process_frame
|
||||
quit()
|
||||
|
||||
|
||||
func _run_multiplayer_client() -> void:
|
||||
root.size = Vector2i(1280, 720)
|
||||
var main: Node = await _create_initialized_main()
|
||||
main.call("_on_title_join_game_requested", "127.0.0.1:7777")
|
||||
var session := main.get_node("%NetworkSession") as NetworkSession
|
||||
var joined := false
|
||||
var join_deadline: int = Time.get_ticks_msec() + 30000
|
||||
while Time.get_ticks_msec() < join_deadline:
|
||||
await process_frame
|
||||
if session.state == NetworkSession.State.VERIFYING_SERVER_IDENTITY:
|
||||
main.call("_confirm_server_trust")
|
||||
if session.is_joined_client() and bool(main.get("_gameplay_started")):
|
||||
joined = true
|
||||
break
|
||||
assert(joined)
|
||||
var player := main.get("_player") as Player
|
||||
var catalog := main.get("fish_catalog") as FishPool
|
||||
var sale_service := main.get_node("%NetworkSaleService") as NetworkSaleService
|
||||
var shop_service := main.get_node("%NetworkShopService") as NetworkShopService
|
||||
sale_service.local_sale_finished.connect(_on_sale_finished)
|
||||
var request_id: String = sale_service.request_local_sale(
|
||||
[fish_catch.catch_id]
|
||||
)
|
||||
assert(not request_id.is_empty())
|
||||
assert(not _finished.is_empty())
|
||||
assert(bool(_finished[1]))
|
||||
assert(not player.inventory.contains_catch_id(fish_catch.catch_id))
|
||||
assert(player.wallet.get_balance() > initial_balance)
|
||||
shop_service.local_purchase_finished.connect(_on_shop_finished)
|
||||
var pelican := (
|
||||
main.get("_test_world") as TestWorld
|
||||
).get_pelican_convenience_landmark()
|
||||
player.global_position = pelican.global_position
|
||||
var catch_ids: Array[StringName] = []
|
||||
for fish: FishData in catalog.candidates:
|
||||
var fish_catch := _make_catch(fish)
|
||||
player.inventory.add_catch(fish_catch)
|
||||
catch_ids.append(fish_catch.catch_id)
|
||||
await create_timer(1.0).timeout
|
||||
_sale_result.clear()
|
||||
assert(not sale_service.request_local_sale(catch_ids).is_empty())
|
||||
var sale_deadline: int = Time.get_ticks_msec() + 10000
|
||||
while Time.get_ticks_msec() < sale_deadline:
|
||||
await process_frame
|
||||
if not _sale_result.is_empty():
|
||||
break
|
||||
print("Client sale result: ", _sale_result)
|
||||
assert(not _sale_result.is_empty() and bool(_sale_result[1]))
|
||||
for catch_id: StringName in catch_ids:
|
||||
assert(not player.inventory.contains_catch_id(catch_id))
|
||||
assert(not sale_service.is_local_sale_pending())
|
||||
|
||||
var ui_catch: FishCatch = _make_catch(catalog.candidates.front())
|
||||
player.inventory.add_catch(ui_catch)
|
||||
var interaction := main.get("_shop_interaction") as FishingShopInteraction
|
||||
player.global_position = interaction.global_position
|
||||
await create_timer(5.5).timeout
|
||||
assert(player.wallet.credit(100))
|
||||
_shop_result.clear()
|
||||
assert(not shop_service.request_supply(&"coffee").is_empty())
|
||||
var shop_deadline: int = Time.get_ticks_msec() + 10000
|
||||
while Time.get_ticks_msec() < shop_deadline:
|
||||
await process_frame
|
||||
if not _shop_result.is_empty():
|
||||
break
|
||||
print("Client shop result: ", _shop_result)
|
||||
assert(not _shop_result.is_empty() and bool(_shop_result[1]))
|
||||
assert(not shop_service.is_local_purchase_pending())
|
||||
print("Economy multiplayer client validation: PASS")
|
||||
session.disconnect_session("Economy client validation complete.")
|
||||
main.queue_free()
|
||||
await process_frame
|
||||
quit()
|
||||
|
||||
|
||||
func _create_initialized_main() -> Node:
|
||||
var main := MainScene.instantiate()
|
||||
root.add_child(main)
|
||||
for _frame: int in 4:
|
||||
await process_frame
|
||||
if not bool(main.get("_application_initialized")):
|
||||
main.call("_activate_selected_data_path", "", true)
|
||||
for _frame: int in 8:
|
||||
await process_frame
|
||||
assert(bool(main.get("_application_initialized")))
|
||||
return main
|
||||
|
||||
|
||||
func _test_each_species(
|
||||
player: Player,
|
||||
catalog: FishPool,
|
||||
sale_service: NetworkSaleService,
|
||||
) -> void:
|
||||
for fish: FishData in catalog.candidates:
|
||||
assert(fish != null)
|
||||
var fish_catch := _make_catch(fish)
|
||||
player.inventory.add_catch(fish_catch)
|
||||
_assert_sale(player, sale_service, [fish_catch.catch_id], true)
|
||||
|
||||
|
||||
func _test_multi_sale(
|
||||
player: Player,
|
||||
catalog: FishPool,
|
||||
sale_service: NetworkSaleService,
|
||||
) -> void:
|
||||
var catches: Array[FishCatch] = [
|
||||
_make_catch(catalog.candidates[0]),
|
||||
_make_catch(catalog.candidates[1]),
|
||||
_make_catch(catalog.candidates[2]),
|
||||
]
|
||||
var catch_ids: Array[StringName] = []
|
||||
for fish_catch: FishCatch in catches:
|
||||
player.inventory.add_catch(fish_catch)
|
||||
catch_ids.append(fish_catch.catch_id)
|
||||
_assert_sale(player, sale_service, catch_ids, true)
|
||||
|
||||
|
||||
func _test_reservations(
|
||||
player: Player,
|
||||
catalog: FishPool,
|
||||
sale_service: NetworkSaleService,
|
||||
reservations: PlayerAssetReservationService,
|
||||
) -> void:
|
||||
var reserved := _make_catch(catalog.candidates[3])
|
||||
var unreserved := _make_catch(catalog.candidates[4])
|
||||
player.inventory.add_catch(reserved)
|
||||
player.inventory.add_catch(unreserved)
|
||||
var reservation_id := "economy-test-reservation"
|
||||
assert(reservations.reserve(reservation_id, {
|
||||
"type": PlayerAssetReservationService.AttachmentType.FISH,
|
||||
"catch_id": str(reserved.catch_id),
|
||||
"catch": reserved.to_network_dict(),
|
||||
}))
|
||||
_assert_sale(player, sale_service, [reserved.catch_id], false, false)
|
||||
_assert_sale(
|
||||
player,
|
||||
sale_service,
|
||||
[reserved.catch_id, unreserved.catch_id],
|
||||
false,
|
||||
false,
|
||||
)
|
||||
assert(player.inventory.contains_catch_id(reserved.catch_id))
|
||||
assert(player.inventory.contains_catch_id(unreserved.catch_id))
|
||||
assert(reservations.release(reservation_id))
|
||||
_assert_sale(
|
||||
player,
|
||||
sale_service,
|
||||
[reserved.catch_id, unreserved.catch_id],
|
||||
true,
|
||||
)
|
||||
|
||||
|
||||
func _test_rejection_cleanup(
|
||||
player: Player,
|
||||
catalog: FishPool,
|
||||
sale_service: NetworkSaleService,
|
||||
pelican: Node3D,
|
||||
) -> void:
|
||||
var fish_catch := _make_catch(catalog.candidates[5])
|
||||
player.inventory.add_catch(fish_catch)
|
||||
player.global_position = pelican.global_position + Vector3(20.0, 0.0, 0.0)
|
||||
_assert_sale(player, sale_service, [fish_catch.catch_id], false)
|
||||
assert(player.inventory.contains_catch_id(fish_catch.catch_id))
|
||||
assert(not sale_service.is_local_sale_pending())
|
||||
player.global_position = pelican.global_position
|
||||
_assert_sale(player, sale_service, [fish_catch.catch_id], true)
|
||||
|
||||
|
||||
func _test_player_menu_sale(
|
||||
main: Node,
|
||||
player: Player,
|
||||
catalog: FishPool,
|
||||
sale_service: NetworkSaleService,
|
||||
pelican: Node3D,
|
||||
) -> void:
|
||||
player.global_position = pelican.global_position
|
||||
var game_ui := main.get_node("%GameUI") as GameUI
|
||||
var player_menu := game_ui.get_node("%PlayerMenu") as PlayerMenu
|
||||
var fish_catch := _make_catch(catalog.candidates[6])
|
||||
player.inventory.add_catch(fish_catch)
|
||||
player_menu.open_menu()
|
||||
await create_timer(2.2).timeout
|
||||
player_menu.call("_on_catch_card_pressed", ui_catch.catch_id)
|
||||
player_menu.call("_on_catch_card_pressed", fish_catch.catch_id)
|
||||
await process_frame
|
||||
var sell_action := player_menu.get_node("%SellBubble") as Button
|
||||
var confirmation := player_menu.get_node("%SaleConfirmation") as Control
|
||||
var confirm_button := player_menu.get_node("%ConfirmSaleButton") as Button
|
||||
assert(sell_action.visible and not sell_action.disabled)
|
||||
var ui_root := sell_action.get_viewport().get_node("GameUI/UIRoot") as Control
|
||||
var sell_screen_center: Vector2 = (
|
||||
ui_root.position
|
||||
+ sell_action.get_global_rect().get_center() * ui_root.scale
|
||||
)
|
||||
Input.warp_mouse(sell_screen_center)
|
||||
assert(sell_action.mouse_filter == Control.MOUSE_FILTER_STOP)
|
||||
assert(sell_action.focus_mode == Control.FOCUS_ALL)
|
||||
sell_action.pressed.emit()
|
||||
await process_frame
|
||||
print(
|
||||
"Sale rect/mouse/filter/tree: ",
|
||||
sell_action.get_global_rect(),
|
||||
" screen center: ",
|
||||
sell_screen_center,
|
||||
" / ",
|
||||
sell_action.get_viewport().get_mouse_position(),
|
||||
" / ",
|
||||
sell_action.mouse_filter,
|
||||
" / ",
|
||||
sell_action.is_visible_in_tree(),
|
||||
" hovered: ",
|
||||
sell_action.get_viewport().gui_get_hovered_control().get_path()
|
||||
if sell_action.get_viewport().gui_get_hovered_control() != null
|
||||
else "none",
|
||||
)
|
||||
_click_control(sell_action, sell_screen_center)
|
||||
for _frame: int in 3:
|
||||
await process_frame
|
||||
assert(confirmation.visible)
|
||||
assert(confirm_button.visible and not confirm_button.disabled)
|
||||
_finished.clear()
|
||||
var confirm_screen_center: Vector2 = (
|
||||
ui_root.position
|
||||
+ confirm_button.get_global_rect().get_center() * ui_root.scale
|
||||
)
|
||||
Input.warp_mouse(confirm_screen_center)
|
||||
_sale_result.clear()
|
||||
confirm_button.pressed.emit()
|
||||
await process_frame
|
||||
_click_control(confirm_button, confirm_screen_center)
|
||||
for _frame: int in 3:
|
||||
await process_frame
|
||||
assert(not _finished.is_empty() and bool(_finished[1]))
|
||||
assert(not player.inventory.contains_catch_id(ui_catch.catch_id))
|
||||
assert(not _sale_result.is_empty() and bool(_sale_result[1]))
|
||||
assert(not player.inventory.contains_catch_id(fish_catch.catch_id))
|
||||
assert(not sale_service.is_local_sale_pending())
|
||||
player_menu.close_menu()
|
||||
await create_timer(2.2).timeout
|
||||
assert(not player_menu.visible)
|
||||
player_menu.open_menu()
|
||||
await create_timer(2.2).timeout
|
||||
assert(player_menu.visible)
|
||||
assert(
|
||||
not sell_action.disabled
|
||||
or player.inventory.get_all_catches().is_empty()
|
||||
)
|
||||
player_menu.close_menu()
|
||||
await create_timer(2.2).timeout
|
||||
|
||||
print("Economy regression validation: PASS")
|
||||
main.queue_free()
|
||||
await process_frame
|
||||
quit()
|
||||
|
||||
func _test_host_shop_purchase(
|
||||
main: Node,
|
||||
player: Player,
|
||||
shop_service: NetworkShopService,
|
||||
) -> void:
|
||||
var interaction := main.get("_shop_interaction") as FishingShopInteraction
|
||||
assert(interaction != null)
|
||||
player.global_position = interaction.global_position
|
||||
for _frame: int in 4:
|
||||
await physics_frame
|
||||
assert(interaction.is_avatar_in_range(player))
|
||||
var quantity_before: int = player.bag.get_quantity(&"coffee")
|
||||
_shop_result.clear()
|
||||
var request_id: String = shop_service.request_supply(&"coffee")
|
||||
assert(not request_id.is_empty())
|
||||
assert(not _shop_result.is_empty() and bool(_shop_result[1]))
|
||||
assert(player.bag.get_quantity(&"coffee") == quantity_before + 1)
|
||||
assert(not shop_service.is_local_purchase_pending())
|
||||
|
||||
|
||||
func _assert_sale(
|
||||
player: Player,
|
||||
sale_service: NetworkSaleService,
|
||||
catch_ids: Array[StringName],
|
||||
expected_success: bool,
|
||||
expect_request_id: bool = true,
|
||||
) -> void:
|
||||
var balance_before: int = player.wallet.get_balance()
|
||||
_sale_result.clear()
|
||||
var request_id: String = sale_service.request_local_sale(catch_ids)
|
||||
assert((not request_id.is_empty()) == expect_request_id)
|
||||
assert(not _sale_result.is_empty())
|
||||
assert(bool(_sale_result[1]) == expected_success)
|
||||
assert(not sale_service.is_local_sale_pending())
|
||||
if expected_success:
|
||||
assert(player.wallet.get_balance() > balance_before)
|
||||
for catch_id: StringName in catch_ids:
|
||||
assert(not player.inventory.contains_catch_id(catch_id))
|
||||
else:
|
||||
assert(player.wallet.get_balance() == balance_before)
|
||||
for catch_id: StringName in catch_ids:
|
||||
assert(player.inventory.contains_catch_id(catch_id))
|
||||
|
||||
|
||||
func _make_catch(fish: FishData) -> FishCatch:
|
||||
|
|
@ -140,23 +405,24 @@ func _on_sale_finished(
|
|||
catch_ids: Array[StringName],
|
||||
payout: int,
|
||||
) -> void:
|
||||
_finished = [request_id, accepted, message, catch_ids, payout]
|
||||
_sale_result = [request_id, accepted, message, catch_ids, payout]
|
||||
|
||||
|
||||
func _click_control(control: Control, center: Vector2) -> void:
|
||||
var motion := InputEventMouseMotion.new()
|
||||
motion.position = center
|
||||
motion.global_position = center
|
||||
control.get_viewport().push_input(motion)
|
||||
var pressed := InputEventMouseButton.new()
|
||||
pressed.button_index = MOUSE_BUTTON_LEFT
|
||||
pressed.pressed = true
|
||||
pressed.position = center
|
||||
pressed.global_position = center
|
||||
control.get_viewport().push_input(pressed)
|
||||
var released := InputEventMouseButton.new()
|
||||
released.button_index = MOUSE_BUTTON_LEFT
|
||||
released.pressed = false
|
||||
released.position = center
|
||||
released.global_position = center
|
||||
control.get_viewport().push_input(released)
|
||||
func _on_shop_finished(
|
||||
request_id: String,
|
||||
accepted: bool,
|
||||
message: String,
|
||||
product_id: StringName,
|
||||
category: int,
|
||||
quantity: int,
|
||||
total_cost: int,
|
||||
) -> void:
|
||||
_shop_result = [
|
||||
request_id,
|
||||
accepted,
|
||||
message,
|
||||
product_id,
|
||||
category,
|
||||
quantity,
|
||||
total_cost,
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue