puppyStateUpdate.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. import json
  2. import math
  3. import random
  4. import time
  5. from django.utils import timezone
  6. from django.core import serializers
  7. from django.http import JsonResponse
  8. from datetime import datetime, timedelta
  9. from django.db.models import F
  10. import os
  11. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "aiDogProject.settings")
  12. import django
  13. django.setup()
  14. from aiDogApp.models import *
  15. # 获取时间差(直接返回秒数)
  16. def get_time_difference(last_time, current_time):
  17. return (current_time - last_time).total_seconds()
  18. # 获取相差天数
  19. def get_days_difference(last_time, current_time):
  20. # time_lasttime字段是datetime类型,可以直接操作datetime对象,无需再strptime转换。
  21. return (current_time.date() - last_time.date()).days
  22. # 更新狗狗状态
  23. # 2024-12-05 author:Feng
  24. # 每隔1小时:狗的饥饿-5(饥饿每减少5时体力增加5),快乐-1,体力+5,口渴-1,干净-1;
  25. # 每隔一天:体力-10(当饥饿,口渴数值低于20后,体力每天减少10),健康-10(当体力低于10后健康每天减少10,当体力大于50时,健康每天增加5),当健康低于10后跑步速度-2,当健康低于10后跳跃高度-2,
  26. # 当健康低于10后活泼-2,当健康低于10后敏捷-2,当健康低于10后肥胖程度-5,和主人亲密度-2,和主人友善度-2,对主人服从性-2,对主人友好程度-1,对陌生人友好程度-1,叼飞盘熟练度-1,玩球熟练度-1,识别自己名字-2,识别坐口令-2,
  27. # 识别躺下口令-2,识别转圈口令-2;
  28. def update_dog_state(uid, d_id, time_now):
  29. try:
  30. dog_status = DogStatus.objects.get(d_id=d_id)
  31. dog_body_attrs = DogBodyAttributes.objects.get(d_id=d_id)
  32. dog_relationship_personality = DogPersonalityRelationship.objects.get(d_id=d_id)
  33. dog_training = DogTraining.objects.get(d_id=d_id)
  34. user = User.objects.get(uid=uid)
  35. except (DogStatus.DoesNotExist, DogBodyAttributes.DoesNotExist, DogPersonalityRelationship.DoesNotExist):
  36. return {"status": "error", "message": f"No dog found with d_id={d_id}"}
  37. except User.DoesNotExist:
  38. return {"status": "error", "message": f"No user found with uid={uid}"}
  39. # 获取时间差
  40. time_difference = get_time_difference(dog_status.time_lasttime, time_now)
  41. days=get_days_difference(dog_status.time_lasttime, time_now)
  42. # 向上求余取整:2.5取值为3
  43. hours = math.ceil(time_difference/3600)
  44. # 更新状态属性
  45. updates = []
  46. # 更新金币逻辑
  47. # 在 Django 中,如果 user.coin 是通过查询出来的对象进行修改并保存,应该使用 F 对象来避免竞态条件。
  48. # 但如果该字段被缓存,应该避免此时直接操作缓存的数据。需要确保 user.save() 之前,user.coin 是最新的。
  49. if days >= 1:
  50. added_coin = min(days * 100, 1000000 - user.coin)
  51. user.coin = F("coin") + added_coin # 可以使用数据库层面的更新方式避免并发问题
  52. user.save(update_fields=["coin"]) # 只更新 coin 字段
  53. if hours < 1:
  54. return
  55. # 更新状态属性
  56. for _ in range(int(hours)):
  57. # 每隔1小时:狗的饱腹度(饥饿)-5(饱腹度每减少5时体力增加5),快乐-1,体力+5,口渴-1,干净-1;
  58. dog_status.satiety = max(1, dog_status.satiety - 5)
  59. dog_status.thirsty = max(1, dog_status.thirsty - 1)
  60. dog_status.clean = max(1, dog_status.clean - 1)
  61. dog_status.happiness = max(1, dog_status.happiness - 1)
  62. if dog_status.satiety>=20 or dog_status.thirsty >=20:
  63. # 饱腹度(饥饿),口渴大于20时,体力每小时+5
  64. dog_status.stamina = min(100, dog_status.stamina + 5)
  65. updates.append(dog_status)
  66. if days >= 1:
  67. # 如果距离上次请求超过一天
  68. # 每隔一天就重置呼唤次数为0
  69. dog_training.numbers_of_calls=0
  70. for _ in range(int(days)):
  71. if dog_status.satiety <20 or dog_status.thirsty <20:
  72. # 每隔一天:
  73. # 饱腹度(饥饿),口渴低于20后,体力变成每日减少10
  74. dog_status.stamina = max(1, dog_status.stamina - 10)
  75. if dog_status.stamina < 50:
  76. # 初始值50,体力低于50后,每天减少10
  77. dog_status.healthy = max(1, dog_status.healthy - 10)
  78. else:
  79. # 体力正常是每天 + 5
  80. dog_status.healthy = min(100, dog_status.healthy + 5)
  81. if dog_status.healthy < 10:
  82. # 当健康低于10后
  83. # 更新身体属性:跑步速度-2,跳跃高度-2,活泼-2,敏捷-2,肥胖程度-5,
  84. dog_body_attrs.runSpeed = max(1, dog_body_attrs.runSpeed - days*2)
  85. dog_body_attrs.JumpHeight = max(1, dog_body_attrs.JumpHeight - days*2)
  86. dog_body_attrs.liveliness = max(1, dog_body_attrs.liveliness - days*2)
  87. dog_body_attrs.agility = max(1, dog_body_attrs.agility - days*2)
  88. dog_body_attrs.obesity = max(1, dog_body_attrs.obesity - days*5)
  89. # 每天更新与主人的关系:和主人亲密度-2,和主人友善度-2,对主人服从性-2,
  90. dog_relationship_personality.intimate = max(1, dog_relationship_personality.intimate - days*2)
  91. dog_relationship_personality.friendly = max(1, dog_relationship_personality.friendly - days*2)
  92. dog_relationship_personality.obedience = max(1, dog_relationship_personality.obedience - days*2)
  93. # 每天更新性格属性 :对主人友好程度-1,对陌生人友好程度-1,
  94. dog_relationship_personality.friendlyToHost = max(1, dog_relationship_personality.friendlyToHost - days*2)
  95. dog_relationship_personality.friendlyToStranger = max(1, dog_relationship_personality.friendlyToStranger - days*1)
  96. # 每天更新:叼飞盘熟练度-1,玩球熟练度-1,识别自己名字-2,识别坐口令-2,识别躺下口令-2,识别转圈口令-2
  97. dog_training.frisbeeSkill = min(100, dog_training.frisbeeSkill - days*1)
  98. dog_training.ballSkill = min(100, dog_training.ballSkill - days*1)
  99. dog_training.commandName = min(100, dog_training.commandName - days*1)
  100. dog_training.commandSit = min(100, dog_training.commandSit - days*1)
  101. dog_training.commandLieDown = min(100, dog_training.commandLieDown - days*2)
  102. dog_training.commandRotate = min(100, dog_training.commandRotate -days*2)
  103. dog_body_attrs.save()
  104. dog_relationship_personality.save()
  105. dog_training.time_lasttime = time_now
  106. dog_training.save()
  107. # 更新最后操作时间
  108. # 批量保存
  109. dog_status.time_lasttime = time_now
  110. # 数据库更新:使用批量更新(bulk_update)可以显著提升性能,避免多次数据库写操作。
  111. # 有效地减少 I/O 操作(如使用批量更新),避免重复调用 save()
  112. DogStatus.objects.bulk_update(updates, ['satiety', 'thirsty', 'clean', 'happiness', 'stamina'])
  113. dog_status.save()
  114. # 使用 Django 的 serializers 序列化模型对象
  115. dog_status_serialized = serializers.serialize('json', [dog_status])
  116. dog_body_attrs_serialized = serializers.serialize('json', [dog_body_attrs])
  117. dog_relationship_personality_serialized = serializers.serialize('json', [dog_relationship_personality])
  118. dog_training_serialized = serializers.serialize('json', [dog_training])
  119. # 解析 JSON 字符串为 Python 对象
  120. dog_status_data = json.loads(dog_status_serialized)[0]['fields']
  121. dog_body_attrs_data = json.loads(dog_body_attrs_serialized)[0]['fields']
  122. dog_relationship_personality_data = json.loads(dog_relationship_personality_serialized)[0]['fields']
  123. dog_training_data = json.loads(dog_training_serialized)[0]['fields']
  124. return {"status": "success", "dog_status": dog_status_data,
  125. "dog_body_attrs": dog_body_attrs_data, "dog_relationship_personality": dog_relationship_personality_data,
  126. "dog_training": dog_training_data}
  127. # 呼唤更新状态
  128. # 2024-12-21 author Feng
  129. # 通过游戏声音输入引导后,初始值为10
  130. # 每次呼唤成功后+1,当日最多+5
  131. # 每次呼唤亲密,友善,服从性+1,每日最多+2
  132. def voice_gain_state(d_id, call_name, time_now):
  133. try:
  134. dog_command_recognition = DogTraining.objects.get(d_id=d_id)
  135. dog_relationship_personality = DogPersonalityRelationship.objects.get(d_id=d_id)
  136. except DogTraining.DoesNotExist:
  137. return {"status": "error", "message": f"No command recognition found for dog with d_id={d_id}"}
  138. except DogPersonalityRelationship.DoesNotExist:
  139. return {"status": "error", "message": f"No relationship data found for dog with d_id={d_id}"}
  140. # 获取时间差
  141. days=get_days_difference(dog_command_recognition.time_lasttime, time_now)
  142. # 判断是否在当日互动逻辑:如果大于1天就重置呼唤次数为0
  143. if days >= 1:
  144. dog_command_recognition.numbers_of_calls=0
  145. dog_command_recognition.save()
  146. #
  147. if call_name == 1:
  148. # 每次呼唤,呼唤次数+1,且不超过999
  149. dog_command_recognition.numbers_of_calls = min(999, dog_command_recognition.numbers_of_calls + 1)
  150. # 每次呼唤,以下值当日最多 + 5
  151. if dog_command_recognition.numbers_of_calls<5:
  152. dog_command_recognition.commandName = min(100, dog_command_recognition.recognize_name + 1)
  153. dog_command_recognition.commandSit = min(100, dog_command_recognition.recognize_sit + 1)
  154. dog_command_recognition.commandLieDown = min(100, dog_command_recognition.recognize_lie_down + 1)
  155. dog_command_recognition.commandRotate = min(100, dog_command_recognition.recognize_spin + 1)
  156. if dog_command_recognition.numbers_of_calls < 3:
  157. # 每次呼唤,以下值当日最多 + 2
  158. dog_relationship_personality.intimate = min(100, dog_relationship_personality.intimate + 1)
  159. dog_relationship_personality.friendly = min(100, dog_relationship_personality.friendly + 1)
  160. dog_relationship_personality.obedience = min(100, dog_relationship_personality.obedience + 1)
  161. #每次请求更新呼唤状态时,记录请求时间,用于比较判断下次呼唤请求是否在当日内
  162. dog_command_recognition.time_lasttime=time_now
  163. dog_command_recognition.save()
  164. dog_relationship_personality.save()
  165. return {"status": "success", "message": "Voice gain updated", "command_recognition": dog_command_recognition.__dict__}
  166. # 道具使用更新状态
  167. # 2025-3-14 author Feng
  168. # 根据不同道具使用效果增加狗的属性
  169. # 使用道具food_00001,体力+30,狗饱腹度在80以上后,喂食肥胖度+10
  170. # 使用道具food_00002,体力+50,狗饱腹度在80以上后,喂食肥胖度+5
  171. # 使用道具food_00003,体力+40,狗饱腹度在80以上后,喂食肥胖度+5
  172. # 使用道具water_00001,口渴恢复到90
  173. # 使用道具water_00002,口渴+40,体力+30
  174. # 使用道具toy_00001,暂不改变
  175. # 使用道具other_00001,根据洗澡时间,恢复Clean60到99。
  176. # 使用道具other_00002,根据梳理时间,增加Clean10到40。上限60。
  177. def props_gain_state(user_id, dog_id, item_id, time_now):
  178. try:
  179. # 取出数据库的uid:
  180. user = User.objects.get(uid=user_id)
  181. # 获取狗的状态信息
  182. dog_status = DogStatus.objects.get(d_id=dog_id)
  183. dog_body_attrs = DogBodyAttributes.objects.get(d_id=dog_id)
  184. # dog_training = DogTraining.objects.get(d_id=dog_id)
  185. # 根据不同道具执行不同的属性更新
  186. if item_id == "food_00001":
  187. # 投喂狗粮,每次投喂用户金币数量-10
  188. coin_cost = 10
  189. # 使用道具food_00001,体力+30,狗饱腹度在80以上后,喂食肥胖度+10
  190. dog_status.stamina = min(100, dog_status.stamina + 30)
  191. dog_status.satiety = min(100, dog_status.satiety + 30)
  192. if dog_status.satiety > 80:
  193. dog_body_attrs.obesity = min(100, dog_body_attrs.obesity + 10)
  194. elif item_id == "food_00002":
  195. # 投喂狗罐头,每次投喂用户金币数量-20
  196. coin_cost = 20
  197. # 使用道具food_00002,体力+50,狗饱腹度在80以上后,喂食肥胖度+5
  198. dog_status.stamina = min(100, dog_status.stamina + 50)
  199. dog_status.satiety = min(100, dog_status.satiety + 40)
  200. if dog_status.satiety > 80:
  201. dog_body_attrs.obesity = min(100, dog_body_attrs.obesity + 5)
  202. elif item_id == "food_00003":
  203. # 投喂冻肉干,每次投喂用户金币数量-15
  204. coin_cost = 15
  205. # 使用道具food_00003,体力+40,狗饱腹度在80以上后,喂食肥胖度+5
  206. dog_status.stamina = min(100, dog_status.stamina + 40)
  207. dog_status.satiety = min(100, dog_status.satiety + 35)
  208. if dog_status.satiety > 80:
  209. dog_body_attrs.obesity = min(100, dog_body_attrs.obesity + 5)
  210. elif item_id == "water_00001":
  211. # 投喂 水 ,每次投喂用户金币数量-2
  212. coin_cost = 2
  213. # 使用道具water_00001,口渴恢复到90
  214. dog_status.thirsty = 90
  215. elif item_id == "water_00002":
  216. # 投喂 牛奶,每次投喂用户金币数量-10
  217. coin_cost = 10
  218. # 使用道具water_00002,口渴+40,体力+30
  219. dog_status.thirsty = min(100, dog_status.thirsty + 40)
  220. dog_status.stamina = min(100, dog_status.stamina + 30)
  221. elif item_id == "toy_00001":
  222. # 叼飞盘 ,每次丢飞盘用户金币数量-50
  223. coin_cost = 50
  224. # 使用道具toy_00001,增加幸福感
  225. # dog_status.happiness = min(100, dog_status.happiness + 20)
  226. # 减少体力
  227. # dog_status.stamina = max(0, dog_status.stamina - 10)
  228. elif item_id == "other_00001":
  229. # 洗澡液 ,每次洗澡液用户金币数量-20
  230. coin_cost = 20
  231. # 使用道具other_00001,根据洗澡时间,恢复Clean60到99
  232. clean_increase = 60
  233. max_clean = 99
  234. dog_status.clean = min(max_clean, dog_status.clean + clean_increase)
  235. elif item_id == "other_00002":
  236. # 用梳子 ,每次用梳子用户金币数量-20
  237. coin_cost = 20
  238. # 使用道具other_00002,根据梳理时间,增加Clean10到40。上限60
  239. clean_increase = random.randint(10, 40)
  240. max_clean = 60
  241. dog_status.clean = min(max_clean, dog_status.clean + clean_increase)
  242. else:
  243. raise ValueError("Invalid item_id parameter")
  244. # 检查用户金币是否足够
  245. if user.coin < coin_cost:
  246. return JsonResponse({
  247. "status": "error",
  248. "message": "Insufficient coins"
  249. })
  250. # 扣除用户金币
  251. user.coin = user.coin - coin_cost
  252. user.save()
  253. # 更新最后交互时间
  254. dog_status.time_lasttime = time_now
  255. # 保存更新
  256. dog_status.save()
  257. dog_body_attrs.save()
  258. # dog_training.save()
  259. return {
  260. "status": "success",
  261. "message": f"Dog {dog_id} attributes updated with item {item_id}",
  262. "code": 200
  263. }
  264. except User.DoesNotExist:
  265. return {"status": "error","message": f"No user found with uid={user_id}"}
  266. except DogStatus.DoesNotExist:
  267. return {"status": "error", "message": f"No status found for dog with d_id={dog_id}"}
  268. except DogBodyAttributes.DoesNotExist:
  269. return {"status": "error", "message": f"No body attributes found for dog with d_id={dog_id}"}
  270. # except DogTraining.DoesNotExist:
  271. # return {"status": "error", "message": f"No training data found for dog with d_id={dog_id}"}
  272. except Exception as e:
  273. return {"status": "error", "message": f"Error updating dog attributes: {str(e)}"}