I am developing a multiplayer game. When I use an object from inventory, it should update the user creature's stats with the values of the attributes of an object.
This is my code:
try:
obj = self._get_obj_by_id(self.query['ObjectID']).first()
# Get user's current creature
cur_creature = self.user.get_current_creature()
# Applying object attributes to user attributes
for attribute in obj.attributes:
cur_creature.__dict__[str(attribute.Name)] += attribute.Value
dbObjs.session.commit()
except (KeyError, AttributeError) as err:
self.query_failed(err)
Now, this doesn't commit things properly for some reason, so I tried:
cur_creature.Health = 100
logging.warning(cur_creature.Health)
dbObjs.session.commit()
Which works, but is not very convenient (since I would need a big if statement to updated the different stats of the creature)
So I tried:
cur_creature.__dict__['Health'] = 100
logging.warning(cur_creature.Health)
dbObjs.session.commit()
I get 100
in logs, but no changes, so I tried:
cur_creature.__dict__['Health'] = 100
cur_creature.Health = cur_creature.__dict__['Health']
logging.warning(cur_creature.Health)
dbObjs.session.commit()
Still '100' in logs, but no changes, so I tried:
cur_creature.__dict__['Health'] = 100
cur_creature.Health = 100
logging.warning(cur_creature.Health)
dbObjs.session.commit()
Which still writes 100 in the logs, but doesn't commit changes to the database.
Now, this is weird, since it only differ by the working version for the fact that it has this line on top:
cur_creature.__dict__['Health'] = 100
Summary: If I modify an attribute directly, commit works fine. Instead, if I modify an attribute through the class' dictionary, then, no matter how I modify it afterwards, it doesn't commit changes to the db.
Any ideas?
Thanks in advance
UPDATE 1:
Also, this updates Health in the db, but not Hunger:
cur_creature.__dict__['Hunger'] = 0
cur_creature.Health = 100
cur_creature.Hunger = 0
logging.warning(cur_creature.Health)
dbObjs.session.commit()
So just accessing the dictionary is not a problem for attributes in general, but modifying an attribute through the dictionary, prevents the changes to that attributes from being committed.
Update 2:
As a temporary fix, I've overridden the function __set_item__(self)
in the class Creatures
:
def __setitem__(self, key, value):
if key == "Health":
self.Health = value
elif key == "Hunger":
self.Hunger = value
So that the new code for 'use object' is:
try:
obj = self._get_obj_by_id(self.query['ObjectID']).first()
# Get user's current creature
cur_creature = self.user.get_current_creature()
# Applying object attributes to user attributes
for attribute in obj.attributes:
cur_creature[str(attribute.Name)] += attribute.Value
dbObjs.session.commit()
except (KeyError, AttributeError) as err:
self.query_failed(err)
Update 3:
By having a look at the suggestions in the answers, I settled down for this solution:
In Creatures
def __setitem__(self, key, value):
if key in self.__dict__:
setattr(self, key, value)
else:
raise KeyError(key)
In the other method
# Applying object attributes to user attributes
for attribute in obj.attributes:
cur_creature[str(attribute.Name)] += attribute.Value
See Question&Answers more detail:
os