123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- 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)}"}
|