Files
whale-town/scripts/CommunityEventSystem.gd
2025-12-05 19:00:14 +08:00

864 lines
25 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends Node
class_name CommunityEventSystem
## 社区活动和事件系统
## 管理社区活动、事件和集体互动
# 事件类型枚举
enum EventType {
SOCIAL_GATHERING, # 社交聚会
LEARNING_SESSION, # 学习会议
COMPETITION, # 竞赛活动
CELEBRATION, # 庆祝活动
WORKSHOP, # 工作坊
DISCUSSION, # 讨论会
GAME_ACTIVITY, # 游戏活动
COMMUNITY_PROJECT, # 社区项目
ANNOUNCEMENT, # 公告
MILESTONE # 里程碑事件
}
# 事件状态枚举
enum EventStatus {
PLANNED, # 计划中
ACTIVE, # 进行中
COMPLETED, # 已完成
CANCELLED # 已取消
}
# 事件数据结构
class CommunityEvent:
var event_id: String
var title: String
var description: String
var event_type: EventType
var status: EventStatus
var organizer_id: String
var participants: Array[String] = []
var max_participants: int = 0 # 0表示无限制
var start_time: float
var end_time: float
var location: String = "" # 游戏内位置
var rewards: Dictionary = {}
var requirements: Dictionary = {}
var created_at: float
var updated_at: float
var tags: Array[String] = []
var metadata: Dictionary = {}
func _init(id: String, event_title: String, type: EventType, organizer: String):
event_id = id
title = event_title
event_type = type
organizer_id = organizer
status = EventStatus.PLANNED
created_at = Time.get_unix_time_from_system()
updated_at = created_at
start_time = created_at + 3600 # 默认1小时后开始
end_time = start_time + 3600 # 默认持续1小时
# 活动数据存储
var events: Dictionary = {} # event_id -> CommunityEvent
var active_events: Array[String] = []
var user_events: Dictionary = {} # user_id -> Array[event_id]
var event_history: Array[Dictionary] = []
# 系统配置
var max_events_per_user: int = 10
var max_active_events: int = 20
var auto_cleanup_days: int = 30
# 关系网络引用
var relationship_network: RelationshipNetwork
# 数据持久化
var events_file_path: String = "user://community_events.json"
# 信号
signal event_created(event_id: String, title: String, organizer_id: String)
signal event_started(event_id: String, title: String)
signal event_completed(event_id: String, title: String, participants: Array[String])
signal event_cancelled(event_id: String, title: String, reason: String)
signal participant_joined(event_id: String, participant_id: String)
signal participant_left(event_id: String, participant_id: String)
signal event_reminder(event_id: String, title: String, minutes_until_start: int)
signal milestone_achieved(milestone_type: String, data: Dictionary)
func _ready():
"""初始化社区事件系统"""
load_events_data()
# 启动定时器检查事件状态
var timer = Timer.new()
timer.wait_time = 60.0 # 每分钟检查一次
timer.timeout.connect(_check_event_status)
timer.autostart = true
add_child(timer)
print("CommunityEventSystem initialized")
## 设置关系网络引用
func set_relationship_network(rn: RelationshipNetwork) -> void:
"""
设置关系网络引用
@param rn: 关系网络实例
"""
relationship_network = rn
## 创建事件
func create_event(title: String, description: String, event_type: EventType, organizer_id: String, start_time: float = 0.0, duration: float = 3600.0) -> String:
"""
创建新的社区事件
@param title: 事件标题
@param description: 事件描述
@param event_type: 事件类型
@param organizer_id: 组织者ID
@param start_time: 开始时间Unix时间戳0表示使用默认时间
@param duration: 持续时间(秒)
@return: 事件ID失败返回空字符串
"""
# 验证输入
if title.strip_edges().is_empty():
print("Event title cannot be empty")
return ""
if title.length() > 100:
print("Event title too long")
return ""
# 检查用户事件数量限制
var user_event_count = user_events.get(organizer_id, []).size()
if user_event_count >= max_events_per_user:
print("User has reached maximum events limit")
return ""
# 检查活跃事件数量限制
if active_events.size() >= max_active_events:
print("Maximum active events limit reached")
return ""
# 生成事件ID
var event_id = generate_event_id()
# 创建事件
var event = CommunityEvent.new(event_id, title.strip_edges(), event_type, organizer_id)
event.description = description.strip_edges()
if start_time > 0:
event.start_time = start_time
event.end_time = start_time + duration
# 组织者自动参与
event.participants.append(organizer_id)
# 存储事件
events[event_id] = event
active_events.append(event_id)
# 更新用户事件索引
_add_event_to_user_index(organizer_id, event_id)
# 保存数据
save_events_data()
# 发射信号
event_created.emit(event_id, title, organizer_id)
print("Event created: ", title, " (", event_id, ") by ", organizer_id)
return event_id
## 加入事件
func join_event(event_id: String, participant_id: String) -> bool:
"""
加入事件
@param event_id: 事件ID
@param participant_id: 参与者ID
@return: 是否成功加入
"""
if not events.has(event_id):
print("Event not found: ", event_id)
return false
var event = events[event_id]
# 检查事件状态
if event.status != EventStatus.PLANNED and event.status != EventStatus.ACTIVE:
print("Cannot join event: event is not active")
return false
# 检查是否已经参与
if participant_id in event.participants:
print("Already participating in event: ", event_id)
return true
# 检查参与者数量限制
if event.max_participants > 0 and event.participants.size() >= event.max_participants:
print("Event is full")
return false
# 检查参与要求
if not _check_event_requirements(event, participant_id):
print("Participant does not meet event requirements")
return false
# 加入事件
event.participants.append(participant_id)
event.updated_at = Time.get_unix_time_from_system()
# 更新用户事件索引
_add_event_to_user_index(participant_id, event_id)
# 记录关系网络互动
if relationship_network:
for other_participant in event.participants:
if other_participant != participant_id:
relationship_network.record_interaction(participant_id, other_participant, "community_event", {"event_id": event_id})
# 保存数据
save_events_data()
# 发射信号
participant_joined.emit(event_id, participant_id)
print("Participant ", participant_id, " joined event ", event_id)
return true
## 离开事件
func leave_event(event_id: String, participant_id: String) -> bool:
"""
离开事件
@param event_id: 事件ID
@param participant_id: 参与者ID
@return: 是否成功离开
"""
if not events.has(event_id):
print("Event not found: ", event_id)
return false
var event = events[event_id]
# 检查是否参与
if not participant_id in event.participants:
print("Not participating in event: ", event_id)
return false
# 组织者不能离开自己的事件
if participant_id == event.organizer_id:
print("Organizer cannot leave their own event")
return false
# 离开事件
event.participants.erase(participant_id)
event.updated_at = Time.get_unix_time_from_system()
# 更新用户事件索引
_remove_event_from_user_index(participant_id, event_id)
# 保存数据
save_events_data()
# 发射信号
participant_left.emit(event_id, participant_id)
print("Participant ", participant_id, " left event ", event_id)
return true
## 开始事件
func start_event(event_id: String) -> bool:
"""
开始事件
@param event_id: 事件ID
@return: 是否成功开始
"""
if not events.has(event_id):
print("Event not found: ", event_id)
return false
var event = events[event_id]
if event.status != EventStatus.PLANNED:
print("Event cannot be started: not in planned status")
return false
# 更新状态
event.status = EventStatus.ACTIVE
event.start_time = Time.get_unix_time_from_system()
event.updated_at = event.start_time
# 保存数据
save_events_data()
# 发射信号
event_started.emit(event_id, event.title)
print("Event started: ", event.title, " (", event_id, ")")
return true
## 完成事件
func complete_event(event_id: String, results: Dictionary = {}) -> bool:
"""
完成事件
@param event_id: 事件ID
@param results: 事件结果数据
@return: 是否成功完成
"""
if not events.has(event_id):
print("Event not found: ", event_id)
return false
var event = events[event_id]
if event.status != EventStatus.ACTIVE:
print("Event cannot be completed: not active")
return false
# 更新状态
event.status = EventStatus.COMPLETED
event.end_time = Time.get_unix_time_from_system()
event.updated_at = event.end_time
event.metadata["results"] = results
# 从活跃事件列表移除
active_events.erase(event_id)
# 添加到历史记录
_add_to_event_history(event)
# 分发奖励
_distribute_event_rewards(event)
# 记录关系网络互动
if relationship_network:
_record_event_relationships(event)
# 检查里程碑
_check_milestones(event)
# 保存数据
save_events_data()
# 发射信号
event_completed.emit(event_id, event.title, event.participants)
print("Event completed: ", event.title, " (", event_id, ") with ", event.participants.size(), " participants")
return true
## 取消事件
func cancel_event(event_id: String, reason: String = "") -> bool:
"""
取消事件
@param event_id: 事件ID
@param reason: 取消原因
@return: 是否成功取消
"""
if not events.has(event_id):
print("Event not found: ", event_id)
return false
var event = events[event_id]
if event.status == EventStatus.COMPLETED or event.status == EventStatus.CANCELLED:
print("Event cannot be cancelled: already completed or cancelled")
return false
# 更新状态
event.status = EventStatus.CANCELLED
event.updated_at = Time.get_unix_time_from_system()
event.metadata["cancel_reason"] = reason
# 从活跃事件列表移除
active_events.erase(event_id)
# 保存数据
save_events_data()
# 发射信号
event_cancelled.emit(event_id, event.title, reason)
print("Event cancelled: ", event.title, " (", event_id, ") - ", reason)
return true
## 获取事件列表
func get_events_list(filter_type: EventType = EventType.SOCIAL_GATHERING, filter_status: EventStatus = EventStatus.PLANNED, include_all_types: bool = true, include_all_statuses: bool = true) -> Array[Dictionary]:
"""
获取事件列表
@param filter_type: 过滤事件类型
@param filter_status: 过滤事件状态
@param include_all_types: 是否包含所有类型
@param include_all_statuses: 是否包含所有状态
@return: 事件信息数组
"""
var events_list = []
for event_id in events:
var event = events[event_id]
# 应用过滤器
if not include_all_types and event.event_type != filter_type:
continue
if not include_all_statuses and event.status != filter_status:
continue
events_list.append(_get_event_info(event))
# 按开始时间排序
events_list.sort_custom(func(a, b): return a.start_time < b.start_time)
return events_list
## 获取用户事件
func get_user_events(user_id: String) -> Array[Dictionary]:
"""
获取用户参与的事件
@param user_id: 用户ID
@return: 事件信息数组
"""
var user_event_ids = user_events.get(user_id, [])
var user_events_list = []
for event_id in user_event_ids:
if events.has(event_id):
user_events_list.append(_get_event_info(events[event_id]))
# 按开始时间排序
user_events_list.sort_custom(func(a, b): return a.start_time < b.start_time)
return user_events_list
## 搜索事件
func search_events(query: String, event_type: EventType = EventType.SOCIAL_GATHERING, include_all_types: bool = true) -> Array[Dictionary]:
"""
搜索事件
@param query: 搜索关键词
@param event_type: 事件类型过滤
@param include_all_types: 是否包含所有类型
@return: 匹配的事件信息数组
"""
var results = []
var search_query = query.to_lower()
for event_id in events:
var event = events[event_id]
# 类型过滤
if not include_all_types and event.event_type != event_type:
continue
# 搜索标题和描述
if event.title.to_lower().contains(search_query) or event.description.to_lower().contains(search_query):
results.append(_get_event_info(event))
# 搜索标签
else:
for tag in event.tags:
if tag.to_lower().contains(search_query):
results.append(_get_event_info(event))
break
return results
## 获取推荐事件
func get_recommended_events(user_id: String, limit: int = 5) -> Array[Dictionary]:
"""
获取推荐事件
@param user_id: 用户ID
@param limit: 限制返回数量
@return: 推荐事件信息数组
"""
var recommendations = []
var user_interests = _get_user_interests(user_id)
for event_id in events:
var event = events[event_id]
# 只推荐计划中的事件
if event.status != EventStatus.PLANNED:
continue
# 不推荐已参与的事件
if user_id in event.participants:
continue
var score = _calculate_recommendation_score(event, user_id, user_interests)
recommendations.append({
"event": _get_event_info(event),
"score": score
})
# 按推荐分数排序
recommendations.sort_custom(func(a, b): return a.score > b.score)
# 提取事件信息
var recommended_events = []
for i in range(min(limit, recommendations.size())):
recommended_events.append(recommendations[i].event)
return recommended_events
## 检查事件状态
func _check_event_status() -> void:
"""定期检查事件状态并处理自动转换"""
var current_time = Time.get_unix_time_from_system()
for event_id in active_events.duplicate(): # 使用副本避免修改时的问题
if not events.has(event_id):
active_events.erase(event_id)
continue
var event = events[event_id]
# 检查是否应该开始
if event.status == EventStatus.PLANNED and current_time >= event.start_time:
start_event(event_id)
# 检查是否应该结束
elif event.status == EventStatus.ACTIVE and current_time >= event.end_time:
complete_event(event_id)
# 发送提醒
elif event.status == EventStatus.PLANNED:
var minutes_until_start = (event.start_time - current_time) / 60.0
if minutes_until_start <= 15 and minutes_until_start > 14: # 15分钟提醒
event_reminder.emit(event_id, event.title, 15)
elif minutes_until_start <= 5 and minutes_until_start > 4: # 5分钟提醒
event_reminder.emit(event_id, event.title, 5)
## 检查事件要求
func _check_event_requirements(_event: CommunityEvent, _participant_id: String) -> bool:
"""
检查参与者是否满足事件要求
@param _event: 事件对象 (暂未使用)
@param _participant_id: 参与者ID (暂未使用)
@return: 是否满足要求
"""
# 这里可以添加各种要求检查,比如等级、成就、关系等
# 目前返回true表示没有特殊要求
return true
## 分发事件奖励
func _distribute_event_rewards(event: CommunityEvent) -> void:
"""
分发事件奖励
@param event: 事件对象
"""
if event.rewards.is_empty():
return
for participant_id in event.participants:
# 这里可以实现具体的奖励分发逻辑
# 比如经验值、成就、物品等
print("Distributing rewards to ", participant_id, " for event ", event.title)
## 记录事件关系
func _record_event_relationships(event: CommunityEvent) -> void:
"""
记录事件中的关系互动
@param event: 事件对象
"""
if not relationship_network:
return
# 为所有参与者之间记录互动
for i in range(event.participants.size()):
for j in range(i + 1, event.participants.size()):
var participant1 = event.participants[i]
var participant2 = event.participants[j]
var interaction_data = {
"event_id": event.event_id,
"event_type": EventType.keys()[event.event_type],
"event_title": event.title
}
relationship_network.record_interaction(participant1, participant2, "community_event", interaction_data)
relationship_network.record_interaction(participant2, participant1, "community_event", interaction_data)
## 检查里程碑
func _check_milestones(event: CommunityEvent) -> void:
"""
检查并触发里程碑事件
@param event: 完成的事件对象
"""
# 检查各种里程碑条件
var total_events = event_history.size()
# 事件数量里程碑
if total_events == 10:
milestone_achieved.emit("events_10", {"count": total_events})
elif total_events == 50:
milestone_achieved.emit("events_50", {"count": total_events})
elif total_events == 100:
milestone_achieved.emit("events_100", {"count": total_events})
# 参与者数量里程碑
if event.participants.size() >= 20:
milestone_achieved.emit("large_event", {"participants": event.participants.size(), "event_id": event.event_id})
## 获取用户兴趣
func _get_user_interests(user_id: String) -> Dictionary:
"""
获取用户兴趣(基于历史参与)
@param user_id: 用户ID
@return: 兴趣数据字典
"""
var interests = {}
var user_event_ids = user_events.get(user_id, [])
for event_id in user_event_ids:
if events.has(event_id):
var event = events[event_id]
var type_name = EventType.keys()[event.event_type]
interests[type_name] = interests.get(type_name, 0) + 1
return interests
## 计算推荐分数
func _calculate_recommendation_score(event: CommunityEvent, user_id: String, user_interests: Dictionary) -> float:
"""
计算事件推荐分数
@param event: 事件对象
@param user_id: 用户ID
@param user_interests: 用户兴趣数据
@return: 推荐分数
"""
var score = 0.0
# 基于用户兴趣
var type_name = EventType.keys()[event.event_type]
score += user_interests.get(type_name, 0) * 10.0
# 基于关系网络
if relationship_network:
var user_relationships = relationship_network.get_character_relationships(user_id)
for relationship in user_relationships:
if relationship.to_character in event.participants:
score += relationship.strength * 0.5
# 基于事件规模(适中规模更受欢迎)
var participant_count = event.participants.size()
if participant_count >= 3 and participant_count <= 10:
score += 5.0
# 基于时间(即将开始的事件更相关)
var time_until_start = event.start_time - Time.get_unix_time_from_system()
if time_until_start > 0 and time_until_start <= 86400: # 24小时内
score += 10.0 - (time_until_start / 8640.0) # 越近分数越高
return score
## 获取事件信息
func _get_event_info(event: CommunityEvent) -> Dictionary:
"""
获取事件信息字典
@param event: 事件对象
@return: 事件信息字典
"""
return {
"id": event.event_id,
"title": event.title,
"description": event.description,
"type": event.event_type,
"type_name": EventType.keys()[event.event_type],
"status": event.status,
"status_name": EventStatus.keys()[event.status],
"organizer_id": event.organizer_id,
"participants": event.participants.duplicate(),
"participant_count": event.participants.size(),
"max_participants": event.max_participants,
"start_time": event.start_time,
"end_time": event.end_time,
"location": event.location,
"rewards": event.rewards.duplicate(),
"requirements": event.requirements.duplicate(),
"created_at": event.created_at,
"updated_at": event.updated_at,
"tags": event.tags.duplicate(),
"metadata": event.metadata.duplicate()
}
## 添加到事件历史
func _add_to_event_history(event: CommunityEvent) -> void:
"""
添加事件到历史记录
@param event: 事件对象
"""
var history_entry = {
"event_id": event.event_id,
"title": event.title,
"type": event.event_type,
"organizer_id": event.organizer_id,
"participant_count": event.participants.size(),
"start_time": event.start_time,
"end_time": event.end_time,
"completed_at": Time.get_unix_time_from_system()
}
event_history.append(history_entry)
# 限制历史记录长度
if event_history.size() > 1000:
event_history.pop_front()
## 添加事件到用户索引
func _add_event_to_user_index(user_id: String, event_id: String) -> void:
"""
添加事件到用户索引
@param user_id: 用户ID
@param event_id: 事件ID
"""
if not user_events.has(user_id):
user_events[user_id] = []
var user_event_list = user_events[user_id]
if not event_id in user_event_list:
user_event_list.append(event_id)
## 从用户索引移除事件
func _remove_event_from_user_index(user_id: String, event_id: String) -> void:
"""
从用户索引移除事件
@param user_id: 用户ID
@param event_id: 事件ID
"""
if user_events.has(user_id):
var user_event_list = user_events[user_id]
user_event_list.erase(event_id)
## 生成事件ID
func generate_event_id() -> String:
"""生成唯一的事件ID"""
var timestamp = Time.get_unix_time_from_system()
var random = randi()
return "event_%d_%d" % [timestamp, random]
## 保存事件数据
func save_events_data() -> void:
"""保存事件数据到本地文件"""
var data = {
"events": {},
"active_events": active_events,
"user_events": user_events,
"event_history": event_history
}
# 序列化事件数据
for event_id in events:
var event = events[event_id]
data.events[event_id] = {
"title": event.title,
"description": event.description,
"event_type": event.event_type,
"status": event.status,
"organizer_id": event.organizer_id,
"participants": event.participants,
"max_participants": event.max_participants,
"start_time": event.start_time,
"end_time": event.end_time,
"location": event.location,
"rewards": event.rewards,
"requirements": event.requirements,
"created_at": event.created_at,
"updated_at": event.updated_at,
"tags": event.tags,
"metadata": event.metadata
}
var file = FileAccess.open(events_file_path, FileAccess.WRITE)
if file:
var json_string = JSON.stringify(data)
file.store_string(json_string)
file.close()
print("Community events data saved")
else:
print("Failed to save community events data")
## 加载事件数据
func load_events_data() -> void:
"""从本地文件加载事件数据"""
if not FileAccess.file_exists(events_file_path):
print("No community events data file found, starting fresh")
return
var file = FileAccess.open(events_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_id in data.events:
var event_data = data.events[event_id]
var event = CommunityEvent.new(
event_id,
event_data.get("title", ""),
event_data.get("event_type", EventType.SOCIAL_GATHERING),
event_data.get("organizer_id", "")
)
event.description = event_data.get("description", "")
event.status = event_data.get("status", EventStatus.PLANNED)
event.participants = event_data.get("participants", [])
event.max_participants = event_data.get("max_participants", 0)
event.start_time = event_data.get("start_time", Time.get_unix_time_from_system())
event.end_time = event_data.get("end_time", event.start_time + 3600)
event.location = event_data.get("location", "")
event.rewards = event_data.get("rewards", {})
event.requirements = event_data.get("requirements", {})
event.created_at = event_data.get("created_at", Time.get_unix_time_from_system())
event.updated_at = event_data.get("updated_at", event.created_at)
event.tags = event_data.get("tags", [])
event.metadata = event_data.get("metadata", {})
events[event_id] = event
# 加载活跃事件列表
if data.has("active_events"):
active_events = data.active_events
# 加载用户事件索引
if data.has("user_events"):
user_events = data.user_events
# 加载事件历史
if data.has("event_history"):
event_history = data.event_history
print("Community events data loaded: ", events.size(), " events, ", active_events.size(), " active")
else:
print("Failed to parse community events data JSON")
else:
print("Failed to open community events data file")
## 获取统计信息
func get_statistics() -> Dictionary:
"""
获取社区事件系统统计信息
@return: 统计信息字典
"""
var type_counts = {}
var status_counts = {}
var total_participants = 0
for event_id in events:
var event = events[event_id]
var type_name = EventType.keys()[event.event_type]
var status_name = EventStatus.keys()[event.status]
type_counts[type_name] = type_counts.get(type_name, 0) + 1
status_counts[status_name] = status_counts.get(status_name, 0) + 1
total_participants += event.participants.size()
return {
"total_events": events.size(),
"active_events": active_events.size(),
"completed_events": event_history.size(),
"total_participants": total_participants,
"average_participants": float(total_participants) / max(events.size(), 1),
"event_types": type_counts,
"event_statuses": status_counts,
"max_events_per_user": max_events_per_user,
"max_active_events": max_active_events
}