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

Objectloop optimization #311

Open
fredrikr opened this issue Dec 27, 2024 · 3 comments
Open

Objectloop optimization #311

fredrikr opened this issue Dec 27, 2024 · 3 comments

Comments

@fredrikr
Copy link

Note: I only examined this for Z-code.

Objectloop generally loops over all objects in the game. Any checks that are made in the objectloop are made to all objects.

However, if the source code follows this pattern, it changes this to start with child(y) and move to the next with sibling(y);

objectloop(x in y) ...

Unfortunately, this faster way of iterating over the contents of an object is not used when the code looks like this:

objectloop(x in y && x has scenery) ...

(or, as far as I can tell, any other condition is added)

Is this something that could and should be changed?

Iterating using sibling is faster and visits the objects in a different order than looping over all objects.

@erkyrath
Copy link
Contributor

erkyrath commented Dec 28, 2024

It's difficult to pattern-match for the general case. E.g. objectloop(x has scenery && x in y).

Advent.inf has a line which is even messier:

objectloop (obj ofclass Treasure && obj in player or location)

Also note that using the sibling chain isn't really a safe optimization. E.g. currently this works:

objectloop(x in chest && x has treasure)
  move x to player;

But if it used the object tree, this would break.

Cases like this aren't documented as safe, but it's an area where people probably relied what the compiler did rather than what the manual said.

@heasm66
Copy link
Contributor

heasm66 commented Dec 28, 2024

It's unfortunate that the order of the iteration changes, depending on method used.

Attribute treasure;

Object chest "chest";
Object first "first treasure" with has treasure;
Object second "second treasure" has treasure;
Object third "third treasure" with has treasure;

[Main;
  TestObjLoop();
];

[TestObjLoop x;
  ! Mix up order of obj.next
  move first to chest;
  move second to chest;
  move third to chest;
  
  print "In chest, looping over siblings^";
  objectloop(x in chest)  
    print "  ", (name) x, "^";

  print "^In chest, looping over object tree^";
  objectloop(x in chest && x has treasure)
    print "  ", (name) x, "^";

  print "^In chest, looping over siblings again^";
  objectloop(x in chest)
    if (x has treasure) print "  ", (name) x, "^";
];

Produces this result

In chest, looping over siblings
  third treasure
  second treasure
  first treasure

In chest, looping over object tree
  first treasure
  second treasure
  third treasure

In chest, looping over siblings again
  third treasure
  second treasure
  first treasure

There's no easy fix to this, because games can depend on this behaviour.

@fredrikr
Copy link
Author

I agree that it doesn't make sense to change this behaviour now, as many old games would have weird effects if recompiled.

I thought I had seen in DM4 that if(x in y && ... would use the sibling-method of iteration, but I must have dreamt this up.

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

No branches or pull requests

3 participants