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

Signal connections from instanced children change positions in .tscn file #35084

Closed
YeldhamDev opened this issue Jan 13, 2020 · 10 comments
Closed

Comments

@YeldhamDev
Copy link
Member

Godot version:
031b545

Issue description:
When saving a scene, the signal connections from instanced scenes will change positions every now and then in the .tscn file.

Very likely related to #30538.

@Keelar
Copy link

Keelar commented Mar 2, 2020

I've been having this same issue and it's been driving me crazy. I don't want a bunch of useless commits titled "Godot randomly changed signal order for no apparent reason"

@Calinou
Copy link
Member

Calinou commented Mar 2, 2020

Could this be fixed by ensuring signal connections are saved in alphabetical order?

@Janglee123
Copy link
Contributor

Signals are sorted according to their parent node index in the scene, and they are sorted again in alphabetical order if they are from the same node.
So I think changing the node index can be a cause for it.

@Keelar
Copy link

Keelar commented Mar 5, 2020

I've now noticed that this issue seems to be triggered after modifying scene files and then discarding the changes. After the changes have been discarded, these reordered signals seems to linger for some reason. Unfortunately this still seems to be somewhat random and isn't easily reproducible, but it seems to trigger it in some situations. The only notable files in my gitignore are the .import/ and export/ directories which I think are supposed to be safe to exclude from version control.

Edit: Here's my full gitignore:

.import/
.mono/
.vscode/
export/
export.cfg
export_presets.cfg

@Keelar
Copy link

Keelar commented Mar 8, 2020

Okay, so I've ran into this again and toyed around with things to try and figure out what seems to trigger it. You can disregard my previous comment. It has nothing to do with discarding changes or really any changes at all.

What seems to happen is every time my scene is read from disk, signals in that scene that emit to at least two separate nodes will be randomly ordered among each other. So if I have SignalA that emits to NodeA and NodeB, within the scene's tscn file, the lines(for that signal) for NodeA and NodeB will swap back and forth with each other at random when it is read from disk. I know it happens when it is read from disk because if I commit these lines being reordered, no matter how many times I resave that scene after committing the changes, those lines will not be reordered until I close the scene or the editor and reopen it.

Since it only happens when it is read from disk, it previously appeared as if it happened when I discarded changes, because I would close the project and discard the changes from git, so when I reopened the project after discarding the changes, the scene would be read from disk and the signals would be randomly reordered.

@akien-mga
Copy link
Member

akien-mga commented Apr 24, 2021

Is this still reproducible in Godot 3.3 or later?

@Keelar
Copy link

Keelar commented Apr 24, 2021

I can confirm that it is still reproducible in my case on 3.3 stable.

@Poobslag
Copy link

Poobslag commented Jul 7, 2021

I can confirm this is still an issue in 3.3 stable. For signals with the same signal name and source node, Godot orders signals signals arbitrarily and the order often changes. Here is an example of a commit where the Godot editor shuffled several signals in this project/src/main/puzzle/Puzzle.tscn scene without any apparent reason.

As a workaround, I've written a shell script which manually sorts the signals in my .tscn files.

#!/bin/bash
while read -r IN_FILE
do
  echo "Sorting signal connections in $IN_FILE..."
  OUT_FILE="$IN_FILE"~

  # calculate the range of lines to sort
  FIRST_LINE=$(awk '/^\[connection signal/{print NR; exit}' "$IN_FILE")
  LINE_COUNT=$(grep -c "^\[connection signal" "$IN_FILE")

  # move the 'signal=' attribute after the 'from=' attribute so that the signal sort order mostly matches Godot
  sed -i "s/^\\(\\[connection\\)\\( signal=\"[^\"]*\"\\)\\( from=\"[^\"]*\"\\)\\(.*\\)/\\1\\3\\2\\4/g" "$IN_FILE"

  # sort the '[connection]' lines
  (head -n $(("$FIRST_LINE" - 1)); head -n "$LINE_COUNT" | sort; cat ) < "$IN_FILE" 1<> "$OUT_FILE"
  mv -f "$OUT_FILE" "$IN_FILE"

  # move the 'signal=' attribute back where it was
  sed -i "s/^\\(\\[connection\\)\\( from=\"[^\"]*\"\\)\\( signal=\"[^\"]*\"\\)\\(.*\\)/\\1\\3\\2\\4/g" "$IN_FILE"
done < <(git diff master --name-only | grep "\.tscn$")

(I'm rubbish at shell scripting, so I'd be receptive to any script improvements or a simpler workaround.)

@KoBeWi
Copy link
Member

KoBeWi commented Sep 8, 2021

I investigated this issue (on master) and tracked it down as far as Callable comparison. The signals are sorted by name, but if the name is the same, they are sorted by target Callable. Then the Callable is sorted by method name and if the name is the same, they are sorted by target ObjectID. The ObjectID will be different every time, so this is most likely the source of randomness.

I assume it's similar in 3.x.

EDIT:
Here's a simple reproduction scene:
ConnectionTest.zip
Just open it, save, reload project and save again and compare results.

EDIT2:
Also forget what I said at first, the issue appears only in 3.x. On master connection order stays the same as long as node order is the same.

EDIT3:
Seems like on 3.x connections are sorted by object pointer. ObjectID is fine.

@KoBeWi KoBeWi added this to the 3.4 milestone Sep 8, 2021
@KoBeWi
Copy link
Member

KoBeWi commented Sep 13, 2021

Fixed by #52493

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants