Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom task logic via extending InteractTask #300

Merged
merged 32 commits into from
Feb 26, 2021

Conversation

TheSecondReal0
Copy link
Member

@TheSecondReal0 TheSecondReal0 commented Feb 13, 2021

  • Added a bunch of virtual functions meant to be overridden to interacttask.gd
  • Added functions in both interacttask.gd and the task manager to facilitate syncing task resource scripts (they are basically proxies for rpc and rset)
  • Ported the clockset task connected to the standbutton to use a script extending InteractTask for logic (tasks are still completed via the UI class)
  • Task networking supports RPC modes
  • Task resources now tell the task manager when they are complete

I'll type up some documentation at some point, to see an example of using the InteractTask resource for logic look at the clockset task (resource script is at res://assets/ui/tasks/clockset/clocksetinteracttask.gd)

TODO:

  • Have task resources tell the task manager when they are completed
  • Add some security to task resource rpc and rset, currently any peer can do whatever they want
  • Maybe change task manager to use task IDs instead of task_info dicts, @Damjan94 what is your opinion on this? Necessary to make sure you know which player(s) the call is referring to

NOTES:

  • You must make your InteractTask extending script a tool script, otherwise the custom editor properties won't work

@github-actions
Copy link

HOW TO REVIEW:

  • Test multiplayer (client and host)
  • Check build status
  • Check UI
  • Check the code
  • Check build artifacts

Copy link
Contributor

@nicemicro nicemicro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quite cool!

Comment on lines 147 to 156
func task_rpc(function: String, args: Array):
TaskManager.task_rpc(function, args, task_id)

func task_rpc_id(id: int, function: String, args: Array):
TaskManager.task_rpc_id(id, function, args, task_id)

func receive_task_rpc(function: String, args: Array):
# using callv instead of call because it will translate the array into
# individual arguments
callv(function, args)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couldn't it be done so that task resources can only RPC the server, and can only accept RPCs from the server?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it could be done that way. I set it up like this so each task can fully customize their networking stuff 😃

functions with virtualized counterparts moved to the top, networking functions are below those, then setters/getters, then code for custom editor properties
This was linked to issues Feb 17, 2021
overhauled how task manager handles completing tasks and somewhat how it handles sync
to make sure you can't go through UI to complete a task
@TheSecondReal0 TheSecondReal0 marked this pull request as ready for review February 19, 2021 02:48
Copy link
Contributor

@nicemicro nicemicro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides the questions with respect to the code, the following bugs need to be addressed:

  1. The task list fails to color the completed tasks green.
  2. When the clockset task (standbutton) is completed, the text showing the time next to the standbutton is only changed on the other players' map if they stand on the button.
  3. On the interact button version, the text is only updated if the other player goes there and clicks on the task test button.

I'd suggest that 2. and 3. should be addressed that every time there is an update broadcasted to all clients, the script should update the text.

return get_res().get_current_time()

func get_res() -> Resource:
return TaskManager.get_task_resource(ui_data[TaskManager.TASK_ID_KEY])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am trying to figure out where is the ui_data dictionary gets populated with the correct task ID, but I can't figure it out. Please enlighten me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is updated by uicontroller.gd right before it's opened

Comment on lines +1 to +25
[gd_resource type="Resource" load_steps=4 format=2]

[ext_resource path="res://assets/ui/tasks/clockset/clocksetinteracttask.gd" type="Script" id=1]
[ext_resource path="res://addons/opensusinteraction/resources/interactui/interactui.gd" type="Script" id=2]

[sub_resource type="Resource" id=1]
resource_local_to_scene = true
resource_name = "InteractUI"
script = ExtResource( 2 )
ui_name = "clockset"
ui_data = {

}
action = 0
advanced/reinstance = false
advanced/free_on_close = false

[resource]
resource_local_to_scene = true
script = ExtResource( 1 )
task_text = "clockset task"
ui_resource = SubResource( 1 )
outputs/toggle_map_interactions = true
outputs/output_map_interactions = [ ]
is_task_global = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this file?
I saw that the map features use the interactpointclockset.tres and standbuttonclockeset.tres resources as Interact Resource in their respective points, however those resources are linked to clocksetinteracttask.gd as their script. However, this tres file seems to be referenced nowhere.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was mostly for testing, and so I could make a copy of it to make the resource files used in the test map. Just putting that resource into the map either did really weird stuff (like adding a copy of the script inside test.tres) or I couldn't give them unique task text (despite them both being local to scene).

