import json import math import random import time from django.utils import timezone from django.core import serializers from django.http import JsonResponse from datetime import datetime, timedelta from django.db.models import F import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "aiDogProject.settings") import django django.setup() from aiDogApp.models import * # 获取时间差(直接返回秒数) def get_time_difference(last_time, current_time): return (current_time - last_time).total_seconds() # 获取相差天数 def get_days_difference(last_time, current_time): # time_lasttime字段是datetime类型,可以直接操作datetime对象,无需再strptime转换。 return (current_time.date() - last_time.date()).days # 更新狗狗状态 # 2024-12-05 author:Feng # 每隔1小时:狗的饥饿-5(饥饿每减少5时体力增加5),快乐-1,体力+5,口渴-1,干净-1; # 每隔一天:体力-10(当饥饿,口渴数值低于20后,体力每天减少10),健康-10(当体力低于10后健康每天减少10,当体力大于50时,健康每天增加5),当健康低于10后跑步速度-2,当健康低于10后跳跃高度-2, # 当健康低于10后活泼-2,当健康低于10后敏捷-2,当健康低于10后肥胖程度-5,和主人亲密度-2,和主人友善度-2,对主人服从性-2,对主人友好程度-1,对陌生人友好程度-1,叼飞盘熟练度-1,玩球熟练度-1,识别自己名字-2,识别坐口令-2, # 识别躺下口令-2,识别转圈口令-2; def update_dog_state(uid, d_id, time_now): try: dog_status = DogStatus.objects.get(d_id=d_id) dog_body_attrs = DogBodyAttributes.objects.get(d_id=d_id) dog_relationship_personality = DogPersonalityRelationship.objects.get(d_id=d_id) dog_training = DogTraining.objects.get(d_id=d_id) user = User.objects.get(uid=uid) except (DogStatus.DoesNotExist, DogBodyAttributes.DoesNotExist, DogPersonalityRelationship.DoesNotExist): return {"status": "error", "message": f"No dog found with d_id={d_id}"} except User.DoesNotExist: return {"status": "error", "message": f"No user found with uid={uid}"} # 获取时间差 time_difference = get_time_difference(dog_status.time_lasttime, time_now) days=get_days_difference(dog_status.time_lasttime, time_now) # 向上求余取整:2.5取值为3 hours = math.ceil(time_difference/3600) # 更新状态属性 updates = [] # 更新金币逻辑 # 在 Django 中,如果 user.coin 是通过查询出来的对象进行修改并保存,应该使用 F 对象来避免竞态条件。 # 但如果该字段被缓存,应该避免此时直接操作缓存的数据。需要确保 user.save() 之前,user.coin 是最新的。 if days >= 1: added_coin = min(days * 100, 1000000 - user.coin) user.coin = F("coin") + added_coin # 可以使用数据库层面的更新方式避免并发问题 user.save(update_fields=["coin"]) # 只更新 coin 字段 if hours < 1: return # 更新状态属性 for _ in range(int(hours)): # 每隔1小时:狗的饱腹度(饥饿)-5(饱腹度每减少5时体力增加5),快乐-1,体力+5,口渴-1,干净-1; dog_status.satiety = max(1, dog_status.satiety - 5) dog_status.thirsty = max(1, dog_status.thirsty - 1) dog_status.clean = max(1, dog_status.clean - 1) dog_status.happiness = max(1, dog_status.happiness - 1) if dog_status.satiety>=20 or dog_status.thirsty >=20: # 饱腹度(饥饿),口渴大于20时,体力每小时+5 dog_status.stamina = min(100, dog_status.stamina + 5) updates.append(dog_status) if days >= 1: # 如果距离上次请求超过一天 # 每隔一天就重置呼唤次数为0 dog_training.numbers_of_calls=0 for _ in range(int(days)): if dog_status.satiety <20 or dog_status.thirsty <20: # 每隔一天: # 饱腹度(饥饿),口渴低于20后,体力变成每日减少10 dog_status.stamina = max(1, dog_status.stamina - 10) if dog_status.stamina < 50: # 初始值50,体力低于50后,每天减少10 dog_status.healthy = max(1, dog_status.healthy - 10) else: # 体力正常是每天 + 5 dog_status.healthy = min(100, dog_status.healthy + 5) if dog_status.healthy < 10: # 当健康低于10后 # 更新身体属性:跑步速度-2,跳跃高度-2,活泼-2,敏捷-2,肥胖程度-5, dog_body_attrs.runSpeed = max(1, dog_body_attrs.runSpeed - days*2) dog_body_attrs.JumpHeight = max(1, dog_body_attrs.JumpHeight - days*2) dog_body_attrs.liveliness = max(1, dog_body_attrs.liveliness - days*2) dog_body_attrs.agility = max(1, dog_body_attrs.agility - days*2) dog_body_attrs.obesity = max(1, dog_body_attrs.obesity - days*5) # 每天更新与主人的关系:和主人亲密度-2,和主人友善度-2,对主人服从性-2, dog_relationship_personality.intimate = max(1, dog_relationship_personality.intimate - days*2) dog_relationship_personality.friendly = max(1, dog_relationship_personality.friendly - days*2) dog_relationship_personality.obedience = max(1, dog_relationship_personality.obedience - days*2) # 每天更新性格属性 :对主人友好程度-1,对陌生人友好程度-1, dog_relationship_personality.friendlyToHost = max(1, dog_relationship_personality.friendlyToHost - days*2) dog_relationship_personality.friendlyToStranger = max(1, dog_relationship_personality.friendlyToStranger - days*1) # 每天更新:叼飞盘熟练度-1,玩球熟练度-1,识别自己名字-2,识别坐口令-2,识别躺下口令-2,识别转圈口令-2 dog_training.frisbeeSkill = min(100, dog_training.frisbeeSkill - days*1) dog_training.ballSkill = min(100, dog_training.ballSkill - days*1) dog_training.commandName = min(100, dog_training.commandName - days*1) dog_training.commandSit = min(100, dog_training.commandSit - days*1) dog_training.commandLieDown = min(100, dog_training.commandLieDown - days*2) dog_training.commandRotate = min(100, dog_training.commandRotate -days*2) dog_body_attrs.save() dog_relationship_personality.save() dog_training.time_lasttime = time_now dog_training.save() # 更新最后操作时间 # 批量保存 dog_status.time_lasttime = time_now # 数据库更新:使用批量更新(bulk_update)可以显著提升性能,避免多次数据库写操作。 # 有效地减少 I/O 操作(如使用批量更新),避免重复调用 save() DogStatus.objects.bulk_update(updates, ['satiety', 'thirsty', 'clean', 'happiness', 'stamina']) dog_status.save() # 使用 Django 的 serializers 序列化模型对象 dog_status_serialized = serializers.serialize('json', [dog_status]) dog_body_attrs_serialized = serializers.serialize('json', [dog_body_attrs]) dog_relationship_personality_serialized = serializers.serialize('json', [dog_relationship_personality]) dog_training_serialized = serializers.serialize('json', [dog_training]) # 解析 JSON 字符串为 Python 对象 dog_status_data = json.loads(dog_status_serialized)[0]['fields'] dog_body_attrs_data = json.loads(dog_body_attrs_serialized)[0]['fields'] dog_relationship_personality_data = json.loads(dog_relationship_personality_serialized)[0]['fields'] dog_training_data = json.loads(dog_training_serialized)[0]['fields'] return {"status": "success", "dog_status": dog_status_data, "dog_body_attrs": dog_body_attrs_data, "dog_relationship_personality": dog_relationship_personality_data, "dog_training": dog_training_data} # 呼唤更新状态 # 2024-12-21 author Feng # 通过游戏声音输入引导后,初始值为10 # 每次呼唤成功后+1,当日最多+5 # 每次呼唤亲密,友善,服从性+1,每日最多+2 def voice_gain_state(d_id, call_name, time_now): try: dog_command_recognition = DogTraining.objects.get(d_id=d_id) dog_relationship_personality = DogPersonalityRelationship.objects.get(d_id=d_id) except DogTraining.DoesNotExist: return {"status": "error", "message": f"No command recognition found for dog with d_id={d_id}"} except DogPersonalityRelationship.DoesNotExist: return {"status": "error", "message": f"No relationship data found for dog with d_id={d_id}"} # 获取时间差 days=get_days_difference(dog_command_recognition.time_lasttime, time_now) # 判断是否在当日互动逻辑:如果大于1天就重置呼唤次数为0 if days >= 1: dog_command_recognition.numbers_of_calls=0 dog_command_recognition.save() # if call_name == 1: # 每次呼唤,呼唤次数+1,且不超过999 dog_command_recognition.numbers_of_calls = min(999, dog_command_recognition.numbers_of_calls + 1) # 每次呼唤,以下值当日最多 + 5 if dog_command_recognition.numbers_of_calls<5: dog_command_recognition.commandName = min(100, dog_command_recognition.recognize_name + 1) dog_command_recognition.commandSit = min(100, dog_command_recognition.recognize_sit + 1) dog_command_recognition.commandLieDown = min(100, dog_command_recognition.recognize_lie_down + 1) dog_command_recognition.commandRotate = min(100, dog_command_recognition.recognize_spin + 1) if dog_command_recognition.numbers_of_calls < 3: # 每次呼唤,以下值当日最多 + 2 dog_relationship_personality.intimate = min(100, dog_relationship_personality.intimate + 1) dog_relationship_personality.friendly = min(100, dog_relationship_personality.friendly + 1) dog_relationship_personality.obedience = min(100, dog_relationship_personality.obedience + 1) #每次请求更新呼唤状态时,记录请求时间,用于比较判断下次呼唤请求是否在当日内 dog_command_recognition.time_lasttime=time_now dog_command_recognition.save() dog_relationship_personality.save() return {"status": "success", "message": "Voice gain updated", "command_recognition": dog_command_recognition.__dict__} # 道具使用更新状态 # 2025-3-14 author Feng # 根据不同道具使用效果增加狗的属性 # 使用道具food_00001,体力+30,狗饱腹度在80以上后,喂食肥胖度+10 # 使用道具food_00002,体力+50,狗饱腹度在80以上后,喂食肥胖度+5 # 使用道具food_00003,体力+40,狗饱腹度在80以上后,喂食肥胖度+5 # 使用道具water_00001,口渴恢复到90 # 使用道具water_00002,口渴+40,体力+30 # 使用道具toy_00001,暂不改变 # 使用道具other_00001,根据洗澡时间,恢复Clean60到99。 # 使用道具other_00002,根据梳理时间,增加Clean10到40。上限60。 def props_gain_state(user_id, dog_id, item_id, time_now): try: # 取出数据库的uid: user = User.objects.get(uid=user_id) # 获取狗的状态信息 dog_status = DogStatus.objects.get(d_id=dog_id) dog_body_attrs = DogBodyAttributes.objects.get(d_id=dog_id) # dog_training = DogTraining.objects.get(d_id=dog_id) # 根据不同道具执行不同的属性更新 if item_id == "food_00001": # 投喂狗粮,每次投喂用户金币数量-10 coin_cost = 10 # 使用道具food_00001,体力+30,狗饱腹度在80以上后,喂食肥胖度+10 dog_status.stamina = min(100, dog_status.stamina + 30) dog_status.satiety = min(100, dog_status.satiety + 30) if dog_status.satiety > 80: dog_body_attrs.obesity = min(100, dog_body_attrs.obesity + 10) elif item_id == "food_00002": # 投喂狗罐头,每次投喂用户金币数量-20 coin_cost = 20 # 使用道具food_00002,体力+50,狗饱腹度在80以上后,喂食肥胖度+5 dog_status.stamina = min(100, dog_status.stamina + 50) dog_status.satiety = min(100, dog_status.satiety + 40) if dog_status.satiety > 80: dog_body_attrs.obesity = min(100, dog_body_attrs.obesity + 5) elif item_id == "food_00003": # 投喂冻肉干,每次投喂用户金币数量-15 coin_cost = 15 # 使用道具food_00003,体力+40,狗饱腹度在80以上后,喂食肥胖度+5 dog_status.stamina = min(100, dog_status.stamina + 40) dog_status.satiety = min(100, dog_status.satiety + 35) if dog_status.satiety > 80: dog_body_attrs.obesity = min(100, dog_body_attrs.obesity + 5) elif item_id == "water_00001": # 投喂 水 ,每次投喂用户金币数量-2 coin_cost = 2 # 使用道具water_00001,口渴恢复到90 dog_status.thirsty = 90 elif item_id == "water_00002": # 投喂 牛奶,每次投喂用户金币数量-10 coin_cost = 10 # 使用道具water_00002,口渴+40,体力+30 dog_status.thirsty = min(100, dog_status.thirsty + 40) dog_status.stamina = min(100, dog_status.stamina + 30) elif item_id == "toy_00001": # 叼飞盘 ,每次丢飞盘用户金币数量-50 coin_cost = 50 # 使用道具toy_00001,增加幸福感 # dog_status.happiness = min(100, dog_status.happiness + 20) # 减少体力 # dog_status.stamina = max(0, dog_status.stamina - 10) elif item_id == "other_00001": # 洗澡液 ,每次洗澡液用户金币数量-20 coin_cost = 20 # 使用道具other_00001,根据洗澡时间,恢复Clean60到99 clean_increase = 60 max_clean = 99 dog_status.clean = min(max_clean, dog_status.clean + clean_increase) elif item_id == "other_00002": # 用梳子 ,每次用梳子用户金币数量-20 coin_cost = 20 # 使用道具other_00002,根据梳理时间,增加Clean10到40。上限60 clean_increase = random.randint(10, 40) max_clean = 60 dog_status.clean = min(max_clean, dog_status.clean + clean_increase) else: raise ValueError("Invalid item_id parameter") # 检查用户金币是否足够 if user.coin < coin_cost: return JsonResponse({ "status": "error", "message": "Insufficient coins" }) # 扣除用户金币 user.coin = user.coin - coin_cost user.save() # 更新最后交互时间 dog_status.time_lasttime = time_now # 保存更新 dog_status.save() dog_body_attrs.save() # dog_training.save() return { "status": "success", "message": f"Dog {dog_id} attributes updated with item {item_id}", "code": 200 } except User.DoesNotExist: return {"status": "error","message": f"No user found with uid={user_id}"} except DogStatus.DoesNotExist: return {"status": "error", "message": f"No status found for dog with d_id={dog_id}"} except DogBodyAttributes.DoesNotExist: return {"status": "error", "message": f"No body attributes found for dog with d_id={dog_id}"} # except DogTraining.DoesNotExist: # return {"status": "error", "message": f"No training data found for dog with d_id={dog_id}"} except Exception as e: return {"status": "error", "message": f"Error updating dog attributes: {str(e)}"}