Why does setFlag() seem to work, but when I refresh the data wasn't really changed?

Author: VegetarianOrc

So I’m trying to use flags to store some actor state that I’m manipulating using an ActorSheet. I’m having an issue where after setting a flag in response to a sheet update the sheet and flags initially are in the correct state, but after I refresh the page, the flag is back to it’s original value. Is there some way I can force flags to persist?

Author: vance


try await unsetFlag() then await setFlag()
theres some detailed explanations in #module-development over in the main discord about it if you care, but it gets everyone the first time they try using flags
you can also try duping the obj before sending it to setFlag()

Author: zeel


To elaborate on the issues:

1. The Diff Problem
When you set a flag the game internally calls the update() method of the Entity. This method has a feature designed to prevent unnecessary server requests. It checks whether or not the update data is actually different from the existing data - this is what can lead to some confusion.

In JS, practically ever value is “passed by reference” - this means that if you pass a value to a flag, you typically are passing it a reference to whatever contained that value in the first place. If the object that contained the value happened to be the original Entity, you are passing it a reference… to itself.

When the update() method is called, it checks to see if the new value is different from the old value. But in this case, the old value is a reference to the same thing as the new value. It can’t tell that something changed, because the two references are the same.

Typically the way to ensure that a flag is set correctly requires that you set a new value that isn’t based on the original value, or that is at least based on a copy of the data. Core includes a global function duplicate() to facilitate this.
2. The race condition
A race condition is caused by two or more processes that happen in a simultaneous manor both attempt to modify the same resource at the same time.

This can happen easily when the client communicates with the server. A communication begins, and takes some time to complete. However the browser has no issue with starting more communications at the same time without waiting.

When you send any data to the server, it is important to avoid sending more until the first data has been processed. This can be accomplished by using Promises in JS - either using the Promise API, or more easily, using the async feature, and the await keyword. The basics are that an async function can “pause” its execution to await some process that takes a while to complete. Each setFlag() call is a long-running asynchronous process, so await setFlag() will wait until the flag is set completely before continuing to execute the code.

This prevents the race condition, which can otherwise result in very unexpected behavior.
In both cases, the data ends up being correct on the client side, but the server is never updated to match, so reloading the page causes that change to be lost.
In order to “force the flags to persist” you will need to correct whichever underlying problem has occurred.