@TheSecondReal0
Copy link
Member Author

TheSecondReal0 commented Feb 19, 2021

@nicemicro I think bugs 2 and 3 are caused by incorrect syncing of the clockset task, which would explain why it works perfectly if you complete the task on the host. I'll fix the syncing issues, and I'll make sure the task state is actually transitioned as @Damjan94 brought up in the Matrix chat

* Task color is now updated in UI
* Task is now remotely completed more reliably
@TheSecondReal0
Copy link
Member Author

Bugs 2 and 3 were actually caused by attempt_complete_task() being called normally instead of via RPC

nicemicro
nicemicro previously approved these changes Feb 20, 2021
Copy link
Contributor

@Damjan94 Damjan94 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you make any task not global
image
and try to complete it, the game crashes...

Copy link
Contributor

@nicemicro nicemicro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have found the following issues, please take a look.

  1. Non-global tasks have the same final state (clock hands) and the states ("digital" clock) are synced through clients
  2. Attempting to finish a non-global task on a client when the server is ran from the editor, results in an assertion error on the server in taskinfo.gd _on_task_completed() function, line 30
  3. Attempting to finish a non-global task on a client when the client is ran from the editor doesn't cause any issues.
  4. Attempting to finish a non-global task on a client not ran from the editor causes an error on a client that's ran from the editor in interacttask.gd transition() function, line 241 "Invalid get index (on base: Dictionary).
  5. When all clients and the server are ran not from the editor, issues 2, 3 and 4 are not reproduced, however issue 1 causes the behavior that when someone finishes their clockset task, the second person who has the same personal task finishes the task immediately on opening it due to the state syncing.
  6. If two players are attending to the same global task, and one changes the state, closes the window, the second player's display changes which is expected behavior. However, if one of the players is killed while their task window is open, they can still change the task state and when closing the window it gets synced across the network.

@TheSecondReal0
Copy link
Member Author

To respond to your review @nicemicro

  1. This is because I wrote the clockset logic with only global tasks in mind, I'll alter it accordingly
  2. That assertion should be removed, as it will trigger an error when the game is functioning correctly
  3. This seems to just be a note
  4. This might be caused by some weird syncing, I'll take a closer look in the future
  5. This is also because the clockset logic is only written to be a global task, like 1
  6. This should probably fall under another PR, since this deals with death behavior (there should probably be a signal from PlayerManager which the UI system would use to close UIs). There could also be a default check added in sync_task() for whether or not the main player is alive

* Removed default inputs to some functions to ensure compatibility with personal tasks
* Removed assert in taskinfo.gd which would fire incorrectly
* Added a check to make sure tasks aren't completed twice
* Improved personal task implementation of clockset task
@nicemicro nicemicro dismissed their stale review February 23, 2021 12:05

New commits address the previous issues

Copy link
Contributor

@nicemicro nicemicro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found the following issue:

  1. The global clockset task have different different goal times on each clients.
  2. When the first player opens the task window and closes it, the goal time gets set to the goal of the first player to everyone else.
  3. The text next to the stand button shows the same time for everyone, but it only matches with the time on the client that was the last to join the party.
  4. The text next to the stand button is only updated in case of successful completion of the task. Is it possible to update the related map item the same way when the task UI is updated, i.e. every time someone closes the task UI / changes some important parameter, so there could be some indication of the state of a task directly on the map in some cases?

@TheSecondReal0
Copy link
Member Author

  • Addressed issues 1, 2, and I think 3 by adding player data syncing (sync occurs when the server sends task assignments)
  • To address issue 4, I made it so that whenever times are synced on global clockset tasks it will update the map text, and personal tasks will update map text if it's assigned to you

Copy link
Contributor

@nicemicro nicemicro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This! Is! Approved!

@nicemicro nicemicro dismissed Damjan94’s stale review February 25, 2021 23:04

Changes have been already implemented.

@nicemicro nicemicro merged commit 1d343a5 into opensuspect:main Feb 26, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Maintenance tasks Tasks system
3 participants