创建新工程

This commit is contained in:
moyin
2025-12-05 19:00:14 +08:00
commit ff4fa5fffd
227 changed files with 32804 additions and 0 deletions

View File

@@ -0,0 +1,669 @@
extends Node
class_name UserBehaviorAnalytics
## 用户行为分析系统
## 收集、分析和报告用户在游戏中的行为数据
# 行为事件类型枚举
enum EventType {
LOGIN, # 登录
LOGOUT, # 登出
CHARACTER_CREATED, # 角色创建
MOVEMENT, # 移动
DIALOGUE_STARTED, # 开始对话
DIALOGUE_ENDED, # 结束对话
MESSAGE_SENT, # 发送消息
FRIEND_REQUEST, # 好友请求
EVENT_JOINED, # 参加活动
INTERACTION, # 交互行为
UI_ACTION, # UI操作
ERROR_OCCURRED, # 错误发生
PERFORMANCE_METRIC # 性能指标
}
# 行为数据结构
class BehaviorEvent:
var event_id: String
var event_type: EventType
var user_id: String
var timestamp: float
var session_id: String
var data: Dictionary = {}
var context: Dictionary = {}
func _init(type: EventType, uid: String, sid: String, event_data: Dictionary = {}):
event_id = generate_event_id()
event_type = type
user_id = uid
session_id = sid
timestamp = Time.get_unix_time_from_system()
data = event_data.duplicate()
context = _get_context_data()
func generate_event_id() -> String:
return "evt_%d_%d" % [Time.get_unix_time_from_system(), randi()]
func _get_context_data() -> Dictionary:
return {
"platform": OS.get_name(),
"viewport_size": get_viewport().get_visible_rect().size if get_viewport() else Vector2.ZERO,
"fps": Engine.get_frames_per_second()
}
# 数据存储和管理
var behavior_events: Array[BehaviorEvent] = []
var current_session_id: String = ""
var current_user_id: String = "player"
var session_start_time: float = 0.0
var max_events_in_memory: int = 1000
var analytics_enabled: bool = true
# 数据持久化
var analytics_file_path: String = "user://user_analytics.json"
var session_file_path: String = "user://session_data.json"
# 统计数据缓存
var cached_statistics: Dictionary = {}
var statistics_cache_time: float = 0.0
var cache_duration: float = 300.0 # 5分钟缓存
# 信号
signal behavior_recorded(event_type: EventType, data: Dictionary)
signal session_started(session_id: String)
signal session_ended(session_id: String, duration: float)
signal analytics_report_generated(report: Dictionary)
func _ready():
"""初始化用户行为分析系统"""
_start_new_session()
_load_analytics_data()
# 设置定时保存
var save_timer = Timer.new()
save_timer.wait_time = 60.0 # 每分钟保存一次
save_timer.timeout.connect(_save_analytics_data)
save_timer.autostart = true
add_child(save_timer)
print("UserBehaviorAnalytics initialized")
## 开始新会话
func _start_new_session() -> void:
"""开始新的用户会话"""
current_session_id = _generate_session_id()
session_start_time = Time.get_unix_time_from_system()
# 记录会话开始事件
record_event(EventType.LOGIN, {"session_start": true})
session_started.emit(current_session_id)
print("New session started: ", current_session_id)
## 结束当前会话
func end_current_session() -> void:
"""结束当前用户会话"""
if current_session_id.is_empty():
return
var session_duration = Time.get_unix_time_from_system() - session_start_time
# 记录会话结束事件
record_event(EventType.LOGOUT, {
"session_duration": session_duration,
"events_count": behavior_events.size()
})
session_ended.emit(current_session_id, session_duration)
# 保存数据
_save_analytics_data()
print("Session ended: ", current_session_id, " Duration: ", session_duration, "s")
## 记录行为事件
func record_event(event_type: EventType, event_data: Dictionary = {}) -> void:
"""
记录用户行为事件
@param event_type: 事件类型
@param event_data: 事件数据
"""
if not analytics_enabled:
return
var event = BehaviorEvent.new(event_type, current_user_id, current_session_id, event_data)
behavior_events.append(event)
# 限制内存中的事件数量
if behavior_events.size() > max_events_in_memory:
behavior_events.pop_front()
# 清除统计缓存
_clear_statistics_cache()
# 发射信号
behavior_recorded.emit(event_type, event_data)
# 调试输出(仅在开发模式)
if OS.is_debug_build():
print("Behavior recorded: ", EventType.keys()[event_type], " - ", event_data)
## 记录移动行为
func record_movement(from_position: Vector2, to_position: Vector2, duration: float) -> void:
"""
记录角色移动行为
@param from_position: 起始位置
@param to_position: 目标位置
@param duration: 移动时长
"""
var distance = from_position.distance_to(to_position)
record_event(EventType.MOVEMENT, {
"from": {"x": from_position.x, "y": from_position.y},
"to": {"x": to_position.x, "y": to_position.y},
"distance": distance,
"duration": duration,
"speed": distance / max(duration, 0.1)
})
## 记录对话行为
func record_dialogue_interaction(target_character: String, message_count: int, duration: float) -> void:
"""
记录对话交互行为
@param target_character: 对话目标角色
@param message_count: 消息数量
@param duration: 对话时长
"""
record_event(EventType.DIALOGUE_STARTED, {
"target": target_character,
"message_count": message_count,
"duration": duration
})
## 记录UI操作
func record_ui_action(action_type: String, ui_element: String, additional_data: Dictionary = {}) -> void:
"""
记录UI操作行为
@param action_type: 操作类型click, hover, input等
@param ui_element: UI元素标识
@param additional_data: 额外数据
"""
var ui_data = {
"action": action_type,
"element": ui_element
}
ui_data.merge(additional_data)
record_event(EventType.UI_ACTION, ui_data)
## 记录性能指标
func record_performance_metric(metric_name: String, value: float, unit: String = "") -> void:
"""
记录性能指标
@param metric_name: 指标名称
@param value: 指标值
@param unit: 单位
"""
record_event(EventType.PERFORMANCE_METRIC, {
"metric": metric_name,
"value": value,
"unit": unit,
"fps": Engine.get_frames_per_second(),
"memory_usage": OS.get_static_memory_usage_by_type()
})
## 记录错误事件
func record_error(error_type: String, error_message: String, context_data: Dictionary = {}) -> void:
"""
记录错误事件
@param error_type: 错误类型
@param error_message: 错误消息
@param context_data: 上下文数据
"""
var error_data = {
"error_type": error_type,
"message": error_message,
"stack_trace": get_stack() if OS.is_debug_build() else []
}
error_data.merge(context_data)
record_event(EventType.ERROR_OCCURRED, error_data)
## 生成会话ID
func _generate_session_id() -> String:
"""生成唯一的会话ID"""
var timestamp = Time.get_unix_time_from_system()
var random = randi()
return "session_%d_%d" % [timestamp, random]
## 清除统计缓存
func _clear_statistics_cache() -> void:
"""清除统计数据缓存"""
cached_statistics.clear()
statistics_cache_time = 0.0## 获
func get_basic_statistics() -> Dictionary:
"""
获取基础统计信息
@return: 统计数据字典
"""
# 检查缓存
var current_time = Time.get_unix_time_from_system()
if not cached_statistics.is_empty() and (current_time - statistics_cache_time) < cache_duration:
return cached_statistics
var stats = {}
# 事件总数统计
stats["total_events"] = behavior_events.size()
stats["current_session_events"] = _count_session_events(current_session_id)
stats["session_duration"] = current_time - session_start_time
# 事件类型分布
var event_type_counts = {}
for event in behavior_events:
var type_name = EventType.keys()[event.event_type]
event_type_counts[type_name] = event_type_counts.get(type_name, 0) + 1
stats["event_types"] = event_type_counts
# 活跃度分析
stats["activity_metrics"] = _calculate_activity_metrics()
# 性能统计
stats["performance_metrics"] = _calculate_performance_metrics()
# 错误统计
stats["error_metrics"] = _calculate_error_metrics()
# 缓存结果
cached_statistics = stats
statistics_cache_time = current_time
return stats
## 计算活跃度指标
func _calculate_activity_metrics() -> Dictionary:
"""计算用户活跃度指标"""
var metrics = {}
var current_time = Time.get_unix_time_from_system()
# 最近1小时的活动
var recent_events = _get_events_in_timeframe(current_time - 3600)
metrics["events_last_hour"] = recent_events.size()
# 移动活跃度
var movement_events = _get_events_by_type(EventType.MOVEMENT)
metrics["total_movements"] = movement_events.size()
if movement_events.size() > 0:
var total_distance = 0.0
for event in movement_events:
total_distance += event.data.get("distance", 0.0)
metrics["total_distance_moved"] = total_distance
metrics["average_movement_distance"] = total_distance / movement_events.size()
# 社交活跃度
var dialogue_events = _get_events_by_type(EventType.DIALOGUE_STARTED)
metrics["dialogue_sessions"] = dialogue_events.size()
var message_events = _get_events_by_type(EventType.MESSAGE_SENT)
metrics["messages_sent"] = message_events.size()
# UI交互频率
var ui_events = _get_events_by_type(EventType.UI_ACTION)
metrics["ui_interactions"] = ui_events.size()
return metrics
## 计算性能指标
func _calculate_performance_metrics() -> Dictionary:
"""计算性能相关指标"""
var metrics = {}
var performance_events = _get_events_by_type(EventType.PERFORMANCE_METRIC)
if performance_events.size() > 0:
var fps_values = []
var memory_values = []
for event in performance_events:
if event.context.has("fps"):
fps_values.append(event.context.fps)
if event.data.has("memory_usage"):
memory_values.append(event.data.memory_usage)
if fps_values.size() > 0:
metrics["average_fps"] = _calculate_average(fps_values)
metrics["min_fps"] = fps_values.min()
metrics["max_fps"] = fps_values.max()
if memory_values.size() > 0:
metrics["average_memory"] = _calculate_average(memory_values)
metrics["peak_memory"] = memory_values.max()
# 当前性能状态
metrics["current_fps"] = Engine.get_frames_per_second()
metrics["current_memory"] = OS.get_static_memory_usage_by_type()
return metrics
## 计算错误指标
func _calculate_error_metrics() -> Dictionary:
"""计算错误相关指标"""
var metrics = {}
var error_events = _get_events_by_type(EventType.ERROR_OCCURRED)
metrics["total_errors"] = error_events.size()
# 错误类型分布
var error_types = {}
for event in error_events:
var error_type = event.data.get("error_type", "unknown")
error_types[error_type] = error_types.get(error_type, 0) + 1
metrics["error_types"] = error_types
# 最近错误
if error_events.size() > 0:
var latest_error = error_events[-1]
metrics["latest_error"] = {
"type": latest_error.data.get("error_type", "unknown"),
"message": latest_error.data.get("message", ""),
"timestamp": latest_error.timestamp
}
return metrics
## 生成用户行为报告
func generate_behavior_report(timeframe_hours: float = 24.0) -> Dictionary:
"""
生成用户行为分析报告
@param timeframe_hours: 分析时间范围(小时)
@return: 行为报告
"""
var current_time = Time.get_unix_time_from_system()
var start_time = current_time - (timeframe_hours * 3600)
var report = {}
report["report_generated_at"] = current_time
report["timeframe_hours"] = timeframe_hours
report["user_id"] = current_user_id
report["session_id"] = current_session_id
# 获取时间范围内的事件
var timeframe_events = _get_events_in_timeframe(start_time)
report["events_in_timeframe"] = timeframe_events.size()
# 活动模式分析
report["activity_patterns"] = _analyze_activity_patterns(timeframe_events)
# 用户偏好分析
report["user_preferences"] = _analyze_user_preferences(timeframe_events)
# 会话质量分析
report["session_quality"] = _analyze_session_quality(timeframe_events)
# 发射报告生成信号
analytics_report_generated.emit(report)
return report
## 分析活动模式
func _analyze_activity_patterns(events: Array[BehaviorEvent]) -> Dictionary:
"""分析用户活动模式"""
var patterns = {}
# 按小时分组活动
var hourly_activity = {}
for event in events:
var hour = Time.get_datetime_dict_from_unix_time(event.timestamp).hour
hourly_activity[hour] = hourly_activity.get(hour, 0) + 1
patterns["hourly_distribution"] = hourly_activity
# 最活跃时段
var max_activity = 0
var peak_hour = 0
for hour in hourly_activity:
if hourly_activity[hour] > max_activity:
max_activity = hourly_activity[hour]
peak_hour = hour
patterns["peak_activity_hour"] = peak_hour
patterns["peak_activity_count"] = max_activity
# 活动类型偏好
var type_preferences = {}
for event in events:
var type_name = EventType.keys()[event.event_type]
type_preferences[type_name] = type_preferences.get(type_name, 0) + 1
patterns["activity_type_preferences"] = type_preferences
return patterns
## 分析用户偏好
func _analyze_user_preferences(events: Array[BehaviorEvent]) -> Dictionary:
"""分析用户偏好和兴趣"""
var preferences = {}
# 对话偏好
var dialogue_targets = {}
var dialogue_events = events.filter(func(e): return e.event_type == EventType.DIALOGUE_STARTED)
for event in dialogue_events:
var target = event.data.get("target", "unknown")
dialogue_targets[target] = dialogue_targets.get(target, 0) + 1
preferences["preferred_dialogue_targets"] = dialogue_targets
# UI使用偏好
var ui_preferences = {}
var ui_events = events.filter(func(e): return e.event_type == EventType.UI_ACTION)
for event in ui_events:
var element = event.data.get("element", "unknown")
ui_preferences[element] = ui_preferences.get(element, 0) + 1
preferences["ui_usage_patterns"] = ui_preferences
# 移动模式偏好
var movement_events = events.filter(func(e): return e.event_type == EventType.MOVEMENT)
if movement_events.size() > 0:
var distances = movement_events.map(func(e): return e.data.get("distance", 0.0))
preferences["average_movement_distance"] = _calculate_average(distances)
preferences["movement_frequency"] = movement_events.size()
return preferences
## 分析会话质量
func _analyze_session_quality(events: Array[BehaviorEvent]) -> Dictionary:
"""分析会话质量指标"""
var quality = {}
# 错误率
var error_events = events.filter(func(e): return e.event_type == EventType.ERROR_OCCURRED)
quality["error_rate"] = float(error_events.size()) / max(events.size(), 1)
# 参与度(基于事件多样性)
var unique_event_types = {}
for event in events:
unique_event_types[event.event_type] = true
quality["engagement_score"] = float(unique_event_types.size()) / EventType.size()
# 会话连续性(事件间隔分析)
if events.size() > 1:
var intervals = []
for i in range(1, events.size()):
intervals.append(events[i].timestamp - events[i-1].timestamp)
quality["average_event_interval"] = _calculate_average(intervals)
quality["session_continuity"] = 1.0 / (1.0 + _calculate_average(intervals))
return quality
## 辅助函数:计算平均值
func _calculate_average(values: Array) -> float:
"""计算数组平均值"""
if values.is_empty():
return 0.0
var sum = 0.0
for value in values:
sum += float(value)
return sum / values.size()
## 辅助函数:按类型获取事件
func _get_events_by_type(event_type: EventType) -> Array[BehaviorEvent]:
"""获取指定类型的事件"""
return behavior_events.filter(func(event): return event.event_type == event_type)
## 辅助函数:获取时间范围内的事件
func _get_events_in_timeframe(start_time: float) -> Array[BehaviorEvent]:
"""获取指定时间范围内的事件"""
return behavior_events.filter(func(event): return event.timestamp >= start_time)
## 辅助函数:统计会话事件数
func _count_session_events(session_id: String) -> int:
"""统计指定会话的事件数量"""
return behavior_events.filter(func(event): return event.session_id == session_id).size()
## 保存分析数据
func _save_analytics_data() -> void:
"""保存分析数据到本地文件"""
var data = {
"events": [],
"session_id": current_session_id,
"session_start_time": session_start_time,
"user_id": current_user_id,
"saved_at": Time.get_unix_time_from_system()
}
# 序列化事件数据(只保存最近的事件)
var events_to_save = behavior_events.slice(max(0, behavior_events.size() - 500), behavior_events.size())
for event in events_to_save:
data.events.append({
"event_id": event.event_id,
"event_type": event.event_type,
"user_id": event.user_id,
"session_id": event.session_id,
"timestamp": event.timestamp,
"data": event.data,
"context": event.context
})
var file = FileAccess.open(analytics_file_path, FileAccess.WRITE)
if file:
var json_string = JSON.stringify(data)
file.store_string(json_string)
file.close()
print("Analytics data saved: ", events_to_save.size(), " events")
else:
print("Failed to save analytics data")
## 加载分析数据
func _load_analytics_data() -> void:
"""从本地文件加载分析数据"""
if not FileAccess.file_exists(analytics_file_path):
print("No analytics data file found, starting fresh")
return
var file = FileAccess.open(analytics_file_path, FileAccess.READ)
if file:
var json_string = file.get_as_text()
file.close()
var json = JSON.new()
var parse_result = json.parse(json_string)
if parse_result == OK:
var data = json.data
# 加载事件数据
if data.has("events"):
for event_data in data.events:
var event = BehaviorEvent.new(
event_data.get("event_type", EventType.UI_ACTION),
event_data.get("user_id", ""),
event_data.get("session_id", "")
)
event.event_id = event_data.get("event_id", "")
event.timestamp = event_data.get("timestamp", 0.0)
event.data = event_data.get("data", {})
event.context = event_data.get("context", {})
behavior_events.append(event)
print("Analytics data loaded: ", behavior_events.size(), " events")
else:
print("Failed to parse analytics data JSON")
else:
print("Failed to open analytics data file")
## 导出分析报告
func export_analytics_report(export_path: String, timeframe_hours: float = 24.0) -> bool:
"""
导出分析报告到文件
@param export_path: 导出文件路径
@param timeframe_hours: 分析时间范围
@return: 是否成功导出
"""
var report = generate_behavior_report(timeframe_hours)
var file = FileAccess.open(export_path, FileAccess.WRITE)
if file:
var json_string = JSON.stringify(report)
file.store_string(json_string)
file.close()
print("Analytics report exported to: ", export_path)
return true
else:
print("Failed to export analytics report to: ", export_path)
return false
## 清理旧数据
func cleanup_old_data(days_to_keep: int = 7) -> void:
"""
清理旧的分析数据
@param days_to_keep: 保留天数
"""
var cutoff_time = Time.get_unix_time_from_system() - (days_to_keep * 86400)
var original_count = behavior_events.size()
behavior_events = behavior_events.filter(func(event): return event.timestamp >= cutoff_time)
var removed_count = original_count - behavior_events.size()
if removed_count > 0:
print("Cleaned up ", removed_count, " old analytics events")
_save_analytics_data()
## 获取实时统计
func get_realtime_statistics() -> Dictionary:
"""获取实时统计信息(不使用缓存)"""
var stats = {}
stats["current_session_duration"] = Time.get_unix_time_from_system() - session_start_time
stats["events_this_session"] = _count_session_events(current_session_id)
stats["current_fps"] = Engine.get_frames_per_second()
stats["memory_usage"] = OS.get_static_memory_usage_by_type()
# 最近5分钟的活动
var recent_time = Time.get_unix_time_from_system() - 300
var recent_events = _get_events_in_timeframe(recent_time)
stats["recent_activity"] = recent_events.size()
return stats
## 设置分析配置
func set_analytics_config(enabled: bool, max_events: int = 1000) -> void:
"""
设置分析系统配置
@param enabled: 是否启用分析
@param max_events: 最大事件数量
"""
analytics_enabled = enabled
max_events_in_memory = max_events
print("Analytics config updated - Enabled: ", enabled, " Max events: ", max_events)
func _exit_tree():
"""节点退出时保存数据"""
end_current_session()