Repository: evennia/evennia

Issue:
[BUG] Prototype wizard loses changes to prototype when updating spawned objects
(Resolved by https://github.com/evennia/evennia/pull/3507.)

#### Describe the bug

When updating existing objects from a template, you are asked twice if you want to save changes to the template -- once when you use `sa` to save and again after you update the objects. If you do not answer "yes" at the second prompt, the changes you made to the template are lost after quitting and re-entering the wizard (*example 1*).

This can also result in changes that have already been saved in a template being reverted to the the spawned object's state (*example 2*). In a scenario where you make changes to a template but don't update spawned objects, and then decide later to update them and *don't* do the second save, the template will be reverted.

#### To Reproduce
In the examples, only the relevant parts of the output are shown to keep things brief.

**Example 1 - make changes to a template and update spawned objects**

```
>4
Current key: test
>test2
Current key: test2
```
```
>sa
Do you want to save/overwrite the existing prototype 'test'?
>y
Prototype saved.
Do you want to update 1 object(s) already using this prototype?
>y
- key:    [1] UPDATE: test -> test2
>u
1 objects were updated successfully.
```
At this point you are asked again if you want to save the prototype, even though the wizard has confirmed the save.
```
Do you want to save/overwrite the existing prototype 'test'?
n
```
From the main index:
```
>4
Current key: test2
```
The key *is* changed in the wizard.

After quitting the wizard, the object is correctly updated:
```
>ex test2
Name/key: test2 (#29)
```
Return to the wizard and load the template. They key has reverted to "test":
```
>4
Current key: test
```
**Example 2 - apply changes from a previously-saved template**

In this example, the prototype has had its key changed and has been saved without updating spawned objects. The wizard was quit and then re-entered:
```
>4
Current key: test2
```
```
>sa
Do you want to save/overwrite the existing prototype 'test'?
>y
Prototype saved.
Do you want to update 1 object(s) already using this prototype?
>y
- key:    [1] UPDATE: test -> test2
>u
1 objects were updated successfully.
```
Next we answer "no" because we haven't made any changes, we just saved it again to update spawned objects:
```
Do you want to save/overwrite the existing prototype 'test'?
n
```
From the main index:
```
>4
Current key: test2
```
Leave the wizard, go back in, load template. The key has reverted to that of the spawned object's *old* key (although the spawned object itself has been updated with the new key):
```
>4
Current key: test
```
#### Expected behavior

The first save prompt should be sufficient to save the template, and answering "no" should not cause existing saved changes to be reverted.

It also seems odd to be asked to be saved again -- in fact you can go round in circles indefinitely if you keep answering "yes". Perhaps it should return to the main index after the update is (or isn't) done.



Discussion:
A bit of an update on this:

I've been poking about trying to fix this and what I've found is that the prototype cache is getting overwritten for the loaded prototype with the state of the spawned object.

I was dumping `protlib.DB_PROTOTYPE_CACHE._cache.values()` at the index (top level menu item) each time and when returning there after the object update I could see that the cached prototype contained values from the object, not from the prototype in the wizard.

I also changed the `back_node` value of the save process to return to the index, avoiding the save question loop.

This explains why the prototype looks correct until you leave the wizard and go back in as it loads the prototype from the cache, which no longer has the same values as the database. If you restart the server and load the prototype in the wizard then you do get the correct values because it's pulled from the database again. The database is always saved correctly with whatever the `prototype` is in the wizard.

I don't know why the cache is being set to the values of the object, but for now I'm using an ugly hack to reset the cached prototype when returning to the index page. While certainly not a fix, this gives me the behaviour I expect.

Resolving patch:
diff --git a/evennia/prototypes/spawner.py b/evennia/prototypes/spawner.py
--- a/evennia/prototypes/spawner.py
+++ b/evennia/prototypes/spawner.py
@@ -323,7 +323,7 @@ def prototype_from_object(obj):
         prot["prototype_locks"] = "spawn:all();edit:all()"
         prot["prototype_tags"] = []
     else:
-        prot = prot[0]
+        prot = prot[0].copy()
 
     prot["key"] = obj.db_key or hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:6]
     prot["typeclass"] = obj.db_typeclass_path


Test patch: